Date: Sun, 15 Dec 2019 21:18:07 +0000 (UTC) From: Jeff Roberson <jeff@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r355781 - in head/sys: kern sys Message-ID: <201912152118.xBFLI72d031613@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
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 */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201912152118.xBFLI72d031613>