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>