]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-barrier.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / test / test-barrier.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
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
30 #include <stdio.h>
31 #include <sys/time.h>
32 #include <sys/wait.h>
33 #include <unistd.h>
34
35 #include "barrier.h"
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. */
42 #define BASE_TIME (20 * USEC_PER_MSEC)
43
44 static void set_alarm(usec_t usecs) {
45 struct itimerval v = { };
46
47 timeval_store(&v.it_value, usecs);
48 assert_se(setitimer(ITIMER_REAL, &v, NULL) >= 0);
49 }
50
51 static void sleep_for(usec_t usecs) {
52 /* stupid usleep() might fail if >1000000 */
53 assert_se(usecs < USEC_PER_SEC);
54 usleep(usecs);
55 }
56
57 #define TEST_BARRIER(_FUNCTION, _CHILD_CODE, _WAIT_CHILD, _PARENT_CODE, _WAIT_PARENT) \
58 static void _FUNCTION(void) { \
59 Barrier b = BARRIER_NULL; \
60 pid_t pid1, pid2; \
61 \
62 assert_se(barrier_create(&b) >= 0); \
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); \
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); \
85 set_alarm(999999); \
86 { _WAIT_CHILD; } \
87 { _WAIT_PARENT; } \
88 set_alarm(0); \
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.
112 * The timeout makes sure the sync works as expected. The sleep_for() on one side
113 * makes sure the exit of the parent does not overwrite previous barriers. Due
114 * to the sleep_for(), we know that the parent already exited, thus there's a
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 */
118 TEST_BARRIER(test_barrier_sync,
119 ({
120 set_alarm(BASE_TIME * 10);
121 assert_se(barrier_place(&b));
122 sleep_for(BASE_TIME * 2);
123 assert_se(barrier_sync(&b));
124 }),
125 TEST_BARRIER_WAIT_SUCCESS(pid1),
126 ({
127 set_alarm(BASE_TIME * 10);
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 */
140 TEST_BARRIER(test_barrier_wait_next,
141 ({
142 sleep_for(BASE_TIME);
143 set_alarm(BASE_TIME * 10);
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 ({
150 set_alarm(BASE_TIME * 4);
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 */
166 TEST_BARRIER(test_barrier_wait_next_twice,
167 ({
168 sleep_for(BASE_TIME);
169 set_alarm(BASE_TIME);
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 ({
176 set_alarm(BASE_TIME * 10);
177 assert_se(barrier_place(&b));
178 assert_se(barrier_place(&b));
179 sleep_for(BASE_TIME * 4);
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 */
189 TEST_BARRIER(test_barrier_wait_next_twice_local,
190 ({
191 sleep_for(BASE_TIME);
192 set_alarm(BASE_TIME);
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 ({
201 set_alarm(BASE_TIME * 10);
202 assert_se(barrier_place(&b));
203 assert_se(barrier_place(&b));
204 sleep_for(BASE_TIME * 4);
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 */
214 TEST_BARRIER(test_barrier_wait_next_twice_sync,
215 ({
216 sleep_for(BASE_TIME);
217 set_alarm(BASE_TIME);
218 assert_se(barrier_wait_next(&b));
219 assert_se(barrier_sync_next(&b));
220 }),
221 TEST_BARRIER_WAIT_SUCCESS(pid1),
222 ({
223 set_alarm(BASE_TIME * 10);
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 */
235 TEST_BARRIER(test_barrier_wait_next_twice_local_sync,
236 ({
237 sleep_for(BASE_TIME);
238 set_alarm(BASE_TIME);
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 ({
246 set_alarm(BASE_TIME * 10);
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 */
257 TEST_BARRIER(test_barrier_sync_next,
258 ({
259 set_alarm(BASE_TIME * 10);
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 ({
270 set_alarm(BASE_TIME * 10);
271 sleep_for(BASE_TIME);
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 */
283 TEST_BARRIER(test_barrier_sync_next_local,
284 ({
285 set_alarm(BASE_TIME);
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 ({
292 sleep_for(BASE_TIME * 2);
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 */
301 TEST_BARRIER(test_barrier_sync_next_local_abort,
302 ({
303 set_alarm(BASE_TIME * 10);
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 */
317 TEST_BARRIER(test_barrier_wait_abortion,
318 ({
319 set_alarm(BASE_TIME * 10);
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 */
333 TEST_BARRIER(test_barrier_wait_abortion_unmatched,
334 ({
335 set_alarm(BASE_TIME);
336 assert_se(barrier_wait_abortion(&b));
337 assert_se(0);
338 }),
339 TEST_BARRIER_WAIT_ALARM(pid1),
340 ({
341 sleep_for(BASE_TIME * 2);
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 */
349 TEST_BARRIER(test_barrier_wait_abortion_local,
350 ({
351 set_alarm(BASE_TIME * 10);
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 */
365 TEST_BARRIER(test_barrier_wait_abortion_local_unmatched,
366 ({
367 set_alarm(BASE_TIME);
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 ({
374 sleep_for(BASE_TIME * 2);
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 */
383 TEST_BARRIER(test_barrier_exit,
384 ({
385 }),
386 TEST_BARRIER_WAIT_SUCCESS(pid1),
387 ({
388 set_alarm(BASE_TIME * 10);
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 */
400 TEST_BARRIER(test_barrier_no_exit,
401 ({
402 sleep_for(BASE_TIME * 2);
403 }),
404 TEST_BARRIER_WAIT_SUCCESS(pid1),
405 ({
406 set_alarm(BASE_TIME);
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 */
422 TEST_BARRIER(test_barrier_pending_exit,
423 ({
424 set_alarm(BASE_TIME * 4);
425 sleep_for(BASE_TIME * 2);
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
439 int main(int argc, char *argv[]) {
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
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 }