If this mutex falls back to the OP_REFCNT mutex, and that a coderef is
freed during global destruction, the mutex is taken twice and the process
hangs. As a general rule, it does not seem very safe so we just set
vmg_loaded to zero early and only run the global teardown callback if
it is zero. This ensures that this callback will only be called once.
MUTEX_DESTROY(&vmg_op_name_init_mutex);
MUTEX_DESTROY(&vmg_vtable_refcount_mutex);
MUTEX_DESTROY(&vmg_op_name_init_mutex);
MUTEX_DESTROY(&vmg_vtable_refcount_mutex);
return;
}
static int vmg_global_teardown_free(pTHX_ SV *sv, MAGIC *mg) {
return;
}
static int vmg_global_teardown_free(pTHX_ SV *sv, MAGIC *mg) {
- vmg_global_teardown_late_locked();
+ VMG_LOADED_LOCK;
+
+ if (vmg_loaded == 0)
+ vmg_global_teardown_late_locked();
+
VMG_LOADED_UNLOCK;
return 0;
VMG_LOADED_UNLOCK;
return 0;
#if VMG_THREADSAFE
VMG_LOADED_LOCK;
#if VMG_THREADSAFE
VMG_LOADED_LOCK;
- if (vmg_loaded <= 1) {
- assert(vmg_loaded == 1);
+ if (vmg_loaded == 1) {
+ vmg_loaded = 0;
if (vmg_destruct_level() == 0) {
vmg_global_teardown_late_locked();
if (vmg_destruct_level() == 0) {
vmg_global_teardown_late_locked();
} else {
if (!PL_strtab)
PL_strtab = newHV();
vmg_sv_magicext((SV *) PL_strtab, NULL, &vmg_global_teardown_vtbl, NULL, 0);
} 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 */
+ assert(vmg_loaded > 1);
#endif
if (MY_CXT.depth == 0 && MY_CXT.freed_tokens) {
#endif
if (MY_CXT.depth == 0 && MY_CXT.freed_tokens) {