summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_sig.c
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2009-11-10 11:46:53 +0000
committerkib <kib@FreeBSD.org>2009-11-10 11:46:53 +0000
commitcd432c18cdf98aaa39b871b643d199d910a1ee8a (patch)
tree917e1b3f029e242c345060d1c391854db34e85ef /sys/kern/kern_sig.c
parent3cf53f181e7360f48fecc50a925d46029888af1d (diff)
downloadFreeBSD-src-cd432c18cdf98aaa39b871b643d199d910a1ee8a.zip
FreeBSD-src-cd432c18cdf98aaa39b871b643d199d910a1ee8a.tar.gz
In r198506, kern_sigsuspend() started doing cursig/postsig loop to make
sure that a signal was delivered to the thread before returning from syscall. Signal delivery puts new return frame on the user stack, and modifies trap frame to enter signal handler. As a consequence, syscall return code sets EINTR as error return for signal frame, instead of the syscall return. Also, for ia64, due to different registers layout for those two kind of frames, usermode sigsegfaulted when returned from signal handler. Use newly-introduced cpu_set_syscall_retval(9) to set syscall result, and return EJUSTRETURN from kern_sigsuspend() to prevent syscall return code from modifying this frame [1]. Another issue is that pending SIGCONT might be cancelled by SIGSTOP, causing postsig() not to deliver any catched signal [2]. Modify postsig() to return 1 if signal was posted, and 0 otherwise, and use this in the kern_sigsuspend loop. Proposed by: marcel [1] Noted by: davidxu [2] Reviewed by: marcel, davidxu MFC after: 1 month
Diffstat (limited to 'sys/kern/kern_sig.c')
-rw-r--r--sys/kern/kern_sig.c15
1 files changed, 7 insertions, 8 deletions
diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c
index e174df1..412e00d 100644
--- a/sys/kern/kern_sig.c
+++ b/sys/kern/kern_sig.c
@@ -1471,21 +1471,19 @@ kern_sigsuspend(struct thread *td, sigset_t mask)
* thread. But sigsuspend should return only on signal
* delivery.
*/
+ cpu_set_syscall_retval(td, EINTR);
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;
- }
+ while ((sig = cursig(td, SIG_STOP_ALLOWED)) != 0)
+ has_sig += postsig(sig);
mtx_unlock(&p->p_sigacts->ps_mtx);
}
PROC_UNLOCK(p);
- /* always return EINTR rather than ERESTART... */
- return (EINTR);
+ return (EJUSTRETURN);
}
#ifdef COMPAT_43 /* XXX - COMPAT_FBSD3 */
@@ -2670,7 +2668,7 @@ thread_stopped(struct proc *p)
* Take the action for the specified signal
* from the current set of pending signals.
*/
-void
+int
postsig(sig)
register int sig;
{
@@ -2689,7 +2687,7 @@ postsig(sig)
ksiginfo_init(&ksi);
if (sigqueue_get(&td->td_sigqueue, sig, &ksi) == 0 &&
sigqueue_get(&p->p_sigqueue, sig, &ksi) == 0)
- return;
+ return (0);
ksi.ksi_signo = sig;
if (ksi.ksi_code == SI_TIMER)
itimer_accept(p, ksi.ksi_timerid, &ksi);
@@ -2757,6 +2755,7 @@ postsig(sig)
}
(*p->p_sysent->sv_sendsig)(action, &ksi, &returnmask);
}
+ return (1);
}
/*
OpenPOWER on IntegriCloud