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-all mailing list