1 /* $NetBSD: t_nanosleep.c,v 1.1 2024/10/09 13:02:53 kre Exp $ */ 2 3 /*- 4 * Copyright (c) 2024 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __COPYRIGHT("@(#) Copyright (c) 2024\ 31 The NetBSD Foundation, inc. All rights reserved."); 32 __RCSID("$NetBSD: t_nanosleep.c,v 1.1 2024/10/09 13:02:53 kre Exp $"); 33 34 #include <sys/types.h> 35 #include <sys/wait.h> 36 37 #include <atf-c.h> 38 39 #include <errno.h> 40 #include <signal.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <time.h> 44 #include <unistd.h> 45 46 static void 47 sacrifice(void) 48 { 49 pause(); 50 } 51 52 static void 53 tester(pid_t victim, clockid_t clock, int flags) 54 { 55 /* 56 * we need this sleep to be long enough that we 57 * can accurately detect when the sleep finishes 58 * early, but not so long that when there's no 59 * bug and things actually sleep this long, that 60 * the execution of a sleep this long, several 61 * times, won't slow down the overall testing 62 * process too much. Trial and error... 63 */ 64 struct timespec to_sleep = { 4, 0 }; 65 66 struct timespec before, after; 67 struct timespec *ts; 68 int e; 69 70 if (clock_gettime(clock, &before) != 0) 71 exit(1); 72 73 if (flags & TIMER_ABSTIME) { 74 timespecadd(&to_sleep, &before, &after); 75 ts = &after; 76 } else 77 ts = &to_sleep; 78 79 printf("Test: Clock=%d Flags=%x, starting at %jd.%.9ld\n", 80 (int)clock, flags, (intmax_t)before.tv_sec, before.tv_nsec); 81 if (flags & TIMER_ABSTIME) 82 printf("Sleeping until %jd.%.9ld\n", 83 (intmax_t)ts->tv_sec, ts->tv_nsec); 84 else 85 printf("Sleeping for %jd.%.9ld\n", 86 (intmax_t)ts->tv_sec, ts->tv_nsec); 87 88 /* OK, we're ready */ 89 90 /* these next two steps need to be as close together as possible */ 91 if (kill(victim, SIGKILL) == -1) 92 exit(2); 93 if ((e = clock_nanosleep(clock, flags, ts, &after)) != 0) 94 exit(20 + e); 95 96 if (!(flags & TIMER_ABSTIME)) { 97 printf("Remaining to sleep: %jd.%.9ld\n", 98 (intmax_t)after.tv_sec, after.tv_nsec); 99 100 if (after.tv_sec != 0 || after.tv_nsec != 0) 101 exit(3); 102 } 103 104 if (clock_gettime(clock, &after) != 0) 105 exit(4); 106 107 printf("Sleep ended at: %jd.%.9ld\n", 108 (intmax_t)after.tv_sec, after.tv_nsec); 109 110 timespecadd(&before, &to_sleep, &before); 111 if (timespeccmp(&before, &after, >)) 112 exit(5); 113 114 exit(0); 115 } 116 117 /* 118 * The parent of the masochist/victim above, controls everything. 119 */ 120 static void 121 runit(clockid_t clock, int flags) 122 { 123 pid_t v, m, x; 124 int status; 125 struct timespec brief = { 0, 3 * 100 * 1000 * 1000 }; /* 300 ms */ 126 127 ATF_REQUIRE((v = fork()) != -1); 128 if (v == 0) 129 sacrifice(); 130 131 ATF_REQUIRE((m = fork()) != -1); 132 if (m == 0) 133 tester(v, clock, flags); 134 135 ATF_REQUIRE((x = wait(&status)) != -1); 136 137 if (x == m) { 138 /* 139 * This is bad, the murderer shouldn't die first 140 */ 141 fprintf(stderr, "M exited first, status %#x\n", status); 142 (void)kill(v, SIGKILL); /* just in case */ 143 atf_tc_fail("2nd child predeceased first"); 144 } 145 if (x != v) { 146 fprintf(stderr, "Unknown exit from %d (status: %#x)" 147 "(M=%d V=%d)\n", x, status, m, v); 148 (void)kill(m, SIGKILL); 149 (void)kill(v, SIGKILL); 150 atf_tc_fail("Strange child died"); 151 } 152 153 /* 154 * OK, the victim died, we don't really care why, 155 * (it should have been because of a SIGKILL, maybe 156 * test for that someday). 157 * 158 * Now we get to proceed to the real test. 159 * 160 * But we want to wait a short whle to try and be sure 161 * that m (the child still running) has a chance to 162 * fall asleep. 163 */ 164 (void) clock_nanosleep(CLOCK_MONOTONIC, TIMER_RELTIME, &brief, NULL); 165 166 /* 167 * This is the test, for PR kern/58733 168 * - stop a process while in clock_nanosleep() 169 * - resume it again 170 * - see if it still sleeps as long as was requested (or longer) 171 */ 172 ATF_REQUIRE(kill(m, SIGSTOP) == 0); 173 (void) clock_nanosleep(CLOCK_MONOTONIC, TIMER_RELTIME, &brief, NULL); 174 ATF_REQUIRE(kill(m, SIGCONT) == 0); 175 176 ATF_REQUIRE((x = wait(&status)) != -1); 177 178 if (x != m) { 179 fprintf(stderr, "Unknown exit from %d (status: %#x)" 180 "(M=%d V=%d)\n", x, status, m, v); 181 (void) kill(m, SIGKILL); 182 atf_tc_fail("Strange child died"); 183 } 184 185 if (status == 0) 186 atf_tc_pass(); 187 188 /* 189 * Here we should decode the status, and give a better 190 * clue what really went wrong. Later... 191 */ 192 fprintf(stderr, "Test failed: status from M: %#x\n", status); 193 atf_tc_fail("M exited with non-zero status. PR kern/58733"); 194 } 195 196 197 ATF_TC(nanosleep_monotonic_absolute); 198 ATF_TC_HEAD(nanosleep_monotonic_absolute, tc) 199 { 200 atf_tc_set_md_var(tc, "descr", "Checks clock_nanosleep(MONO, ABS)"); 201 } 202 ATF_TC_BODY(nanosleep_monotonic_absolute, tc) 203 { 204 runit(CLOCK_MONOTONIC, TIMER_ABSTIME); 205 } 206 207 ATF_TC(nanosleep_monotonic_relative); 208 ATF_TC_HEAD(nanosleep_monotonic_relative, tc) 209 { 210 atf_tc_set_md_var(tc, "descr", "Checks clock_nanosleep(MONO, REL)"); 211 } 212 ATF_TC_BODY(nanosleep_monotonic_relative, tc) 213 { 214 runit(CLOCK_MONOTONIC, TIMER_RELTIME); 215 } 216 217 ATF_TC(nanosleep_realtime_absolute); 218 ATF_TC_HEAD(nanosleep_realtime_absolute, tc) 219 { 220 atf_tc_set_md_var(tc, "descr", "Checks clock_nanosleep(REAL, ABS)"); 221 } 222 ATF_TC_BODY(nanosleep_realtime_absolute, tc) 223 { 224 runit(CLOCK_REALTIME, TIMER_ABSTIME); 225 } 226 227 ATF_TC(nanosleep_realtime_relative); 228 ATF_TC_HEAD(nanosleep_realtime_relative, tc) 229 { 230 atf_tc_set_md_var(tc, "descr", "Checks clock_nanosleep(REAL, REL)"); 231 } 232 ATF_TC_BODY(nanosleep_realtime_relative, tc) 233 { 234 runit(CLOCK_REALTIME, TIMER_RELTIME); 235 } 236 237 ATF_TP_ADD_TCS(tp) 238 { 239 240 ATF_TP_ADD_TC(tp, nanosleep_monotonic_absolute); 241 ATF_TP_ADD_TC(tp, nanosleep_monotonic_relative); 242 ATF_TP_ADD_TC(tp, nanosleep_realtime_absolute); 243 ATF_TP_ADD_TC(tp, nanosleep_realtime_relative); 244 245 return atf_no_error(); 246 } 247