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