(signal sb!alien:int))
;;; Send the signal SIGNAL to the process with process id PID. SIGNAL
-;;; should be a valid signal number or a keyword of the standard UNIX
-;;; signal name.
+;;; should be a valid signal number
(defun unix-kill (pid signal)
(real-unix-kill pid signal))
(signal sb!alien:int))
;;; Send the signal SIGNAL to the all the process in process group
-;;; PGRP. SIGNAL should be a valid signal number or a keyword of the
-;;; standard UNIX signal name.
+;;; PGRP. SIGNAL should be a valid signal number
(defun unix-killpg (pgrp signal)
(real-unix-killpg pgrp signal))
sb!alien:unsigned-long
(signal sb!alien:int)
(handler sb!alien:unsigned-long))
+;;; assert (though non-fatally) that there are no signals masked
+(sb!alien:define-alien-routine "warn_when_signals_masked" sb!alien:void)
+
\f
+
+
+
;;;; interface to enabling and disabling signal handlers
(defun enable-interrupt (signal handler)
(abort
"~@<Reduce debugger level (leaving debugger, returning to toplevel).~@:>")
(catch 'toplevel-catcher
- #!-sunos (sb!unix:unix-sigsetmask 0) ; FIXME: What is this for?
+ (sb!unix::warn-when-signals-masked)
;; in the event of a control-stack-exhausted-error, we should
;; have unwound enough stack by the time we get here that this
;; is now possible
(loop
;; (See comment preceding the definition of SCRUB-CONTROL-STACK.)
(scrub-control-stack)
+ (sb!thread::get-foreground)
(unless noprint
(funcall *repl-prompt-fun* *standard-output*)
;; (Should *REPL-PROMPT-FUN* be responsible for doing its own
(tls-cookie) ; on x86, the LDT index
(this :c-type "struct thread *" :length #!+alpha 2 #!-alpha 1)
(next :c-type "struct thread *" :length #!+alpha 2 #!-alpha 1)
+ (state) ; running, stopping, stopped
#!+x86 (pseudo-atomic-atomic)
#!+x86 (pseudo-atomic-interrupted)
(interrupt-data :c-type "struct interrupt_data *"
os_context_t *context);
boolean interrupt_maybe_gc_int(int signal, siginfo_t *info, void *v_context);
-extern lispobj all_threads_lock;
+extern volatile lispobj all_threads_lock;
extern volatile int countdown_to_gc;
/*
struct interrupt_data * global_interrupt_data;
+/* this is used from Lisp in toplevel.lisp, replacing an older
+ * (sigsetmask 0) - we'd like to find out when the signal mask is
+ * not 0 */
+
+/* This check was introduced in 0.8.4.x and some day will go away
+ * again unless we find a way to trigger it */
+
+void warn_when_signals_masked ()
+{
+ /* and as a side-eeffect, unmask them */
+ sigset_t new,old;
+ int i;
+ int wrong=0;
+ sigemptyset(&new);
+ sigprocmask(SIG_SETMASK,&new,&old);
+ for(i=1; i<NSIG; i++) {
+ if(sigismember(&old,i)) {
+ fprintf(stderr,
+ "Warning: signal %d is masked: this is unexpected\n",i);
+ wrong=1;
+ }
+ }
+ if(wrong)
+ fprintf(stderr,"If this version of SBCL is less than three months old, please report this.\nOtherwise, please try a newer version first\n. Reset signal mask.\n");
+}
+
\f
/*
* utility routines used by various signal handlers
get_spinlock(&all_threads_lock,thread->pid);
countdown_to_gc--;
+ thread->state=STATE_STOPPED;
release_spinlock(&all_threads_lock);
kill(thread->pid,SIGSTOP);
}
#ifdef LISP_FEATURE_SB_THREAD
+int show_thread_exit=0;
static void /* noreturn */ parent_loop(void)
{
if(WIFEXITED(status) || WIFSIGNALED(status)) {
th=find_thread_by_pid(pid);
if(!th) continue;
- fprintf(stderr,"waitpid : child %d %x exited \n", pid,th);
+ if(show_thread_exit)
+ fprintf(stderr,"waitpid : child %d %x exited \n", pid,th);
destroy_thread(th);
if(!all_threads) break;
}
int dynamic_values_bytes=4096*sizeof(lispobj); /* same for all threads */
struct thread *all_threads;
-lispobj all_threads_lock;
+volatile lispobj all_threads_lock;
volatile int countdown_to_gc;
extern struct interrupt_data * global_interrupt_data;
#endif
get_spinlock(&all_threads_lock,th->pid);
if(countdown_to_gc>0) countdown_to_gc--;
+ th->state=STATE_STOPPED;
if(th==all_threads)
all_threads=th->next;
else {
* for them on each time around */
for(p=all_threads;p!=tail;p=p->next) {
if(p==th) continue;
- countdown_to_gc++;
- kill(p->pid,SIG_STOP_FOR_GC);
+ /* if the head of all_threads is removed during
+ * gc_stop_the_world, we may take a second trip through the
+ * list and end up counting twice as many threads to wait for
+ * as actually exist */
+ if(p->state!=STATE_RUNNING) continue;
+ countdown_to_gc++;
+ p->state=STATE_STOPPING;
+ /* Note no return value check from kill(). If the
+ * thread had been reaped already, we kill it and
+ * increment countdown_to_gc anyway. This is to avoid
+ * complicating the logic in destroy_thread, which would
+ * otherwise have to know whether the thread died before or
+ * after it was killed
+ */
+ kill(p->pid,SIG_STOP_FOR_GC);
}
tail=all_threads;
} else {
get_spinlock(&all_threads_lock,th->pid);
for(p=all_threads;p;p=p->next) {
if(p==th) continue;
+ p->state=STATE_RUNNING;
kill(p->pid,SIGCONT);
}
release_spinlock(&all_threads_lock);
#include "genesis/static-symbols.h"
#include "genesis/thread.h"
+#define STATE_RUNNING (make_fixnum(0))
+#define STATE_STOPPING (make_fixnum(1))
+#define STATE_STOPPED (make_fixnum(2))
+
#define THREAD_SLOT_OFFSET_WORDS(c) \
(offsetof(struct thread,c)/(sizeof (struct thread *)))
;;; 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".)
-"0.8.4.7"
+"0.8.4.8"