summaryrefslogtreecommitdiff
path: root/dist
diff options
context:
space:
mode:
authorDavid Mitchell <davem@iabyn.com>2010-06-04 17:05:21 +0100
committerDavid Mitchell <davem@iabyn.com>2010-06-04 17:05:21 +0100
commit65c7421c80585e0d12a20773935dc01f4ffa3e42 (patch)
treeb136c08b8c0bb3d7d4da49a66655171d338f20a6 /dist
parent92f022bbf8c129c6f2379a382f1eaaa5c7bd9f3f (diff)
downloadperl-65c7421c80585e0d12a20773935dc01f4ffa3e42.tar.gz
threads::shared: veto signal despatch if locked
This fixes RT #74868: Safe signals changes causing hangs with threads. The basic issue is that due to changes in where safe signals can be despatched, (including now on leaving scope), it's possible for a perl-level signal handler to be called while PL_sharedsv_lock is held. If the handler does locking or manipulation of shared vars, then deadlock can occur. A robust fix for this is to ensure that the signal handler isn't called while we have the lock. This is done using the signal handler hook added in the previous commit.
Diffstat (limited to 'dist')
-rw-r--r--dist/threads-shared/shared.xs23
1 files changed, 23 insertions, 0 deletions
diff --git a/dist/threads-shared/shared.xs b/dist/threads-shared/shared.xs
index a1c6925f29..720e3b6749 100644
--- a/dist/threads-shared/shared.xs
+++ b/dist/threads-shared/shared.xs
@@ -1167,6 +1167,23 @@ Perl_shared_object_destroy(pTHX_ SV *sv)
}
#endif
+/* veto signal despatch if we have the lock */
+
+#ifdef PL_signalhook
+
+STATIC despatch_signals_proc_t prev_signal_hook = NULL;
+
+STATIC void
+S_shared_signal_hook(pTHX) {
+ int us;
+ MUTEX_LOCK(&PL_sharedsv_lock.mutex);
+ us = (PL_sharedsv_lock.owner == aTHX);
+ MUTEX_UNLOCK(&PL_sharedsv_lock.mutex);
+ if (us)
+ return; /* try again later */
+ CALL_FPTR(prev_signal_hook)(aTHX);
+}
+#endif
/* Saves a space for keeping SVs wider than an interpreter. */
@@ -1184,6 +1201,12 @@ Perl_sharedsv_init(pTHX)
#ifdef PL_destroyhook
PL_destroyhook = &Perl_shared_object_destroy;
#endif
+#ifdef PL_signalhook
+ if (!prev_signal_hook) {
+ prev_signal_hook = PL_signalhook;
+ PL_signalhook = &S_shared_signal_hook;
+ }
+#endif
}
#endif /* USE_ITHREADS */