Author: kib
Date: Tue Jun 28 16:41:50 2016
New Revision: 302250
URL: https://svnweb.freebsd.org/changeset/base/302250

Log:
  Complete r302215.  TDF_SBDRY | TDF_SERESTART and TDF_SBDRY |
  TDF_SEINTR flags values, unlike TDF_SBDRY, must be treated almost as
  if TDF_SBDRY is not set for STOP signal delivery.  The only difference
  is that sig_suspend_threads() should abort the sleep instead of doing
  immediate suspension.
  
  Reported by:  ngie
  Sponsored by: The FreeBSD Foundation
  MFC after:    12 days
  Approved by:  re (gjb)

Modified:
  head/sys/kern/kern_sig.c

Modified: head/sys/kern/kern_sig.c
==============================================================================
--- head/sys/kern/kern_sig.c    Tue Jun 28 16:41:02 2016        (r302249)
+++ head/sys/kern/kern_sig.c    Tue Jun 28 16:41:50 2016        (r302250)
@@ -107,7 +107,7 @@ static int  killpg1(struct thread *td, in
 static int     issignal(struct thread *td);
 static int     sigprop(int sig);
 static void    tdsigwakeup(struct thread *, int, sig_t, int);
-static void    sig_suspend_threads(struct thread *, struct proc *, int);
+static int     sig_suspend_threads(struct thread *, struct proc *, int);
 static int     filt_sigattach(struct knote *kn);
 static void    filt_sigdetach(struct knote *kn);
 static int     filt_signal(struct knote *kn, long hint);
@@ -2327,7 +2327,7 @@ tdsendsignal(struct proc *p, struct thre
                        p->p_flag |= P_STOPPED_SIG;
                        p->p_xsig = sig;
                        PROC_SLOCK(p);
-                       sig_suspend_threads(td, p, 1);
+                       wakeup_swapper = sig_suspend_threads(td, p, 1);
                        if (p->p_numthreads == p->p_suspcount) {
                                /*
                                 * only thread sending signal to another
@@ -2341,6 +2341,8 @@ tdsendsignal(struct proc *p, struct thre
                                sigqueue_delete_proc(p, p->p_xsig);
                        } else
                                PROC_SUNLOCK(p);
+                       if (wakeup_swapper)
+                               kick_proc0();
                        goto out;
                }
        } else {
@@ -2421,7 +2423,8 @@ tdsigwakeup(struct thread *td, int sig, 
                 * Don't awaken a sleeping thread for SIGSTOP if the
                 * STOP signal is deferred.
                 */
-               if ((prop & SA_STOP) && (td->td_flags & TDF_SBDRY))
+               if ((prop & SA_STOP) != 0 && (td->td_flags & (TDF_SBDRY |
+                   TDF_SERESTART | TDF_SEINTR)) == TDF_SBDRY)
                        goto out;
 
                /*
@@ -2449,14 +2452,16 @@ out:
                kick_proc0();
 }
 
-static void
+static int
 sig_suspend_threads(struct thread *td, struct proc *p, int sending)
 {
        struct thread *td2;
+       int wakeup_swapper;
 
        PROC_LOCK_ASSERT(p, MA_OWNED);
        PROC_SLOCK_ASSERT(p, MA_OWNED);
 
+       wakeup_swapper = 0;
        FOREACH_THREAD_IN_PROC(p, td2) {
                thread_lock(td2);
                td2->td_flags |= TDF_ASTPENDING | TDF_NEEDSUSPCHK;
@@ -2465,11 +2470,18 @@ sig_suspend_threads(struct thread *td, s
                        if (td2->td_flags & TDF_SBDRY) {
                                /*
                                 * Once a thread is asleep with
-                                * TDF_SBDRY set, it should never
+                                * TDF_SBDRY and without TDF_SERESTART
+                                * or TDF_SEINTR set, it should never
                                 * become suspended due to this check.
                                 */
                                KASSERT(!TD_IS_SUSPENDED(td2),
                                    ("thread with deferred stops suspended"));
+                               if ((td2->td_flags & (TDF_SERESTART |
+                                   TDF_SEINTR)) != 0 && sending) {
+                                       wakeup_swapper |= sleepq_abort(td,
+                                           (td2->td_flags & TDF_SERESTART)
+                                           != 0 ? ERESTART : EINTR);
+                               }
                        } else if (!TD_IS_SUSPENDED(td2)) {
                                thread_suspend_one(td2);
                        }
@@ -2483,6 +2495,7 @@ sig_suspend_threads(struct thread *td, s
                }
                thread_unlock(td2);
        }
+       return (wakeup_swapper);
 }
 
 int
@@ -2705,7 +2718,8 @@ issignal(struct thread *td)
                SIGSETOR(sigpending, p->p_sigqueue.sq_signals);
                SIGSETNAND(sigpending, td->td_sigmask);
 
-               if (p->p_flag & P_PPWAIT || td->td_flags & TDF_SBDRY)
+               if ((p->p_flag & P_PPWAIT) != 0 || (td->td_flags &
+                   (TDF_SBDRY | TDF_SERESTART | TDF_SEINTR)) == TDF_SBDRY)
                        SIG_STOPSIGMASK(sigpending);
                if (SIGISEMPTY(sigpending))     /* no signal to send */
                        return (0);
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to