chiark / gitweb /
Support negated fstab options
[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                 assert_se(b.me > 0);                                    \
68                 assert_se(b.them > 0);                                  \
69                 assert_se(b.pipe[0] > 0);                               \
70                 assert_se(b.pipe[1] > 0);                               \
71                                                                         \
72                 pid1 = fork();                                          \
73                 assert_se(pid1 >= 0);                                   \
74                 if (pid1 == 0) {                                        \
75                         barrier_set_role(&b, BARRIER_CHILD);            \
76                         { _CHILD_CODE; }                                \
77                         exit(42);                                       \
78                 }                                                       \
79                                                                         \
80                 pid2 = fork();                                          \
81                 assert_se(pid2 >= 0);                                   \
82                 if (pid2 == 0) {                                        \
83                         barrier_set_role(&b, BARRIER_PARENT);           \
84                         { _PARENT_CODE; }                               \
85                         exit(42);                                       \
86                 }                                                       \
87                                                                         \
88                 barrier_destroy(&b);                                    \
89                 set_alarm(999999);                                      \
90                 { _WAIT_CHILD; }                                        \
91                 { _WAIT_PARENT; }                                       \
92                 set_alarm(0);                                           \
93         }
94
95 #define TEST_BARRIER_WAIT_SUCCESS(_pid) \
96                 ({                                                      \
97                         int pidr, status;                               \
98                         pidr = waitpid(_pid, &status, 0);               \
99                         assert_se(pidr == _pid);                        \
100                         assert_se(WIFEXITED(status));                   \
101                         assert_se(WEXITSTATUS(status) == 42);           \
102                 })
103
104 #define TEST_BARRIER_WAIT_ALARM(_pid) \
105                 ({                                                      \
106                         int pidr, status;                               \
107                         pidr = waitpid(_pid, &status, 0);               \
108                         assert_se(pidr == _pid);                        \
109                         assert_se(WIFSIGNALED(status));                 \
110                         assert_se(WTERMSIG(status) == SIGALRM);         \
111                 })
112
113 /*
114  * Test basic sync points
115  * This places a barrier in both processes and waits synchronously for them.
116  * The timeout makes sure the sync works as expected. The sleep_for() on one side
117  * makes sure the exit of the parent does not overwrite previous barriers. Due
118  * to the sleep_for(), we know that the parent already exited, thus there's a
119  * pending HUP on the pipe. However, the barrier_sync() prefers reads on the
120  * eventfd, thus we can safely wait on the barrier.
121  */
122 TEST_BARRIER(test_barrier_sync,
123         ({
124                 set_alarm(BASE_TIME * 10);
125                 assert_se(barrier_place(&b));
126                 sleep_for(BASE_TIME * 2);
127                 assert_se(barrier_sync(&b));
128         }),
129         TEST_BARRIER_WAIT_SUCCESS(pid1),
130         ({
131                 set_alarm(BASE_TIME * 10);
132                 assert_se(barrier_place(&b));
133                 assert_se(barrier_sync(&b));
134         }),
135         TEST_BARRIER_WAIT_SUCCESS(pid2));
136
137 /*
138  * Test wait_next()
139  * This places a barrier in the parent and syncs on it. The child sleeps while
140  * the parent places the barrier and then waits for a barrier. The wait will
141  * succeed as the child hasn't read the parent's barrier, yet. The following
142  * barrier and sync synchronize the exit.
143  */
144 TEST_BARRIER(test_barrier_wait_next,
145         ({
146                 sleep_for(BASE_TIME);
147                 set_alarm(BASE_TIME * 10);
148                 assert_se(barrier_wait_next(&b));
149                 assert_se(barrier_place(&b));
150                 assert_se(barrier_sync(&b));
151         }),
152         TEST_BARRIER_WAIT_SUCCESS(pid1),
153         ({
154                 set_alarm(BASE_TIME * 4);
155                 assert_se(barrier_place(&b));
156                 assert_se(barrier_sync(&b));
157         }),
158         TEST_BARRIER_WAIT_SUCCESS(pid2));
159
160 /*
161  * Test wait_next() multiple times
162  * This places two barriers in the parent and waits for the child to exit. The
163  * child sleeps 20ms so both barriers _should_ be in place. It then waits for
164  * the parent to place the next barrier twice. The first call will fetch both
165  * barriers and return. However, the second call will stall as the parent does
166  * not place a 3rd barrier (the sleep caught two barriers). wait_next() is does
167  * not look at barrier-links so this stall is expected. Thus this test times
168  * out.
169  */
170 TEST_BARRIER(test_barrier_wait_next_twice,
171         ({
172                 sleep_for(BASE_TIME);
173                 set_alarm(BASE_TIME);
174                 assert_se(barrier_wait_next(&b));
175                 assert_se(barrier_wait_next(&b));
176                 assert_se(0);
177         }),
178         TEST_BARRIER_WAIT_ALARM(pid1),
179         ({
180                 set_alarm(BASE_TIME * 10);
181                 assert_se(barrier_place(&b));
182                 assert_se(barrier_place(&b));
183                 sleep_for(BASE_TIME * 4);
184         }),
185         TEST_BARRIER_WAIT_SUCCESS(pid2));
186
187 /*
188  * Test wait_next() with local barriers
189  * This is the same as test_barrier_wait_next_twice, but places local barriers
190  * between both waits. This does not have any effect on the wait so it times out
191  * like the other test.
192  */
193 TEST_BARRIER(test_barrier_wait_next_twice_local,
194         ({
195                 sleep_for(BASE_TIME);
196                 set_alarm(BASE_TIME);
197                 assert_se(barrier_wait_next(&b));
198                 assert_se(barrier_place(&b));
199                 assert_se(barrier_place(&b));
200                 assert_se(barrier_wait_next(&b));
201                 assert_se(0);
202         }),
203         TEST_BARRIER_WAIT_ALARM(pid1),
204         ({
205                 set_alarm(BASE_TIME * 10);
206                 assert_se(barrier_place(&b));
207                 assert_se(barrier_place(&b));
208                 sleep_for(BASE_TIME * 4);
209         }),
210         TEST_BARRIER_WAIT_SUCCESS(pid2));
211
212 /*
213  * Test wait_next() with sync_next()
214  * This is again the same as test_barrier_wait_next_twice but uses a
215  * synced wait as the second wait. This works just fine because the local state
216  * has no barriers placed, therefore, the remote is always in sync.
217  */
218 TEST_BARRIER(test_barrier_wait_next_twice_sync,
219         ({
220                 sleep_for(BASE_TIME);
221                 set_alarm(BASE_TIME);
222                 assert_se(barrier_wait_next(&b));
223                 assert_se(barrier_sync_next(&b));
224         }),
225         TEST_BARRIER_WAIT_SUCCESS(pid1),
226         ({
227                 set_alarm(BASE_TIME * 10);
228                 assert_se(barrier_place(&b));
229                 assert_se(barrier_place(&b));
230         }),
231         TEST_BARRIER_WAIT_SUCCESS(pid2));
232
233 /*
234  * Test wait_next() with sync_next() and local barriers
235  * This is again the same as test_barrier_wait_next_twice_local but uses a
236  * synced wait as the second wait. This works just fine because the local state
237  * is in sync with the remote.
238  */
239 TEST_BARRIER(test_barrier_wait_next_twice_local_sync,
240         ({
241                 sleep_for(BASE_TIME);
242                 set_alarm(BASE_TIME);
243                 assert_se(barrier_wait_next(&b));
244                 assert_se(barrier_place(&b));
245                 assert_se(barrier_place(&b));
246                 assert_se(barrier_sync_next(&b));
247         }),
248         TEST_BARRIER_WAIT_SUCCESS(pid1),
249         ({
250                 set_alarm(BASE_TIME * 10);
251                 assert_se(barrier_place(&b));
252                 assert_se(barrier_place(&b));
253         }),
254         TEST_BARRIER_WAIT_SUCCESS(pid2));
255
256 /*
257  * Test sync_next() and sync()
258  * This tests sync_*() synchronizations and makes sure they work fine if the
259  * local state is behind the remote state.
260  */
261 TEST_BARRIER(test_barrier_sync_next,
262         ({
263                 set_alarm(BASE_TIME * 10);
264                 assert_se(barrier_sync_next(&b));
265                 assert_se(barrier_sync(&b));
266                 assert_se(barrier_place(&b));
267                 assert_se(barrier_place(&b));
268                 assert_se(barrier_sync_next(&b));
269                 assert_se(barrier_sync_next(&b));
270                 assert_se(barrier_sync(&b));
271         }),
272         TEST_BARRIER_WAIT_SUCCESS(pid1),
273         ({
274                 set_alarm(BASE_TIME * 10);
275                 sleep_for(BASE_TIME);
276                 assert_se(barrier_place(&b));
277                 assert_se(barrier_place(&b));
278                 assert_se(barrier_sync(&b));
279         }),
280         TEST_BARRIER_WAIT_SUCCESS(pid2));
281
282 /*
283  * Test sync_next() and sync() with local barriers
284  * This tests timeouts if sync_*() is used if local barriers are placed but the
285  * remote didn't place any.
286  */
287 TEST_BARRIER(test_barrier_sync_next_local,
288         ({
289                 set_alarm(BASE_TIME);
290                 assert_se(barrier_place(&b));
291                 assert_se(barrier_sync_next(&b));
292                 assert_se(0);
293         }),
294         TEST_BARRIER_WAIT_ALARM(pid1),
295         ({
296                 sleep_for(BASE_TIME * 2);
297         }),
298         TEST_BARRIER_WAIT_SUCCESS(pid2));
299
300 /*
301  * Test sync_next() and sync() with local barriers and abortion
302  * This is the same as test_barrier_sync_next_local but aborts the sync in the
303  * parent. Therefore, the sync_next() succeeds just fine due to the abortion.
304  */
305 TEST_BARRIER(test_barrier_sync_next_local_abort,
306         ({
307                 set_alarm(BASE_TIME * 10);
308                 assert_se(barrier_place(&b));
309                 assert_se(!barrier_sync_next(&b));
310         }),
311         TEST_BARRIER_WAIT_SUCCESS(pid1),
312         ({
313                 assert_se(barrier_abort(&b));
314         }),
315         TEST_BARRIER_WAIT_SUCCESS(pid2));
316
317 /*
318  * Test matched wait_abortion()
319  * This runs wait_abortion() with remote abortion.
320  */
321 TEST_BARRIER(test_barrier_wait_abortion,
322         ({
323                 set_alarm(BASE_TIME * 10);
324                 assert_se(barrier_wait_abortion(&b));
325         }),
326         TEST_BARRIER_WAIT_SUCCESS(pid1),
327         ({
328                 assert_se(barrier_abort(&b));
329         }),
330         TEST_BARRIER_WAIT_SUCCESS(pid2));
331
332 /*
333  * Test unmatched wait_abortion()
334  * This runs wait_abortion() without any remote abortion going on. It thus must
335  * timeout.
336  */
337 TEST_BARRIER(test_barrier_wait_abortion_unmatched,
338         ({
339                 set_alarm(BASE_TIME);
340                 assert_se(barrier_wait_abortion(&b));
341                 assert_se(0);
342         }),
343         TEST_BARRIER_WAIT_ALARM(pid1),
344         ({
345                 sleep_for(BASE_TIME * 2);
346         }),
347         TEST_BARRIER_WAIT_SUCCESS(pid2));
348
349 /*
350  * Test matched wait_abortion() with local abortion
351  * This runs wait_abortion() with local and remote abortion.
352  */
353 TEST_BARRIER(test_barrier_wait_abortion_local,
354         ({
355                 set_alarm(BASE_TIME * 10);
356                 assert_se(barrier_abort(&b));
357                 assert_se(!barrier_wait_abortion(&b));
358         }),
359         TEST_BARRIER_WAIT_SUCCESS(pid1),
360         ({
361                 assert_se(barrier_abort(&b));
362         }),
363         TEST_BARRIER_WAIT_SUCCESS(pid2));
364
365 /*
366  * Test unmatched wait_abortion() with local abortion
367  * This runs wait_abortion() with only local abortion. This must time out.
368  */
369 TEST_BARRIER(test_barrier_wait_abortion_local_unmatched,
370         ({
371                 set_alarm(BASE_TIME);
372                 assert_se(barrier_abort(&b));
373                 assert_se(!barrier_wait_abortion(&b));
374                 assert_se(0);
375         }),
376         TEST_BARRIER_WAIT_ALARM(pid1),
377         ({
378                 sleep_for(BASE_TIME * 2);
379         }),
380         TEST_BARRIER_WAIT_SUCCESS(pid2));
381
382 /*
383  * Test child exit
384  * Place barrier and sync with the child. The child only exits()s, which should
385  * cause an implicit abortion and wake the parent.
386  */
387 TEST_BARRIER(test_barrier_exit,
388         ({
389         }),
390         TEST_BARRIER_WAIT_SUCCESS(pid1),
391         ({
392                 set_alarm(BASE_TIME * 10);
393                 assert_se(barrier_place(&b));
394                 assert_se(!barrier_sync(&b));
395         }),
396         TEST_BARRIER_WAIT_SUCCESS(pid2));
397
398 /*
399  * Test child exit with sleep
400  * Same as test_barrier_exit but verifies the test really works due to the
401  * child-exit. We add a usleep() which triggers the alarm in the parent and
402  * causes the test to time out.
403  */
404 TEST_BARRIER(test_barrier_no_exit,
405         ({
406                 sleep_for(BASE_TIME * 2);
407         }),
408         TEST_BARRIER_WAIT_SUCCESS(pid1),
409         ({
410                 set_alarm(BASE_TIME);
411                 assert_se(barrier_place(&b));
412                 assert_se(!barrier_sync(&b));
413         }),
414         TEST_BARRIER_WAIT_ALARM(pid2));
415
416 /*
417  * Test pending exit against sync
418  * The parent places a barrier *and* exits. The 20ms wait in the child
419  * guarantees both are pending. However, our logic prefers pending barriers over
420  * pending exit-abortions (unlike normal abortions), thus the wait_next() must
421  * succeed, same for the sync_next() as our local barrier-count is smaller than
422  * the remote. Once we place a barrier our count is equal, so the sync still
423  * succeeds. Only if we place one more barrier, we're ahead of the remote, thus
424  * we will fail due to HUP on the pipe.
425  */
426 TEST_BARRIER(test_barrier_pending_exit,
427         ({
428                 set_alarm(BASE_TIME * 4);
429                 sleep_for(BASE_TIME * 2);
430                 assert_se(barrier_wait_next(&b));
431                 assert_se(barrier_sync_next(&b));
432                 assert_se(barrier_place(&b));
433                 assert_se(barrier_sync_next(&b));
434                 assert_se(barrier_place(&b));
435                 assert_se(!barrier_sync_next(&b));
436         }),
437         TEST_BARRIER_WAIT_SUCCESS(pid1),
438         ({
439                 assert_se(barrier_place(&b));
440         }),
441         TEST_BARRIER_WAIT_SUCCESS(pid2));
442
443 int main(int argc, char *argv[]) {
444         log_parse_environment();
445         log_open();
446
447         test_barrier_sync();
448         test_barrier_wait_next();
449         test_barrier_wait_next_twice();
450         test_barrier_wait_next_twice_sync();
451         test_barrier_wait_next_twice_local();
452         test_barrier_wait_next_twice_local_sync();
453         test_barrier_sync_next();
454         test_barrier_sync_next_local();
455         test_barrier_sync_next_local_abort();
456         test_barrier_wait_abortion();
457         test_barrier_wait_abortion_unmatched();
458         test_barrier_wait_abortion_local();
459         test_barrier_wait_abortion_local_unmatched();
460         test_barrier_exit();
461         test_barrier_no_exit();
462         test_barrier_pending_exit();
463
464         return 0;
465 }