Mallctl: Add experimental.hooks.[install|remove].

This commit is contained in:
David Goldblatt 2018-04-24 14:45:41 -07:00 committed by David Goldblatt
parent 126e9a84a5
commit bb071db92e
2 changed files with 97 additions and 2 deletions

View File

@ -202,6 +202,8 @@ CTL_PROTO(stats_metadata_thp)
CTL_PROTO(stats_resident)
CTL_PROTO(stats_mapped)
CTL_PROTO(stats_retained)
CTL_PROTO(experimental_hooks_install)
CTL_PROTO(experimental_hooks_remove)
#define MUTEX_STATS_CTL_PROTO_GEN(n) \
CTL_PROTO(stats_##n##_num_ops) \
@ -536,6 +538,15 @@ static const ctl_named_node_t stats_node[] = {
{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[] = {
{NAME("version"), CTL(version)},
{NAME("epoch"), CTL(epoch)},
@ -548,7 +559,8 @@ static const ctl_named_node_t root_node[] = {
{NAME("arena"), CHILD(indexed, arena)},
{NAME("arenas"), CHILD(named, arenas)},
{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[] = {
{NAME(""), CHILD(named, root)}
@ -2879,3 +2891,48 @@ label_return:
malloc_mutex_unlock(tsdn, &ctl_mtx);
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;
}

View File

@ -773,6 +773,43 @@ TEST_BEGIN(test_stats_arenas) {
}
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
main(void) {
return test(
@ -801,5 +838,6 @@ main(void) {
test_arenas_lextent_constants,
test_arenas_create,
test_arenas_lookup,
test_stats_arenas);
test_stats_arenas,
test_hooks);
}