]> git.vpit.fr Git - perl/modules/indirect.git/blobdiff - indirect.xs
Keep track of which thread-local contexts have been initialized
[perl/modules/indirect.git] / indirect.xs
index 3a977f04e8eb1b4468c3d2dc9a01ce056539c57a..f020a1f52508ccdaebef759f8cfa086f160d4bbe 100644 (file)
 # define HvNAMELEN_get(H) strlen(HvNAME_get(H))
 #endif
 
-#ifndef OP_SIBLING
-# define OP_SIBLING(O) ((O)->op_sibling)
+#ifndef OpSIBLING
+# ifdef OP_SIBLING
+#  define OpSIBLING(O) OP_SIBLING(O)
+# else
+#  define OpSIBLING(O) ((O)->op_sibling)
+# endif
 #endif
 
 #define I_HAS_PERL(R, V, S) (PERL_REVISION > (R) || (PERL_REVISION == (R) && (PERL_VERSION > (V) || (PERL_VERSION == (V) && (PERL_SUBVERSION >= (S))))))
 #endif
 
 #ifndef I_MULTIPLICITY
-# if defined(MULTIPLICITY) || defined(PERL_IMPLICIT_CONTEXT)
+# if defined(MULTIPLICITY)
 #  define I_MULTIPLICITY 1
 # else
 #  define I_MULTIPLICITY 0
 # endif
 #endif
+#if I_MULTIPLICITY
+# ifndef PERL_IMPLICIT_CONTEXT
+#  error MULTIPLICITY builds must set PERL_IMPLICIT_CONTEXT
+# endif
+#endif
 #if I_MULTIPLICITY && !defined(tTHX)
 # define tTHX PerlInterpreter*
 #endif
 # undef  MY_CXT
 # define MY_CXT       indirect_globaldata
 # undef  START_MY_CXT
-# define START_MY_CXT STATIC my_cxt_t MY_CXT;
+# define START_MY_CXT static my_cxt_t MY_CXT;
 # undef  MY_CXT_INIT
 # define MY_CXT_INIT  NOOP
 # undef  MY_CXT_CLONE
@@ -158,7 +167,7 @@ typedef OP *(*indirect_ck_t)(pTHX_ OP *);
 
 #else
 
