X-Git-Url: http://git.vpit.fr/?p=perl%2Fmodules%2Findirect.git;a=blobdiff_plain;f=indirect.xs;h=ba0543dae7e778c864bac2a9543479f2a2317e53;hp=40aebea36f97c0d56e583f19220bdf70bfc58c13;hb=f005f899e4ca83b205bf4cfb37e5d7c56b5d2b4b;hpb=48aed0641a91994514808460cdc6297140a2f149 diff --git a/indirect.xs b/indirect.xs index 40aebea..ba0543d 100644 --- a/indirect.xs +++ b/indirect.xs @@ -113,12 +113,17 @@ #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 @@ -146,12 +151,33 @@ # define MY_CXT_CLONE NOOP #endif +#if I_THREADSAFE +/* 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 +#else +# define I_LOADED_LOCK NOOP +# define I_LOADED_UNLOCK NOOP +#endif + #if defined(OP_CHECK_MUTEX_LOCK) && defined(OP_CHECK_MUTEX_UNLOCK) -# define I_CHECK_MUTEX_LOCK OP_CHECK_MUTEX_LOCK -# define I_CHECK_MUTEX_UNLOCK OP_CHECK_MUTEX_UNLOCK +# define I_CHECK_LOCK OP_CHECK_MUTEX_LOCK +# define I_CHECK_UNLOCK OP_CHECK_MUTEX_UNLOCK +#elif I_HAS_PERL(5, 9, 3) +# define I_CHECK_LOCK OP_REFCNT_LOCK +# define I_CHECK_UNLOCK OP_REFCNT_UNLOCK #else -# define I_CHECK_MUTEX_LOCK OP_REFCNT_LOCK -# define I_CHECK_MUTEX_UNLOCK OP_REFCNT_UNLOCK +/* Before perl 5.9.3, indirect_ck_*() calls are already protected by the + * I_LOADED mutex, which falls back to the OP_REFCNT mutex. Make sure we don't + * lock it twice. */ +# define I_CHECK_LOCK NOOP +# define I_CHECK_UNLOCK NOOP #endif typedef OP *(*indirect_ck_t)(pTHX_ OP *); @@ -164,28 +190,101 @@ typedef OP *(*indirect_ck_t)(pTHX_ OP *); 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; + I_CHECK_LOCK; if (!*old_ck_p) { *old_ck_p = PL_check[type]; PL_check[type] = new_ck; } - I_CHECK_MUTEX_UNLOCK; + I_CHECK_UNLOCK; } #endif 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; + I_CHECK_LOCK; if (*old_ck_p) { PL_check[type] = *old_ck_p; *old_ck_p = 0; } - I_CHECK_MUTEX_UNLOCK; + I_CHECK_UNLOCK; } /* --- Helpers ------------------------------------------------------------- */ +/* ... Check if the module is loaded ....................................... */ + +static I32 indirect_loaded = 0; + +#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)) + +static ptable *indirect_loaded_cxts = NULL; + +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 int indirect_set_loaded_locked(pTHX_ void *cxt) { +#define indirect_set_loaded_locked(C) indirect_set_loaded_locked(aTHX_ (C)) + int global_setup = 0; + + if (indirect_loaded <= 0) { + assert(indirect_loaded == 0); + assert(!indirect_loaded_cxts); + indirect_loaded_cxts = ptable_new(); + global_setup = 1; + } + ++indirect_loaded; + assert(indirect_loaded_cxts); + ptable_loaded_store(indirect_loaded_cxts, cxt, cxt); + + return global_setup; +} + +static int indirect_clear_loaded_locked(pTHX_ void *cxt) { +#define indirect_clear_loaded_locked(C) indirect_clear_loaded_locked(aTHX_ (C)) + int global_teardown = 0; + + if (indirect_loaded > 1) { + assert(indirect_loaded_cxts); + ptable_loaded_delete(indirect_loaded_cxts, cxt); + --indirect_loaded; + } else if (indirect_loaded_cxts) { + assert(indirect_loaded == 1); + ptable_loaded_free(indirect_loaded_cxts); + indirect_loaded_cxts = NULL; + indirect_loaded = 0; + global_teardown = 1; + } + + return global_teardown; +} + +#else + +#define indirect_is_loaded(C) (indirect_loaded > 0) +#define indirect_set_loaded_locked(C) ((indirect_loaded++ <= 0) ? 1 : 0) +#define indirect_clear_loaded_locked(C) ((--indirect_loaded <= 0) ? 1 : 0) + +#endif + /* ... Thread-safe hints ................................................... */ #if I_WORKAROUND_REQUIRE_PROPAGATION @@ -323,12 +422,18 @@ static void indirect_ptable_clone(pTHX_ ptable_ent *ent, void *ud_) { } static void indirect_thread_cleanup(pTHX_ void *ud) { + int global_teardown; dMY_CXT; + global_teardown = indirect_clear_loaded_locked(&MY_CXT); + assert(!global_teardown); + 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; } @@ -468,7 +573,7 @@ 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) { #define indirect_hint() indirect_hint(aTHX) @@ -499,11 +604,14 @@ 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; } } @@ -559,7 +667,7 @@ 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); } @@ -933,75 +1041,34 @@ done: return o; } -/* --- Global setup/teardown ------------------------------------------------ */ - -static U32 indirect_initialized = 0; +/* --- Module setup/teardown ----------------------------------------------- */ -static void indirect_global_teardown(pTHX_ void *root) { - if (!indirect_initialized) - return; +static void indirect_teardown(pTHX_ void *interp) { + dMY_CXT; #if I_MULTIPLICITY - if (aTHX != root) + if (aTHX != interp) return; #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); - indirect_ck_restore(OP_SCOPE, &indirect_old_ck_scope); - indirect_ck_restore(OP_LINESEQ, &indirect_old_ck_lineseq); - - indirect_ck_restore(OP_METHOD, &indirect_old_ck_method); - indirect_ck_restore(OP_METHOD_NAMED, &indirect_old_ck_method_named); - indirect_ck_restore(OP_ENTERSUB, &indirect_old_ck_entersub); - - indirect_initialized = 0; - - return; -} - -static void indirect_global_setup(pTHX) { -#define indirect_global_setup() indirect_global_setup(aTHX) - HV *stash; - - if (indirect_initialized) - return; - - PERL_HASH(indirect_hash, __PACKAGE__, __PACKAGE_LEN__); + I_LOADED_LOCK; - stash = gv_stashpvn(__PACKAGE__, __PACKAGE_LEN__, 1); - newCONSTSUB(stash, "I_THREADSAFE", newSVuv(I_THREADSAFE)); - newCONSTSUB(stash, "I_FORKSAFE", newSVuv(I_FORKSAFE)); + if (indirect_clear_loaded_locked(&MY_CXT)) { + 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); + indirect_ck_restore(OP_SCOPE, &indirect_old_ck_scope); + indirect_ck_restore(OP_LINESEQ, &indirect_old_ck_lineseq); - indirect_ck_replace(OP_CONST, indirect_ck_const, &indirect_old_ck_const); - indirect_ck_replace(OP_RV2SV, indirect_ck_rv2sv, &indirect_old_ck_rv2sv); - indirect_ck_replace(OP_PADANY, indirect_ck_padany, &indirect_old_ck_padany); - indirect_ck_replace(OP_SCOPE, indirect_ck_scope, &indirect_old_ck_scope); - indirect_ck_replace(OP_LINESEQ, indirect_ck_scope, &indirect_old_ck_lineseq); - - indirect_ck_replace(OP_METHOD, indirect_ck_method, - &indirect_old_ck_method); - indirect_ck_replace(OP_METHOD_NAMED, indirect_ck_method_named, - &indirect_old_ck_method_named); - indirect_ck_replace(OP_ENTERSUB, indirect_ck_entersub, - &indirect_old_ck_entersub); - -#if I_MULTIPLICITY - call_atexit(indirect_global_teardown, aTHX); -#else - call_atexit(indirect_global_teardown, NULL); -#endif - - indirect_initialized = 1; - - return; -} + indirect_ck_restore(OP_METHOD, &indirect_old_ck_method); + indirect_ck_restore(OP_METHOD_NAMED, &indirect_old_ck_method_named); + indirect_ck_restore(OP_ENTERSUB, &indirect_old_ck_entersub); + } -/* --- Interpreter setup/teardown ------------------------------------------ */ + I_LOADED_UNLOCK; -static void indirect_local_teardown(pTHX_ void *param) { - dMY_CXT; + SvREFCNT_dec(MY_CXT.global_code); + MY_CXT.global_code = NULL; ptable_free(MY_CXT.map); MY_CXT.map = NULL; @@ -1014,19 +1081,52 @@ static void indirect_local_teardown(pTHX_ void *param) { return; } -static void indirect_local_setup(pTHX) { -#define indirect_local_setup() indirect_local_setup(aTHX) - MY_CXT_INIT; +static void indirect_setup(pTHX) { +#define indirect_setup() indirect_setup(aTHX) + MY_CXT_INIT; /* Takes/release PL_my_ctx_mutex */ + + I_LOADED_LOCK; + + if (indirect_set_loaded_locked(&MY_CXT)) { + PERL_HASH(indirect_hash, __PACKAGE__, __PACKAGE_LEN__); + + indirect_ck_replace(OP_CONST, indirect_ck_const, &indirect_old_ck_const); + indirect_ck_replace(OP_RV2SV, indirect_ck_rv2sv, &indirect_old_ck_rv2sv); + indirect_ck_replace(OP_PADANY, indirect_ck_padany, &indirect_old_ck_padany); + indirect_ck_replace(OP_SCOPE, indirect_ck_scope, &indirect_old_ck_scope); + indirect_ck_replace(OP_LINESEQ, indirect_ck_scope, &indirect_old_ck_lineseq); + + indirect_ck_replace(OP_METHOD, indirect_ck_method, + &indirect_old_ck_method); + indirect_ck_replace(OP_METHOD_NAMED, indirect_ck_method_named, + &indirect_old_ck_method_named); + indirect_ck_replace(OP_ENTERSUB, indirect_ck_entersub, + &indirect_old_ck_entersub); + } + + I_LOADED_UNLOCK; + + { + HV *stash; + + stash = gv_stashpvn(__PACKAGE__, __PACKAGE_LEN__, 1); + newCONSTSUB(stash, "I_THREADSAFE", newSVuv(I_THREADSAFE)); + newCONSTSUB(stash, "I_FORKSAFE", newSVuv(I_FORKSAFE)); #if I_THREADSAFE - MY_CXT.tbl = ptable_new(); - MY_CXT.owner = aTHX; + MY_CXT.tbl = ptable_new(); + MY_CXT.owner = aTHX; #endif - MY_CXT.map = ptable_new(); - MY_CXT.global_code = NULL; + MY_CXT.map = ptable_new(); + MY_CXT.global_code = NULL; + } - call_atexit(indirect_local_teardown, NULL); +#if I_MULTIPLICITY + call_atexit(indirect_teardown, aTHX); +#else + call_atexit(indirect_teardown, NULL); +#endif return; } @@ -1039,8 +1139,7 @@ PROTOTYPES: ENABLE BOOT: { - indirect_global_setup(); - indirect_local_setup(); + indirect_setup(); } #if I_THREADSAFE @@ -1068,6 +1167,13 @@ PPCODE: MY_CXT.tbl = t; MY_CXT.owner = aTHX; MY_CXT.global_code = global_code_dup; + { + int global_setup; + I_LOADED_LOCK; + global_setup = indirect_set_loaded_locked(&MY_CXT); + assert(!global_setup); + I_LOADED_UNLOCK; + } } gv = gv_fetchpv(__PACKAGE__ "::_THREAD_CLEANUP", 0, SVt_PVCV); if (gv) {