File Coverage

xsh/threads.h
Criterion Covered Total %
statement 15 15 100.0
branch 2 4 50.0
condition n/a
subroutine n/a
pod n/a
total 17 19 89.4


line stmt bran cond sub pod time code
1             #ifndef XSH_THREADS_H
2             #define XSH_THREADS_H 1
3              
4             #include "caps.h" /* XSH_HAS_PERL(), XSH_THREADSAFE */
5             #include "util.h" /* XSH_PACKAGE, dNOOP, NOOP */
6             #include "mem.h" /* XSH_SHARED_*() */
7              
8             #ifndef XSH_THREADS_COMPILE_TIME_PROTECTION
9             # define XSH_THREADS_COMPILE_TIME_PROTECTION 0
10             #endif
11              
12             #ifndef XSH_THREADS_USER_CONTEXT
13             # define XSH_THREADS_USER_CONTEXT 1
14             #endif
15              
16             #ifndef XSH_THREADS_USER_GLOBAL_SETUP
17             # define XSH_THREADS_USER_GLOBAL_SETUP 1
18             #endif
19              
20             #ifndef XSH_THREADS_USER_LOCAL_SETUP
21             # define XSH_THREADS_USER_LOCAL_SETUP 1
22             #endif
23              
24             #ifndef XSH_THREADS_USER_LOCAL_TEARDOWN
25             # define XSH_THREADS_USER_LOCAL_TEARDOWN 1
26             #endif
27              
28             #ifndef XSH_THREADS_USER_GLOBAL_TEARDOWN
29             # define XSH_THREADS_USER_GLOBAL_TEARDOWN 1
30             #endif
31              
32             #ifndef XSH_THREADS_PEEP_CONTEXT
33             # define XSH_THREADS_PEEP_CONTEXT 0
34             #endif
35              
36             #ifndef XSH_THREADS_HINTS_CONTEXT
37             # define XSH_THREADS_HINTS_CONTEXT 0
38             #endif
39              
40             #ifndef XSH_THREADS_USER_CLONE_NEEDS_DUP
41             # define XSH_THREADS_USER_CLONE_NEEDS_DUP 0
42             #endif
43              
44             #if XSH_THREADSAFE && (XSH_THREADS_HINTS_CONTEXT || XSH_THREADS_USER_CLONE_NEEDS_DUP)
45             # define XSH_THREADS_CLONE_NEEDS_DUP 1
46             #else
47             # define XSH_THREADS_CLONE_NEEDS_DUP 0
48             #endif
49              
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
52             #endif
53              
54             #ifndef XSH_THREADS_NEED_TEARDOWN_LATE
55             # define XSH_THREADS_NEED_TEARDOWN_LATE 0
56             #endif
57              
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
60             #endif
61              
62             #if XSH_THREADSAFE
63             # ifndef MY_CXT_CLONE
64             # define MY_CXT_CLONE \
65             dMY_CXT_SV; \
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))
69             # endif
70             #else
71             # undef dMY_CXT
72             # define dMY_CXT dNOOP
73             # undef MY_CXT
74             # define MY_CXT xsh_globaldata
75             # undef START_MY_CXT
76             # define START_MY_CXT static my_cxt_t MY_CXT;
77             # undef MY_CXT_INIT
78             # define MY_CXT_INIT NOOP
79             # undef MY_CXT_CLONE
80             # define MY_CXT_CLONE NOOP
81             #endif
82              
83             #if XSH_THREADSAFE
84             /* We must use preexistent global mutexes or we will never be able to destroy
85             * them. */
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)
89             # else
90             # define XSH_LOADED_LOCK OP_REFCNT_LOCK
91             # define XSH_LOADED_UNLOCK OP_REFCNT_UNLOCK
92             # endif
93             #else
94             # define XSH_LOADED_LOCK NOOP
95             # define XSH_LOADED_UNLOCK NOOP
96             #endif
97              
98             static I32 xsh_loaded = 0;
99              
100             #if XSH_THREADSAFE && XSH_THREADS_COMPILE_TIME_PROTECTION
101              
102             #define PTABLE_USE_DEFAULT 1
103              
104             #include "ptable.h"
105              
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))
109              
110             static ptable *xsh_loaded_cxts = NULL;
111              
112             static int xsh_is_loaded(pTHX_ void *cxt) {
113             #define xsh_is_loaded(C) xsh_is_loaded(aTHX_ (C))
114             int res = 0;
115              
116             XSH_LOADED_LOCK;
117             if (xsh_loaded_cxts && ptable_fetch(xsh_loaded_cxts, cxt))
118             res = 1;
119             XSH_LOADED_UNLOCK;
120              
121             return res;
122             }
123              
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;
127              
128             if (xsh_loaded <= 0) {
129             XSH_ASSERT(xsh_loaded == 0);
130             XSH_ASSERT(!xsh_loaded_cxts);
131             xsh_loaded_cxts = ptable_new(4);
132             global_setup = 1;
133             }
134             ++xsh_loaded;
135             XSH_ASSERT(xsh_loaded_cxts);
136             ptable_loaded_store(xsh_loaded_cxts, cxt, cxt);
137              
138             return global_setup;
139             }
140              
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;
144              
145             if (xsh_loaded > 1) {
146             XSH_ASSERT(xsh_loaded_cxts);
147             ptable_loaded_delete(xsh_loaded_cxts, cxt);
148             --xsh_loaded;
149             } else if (xsh_loaded_cxts) {
150             XSH_ASSERT(xsh_loaded == 1);
151             ptable_loaded_free(xsh_loaded_cxts);
152             xsh_loaded_cxts = NULL;
153             xsh_loaded = 0;
154             global_teardown = 1;
155             }
156              
157             return global_teardown;
158             }
159              
160             #else /* XSH_THREADS_COMPILE_TIME_PROTECTION */
161              
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)
165              
166             #if XSH_THREADSAFE
167              
168             static int xsh_is_loaded(pTHX_ void *cxt) {
169             #define xsh_is_loaded(C) xsh_is_loaded(aTHX_ (C))
170             int res = 0;
171              
172             XSH_LOADED_LOCK;
173             res = xsh_is_loaded_locked(cxt);
174             XSH_LOADED_UNLOCK;
175              
176             return res;
177             }
178              
179             #else
180              
181             #define xsh_is_loaded(C) xsh_is_loaded_locked(C)
182              
183             #endif
184              
185             #endif /* !XSH_THREADS_COMPILE_TIME_PROTECTION */
186              
187             #define MY_CXT_KEY XSH_PACKAGE "::_guts" XS_VERSION
188              
189             typedef struct {
190             #if XSH_THREADS_USER_CONTEXT
191             xsh_user_cxt_t cxt_user;
192             #endif
193             #if XSH_THREADS_PEEP_CONTEXT
194             xsh_peep_cxt_t cxt_peep;
195             #endif
196             #if XSH_THREADS_HINTS_CONTEXT
197             xsh_hints_cxt_t cxt_hints;
198             #endif
199             #if XSH_THREADS_CLONE_NEEDS_DUP
200             tTHX owner;
201             #endif
202             #if !(XSH_THREADS_USER_CONTEXT || XSH_THREADS_PEEP_CONTEXT || XSH_THREADS_HINTS_CONTEXT || XSH_THREADS_CLONE_NEEDS_DUP)
203             int dummy;
204             #endif
205             } my_cxt_t;
206              
207             START_MY_CXT
208              
209             #if XSH_THREADS_USER_CONTEXT
210             # define dXSH_CXT dMY_CXT
211             # define XSH_CXT (MY_CXT.cxt_user)
212             #endif
213              
214             #if XSH_THREADS_USER_GLOBAL_SETUP
215             static void xsh_user_global_setup(pTHX);
216             #endif
217              
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);
221             # else
222             static void xsh_user_local_setup(pTHX);
223             # endif
224             #endif
225              
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);
229             # else
230             static void xsh_user_local_teardown(pTHX);
231             # endif
232             #endif
233              
234             #if XSH_THREADS_USER_GLOBAL_TEARDOWN
235             static void xsh_user_global_teardown(pTHX);
236             #endif
237              
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);
241             # else
242             static void xsh_user_clone(pTHX_ const xsh_user_cxt_t *old_cxt, xsh_user_cxt_t *new_cxt);
243             # endif
244             #endif
245              
246             #if XSH_THREADS_PEEP_CONTEXT
247 5688           static xsh_peep_cxt_t *xsh_peep_get_cxt(pTHX) {
248             dMY_CXT;
249             XSH_ASSERT(xsh_is_loaded(&MY_CXT));
250 5688           return &MY_CXT.cxt_peep;
251             }
252             #endif
253              
254             #if XSH_THREADS_HINTS_CONTEXT
255             static xsh_hints_cxt_t *xsh_hints_get_cxt(pTHX) {
256             dMY_CXT;
257             XSH_ASSERT(xsh_is_loaded(&MY_CXT));
258             return &MY_CXT.cxt_hints;
259             }
260             #endif
261              
262             #if XSH_THREADS_NEED_TEARDOWN_LATE
263              
264             typedef void (*xsh_teardown_late_cb)(pTHX_ void *ud);
265              
266             static int xsh_teardown_late_simple_free(pTHX_ SV *sv, MAGIC *mg) {
267             xsh_teardown_late_cb cb;
268              
269             cb = DPTR2FPTR(xsh_teardown_late_cb, mg->mg_ptr);
270              
271             XSH_LOADED_LOCK;
272             if (xsh_loaded == 0)
273             cb(aTHX_ NULL);
274             XSH_LOADED_UNLOCK;
275              
276             return 0;
277             }
278              
279             static MGVTBL xsh_teardown_late_simple_vtbl = {
280             0,
281             0,
282             0,
283             0,
284             xsh_teardown_late_simple_free
285             #if MGf_COPY
286             , 0
287             #endif
288             #if MGf_DUP
289             , 0
290             #endif
291             #if MGf_LOCAL
292             , 0
293             #endif
294             };
295              
296             typedef struct {
297             xsh_teardown_late_cb cb;
298             void *ud;
299             } xsh_teardown_late_token;
300              
301             static int xsh_teardown_late_arg_free(pTHX_ SV *sv, MAGIC *mg) {
302             xsh_teardown_late_token *tok;
303              
304             tok = (xsh_teardown_late_token *) mg->mg_ptr;
305              
306             XSH_LOADED_LOCK;
307             if (xsh_loaded == 0)
308             tok->cb(aTHX_ tok->ud);
309             XSH_LOADED_UNLOCK;
310              
311             XSH_SHARED_FREE(tok, 1, xsh_teardown_late_token);
312              
313             return 0;
314             }
315              
316             static MGVTBL xsh_teardown_late_arg_vtbl = {
317             0,
318             0,
319             0,
320             0,
321             xsh_teardown_late_arg_free
322             #if MGf_COPY
323             , 0
324             #endif
325             #if MGf_DUP
326             , 0
327             #endif
328             #if MGf_LOCAL
329             , 0
330             #endif
331             };
332              
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))
335             void *ptr;
336              
337             if (!ud) {
338             ptr = FPTR2DPTR(void *, cb);
339             } else {
340             xsh_teardown_late_token *tok;
341              
342             XSH_SHARED_ALLOC(tok, 1, xsh_teardown_late_token);
343             tok->cb = cb;
344             tok->ud = ud;
345              
346             ptr = tok;
347             }
348              
349             if (!PL_strtab)
350             PL_strtab = newHV();
351              
352             sv_magicext((SV *) PL_strtab, NULL, PERL_MAGIC_ext,
353             ud ? &xsh_teardown_late_arg_vtbl : &xsh_teardown_late_simple_vtbl,
354             ptr, 0);
355              
356             return;
357             }
358              
359             #endif /* XSH_THREADS_NEED_TEARDOWN_LATE */
360              
361 15           static void xsh_teardown(pTHX_ void *root) {
362             dMY_CXT;
363              
364             #if XSH_THREADS_USER_LOCAL_TEARDOWN
365             # if XSH_THREADS_USER_CONTEXT
366 15           xsh_user_local_teardown(aTHX_ &XSH_CXT);
367             # else
368             xsh_user_local_teardown(aTHX);
369             # endif
370             #endif
371              
372             #if XSH_THREADS_PEEP_CONTEXT
373 15           xsh_peep_local_teardown(aTHX_ &MY_CXT.cxt_peep);
374             #endif
375              
376             #if XSH_THREADS_HINTS_CONTEXT
377             xsh_hints_local_teardown(aTHX_ &MY_CXT.cxt_hints);
378             #endif
379              
380             XSH_LOADED_LOCK;
381              
382 15 50         if (xsh_clear_loaded_locked(&MY_CXT)) {
383             #if XSH_THREADS_USER_GLOBAL_TEARDOWN
384 15           xsh_user_global_teardown(aTHX);
385             #endif
386              
387             #if XSH_THREADS_HINTS_CONTEXT
388             xsh_hints_global_teardown(aTHX);
389             #endif
390             }
391              
392             XSH_LOADED_UNLOCK;
393              
394 15           return;
395             }
396              
397 15           static void xsh_setup(pTHX) {
398             #define xsh_setup() xsh_setup(aTHX)
399             MY_CXT_INIT; /* Takes/release PL_my_ctx_mutex */
400              
401             XSH_LOADED_LOCK;
402              
403 15 50         if (xsh_set_loaded_locked(&MY_CXT)) {
404             #if XSH_THREADS_HINTS_CONTEXT
405             xsh_hints_global_setup(aTHX);
406             #endif
407              
408             #if XSH_THREADS_USER_GLOBAL_SETUP
409 15           xsh_user_global_setup(aTHX);
410             #endif
411             }
412              
413             XSH_LOADED_UNLOCK;
414              
415             #if XSH_THREADS_CLONE_NEEDS_DUP
416             MY_CXT.owner = aTHX;
417             #endif
418              
419             #if XSH_THREADS_HINTS_CONTEXT
420             xsh_hints_local_setup(aTHX_ &MY_CXT.cxt_hints);
421             #endif
422              
423             #if XSH_THREADS_PEEP_CONTEXT
424 15           xsh_peep_local_setup(aTHX_ &MY_CXT.cxt_peep);
425             #endif
426              
427             #if XSH_THREADS_USER_LOCAL_SETUP
428             # if XSH_THREADS_USER_CONTEXT
429 15           xsh_user_local_setup(aTHX_ &XSH_CXT);
430             # else
431             xsh_user_local_setup(aTHX);
432             # endif
433             #endif
434              
435 15           call_atexit(xsh_teardown, NULL);
436              
437 15           return;
438             }
439              
440             #if XSH_THREADSAFE
441              
442             static void xsh_clone(pTHX) {
443             #define xsh_clone() xsh_clone(aTHX)
444             const my_cxt_t *old_cxt;
445             my_cxt_t *new_cxt;
446              
447             {
448             dMY_CXT;
449             old_cxt = &MY_CXT;
450             }
451              
452             {
453             int global_setup;
454              
455             MY_CXT_CLONE;
456             new_cxt = &MY_CXT;
457              
458             XSH_LOADED_LOCK;
459             global_setup = xsh_set_loaded_locked(new_cxt);
460             XSH_ASSERT(!global_setup);
461             XSH_LOADED_UNLOCK;
462              
463             #if XSH_THREADS_CLONE_NEEDS_DUP
464             new_cxt->owner = aTHX;
465             #endif
466             }
467              
468             {
469             #if XSH_THREADS_CLONE_NEEDS_DUP
470             XSH_DUP_PARAMS_TYPE params;
471             xsh_dup_params_init(params, old_cxt->owner);
472             #endif
473              
474             #if XSH_THREADS_PEEP_CONTEXT
475             xsh_peep_clone(aTHX_ &old_cxt->cxt_peep, &new_cxt->cxt_peep);
476             #endif
477              
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));
481             #endif
482              
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));
487             # else
488             xsh_user_clone(aTHX_ &old_cxt->cxt_user, &new_cxt->cxt_user);
489             # endif
490             #endif
491              
492             #if XSH_THREADS_CLONE_NEEDS_DUP
493             xsh_dup_params_deinit(params);
494             #endif
495             }
496              
497             return;
498             }
499              
500             #endif /* XSH_THREADSAFE */
501              
502             #endif /* XSH_THREADS_H */