-STATIC void indirect_ck_replace(pTHX_ OPCODE type, indirect_ck_t new_ck, indirect_ck_t *old_ck_p) {
+static void indirect_ck_replace(pTHX_ OPCODE type, indirect_ck_t new_ck, indirect_ck_t *old_ck_p) {
 #define indirect_ck_replace(T, NC, OCP) indirect_ck_replace(aTHX_ (T), (NC), (OCP))
  I_CHECK_MUTEX_LOCK;
  if (!*old_ck_p) {
@@ -170,7 +179,7 @@ STATIC void indirect_ck_replace(pTHX_ OPCODE type, indirect_ck_t new_ck, indirec
 
 #endif
 
-STATIC void indirect_ck_restore(pTHX_ OPCODE type, indirect_ck_t *old_ck_p) {
+static void indirect_ck_restore(pTHX_ OPCODE type, indirect_ck_t *old_ck_p) {
 #define indirect_ck_restore(T, OCP) indirect_ck_restore(aTHX_ (T), (OCP))
  I_CHECK_MUTEX_LOCK;
  if (*old_ck_p) {
@@ -182,6 +191,80 @@ STATIC void indirect_ck_restore(pTHX_ OPCODE type, indirect_ck_t *old_ck_p) {
 
 /* --- Helpers ------------------------------------------------------------- */
 
+/* ... Check if the module is loaded ....................................... */
+
+#if I_THREADSAFE
+
+#define PTABLE_NAME        ptable_loaded
+#define PTABLE_VAL_FREE(V) NOOP
+
+#include "ptable.h"
+
+#define ptable_loaded_store(T, K, V) ptable_loaded_store(aPTBLMS_ (T), (K), (V))
+#define ptable_loaded_delete(T, K)   ptable_loaded_delete(aPTBLMS_ (T), (K))
+#define ptable_loaded_free(T)        ptable_loaded_free(aPTBLMS_ (T))
+
+#define indirect_loaded()
+
+static ptable *indirect_loaded_cxts          = NULL;
+static U32     indirect_loaded_cxts_refcount = 0;
+
+/* We must use preexistent global mutexes or we will never be able to destroy
+ * them. */
+#if I_HAS_PERL(5, 9, 3)
+# define I_LOADED_LOCK   MUTEX_LOCK(&PL_my_ctx_mutex)
+# define I_LOADED_UNLOCK MUTEX_UNLOCK(&PL_my_ctx_mutex)
+#else
+# define I_LOADED_LOCK   OP_REFCNT_LOCK
+# define I_LOADED_UNLOCK OP_REFCNT_UNLOCK
+#endif
+
+static int indirect_is_loaded(pTHX_ void *cxt) {
+#define indirect_is_loaded(C) indirect_is_loaded(aTHX_ (C))
+ int res = 0;
+
+ I_LOADED_LOCK;
+ if (indirect_loaded_cxts && ptable_fetch(indirect_loaded_cxts, cxt))
+  res = 1;
+ I_LOADED_UNLOCK;
+
+ return res;
+}
+
+static void indirect_set_loaded(pTHX_ void *cxt) {
+#define indirect_set_loaded(C) indirect_set_loaded(aTHX_ (C))
+ I_LOADED_LOCK;
+ if (!indirect_loaded_cxts) {
+  indirect_loaded_cxts          = ptable_new();
+  indirect_loaded_cxts_refcount = 0;
+ }
+ ++indirect_loaded_cxts_refcount;
+ ptable_loaded_store(indirect_loaded_cxts, cxt, cxt);
+ I_LOADED_UNLOCK;
+}
+
+static void indirect_clear_loaded(pTHX_ void *cxt) {
+#define indirect_clear_loaded(C) indirect_clear_loaded(aTHX_ (C))
+ I_LOADED_LOCK;
+ if (indirect_loaded_cxts_refcount <= 1) {
+  ptable_loaded_free(indirect_loaded_cxts);
+  indirect_loaded_cxts          = NULL;
+  indirect_loaded_cxts_refcount = 0;
+ } else {
+  --indirect_loaded_cxts_refcount;
+  ptable_loaded_delete(indirect_loaded_cxts, cxt);
+ }
+ I_LOADED_UNLOCK;
+}
+
+#else
+
+#define indirect_is_loaded(C)    (1)
+#define indirect_set_loaded(C)   NOOP
+#define indirect_clear_loaded(C) NOOP
+
+#endif
+
 /* ... Thread-safe hints ................................................... */
 
 #if I_WORKAROUND_REQUIRE_PROPAGATION
@@ -296,7 +379,7 @@ typedef struct {
 # define indirect_dup_inc(S, U)             SvREFCNT_inc(sv_dup((S), &((U)->params)))
 #endif
 
-STATIC void indirect_ptable_clone(pTHX_ ptable_ent *ent, void *ud_) {
+static void indirect_ptable_clone(pTHX_ ptable_ent *ent, void *ud_) {
  indirect_ptable_clone_ud *ud = ud_;
  indirect_hint_t          *h1 = ent->val;
  indirect_hint_t          *h2;
@@ -318,24 +401,28 @@ STATIC void indirect_ptable_clone(pTHX_ ptable_ent *ent, void *ud_) {
  ptable_hints_store(ud->tbl, ent->key, h2);
 }
 
-STATIC void indirect_thread_cleanup(pTHX_ void *ud) {
+static void indirect_thread_cleanup(pTHX_ void *ud) {
  dMY_CXT;
 
+ indirect_clear_loaded(&MY_CXT);
+
  SvREFCNT_dec(MY_CXT.global_code);
  MY_CXT.global_code = NULL;
+
  ptable_free(MY_CXT.map);
  MY_CXT.map = NULL;
+
  ptable_hints_free(MY_CXT.tbl);
  MY_CXT.tbl = NULL;
 }
 
-STATIC int indirect_endav_free(pTHX_ SV *sv, MAGIC *mg) {
+static int indirect_endav_free(pTHX_ SV *sv, MAGIC *mg) {
  SAVEDESTRUCTOR_X(indirect_thread_cleanup, NULL);
 
  return 0;
 }
 
-STATIC MGVTBL indirect_endav_vtbl = {
+static MGVTBL indirect_endav_vtbl = {
  0,
  0,
  0,
@@ -355,7 +442,7 @@ STATIC MGVTBL indirect_endav_vtbl = {
 #endif /* I_THREADSAFE */
 
 #if I_WORKAROUND_REQUIRE_PROPAGATION
-STATIC IV indirect_require_tag(pTHX) {
+static IV indirect_require_tag(pTHX) {
 #define indirect_require_tag() indirect_require_tag(aTHX)
  const CV *cv, *outside;
 
@@ -400,7 +487,7 @@ get_enclosing_cv:
 }
 #endif /* I_WORKAROUND_REQUIRE_PROPAGATION */
 
-STATIC SV *indirect_tag(pTHX_ SV *value) {
+static SV *indirect_tag(pTHX_ SV *value) {
 #define indirect_tag(V) indirect_tag(aTHX_ (V))
  indirect_hint_t *h;
  SV              *code = NULL;
@@ -439,7 +526,7 @@ STATIC SV *indirect_tag(pTHX_ SV *value) {
  return newSViv(PTR2IV(h));
 }
 
-STATIC SV *indirect_detag(pTHX_ const SV *hint) {
+static SV *indirect_detag(pTHX_ const SV *hint) {
 #define indirect_detag(H) indirect_detag(aTHX_ (H))
  indirect_hint_t *h;
 #if I_THREADSAFE || I_WORKAROUND_REQUIRE_PROPAGATION
@@ -464,9 +551,9 @@ STATIC SV *indirect_detag(pTHX_ const SV *hint) {
  return I_HINT_CODE(h);
 }
 
-STATIC U32 indirect_hash = 0;
+static VOL U32 indirect_hash = 0;
 
-STATIC SV *indirect_hint(pTHX) {
+static SV *indirect_hint(pTHX) {
 #define indirect_hint() indirect_hint(aTHX)
  SV *hint = NULL;
 
@@ -495,17 +582,20 @@ STATIC SV *indirect_hint(pTHX) {
  }
 #endif
 
- if (hint && SvIOK(hint))
+ if (hint && SvIOK(hint)) {
   return indirect_detag(hint);
- else {
else {
   dMY_CXT;
-  return MY_CXT.global_code;
+  if (indirect_is_loaded(&MY_CXT))
+   return MY_CXT.global_code;
+  else
+   return NULL;
  }
 }
 
 /* ... op -> source position ............................................... */
 
-STATIC void indirect_map_store(pTHX_ const OP *o, STRLEN pos, SV *sv, line_t line) {
+static void indirect_map_store(pTHX_ const OP *o, STRLEN pos, SV *sv, line_t line) {
 #define indirect_map_store(O, P, N, L) indirect_map_store(aTHX_ (O), (P), (N), (L))
  indirect_op_info_t *oi;
  const char *s;
@@ -541,7 +631,7 @@ STATIC void indirect_map_store(pTHX_ const OP *o, STRLEN pos, SV *sv, line_t lin
  oi->line = line;
 }
 
-STATIC const indirect_op_info_t *indirect_map_fetch(pTHX_ const OP *o) {
+static const indirect_op_info_t *indirect_map_fetch(pTHX_ const OP *o) {
 #define indirect_map_fetch(O) indirect_map_fetch(aTHX_ (O))
  dMY_CXT;
 
@@ -551,17 +641,17 @@ STATIC const indirect_op_info_t *indirect_map_fetch(pTHX_ const OP *o) {
  return ptable_fetch(MY_CXT.map, o);
 }
 
-STATIC void indirect_map_delete(pTHX_ const OP *o) {
+static void indirect_map_delete(pTHX_ const OP *o) {
 #define indirect_map_delete(O) indirect_map_delete(aTHX_ (O))
  dMY_CXT;
 
- if (MY_CXT.map)
+ if (indirect_is_loaded(&MY_CXT) && MY_CXT.map)
   ptable_delete(MY_CXT.map, o);
 }
 
 /* --- Check functions ----------------------------------------------------- */
 
-STATIC int indirect_find(pTHX_ SV *name_sv, const char *line_bufptr, STRLEN *name_pos) {
+static int indirect_find(pTHX_ SV *name_sv, const char *line_bufptr, STRLEN *name_pos) {
 #define indirect_find(NSV, LBP, NP) indirect_find(aTHX_ (NSV), (LBP), (NP))
  STRLEN      name_len, line_len;
  const char *name, *name_end;
@@ -602,9 +692,9 @@ STATIC int indirect_find(pTHX_ SV *name_sv, const char *line_bufptr, STRLEN *nam
 
 /* ... ck_const ............................................................ */
 
-STATIC OP *(*indirect_old_ck_const)(pTHX_ OP *) = 0;
+static OP *(*indirect_old_ck_const)(pTHX_ OP *) = 0;
 
-STATIC OP *indirect_ck_const(pTHX_ OP *o) {
+static OP *indirect_ck_const(pTHX_ OP *o) {
  o = indirect_old_ck_const(aTHX_ o);
 
  if (indirect_hint()) {
@@ -646,9 +736,9 @@ STATIC OP *indirect_ck_const(pTHX_ OP *o) {
 
 /* ... ck_rv2sv ............................................................ */
 
-STATIC OP *(*indirect_old_ck_rv2sv)(pTHX_ OP *) = 0;
+static OP *(*indirect_old_ck_rv2sv)(pTHX_ OP *) = 0;
 
-STATIC OP *indirect_ck_rv2sv(pTHX_ OP *o) {
+static OP *indirect_ck_rv2sv(pTHX_ OP *o) {
  if (indirect_hint()) {
   OP *op = cUNOPo->op_first;
   SV *sv;
@@ -713,9 +803,9 @@ done:
 
 /* ... ck_padany ........................................................... */
 
-STATIC OP *(*indirect_old_ck_padany)(pTHX_ OP *) = 0;
+static OP *(*indirect_old_ck_padany)(pTHX_ OP *) = 0;
 
-STATIC OP *indirect_ck_padany(pTHX_ OP *o) {
+static OP *indirect_ck_padany(pTHX_ OP *o) {
  o = indirect_old_ck_padany(aTHX_ o);
 
  if (indirect_hint()) {
@@ -740,10 +830,10 @@ STATIC OP *indirect_ck_padany(pTHX_ OP *o) {
 
 /* ... ck_scope ............................................................ */
 
-STATIC OP *(*indirect_old_ck_scope)  (pTHX_ OP *) = 0;
-STATIC OP *(*indirect_old_ck_lineseq)(pTHX_ OP *) = 0;
+static OP *(*indirect_old_ck_scope)  (pTHX_ OP *) = 0;
+static OP *(*indirect_old_ck_lineseq)(pTHX_ OP *) = 0;
 
-STATIC OP *indirect_ck_scope(pTHX_ OP *o) {
+static OP *indirect_ck_scope(pTHX_ OP *o) {
  OP *(*old_ck)(pTHX_ OP *) = 0;
 
  switch (o->op_type) {
@@ -767,9 +857,9 @@ STATIC OP *indirect_ck_scope(pTHX_ OP *o) {
 
 /* ... ck_method ........................................................... */
 
-STATIC OP *(*indirect_old_ck_method)(pTHX_ OP *) = 0;
+static OP *(*indirect_old_ck_method)(pTHX_ OP *) = 0;
 
-STATIC OP *indirect_ck_method(pTHX_ OP *o) {
+static OP *indirect_ck_method(pTHX_ OP *o) {
  if (indirect_hint()) {
   OP *op = cUNOPo->op_first;
 
@@ -810,9 +900,9 @@ done:
 /* "use foo/no foo" compiles its call to import/unimport directly to a
  * method_named op. */
 
-STATIC OP *(*indirect_old_ck_method_named)(pTHX_ OP *) = 0;
+static OP *(*indirect_old_ck_method_named)(pTHX_ OP *) = 0;
 
-STATIC OP *indirect_ck_method_named(pTHX_ OP *o) {
+static OP *indirect_ck_method_named(pTHX_ OP *o) {
  if (indirect_hint()) {
   STRLEN pos;
   line_t line;
@@ -842,9 +932,9 @@ done:
 
 /* ... ck_entersub ......................................................... */
 
-STATIC OP *(*indirect_old_ck_entersub)(pTHX_ OP *) = 0;
+static OP *(*indirect_old_ck_entersub)(pTHX_ OP *) = 0;
 
-STATIC OP *indirect_ck_entersub(pTHX_ OP *o) {
+static OP *indirect_ck_entersub(pTHX_ OP *o) {
  SV *code = indirect_hint();
 
  o = indirect_old_ck_entersub(aTHX_ o);
@@ -861,7 +951,7 @@ STATIC OP *indirect_ck_entersub(pTHX_ OP *o) {
     goto done;
    oop = lop->op_first;
   } while (oop->op_type != OP_PUSHMARK);
-  oop = OP_SIBLING(oop);
+  oop = OpSIBLING(oop);
   mop = lop->op_last;
 
   if (!oop)
@@ -929,9 +1019,11 @@ done:
  return o;
 }
 
-STATIC U32 indirect_initialized = 0;
+/* --- Global setup/teardown ------------------------------------------------ */
+
+static VOL U32 indirect_initialized = 0;
 
-STATIC void indirect_teardown(pTHX_ void *root) {
+static void indirect_global_teardown(pTHX_ void *root) {
  if (!indirect_initialized)
   return;
 
@@ -940,16 +1032,6 @@ STATIC void indirect_teardown(pTHX_ void *root) {
   return;
 #endif
 
- {
-  dMY_CXT;
-  ptable_free(MY_CXT.map);
-  MY_CXT.map = NULL;
-#if I_THREADSAFE
-  ptable_hints_free(MY_CXT.tbl);
-  MY_CXT.tbl = NULL;
-#endif
- }
-
  indirect_ck_restore(OP_CONST,   &indirect_old_ck_const);
  indirect_ck_restore(OP_RV2SV,   &indirect_old_ck_rv2sv);
  indirect_ck_restore(OP_PADANY,  &indirect_old_ck_padany);
@@ -961,22 +1043,22 @@ STATIC void indirect_teardown(pTHX_ void *root) {
  indirect_ck_restore(OP_ENTERSUB,     &indirect_old_ck_entersub);
 
  indirect_initialized = 0;
+
+ return;
 }
 
-STATIC void indirect_setup(pTHX) {
-#define indirect_setup() indirect_setup(aTHX)
+static void indirect_global_setup(pTHX) {
+#define indirect_global_setup() indirect_global_setup(aTHX)
+ HV *stash;
+
  if (indirect_initialized)
   return;
 
- {
-  MY_CXT_INIT;
-#if I_THREADSAFE
-  MY_CXT.tbl         = ptable_new();
-  MY_CXT.owner       = aTHX;
-#endif
-  MY_CXT.map         = ptable_new();
-  MY_CXT.global_code = NULL;
- }
+ PERL_HASH(indirect_hash, __PACKAGE__, __PACKAGE_LEN__);
+
+ stash = gv_stashpvn(__PACKAGE__, __PACKAGE_LEN__, 1);
+ newCONSTSUB(stash, "I_THREADSAFE", newSVuv(I_THREADSAFE));
+ newCONSTSUB(stash, "I_FORKSAFE",   newSVuv(I_FORKSAFE));
 
  indirect_ck_replace(OP_CONST,   indirect_ck_const,  &indirect_old_ck_const);
  indirect_ck_replace(OP_RV2SV,   indirect_ck_rv2sv,  &indirect_old_ck_rv2sv);
@@ -992,15 +1074,52 @@ STATIC void indirect_setup(pTHX) {
                                       &indirect_old_ck_entersub);
 
 #if I_MULTIPLICITY
- call_atexit(indirect_teardown, aTHX);
+ call_atexit(indirect_global_teardown, aTHX);
 #else
- call_atexit(indirect_teardown, NULL);
+ call_atexit(indirect_global_teardown, NULL);
 #endif
 
  indirect_initialized = 1;
+
+ return;
 }
 
-STATIC U32 indirect_booted = 0;
+/* --- Interpreter setup/teardown ------------------------------------------ */
+
+static void indirect_local_teardown(pTHX_ void *param) {
+ dMY_CXT;
+
+ indirect_clear_loaded(&MY_CXT);
+
+ ptable_free(MY_CXT.map);
+ MY_CXT.map = NULL;
+
+#if I_THREADSAFE
+ ptable_hints_free(MY_CXT.tbl);
+ MY_CXT.tbl = NULL;
+#endif
+
+ return;
+}
+
+static void indirect_local_setup(pTHX) {
+#define indirect_local_setup() indirect_local_setup(aTHX)
+ MY_CXT_INIT;
+
+#if I_THREADSAFE
+ MY_CXT.tbl         = ptable_new();
+ MY_CXT.owner       = aTHX;
+#endif
+
+ MY_CXT.map         = ptable_new();
+ MY_CXT.global_code = NULL;
+
+ indirect_set_loaded(&MY_CXT);
+
+ call_atexit(indirect_local_teardown, NULL);
+
+ return;
+}
 
 /* --- XS ------------------------------------------------------------------ */
 
@@ -1010,17 +1129,8 @@ PROTOTYPES: ENABLE
 
 BOOT:
 {
- if (!indirect_booted++) {
-  HV *stash;
-
-  PERL_HASH(indirect_hash, __PACKAGE__, __PACKAGE_LEN__);
-
-  stash = gv_stashpvn(__PACKAGE__, __PACKAGE_LEN__, 1);
-  newCONSTSUB(stash, "I_THREADSAFE", newSVuv(I_THREADSAFE));
-  newCONSTSUB(stash, "I_FORKSAFE",   newSVuv(I_FORKSAFE));
- }
-
- indirect_setup();
+ indirect_global_setup();
+ indirect_local_setup();
 }
 
 #if I_THREADSAFE
@@ -1048,6 +1158,7 @@ PPCODE:
   MY_CXT.tbl         = t;
   MY_CXT.owner       = aTHX;
   MY_CXT.global_code = global_code_dup;
+  indirect_set_loaded(&MY_CXT);
  }
  gv = gv_fetchpv(__PACKAGE__ "::_THREAD_CLEANUP", 0, SVt_PVCV);
  if (gv) {