diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index e174df1..bfd6a1d 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -1450,40 +1450,21 @@ sigsuspend(td, uap) int kern_sigsuspend(struct thread *td, sigset_t mask) { - struct proc *p = td->td_proc; - int has_sig, sig; - - /* - * When returning from sigsuspend, we want - * the old mask to be restored after the - * signal handler has finished. Thus, we - * save it here and mark the sigacts structure - * to indicate this. - */ - PROC_LOCK(p); - kern_sigprocmask(td, SIG_SETMASK, &mask, &td->td_oldsigmask, - SIGPROCMASK_PROC_LOCKED); - td->td_pflags |= TDP_OLDMASK; /* - * Process signals now. Otherwise, we can get spurious wakeup - * due to signal entered process queue, but delivered to other - * thread. But sigsuspend should return only on signal - * delivery. + * When returning from sigsuspend, we want the old mask to be + * restored after the signal handler has finished. Thus, we + * save it here and mark the sigacts structure to indicate + * this. + * + * The signal is waited for in ast(), to make sure that signal + * is actually delivered. */ - for (has_sig = 0; !has_sig;) { - while (msleep(&p->p_sigacts, &p->p_mtx, PPAUSE|PCATCH, "pause", - 0) == 0) - /* void */; - thread_suspend_check(0); - mtx_lock(&p->p_sigacts->ps_mtx); - while ((sig = cursig(td, SIG_STOP_ALLOWED)) != 0) { - postsig(sig); - has_sig = 1; - } - mtx_unlock(&p->p_sigacts->ps_mtx); - } - PROC_UNLOCK(p); + kern_sigprocmask(td, SIG_SETMASK, &mask, &td->td_oldsigmask, 0); + td->td_pflags |= TDP_OLDMASK | TDP_SIGSUSPEND; + thread_lock(td); + td->td_flags |= TDF_ASTPENDING | TDF_NEEDSIGCHK; + thread_unlock(td); /* always return EINTR rather than ERESTART... */ return (EINTR); } diff --git a/sys/kern/subr_trap.c b/sys/kern/subr_trap.c index 4d20ebd..6dc40c6 100644 --- a/sys/kern/subr_trap.c +++ b/sys/kern/subr_trap.c @@ -230,9 +230,25 @@ ast(struct trapframe *framep) !SIGISEMPTY(p->p_siglist)) { PROC_LOCK(p); mtx_lock(&p->p_sigacts->ps_mtx); - while ((sig = cursig(td, SIG_STOP_ALLOWED)) != 0) + while ((sig = cursig(td, SIG_STOP_ALLOWED)) != 0) { postsig(sig); + td->td_pflags &= ~TDP_SIGSUSPEND; + } mtx_unlock(&p->p_sigacts->ps_mtx); + if (td->td_pflags & TDP_SIGSUSPEND) { + + /* + * Signal was not delivered. Reenter ast() + * after the wait. + */ + while (msleep(&p->p_sigacts, &p->p_mtx, PPAUSE|PCATCH, + "pause", 0) == 0) + /* void */; + thread_suspend_check(0); + thread_lock(td); + td->td_flags |= TDF_ASTPENDING | TDF_NEEDSIGCHK; + thread_unlock(td); + } PROC_UNLOCK(p); } /* @@ -245,7 +261,7 @@ ast(struct trapframe *framep) PROC_UNLOCK(p); } - if (td->td_pflags & TDP_OLDMASK) { + if ((td->td_pflags & (TDP_SIGSUSPEND | TDP_OLDMASK)) == TDP_OLDMASK) { td->td_pflags &= ~TDP_OLDMASK; kern_sigprocmask(td, SIG_SETMASK, &td->td_oldsigmask, NULL, 0); } diff --git a/sys/sys/proc.h b/sys/sys/proc.h index 384f280..bd8e467 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -351,7 +351,7 @@ do { \ #define TDP_COWINPROGRESS 0x00000010 /* Snapshot copy-on-write in progress. */ #define TDP_ALTSTACK 0x00000020 /* Have alternate signal stack. */ #define TDP_DEADLKTREAT 0x00000040 /* Lock aquisition - deadlock treatment. */ -#define TDP_UNUSED80 0x00000080 /* available. */ +#define TDP_SIGSUSPEND 0x00000080 /* ast() until signal is delivered. */ #define TDP_NOSLEEPING 0x00000100 /* Thread is not allowed to sleep on a sq. */ #define TDP_OWEUPC 0x00000200 /* Call addupc() at next AST. */ #define TDP_ITHREAD 0x00000400 /* Thread is an interrupt thread. */