]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/jemalloc/include/jemalloc/internal/hook.h
Update Subversion to 1.14.0 LTS. See contrib/subversion/CHANGES for a
[FreeBSD/FreeBSD.git] / contrib / jemalloc / include / jemalloc / internal / hook.h
1 #ifndef JEMALLOC_INTERNAL_HOOK_H
2 #define JEMALLOC_INTERNAL_HOOK_H
3
4 #include "jemalloc/internal/tsd.h"
5
6 /*
7  * This API is *extremely* experimental, and may get ripped out, changed in API-
8  * and ABI-incompatible ways, be insufficiently or incorrectly documented, etc.
9  *
10  * It allows hooking the stateful parts of the API to see changes as they
11  * happen.
12  *
13  * Allocation hooks are called after the allocation is done, free hooks are
14  * called before the free is done, and expand hooks are called after the
15  * allocation is expanded.
16  *
17  * For realloc and rallocx, if the expansion happens in place, the expansion
18  * hook is called.  If it is moved, then the alloc hook is called on the new
19  * location, and then the free hook is called on the old location (i.e. both
20  * hooks are invoked in between the alloc and the dalloc).
21  *
22  * If we return NULL from OOM, then usize might not be trustworthy.  Calling
23  * realloc(NULL, size) only calls the alloc hook, and calling realloc(ptr, 0)
24  * only calls the free hook.  (Calling realloc(NULL, 0) is treated as malloc(0),
25  * and only calls the alloc hook).
26  *
27  * Reentrancy:
28  *   Reentrancy is guarded against from within the hook implementation.  If you
29  *   call allocator functions from within a hook, the hooks will not be invoked
30  *   again.
31  * Threading:
32  *   The installation of a hook synchronizes with all its uses.  If you can
33  *   prove the installation of a hook happens-before a jemalloc entry point,
34  *   then the hook will get invoked (unless there's a racing removal).
35  *
36  *   Hook insertion appears to be atomic at a per-thread level (i.e. if a thread
37  *   allocates and has the alloc hook invoked, then a subsequent free on the
38  *   same thread will also have the free hook invoked).
39  *
40  *   The *removal* of a hook does *not* block until all threads are done with
41  *   the hook.  Hook authors have to be resilient to this, and need some
42  *   out-of-band mechanism for cleaning up any dynamically allocated memory
43  *   associated with their hook.
44  * Ordering:
45  *   Order of hook execution is unspecified, and may be different than insertion
46  *   order.
47  */
48
49 #define HOOK_MAX 4
50
51 enum hook_alloc_e {
52         hook_alloc_malloc,
53         hook_alloc_posix_memalign,
54         hook_alloc_aligned_alloc,
55         hook_alloc_calloc,
56         hook_alloc_memalign,
57         hook_alloc_valloc,
58         hook_alloc_mallocx,
59
60         /* The reallocating functions have both alloc and dalloc variants */
61         hook_alloc_realloc,
62         hook_alloc_rallocx,
63 };
64 /*
65  * We put the enum typedef after the enum, since this file may get included by
66  * jemalloc_cpp.cpp, and C++ disallows enum forward declarations.
67  */
68 typedef enum hook_alloc_e hook_alloc_t;
69
70 enum hook_dalloc_e {
71         hook_dalloc_free,
72         hook_dalloc_dallocx,
73         hook_dalloc_sdallocx,
74
75         /*
76          * The dalloc halves of reallocation (not called if in-place expansion
77          * happens).
78          */
79         hook_dalloc_realloc,
80         hook_dalloc_rallocx,
81 };
82 typedef enum hook_dalloc_e hook_dalloc_t;
83
84
85 enum hook_expand_e {
86         hook_expand_realloc,
87         hook_expand_rallocx,
88         hook_expand_xallocx,
89 };
90 typedef enum hook_expand_e hook_expand_t;
91
92 typedef void (*hook_alloc)(
93     void *extra, hook_alloc_t type, void *result, uintptr_t result_raw,
94     uintptr_t args_raw[3]);
95
96 typedef void (*hook_dalloc)(
97     void *extra, hook_dalloc_t type, void *address, uintptr_t args_raw[3]);
98
99 typedef void (*hook_expand)(
100     void *extra, hook_expand_t type, void *address, size_t old_usize,
101     size_t new_usize, uintptr_t result_raw, uintptr_t args_raw[4]);
102
103 typedef struct hooks_s hooks_t;
104 struct hooks_s {
105         hook_alloc alloc_hook;
106         hook_dalloc dalloc_hook;
107         hook_expand expand_hook;
108         void *extra;
109 };
110
111 /*
112  * Begin implementation details; everything above this point might one day live
113  * in a public API.  Everything below this point never will.
114  */
115
116 /*
117  * The realloc pathways haven't gotten any refactoring love in a while, and it's
118  * fairly difficult to pass information from the entry point to the hooks.  We
119  * put the informaiton the hooks will need into a struct to encapsulate
120  * everything.
121  *
122  * Much of these pathways are force-inlined, so that the compiler can avoid
123  * materializing this struct until we hit an extern arena function.  For fairly
124  * goofy reasons, *many* of the realloc paths hit an extern arena function.
125  * These paths are cold enough that it doesn't matter; eventually, we should
126  * rewrite the realloc code to make the expand-in-place and the
127  * free-then-realloc paths more orthogonal, at which point we don't need to
128  * spread the hook logic all over the place.
129  */
130 typedef struct hook_ralloc_args_s hook_ralloc_args_t;
131 struct hook_ralloc_args_s {
132         /* I.e. as opposed to rallocx. */
133         bool is_realloc;
134         /*
135          * The expand hook takes 4 arguments, even if only 3 are actually used;
136          * we add an extra one in case the user decides to memcpy without
137          * looking too closely at the hooked function.
138          */
139         uintptr_t args[4];
140 };
141
142 /*
143  * Returns an opaque handle to be used when removing the hook.  NULL means that
144  * we couldn't install the hook.
145  */
146 bool hook_boot();
147
148 void *hook_install(tsdn_t *tsdn, hooks_t *hooks);
149 /* Uninstalls the hook with the handle previously returned from hook_install. */
150 void hook_remove(tsdn_t *tsdn, void *opaque);
151
152 /* Hooks */
153
154 void hook_invoke_alloc(hook_alloc_t type, void *result, uintptr_t result_raw,
155     uintptr_t args_raw[3]);
156
157 void hook_invoke_dalloc(hook_dalloc_t type, void *address,
158     uintptr_t args_raw[3]);
159
160 void hook_invoke_expand(hook_expand_t type, void *address, size_t old_usize,
161     size_t new_usize, uintptr_t result_raw, uintptr_t args_raw[4]);
162
163 #endif /* JEMALLOC_INTERNAL_HOOK_H */