chiark / gitweb /
barrier: convert msecs to usecs in test-code
[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 <errno.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <sys/time.h>
35 #include <sys/wait.h>
36 #include <unistd.h>
37
38 #include "barrier.h"
39 #include "def.h"
40 #include "util.h"
41
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. */
46 #define BASE_TIME (20 * USEC_PER_MSEC)
47
48 static void set_alarm(usec_t usecs) {
49         struct itimerval v = { };
50
51         timeval_store(&v.it_value, usecs);
52         assert_se(setitimer(ITIMER_REAL, &v, NULL) >= 0);
53 }
54
55 static void sleep_for(usec_t usecs) {
56         /* stupid usleep() might fail if >1000000 */
57         assert_se(usecs < USEC_PER_SEC);
58         usleep(usecs);
59 }
60
61 #define TEST_BARRIER(_FUNCTION, _CHILD_CODE, _WAIT_CHILD, _PARENT_CODE, _WAIT_PARENT)  \
62         static void _FUNCTION(void) {                                   \
63                 Barrier b = BARRIER_NULL;                               \
64                 pid_t pid1, pid2;                                       \
65                                                                         \
66                 assert_se(barrier_create(&b) >= 0);                     \
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);                                    \
85                 set_alarm(999999);                                      \
86                 { _WAIT_CHILD; }                                        \
87                 { _WAIT_PARENT; }                                       \
88                 set_alarm(0);                                           \
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.
112  * The timeout makes sure the sync works as expected. The sleep_for() on one side
113  * makes sure the exit of the parent does not overwrite previous barriers. Due
114  * to the sleep_for(), we know that the parent already exited, thus there's a
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         ({
120                 set_alarm(BASE_TIME * 10);
121                 assert_se(barrier_place(&b));
122                 sleep_for(BASE_TIME * 2);
123                 assert_se(barrier_sync(&b));
124         }),
125         TEST_BARRIER_WAIT_SUCCESS(pid1),
126         ({
127                 set_alarm(BASE_TIME * 10);
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         ({
142                 sleep_for(BASE_TIME);
143                 set_alarm(BASE_TIME * 10);
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         ({
150                 set_alarm(BASE_TIME * 4);
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         ({
168                 sleep_for(BASE_TIME);
169                 set_alarm(BASE_TIME);
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         ({
176                 set_alarm(BASE_TIME * 10);
177                 assert_se(barrier_place(&b));
178                 assert_se(barrier_place(&b));
179                 sleep_for(BASE_TIME * 2);
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         ({
191                 sleep_for(BASE_TIME);
192                 set_alarm(BASE_TIME);
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         ({
201                 set_alarm(BASE_TIME * 10);
202                 assert_se(barrier_place(&b));
203                 assert_se(barrier_place(&b));
204                 sleep_for(BASE_TIME * 2);
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         ({
216                 sleep_for(BASE_TIME);
217                 set_alarm(BASE_TIME);
218                 assert_se(barrier_wait_next(&b));
219                 assert_se(barrier_sync_next(&b));
220         }),
221         TEST_BARRIER_WAIT_SUCCESS(pid1),
222         ({
223                 set_alarm(BASE_TIME * 10);
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         ({
237                 sleep_for(BASE_TIME);
238                 set_alarm(BASE_TIME);
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         ({
246                 set_alarm(BASE_TIME * 10);
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         ({
259                 set_alarm(BASE_TIME * 10);
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         ({
270                 set_alarm(BASE_TIME * 10);
271                 sleep_for(BASE_TIME);
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         ({
285                 set_alarm(BASE_TIME);
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         ({
292                 sleep_for(BASE_TIME * 2);
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         ({
303                 set_alarm(BASE_TIME * 10);
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         ({
319                 set_alarm(BASE_TIME * 10);
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         ({
335                 set_alarm(BASE_TIME);
336                 assert_se(barrier_wait_abortion(&b));
337                 assert_se(0);
338         }),
339         TEST_BARRIER_WAIT_ALARM(pid1),
340         ({
341                 sleep_for(BASE_TIME * 2);
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         ({
351                 set_alarm(BASE_TIME * 10);
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         ({
367                 set_alarm(BASE_TIME);
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         ({
374                 sleep_for(BASE_TIME * 2);
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         ({
388                 set_alarm(BASE_TIME * 10);
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         ({
402                 sleep_for(BASE_TIME * 2);
403         }),
404         TEST_BARRIER_WAIT_SUCCESS(pid1),
405         ({
406                 set_alarm(BASE_TIME);
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         ({
424                 set_alarm(BASE_TIME * 4);
425                 sleep_for(BASE_TIME * 2);
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[]) {
440         log_parse_environment();
441         log_open();
442
443         test_barrier_sync();
444         test_barrier_wait_next();
445         test_barrier_wait_next_twice();
446         test_barrier_wait_next_twice_sync();
447         test_barrier_wait_next_twice_local();
448         test_barrier_wait_next_twice_local_sync();
449         test_barrier_sync_next();
450         test_barrier_sync_next_local();
451         test_barrier_sync_next_local_abort();
452         test_barrier_wait_abortion();
453         test_barrier_wait_abortion_unmatched();
454         test_barrier_wait_abortion_local();
455         test_barrier_wait_abortion_local_unmatched();
456         test_barrier_exit();
457         test_barrier_no_exit();
458         test_barrier_pending_exit();
459
460         return 0;
461 }