2 #define XSH_THREADS_H 1
4 #include "caps.h" /* XSH_HAS_PERL(), XSH_THREADSAFE */
5 #include "util.h" /* XSH_PACKAGE, dNOOP, NOOP */
7 #ifndef XSH_THREADS_COMPILE_TIME_PROTECTION
8 # define XSH_THREADS_COMPILE_TIME_PROTECTION 0
11 #ifndef XSH_THREADS_USER_CONTEXT
12 # define XSH_THREADS_USER_CONTEXT 1
15 #ifndef XSH_THREADS_USER_GLOBAL_SETUP
16 # define XSH_THREADS_USER_GLOBAL_SETUP 1
19 #ifndef XSH_THREADS_USER_LOCAL_SETUP
20 # define XSH_THREADS_USER_LOCAL_SETUP 1
23 #ifndef XSH_THREADS_USER_LOCAL_TEARDOWN
24 # define XSH_THREADS_USER_LOCAL_TEARDOWN 1
27 #ifndef XSH_THREADS_USER_GLOBAL_TEARDOWN
28 # define XSH_THREADS_USER_GLOBAL_TEARDOWN 1
31 #ifndef XSH_THREADS_PEEP_CONTEXT
32 # define XSH_THREADS_PEEP_CONTEXT 0
35 #ifndef XSH_THREADS_HINTS_CONTEXT
36 # define XSH_THREADS_HINTS_CONTEXT 0
39 #ifndef XSH_THREADS_USER_CLONE_NEEDS_DUP
40 # define XSH_THREADS_USER_CLONE_NEEDS_DUP 0
43 #if XSH_THREADSAFE && (XSH_THREADS_HINTS_CONTEXT || XSH_THREADS_USER_CLONE_NEEDS_DUP)
44 # define XSH_THREADS_CLONE_NEEDS_DUP 1
46 # define XSH_THREADS_CLONE_NEEDS_DUP 0
49 #if defined(XSH_OPS_H) && (!XSH_THREADS_GLOBAL_SETUP || !XSH_THREADS_GLOBAL_TEARDOWN)
50 # error settting up hook check functions require global setup/teardown
53 #ifndef XSH_THREADS_NEED_TEARDOWN_LATE
54 # define XSH_THREADS_NEED_TEARDOWN_LATE 0
57 #if XSH_THREADS_NEED_TEARDOWN_LATE && (!XSH_THREADS_USER_LOCAL_TEARDOWN || !XSH_THREADS_USER_GLOBAL_TEARDOWN)
58 # error you need to declare local or global teardown handlers to use the late teardown feature
63 # define MY_CXT_CLONE \
65 my_cxt_t *my_cxtp = (my_cxt_t*)SvPVX(newSV(sizeof(my_cxt_t)-1)); \
66 Copy(INT2PTR(my_cxt_t*, SvUV(my_cxt_sv)), my_cxtp, 1, my_cxt_t); \
67 sv_setuv(my_cxt_sv, PTR2UV(my_cxtp))
71 # define dMY_CXT dNOOP
73 # define MY_CXT xsh_globaldata
75 # define START_MY_CXT static my_cxt_t MY_CXT;
77 # define MY_CXT_INIT NOOP
79 # define MY_CXT_CLONE NOOP
83 /* We must use preexistent global mutexes or we will never be able to destroy
85 # if XSH_HAS_PERL(5, 9, 3)
86 # define XSH_LOADED_LOCK MUTEX_LOCK(&PL_my_ctx_mutex)
87 # define XSH_LOADED_UNLOCK MUTEX_UNLOCK(&PL_my_ctx_mutex)
89 # define XSH_LOADED_LOCK OP_REFCNT_LOCK
90 # define XSH_LOADED_UNLOCK OP_REFCNT_UNLOCK
93 # define XSH_LOADED_LOCK NOOP
94 # define XSH_LOADED_UNLOCK NOOP
97 static I32 xsh_loaded = 0;
99 #if XSH_THREADSAFE && XSH_THREADS_COMPILE_TIME_PROTECTION
101 #define PTABLE_USE_DEFAULT 1
105 #define ptable_loaded_store(T, K, V) ptable_default_store(aPTBL_ (T), (K), (V))
106 #define ptable_loaded_delete(T, K) ptable_default_delete(aPTBL_ (T), (K))
107 #define ptable_loaded_free(T) ptable_default_free(aPTBL_ (T))
109 static ptable *xsh_loaded_cxts = NULL;
111 static int xsh_is_loaded(pTHX_ void *cxt) {
112 #define xsh_is_loaded(C) xsh_is_loaded(aTHX_ (C))
116 if (xsh_loaded_cxts && ptable_fetch(xsh_loaded_cxts, cxt))
123 static int xsh_set_loaded_locked(pTHX_ void *cxt) {
124 #define xsh_set_loaded_locked(C) xsh_set_loaded_locked(aTHX_ (C))
125 int global_setup = 0;
127 if (xsh_loaded <= 0) {
128 XSH_ASSERT(xsh_loaded == 0);
129 XSH_ASSERT(!xsh_loaded_cxts);
130 xsh_loaded_cxts = ptable_new(4);
134 XSH_ASSERT(xsh_loaded_cxts);
135 ptable_loaded_store(xsh_loaded_cxts, cxt, cxt);
140 static int xsh_clear_loaded_locked(pTHX_ void *cxt) {
141 #define xsh_clear_loaded_locked(C) xsh_clear_loaded_locked(aTHX_ (C))
142 int global_teardown = 0;
144 if (xsh_loaded > 1) {
145 XSH_ASSERT(xsh_loaded_cxts);
146 ptable_loaded_delete(xsh_loaded_cxts, cxt);
148 } else if (xsh_loaded_cxts) {
149 XSH_ASSERT(xsh_loaded == 1);
150 ptable_loaded_free(xsh_loaded_cxts);
151 xsh_loaded_cxts = NULL;
156 return global_teardown;
159 #else /* XSH_THREADS_COMPILE_TIME_PROTECTION */
161 #define xsh_is_loaded_locked(C) (xsh_loaded > 0)
162 #define xsh_set_loaded_locked(C) ((xsh_loaded++ <= 0) ? 1 : 0)
163 #define xsh_clear_loaded_locked(C) ((--xsh_loaded <= 0) ? 1 : 0)
167 static int xsh_is_loaded(pTHX_ void *cxt) {
168 #define xsh_is_loaded(C) xsh_is_loaded(aTHX_ (C))
172 res = xsh_is_loaded_locked(cxt);
180 #define xsh_is_loaded(C) xsh_is_loaded_locked(C)
184 #endif /* !XSH_THREADS_COMPILE_TIME_PROTECTION */
186 #define MY_CXT_KEY XSH_PACKAGE "::_guts" XS_VERSION
189 #if XSH_THREADS_USER_CONTEXT
190 xsh_user_cxt_t cxt_user;
192 #if XSH_THREADS_PEEP_CONTEXT
193 xsh_peep_cxt_t cxt_peep;
195 #if XSH_THREADS_HINTS_CONTEXT
196 xsh_hints_cxt_t cxt_hints;
198 #if XSH_THREADS_CLONE_NEEDS_DUP
201 #if !(XSH_THREADS_USER_CONTEXT || XSH_THREADS_PEEP_CONTEXT || XSH_THREADS_HINTS_CONTEXT || XSH_THREADS_CLONE_NEEDS_DUP)
208 #if XSH_THREADS_USER_CONTEXT
209 # define dXSH_CXT dMY_CXT
210 # define XSH_CXT (MY_CXT.cxt_user)
213 #if XSH_THREADS_USER_GLOBAL_SETUP
214 static void xsh_user_global_setup(pTHX);
217 #if XSH_THREADS_USER_LOCAL_SETUP
218 # if XSH_THREADS_USER_CONTEXT
219 static void xsh_user_local_setup(pTHX_ xsh_user_cxt_t *cxt);
221 static void xsh_user_local_setup(pTHX);
225 #if XSH_THREADS_USER_LOCAL_TEARDOWN
226 # if XSH_THREADS_USER_CONTEXT
227 static void xsh_user_local_teardown(pTHX_ xsh_user_cxt_t *cxt);
229 static void xsh_user_local_teardown(pTHX);
233 #if XSH_THREADS_USER_GLOBAL_TEARDOWN
234 static void xsh_user_global_teardown(pTHX);
237 #if XSH_THREADSAFE && XSH_THREADS_USER_CONTEXT
238 # if XSH_THREADS_USER_CLONE_NEEDS_DUP
239 static void xsh_user_clone(pTHX_ const xsh_user_cxt_t *old_cxt, xsh_user_cxt_t *new_cxt, CLONE_PARAMS *params);
241 static void xsh_user_clone(pTHX_ const xsh_user_cxt_t *old_cxt, xsh_user_cxt_t *new_cxt);
245 #if XSH_THREADS_PEEP_CONTEXT
246 static xsh_peep_cxt_t *xsh_peep_get_cxt(pTHX) {
248 XSH_ASSERT(xsh_is_loaded(&MY_CXT));
249 return &MY_CXT.cxt_peep;
253 #if XSH_THREADS_HINTS_CONTEXT
254 static xsh_hints_cxt_t *xsh_hints_get_cxt(pTHX) {
256 XSH_ASSERT(xsh_is_loaded(&MY_CXT));
257 return &MY_CXT.cxt_hints;
261 #if XSH_THREADS_NEED_TEARDOWN_LATE
263 typedef void (*xsh_teardown_late_cb)(pTHX_ void *ud);
265 static int xsh_teardown_late_simple_free(pTHX_ SV *sv, MAGIC *mg) {
266 xsh_teardown_late_cb cb;
268 cb = DPTR2FPTR(xsh_teardown_late_cb, mg->mg_ptr);
278 static MGVTBL xsh_teardown_late_simple_vtbl = {
283 xsh_teardown_late_simple_free
296 xsh_teardown_late_cb cb;
298 } xsh_teardown_late_token;
300 static int xsh_teardown_late_arg_free(pTHX_ SV *sv, MAGIC *mg) {
301 xsh_teardown_late_token *tok;
303 tok = (xsh_teardown_late_token *) mg->mg_ptr;
307 tok->cb(aTHX_ tok->ud);
310 PerlMemShared_free(tok);
315 static MGVTBL xsh_teardown_late_arg_vtbl = {
320 xsh_teardown_late_arg_free
332 static void xsh_teardown_late_register(pTHX_ xsh_teardown_late_cb cb, void *ud){
333 #define xsh_teardown_late_register(CB, UD) xsh_teardown_late_register(aTHX_ (CB), (UD))
337 ptr = FPTR2DPTR(void *, cb);
339 xsh_teardown_late_token *tok;
341 tok = PerlMemShared_malloc(sizeof *tok);
351 sv_magicext((SV *) PL_strtab, NULL, PERL_MAGIC_ext,
352 ud ? &xsh_teardown_late_arg_vtbl : &xsh_teardown_late_simple_vtbl,
358 #endif /* XSH_THREADS_NEED_TEARDOWN_LATE */
360 static void xsh_teardown(pTHX_ void *root) {
363 #if XSH_THREADS_USER_LOCAL_TEARDOWN
364 # if XSH_THREADS_USER_CONTEXT
365 xsh_user_local_teardown(aTHX_ &XSH_CXT);
367 xsh_user_local_teardown(aTHX);
371 #if XSH_THREADS_PEEP_CONTEXT
372 xsh_peep_local_teardown(aTHX_ &MY_CXT.cxt_peep);
375 #if XSH_THREADS_HINTS_CONTEXT
376 xsh_hints_local_teardown(aTHX_ &MY_CXT.cxt_hints);
381 if (xsh_clear_loaded_locked(&MY_CXT)) {
382 #if XSH_THREADS_USER_GLOBAL_TEARDOWN
383 xsh_user_global_teardown(aTHX);
386 #if XSH_THREADS_HINTS_CONTEXT
387 xsh_hints_global_teardown(aTHX);
396 static void xsh_setup(pTHX) {
397 #define xsh_setup() xsh_setup(aTHX)
398 MY_CXT_INIT; /* Takes/release PL_my_ctx_mutex */
402 if (xsh_set_loaded_locked(&MY_CXT)) {
403 #if XSH_THREADS_HINTS_CONTEXT
404 xsh_hints_global_setup(aTHX);
407 #if XSH_THREADS_USER_GLOBAL_SETUP
408 xsh_user_global_setup(aTHX);
414 #if XSH_THREADS_CLONE_NEEDS_DUP
418 #if XSH_THREADS_HINTS_CONTEXT
419 xsh_hints_local_setup(aTHX_ &MY_CXT.cxt_hints);
422 #if XSH_THREADS_PEEP_CONTEXT
423 xsh_peep_local_setup(aTHX_ &MY_CXT.cxt_peep);
426 #if XSH_THREADS_USER_LOCAL_SETUP
427 # if XSH_THREADS_USER_CONTEXT
428 xsh_user_local_setup(aTHX_ &XSH_CXT);
430 xsh_user_local_setup(aTHX);
434 call_atexit(xsh_teardown, NULL);
441 static void xsh_clone(pTHX) {
442 #define xsh_clone() xsh_clone(aTHX)
443 const my_cxt_t *old_cxt;
458 global_setup = xsh_set_loaded_locked(new_cxt);
459 XSH_ASSERT(!global_setup);
462 #if XSH_THREADS_CLONE_NEEDS_DUP
463 new_cxt->owner = aTHX;
468 #if XSH_THREADS_CLONE_NEEDS_DUP
469 XSH_DUP_PARAMS_TYPE params;
470 xsh_dup_params_init(params, old_cxt->owner);
473 #if XSH_THREADS_PEEP_CONTEXT
474 xsh_peep_clone(aTHX_ &old_cxt->cxt_peep, &new_cxt->cxt_peep);
477 #if XSH_THREADS_HINTS_CONTEXT
478 xsh_hints_clone(aTHX_ &old_cxt->cxt_hints, &new_cxt->cxt_hints,
479 xsh_dup_params_ptr(params));
482 #if XSH_THREADS_USER_CONTEXT
483 # if XSH_THREADS_USER_CLONE_NEEDS_DUP
484 xsh_user_clone(aTHX_ &old_cxt->cxt_user, &new_cxt->cxt_user,
485 xsh_dup_params_ptr(params));
487 xsh_user_clone(aTHX_ &old_cxt->cxt_user, &new_cxt->cxt_user);
491 #if XSH_THREADS_CLONE_NEEDS_DUP
492 xsh_dup_params_deinit(params);
499 #endif /* XSH_THREADSAFE */
501 #endif /* XSH_THREADS_H */