Author: jeff
Date: Sun Dec 15 21:18:07 2019
New Revision: 355781
URL: https://svnweb.freebsd.org/changeset/base/355781

Log:
  schedlock 2/4
  
  Do all sleepqueue post-processing in sleepq_remove_thread() so that we
  do not require the thread lock after a context switch.
  
  Reviewed by:  jhb, kib
  Differential Revision:        https://reviews.freebsd.org/D22745

Modified:
  head/sys/kern/subr_sleepqueue.c
  head/sys/sys/proc.h

Modified: head/sys/kern/subr_sleepqueue.c
==============================================================================
--- head/sys/kern/subr_sleepqueue.c     Sun Dec 15 21:16:35 2019        
(r355780)
+++ head/sys/kern/subr_sleepqueue.c     Sun Dec 15 21:18:07 2019        
(r355781)
@@ -164,8 +164,8 @@ static uma_zone_t sleepq_zone;
  * Prototypes for non-exported routines.
  */
 static int     sleepq_catch_signals(void *wchan, int pri);
-static int     sleepq_check_signals(void);
-static int     sleepq_check_timeout(void);
+static inline int sleepq_check_signals(void);
+static inline int sleepq_check_timeout(void);
 #ifdef INVARIANTS
 static void    sleepq_dtor(void *mem, int size, void *arg);
 #endif
@@ -378,9 +378,10 @@ sleepq_add(void *wchan, struct lock_object *lock, cons
        td->td_wchan = wchan;
        td->td_wmesg = wmesg;
        if (flags & SLEEPQ_INTERRUPTIBLE) {
+               td->td_intrval = 0;
                td->td_flags |= TDF_SINTR;
-               td->td_flags &= ~TDF_SLEEPABORT;
        }
+       td->td_flags &= ~TDF_TIMEOUT;
        thread_unlock(td);
 }
 
@@ -624,63 +625,35 @@ sleepq_switch(void *wchan, int pri)
 /*
  * Check to see if we timed out.
  */
-static int
+static inline int
 sleepq_check_timeout(void)
 {
        struct thread *td;
        int res;
 
-       td = curthread;
-       THREAD_LOCK_ASSERT(td, MA_OWNED);
-
-       /*
-        * If TDF_TIMEOUT is set, we timed out.  But recheck
-        * td_sleeptimo anyway.
-        */
        res = 0;
+       td = curthread;
        if (td->td_sleeptimo != 0) {
                if (td->td_sleeptimo <= sbinuptime())
                        res = EWOULDBLOCK;
                td->td_sleeptimo = 0;
        }
-       if (td->td_flags & TDF_TIMEOUT)
-               td->td_flags &= ~TDF_TIMEOUT;
-       else
-               /*
-                * We ignore the situation where timeout subsystem was
-                * unable to stop our callout.  The struct thread is
-                * type-stable, the callout will use the correct
-                * memory when running.  The checks of the
-                * td_sleeptimo value in this function and in
-                * sleepq_timeout() ensure that the thread does not
-                * get spurious wakeups, even if the callout was reset
-                * or thread reused.
-                */
-               callout_stop(&td->td_slpcallout);
        return (res);
 }
 
 /*
  * Check to see if we were awoken by a signal.
  */
-static int
+static inline int
 sleepq_check_signals(void)
 {
        struct thread *td;
 
        td = curthread;
-       THREAD_LOCK_ASSERT(td, MA_OWNED);
+       KASSERT((td->td_flags & TDF_SINTR) == 0,
+           ("thread %p still in interruptible sleep?", td));
 
-       /* We are no longer in an interruptible sleep. */
-       if (td->td_flags & TDF_SINTR)
-               td->td_flags &= ~TDF_SINTR;
-
-       if (td->td_flags & TDF_SLEEPABORT) {
-               td->td_flags &= ~TDF_SLEEPABORT;
-               return (td->td_intrval);
-       }
-
-       return (0);
+       return (td->td_intrval);
 }
 
 /*
@@ -706,14 +679,12 @@ int
 sleepq_wait_sig(void *wchan, int pri)
 {
        int rcatch;
-       int rval;
 
        rcatch = sleepq_catch_signals(wchan, pri);
-       rval = sleepq_check_signals();
        thread_unlock(curthread);
        if (rcatch)
                return (rcatch);
-       return (rval);
+       return (sleepq_check_signals());
 }
 
 /*
@@ -724,16 +695,14 @@ int
 sleepq_timedwait(void *wchan, int pri)
 {
        struct thread *td;
-       int rval;
 
        td = curthread;
        MPASS(!(td->td_flags & TDF_SINTR));
        thread_lock(td);
        sleepq_switch(wchan, pri);
-       rval = sleepq_check_timeout();
        thread_unlock(td);
 
-       return (rval);
+       return (sleepq_check_timeout());
 }
 
 /*
@@ -746,9 +715,11 @@ sleepq_timedwait_sig(void *wchan, int pri)
        int rcatch, rvalt, rvals;
 
        rcatch = sleepq_catch_signals(wchan, pri);
+       thread_unlock(curthread);
+
+       /* We must always call check_timeout() to clear sleeptimo. */
        rvalt = sleepq_check_timeout();
        rvals = sleepq_check_signals();
