1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2014 David Herrmann <dh.herrmann@gmail.com>
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.
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.
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/>.
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.
42 /* 20ms to test deadlocks; All timings use multiples of this constant as
43 * alarm/sleep timers. If this timeout is too small for slow machines to perform
44 * the requested operations, we have to increase it. On an i7 this works fine
45 * with 1ms base-time, so 20ms should be just fine for everyone. */
48 static void malarm(unsigned long msecs) {
49 struct itimerval v = { };
51 timeval_store(&v.it_value, msecs * USEC_PER_MSEC);
52 assert_se(setitimer(ITIMER_REAL, &v, NULL) >= 0);
55 static void msleep(unsigned long msecs) {
56 assert_se(msecs < MSEC_PER_SEC);
57 usleep(msecs * USEC_PER_MSEC);
60 #define TEST_BARRIER(_FUNCTION, _CHILD_CODE, _WAIT_CHILD, _PARENT_CODE, _WAIT_PARENT) \
61 static void _FUNCTION(void) { \
65 assert_se(barrier_init(&b) >= 0); \
68 assert_se(pid1 >= 0); \
70 barrier_set_role(&b, BARRIER_CHILD); \
76 assert_se(pid2 >= 0); \
78 barrier_set_role(&b, BARRIER_PARENT); \
83 barrier_destroy(&b); \
90 #define TEST_BARRIER_WAIT_SUCCESS(_pid) \
93 pidr = waitpid(_pid, &status, 0); \
94 assert_se(pidr == _pid); \
95 assert_se(WIFEXITED(status)); \
96 assert_se(WEXITSTATUS(status) == 42); \
99 #define TEST_BARRIER_WAIT_ALARM(_pid) \
102 pidr = waitpid(_pid, &status, 0); \
103 assert_se(pidr == _pid); \
104 assert_se(WIFSIGNALED(status)); \
105 assert_se(WTERMSIG(status) == SIGALRM); \
109 * Test basic sync points
110 * This places a barrier in both processes and waits synchronously for them.
111 * The timeout makes sure the sync works as expected. The msleep() on one side
112 * makes sure the exit of the parent does not overwrite previous barriers. Due
113 * to the msleep(), we know that the parent already exited, thus there's a
114 * pending HUP on the pipe. However, the barrier_sync() prefers reads on the
115 * eventfd, thus we can safely wait on the barrier.
117 TEST_BARRIER(test_barrier_sync,
119 malarm(BASE_TIME * 10);
120 assert_se(barrier_place(&b));
121 msleep(BASE_TIME * 2);
122 assert_se(barrier_sync(&b));
124 TEST_BARRIER_WAIT_SUCCESS(pid1),
126 malarm(BASE_TIME * 10);
127 assert_se(barrier_place(&b));
128 assert_se(barrier_sync(&b));
130 TEST_BARRIER_WAIT_SUCCESS(pid2));
134 * This places a barrier in the parent and syncs on it. The child sleeps while
135 * the parent places the barrier and then waits for a barrier. The wait will
136 * succeed as the child hasn't read the parent's barrier, yet. The following
137 * barrier and sync synchronize the exit.
139 TEST_BARRIER(test_barrier_wait_next,
142 malarm(BASE_TIME * 10);
143 assert_se(barrier_wait_next(&b));
144 assert_se(barrier_place(&b));
145 assert_se(barrier_sync(&b));
147 TEST_BARRIER_WAIT_SUCCESS(pid1),
150 assert_se(barrier_place(&b));
151 assert_se(barrier_sync(&b));
153 TEST_BARRIER_WAIT_SUCCESS(pid2));
156 * Test wait_next() multiple times
157 * This places two barriers in the parent and waits for the child to exit. The
158 * child sleeps 20ms so both barriers _should_ be in place. It then waits for
159 * the parent to place the next barrier twice. The first call will fetch both
160 * barriers and return. However, the second call will stall as the parent does
161 * not place a 3rd barrier (the sleep caught two barriers). wait_next() is does
162 * not look at barrier-links so this stall is expected. Thus this test times
165 TEST_BARRIER(test_barrier_wait_next_twice,
169 assert_se(barrier_wait_next(&b));
170 assert_se(barrier_wait_next(&b));
173 TEST_BARRIER_WAIT_ALARM(pid1),
175 malarm(BASE_TIME * 10);
176 assert_se(barrier_place(&b));
177 assert_se(barrier_place(&b));
178 msleep(BASE_TIME * 2);
180 TEST_BARRIER_WAIT_SUCCESS(pid2));
183 * Test wait_next() with local barriers
184 * This is the same as test_barrier_wait_next_twice, but places local barriers
185 * between both waits. This does not have any effect on the wait so it times out
186 * like the other test.
188 TEST_BARRIER(test_barrier_wait_next_twice_local,
192 assert_se(barrier_wait_next(&b));
193 assert_se(barrier_place(&b));
194 assert_se(barrier_place(&b));
195 assert_se(barrier_wait_next(&b));
198 TEST_BARRIER_WAIT_ALARM(pid1),
200 malarm(BASE_TIME * 10);
201 assert_se(barrier_place(&b));
202 assert_se(barrier_place(&b));
203 msleep(BASE_TIME * 2);
205 TEST_BARRIER_WAIT_SUCCESS(pid2));
208 * Test wait_next() with sync_next()
209 * This is again the same as test_barrier_wait_next_twice but uses a
210 * synced wait as the second wait. This works just fine because the local state
211 * has no barriers placed, therefore, the remote is always in sync.
213 TEST_BARRIER(test_barrier_wait_next_twice_sync,
217 assert_se(barrier_wait_next(&b));
218 assert_se(barrier_sync_next(&b));
220 TEST_BARRIER_WAIT_SUCCESS(pid1),
222 malarm(BASE_TIME * 10);
223 assert_se(barrier_place(&b));
224 assert_se(barrier_place(&b));
226 TEST_BARRIER_WAIT_SUCCESS(pid2));
229 * Test wait_next() with sync_next() and local barriers
230 * This is again the same as test_barrier_wait_next_twice_local but uses a
231 * synced wait as the second wait. This works just fine because the local state
232 * is in sync with the remote.
234 TEST_BARRIER(test_barrier_wait_next_twice_local_sync,
238 assert_se(barrier_wait_next(&b));
239 assert_se(barrier_place(&b));
240 assert_se(barrier_place(&b));
241 assert_se(barrier_sync_next(&b));
243 TEST_BARRIER_WAIT_SUCCESS(pid1),
245 malarm(BASE_TIME * 10);
246 assert_se(barrier_place(&b));
247 assert_se(barrier_place(&b));
249 TEST_BARRIER_WAIT_SUCCESS(pid2));
252 * Test sync_next() and sync()
253 * This tests sync_*() synchronizations and makes sure they work fine if the
254 * local state is behind the remote state.
256 TEST_BARRIER(test_barrier_sync_next,
258 malarm(BASE_TIME * 10);
259 assert_se(barrier_sync_next(&b));
260 assert_se(barrier_sync(&b));
261 assert_se(barrier_place(&b));
262 assert_se(barrier_place(&b));
263 assert_se(barrier_sync_next(&b));
264 assert_se(barrier_sync_next(&b));
265 assert_se(barrier_sync(&b));
267 TEST_BARRIER_WAIT_SUCCESS(pid1),
269 malarm(BASE_TIME * 10);
271 assert_se(barrier_place(&b));
272 assert_se(barrier_place(&b));
273 assert_se(barrier_sync(&b));
275 TEST_BARRIER_WAIT_SUCCESS(pid2));
278 * Test sync_next() and sync() with local barriers
279 * This tests timeouts if sync_*() is used if local barriers are placed but the
280 * remote didn't place any.
282 TEST_BARRIER(test_barrier_sync_next_local,
285 assert_se(barrier_place(&b));
286 assert_se(barrier_sync_next(&b));
289 TEST_BARRIER_WAIT_ALARM(pid1),
291 msleep(BASE_TIME * 2);
293 TEST_BARRIER_WAIT_SUCCESS(pid2));
296 * Test sync_next() and sync() with local barriers and abortion
297 * This is the same as test_barrier_sync_next_local but aborts the sync in the
298 * parent. Therefore, the sync_next() succeeds just fine due to the abortion.
300 TEST_BARRIER(test_barrier_sync_next_local_abort,
302 malarm(BASE_TIME * 10);
303 assert_se(barrier_place(&b));
304 assert_se(!barrier_sync_next(&b));
306 TEST_BARRIER_WAIT_SUCCESS(pid1),
308 assert_se(barrier_abort(&b));
310 TEST_BARRIER_WAIT_SUCCESS(pid2));
313 * Test matched wait_abortion()
314 * This runs wait_abortion() with remote abortion.
316 TEST_BARRIER(test_barrier_wait_abortion,
318 malarm(BASE_TIME * 10);
319 assert_se(barrier_wait_abortion(&b));
321 TEST_BARRIER_WAIT_SUCCESS(pid1),
323 assert_se(barrier_abort(&b));
325 TEST_BARRIER_WAIT_SUCCESS(pid2));
328 * Test unmatched wait_abortion()
329 * This runs wait_abortion() without any remote abortion going on. It thus must
332 TEST_BARRIER(test_barrier_wait_abortion_unmatched,
335 assert_se(barrier_wait_abortion(&b));
338 TEST_BARRIER_WAIT_ALARM(pid1),
340 msleep(BASE_TIME * 2);
342 TEST_BARRIER_WAIT_SUCCESS(pid2));
345 * Test matched wait_abortion() with local abortion
346 * This runs wait_abortion() with local and remote abortion.
348 TEST_BARRIER(test_barrier_wait_abortion_local,
350 malarm(BASE_TIME * 10);
351 assert_se(barrier_abort(&b));
352 assert_se(!barrier_wait_abortion(&b));
354 TEST_BARRIER_WAIT_SUCCESS(pid1),
356 assert_se(barrier_abort(&b));
358 TEST_BARRIER_WAIT_SUCCESS(pid2));
361 * Test unmatched wait_abortion() with local abortion
362 * This runs wait_abortion() with only local abortion. This must time out.
364 TEST_BARRIER(test_barrier_wait_abortion_local_unmatched,
367 assert_se(barrier_abort(&b));
368 assert_se(!barrier_wait_abortion(&b));
371 TEST_BARRIER_WAIT_ALARM(pid1),
373 msleep(BASE_TIME * 2);
375 TEST_BARRIER_WAIT_SUCCESS(pid2));
379 * Place barrier and sync with the child. The child only exits()s, which should
380 * cause an implicit abortion and wake the parent.
382 TEST_BARRIER(test_barrier_exit,
385 TEST_BARRIER_WAIT_SUCCESS(pid1),
387 malarm(BASE_TIME * 10);
388 assert_se(barrier_place(&b));
389 assert_se(!barrier_sync(&b));
391 TEST_BARRIER_WAIT_SUCCESS(pid2));
394 * Test child exit with sleep
395 * Same as test_barrier_exit but verifies the test really works due to the
396 * child-exit. We add a usleep() which triggers the alarm in the parent and
397 * causes the test to time out.
399 TEST_BARRIER(test_barrier_no_exit,
401 msleep(BASE_TIME * 2);
403 TEST_BARRIER_WAIT_SUCCESS(pid1),
406 assert_se(barrier_place(&b));
407 assert_se(!barrier_sync(&b));
409 TEST_BARRIER_WAIT_ALARM(pid2));
412 * Test pending exit against sync
413 * The parent places a barrier *and* exits. The 20ms wait in the child
414 * guarantees both are pending. However, our logic prefers pending barriers over
415 * pending exit-abortions (unlike normal abortions), thus the wait_next() must
416 * succeed, same for the sync_next() as our local barrier-count is smaller than
417 * the remote. Once we place a barrier our count is equal, so the sync still
418 * succeeds. Only if we place one more barrier, we're ahead of the remote, thus
419 * we will fail due to HUP on the pipe.
421 TEST_BARRIER(test_barrier_pending_exit,
423 malarm(BASE_TIME * 4);
424 msleep(BASE_TIME * 2);
425 assert_se(barrier_wait_next(&b));
426 assert_se(barrier_sync_next(&b));
427 assert_se(barrier_place(&b));
428 assert_se(barrier_sync_next(&b));
429 assert_se(barrier_place(&b));
430 assert_se(!barrier_sync_next(&b));
432 TEST_BARRIER_WAIT_SUCCESS(pid1),
434 assert_se(barrier_place(&b));
436 TEST_BARRIER_WAIT_SUCCESS(pid2));
438 int main(int argc, char *argv[]) {
439 log_parse_environment();
443 test_barrier_wait_next();
444 test_barrier_wait_next_twice();
445 test_barrier_wait_next_twice_sync();
446 test_barrier_wait_next_twice_local();
447 test_barrier_wait_next_twice_local_sync();
448 test_barrier_sync_next();
449 test_barrier_sync_next_local();
450 test_barrier_sync_next_local_abort();
451 test_barrier_wait_abortion();
452 test_barrier_wait_abortion_unmatched();
453 test_barrier_wait_abortion_local();
454 test_barrier_wait_abortion_local_unmatched();
456 test_barrier_no_exit();
457 test_barrier_pending_exit();