]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/test/test-barrier.c
hwdb: add support for Alienware graphics amplifier
[thirdparty/systemd.git] / src / test / test-barrier.c
CommitLineData
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 45static 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
52static 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 */
119TEST_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 */
141TEST_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 */
167TEST_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 */
190TEST_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 */
215TEST_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 */
236TEST_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 */
258TEST_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 */
284TEST_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 */
302TEST_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 */
318TEST_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 */
334TEST_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 */
350TEST_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 */
366TEST_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 */
384TEST_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 */
401TEST_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 */
423TEST_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
440int 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}