]> git.vpit.fr Git - perl/modules/VPIT-XSHelpers.git/blob - xsh/threads.h
Wrap memory-related functions into new helpers
[perl/modules/VPIT-XSHelpers.git] / xsh / threads.h
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 static xsh_peep_cxt_t *xsh_peep_get_cxt(pTHX) {
248  dMY_CXT;
249  XSH_ASSERT(xsh_is_loaded(&MY_CXT));
250  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 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  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  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  if (xsh_clear_loaded_locked(&MY_CXT)) {
383 #if XSH_THREADS_USER_GLOBAL_TEARDOWN
384   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  return;
395 }
396
397 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  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   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  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  xsh_user_local_setup(aTHX_ &XSH_CXT);
430 # else
431  xsh_user_local_setup(aTHX);
432 # endif
433 #endif
434
435  call_atexit(xsh_teardown, NULL);
436
437  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 */