]> git.vpit.fr Git - perl/modules/Variable-Magic.git/commitdiff
Don't lock the VMG_LOADED mutex across global destruction
authorVincent Pit <vince@profvince.com>
Thu, 9 Apr 2015 18:12:26 +0000 (15:12 -0300)
committerVincent Pit <vince@profvince.com>
Tue, 14 Apr 2015 14:42:58 +0000 (11:42 -0300)
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.

Magic.xs

index f3ed0d6775754f061744351420ca66de67445011..207fcb383a75a3162632239b0cc74c7ff5335504 100644 (file)
--- a/Magic.xs
+++ b/Magic.xs
@@ -1766,13 +1766,15 @@ static void vmg_global_teardown_late_locked(pTHX) {
  MUTEX_DESTROY(&vmg_op_name_init_mutex);
  MUTEX_DESTROY(&vmg_vtable_refcount_mutex);
 
- vmg_loaded = 0;
-
  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;
@@ -1845,21 +1847,21 @@ static void vmg_teardown(pTHX_ void *interp) {
 #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();
-   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 {
+  assert(vmg_loaded > 1);
   --vmg_loaded;
-  VMG_LOADED_UNLOCK;
  }
+
+ VMG_LOADED_UNLOCK;
 #endif
 
  if (MY_CXT.depth == 0 && MY_CXT.freed_tokens) {