test-barrier.c revision 359017c1aec9596e9d3c4c19bd62d34a6f3366b8
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen/***
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen This file is part of systemd.
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen Copyright 2014 David Herrmann <dh.herrmann@gmail.com>
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen systemd is free software; you can redistribute it and/or modify it
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen under the terms of the GNU Lesser General Public License as published by
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen the Free Software Foundation; either version 2.1 of the License, or
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen (at your option) any later version.
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen systemd is distributed in the hope that it will be useful, but
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen WITHOUT ANY WARRANTY; without even the implied warranty of
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen Lesser General Public License for more details.
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen You should have received a copy of the GNU Lesser General Public License
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen along with systemd; If not, see <http://www.gnu.org/licenses/>.
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen***/
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen/*
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen * IPC barrier tests
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen * These tests verify the correct behavior of the IPC Barrier implementation.
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen * Note that the tests use alarm-timers to verify dead-locks and timeouts. These
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen * might not work on slow machines where 20ms are too short to perform specific
848d08b74eb0272774b1f8eff688d00ed9b63d9dDaniel Mack * operations (though, very unlikely). In case that turns out true, we have to
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen * increase it at the slightly cost of lengthen test-duration on other machines.
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen */
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen#include <errno.h>
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen#include <stdio.h>
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen#include <string.h>
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen#include <sys/time.h>
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen#include <sys/wait.h>
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen#include <unistd.h>
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen#include "barrier.h"
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen#include "def.h"
848d08b74eb0272774b1f8eff688d00ed9b63d9dDaniel Mack#include "util.h"
848d08b74eb0272774b1f8eff688d00ed9b63d9dDaniel Mack
848d08b74eb0272774b1f8eff688d00ed9b63d9dDaniel Mack/* 20ms to test deadlocks; All timings use multiples of this constant as
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen * alarm/sleep timers. If this timeout is too small for slow machines to perform
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen * the requested operations, we have to increase it. On an i7 this works fine
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen * with 1ms base-time, so 20ms should be just fine for everyone. */
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen#define BASE_TIME (20 * USEC_PER_MSEC)
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersenstatic void set_alarm(usec_t usecs) {
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen struct itimerval v = { };
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen timeval_store(&v.it_value, usecs);
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen assert_se(setitimer(ITIMER_REAL, &v, NULL) >= 0);
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen}
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersenstatic void sleep_for(usec_t usecs) {
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen /* stupid usleep() might fail if >1000000 */
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen assert_se(usecs < USEC_PER_SEC);
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen usleep(usecs);
370a2172ac0f455863a1ac8e7a9b0a284d810fd4Lennart Poettering}
370a2172ac0f455863a1ac8e7a9b0a284d810fd4Lennart Poettering
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen#define TEST_BARRIER(_FUNCTION, _CHILD_CODE, _WAIT_CHILD, _PARENT_CODE, _WAIT_PARENT) \
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen static void _FUNCTION(void) { \
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen Barrier b = BARRIER_NULL; \
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen pid_t pid1, pid2; \
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen \
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen assert_se(barrier_create(&b) >= 0); \
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen \
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen pid1 = fork(); \
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen assert_se(pid1 >= 0); \
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen if (pid1 == 0) { \
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen barrier_set_role(&b, BARRIER_CHILD); \
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen { _CHILD_CODE; } \
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen exit(42); \
848d08b74eb0272774b1f8eff688d00ed9b63d9dDaniel Mack } \
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen \
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen pid2 = fork(); \
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen assert_se(pid2 >= 0); \
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen if (pid2 == 0) { \
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen barrier_set_role(&b, BARRIER_PARENT); \
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen { _PARENT_CODE; } \
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen exit(42); \
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen } \
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen \
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen barrier_destroy(&b); \
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen set_alarm(999999); \
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen { _WAIT_CHILD; } \
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen { _WAIT_PARENT; } \
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen set_alarm(0); \
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen }
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen#define TEST_BARRIER_WAIT_SUCCESS(_pid) \
370a2172ac0f455863a1ac8e7a9b0a284d810fd4Lennart Poettering ({ \
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen int pidr, status; \
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen pidr = waitpid(_pid, &status, 0); \
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen assert_se(pidr == _pid); \
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen assert_se(WIFEXITED(status)); \
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen assert_se(WEXITSTATUS(status) == 42); \
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen })
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen
848d08b74eb0272774b1f8eff688d00ed9b63d9dDaniel Mack#define TEST_BARRIER_WAIT_ALARM(_pid) \
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen ({ \
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen int pidr, status; \
370a2172ac0f455863a1ac8e7a9b0a284d810fd4Lennart Poettering pidr = waitpid(_pid, &status, 0); \
370a2172ac0f455863a1ac8e7a9b0a284d810fd4Lennart Poettering assert_se(pidr == _pid); \
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen assert_se(WIFSIGNALED(status)); \
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen assert_se(WTERMSIG(status) == SIGALRM); \
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen })
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen/*
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen * Test basic sync points
370a2172ac0f455863a1ac8e7a9b0a284d810fd4Lennart Poettering * This places a barrier in both processes and waits synchronously for them.
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen * The timeout makes sure the sync works as expected. The sleep_for() on one side
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen * makes sure the exit of the parent does not overwrite previous barriers. Due
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen * to the sleep_for(), we know that the parent already exited, thus there's a
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen * pending HUP on the pipe. However, the barrier_sync() prefers reads on the
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen * eventfd, thus we can safely wait on the barrier.
848d08b74eb0272774b1f8eff688d00ed9b63d9dDaniel Mack */
5ffa42cb8028833440040c2e240e0d788f11c112Tom GundersenTEST_BARRIER(test_barrier_sync,
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen ({
370a2172ac0f455863a1ac8e7a9b0a284d810fd4Lennart Poettering set_alarm(BASE_TIME * 10);
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen assert_se(barrier_place(&b));
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen sleep_for(BASE_TIME * 2);
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen assert_se(barrier_sync(&b));
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen }),
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen TEST_BARRIER_WAIT_SUCCESS(pid1),
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen ({
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen set_alarm(BASE_TIME * 10);
370a2172ac0f455863a1ac8e7a9b0a284d810fd4Lennart Poettering assert_se(barrier_place(&b));
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen assert_se(barrier_sync(&b));
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen }),
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen TEST_BARRIER_WAIT_SUCCESS(pid2));
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen/*
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen * Test wait_next()
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen * This places a barrier in the parent and syncs on it. The child sleeps while
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen * the parent places the barrier and then waits for a barrier. The wait will
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen * succeed as the child hasn't read the parent's barrier, yet. The following
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen * barrier and sync synchronize the exit.
370a2172ac0f455863a1ac8e7a9b0a284d810fd4Lennart Poettering */
5ffa42cb8028833440040c2e240e0d788f11c112Tom GundersenTEST_BARRIER(test_barrier_wait_next,
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen ({
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen sleep_for(BASE_TIME);
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen set_alarm(BASE_TIME * 10);
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen assert_se(barrier_wait_next(&b));
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen assert_se(barrier_place(&b));
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen assert_se(barrier_sync(&b));
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen }),
a1e58e8ee1c84b633d6d6d651d5328d4dd4eba5bLennart Poettering TEST_BARRIER_WAIT_SUCCESS(pid1),
05fb03beeecd730e5525253b9c3c8706e1834b09Lennart Poettering ({
951c3eefacedcdbdb2cebf245f043aa3e81fb483Martin Mikkelsen set_alarm(BASE_TIME * 4);
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen assert_se(barrier_place(&b));
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen assert_se(barrier_sync(&b));
cb57dd41595adddb08095298bb1ed258c8ea4877Tom Gundersen }),
848d08b74eb0272774b1f8eff688d00ed9b63d9dDaniel Mack TEST_BARRIER_WAIT_SUCCESS(pid2));
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen/*
370a2172ac0f455863a1ac8e7a9b0a284d810fd4Lennart Poettering * Test wait_next() multiple times
370a2172ac0f455863a1ac8e7a9b0a284d810fd4Lennart Poettering * This places two barriers in the parent and waits for the child to exit. The
370a2172ac0f455863a1ac8e7a9b0a284d810fd4Lennart Poettering * child sleeps 20ms so both barriers _should_ be in place. It then waits for
22cedfe15fda59106b890ae2c646de96aa18a5ebDavid Herrmann * the parent to place the next barrier twice. The first call will fetch both
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen * barriers and return. However, the second call will stall as the parent does
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen * not place a 3rd barrier (the sleep caught two barriers). wait_next() is does
cb57dd41595adddb08095298bb1ed258c8ea4877Tom Gundersen * not look at barrier-links so this stall is expected. Thus this test times
cb57dd41595adddb08095298bb1ed258c8ea4877Tom Gundersen * out.
370a2172ac0f455863a1ac8e7a9b0a284d810fd4Lennart Poettering */
5ffa42cb8028833440040c2e240e0d788f11c112Tom GundersenTEST_BARRIER(test_barrier_wait_next_twice,
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen ({
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen sleep_for(BASE_TIME);
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen set_alarm(BASE_TIME);
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen assert_se(barrier_wait_next(&b));
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen assert_se(barrier_wait_next(&b));
cb57dd41595adddb08095298bb1ed258c8ea4877Tom Gundersen assert_se(0);
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen }),
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen TEST_BARRIER_WAIT_ALARM(pid1),
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen ({
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen set_alarm(BASE_TIME * 10);
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen assert_se(barrier_place(&b));
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen assert_se(barrier_place(&b));
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen sleep_for(BASE_TIME * 4);
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen }),
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen TEST_BARRIER_WAIT_SUCCESS(pid2));
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen
cb57dd41595adddb08095298bb1ed258c8ea4877Tom Gundersen/*
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen * Test wait_next() with local barriers
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen * This is the same as test_barrier_wait_next_twice, but places local barriers
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen * between both waits. This does not have any effect on the wait so it times out
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen * like the other test.
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen */
d5fa81995849cb263ecfcd0aa6ab661360d9213eMartin MikkelsenTEST_BARRIER(test_barrier_wait_next_twice_local,
d5fa81995849cb263ecfcd0aa6ab661360d9213eMartin Mikkelsen ({
d5fa81995849cb263ecfcd0aa6ab661360d9213eMartin Mikkelsen sleep_for(BASE_TIME);
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen set_alarm(BASE_TIME);
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen assert_se(barrier_wait_next(&b));
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen assert_se(barrier_place(&b));
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen assert_se(barrier_place(&b));
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen assert_se(barrier_wait_next(&b));
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen assert_se(0);
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen }),
d5fa81995849cb263ecfcd0aa6ab661360d9213eMartin Mikkelsen TEST_BARRIER_WAIT_ALARM(pid1),
d5fa81995849cb263ecfcd0aa6ab661360d9213eMartin Mikkelsen ({
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen set_alarm(BASE_TIME * 10);
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen assert_se(barrier_place(&b));
d5fa81995849cb263ecfcd0aa6ab661360d9213eMartin Mikkelsen assert_se(barrier_place(&b));
d5fa81995849cb263ecfcd0aa6ab661360d9213eMartin Mikkelsen sleep_for(BASE_TIME * 4);
d5fa81995849cb263ecfcd0aa6ab661360d9213eMartin Mikkelsen }),
d5fa81995849cb263ecfcd0aa6ab661360d9213eMartin Mikkelsen TEST_BARRIER_WAIT_SUCCESS(pid2));
d5fa81995849cb263ecfcd0aa6ab661360d9213eMartin Mikkelsen
d5fa81995849cb263ecfcd0aa6ab661360d9213eMartin Mikkelsen/*
5ffa42cb8028833440040c2e240e0d788f11c112Tom Gundersen * Test wait_next() with sync_next()
* This is again the same as test_barrier_wait_next_twice but uses a
* synced wait as the second wait. This works just fine because the local state
* has no barriers placed, therefore, the remote is always in sync.
*/
TEST_BARRIER(test_barrier_wait_next_twice_sync,
({
sleep_for(BASE_TIME);
set_alarm(BASE_TIME);
assert_se(barrier_wait_next(&b));
assert_se(barrier_sync_next(&b));
}),
TEST_BARRIER_WAIT_SUCCESS(pid1),
({
set_alarm(BASE_TIME * 10);
assert_se(barrier_place(&b));
assert_se(barrier_place(&b));
}),
TEST_BARRIER_WAIT_SUCCESS(pid2));
/*
* Test wait_next() with sync_next() and local barriers
* This is again the same as test_barrier_wait_next_twice_local but uses a
* synced wait as the second wait. This works just fine because the local state
* is in sync with the remote.
*/
TEST_BARRIER(test_barrier_wait_next_twice_local_sync,
({
sleep_for(BASE_TIME);
set_alarm(BASE_TIME);
assert_se(barrier_wait_next(&b));
assert_se(barrier_place(&b));
assert_se(barrier_place(&b));
assert_se(barrier_sync_next(&b));
}),
TEST_BARRIER_WAIT_SUCCESS(pid1),
({
set_alarm(BASE_TIME * 10);
assert_se(barrier_place(&b));
assert_se(barrier_place(&b));
}),
TEST_BARRIER_WAIT_SUCCESS(pid2));
/*
* Test sync_next() and sync()
* This tests sync_*() synchronizations and makes sure they work fine if the
* local state is behind the remote state.
*/
TEST_BARRIER(test_barrier_sync_next,
({
set_alarm(BASE_TIME * 10);
assert_se(barrier_sync_next(&b));
assert_se(barrier_sync(&b));
assert_se(barrier_place(&b));
assert_se(barrier_place(&b));
assert_se(barrier_sync_next(&b));
assert_se(barrier_sync_next(&b));
assert_se(barrier_sync(&b));
}),
TEST_BARRIER_WAIT_SUCCESS(pid1),
({
set_alarm(BASE_TIME * 10);
sleep_for(BASE_TIME);
assert_se(barrier_place(&b));
assert_se(barrier_place(&b));
assert_se(barrier_sync(&b));
}),
TEST_BARRIER_WAIT_SUCCESS(pid2));
/*
* Test sync_next() and sync() with local barriers
* This tests timeouts if sync_*() is used if local barriers are placed but the
* remote didn't place any.
*/
TEST_BARRIER(test_barrier_sync_next_local,
({
set_alarm(BASE_TIME);
assert_se(barrier_place(&b));
assert_se(barrier_sync_next(&b));
assert_se(0);
}),
TEST_BARRIER_WAIT_ALARM(pid1),
({
sleep_for(BASE_TIME * 2);
}),
TEST_BARRIER_WAIT_SUCCESS(pid2));
/*
* Test sync_next() and sync() with local barriers and abortion
* This is the same as test_barrier_sync_next_local but aborts the sync in the
* parent. Therefore, the sync_next() succeeds just fine due to the abortion.
*/
TEST_BARRIER(test_barrier_sync_next_local_abort,
({
set_alarm(BASE_TIME * 10);
assert_se(barrier_place(&b));
assert_se(!barrier_sync_next(&b));
}),
TEST_BARRIER_WAIT_SUCCESS(pid1),
({
assert_se(barrier_abort(&b));
}),
TEST_BARRIER_WAIT_SUCCESS(pid2));
/*
* Test matched wait_abortion()
* This runs wait_abortion() with remote abortion.
*/
TEST_BARRIER(test_barrier_wait_abortion,
({
set_alarm(BASE_TIME * 10);
assert_se(barrier_wait_abortion(&b));
}),
TEST_BARRIER_WAIT_SUCCESS(pid1),
({
assert_se(barrier_abort(&b));
}),
TEST_BARRIER_WAIT_SUCCESS(pid2));
/*
* Test unmatched wait_abortion()
* This runs wait_abortion() without any remote abortion going on. It thus must
* timeout.
*/
TEST_BARRIER(test_barrier_wait_abortion_unmatched,
({
set_alarm(BASE_TIME);
assert_se(barrier_wait_abortion(&b));
assert_se(0);
}),
TEST_BARRIER_WAIT_ALARM(pid1),
({
sleep_for(BASE_TIME * 2);
}),
TEST_BARRIER_WAIT_SUCCESS(pid2));
/*
* Test matched wait_abortion() with local abortion
* This runs wait_abortion() with local and remote abortion.
*/
TEST_BARRIER(test_barrier_wait_abortion_local,
({
set_alarm(BASE_TIME * 10);
assert_se(barrier_abort(&b));
assert_se(!barrier_wait_abortion(&b));
}),
TEST_BARRIER_WAIT_SUCCESS(pid1),
({
assert_se(barrier_abort(&b));
}),
TEST_BARRIER_WAIT_SUCCESS(pid2));
/*
* Test unmatched wait_abortion() with local abortion
* This runs wait_abortion() with only local abortion. This must time out.
*/
TEST_BARRIER(test_barrier_wait_abortion_local_unmatched,
({
set_alarm(BASE_TIME);
assert_se(barrier_abort(&b));
assert_se(!barrier_wait_abortion(&b));
assert_se(0);
}),
TEST_BARRIER_WAIT_ALARM(pid1),
({
sleep_for(BASE_TIME * 2);
}),
TEST_BARRIER_WAIT_SUCCESS(pid2));
/*
* Test child exit
* Place barrier and sync with the child. The child only exits()s, which should
* cause an implicit abortion and wake the parent.
*/
TEST_BARRIER(test_barrier_exit,
({
}),
TEST_BARRIER_WAIT_SUCCESS(pid1),
({
set_alarm(BASE_TIME * 10);
assert_se(barrier_place(&b));
assert_se(!barrier_sync(&b));
}),
TEST_BARRIER_WAIT_SUCCESS(pid2));
/*
* Test child exit with sleep
* Same as test_barrier_exit but verifies the test really works due to the
* child-exit. We add a usleep() which triggers the alarm in the parent and
* causes the test to time out.
*/
TEST_BARRIER(test_barrier_no_exit,
({
sleep_for(BASE_TIME * 2);
}),
TEST_BARRIER_WAIT_SUCCESS(pid1),
({
set_alarm(BASE_TIME);
assert_se(barrier_place(&b));
assert_se(!barrier_sync(&b));
}),
TEST_BARRIER_WAIT_ALARM(pid2));
/*
* Test pending exit against sync
* The parent places a barrier *and* exits. The 20ms wait in the child
* guarantees both are pending. However, our logic prefers pending barriers over
* pending exit-abortions (unlike normal abortions), thus the wait_next() must
* succeed, same for the sync_next() as our local barrier-count is smaller than
* the remote. Once we place a barrier our count is equal, so the sync still
* succeeds. Only if we place one more barrier, we're ahead of the remote, thus
* we will fail due to HUP on the pipe.
*/
TEST_BARRIER(test_barrier_pending_exit,
({
set_alarm(BASE_TIME * 4);
sleep_for(BASE_TIME * 2);
assert_se(barrier_wait_next(&b));
assert_se(barrier_sync_next(&b));
assert_se(barrier_place(&b));
assert_se(barrier_sync_next(&b));
assert_se(barrier_place(&b));
assert_se(!barrier_sync_next(&b));
}),
TEST_BARRIER_WAIT_SUCCESS(pid1),
({
assert_se(barrier_place(&b));
}),
TEST_BARRIER_WAIT_SUCCESS(pid2));
int main(int argc, char *argv[]) {
log_parse_environment();
log_open();
test_barrier_sync();
test_barrier_wait_next();
test_barrier_wait_next_twice();
test_barrier_wait_next_twice_sync();
test_barrier_wait_next_twice_local();
test_barrier_wait_next_twice_local_sync();
test_barrier_sync_next();
test_barrier_sync_next_local();
test_barrier_sync_next_local_abort();
test_barrier_wait_abortion();
test_barrier_wait_abortion_unmatched();
test_barrier_wait_abortion_local();
test_barrier_wait_abortion_local_unmatched();
test_barrier_exit();
test_barrier_no_exit();
test_barrier_pending_exit();
return 0;
}