svn commit: r200721 - in stable/8/sys: compat/freebsd32 kern sys
Konstantin Belousov
kib at FreeBSD.org
Sat Dec 19 11:14:00 UTC 2009
Author: kib
Date: Sat Dec 19 11:13:59 2009
New Revision: 200721
URL: http://svn.freebsd.org/changeset/base/200721
Log:
MFC r198506:
In kern_sigsuspend(), manipulate thread signal mask using
kern_sigprocmask(). Also, do cursig/postsig loop immediately after
waiting for signal, repeating the wait if wakeup was spurious due to
race with other thread fetching signal from the process queue before us.
MFC r199136:
Use cpu_set_syscall_retval(9) to set syscall result, and return
EJUSTRETURN from kern_sigsuspend() to prevent syscall return code from
modifying wrong frame.
Take care of possibility that pending SIGCONT might be cancelled by
SIGSTOP, causing postsig() not to deliver any catched signal.
Modified:
stable/8/sys/compat/freebsd32/freebsd32_misc.c
stable/8/sys/kern/kern_sig.c
stable/8/sys/sys/signalvar.h
stable/8/sys/sys/syscallsubr.h
Directory Properties:
stable/8/sys/ (props changed)
stable/8/sys/amd64/include/xen/ (props changed)
stable/8/sys/cddl/contrib/opensolaris/ (props changed)
stable/8/sys/contrib/dev/acpica/ (props changed)
stable/8/sys/contrib/pf/ (props changed)
stable/8/sys/dev/xen/xenpci/ (props changed)
Modified: stable/8/sys/compat/freebsd32/freebsd32_misc.c
==============================================================================
--- stable/8/sys/compat/freebsd32/freebsd32_misc.c Sat Dec 19 11:11:57 2009 (r200720)
+++ stable/8/sys/compat/freebsd32/freebsd32_misc.c Sat Dec 19 11:13:59 2009 (r200721)
@@ -2579,21 +2579,10 @@ int
ofreebsd32_sigsuspend(struct thread *td,
struct ofreebsd32_sigsuspend_args *uap)
{
- struct proc *p = td->td_proc;
sigset_t mask;
- PROC_LOCK(p);
- td->td_oldsigmask = td->td_sigmask;
- td->td_pflags |= TDP_OLDMASK;
OSIG2SIG(uap->mask, mask);
- SIG_CANTMASK(mask);
- SIGSETLO(td->td_sigmask, mask);
- signotify(td);
- while (msleep(&p->p_sigacts, &p->p_mtx, PPAUSE|PCATCH, "opause", 0) == 0)
- /* void */;
- PROC_UNLOCK(p);
- /* always return EINTR rather than ERESTART... */
- return (EINTR);
+ return (kern_sigsuspend(td, mask));
}
struct sigstack32 {
Modified: stable/8/sys/kern/kern_sig.c
==============================================================================
--- stable/8/sys/kern/kern_sig.c Sat Dec 19 11:11:57 2009 (r200720)
+++ stable/8/sys/kern/kern_sig.c Sat Dec 19 11:13:59 2009 (r200721)
@@ -966,14 +966,15 @@ execsigs(struct proc *p)
*/
int
kern_sigprocmask(struct thread *td, int how, sigset_t *set, sigset_t *oset,
- int old)
+ int flags)
{
sigset_t new_block, oset1;
struct proc *p;
int error;
p = td->td_proc;
- PROC_LOCK(p);
+ if (!(flags & SIGPROCMASK_PROC_LOCKED))
+ PROC_LOCK(p);
if (oset != NULL)
*oset = td->td_sigmask;
@@ -995,7 +996,7 @@ kern_sigprocmask(struct thread *td, int
case SIG_SETMASK:
SIG_CANTMASK(*set);
oset1 = td->td_sigmask;
- if (old)
+ if (flags & SIGPROCMASK_OLD)
SIGSETLO(td->td_sigmask, *set);
else
td->td_sigmask = *set;
@@ -1021,7 +1022,8 @@ kern_sigprocmask(struct thread *td, int
if (p->p_numthreads != 1)
reschedule_signals(p, new_block);
- PROC_UNLOCK(p);
+ if (!(flags & SIGPROCMASK_PROC_LOCKED))
+ PROC_UNLOCK(p);
return (error);
}
@@ -1454,6 +1456,7 @@ 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
@@ -1463,16 +1466,29 @@ kern_sigsuspend(struct thread *td, sigse
* to indicate this.
*/
PROC_LOCK(p);
- td->td_oldsigmask = td->td_sigmask;
+ kern_sigprocmask(td, SIG_SETMASK, &mask, &td->td_oldsigmask,
+ SIGPROCMASK_PROC_LOCKED);
td->td_pflags |= TDP_OLDMASK;
- SIG_CANTMASK(mask);
- td->td_sigmask = mask;
- signotify(td);
- while (msleep(&p->p_sigacts, &p->p_mtx, PPAUSE|PCATCH, "pause", 0) == 0)
- /* void */;
+
+ /*
+ * 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.
+ */
+ 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)
+ 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 */
@@ -1491,21 +1507,10 @@ osigsuspend(td, uap)
struct thread *td;
struct osigsuspend_args *uap;
{
- struct proc *p = td->td_proc;
sigset_t mask;
- PROC_LOCK(p);
- td->td_oldsigmask = td->td_sigmask;
- td->td_pflags |= TDP_OLDMASK;
OSIG2SIG(uap->mask, mask);
- SIG_CANTMASK(mask);
- SIGSETLO(td->td_sigmask, mask);
- signotify(td);
- while (msleep(&p->p_sigacts, &p->p_mtx, PPAUSE|PCATCH, "opause", 0) == 0)
- /* void */;
- PROC_UNLOCK(p);
- /* always return EINTR rather than ERESTART... */
- return (EINTR);
+ return (kern_sigsuspend(td, mask));
}
#endif /* COMPAT_43 */
@@ -2662,7 +2667,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;
{
@@ -2681,7 +2686,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);
@@ -2747,6 +2752,7 @@ postsig(sig)
}
(*p->p_sysent->sv_sendsig)(action, &ksi, &returnmask);
}
+ return (1);
}
/*
Modified: stable/8/sys/sys/signalvar.h
==============================================================================
--- stable/8/sys/sys/signalvar.h Sat Dec 19 11:11:57 2009 (r200720)
+++ stable/8/sys/sys/signalvar.h Sat Dec 19 11:13:59 2009 (r200721)
@@ -316,6 +316,10 @@ extern int kern_logsigexit; /* Sysctl va
#define SIG_STOP_ALLOWED 100
#define SIG_STOP_NOT_ALLOWED 101
+/* flags for kern_sigprocmask */
+#define SIGPROCMASK_OLD 0x0001
+#define SIGPROCMASK_PROC_LOCKED 0x0002
+
/*
* Machine-independent functions:
*/
@@ -325,7 +329,7 @@ void gsignal(int pgid, int sig);
void killproc(struct proc *p, char *why);
void pgsigio(struct sigio **, int signum, int checkctty);
void pgsignal(struct pgrp *pgrp, int sig, int checkctty);
-void postsig(int sig);
+int postsig(int sig);
void psignal(struct proc *p, int sig);
int psignal_event(struct proc *p, struct sigevent *, ksiginfo_t *);
struct sigacts *sigacts_alloc(void);
@@ -359,7 +363,8 @@ void sigqueue_delete_stopmask_proc(struc
void sigqueue_take(ksiginfo_t *ksi);
int kern_sigtimedwait(struct thread *, sigset_t,
ksiginfo_t *, struct timespec *);
-
+int kern_sigprocmask(struct thread *td, int how,
+ sigset_t *set, sigset_t *oset, int flags);
/*
* Machine-dependent functions:
*/
Modified: stable/8/sys/sys/syscallsubr.h
==============================================================================
--- stable/8/sys/sys/syscallsubr.h Sat Dec 19 11:11:57 2009 (r200720)
+++ stable/8/sys/sys/syscallsubr.h Sat Dec 19 11:13:59 2009 (r200721)
@@ -190,8 +190,6 @@ int kern_shmctl(struct thread *td, int s
int kern_sigaction(struct thread *td, int sig, struct sigaction *act,
struct sigaction *oact, int flags);
int kern_sigaltstack(struct thread *td, stack_t *ss, stack_t *oss);
-int kern_sigprocmask(struct thread *td, int how,
- sigset_t *set, sigset_t *oset, int old);
int kern_sigsuspend(struct thread *td, sigset_t mask);
int kern_stat(struct thread *td, char *path, enum uio_seg pathseg,
struct stat *sbp);
More information about the svn-src-stable
mailing list