#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;
}
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;
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;
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;
}
BOOT:
{
- vmg_global_setup();
- vmg_local_setup();
+ vmg_setup();
}
#if VMG_THREADSAFE
}
MY_CXT.depth = old_depth;
MY_CXT.freed_tokens = NULL;
+ VMG_LOADED_LOCK;
+ assert(vmg_loaded > 0);
+ ++vmg_loaded;
+ VMG_LOADED_UNLOCK;
}
XSRETURN(0);