-       thread_unlock(curthread);
        if (rcatch)
                return (rcatch);
        if (rvals)
@@ -877,9 +848,22 @@ sleepq_remove_thread(struct sleepqueue *sq, struct thr
                td->td_sleepqueue = LIST_FIRST(&sq->sq_free);
        LIST_REMOVE(td->td_sleepqueue, sq_hash);
 
+       if ((td->td_flags & TDF_TIMEOUT) == 0 && td->td_sleeptimo != 0)
+               /*
+                * We ignore the situation where timeout subsystem was
+                * unable to stop our callout.  The struct thread is
+                * type-stable, the callout will use the correct
+                * memory when running.  The checks of the
+                * td_sleeptimo value in this function and in
+                * sleepq_timeout() ensure that the thread does not
+                * get spurious wakeups, even if the callout was reset
+                * or thread reused.
+                */
+               callout_stop(&td->td_slpcallout);
+
        td->td_wmesg = NULL;
        td->td_wchan = NULL;
-       td->td_flags &= ~TDF_SINTR;
+       td->td_flags &= ~(TDF_SINTR | TDF_TIMEOUT);
 
        CTR3(KTR_PROC, "sleepq_wakeup: thread %p (pid %ld, %s)",
            (void *)td, (long)td->td_proc->p_pid, td->td_name);
@@ -1047,7 +1031,7 @@ sleepq_timeout(void *arg)
            (void *)td, (long)td->td_proc->p_pid, (void *)td->td_name);
 
        thread_lock(td);
-       if (td->td_sleeptimo > sbinuptime() || td->td_sleeptimo == 0) {
+       if (td->td_sleeptimo == 0 || td->td_sleeptimo > sbinuptime()) {
                /*
                 * The thread does not want a timeout (yet).
                 */
@@ -1146,7 +1130,6 @@ sleepq_abort(struct thread *td, int intrval)
        CTR3(KTR_PROC, "sleepq_abort: thread %p (pid %ld, %s)",
            (void *)td, (long)td->td_proc->p_pid, (void *)td->td_name);
        td->td_intrval = intrval;
-       td->td_flags |= TDF_SLEEPABORT;
 
        /*
         * If the thread has not slept yet it will find the signal in

Modified: head/sys/sys/proc.h
==============================================================================
--- head/sys/sys/proc.h Sun Dec 15 21:16:35 2019        (r355780)
+++ head/sys/sys/proc.h Sun Dec 15 21:18:07 2019        (r355781)
@@ -431,7 +431,7 @@ do {                                                        
                \
 #define        TDF_TIMEOUT     0x00000010 /* Timing out during sleep. */
 #define        TDF_IDLETD      0x00000020 /* This is a per-CPU idle thread. */
 #define        TDF_CANSWAP     0x00000040 /* Thread can be swapped. */
-#define        TDF_SLEEPABORT  0x00000080 /* sleepq_abort was called. */
+#define        TDF_UNUSED80    0x00000080 /* unused. */
 #define        TDF_KTH_SUSP    0x00000100 /* kthread is suspended */
 #define        TDF_ALLPROCSUSP 0x00000200 /* suspended by SINGLE_ALLPROC */
 #define        TDF_BOUNDARY    0x00000400 /* Thread suspended at user boundary 
*/
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to