]>
Commit | Line | Data |
---|---|---|
970d7e83 LB |
1 | #define JEMALLOC_TSD_C_ |
2 | #include "jemalloc/internal/jemalloc_internal.h" | |
3 | ||
4 | /******************************************************************************/ | |
5 | /* Data. */ | |
6 | ||
7 | static unsigned ncleanups; | |
8 | static malloc_tsd_cleanup_t cleanups[MALLOC_TSD_CLEANUPS_MAX]; | |
9 | ||
1a4d82fc JJ |
10 | malloc_tsd_data(, , tsd_t, TSD_INITIALIZER) |
11 | ||
970d7e83 LB |
12 | /******************************************************************************/ |
13 | ||
14 | void * | |
15 | malloc_tsd_malloc(size_t size) | |
16 | { | |
17 | ||
18 | /* Avoid choose_arena() in order to dodge bootstrapping issues. */ | |
1a4d82fc JJ |
19 | return (arena_malloc(NULL, arenas[0], CACHELINE_CEILING(size), false, |
20 | false)); | |
970d7e83 LB |
21 | } |
22 | ||
23 | void | |
24 | malloc_tsd_dalloc(void *wrapper) | |
25 | { | |
26 | ||
1a4d82fc | 27 | idalloct(NULL, wrapper, false); |
970d7e83 LB |
28 | } |
29 | ||
30 | void | |
31 | malloc_tsd_no_cleanup(void *arg) | |
32 | { | |
33 | ||
34 | not_reached(); | |
35 | } | |
36 | ||
37 | #if defined(JEMALLOC_MALLOC_THREAD_CLEANUP) || defined(_WIN32) | |
38 | #ifndef _WIN32 | |
39 | JEMALLOC_EXPORT | |
40 | #endif | |
41 | void | |
42 | _malloc_thread_cleanup(void) | |
43 | { | |
44 | bool pending[MALLOC_TSD_CLEANUPS_MAX], again; | |
45 | unsigned i; | |
46 | ||
47 | for (i = 0; i < ncleanups; i++) | |
48 | pending[i] = true; | |
49 | ||
50 | do { | |
51 | again = false; | |
52 | for (i = 0; i < ncleanups; i++) { | |
53 | if (pending[i]) { | |
54 | pending[i] = cleanups[i](); | |
55 | if (pending[i]) | |
56 | again = true; | |
57 | } | |
58 | } | |
59 | } while (again); | |
60 | } | |
61 | #endif | |
62 | ||
63 | void | |
64 | malloc_tsd_cleanup_register(bool (*f)(void)) | |
65 | { | |
66 | ||
67 | assert(ncleanups < MALLOC_TSD_CLEANUPS_MAX); | |
68 | cleanups[ncleanups] = f; | |
69 | ncleanups++; | |
70 | } | |
71 | ||
72 | void | |
1a4d82fc JJ |
73 | tsd_cleanup(void *arg) |
74 | { | |
75 | tsd_t *tsd = (tsd_t *)arg; | |
76 | ||
77 | switch (tsd->state) { | |
78 | case tsd_state_nominal: | |
79 | #define O(n, t) \ | |
80 | n##_cleanup(tsd); | |
81 | MALLOC_TSD | |
82 | #undef O | |
83 | tsd->state = tsd_state_purgatory; | |
84 | tsd_set(tsd); | |
85 | break; | |
86 | case tsd_state_purgatory: | |
87 | /* | |
88 | * The previous time this destructor was called, we set the | |
89 | * state to tsd_state_purgatory so that other destructors | |
90 | * wouldn't cause re-creation of the tsd. This time, do | |
91 | * nothing, and do not request another callback. | |
92 | */ | |
93 | break; | |
94 | case tsd_state_reincarnated: | |
95 | /* | |
96 | * Another destructor deallocated memory after this destructor | |
97 | * was called. Reset state to tsd_state_purgatory and request | |
98 | * another callback. | |
99 | */ | |
100 | tsd->state = tsd_state_purgatory; | |
101 | tsd_set(tsd); | |
102 | break; | |
103 | default: | |
104 | not_reached(); | |
105 | } | |
106 | } | |
107 | ||
108 | bool | |
970d7e83 LB |
109 | malloc_tsd_boot(void) |
110 | { | |
111 | ||
112 | ncleanups = 0; | |
1a4d82fc JJ |
113 | if (tsd_boot()) |
114 | return (true); | |
115 | return (false); | |
970d7e83 LB |
116 | } |
117 | ||
118 | #ifdef _WIN32 | |
119 | static BOOL WINAPI | |
120 | _tls_callback(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) | |
121 | { | |
122 | ||
123 | switch (fdwReason) { | |
124 | #ifdef JEMALLOC_LAZY_LOCK | |
125 | case DLL_THREAD_ATTACH: | |
126 | isthreaded = true; | |
127 | break; | |
128 | #endif | |
129 | case DLL_THREAD_DETACH: | |
130 | _malloc_thread_cleanup(); | |
131 | break; | |
132 | default: | |
133 | break; | |
134 | } | |
135 | return (true); | |
136 | } | |
137 | ||
138 | #ifdef _MSC_VER | |
139 | # ifdef _M_IX86 | |
140 | # pragma comment(linker, "/INCLUDE:__tls_used") | |
141 | # else | |
142 | # pragma comment(linker, "/INCLUDE:_tls_used") | |
143 | # endif | |
144 | # pragma section(".CRT$XLY",long,read) | |
145 | #endif | |
146 | JEMALLOC_SECTION(".CRT$XLY") JEMALLOC_ATTR(used) | |
147 | static const BOOL (WINAPI *tls_callback)(HINSTANCE hinstDLL, | |
148 | DWORD fdwReason, LPVOID lpvReserved) = _tls_callback; | |
149 | #endif | |
1a4d82fc JJ |
150 | |
151 | #if (!defined(JEMALLOC_MALLOC_THREAD_CLEANUP) && !defined(JEMALLOC_TLS) && \ | |
152 | !defined(_WIN32)) | |
153 | void * | |
154 | tsd_init_check_recursion(tsd_init_head_t *head, tsd_init_block_t *block) | |
155 | { | |
156 | pthread_t self = pthread_self(); | |
157 | tsd_init_block_t *iter; | |
158 | ||
159 | /* Check whether this thread has already inserted into the list. */ | |
160 | malloc_mutex_lock(&head->lock); | |
161 | ql_foreach(iter, &head->blocks, link) { | |
162 | if (iter->thread == self) { | |
163 | malloc_mutex_unlock(&head->lock); | |
164 | return (iter->data); | |
165 | } | |
166 | } | |
167 | /* Insert block into list. */ | |
168 | ql_elm_new(block, link); | |
169 | block->thread = self; | |
170 | ql_tail_insert(&head->blocks, block, link); | |
171 | malloc_mutex_unlock(&head->lock); | |
172 | return (NULL); | |
173 | } | |
174 | ||
175 | void | |
176 | tsd_init_finish(tsd_init_head_t *head, tsd_init_block_t *block) | |
177 | { | |
178 | ||
179 | malloc_mutex_lock(&head->lock); | |
180 | ql_remove(&head->blocks, block, link); | |
181 | malloc_mutex_unlock(&head->lock); | |
182 | } | |
183 | #endif |