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