]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/test/test-barrier.c
tests: add helper to unify skipping a test and exiting
[thirdparty/systemd.git] / src / test / test-barrier.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
279da1e3
DH
2
3/*
4 * IPC barrier tests
5 * These tests verify the correct behavior of the IPC Barrier implementation.
6 * Note that the tests use alarm-timers to verify dead-locks and timeouts. These
7 * might not work on slow machines where 20ms are too short to perform specific
8 * operations (though, very unlikely). In case that turns out true, we have to
9 * increase it at the slightly cost of lengthen test-duration on other machines.
10 */
11
279da1e3 12#include <stdio.h>
279da1e3
DH
13#include <sys/time.h>
14#include <sys/wait.h>
15#include <unistd.h>
16
17#include "barrier.h"
279da1e3 18#include "util.h"
f57d003c 19#include "tests.h"
279da1e3
DH
20
21/* 20ms to test deadlocks; All timings use multiples of this constant as
22 * alarm/sleep timers. If this timeout is too small for slow machines to perform
23 * the requested operations, we have to increase it. On an i7 this works fine
24 * with 1ms base-time, so 20ms should be just fine for everyone. */
cf347234 25#define BASE_TIME (20 * USEC_PER_MSEC)
279da1e3 26
cf347234 27static void set_alarm(usec_t usecs) {
279da1e3
DH
28 struct itimerval v = { };
29
cf347234 30 timeval_store(&v.it_value, usecs);
279da1e3
DH
31 assert_se(setitimer(ITIMER_REAL, &v, NULL) >= 0);
32}
33
cf347234
DH
34static void sleep_for(usec_t usecs) {
35 /* stupid usleep() might fail if >1000000 */
36 assert_se(usecs < USEC_PER_SEC);
37 usleep(usecs);
279da1e3
DH
38}
39
40#define TEST_BARRIER(_FUNCTION, _CHILD_CODE, _WAIT_CHILD, _PARENT_CODE, _WAIT_PARENT) \
41 static void _FUNCTION(void) { \
7566e267 42 Barrier b = BARRIER_NULL; \
279da1e3
DH
43 pid_t pid1, pid2; \
44 \
7566e267 45 assert_se(barrier_create(&b) >= 0); \
2ad8887a
TA
46 assert_se(b.me > 0); \
47 assert_se(b.them > 0); \
48 assert_se(b.pipe[0] > 0); \
49 assert_se(b.pipe[1] > 0); \
279da1e3
DH
50 \
51 pid1 = fork(); \
52 assert_se(pid1 >= 0); \
53 if (pid1 == 0) { \
54 barrier_set_role(&b, BARRIER_CHILD); \
55 { _CHILD_CODE; } \
56 exit(42); \
57 } \
58 \
59 pid2 = fork(); \
60 assert_se(pid2 >= 0); \
61 if (pid2 == 0) { \
62 barrier_set_role(&b, BARRIER_PARENT); \
63 { _PARENT_CODE; } \
64 exit(42); \
65 } \
66 \
67 barrier_destroy(&b); \
cf347234 68 set_alarm(999999); \
279da1e3
DH
69 { _WAIT_CHILD; } \
70 { _WAIT_PARENT; } \
cf347234 71 set_alarm(0); \
279da1e3
DH
72 }
73
74#define TEST_BARRIER_WAIT_SUCCESS(_pid) \
75 ({ \
76 int pidr, status; \
77 pidr = waitpid(_pid, &status, 0); \
78 assert_se(pidr == _pid); \
79 assert_se(WIFEXITED(status)); \
80 assert_se(WEXITSTATUS(status) == 42); \
81 })
82
83#define TEST_BARRIER_WAIT_ALARM(_pid) \
84 ({ \
85 int pidr, status; \
86 pidr = waitpid(_pid, &status, 0); \
87 assert_se(pidr == _pid); \
88 assert_se(WIFSIGNALED(status)); \
89 assert_se(WTERMSIG(status) == SIGALRM); \
90 })
91
92/*
93 * Test basic sync points
94 * This places a barrier in both processes and waits synchronously for them.
cf347234 95 * The timeout makes sure the sync works as expected. The sleep_for() on one side
279da1e3 96 * makes sure the exit of the parent does not overwrite previous barriers. Due
cf347234 97 * to the sleep_for(), we know that the parent already exited, thus there's a
279da1e3
DH
98 * pending HUP on the pipe. However, the barrier_sync() prefers reads on the
99 * eventfd, thus we can safely wait on the barrier.
100 */
101TEST_BARRIER(test_barrier_sync,
102 ({
cf347234 103 set_alarm(BASE_TIME * 10);
279da1e3 104 assert_se(barrier_place(&b));
cf347234 105 sleep_for(BASE_TIME * 2);
279da1e3
DH
106 assert_se(barrier_sync(&b));
107 }),
108 TEST_BARRIER_WAIT_SUCCESS(pid1),
109 ({
cf347234 110 set_alarm(BASE_TIME * 10);
279da1e3
DH
111 assert_se(barrier_place(&b));
112 assert_se(barrier_sync(&b));
113 }),
114 TEST_BARRIER_WAIT_SUCCESS(pid2));
115
116/*
117 * Test wait_next()
118 * This places a barrier in the parent and syncs on it. The child sleeps while
119 * the parent places the barrier and then waits for a barrier. The wait will
120 * succeed as the child hasn't read the parent's barrier, yet. The following
121 * barrier and sync synchronize the exit.
122 */
123TEST_BARRIER(test_barrier_wait_next,
124 ({
cf347234
DH
125 sleep_for(BASE_TIME);
126 set_alarm(BASE_TIME * 10);
279da1e3
DH
127 assert_se(barrier_wait_next(&b));
128 assert_se(barrier_place(&b));
129 assert_se(barrier_sync(&b));
130 }),
131 TEST_BARRIER_WAIT_SUCCESS(pid1),
132 ({
cf347234 133 set_alarm(BASE_TIME * 4);
279da1e3
DH
134 assert_se(barrier_place(&b));
135 assert_se(barrier_sync(&b));
136 }),
137 TEST_BARRIER_WAIT_SUCCESS(pid2));
138
139/*
140 * Test wait_next() multiple times
141 * This places two barriers in the parent and waits for the child to exit. The
142 * child sleeps 20ms so both barriers _should_ be in place. It then waits for
143 * the parent to place the next barrier twice. The first call will fetch both
144 * barriers and return. However, the second call will stall as the parent does
145 * not place a 3rd barrier (the sleep caught two barriers). wait_next() is does
146 * not look at barrier-links so this stall is expected. Thus this test times
147 * out.
148 */
149TEST_BARRIER(test_barrier_wait_next_twice,
150 ({
cf347234
DH
151 sleep_for(BASE_TIME);
152 set_alarm(BASE_TIME);
279da1e3
DH
153 assert_se(barrier_wait_next(&b));
154 assert_se(barrier_wait_next(&b));
155 assert_se(0);
156 }),
157 TEST_BARRIER_WAIT_ALARM(pid1),
158 ({
cf347234 159 set_alarm(BASE_TIME * 10);
279da1e3
DH
160 assert_se(barrier_place(&b));
161 assert_se(barrier_place(&b));
359017c1 162 sleep_for(BASE_TIME * 4);
279da1e3
DH
163 }),
164 TEST_BARRIER_WAIT_SUCCESS(pid2));
165
166/*
167 * Test wait_next() with local barriers
168 * This is the same as test_barrier_wait_next_twice, but places local barriers
169 * between both waits. This does not have any effect on the wait so it times out
170 * like the other test.
171 */
172TEST_BARRIER(test_barrier_wait_next_twice_local,
173 ({
cf347234
DH
174 sleep_for(BASE_TIME);
175 set_alarm(BASE_TIME);
279da1e3
DH
176 assert_se(barrier_wait_next(&b));
177 assert_se(barrier_place(&b));
178 assert_se(barrier_place(&b));
179 assert_se(barrier_wait_next(&b));
180 assert_se(0);
181 }),
182 TEST_BARRIER_WAIT_ALARM(pid1),
183 ({
cf347234 184 set_alarm(BASE_TIME * 10);
279da1e3
DH
185 assert_se(barrier_place(&b));
186 assert_se(barrier_place(&b));
359017c1 187 sleep_for(BASE_TIME * 4);
279da1e3
DH
188 }),
189 TEST_BARRIER_WAIT_SUCCESS(pid2));
190
191/*
192 * Test wait_next() with sync_next()
193 * This is again the same as test_barrier_wait_next_twice but uses a
194 * synced wait as the second wait. This works just fine because the local state
195 * has no barriers placed, therefore, the remote is always in sync.
196 */
197TEST_BARRIER(test_barrier_wait_next_twice_sync,
198 ({
cf347234
DH
199 sleep_for(BASE_TIME);
200 set_alarm(BASE_TIME);
279da1e3
DH
201 assert_se(barrier_wait_next(&b));
202 assert_se(barrier_sync_next(&b));
203 }),
204 TEST_BARRIER_WAIT_SUCCESS(pid1),
205 ({
cf347234 206 set_alarm(BASE_TIME * 10);
279da1e3
DH
207 assert_se(barrier_place(&b));
208 assert_se(barrier_place(&b));
209 }),
210 TEST_BARRIER_WAIT_SUCCESS(pid2));
211
212/*
213 * Test wait_next() with sync_next() and local barriers
214 * This is again the same as test_barrier_wait_next_twice_local but uses a
215 * synced wait as the second wait. This works just fine because the local state
216 * is in sync with the remote.
217 */
218TEST_BARRIER(test_barrier_wait_next_twice_local_sync,
219 ({
cf347234
DH
220 sleep_for(BASE_TIME);
221 set_alarm(BASE_TIME);
279da1e3
DH
222 assert_se(barrier_wait_next(&b));
223 assert_se(barrier_place(&b));
224 assert_se(barrier_place(&b));
225 assert_se(barrier_sync_next(&b));
226 }),
227 TEST_BARRIER_WAIT_SUCCESS(pid1),
228 ({
cf347234 229 set_alarm(BASE_TIME * 10);
279da1e3
DH
230 assert_se(barrier_place(&b));
231 assert_se(barrier_place(&b));
232 }),
233 TEST_BARRIER_WAIT_SUCCESS(pid2));
234
235/*
236 * Test sync_next() and sync()
237 * This tests sync_*() synchronizations and makes sure they work fine if the
238 * local state is behind the remote state.
239 */
240TEST_BARRIER(test_barrier_sync_next,
241 ({
cf347234 242 set_alarm(BASE_TIME * 10);
279da1e3
DH
243 assert_se(barrier_sync_next(&b));
244 assert_se(barrier_sync(&b));
245 assert_se(barrier_place(&b));
246 assert_se(barrier_place(&b));
247 assert_se(barrier_sync_next(&b));
248 assert_se(barrier_sync_next(&b));
249 assert_se(barrier_sync(&b));
250 }),
251 TEST_BARRIER_WAIT_SUCCESS(pid1),
252 ({
cf347234
DH
253 set_alarm(BASE_TIME * 10);
254 sleep_for(BASE_TIME);
279da1e3
DH
255 assert_se(barrier_place(&b));
256 assert_se(barrier_place(&b));
257 assert_se(barrier_sync(&b));
258 }),
259 TEST_BARRIER_WAIT_SUCCESS(pid2));
260
261/*
262 * Test sync_next() and sync() with local barriers
263 * This tests timeouts if sync_*() is used if local barriers are placed but the
264 * remote didn't place any.
265 */
266TEST_BARRIER(test_barrier_sync_next_local,
267 ({
cf347234 268 set_alarm(BASE_TIME);
279da1e3
DH
269 assert_se(barrier_place(&b));
270 assert_se(barrier_sync_next(&b));
271 assert_se(0);
272 }),
273 TEST_BARRIER_WAIT_ALARM(pid1),
274 ({
cf347234 275 sleep_for(BASE_TIME * 2);
279da1e3
DH
276 }),
277 TEST_BARRIER_WAIT_SUCCESS(pid2));
278
279/*
280 * Test sync_next() and sync() with local barriers and abortion
281 * This is the same as test_barrier_sync_next_local but aborts the sync in the
282 * parent. Therefore, the sync_next() succeeds just fine due to the abortion.
283 */
284TEST_BARRIER(test_barrier_sync_next_local_abort,
285 ({
cf347234 286 set_alarm(BASE_TIME * 10);
279da1e3
DH
287 assert_se(barrier_place(&b));
288 assert_se(!barrier_sync_next(&b));
289 }),
290 TEST_BARRIER_WAIT_SUCCESS(pid1),
291 ({
292 assert_se(barrier_abort(&b));
293 }),
294 TEST_BARRIER_WAIT_SUCCESS(pid2));
295
296/*
297 * Test matched wait_abortion()
298 * This runs wait_abortion() with remote abortion.
299 */
300TEST_BARRIER(test_barrier_wait_abortion,
301 ({
cf347234 302 set_alarm(BASE_TIME * 10);
279da1e3
DH
303 assert_se(barrier_wait_abortion(&b));
304 }),
305 TEST_BARRIER_WAIT_SUCCESS(pid1),
306 ({
307 assert_se(barrier_abort(&b));
308 }),
309 TEST_BARRIER_WAIT_SUCCESS(pid2));
310
311/*
312 * Test unmatched wait_abortion()
313 * This runs wait_abortion() without any remote abortion going on. It thus must
314 * timeout.
315 */
316TEST_BARRIER(test_barrier_wait_abortion_unmatched,
317 ({
cf347234 318 set_alarm(BASE_TIME);
279da1e3
DH
319 assert_se(barrier_wait_abortion(&b));
320 assert_se(0);
321 }),
322 TEST_BARRIER_WAIT_ALARM(pid1),
323 ({
cf347234 324 sleep_for(BASE_TIME * 2);
279da1e3
DH
325 }),
326 TEST_BARRIER_WAIT_SUCCESS(pid2));
327
328/*
329 * Test matched wait_abortion() with local abortion
330 * This runs wait_abortion() with local and remote abortion.
331 */
332TEST_BARRIER(test_barrier_wait_abortion_local,
333 ({
cf347234 334 set_alarm(BASE_TIME * 10);
279da1e3
DH
335 assert_se(barrier_abort(&b));
336 assert_se(!barrier_wait_abortion(&b));
337 }),
338 TEST_BARRIER_WAIT_SUCCESS(pid1),
339 ({
340 assert_se(barrier_abort(&b));
341 }),
342 TEST_BARRIER_WAIT_SUCCESS(pid2));
343
344/*
345 * Test unmatched wait_abortion() with local abortion
346 * This runs wait_abortion() with only local abortion. This must time out.
347 */
348TEST_BARRIER(test_barrier_wait_abortion_local_unmatched,
349 ({
cf347234 350 set_alarm(BASE_TIME);
279da1e3
DH
351 assert_se(barrier_abort(&b));
352 assert_se(!barrier_wait_abortion(&b));
353 assert_se(0);
354 }),
355 TEST_BARRIER_WAIT_ALARM(pid1),
356 ({
cf347234 357 sleep_for(BASE_TIME * 2);
279da1e3
DH
358 }),
359 TEST_BARRIER_WAIT_SUCCESS(pid2));
360
361/*
362 * Test child exit
363 * Place barrier and sync with the child. The child only exits()s, which should
364 * cause an implicit abortion and wake the parent.
365 */
366TEST_BARRIER(test_barrier_exit,
367 ({
368 }),
369 TEST_BARRIER_WAIT_SUCCESS(pid1),
370 ({
cf347234 371 set_alarm(BASE_TIME * 10);
279da1e3
DH
372 assert_se(barrier_place(&b));
373 assert_se(!barrier_sync(&b));
374 }),
375 TEST_BARRIER_WAIT_SUCCESS(pid2));
376
377/*
378 * Test child exit with sleep
379 * Same as test_barrier_exit but verifies the test really works due to the
380 * child-exit. We add a usleep() which triggers the alarm in the parent and
381 * causes the test to time out.
382 */
383TEST_BARRIER(test_barrier_no_exit,
384 ({
cf347234 385 sleep_for(BASE_TIME * 2);
279da1e3
DH
386 }),
387 TEST_BARRIER_WAIT_SUCCESS(pid1),
388 ({
cf347234 389 set_alarm(BASE_TIME);
279da1e3
DH
390 assert_se(barrier_place(&b));
391 assert_se(!barrier_sync(&b));
392 }),
393 TEST_BARRIER_WAIT_ALARM(pid2));
394
395/*
396 * Test pending exit against sync
397 * The parent places a barrier *and* exits. The 20ms wait in the child
398 * guarantees both are pending. However, our logic prefers pending barriers over
399 * pending exit-abortions (unlike normal abortions), thus the wait_next() must
400 * succeed, same for the sync_next() as our local barrier-count is smaller than
401 * the remote. Once we place a barrier our count is equal, so the sync still
402 * succeeds. Only if we place one more barrier, we're ahead of the remote, thus
403 * we will fail due to HUP on the pipe.
404 */
405TEST_BARRIER(test_barrier_pending_exit,
406 ({
cf347234
DH
407 set_alarm(BASE_TIME * 4);
408 sleep_for(BASE_TIME * 2);
279da1e3
DH
409 assert_se(barrier_wait_next(&b));
410 assert_se(barrier_sync_next(&b));
411 assert_se(barrier_place(&b));
412 assert_se(barrier_sync_next(&b));
413 assert_se(barrier_place(&b));
414 assert_se(!barrier_sync_next(&b));
415 }),
416 TEST_BARRIER_WAIT_SUCCESS(pid1),
417 ({
418 assert_se(barrier_place(&b));
419 }),
420 TEST_BARRIER_WAIT_SUCCESS(pid2));
421
422int main(int argc, char *argv[]) {
f57d003c 423 log_set_max_level(LOG_INFO);
279da1e3
DH
424 log_parse_environment();
425 log_open();
426
317bb217
ZJS
427 if (!slow_tests_enabled())
428 return log_tests_skipped("slow tests are disabled");
f57d003c 429
279da1e3
DH
430 test_barrier_sync();
431 test_barrier_wait_next();
432 test_barrier_wait_next_twice();
433 test_barrier_wait_next_twice_sync();
434 test_barrier_wait_next_twice_local();
435 test_barrier_wait_next_twice_local_sync();
436 test_barrier_sync_next();
437 test_barrier_sync_next_local();
438 test_barrier_sync_next_local_abort();
439 test_barrier_wait_abortion();
440 test_barrier_wait_abortion_unmatched();
441 test_barrier_wait_abortion_local();
442 test_barrier_wait_abortion_local_unmatched();
443 test_barrier_exit();
444 test_barrier_no_exit();
445 test_barrier_pending_exit();
446
447 return 0;
448}