/* * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __HAIKU__ # include #else typedef int64_t bigtime_t; static bigtime_t system_time() { timeval tv; gettimeofday(&tv, NULL); return (bigtime_t)tv.tv_sec * 1000000 + tv.tv_usec; } #endif // !__HAIKU__ #include "TestUnitUtils.h" #if 0 static void dump_sem(const char* name, sem_t* sem) { printf("%s, %p: ", name, sem); for (size_t i = 0; i < sizeof(sem_t); i++) printf("%02x", ((char*)sem)[i]); printf("\n"); } #endif static const char* const kSemName1 = "/test_sem1"; static void test_open_close_unlink() { TEST_SET("sem_{open,close,unlink}()"); const char* currentTest = NULL; // open non-existing with O_CREAT TEST("sem_open(O_CREAT) non-existing"); sem_t* sem = sem_open(kSemName1, O_CREAT, S_IRUSR | S_IWUSR, 1); assert_posix_bool_success(sem != SEM_FAILED); // close TEST("sem_close()"); assert_posix_success(sem_close(sem)); // open existing with O_CREAT TEST("sem_open(O_CREAT) existing"); sem = sem_open(kSemName1, O_CREAT, S_IRUSR | S_IWUSR, 1); assert_posix_bool_success(sem != SEM_FAILED); // close TEST("sem_close()"); assert_posix_success(sem_close(sem)); // open existing without O_CREAT TEST("sem_open() existing"); sem = sem_open(kSemName1, 0); assert_posix_bool_success(sem != SEM_FAILED); // re-open existing without O_CREAT TEST("sem_open() existing"); sem_t* sem2 = sem_open(kSemName1, 0); assert_posix_bool_success(sem2 != SEM_FAILED); assert_equals(sem, sem2); // close TEST("sem_close()"); assert_posix_success(sem_close(sem)); // close TEST("sem_close()"); assert_posix_success(sem_close(sem)); // open existing with O_CREAT | O_EXCL TEST("sem_open(O_CREAT | O_EXCL) existing"); sem = sem_open(kSemName1, O_CREAT | O_EXCL, S_IRUSR | S_IWUSR, 1); assert_posix_bool_error(EEXIST, sem != SEM_FAILED); // open existing without O_CREAT TEST("sem_open() existing"); sem = sem_open(kSemName1, 0); assert_posix_bool_success(sem != SEM_FAILED); // unlink TEST("unlink() existing"); assert_posix_success(sem_unlink(kSemName1)); // open non-existing with O_CREAT | O_EXCL TEST("sem_open(O_CREAT | O_EXCL) non-existing"); sem2 = sem_open(kSemName1, O_CREAT | O_EXCL, S_IRUSR | S_IWUSR, 2); assert_posix_bool_success(sem2 != SEM_FAILED); assert_equals_not(sem, sem2); // unlink TEST("unlink() existing"); assert_posix_success(sem_unlink(kSemName1)); // unlink TEST("unlink() non-existing"); assert_posix_error(ENOENT, sem_unlink(kSemName1)); // close TEST("sem_close()"); assert_posix_success(sem_close(sem)); // close TEST("sem_close()"); assert_posix_success(sem_close(sem2)); TEST("done"); } static void test_init_destroy() { TEST_SET("sem_{init,destroy}()"); const char* currentTest = NULL; // init TEST("sem_init()"); sem_t sem; assert_posix_success(sem_init(&sem, 0, 1)); // destroy TEST("sem_destroy()"); assert_posix_success(sem_destroy(&sem)); // init TEST("sem_init()"); assert_posix_success(sem_init(&sem, 0, 1)); // init TEST("sem_init()"); sem_t sem2; assert_posix_success(sem_init(&sem2, 0, 2)); // destroy TEST("sem_destroy()"); assert_posix_success(sem_destroy(&sem)); // destroy TEST("sem_destroy()"); assert_posix_success(sem_destroy(&sem2)); TEST("done"); } static void test_open_close_fork() { TEST_SET("sem_{open,close}() with fork()"); const char* currentTest = NULL; // open non-existing with O_CREAT TEST("sem_open(O_CREAT) non-existing"); sem_t* sem = sem_open(kSemName1, O_CREAT, S_IRUSR | S_IWUSR, 1); assert_posix_bool_success(sem != SEM_FAILED); TEST("close_sem() forked"); pid_t child = fork(); assert_posix_bool_success(child >= 0); if (child == 0) { // child assert_posix_success(sem_close(sem)); exit(0); } else { // parent assert_posix_success(sem_close(sem)); wait_for_child(child); } TEST("sem_open() existing forked"); child = fork(); assert_posix_bool_success(child >= 0); if (child == 0) { // child sem = sem_open(kSemName1, O_CREAT); assert_posix_bool_success(sem != SEM_FAILED); exit(0); } else { // parent sem = sem_open(kSemName1, O_CREAT); wait_for_child(child); assert_posix_success(sem_close(sem)); } TEST("done"); } static void test_init_destroy_fork() { TEST_SET("sem_{init,destroy}() with fork()"); const char* currentTest = NULL; // init TEST("sem_init()"); sem_t sem; assert_posix_success(sem_init(&sem, 0, 1)); // destroy TEST("sem_destroy() forked"); pid_t child = fork(); assert_posix_bool_success(child >= 0); if (child == 0) { // child assert_posix_success(sem_destroy(&sem)); exit(0); } else { // parent assert_posix_success(sem_destroy(&sem)); wait_for_child(child); } TEST("done"); } static void test_post_wait_named() { TEST_SET("sem_{post,wait,trywait,timedwait}() named semaphore"); const char* currentTest = NULL; // make sure the sem doesn't exist yet sem_unlink(kSemName1); // open non-existing with O_CREAT TEST("sem_open(O_CREAT) non-existing"); sem_t* sem = sem_open(kSemName1, O_CREAT, S_IRUSR | S_IWUSR, 1); assert_posix_bool_success(sem != SEM_FAILED); TEST("sem_getvalue()"); int value; assert_posix_success(sem_getvalue(sem, &value)); assert_equals(1, value); // post TEST("sem_post() no waiting"); assert_posix_success(sem_post(sem)); TEST("sem_getvalue()"); assert_posix_success(sem_getvalue(sem, &value)); assert_equals(2, value); // wait TEST("sem_wait() non-blocking"); assert_posix_success(sem_wait(sem)); TEST("sem_getvalue()"); assert_posix_success(sem_getvalue(sem, &value)); assert_equals(1, value); // wait TEST("sem_wait() non-blocking"); assert_posix_success(sem_wait(sem)); TEST("sem_getvalue()"); assert_posix_success(sem_getvalue(sem, &value)); assert_equals(0, value); // close TEST("sem_close()"); assert_posix_success(sem_close(sem)); // re-open existing TEST("sem_open() existing"); sem = sem_open(kSemName1, 0); assert_posix_bool_success(sem != SEM_FAILED); TEST("sem_getvalue()"); assert_posix_success(sem_getvalue(sem, &value)); assert_equals(0, value); // post TEST("sem_post() no waiting"); assert_posix_success(sem_post(sem)); TEST("sem_getvalue()"); assert_posix_success(sem_getvalue(sem, &value)); assert_equals(1, value); // post TEST("sem_post() no waiting"); assert_posix_success(sem_post(sem)); TEST("sem_getvalue()"); assert_posix_success(sem_getvalue(sem, &value)); assert_equals(2, value); // trywait TEST("sem_trywait() success"); assert_posix_success(sem_trywait(sem)); TEST("sem_getvalue()"); assert_posix_success(sem_getvalue(sem, &value)); assert_equals(1, value); // trywait TEST("sem_trywait() success"); assert_posix_success(sem_trywait(sem)); TEST("sem_getvalue()"); assert_posix_success(sem_getvalue(sem, &value)); assert_equals(0, value); // trywait failure TEST("sem_trywait() failure"); assert_posix_error(EAGAIN, sem_trywait(sem)); TEST("sem_getvalue()"); assert_posix_success(sem_getvalue(sem, &value)); assert_equals(0, value); // post TEST("sem_post() no waiting"); assert_posix_success(sem_post(sem)); TEST("sem_getvalue()"); assert_posix_success(sem_getvalue(sem, &value)); assert_equals(1, value); // post TEST("sem_post() no waiting"); assert_posix_success(sem_post(sem)); TEST("sem_getvalue()"); assert_posix_success(sem_getvalue(sem, &value)); assert_equals(2, value); // timedwait TEST("sem_timedwait() success"); timespec timeout; assert_posix_success(sem_timedwait(sem, absolute_timeout(timeout, 1000000))); TEST("sem_getvalue()"); assert_posix_success(sem_getvalue(sem, &value)); assert_equals(1, value); TEST("sem_timedwait() success"); assert_posix_success(sem_timedwait(sem, absolute_timeout(timeout, 1000000))); TEST("sem_getvalue()"); assert_posix_success(sem_getvalue(sem, &value)); assert_equals(0, value); TEST("sem_timedwait() timeout"); bigtime_t startTime = system_time(); assert_posix_error(ETIMEDOUT, sem_timedwait(sem, absolute_timeout(timeout, 1000000))); bigtime_t diffTime = system_time() - startTime; assert_time_equals(1000000, diffTime); TEST("sem_getvalue()"); assert_posix_success(sem_getvalue(sem, &value)); assert_equals(0, value); // close TEST("sem_close()"); assert_posix_success(sem_close(sem)); TEST("done"); } static void test_post_wait_unnamed() { TEST_SET("sem_{post,wait,trywait,timedwait}() unnamed semaphore"); const char* currentTest = NULL; // init TEST("sem_init()"); sem_t _sem; assert_posix_success(sem_init(&_sem, 0, 1)); sem_t* sem = &_sem; TEST("sem_getvalue()"); int value; assert_posix_success(sem_getvalue(sem, &value)); assert_equals(1, value); // post TEST("sem_post() no waiting"); assert_posix_success(sem_post(sem)); TEST("sem_getvalue()"); assert_posix_success(sem_getvalue(sem, &value)); assert_equals(2, value); // wait TEST("sem_wait() non-blocking"); assert_posix_success(sem_wait(sem)); TEST("sem_getvalue()"); assert_posix_success(sem_getvalue(sem, &value)); assert_equals(1, value); // wait TEST("sem_wait() non-blocking"); assert_posix_success(sem_wait(sem)); TEST("sem_getvalue()"); assert_posix_success(sem_getvalue(sem, &value)); assert_equals(0, value); // post TEST("sem_post() no waiting"); assert_posix_success(sem_post(sem)); TEST("sem_getvalue()"); assert_posix_success(sem_getvalue(sem, &value)); assert_equals(1, value); // post TEST("sem_post() no waiting"); assert_posix_success(sem_post(sem)); TEST("sem_getvalue()"); assert_posix_success(sem_getvalue(sem, &value)); assert_equals(2, value); // trywait TEST("sem_trywait() success"); assert_posix_success(sem_trywait(sem)); TEST("sem_getvalue()"); assert_posix_success(sem_getvalue(sem, &value)); assert_equals(1, value); // trywait TEST("sem_trywait() success"); assert_posix_success(sem_trywait(sem)); TEST("sem_getvalue()"); assert_posix_success(sem_getvalue(sem, &value)); assert_equals(0, value); // trywait failure TEST("sem_trywait() failure"); assert_posix_error(EAGAIN, sem_trywait(sem)); TEST("sem_getvalue()"); assert_posix_success(sem_getvalue(sem, &value)); assert_equals(0, value); // post TEST("sem_post() no waiting"); assert_posix_success(sem_post(sem)); TEST("sem_getvalue()"); assert_posix_success(sem_getvalue(sem, &value)); assert_equals(1, value); // post TEST("sem_post() no waiting"); assert_posix_success(sem_post(sem)); TEST("sem_getvalue()"); assert_posix_success(sem_getvalue(sem, &value)); assert_equals(2, value); // timedwait TEST("sem_timedwait() success"); timespec timeout; assert_posix_success(sem_timedwait(sem, absolute_timeout(timeout, 1000000))); TEST("sem_getvalue()"); assert_posix_success(sem_getvalue(sem, &value)); assert_equals(1, value); TEST("sem_timedwait() success"); assert_posix_success(sem_timedwait(sem, absolute_timeout(timeout, 1000000))); TEST("sem_getvalue()"); assert_posix_success(sem_getvalue(sem, &value)); assert_equals(0, value); TEST("sem_timedwait() timeout"); bigtime_t startTime = system_time(); assert_posix_error(ETIMEDOUT, sem_timedwait(sem, absolute_timeout(timeout, 1000000))); bigtime_t diffTime = system_time() - startTime; assert_time_equals(1000000, diffTime); TEST("sem_getvalue()"); assert_posix_success(sem_getvalue(sem, &value)); assert_equals(0, value); // destroy TEST("sem_destroy()"); assert_posix_success(sem_destroy(sem)); TEST("done"); } static void test_post_wait_named_fork() { TEST_SET("sem_{post,wait,trywait,timedwait}() named semaphore with fork()"); const char* currentTest = NULL; // make sure the sem doesn't exist yet sem_unlink(kSemName1); // open non-existing with O_CREAT TEST("sem_open(O_CREAT) non-existing"); sem_t* sem = sem_open(kSemName1, O_CREAT, S_IRUSR | S_IWUSR, 0); assert_posix_bool_success(sem != SEM_FAILED); TEST("sem_getvalue()"); int value; assert_posix_success(sem_getvalue(sem, &value)); assert_equals(0, value); TEST("unblock child after wait"); pid_t child = fork(); assert_posix_bool_success(child >= 0); if (child == 0) { // child bigtime_t startTime = system_time(); assert_posix_success(sem_wait(sem)); bigtime_t diffTime = system_time() - startTime; assert_time_equals(1000000, diffTime); exit(0); } else { // parent sleep(1); assert_posix_success(sem_post(sem)); wait_for_child(child); } TEST("sem_getvalue()"); assert_posix_success(sem_getvalue(sem, &value)); assert_equals(0, value); TEST("unblock parent after wait"); child = fork(); assert_posix_bool_success(child >= 0); if (child == 0) { // child sleep(1); assert_posix_success(sem_post(sem)); exit(0); } else { // parent bigtime_t startTime = system_time(); assert_posix_success(sem_wait(sem)); bigtime_t diffTime = system_time() - startTime; assert_time_equals(1000000, diffTime); wait_for_child(child); } TEST("sem_getvalue()"); assert_posix_success(sem_getvalue(sem, &value)); assert_equals(0, value); TEST("unblock child after wait before timeout"); child = fork(); assert_posix_bool_success(child >= 0); if (child == 0) { // child timespec timeout; bigtime_t startTime = system_time(); assert_posix_success(sem_timedwait(sem, absolute_timeout(timeout, 2000000))); bigtime_t diffTime = system_time() - startTime; assert_time_equals(1000000, diffTime); exit(0); } else { // parent sleep(1); assert_posix_success(sem_post(sem)); wait_for_child(child); } TEST("sem_getvalue()"); assert_posix_success(sem_getvalue(sem, &value)); assert_equals(0, value); TEST("unblock child after wait after timeout"); child = fork(); assert_posix_bool_success(child >= 0); if (child == 0) { // child timespec timeout; bigtime_t startTime = system_time(); assert_posix_error(ETIMEDOUT, sem_timedwait(sem, absolute_timeout(timeout, 1000000))); bigtime_t diffTime = system_time() - startTime; assert_time_equals(1000000, diffTime); exit(0); } else { // parent sleep(2); assert_posix_success(sem_post(sem)); wait_for_child(child); } TEST("sem_getvalue()"); assert_posix_success(sem_getvalue(sem, &value)); assert_equals(1, value); // close TEST("sem_close()"); assert_posix_success(sem_close(sem)); TEST("done"); } static void test_post_wait_named_fork2() { TEST_SET("sem_{post,wait,trywait,timedwait}() named semaphore open after " "fork"); const char* currentTest = NULL; // make sure the sem doesn't exist yet sem_unlink(kSemName1); // open non-existing with O_CREAT TEST("sem_open(O_CREAT) non-existing"); sem_t* sem = sem_open(kSemName1, O_CREAT, S_IRUSR | S_IWUSR, 0); assert_posix_bool_success(sem != SEM_FAILED); TEST("sem_getvalue()"); int value; assert_posix_success(sem_getvalue(sem, &value)); assert_equals(0, value); // close TEST("sem_close()"); assert_posix_success(sem_close(sem)); sem = NULL; TEST("unblock child after wait"); pid_t child = fork(); assert_posix_bool_success(child >= 0); if (child == 0) { // child sem = sem_open(kSemName1, 0); assert_posix_bool_success(sem != SEM_FAILED); bigtime_t startTime = system_time(); assert_posix_success(sem_wait(sem)); bigtime_t diffTime = system_time() - startTime; assert_time_equals(1000000, diffTime); exit(0); } else { // parent sem = sem_open(kSemName1, 0); assert_posix_bool_success(sem != SEM_FAILED); sleep(1); assert_posix_success(sem_post(sem)); wait_for_child(child); } TEST("sem_getvalue()"); assert_posix_success(sem_getvalue(sem, &value)); assert_equals(0, value); // close TEST("sem_close()"); assert_posix_success(sem_close(sem)); sem = NULL; TEST("unblock child after wait before timeout"); child = fork(); assert_posix_bool_success(child >= 0); if (child == 0) { // child sem = sem_open(kSemName1, 0); assert_posix_bool_success(sem != SEM_FAILED); timespec timeout; bigtime_t startTime = system_time(); assert_posix_success(sem_timedwait(sem, absolute_timeout(timeout, 2000000))); bigtime_t diffTime = system_time() - startTime; assert_time_equals(1000000, diffTime); exit(0); } else { // parent sem = sem_open(kSemName1, 0); assert_posix_bool_success(sem != SEM_FAILED); sleep(1); assert_posix_success(sem_post(sem)); wait_for_child(child); } TEST("sem_getvalue()"); assert_posix_success(sem_getvalue(sem, &value)); assert_equals(0, value); // close TEST("sem_close()"); assert_posix_success(sem_close(sem)); sem = NULL; TEST("unblock child after wait after timeout"); child = fork(); assert_posix_bool_success(child >= 0); if (child == 0) { // child sem = sem_open(kSemName1, 0); assert_posix_bool_success(sem != SEM_FAILED); timespec timeout; bigtime_t startTime = system_time(); assert_posix_error(ETIMEDOUT, sem_timedwait(sem, absolute_timeout(timeout, 1000000))); bigtime_t diffTime = system_time() - startTime; assert_time_equals(1000000, diffTime); exit(0); } else { // parent sem = sem_open(kSemName1, 0); assert_posix_bool_success(sem != SEM_FAILED); sleep(2); assert_posix_success(sem_post(sem)); wait_for_child(child); } TEST("sem_getvalue()"); assert_posix_success(sem_getvalue(sem, &value)); assert_equals(1, value); // close TEST("sem_close()"); assert_posix_success(sem_close(sem)); TEST("done"); } static void test_post_wait_unnamed_fork() { TEST_SET("sem_{post,wait,trywait,timedwait}() unnamed semaphore with " "fork()"); const char* currentTest = NULL; // init TEST("sem_init()"); sem_t _sem; assert_posix_success(sem_init(&_sem, 0, 1)); sem_t* sem = &_sem; TEST("sem_getvalue()"); int value; assert_posix_success(sem_getvalue(sem, &value)); assert_equals(1, value); TEST("sem_wait() on fork()ed unnamed sem in parent and child"); pid_t child = fork(); assert_posix_bool_success(child >= 0); if (child == 0) { // child sleep(1); assert_posix_success(sem_wait(sem)); assert_posix_success(sem_getvalue(sem, &value)); assert_equals(0, value); exit(0); } else { // parent assert_posix_success(sem_wait(sem)); assert_posix_success(sem_getvalue(sem, &value)); assert_equals(0, value); wait_for_child(child); } TEST("sem_getvalue()"); assert_posix_success(sem_getvalue(sem, &value)); assert_equals(0, value); TEST("sem_post() on fork()ed unnamed sem in parent and child"); child = fork(); assert_posix_bool_success(child >= 0); if (child == 0) { // child assert_posix_success(sem_post(sem)); assert_posix_success(sem_getvalue(sem, &value)); assert_equals(1, value); exit(0); } else { // parent assert_posix_success(sem_post(sem)); assert_posix_success(sem_getvalue(sem, &value)); assert_equals(1, value); wait_for_child(child); } TEST("sem_getvalue()"); assert_posix_success(sem_getvalue(sem, &value)); assert_equals(1, value); // destroy TEST("sem_destroy()"); assert_posix_success(sem_destroy(sem)); TEST("done"); } static void test_post_wait_unnamed_fork_shared() { TEST_SET("sem_{post,wait,trywait,timedwait}() unnamed semaphore with " "fork() in shared memory"); const char* currentTest = NULL; // create shared memory area void* address = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0); assert_posix_bool_success(address != MAP_FAILED); // init TEST("sem_init()"); sem_t* sem = (sem_t*)address; assert_posix_success(sem_init(sem, 1, 0)); TEST("sem_getvalue()"); int value; assert_posix_success(sem_getvalue(sem, &value)); assert_equals(0, value); TEST("unblock child after wait"); pid_t child = fork(); assert_posix_bool_success(child >= 0); if (child == 0) { // child bigtime_t startTime = system_time(); assert_posix_success(sem_wait(sem)); bigtime_t diffTime = system_time() - startTime; assert_time_equals(1000000, diffTime); exit(0); } else { // parent sleep(1); assert_posix_success(sem_post(sem)); wait_for_child(child); } TEST("sem_getvalue()"); assert_posix_success(sem_getvalue(sem, &value)); assert_equals(0, value); TEST("unblock parent after wait"); child = fork(); assert_posix_bool_success(child >= 0); if (child == 0) { // child sleep(1); assert_posix_success(sem_post(sem)); exit(0); } else { // parent bigtime_t startTime = system_time(); assert_posix_success(sem_wait(sem)); bigtime_t diffTime = system_time() - startTime; assert_time_equals(1000000, diffTime); wait_for_child(child); } TEST("sem_getvalue()"); assert_posix_success(sem_getvalue(sem, &value)); assert_equals(0, value); TEST("unblock child after wait before timeout"); child = fork(); assert_posix_bool_success(child >= 0); if (child == 0) { // child timespec timeout; bigtime_t startTime = system_time(); assert_posix_success(sem_timedwait(sem, absolute_timeout(timeout, 2000000))); bigtime_t diffTime = system_time() - startTime; assert_time_equals(1000000, diffTime); exit(0); } else { // parent sleep(1); assert_posix_success(sem_post(sem)); wait_for_child(child); } TEST("sem_getvalue()"); assert_posix_success(sem_getvalue(sem, &value)); assert_equals(0, value); TEST("unblock child after wait after timeout"); child = fork(); assert_posix_bool_success(child >= 0); if (child == 0) { // child timespec timeout; bigtime_t startTime = system_time(); assert_posix_error(ETIMEDOUT, sem_timedwait(sem, absolute_timeout(timeout, 1000000))); bigtime_t diffTime = system_time() - startTime; assert_time_equals(1000000, diffTime); exit(0); } else { // parent sleep(2); assert_posix_success(sem_post(sem)); wait_for_child(child); } TEST("sem_getvalue()"); assert_posix_success(sem_getvalue(sem, &value)); assert_equals(1, value); // destroy TEST("sem_destroy()"); assert_posix_success(sem_destroy(sem)); // unmap memory assert_posix_success(munmap(address, 4096)); TEST("done"); } int main() { test_open_close_unlink(); test_init_destroy(); test_open_close_fork(); test_init_destroy_fork(); test_post_wait_named(); test_post_wait_unnamed(); test_post_wait_named_fork(); test_post_wait_named_fork2(); test_post_wait_unnamed_fork(); test_post_wait_unnamed_fork_shared(); printf("\nall tests OK\n"); }