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