1.0.25.30: INTERRUPT-THREAD without RT signals
authorGabor Melis <mega@hotpop.com>
Mon, 16 Feb 2009 21:45:22 +0000 (21:45 +0000)
committerGabor Melis <mega@hotpop.com>
Mon, 16 Feb 2009 21:45:22 +0000 (21:45 +0000)
All non-win32 platforms converted to use normal signals
(SIGINFO/SIGPWR) to implement INTERRUPT-THREAD.

Remove mention of RT signals from the internals manual.

NEWS
doc/internals/signals.texinfo
src/code/target-thread.lisp
src/runtime/linux-os.h
src/runtime/sunos-os.h
src/runtime/thread.c
src/runtime/thread.h
version.lisp-expr

diff --git a/NEWS b/NEWS
index e175a0f..9a946f9 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -7,6 +7,8 @@ changes in sbcl-1.0.26 relative to 1.0.25:
     fault, etc. In the absence of --lose-on-corruption a warning is
     printed to stderr.
   * optimization: slightly faster gc on multithreaded builds
+  * bug fix: real-time signals are not used anymore, so no more
+    hanging when the system wide real-time signal queue gets full.
 
 changes in sbcl-1.0.25 relative to 1.0.24:
   * incompatible change: SB-INTROSPECT:FUNCTION-ARGLIST is deprecated, to be
index dc2b3a6..33c0adf 100644 (file)
@@ -73,20 +73,6 @@ is deferred by pseudo atomic and @code{WITHOUT-GCING}.
 @node Implementation warts
 @section Implementation warts
 
-@subsection RT signals
-
-Sending and receiving the same number of signals is crucial for
-@code{INTERRUPT-THREAD} and @code{sig_stop_for_gc}, hence they are
-real-time signals for which the kernel maintains a queue as opposed to
-just setting a flag for ``sigint pending''.
-
-Note, however, that the rt signal queue is finite and on current linux
-kernels a system wide resource. If the queue is full, SBCL tries to
-signal until it succeeds. This behaviour can lead to deadlocks, if a
-thread in a @code{WITHOUT-INTERRUPTS} is interrupted many times,
-filling up the queue and then a gc hits and tries to send
-@code{SIG_STOP_FOR_GC}.
-
 @subsection Miscellaneous issues
 
 Signal handlers should automatically restore errno and fp
index d4a90a5..a0cf2e0 100644 (file)
@@ -892,12 +892,18 @@ return DEFAULT if given or else signal JOIN-THREAD-ERROR."
 (defun run-interruption ()
   (in-interruption ()
     (loop
-       (let ((interruption (with-interruptions-lock (*current-thread*)
-                             (pop (thread-interruptions *current-thread*)))))
-         (if interruption
-             (with-interrupts
-               (funcall interruption))
-             (return))))))
+     (let ((interruption (with-interruptions-lock (*current-thread*)
+                           (pop (thread-interruptions *current-thread*)))))
+       ;; Resignalling after popping one works fine, because from the
+       ;; OS's point of view we have returned from the signal handler
+       ;; (thanks to arrange_return_to_lisp_function) so at least one
+       ;; more signal will be delivered.
+       (when (thread-interruptions *current-thread*)
+         (signal-interrupt-thread (thread-os-thread *current-thread*)))
+       (if interruption
+           (with-interrupts
+             (funcall interruption))
+           (return))))))
 
 ;;; The order of interrupt execution is peculiar. If thread A
 ;;; interrupts thread B with I1, I2 and B for some reason receives I1
index 02851a3..e930693 100644 (file)
@@ -39,5 +39,5 @@ typedef int os_vm_prot_t;
 
 #define SIG_MEMORY_FAULT SIGSEGV
 
-#define SIG_INTERRUPT_THREAD (SIGRTMIN)
+#define SIG_INTERRUPT_THREAD (SIGPWR)
 #define SIG_STOP_FOR_GC (SIGUSR1)
index b8560c7..dda6f4f 100644 (file)
@@ -32,7 +32,7 @@ typedef int os_vm_prot_t;
 
 #define SIG_MEMORY_FAULT SIGSEGV
 
-#define SIG_INTERRUPT_THREAD (SIGRTMIN)
+#define SIG_INTERRUPT_THREAD (SIGPWR)
 #define SIG_STOP_FOR_GC (SIGUSR1)
 
 /* Yaargh?! */
index 24daaae..600d168 100644 (file)
@@ -560,31 +560,9 @@ os_thread_t create_thread(lispobj initial_function) {
     }
 }
 
-/* Send the signo to os_thread, retry if the rt signal queue is
- * full. */
-int
-kill_thread_safely(os_thread_t os_thread, int signo)
-{
-    int r;
-    /* The man page does not mention EAGAIN as a valid return value
-     * for either pthread_kill or kill. But that's theory, this is
-     * practice. By waiting here we assume that the delivery of this
-     * signal is not necessary for the delivery of the signals in the
-     * queue. In other words, we _assume_ there are no deadlocks. */
-    while ((r=pthread_kill(os_thread,signo))==EAGAIN) {
-        /* wait a bit then try again in the hope of the rt signal
-         * queue not being full */
-        FSHOW_SIGNAL((stderr,"/rt signal queue full\n"));
-        /* FIXME: some kind of backoff (random, exponential) would be
-         * nice. */
-        sleep(1);
-    }
-    return r;
-}
-
 int signal_interrupt_thread(os_thread_t os_thread)
 {
-    int status = kill_thread_safely(os_thread, SIG_INTERRUPT_THREAD);
+    int status = pthread_kill(os_thread, SIG_INTERRUPT_THREAD);
     FSHOW_SIGNAL((stderr,"/signal_interrupt_thread: %lu\n", os_thread));
     if (status == 0) {
         return 0;
index f8ec4e7..c123077 100644 (file)
@@ -235,6 +235,5 @@ static inline struct thread *arch_os_get_current_thread(void)
 #endif
 
 extern void create_initial_thread(lispobj);
-extern int kill_thread_safely(os_thread_t os_thread, int signo);
 
 #endif /* _INCLUDE_THREAD_H_ */
index 0f7cc46..48cffab 100644 (file)
@@ -17,4 +17,4 @@
 ;;; checkins which aren't released. (And occasionally for internal
 ;;; versions, especially for internal versions off the main CVS
 ;;; branch, it gets hairier, e.g. "0.pre7.14.flaky4.13".)
-"1.0.25.29"
+"1.0.25.30"