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
@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
(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
#define SIG_MEMORY_FAULT SIGSEGV
-#define SIG_INTERRUPT_THREAD (SIGRTMIN)
+#define SIG_INTERRUPT_THREAD (SIGPWR)
#define SIG_STOP_FOR_GC (SIGUSR1)
#define SIG_MEMORY_FAULT SIGSEGV
-#define SIG_INTERRUPT_THREAD (SIGRTMIN)
+#define SIG_INTERRUPT_THREAD (SIGPWR)
#define SIG_STOP_FOR_GC (SIGUSR1)
/* Yaargh?! */
}
}
-/* 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;
#endif
extern void create_initial_thread(lispobj);
-extern int kill_thread_safely(os_thread_t os_thread, int signo);
#endif /* _INCLUDE_THREAD_H_ */
;;; 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"