From 94ca573005daeb5c2d0f141b688175d493617cf1 Mon Sep 17 00:00:00 2001 From: Andy Wingo Date: Sun, 19 Apr 2015 13:28:47 +0200 Subject: Remove src/test --- src/test/test-barrier.c | 462 ------------------------------------------------ 1 file changed, 462 deletions(-) delete mode 100644 src/test/test-barrier.c (limited to 'src/test/test-barrier.c') diff --git a/src/test/test-barrier.c b/src/test/test-barrier.c deleted file mode 100644 index 2d109a30e7..0000000000 --- a/src/test/test-barrier.c +++ /dev/null @@ -1,462 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2014 David Herrmann - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -/* - * IPC barrier tests - * These tests verify the correct behavior of the IPC Barrier implementation. - * Note that the tests use alarm-timers to verify dead-locks and timeouts. These - * might not work on slow machines where 20ms are too short to perform specific - * operations (though, very unlikely). In case that turns out true, we have to - * increase it at the slightly cost of lengthen test-duration on other machines. - */ - -#include -#include -#include -#include - -#include "barrier.h" -#include "util.h" - -/* 20ms to test deadlocks; All timings use multiples of this constant as - * alarm/sleep timers. If this timeout is too small for slow machines to perform - * the requested operations, we have to increase it. On an i7 this works fine - * with 1ms base-time, so 20ms should be just fine for everyone. */ -#define BASE_TIME (20 * USEC_PER_MSEC) - -static void set_alarm(usec_t usecs) { - struct itimerval v = { }; - - timeval_store(&v.it_value, usecs); - assert_se(setitimer(ITIMER_REAL, &v, NULL) >= 0); -} - -static void sleep_for(usec_t usecs) { - /* stupid usleep() might fail if >1000000 */ - assert_se(usecs < USEC_PER_SEC); - usleep(usecs); -} - -#define TEST_BARRIER(_FUNCTION, _CHILD_CODE, _WAIT_CHILD, _PARENT_CODE, _WAIT_PARENT) \ - static void _FUNCTION(void) { \ - Barrier b = BARRIER_NULL; \ - pid_t pid1, pid2; \ - \ - assert_se(barrier_create(&b) >= 0); \ - assert_se(b.me > 0); \ - assert_se(b.them > 0); \ - assert_se(b.pipe[0] > 0); \ - assert_se(b.pipe[1] > 0); \ - \ - pid1 = fork(); \ - assert_se(pid1 >= 0); \ - if (pid1 == 0) { \ - barrier_set_role(&b, BARRIER_CHILD); \ - { _CHILD_CODE; } \ - exit(42); \ - } \ - \ - pid2 = fork(); \ - assert_se(pid2 >= 0); \ - if (pid2 == 0) { \ - barrier_set_role(&b, BARRIER_PARENT); \ - { _PARENT_CODE; } \ - exit(42); \ - } \ - \ - barrier_destroy(&b); \ - set_alarm(999999); \ - { _WAIT_CHILD; } \ - { _WAIT_PARENT; } \ - set_alarm(0); \ - } - -#define TEST_BARRIER_WAIT_SUCCESS(_pid) \ - ({ \ - int pidr, status; \ - pidr = waitpid(_pid, &status, 0); \ - assert_se(pidr == _pid); \ - assert_se(WIFEXITED(status)); \ - assert_se(WEXITSTATUS(status) == 42); \ - }) - -#define TEST_BARRIER_WAIT_ALARM(_pid) \ - ({ \ - int pidr, status; \ - pidr = waitpid(_pid, &status, 0); \ - assert_se(pidr == _pid); \ - assert_se(WIFSIGNALED(status)); \ - assert_se(WTERMSIG(status) == SIGALRM); \ - }) - -/* - * Test basic sync points - * This places a barrier in both processes and waits synchronously for them. - * The timeout makes sure the sync works as expected. The sleep_for() on one side - * makes sure the exit of the parent does not overwrite previous barriers. Due - * to the sleep_for(), we know that the parent already exited, thus there's a - * pending HUP on the pipe. However, the barrier_sync() prefers reads on the - * eventfd, thus we can safely wait on the barrier. - */ -TEST_BARRIER(test_barrier_sync, - ({ - set_alarm(BASE_TIME * 10); - assert_se(barrier_place(&b)); - sleep_for(BASE_TIME * 2); - assert_se(barrier_sync(&b)); - }), - 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 wait_next() - * This places a barrier in the parent and syncs on it. The child sleeps while - * the parent places the barrier and then waits for a barrier. The wait will - * succeed as the child hasn't read the parent's barrier, yet. The following - * barrier and sync synchronize the exit. - */ -TEST_BARRIER(test_barrier_wait_next, - ({ - sleep_for(BASE_TIME); - set_alarm(BASE_TIME * 10); - assert_se(barrier_wait_next(&b)); - assert_se(barrier_place(&b)); - assert_se(barrier_sync(&b)); - }), - TEST_BARRIER_WAIT_SUCCESS(pid1), - ({ - set_alarm(BASE_TIME * 4); - assert_se(barrier_place(&b)); - assert_se(barrier_sync(&b)); - }), - TEST_BARRIER_WAIT_SUCCESS(pid2)); - -/* - * Test wait_next() multiple times - * This places two barriers in the parent and waits for the child to exit. The - * child sleeps 20ms so both barriers _should_ be in place. It then waits for - * the parent to place the next barrier twice. The first call will fetch both - * barriers and return. However, the second call will stall as the parent does - * not place a 3rd barrier (the sleep caught two barriers). wait_next() is does - * not look at barrier-links so this stall is expected. Thus this test times - * out. - */ -TEST_BARRIER(test_barrier_wait_next_twice, - ({ - sleep_for(BASE_TIME); - set_alarm(BASE_TIME); - assert_se(barrier_wait_next(&b)); - assert_se(barrier_wait_next(&b)); - assert_se(0); - }), - TEST_BARRIER_WAIT_ALARM(pid1), - ({ - set_alarm(BASE_TIME * 10); - assert_se(barrier_place(&b)); - assert_se(barrier_place(&b)); - sleep_for(BASE_TIME * 4); - }), - TEST_BARRIER_WAIT_SUCCESS(pid2)); - -/* - * Test wait_next() with local barriers - * This is the same as test_barrier_wait_next_twice, but places local barriers - * between both waits. This does not have any effect on the wait so it times out - * like the other test. - */ -TEST_BARRIER(test_barrier_wait_next_twice_local, - ({ - 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_wait_next(&b)); - assert_se(0); - }), - TEST_BARRIER_WAIT_ALARM(pid1), - ({ - set_alarm(BASE_TIME * 10); - assert_se(barrier_place(&b)); - assert_se(barrier_place(&b)); - sleep_for(BASE_TIME * 4); - }), - TEST_BARRIER_WAIT_SUCCESS(pid2)); - -/* - * 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; -} -- cgit v1.2.3-54-g00ecf