chiark / gitweb /
fstab-generator: ignore invalid swap priority
[elogind.git] / src / test / test-barrier.c
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
31 #include <stdio.h>
32 #include <sys/time.h>
33 #include <sys/wait.h>
34 #include <unistd.h>
35
36 #include "barrier.h"
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. */
43 #define BASE_TIME (20 * USEC_PER_MSEC)
44
45 static void set_alarm(usec_t usecs) {
46         struct itimerval v = { };
47
48         timeval_store(&v.it_value, usecs);
49         assert_se(setitimer(ITIMER_REAL, &v, NULL) >= 0);
50 }
51
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);
56 }
57
58 #define TEST_BARRIER(_FUNCTION, _CHILD_CODE, _WAIT_CHILD, _PARENT_CODE, _WAIT_PARENT)  \
59         static void _FUNCTION(void) {                                   \
60                 Barrier b = BARRIER_NULL;                               \
61                 pid_t pid1, pid2;                                       \
62                                                                         \
63                 assert_se(barrier_create(&b) >= 0);                     \
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);                               \
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);                                    \
86                 set_alarm(999999);                                      \
87                 { _WAIT_CHILD; }                                        \
88                 { _WAIT_PARENT; }                                       \
89                 set_alarm(0);                                           \
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.
113  * The timeout makes sure the sync works as expected. The sleep_for() on one side
114  * makes sure the exit of the parent does not overwrite previous barriers. Due
115  * to the sleep_for(), we know that the parent already exited, thus there's a
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         ({
121                 set_alarm(BASE_TIME * 10);
122                 assert_se(barrier_place(&b));
123                 sleep_for(BASE_TIME * 2);
124                 assert_se(barrier_sync(&b));
125         }),
126         TEST_BARRIER_WAIT_SUCCESS(pid1),
127         ({
128                 set_alarm(BASE_TIME * 10);
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         ({
143                 sleep_for(BASE_TIME);
144                 set_alarm(BASE_TIME * 10);
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         ({
151                 set_alarm(BASE_TIME * 4);
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         ({
169                 sleep_for(BASE_TIME);
170                 set_alarm(BASE_TIME);
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         ({
177                 set_alarm(BASE_TIME * 10);
178                 assert_se(barrier_place(&b));
179                 assert_se(barrier_place(&b));
180                 sleep_for(BASE_TIME * 4);
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         ({
192                 sleep_for(BASE_TIME);
193                 set_alarm(BASE_TIME);
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         ({
202                 set_alarm(BASE_TIME * 10);
203                 assert_se(barrier_place(&b));
204                 assert_se(barrier_place(&b));
205                 sleep_for(BASE_TIME * 4);
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         ({
217                 sleep_for(BASE_TIME);
218                 set_alarm(BASE_TIME);
219                 assert_se(barrier_wait_next(&b));
220                 assert_se(barrier_sync_next(&b));
221         }),
222         TEST_BARRIER_WAIT_SUCCESS(pid1),
223         ({
224                 set_alarm(BASE_TIME * 10);
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         ({
238                 sleep_for(BASE_TIME);
239                 set_alarm(BASE_TIME);
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         ({
247                 set_alarm(BASE_TIME * 10);
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         ({
260                 set_alarm(BASE_TIME * 10);
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         ({
271                 set_alarm(BASE_TIME * 10);
272                 sleep_for(BASE_TIME);
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         ({
286                 set_alarm(BASE_TIME);
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         ({
293                 sleep_for(BASE_TIME * 2);
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         ({
304                 set_alarm(BASE_TIME * 10);
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         ({
320                 set_alarm(BASE_TIME * 10);
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         ({
336                 set_alarm(BASE_TIME);
337                 assert_se(barrier_wait_abortion(&b));
338                 assert_se(0);
339         }),
340         TEST_BARRIER_WAIT_ALARM(pid1),
341         ({
342                 sleep_for(BASE_TIME * 2);
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         ({
352                 set_alarm(BASE_TIME * 10);
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         ({
368                 set_alarm(BASE_TIME);
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         ({
375                 sleep_for(BASE_TIME * 2);
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         ({
389                 set_alarm(BASE_TIME * 10);
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         ({
403                 sleep_for(BASE_TIME * 2);
404         }),
405         TEST_BARRIER_WAIT_SUCCESS(pid1),
406         ({
407                 set_alarm(BASE_TIME);
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         ({
425                 set_alarm(BASE_TIME * 4);
426                 sleep_for(BASE_TIME * 2);
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 }