Author: kib
Date: Fri Oct 30 10:10:39 2009
New Revision: 198670
URL: http://svn.freebsd.org/changeset/base/198670

Log:
  Trapsignal() and postsig() call kern_sigprocmask() with both process
  lock and curproc->p_sigacts->ps_mtx. Reschedule_signals may need to have
  ps_mtx locked to decide and wakeup a thread, causing recursion on the
  mutex.
  
  Inform kern_sigprocmask() and reschedule_signals() about lock state
  of the ps_mtx by new flag SIGPROCMASK_PS_LOCKED to avoid recursion.
  
  Reported and tested by:       keramida
  MFC after:    1 month

Modified:
  head/sys/kern/kern_sig.c
  head/sys/sys/signalvar.h

Modified: head/sys/kern/kern_sig.c
==============================================================================
--- head/sys/kern/kern_sig.c    Fri Oct 30 08:53:11 2009        (r198669)
+++ head/sys/kern/kern_sig.c    Fri Oct 30 10:10:39 2009        (r198670)
@@ -220,7 +220,7 @@ static int sigproptbl[NSIG] = {
         SA_KILL|SA_PROC,               /* SIGUSR2 */
 };
 
-static void reschedule_signals(struct proc *p, sigset_t block);
+static void reschedule_signals(struct proc *p, sigset_t block, int flags);
 
 static void
 sigqueue_start(void)
@@ -1024,7 +1024,7 @@ kern_sigprocmask(struct thread *td, int 
         * possibly waking it up.
         */
        if (p->p_numthreads != 1)
-               reschedule_signals(p, new_block);
+               reschedule_signals(p, new_block, flags);
 
        if (!(flags & SIGPROCMASK_PROC_LOCKED))
                PROC_UNLOCK(p);
@@ -1859,13 +1859,11 @@ trapsignal(struct thread *td, ksiginfo_t
 #endif
                (*p->p_sysent->sv_sendsig)(ps->ps_sigact[_SIG_IDX(sig)], 
                                ksi, &td->td_sigmask);
-               SIGSETOR(td->td_sigmask, ps->ps_catchmask[_SIG_IDX(sig)]);
-               if (!SIGISMEMBER(ps->ps_signodefer, sig)) {
-                       SIGEMPTYSET(mask);
+               mask = ps->ps_catchmask[_SIG_IDX(sig)];
+               if (!SIGISMEMBER(ps->ps_signodefer, sig))
                        SIGADDSET(mask, sig);
-                       kern_sigprocmask(td, SIG_BLOCK, &mask, NULL,
-                           SIGPROCMASK_PROC_LOCKED);
-               }
+               kern_sigprocmask(td, SIG_BLOCK, &mask, NULL,
+                   SIGPROCMASK_PROC_LOCKED | SIGPROCMASK_PS_LOCKED);
                if (SIGISMEMBER(ps->ps_sigreset, sig)) {
                        /*
                         * See kern_sigaction() for origin of this code.
@@ -2401,7 +2399,7 @@ stopme:
 }
 
 static void
-reschedule_signals(struct proc *p, sigset_t block)
+reschedule_signals(struct proc *p, sigset_t block, int flags)
 {
        struct sigacts *ps;
        struct thread *td;
@@ -2419,12 +2417,14 @@ reschedule_signals(struct proc *p, sigse
 
                td = sigtd(p, i, 0);
                signotify(td);
-               mtx_lock(&ps->ps_mtx);
+               if (!(flags & SIGPROCMASK_PS_LOCKED))
+                       mtx_lock(&ps->ps_mtx);
                if (p->p_flag & P_TRACED || SIGISMEMBER(ps->ps_sigcatch, i))
                        tdsigwakeup(td, i, SIG_CATCH,
                            (SIGISMEMBER(ps->ps_sigintr, i) ? EINTR :
                             ERESTART));
-               mtx_unlock(&ps->ps_mtx);
+               if (!(flags & SIGPROCMASK_PS_LOCKED))
+                       mtx_unlock(&ps->ps_mtx);
        }
 }
 
@@ -2452,7 +2452,7 @@ tdsigcleanup(struct thread *td)
        SIGFILLSET(unblocked);
        SIGSETNAND(unblocked, td->td_sigmask);
        SIGFILLSET(td->td_sigmask);
-       reschedule_signals(p, unblocked);
+       reschedule_signals(p, unblocked, 0);
 
 }
 
@@ -2734,15 +2734,11 @@ postsig(sig)
                } else
                        returnmask = td->td_sigmask;
 
-               kern_sigprocmask(td, SIG_BLOCK,
-                   &ps->ps_catchmask[_SIG_IDX(sig)], NULL,
-                   SIGPROCMASK_PROC_LOCKED);
-               if (!SIGISMEMBER(ps->ps_signodefer, sig)) {
-                       SIGEMPTYSET(mask);
+               mask = ps->ps_catchmask[_SIG_IDX(sig)];
+               if (!SIGISMEMBER(ps->ps_signodefer, sig))
                        SIGADDSET(mask, sig);
-                       kern_sigprocmask(td, SIG_BLOCK, &mask, NULL,
-                           SIGPROCMASK_PROC_LOCKED);
-               }
+               kern_sigprocmask(td, SIG_BLOCK, &mask, NULL,
+                   SIGPROCMASK_PROC_LOCKED | SIGPROCMASK_PS_LOCKED);
 
                if (SIGISMEMBER(ps->ps_sigreset, sig)) {
                        /*

Modified: head/sys/sys/signalvar.h
==============================================================================
--- head/sys/sys/signalvar.h    Fri Oct 30 08:53:11 2009        (r198669)
+++ head/sys/sys/signalvar.h    Fri Oct 30 10:10:39 2009        (r198670)
@@ -319,6 +319,7 @@ extern int kern_logsigexit; /* Sysctl va
 /* flags for kern_sigprocmask */
 #define        SIGPROCMASK_OLD         0x0001
 #define        SIGPROCMASK_PROC_LOCKED 0x0002
+#define        SIGPROCMASK_PS_LOCKED   0x0004
 
 /*
  * Machine-independent functions:
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to