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);
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to