svn commit: r315287 - in head: share/man/man9 sys/kern sys/sys

Eric van Gyzen vangyzen at FreeBSD.org
Tue Mar 14 22:02:04 UTC 2017


Author: vangyzen
Date: Tue Mar 14 22:02:02 2017
New Revision: 315287
URL: https://svnweb.freebsd.org/changeset/base/315287

Log:
  Add missing pieces of r315280
  
  I moved this branch from github to a private server, and pulled from the
  wrong one when committing r315280, so I failed to include two recent commits.
  Thankfully, they were only cosmetic and were included in the review.
  Specifically:
  
  Add documentation, polish comments, and improve style(9).
  
  Tested by:	pho (r315280)
  MFC after:	2 weeks
  Sponsored by:	Dell EMC
  Differential Revision:	https://reviews.freebsd.org/D9791

Modified:
  head/share/man/man9/sleep.9
  head/sys/kern/kern_tc.c
  head/sys/kern/subr_sleepqueue.c
  head/sys/sys/proc.h

Modified: head/share/man/man9/sleep.9
==============================================================================
--- head/share/man/man9/sleep.9	Tue Mar 14 20:57:54 2017	(r315286)
+++ head/share/man/man9/sleep.9	Tue Mar 14 22:02:02 2017	(r315287)
@@ -280,6 +280,21 @@ to
 pay particular attention to ensure that no other threads wait on the
 same
 .Fa chan .
+.Pp
+If the timeout given by
+.Fa timo
+or
+.Fa sbt
+is based on an absolute real-time clock value,
+then the thread should copy the global
+.Va rtc_generation
+into its
+.Va td_rtcgen
+member before reading the RTC.
+If the real-time clock is adjusted, these functions will set
+.Va td_rtcgen
+to zero and return zero.
+The caller should reconsider its orientation with the new RTC value.
 .Sh RETURN VALUES
 When awakened by a call to
 .Fn wakeup
@@ -298,6 +313,9 @@ the
 .Fn msleep_spin ,
 .Fn tsleep ,
 and locking primitive sleep functions return 0.
+Zero can also be returned when the real-time clock is adjusted;
+see above regarding
+.Va td_rtcgen .
 Otherwise, a non-zero error code is returned.
 .Sh ERRORS
 .Fn msleep ,

Modified: head/sys/kern/kern_tc.c
==============================================================================
--- head/sys/kern/kern_tc.c	Tue Mar 14 20:57:54 2017	(r315286)
+++ head/sys/kern/kern_tc.c	Tue Mar 14 22:02:02 2017	(r315287)
@@ -1269,6 +1269,15 @@ static bool
 sleeping_on_old_rtc(struct thread *td)
 {
 
+	/*
+	 * td_rtcgen is modified by curthread when it is running,
+	 * and by other threads in this function.  By finding the thread
+	 * on a sleepqueue and holding the lock on the sleepqueue
+	 * chain, we guarantee that the thread is not running and that
+	 * modifying td_rtcgen is safe.  Setting td_rtcgen to zero informs
+	 * the thread that it was woken due to a real-time clock adjustment.
+	 * (The declaration of td_rtcgen refers to this comment.)
+	 */
 	if (td->td_rtcgen != 0 && td->td_rtcgen != rtc_generation) {
 		td->td_rtcgen = 0;
 		return (true);
@@ -1299,6 +1308,7 @@ tc_setclock(struct timespec *ts)
 	/* XXX fiddle all the little crinkly bits around the fiords... */
 	tc_windup(&bt);
 	mtx_unlock_spin(&tc_setclock_mtx);
+
 	/* Avoid rtc_generation == 0, since td_rtcgen == 0 is special. */
 	atomic_add_rel_int(&rtc_generation, 2);
 	sleepq_chains_remove_matching(sleeping_on_old_rtc);

Modified: head/sys/kern/subr_sleepqueue.c
==============================================================================
--- head/sys/kern/subr_sleepqueue.c	Tue Mar 14 20:57:54 2017	(r315286)
+++ head/sys/kern/subr_sleepqueue.c	Tue Mar 14 22:02:02 2017	(r315287)
@@ -561,9 +561,21 @@ sleepq_switch(void *wchan, int pri)
 	/*
 	 * If TDF_TIMEOUT is set, then our sleep has been timed out
 	 * already but we are still on the sleep queue, so dequeue the
-	 * thread and return.  Do the same if the real-time clock has
-	 * been adjusted since this thread calculated its timeout
-	 * based on that clock.
+	 * thread and return.
+	 *
+	 * Do the same if the real-time clock has been adjusted since this
+	 * thread calculated its timeout based on that clock.  This handles
+	 * the following race:
+	 * - The Ts thread needs to sleep until an absolute real-clock time.
+	 *   It copies the global rtc_generation into curthread->td_rtcgen,
+	 *   reads the RTC, and calculates a sleep duration based on that time.
+	 *   See umtxq_sleep() for an example.
+	 * - The Tc thread adjusts the RTC, bumps rtc_generation, and wakes
+	 *   threads that are sleeping until an absolute real-clock time.
+	 *   See tc_setclock() and the POSIX specification of clock_settime().
+	 * - Ts reaches the code below.  It holds the sleepqueue chain lock,
+	 *   so Tc has finished waking, so this thread must test td_rtcgen.
+	 * (The declaration of td_rtcgen refers to this comment.)
 	 */
 	rtc_changed = td->td_rtcgen != 0 && td->td_rtcgen != rtc_generation;
 	if ((td->td_flags & TDF_TIMEOUT) || rtc_changed) {
@@ -899,6 +911,7 @@ sleepq_signal(void *wchan, int flags, in
 static bool
 match_any(struct thread *td __unused)
 {
+
 	return (true);
 }
 

Modified: head/sys/sys/proc.h
==============================================================================
--- head/sys/sys/proc.h	Tue Mar 14 20:57:54 2017	(r315286)
+++ head/sys/sys/proc.h	Tue Mar 14 22:02:02 2017	(r315287)
@@ -148,7 +148,7 @@ struct pargs {
  *      o - ktrace lock
  *      q - td_contested lock
  *      r - p_peers lock
- *      s - by curthread, or by others when curthread is on sleepqueue
+ *      s - see sleepq_switch(), sleeping_on_old_rtc(), and sleep(9)
  *      t - thread lock
  *	u - process stat lock
  *	w - process timer lock


More information about the svn-src-head mailing list