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
This commit is contained in:
parent
f52add1296
commit
70c144dc78
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=329271
@ -50,6 +50,15 @@ handler(int signo __unused)
|
|||||||
/* Nothing. */
|
/* Nothing. */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int got_info;
|
||||||
|
static void
|
||||||
|
info_handler(int signo __unused)
|
||||||
|
{
|
||||||
|
|
||||||
|
got_info = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ATF_TC(nanosleep_basic);
|
ATF_TC(nanosleep_basic);
|
||||||
ATF_TC_HEAD(nanosleep_basic, tc)
|
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_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_TCS(tp)
|
||||||
{
|
{
|
||||||
|
|
||||||
ATF_TP_ADD_TC(tp, nanosleep_basic);
|
ATF_TP_ADD_TC(tp, nanosleep_basic);
|
||||||
ATF_TP_ADD_TC(tp, nanosleep_err);
|
ATF_TP_ADD_TC(tp, nanosleep_err);
|
||||||
ATF_TP_ADD_TC(tp, nanosleep_sig);
|
ATF_TP_ADD_TC(tp, nanosleep_sig);
|
||||||
|
ATF_TP_ADD_TC(tp, nanosleep_eintr);
|
||||||
|
|
||||||
return atf_no_error();
|
return atf_no_error();
|
||||||
}
|
}
|
||||||
|
@ -563,7 +563,8 @@ kern_clock_nanosleep(struct thread *td, clockid_t clock_id, int flags,
|
|||||||
} while (error == 0 && is_abs_real && td->td_rtcgen == 0);
|
} while (error == 0 && is_abs_real && td->td_rtcgen == 0);
|
||||||
td->td_rtcgen = 0;
|
td->td_rtcgen = 0;
|
||||||
if (error != EWOULDBLOCK) {
|
if (error != EWOULDBLOCK) {
|
||||||
TIMESEL(&sbtt, tmp);
|
if (TIMESEL(&sbtt, tmp))
|
||||||
|
sbtt += tc_tick_sbt;
|
||||||
if (sbtt >= sbt)
|
if (sbtt >= sbt)
|
||||||
return (0);
|
return (0);
|
||||||
if (error == ERESTART)
|
if (error == ERESTART)
|
||||||
|
Loading…
Reference in New Issue
Block a user