]>
Commit | Line | Data |
---|---|---|
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 | 44 | static 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 |
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); | |
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 | */ | |
118 | TEST_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 | */ | |
140 | TEST_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 | */ | |
166 | TEST_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 | */ | |
189 | TEST_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 | */ | |
214 | TEST_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 | */ | |
235 | TEST_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 | */ | |
257 | TEST_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 | */ | |
283 | TEST_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 | */ | |
301 | TEST_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 | */ | |
317 | TEST_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 | */ | |
333 | TEST_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 | */ | |
349 | TEST_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 | */ | |
365 | TEST_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 | */ | |
383 | TEST_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 | */ | |
400 | TEST_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 | */ | |
422 | TEST_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 | ||
439 | int 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 | } |