Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 14 Feb 2018 18:43:50 +0000 (UTC)
From:      Bryan Drewery <bdrewery@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r329271 - in head: contrib/netbsd-tests/lib/libc/sys sys/kern
Message-ID:  <201802141843.w1EIhocY056637@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: bdrewery
Date: Wed Feb 14 18:43:50 2018
New Revision: 329271
URL: https://svnweb.freebsd.org/changeset/base/329271

Log:
  nanosleep(2): Fix bogus incrementing of rmtp by tc_tick_sbt on [EINTR].
  
  sbt is the time in the future that the tsleep_sbt() is expected to be completed
  at.  sbtt is the current time.  Depending on the precision with sysctl
  kern.timecounter.alloweddeviation the start time may be incremented by
  tc_tick_sbt.  The same increment is needed for the current time of sbtt before
  calculating the difference.  The impact of missing this increment is that rmtp
  may increase by one tc_tick_sbt on every early [EINTR] return.  If the same
  struct is passed in for rqtp as rmtp this can result in rqtp effectively
  incrementing by tc_tick_sbt and sleeping longer than originally intended.
  
  This problem was introduced in r247797.
  
  Reviewed by:	kib, markj, vangyzen (all on an older version of the test)
  MFC after:	2 weeks
  Sponsored by:	Dell EMC
  Differential Revision:	https://reviews.freebsd.org/D14362

Modified:
  head/contrib/netbsd-tests/lib/libc/sys/t_nanosleep.c
  head/sys/kern/kern_time.c

Modified: head/contrib/netbsd-tests/lib/libc/sys/t_nanosleep.c
==============================================================================
--- head/contrib/netbsd-tests/lib/libc/sys/t_nanosleep.c	Wed Feb 14 18:21:54 2018	(r329270)
+++ head/contrib/netbsd-tests/lib/libc/sys/t_nanosleep.c	Wed Feb 14 18:43:50 2018	(r329271)
@@ -50,6 +50,15 @@ handler(int signo __unused)
 	/* Nothing. */
 }
 
+static int got_info;
+static void
+info_handler(int signo __unused)
+{
+
+	got_info = 1;
+}
+
+
 ATF_TC(nanosleep_basic);
 ATF_TC_HEAD(nanosleep_basic, tc)
 {
@@ -176,12 +185,84 @@ ATF_TC_BODY(nanosleep_sig, tc)
 		atf_tc_fail("signal did not interrupt nanosleep(2)");
 }
 
+ATF_TC(nanosleep_eintr);
+ATF_TC_HEAD(nanosleep_eintr, tc)
+{
+	atf_tc_set_md_var(tc, "descr", "Test [EINTR] for nanosleep(2)");
+	atf_tc_set_md_var(tc, "timeout", "7");
+}
+
+ATF_TC_BODY(nanosleep_eintr, tc)
+{
+	struct sigaction act;
+	struct timespec tso, ts;
+	pid_t pid;
+	int sta;
+
+	/*
+	 * Test that [EINTR] properly handles rmtp for nanosleep(2).
+	 */
+	pid = fork();
+
+	ATF_REQUIRE(pid >= 0);
+
+	got_info = 0;
+
+	if (pid == 0) {
+		act.sa_handler = info_handler;
+		sigemptyset(&act.sa_mask);
+		act.sa_flags = 0; /* Don't allow restart. */
+		ATF_REQUIRE(sigaction(SIGINFO, &act, NULL) == 0);
+
+		tso.tv_sec = 5;
+		tso.tv_nsec = 0;
+
+		ts.tv_sec = tso.tv_sec;
+		ts.tv_nsec = tso.tv_nsec;
+
+		errno = 0;
+		while (nanosleep(&ts, &ts) != 0) {
+			ATF_REQUIRE_MSG(timespeccmp(&ts, &tso, <=),
+			    "errno=%d ts=%0.9f should be <= last tso=%0.9f\n",
+			    errno,
+			    ts.tv_sec + ts.tv_nsec / 1e9,
+			    tso.tv_sec + tso.tv_nsec / 1e9);
+			if (errno == EINTR && got_info == 1) {
+				got_info = 0;
+				errno = 0;
+				tso.tv_sec = ts.tv_sec;
+				tso.tv_nsec = ts.tv_nsec;
+				continue;
+			}
+			_exit(EXIT_FAILURE);
+		}
+
+		if (errno != 0)
+			_exit(EXIT_FAILURE);
+
+		_exit(EXIT_SUCCESS);
+	}
+
+	/* Flood the process with SIGINFO until it exits. */
+	do {
+		for (int i = 0; i < 10; i++)
+			ATF_REQUIRE(kill(pid, SIGINFO) == 0);
+		ATF_REQUIRE(usleep(10000) == 0);
+	} while (waitpid(pid, &sta, WNOHANG) == 0);
+
+	ATF_REQUIRE(WIFEXITED(sta) == 1);
+
+	if (WEXITSTATUS(sta) != EXIT_SUCCESS)
+		atf_tc_fail("nanosleep(2) handled rtmp incorrectly");
+}
+
 ATF_TP_ADD_TCS(tp)
 {
 
 	ATF_TP_ADD_TC(tp, nanosleep_basic);
 	ATF_TP_ADD_TC(tp, nanosleep_err);
 	ATF_TP_ADD_TC(tp, nanosleep_sig);
+	ATF_TP_ADD_TC(tp, nanosleep_eintr);
 
 	return atf_no_error();
 }

Modified: head/sys/kern/kern_time.c
==============================================================================
--- head/sys/kern/kern_time.c	Wed Feb 14 18:21:54 2018	(r329270)
+++ head/sys/kern/kern_time.c	Wed Feb 14 18:43:50 2018	(r329271)
@@ -563,7 +563,8 @@ kern_clock_nanosleep(struct thread *td, clockid_t cloc
 	} while (error == 0 && is_abs_real && td->td_rtcgen == 0);
 	td->td_rtcgen = 0;
 	if (error != EWOULDBLOCK) {
-		TIMESEL(&sbtt, tmp);
+		if (TIMESEL(&sbtt, tmp))
+			sbtt += tc_tick_sbt;
 		if (sbtt >= sbt)
 			return (0);
 		if (error == ERESTART)



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201802141843.w1EIhocY056637>