2 #define XSH_THREADS_H 1
4 #include "caps.h" /* XSH_HAS_PERL(), XSH_THREADSAFE */
5 #include "util.h" /* XSH_PACKAGE, dNOOP, NOOP */
6 #include "mem.h" /* XSH_SHARED_*() */
8 #ifndef XSH_THREADS_COMPILE_TIME_PROTECTION
9 # define XSH_THREADS_COMPILE_TIME_PROTECTION 0
12 #ifndef XSH_THREADS_USER_CONTEXT
13 # define XSH_THREADS_USER_CONTEXT 1
16 #ifndef XSH_THREADS_USER_GLOBAL_SETUP
17 # define XSH_THREADS_USER_GLOBAL_SETUP 1
20 #ifndef XSH_THREADS_USER_LOCAL_SETUP
21 # define XSH_THREADS_USER_LOCAL_SETUP 1
24 #ifndef XSH_THREADS_USER_LOCAL_TEARDOWN
25 # define XSH_THREADS_USER_LOCAL_TEARDOWN 1
28 #ifndef XSH_THREADS_USER_GLOBAL_TEARDOWN
29 # define XSH_THREADS_USER_GLOBAL_TEARDOWN 1
32 #ifndef XSH_THREADS_PEEP_CONTEXT
33 # define XSH_THREADS_PEEP_CONTEXT 0
36 #ifndef XSH_THREADS_HINTS_CONTEXT
37 # define XSH_THREADS_HINTS_CONTEXT 0
40 #ifndef XSH_THREADS_USER_CLONE_NEEDS_DUP
41 # define XSH_THREADS_USER_CLONE_NEEDS_DUP 0
44 #if XSH_THREADSAFE && (XSH_THREADS_HINTS_CONTEXT || XSH_THREADS_USER_CLONE_NEEDS_DUP)
45 # define XSH_THREADS_CLONE_NEEDS_DUP 1
47 # define XSH_THREADS_CLONE_NEEDS_DUP 0
50 #if defined(XSH_OPS_H) && (!XSH_THREADS_GLOBAL_SETUP || !XSH_THREADS_GLOBAL_TEARDOWN)
51 # error settting up hook check functions require global setup/teardown
54 #ifndef XSH_THREADS_NEED_TEARDOWN_LATE
55 # define XSH_THREADS_NEED_TEARDOWN_LATE 0
58 #if XSH_THREADS_NEED_TEARDOWN_LATE && (!XSH_THREADS_USER_LOCAL_TEARDOWN || !XSH_THREADS_USER_GLOBAL_TEARDOWN)
59 # error you need to declare local or global teardown handlers to use the late teardown feature
64 # define MY_CXT_CLONE \
66 my_cxt_t *my_cxtp = (my_cxt_t*)SvPVX(newSV(sizeof(my_cxt_t)-1)); \
67 Copy(INT2PTR(my_cxt_t*, SvUV(my_cxt_sv)), my_cxtp, 1, my_cxt_t); \
68 sv_setuv(my_cxt_sv, PTR2UV(my_cxtp))
72 # define dMY_CXT dNOOP
74 # define MY_CXT xsh_globaldata
76 # define START_MY_CXT static my_cxt_t MY_CXT;
78 # define MY_CXT_INIT NOOP
80 # define MY_CXT_CLONE NOOP
84 /* We must use preexistent global mutexes or we will never be able to destroy
86 # if XSH_HAS_PERL(5, 9, 3)
87 # define XSH_LOADED_LOCK MUTEX_LOCK(&PL_my_ctx_mutex)
88 # define XSH_LOADED_UNLOCK MUTEX_UNLOCK(&PL_my_ctx_mutex)
90 # define XSH_LOADED_LOCK OP_REFCNT_LOCK
91 # define XSH_LOADED_UNLOCK OP_REFCNT_UNLOCK
94 # define XSH_LOADED_LOCK NOOP
95 # define XSH_LOADED_UNLOCK NOOP
98 static I32 xsh_loaded = 0;
100 #if XSH_THREADSAFE && XSH_THREADS_COMPILE_TIME_PROTECTION
102 #define PTABLE_USE_DEFAULT 1
106 #define ptable_loaded_store(T, K, V) ptable_default_store(aPTBL_ (T), (K), (V))
107 #define ptable_loaded_delete(T, K) ptable_default_delete(aPTBL_ (T), (K))
108 #define ptable_loaded_free(T) ptable_default_free(aPTBL_ (T))
110 static ptable *xsh_loaded_cxts = NULL;
112 static int xsh_is_loaded(pTHX_ void *cxt) {
113 #define xsh_is_loaded(C) xsh_is_loaded(aTHX_ (C))
117 if (xsh_loaded_cxts && ptable_fetch(xsh_loaded_cxts, cxt))
124 static int xsh_set_loaded_locked(pTHX_ void *cxt) {
125 #define xsh_set_loaded_locked(C) xsh_set_loaded_locked(aTHX_ (C))
126 int global_setup = 0;
128 if (xsh_loaded <= 0) {
129 XSH_ASSERT(xsh_loaded == 0);
130 XSH_ASSERT(!xsh_loaded_cxts);
131 xsh_loaded_cxts = ptable_new(4);
135 XSH_ASSERT(xsh_loaded_cxts);
136 ptable_loaded_store(xsh_loaded_cxts, cxt, cxt);
141 static int xsh_clear_loaded_locked(pTHX_ void *cxt) {
142 #define xsh_clear_loaded_locked(C) xsh_clear_loaded_locked(aTHX_ (C))
143 int global_teardown = 0;
145 if (xsh_loaded > 1) {
146 XSH_ASSERT(xsh_loaded_cxts);
147 ptable_loaded_delete(xsh_loaded_cxts, cxt);
149 } else if (xsh_loaded_cxts) {
150 XSH_ASSERT(xsh_loaded == 1);
151 ptable_loaded_free(xsh_loaded_cxts);
152 xsh_loaded_cxts = NULL;
157 return global_teardown;
160 #else /* XSH_THREADS_COMPILE_TIME_PROTECTION */
162 #define xsh_is_loaded_locked(C) (xsh_loaded > 0)
163 #define xsh_set_loaded_locked(C) ((xsh_loaded++ <= 0) ? 1 : 0)
164 #define xsh_clear_loaded_locked(C) ((--xsh_loaded <= 0) ? 1 : 0)
168 static int xsh_is_loaded(pTHX_ void *cxt) {
169 #define xsh_is_loaded(C) xsh_is_loaded(aTHX_ (C))
173 res = xsh_is_loaded_locked(cxt);
181 #define xsh_is_loaded(C) xsh_is_loaded_locked(C)
185 #endif /* !XSH_THREADS_COMPILE_TIME_PROTECTION */
187 #define MY_CXT_KEY XSH_PACKAGE "::_guts" XS_VERSION
190 #if XSH_THREADS_USER_CONTEXT
191 xsh_user_cxt_t cxt_user;
193 #if XSH_THREADS_PEEP_CONTEXT
194 xsh_peep_cxt_t cxt_peep;
196 #if XSH_THREADS_HINTS_CONTEXT
197 xsh_hints_cxt_t cxt_hints;
199 #if XSH_THREADS_CLONE_NEEDS_DUP
202 #if !(XSH_THREADS_USER_CONTEXT || XSH_THREADS_PEEP_CONTEXT || XSH_THREADS_HINTS_CONTEXT || XSH_THREADS_CLONE_NEEDS_DUP)
209 #if XSH_THREADS_USER_CONTEXT
210 # define dXSH_CXT dMY_CXT
211 # define XSH_CXT (MY_CXT.cxt_user)
214 #if XSH_THREADS_USER_GLOBAL_SETUP
215 static void xsh_user_global_setup(pTHX);
218 #if XSH_THREADS_USER_LOCAL_SETUP
219 # if XSH_THREADS_USER_CONTEXT
220 static void xsh_user_local_setup(pTHX_ xsh_user_cxt_t *cxt);
222 static void xsh_user_local_setup(pTHX);
226 #if XSH_THREADS_USER_LOCAL_TEARDOWN
227 # if XSH_THREADS_USER_CONTEXT
228 static void xsh_user_local_teardown(pTHX_ xsh_user_cxt_t *cxt);
230 static void xsh_user_local_teardown(pTHX);
234 #if XSH_THREADS_USER_GLOBAL_TEARDOWN
235 static void xsh_user_global_teardown(pTHX);
238 #if XSH_THREADSAFE && XSH_THREADS_USER_CONTEXT
239 # if XSH_THREADS_USER_CLONE_NEEDS_DUP
240 static void xsh_user_clone(pTHX_ const xsh_user_cxt_t *old_cxt, xsh_user_cxt_t *new_cxt, CLONE_PARAMS *params);
242 static void xsh_user_clone(pTHX_ const xsh_user_cxt_t *old_cxt, xsh_user_cxt_t *new_cxt);
246 #if XSH_THREADS_PEEP_CONTEXT
247 static xsh_peep_cxt_t *xsh_peep_get_cxt(pTHX) {
249 XSH_ASSERT(xsh_is_loaded(&MY_CXT));
250 return &MY_CXT.cxt_peep;
254 #if XSH_THREADS_HINTS_CONTEXT
255 static xsh_hints_cxt_t *xsh_hints_get_cxt(pTHX) {
257 XSH_ASSERT(xsh_is_loaded(&MY_CXT));
258 return &MY_CXT.cxt_hints;
262 #if XSH_THREADS_NEED_TEARDOWN_LATE
264 typedef void (*xsh_teardown_late_cb)(pTHX_ void *ud);
266 static int xsh_teardown_late_simple_free(pTHX_ SV *sv, MAGIC *mg) {
267 xsh_teardown_late_cb cb;
269 cb = DPTR2FPTR(xsh_teardown_late_cb, mg->mg_ptr);
279 static MGVTBL xsh_teardown_late_simple_vtbl = {
284 xsh_teardown_late_simple_free
297 xsh_teardown_late_cb cb;
299 } xsh_teardown_late_token;
301 static int xsh_teardown_late_arg_free(pTHX_ SV *sv, MAGIC *mg) {
302 xsh_teardown_late_token *tok;
304 tok = (xsh_teardown_late_token *) mg->mg_ptr;
308 tok->cb(aTHX_ tok->ud);
311 XSH_SHARED_FREE(tok, 1, xsh_teardown_late_token);
316 static MGVTBL xsh_teardown_late_arg_vtbl = {
321 xsh_teardown_late_arg_free
333 static void xsh_teardown_late_register(pTHX_ xsh_teardown_late_cb cb, void *ud){
334 #define xsh_teardown_late_register(CB, UD) xsh_teardown_late_register(aTHX_ (CB), (UD))
338 ptr = FPTR2DPTR(void *, cb);
340 xsh_teardown_late_token *tok;
342 XSH_SHARED_ALLOC(tok, 1, xsh_teardown_late_token);
352 sv_magicext((SV *) PL_strtab, NULL, PERL_MAGIC_ext,
353 ud ? &xsh_teardown_late_arg_vtbl : &xsh_teardown_late_simple_vtbl,
359 #endif /* XSH_THREADS_NEED_TEARDOWN_LATE */
361 static void xsh_teardown(pTHX_ void *root) {
364 #if XSH_THREADS_USER_LOCAL_TEARDOWN
365 # if XSH_THREADS_USER_CONTEXT
366 xsh_user_local_teardown(aTHX_ &XSH_CXT);
368 xsh_user_local_teardown(aTHX);
372 #if XSH_THREADS_PEEP_CONTEXT
373 xsh_peep_local_teardown(aTHX_ &MY_CXT.cxt_peep);
376 #if XSH_THREADS_HINTS_CONTEXT
377 xsh_hints_local_teardown(aTHX_ &MY_CXT.cxt_hints);
382 if (xsh_clear_loaded_locked(&MY_CXT)) {
383 #if XSH_THREADS_USER_GLOBAL_TEARDOWN
384 xsh_user_global_teardown(aTHX);
387 #if XSH_THREADS_HINTS_CONTEXT
388 xsh_hints_global_teardown(aTHX);
397 static void xsh_setup(pTHX) {
398 #define xsh_setup() xsh_setup(aTHX)
399 MY_CXT_INIT; /* Takes/release PL_my_ctx_mutex */
403 if (xsh_set_loaded_locked(&MY_CXT)) {
404 #if XSH_THREADS_HINTS_CONTEXT
405 xsh_hints_global_setup(aTHX);
408 #if XSH_THREADS_USER_GLOBAL_SETUP
409 xsh_user_global_setup(aTHX);
415 #if XSH_THREADS_CLONE_NEEDS_DUP
419 #if XSH_THREADS_HINTS_CONTEXT
420 xsh_hints_local_setup(aTHX_ &MY_CXT.cxt_hints);
423 #if XSH_THREADS_PEEP_CONTEXT
424 xsh_peep_local_setup(aTHX_ &MY_CXT.cxt_peep);
427 #if XSH_THREADS_USER_LOCAL_SETUP
428 # if XSH_THREADS_USER_CONTEXT
429 xsh_user_local_setup(aTHX_ &XSH_CXT);
431 xsh_user_local_setup(aTHX);
435 call_atexit(xsh_teardown, NULL);
442 static void xsh_clone(pTHX) {
443 #define xsh_clone() xsh_clone(aTHX)
444 const my_cxt_t *old_cxt;
459 global_setup = xsh_set_loaded_locked(new_cxt);
460 XSH_ASSERT(!global_setup);
463 #if XSH_THREADS_CLONE_NEEDS_DUP
464 new_cxt->owner = aTHX;
469 #if XSH_THREADS_CLONE_NEEDS_DUP
470 XSH_DUP_PARAMS_TYPE params;
471 xsh_dup_params_init(params, old_cxt->owner);
474 #if XSH_THREADS_PEEP_CONTEXT
475 xsh_peep_clone(aTHX_ &old_cxt->cxt_peep, &new_cxt->cxt_peep);
478 #if XSH_THREADS_HINTS_CONTEXT
479 xsh_hints_clone(aTHX_ &old_cxt->cxt_hints, &new_cxt->cxt_hints,
480 xsh_dup_params_ptr(params));
483 #if XSH_THREADS_USER_CONTEXT
484 # if XSH_THREADS_USER_CLONE_NEEDS_DUP
485 xsh_user_clone(aTHX_ &old_cxt->cxt_user, &new_cxt->cxt_user,
486 xsh_dup_params_ptr(params));
488 xsh_user_clone(aTHX_ &old_cxt->cxt_user, &new_cxt->cxt_user);
492 #if XSH_THREADS_CLONE_NEEDS_DUP
493 xsh_dup_params_deinit(params);
500 #endif /* XSH_THREADSAFE */
502 #endif /* XSH_THREADS_H */