Mallctl: Add experimental.hooks.[install|remove].
This commit is contained in:
parent
126e9a84a5
commit
bb071db92e
59
src/ctl.c
59
src/ctl.c
@ -202,6 +202,8 @@ CTL_PROTO(stats_metadata_thp)
|
|||||||
CTL_PROTO(stats_resident)
|
CTL_PROTO(stats_resident)
|
||||||
CTL_PROTO(stats_mapped)
|
CTL_PROTO(stats_mapped)
|
||||||
CTL_PROTO(stats_retained)
|
CTL_PROTO(stats_retained)
|
||||||
|
CTL_PROTO(experimental_hooks_install)
|
||||||
|
CTL_PROTO(experimental_hooks_remove)
|
||||||
|
|
||||||
#define MUTEX_STATS_CTL_PROTO_GEN(n) \
|
#define MUTEX_STATS_CTL_PROTO_GEN(n) \
|
||||||
CTL_PROTO(stats_##n##_num_ops) \
|
CTL_PROTO(stats_##n##_num_ops) \
|
||||||
@ -536,6 +538,15 @@ static const ctl_named_node_t stats_node[] = {
|
|||||||
{NAME("arenas"), CHILD(indexed, stats_arenas)}
|
{NAME("arenas"), CHILD(indexed, stats_arenas)}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const ctl_named_node_t hooks_node[] = {
|
||||||
|
{NAME("install"), CTL(experimental_hooks_install)},
|
||||||
|
{NAME("remove"), CTL(experimental_hooks_remove)},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const ctl_named_node_t experimental_node[] = {
|
||||||
|
{NAME("hooks"), CHILD(named, hooks)}
|
||||||
|
};
|
||||||
|
|
||||||
static const ctl_named_node_t root_node[] = {
|
static const ctl_named_node_t root_node[] = {
|
||||||
{NAME("version"), CTL(version)},
|
{NAME("version"), CTL(version)},
|
||||||
{NAME("epoch"), CTL(epoch)},
|
{NAME("epoch"), CTL(epoch)},
|
||||||
@ -548,7 +559,8 @@ static const ctl_named_node_t root_node[] = {
|
|||||||
{NAME("arena"), CHILD(indexed, arena)},
|
{NAME("arena"), CHILD(indexed, arena)},
|
||||||
{NAME("arenas"), CHILD(named, arenas)},
|
{NAME("arenas"), CHILD(named, arenas)},
|
||||||
{NAME("prof"), CHILD(named, prof)},
|
{NAME("prof"), CHILD(named, prof)},
|
||||||
{NAME("stats"), CHILD(named, stats)}
|
{NAME("stats"), CHILD(named, stats)},
|
||||||
|
{NAME("experimental"), CHILD(named, experimental)}
|
||||||
};
|
};
|
||||||
static const ctl_named_node_t super_root_node[] = {
|
static const ctl_named_node_t super_root_node[] = {
|
||||||
{NAME(""), CHILD(named, root)}
|
{NAME(""), CHILD(named, root)}
|
||||||
@ -2879,3 +2891,48 @@ label_return:
|
|||||||
malloc_mutex_unlock(tsdn, &ctl_mtx);
|
malloc_mutex_unlock(tsdn, &ctl_mtx);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
experimental_hooks_install_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
|
||||||
|
void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
|
||||||
|
int ret;
|
||||||
|
if (oldp == NULL || oldlenp == NULL|| newp == NULL) {
|
||||||
|
ret = EINVAL;
|
||||||
|
goto label_return;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Note: this is a *private* struct. This is an experimental interface;
|
||||||
|
* forcing the user to know the jemalloc internals well enough to
|
||||||
|
* extract the ABI hopefully ensures nobody gets too comfortable with
|
||||||
|
* this API, which can change at a moment's notice.
|
||||||
|
*/
|
||||||
|
hooks_t hooks;
|
||||||
|
WRITE(hooks, hooks_t);
|
||||||
|
void *handle = hook_install(tsd_tsdn(tsd), &hooks);
|
||||||
|
if (handle == NULL) {
|
||||||
|
ret = EAGAIN;
|
||||||
|
goto label_return;
|
||||||
|
}
|
||||||
|
READ(handle, void *);
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
label_return:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
experimental_hooks_remove_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
|
||||||
|
void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
|
||||||
|
int ret;
|
||||||
|
WRITEONLY();
|
||||||
|
void *handle = NULL;
|
||||||
|
WRITE(handle, void *);
|
||||||
|
if (handle == NULL) {
|
||||||
|
ret = EINVAL;
|
||||||
|
goto label_return;
|
||||||
|
}
|
||||||
|
hook_remove(tsd_tsdn(tsd), handle);
|
||||||
|
ret = 0;
|
||||||
|
label_return:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
@ -773,6 +773,43 @@ TEST_BEGIN(test_stats_arenas) {
|
|||||||
}
|
}
|
||||||
TEST_END
|
TEST_END
|
||||||
|
|
||||||
|
static void
|
||||||
|
alloc_hook(void *extra, UNUSED hook_alloc_t type, UNUSED void *result,
|
||||||
|
UNUSED uintptr_t result_raw, UNUSED uintptr_t args_raw[3]) {
|
||||||
|
*(bool *)extra = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dalloc_hook(void *extra, UNUSED hook_dalloc_t type,
|
||||||
|
UNUSED void *address, UNUSED uintptr_t args_raw[3]) {
|
||||||
|
*(bool *)extra = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_BEGIN(test_hooks) {
|
||||||
|
bool hook_called = false;
|
||||||
|
hooks_t hooks = {&alloc_hook, &dalloc_hook, NULL, &hook_called};
|
||||||
|
void *handle = NULL;
|
||||||
|
size_t sz = sizeof(handle);
|
||||||
|
int err = mallctl("experimental.hooks.install", &handle, &sz, &hooks,
|
||||||
|
sizeof(hooks));
|
||||||
|
assert_d_eq(err, 0, "Hook installation failed");
|
||||||
|
assert_ptr_ne(handle, NULL, "Hook installation gave null handle");
|
||||||
|
void *ptr = mallocx(1, 0);
|
||||||
|
assert_true(hook_called, "Alloc hook not called");
|
||||||
|
hook_called = false;
|
||||||
|
free(ptr);
|
||||||
|
assert_true(hook_called, "Free hook not called");
|
||||||
|
|
||||||
|
err = mallctl("experimental.hooks.remove", NULL, NULL, &handle,
|
||||||
|
sizeof(handle));
|
||||||
|
assert_d_eq(err, 0, "Hook removal failed");
|
||||||
|
hook_called = false;
|
||||||
|
ptr = mallocx(1, 0);
|
||||||
|
free(ptr);
|
||||||
|
assert_false(hook_called, "Hook called after removal");
|
||||||
|
}
|
||||||
|
TEST_END
|
||||||
|
|
||||||
int
|
int
|
||||||
main(void) {
|
main(void) {
|
||||||
return test(
|
return test(
|
||||||
@ -801,5 +838,6 @@ main(void) {
|
|||||||
test_arenas_lextent_constants,
|
test_arenas_lextent_constants,
|
||||||
test_arenas_create,
|
test_arenas_create,
|
||||||
test_arenas_lookup,
|
test_arenas_lookup,
|
||||||
test_stats_arenas);
|
test_stats_arenas,
|
||||||
|
test_hooks);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user