From: Vincent Pit Date: Wed, 8 Apr 2015 12:24:50 +0000 (-0300) Subject: Reference-count global setup/teardown X-Git-Tag: v0.57~11 X-Git-Url: http://git.vpit.fr/?a=commitdiff_plain;h=4a19e38d1c3cae3504a5d2dbbca0bd483280f1f7;p=perl%2Fmodules%2FVariable-Magic.git Reference-count global setup/teardown This fixes surprises like this one : module loaded in thread 1, then in thread 2, then thread 1 ends and now the module does not work anymore in thread 2 (even though it should). --- diff --git a/Magic.xs b/Magic.xs index cf5bc21..f3ed0d6 100644 --- a/Magic.xs +++ b/Magic.xs @@ -1745,24 +1745,35 @@ static I32 vmg_svt_val(pTHX_ IV action, SV *sv) { #endif /* VMG_UVAR */ -/* --- Global setup/teardown ----------------------------------------------- */ +/* --- Module setup/teardown ----------------------------------------------- */ -static VOL U32 vmg_initialized = 0; - -static void vmg_global_teardown_late(pTHX) { -#define vmg_global_teardown_late() vmg_global_teardown_late(aTHX) #if VMG_THREADSAFE + +static I32 vmg_loaded = 0; + +/* We must use preexistent global mutexes or we will never be able to destroy + * them. */ +# if VMG_HAS_PERL(5, 9, 3) +# define VMG_LOADED_LOCK MUTEX_LOCK(&PL_my_ctx_mutex) +# define VMG_LOADED_UNLOCK MUTEX_UNLOCK(&PL_my_ctx_mutex) +# else +# define VMG_LOADED_LOCK OP_REFCNT_LOCK +# define VMG_LOADED_UNLOCK OP_REFCNT_UNLOCK +# endif + +static void vmg_global_teardown_late_locked(pTHX) { +#define vmg_global_teardown_late_locked() vmg_global_teardown_late_locked(aTHX) MUTEX_DESTROY(&vmg_op_name_init_mutex); MUTEX_DESTROY(&vmg_vtable_refcount_mutex); -#endif - vmg_initialized = 0; + vmg_loaded = 0; return; } static int vmg_global_teardown_free(pTHX_ SV *sv, MAGIC *mg) { - vmg_global_teardown_late(); + vmg_global_teardown_late_locked(); + VMG_LOADED_UNLOCK; return 0; } @@ -1821,52 +1832,36 @@ static signed char vmg_destruct_level(pTHX) { return lvl; } -static void vmg_global_teardown(pTHX_ void *root) { - if (!vmg_initialized) - return; +#endif /* VMG_THREADSAFE */ + +static void vmg_teardown(pTHX_ void *interp) { + dMY_CXT; #if VMG_MULTIPLICITY - if (aTHX != root) + if (aTHX != interp) return; #endif - if (vmg_destruct_level() == 0) { - vmg_global_teardown_late(); - } else { - if (!PL_strtab) - PL_strtab = newHV(); - vmg_sv_magicext((SV *) PL_strtab, NULL, &vmg_global_teardown_vtbl, NULL, 0); - } - - return; -} - -static void vmg_global_setup(pTHX) { -#define vmg_global_setup() vmg_global_setup(aTHX) - if (vmg_initialized) - return; - #if VMG_THREADSAFE - MUTEX_INIT(&vmg_vtable_refcount_mutex); - MUTEX_INIT(&vmg_op_name_init_mutex); -#endif + VMG_LOADED_LOCK; -#if VMG_MULTIPLICITY - call_atexit(vmg_global_teardown, aTHX); -#else - call_atexit(vmg_global_teardown, NULL); + if (vmg_loaded <= 1) { + assert(vmg_loaded == 1); + if (vmg_destruct_level() == 0) { + vmg_global_teardown_late_locked(); + VMG_LOADED_UNLOCK; + } else { + if (!PL_strtab) + PL_strtab = newHV(); + vmg_sv_magicext((SV *) PL_strtab, NULL, &vmg_global_teardown_vtbl, NULL, 0); + /* Lock until vmg_global_teardown_free() is called */ + } + } else { + --vmg_loaded; + VMG_LOADED_UNLOCK; + } #endif - vmg_initialized = 1; - - return; -} - -/* --- Interpreter setup/teardown ------------------------------------------ */ - -static void vmg_local_teardown(pTHX_ void *param) { - dMY_CXT; - if (MY_CXT.depth == 0 && MY_CXT.freed_tokens) { vmg_magic_chain_free(MY_CXT.freed_tokens, NULL); MY_CXT.freed_tokens = NULL; @@ -1875,12 +1870,25 @@ static void vmg_local_teardown(pTHX_ void *param) { return; } -static void vmg_local_setup(pTHX) { -#define vmg_local_setup() vmg_local_setup(aTHX) +static void vmg_setup(pTHX) { +#define vmg_setup() vmg_setup(aTHX) HV *stash; int c; - MY_CXT_INIT; + +#if VMG_THREADSAFE + VMG_LOADED_LOCK; + + if (vmg_loaded <= 0) { + assert(vmg_loaded == 0); + MUTEX_INIT(&vmg_vtable_refcount_mutex); + MUTEX_INIT(&vmg_op_name_init_mutex); + } + ++vmg_loaded; + + VMG_LOADED_UNLOCK; +#endif + for (c = OPc_NULL; c < OPc_MAX; ++c) MY_CXT.b__op_stashes[c] = NULL; @@ -1922,7 +1930,11 @@ static void vmg_local_setup(pTHX) { newCONSTSUB(stash, "VMG_OP_INFO_NAME", newSVuv(VMG_OP_INFO_NAME)); newCONSTSUB(stash, "VMG_OP_INFO_OBJECT", newSVuv(VMG_OP_INFO_OBJECT)); - call_atexit(vmg_local_teardown, NULL); +#if VMG_MULTIPLICITY + call_atexit(vmg_teardown, aTHX); +#else + call_atexit(vmg_teardown, NULL); +#endif return; } @@ -1978,8 +1990,7 @@ PROTOTYPES: ENABLE BOOT: { - vmg_global_setup(); - vmg_local_setup(); + vmg_setup(); } #if VMG_THREADSAFE @@ -2008,6 +2019,10 @@ PPCODE: } MY_CXT.depth = old_depth; MY_CXT.freed_tokens = NULL; + VMG_LOADED_LOCK; + assert(vmg_loaded > 0); + ++vmg_loaded; + VMG_LOADED_UNLOCK; } XSRETURN(0);