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