diff --git a/src/tests/system/libroot/posix/Jamfile b/src/tests/system/libroot/posix/Jamfile index 4ca97c96fe..cfde63a0f1 100644 --- a/src/tests/system/libroot/posix/Jamfile +++ b/src/tests/system/libroot/posix/Jamfile @@ -52,6 +52,10 @@ SimpleTest init_rld_after_fork_test : init_rld_after_fork_test.cpp ; +SimpleTest xsi_sem_test1 + : xsi_sem_test1.cpp +; + # Tell Jam where to find these sources SEARCH on [ FGristFiles syslog.cpp diff --git a/src/tests/system/libroot/posix/TestUnitUtils.h b/src/tests/system/libroot/posix/TestUnitUtils.h new file mode 100644 index 0000000000..aca85354c5 --- /dev/null +++ b/src/tests/system/libroot/posix/TestUnitUtils.h @@ -0,0 +1,150 @@ +/* + * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef _UNIT_TEST_UTILS_H +#define _UNIT_TEST_UTILS_H + +static timespec* +absolute_timeout(timespec& timeout, bigtime_t relativeTimeout) +{ + timeval tv; + gettimeofday(&tv, NULL); + timeout.tv_sec = tv.tv_sec + relativeTimeout / 1000000; + timeout.tv_nsec = (tv.tv_usec + relativeTimeout % 1000000) * 1000; + if (timeout.tv_nsec > 1000000000) { + timeout.tv_sec++; + timeout.tv_nsec -= 1000000000; + } + + return &timeout; +} + + +template +static void +_assert_equals(const char* test, const Type& expected, const Type& actual, + int lineNumber) +{ + if (actual == expected) + return; + + fprintf(stderr, "%s FAILED in line %d\n", test, lineNumber); + exit(1); +} + + +template +static void +_assert_equals_not(const char* test, const Type& unexpected, const Type& actual, + int lineNumber) +{ + if (actual != unexpected) + return; + + fprintf(stderr, "%s FAILED in line %d\n", test, lineNumber); + exit(1); +} + + +static void +_assert_time_equals(const char* test, bigtime_t expected, + bigtime_t actual, int lineNumber) +{ + // allow 5% deviation + bigtime_t diff = actual > expected ? actual - expected : expected - actual; + if (diff <= expected / 20) + return; + + fprintf(stderr, "%s FAILED in line %d: expected time: %lld, actual: %lld\n", + test, lineNumber, (long long)expected, (long long)actual); + exit(1); +} + + +static void +_assert_posix_bool_success(const char* test, bool success, int lineNumber) +{ + if (success) + return; + + fprintf(stderr, "%s FAILED in line %d: %s\n", test, lineNumber, + strerror(errno)); + exit(1); +} + + +static void +_assert_posix_bool_error(const char* test, int expectedError, bool success, + int lineNumber) +{ + if (success) { + fprintf(stderr, "%s FAILED in line %d: call succeeded unexpectedly\n", + test, lineNumber); + exit(1); + } + + if (errno != expectedError) { + fprintf(stderr, "%s FAILED in line %d: call set unexpected error " + "code \"%s\" (0x%x), expected: \"%s\" (0x%x)\n", test, lineNumber, + strerror(errno), errno, strerror(expectedError), expectedError); + exit(1); + } +} + + +static void +test_set(const char* testSet) +{ + printf("\nTEST SET: %s\n", testSet); +} + + +static void +test_ok(const char* test) +{ + if (test != NULL) + printf("%s OK\n", test); +} + + +static void +_wait_for_child(const char* test, pid_t child, int lineNumber) +{ + int status; + pid_t result = wait(&status); + _assert_posix_bool_success(test, result >= 0, lineNumber); + _assert_equals(test, child, result, lineNumber); + _assert_equals(test, 0, status, lineNumber); +} + + +#define TEST_SET(testSet) test_set(testSet) +#define TEST(test) test_ok(currentTest); currentTest = (test) + +#define assert_equals(expected, actual) \ + _assert_equals(currentTest, (expected), (actual), __LINE__) + +#define assert_equals_not(expected, actual) \ + _assert_equals_not(currentTest, (expected), (actual), __LINE__) + +#define assert_time_equals(expected, actual) \ + _assert_time_equals(currentTest, (expected), (actual), __LINE__) + +#define assert_posix_bool_success(success) \ + _assert_posix_bool_success(currentTest, (success), __LINE__) + +#define assert_posix_success(result) \ + _assert_posix_bool_success(currentTest, (result) == 0, __LINE__) + +#define assert_posix_bool_error(expectedError, success) \ + _assert_posix_bool_error(currentTest, (expectedError), (success), __LINE__) + +#define assert_posix_error(expectedError, result) \ + _assert_posix_bool_error(currentTest, (expectedError), (result) == 0, \ + __LINE__) + +#define wait_for_child(child) \ + _wait_for_child(currentTest, (child), __LINE__) + +#endif // _UNIT_TEST_UTILS_H diff --git a/src/tests/system/libroot/posix/realtime_sem_test1.cpp b/src/tests/system/libroot/posix/realtime_sem_test1.cpp index f1606594cd..d3cac89377 100644 --- a/src/tests/system/libroot/posix/realtime_sem_test1.cpp +++ b/src/tests/system/libroot/posix/realtime_sem_test1.cpp @@ -35,120 +35,7 @@ system_time() #endif // !__HAIKU__ - -static timespec* -absolute_timeout(timespec& timeout, bigtime_t relativeTimeout) -{ - timeval tv; - gettimeofday(&tv, NULL); - timeout.tv_sec = tv.tv_sec + relativeTimeout / 1000000; - timeout.tv_nsec = (tv.tv_usec + relativeTimeout % 1000000) * 1000; - if (timeout.tv_nsec > 1000000000) { - timeout.tv_sec++; - timeout.tv_nsec -= 1000000000; - } - - return &timeout; -} - - -template -static void -_assert_equals(const char* test, const Type& expected, const Type& actual, - int lineNumber) -{ - if (actual == expected) - return; - - fprintf(stderr, "%s FAILED in line %d\n", test, lineNumber); - exit(1); -} - - -template -static void -_assert_equals_not(const char* test, const Type& unexpected, const Type& actual, - int lineNumber) -{ - if (actual != unexpected) - return; - - fprintf(stderr, "%s FAILED in line %d\n", test, lineNumber); - exit(1); -} - - -static void -_assert_time_equals(const char* test, bigtime_t expected, - bigtime_t actual, int lineNumber) -{ - // allow 5% deviation - bigtime_t diff = actual > expected ? actual - expected : expected - actual; - if (diff <= expected / 20) - return; - - fprintf(stderr, "%s FAILED in line %d: expected time: %lld, actual: %lld\n", - test, lineNumber, (long long)expected, (long long)actual); - exit(1); -} - - -static void -_assert_posix_bool_success(const char* test, bool success, int lineNumber) -{ - if (success) - return; - - fprintf(stderr, "%s FAILED in line %d: %s\n", test, lineNumber, - strerror(errno)); - exit(1); -} - - -static void -_assert_posix_bool_error(const char* test, int expectedError, bool success, - int lineNumber) -{ - if (success) { - fprintf(stderr, "%s FAILED in line %d: call succeeded unexpectedly\n", - test, lineNumber); - exit(1); - } - - if (errno != expectedError) { - fprintf(stderr, "%s FAILED in line %d: call set unexpected error " - "code \"%s\" (0x%x), expected: \"%s\" (0x%x)\n", test, lineNumber, - strerror(errno), errno, strerror(expectedError), expectedError); - exit(1); - } -} - - -static void -test_set(const char* testSet) -{ - printf("\nTEST SET: %s\n", testSet); -} - - -static void -test_ok(const char* test) -{ - if (test != NULL) - printf("%s OK\n", test); -} - - -static void -_wait_for_child(const char* test, pid_t child, int lineNumber) -{ - int status; - pid_t result = wait(&status); - _assert_posix_bool_success(test, result >= 0, lineNumber); - _assert_equals(test, child, result, lineNumber); - _assert_equals(test, 0, status, lineNumber); -} - +#include "TestUnitUtils.h" #if 0 static void @@ -162,35 +49,6 @@ dump_sem(const char* name, sem_t* sem) #endif -#define TEST_SET(testSet) test_set(testSet) -#define TEST(test) test_ok(currentTest); currentTest = (test) - -#define assert_equals(expected, actual) \ - _assert_equals(currentTest, (expected), (actual), __LINE__) - -#define assert_equals_not(expected, actual) \ - _assert_equals_not(currentTest, (expected), (actual), __LINE__) - -#define assert_time_equals(expected, actual) \ - _assert_time_equals(currentTest, (expected), (actual), __LINE__) - -#define assert_posix_bool_success(success) \ - _assert_posix_bool_success(currentTest, (success), __LINE__) - -#define assert_posix_success(result) \ - _assert_posix_bool_success(currentTest, (result) == 0, __LINE__) - -#define assert_posix_bool_error(expectedError, success) \ - _assert_posix_bool_error(currentTest, (expectedError), (success), __LINE__) - -#define assert_posix_error(expectedError, result) \ - _assert_posix_bool_error(currentTest, (expectedError), (result) == 0, \ - __LINE__) - -#define wait_for_child(child) \ - _wait_for_child(currentTest, (child), __LINE__) - - static const char* const kSemName1 = "/test_sem1"; diff --git a/src/tests/system/libroot/posix/xsi_sem_test1.cpp b/src/tests/system/libroot/posix/xsi_sem_test1.cpp new file mode 100644 index 0000000000..c894ae29ee --- /dev/null +++ b/src/tests/system/libroot/posix/xsi_sem_test1.cpp @@ -0,0 +1,325 @@ +/* + * Copyright 2008, Salvatore Benedetto, salvatore.benedetto@gmail.com. + * Distributed under the terms of the MIT License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "TestUnitUtils.h" + +#define KEY ((key_t)12345) +#define NUM_OF_SEMS 10 + +union semun { + int val; + struct semid_ds *buf; + unsigned short *array; +}; + + +static status_t +remove_semaphore(int semID) +{ + return semctl(semID, 0, IPC_RMID, 0); +} + + +static void +test_semget() +{ + TEST_SET("semget({IPC_PRIVATE, key})"); + + const char* currentTest = NULL; + + // Open private set with IPC_PRIVATE + TEST("semget(IPC_PRIVATE) - private"); + int semID = semget(IPC_PRIVATE, NUM_OF_SEMS, S_IRUSR | S_IWUSR); + assert_posix_bool_success(semID != -1); + + // Destroy private semaphore + TEST("semctl(IPC_RMID) - private"); + status_t status = remove_semaphore(semID); + assert_posix_bool_success(status != -1); + + // Open non-private non-existing set with IPC_CREAT + TEST("semget(KEY, IPC_CREAT) non-existing"); + semID = semget(KEY, NUM_OF_SEMS, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR + | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); + assert_posix_bool_success(status != -1); + + // Re-open non-private existing without IPC_CREAT + TEST("semget(KEY) re-open existing without IPC_CREAT"); + int returnID = semget(KEY, 0, 0); + assert_equals(semID, returnID); + + // Re-open non-private existing with IPC_CREAT + TEST("semget(IPC_CREATE) re-open existing with IPC_CREAT"); + returnID = semget(KEY, 0, IPC_CREAT | IPC_EXCL); + assert_posix_bool_success(errno == EEXIST); + + // Destroy non-private semaphore + TEST("semctl(IPC_RMID)"); + status = remove_semaphore(semID); + assert_posix_bool_success(status != -1); + + // Open non-private non-existing without IPC_CREAT + TEST("semget(IPC_CREATE) non-existing without IPC_CREAT"); + semID = semget(KEY, NUM_OF_SEMS, IPC_EXCL | S_IRUSR | S_IWUSR + | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); + assert_posix_bool_success(errno == ENOENT); + + // Destroy non-existing semaphore + TEST("semctl()"); + status = remove_semaphore(semID); + assert_posix_bool_success(errno == EINVAL); + + TEST("done"); +} + + +static void +test_semop2() +{ + TEST_SET("semop2()"); + + const char* currentTest = NULL; + + // Re-open non-private existing without IPC_CREAT + TEST("semget(KEY) re-open existing without IPC_CREAT"); + int returnedID = semget(KEY, 0, 0); + assert_posix_bool_success(returnedID != -1); + + TEST("semop(IPC_NOWAIT) - wait for zero"); + // Set up array of semaphores + struct sembuf array[NUM_OF_SEMS]; + for (int i = 0; i < NUM_OF_SEMS; i++) { + array[i].sem_num = i; + array[i].sem_op = 0; + array[i].sem_flg = IPC_NOWAIT; + } + semop(returnedID, array, NUM_OF_SEMS); + assert_posix_bool_success(errno == EAGAIN); + + TEST("semop(IPC_NOWAIT) - wait to increase"); + for (int i = 0; i < NUM_OF_SEMS; i++) { + array[i].sem_num = i; + array[i].sem_op = -9; + array[i].sem_flg = IPC_NOWAIT; + } + semop(returnedID, array, NUM_OF_SEMS); + assert_posix_bool_success(errno == EAGAIN); + + TEST("semop(IPC_NOWAIT) - acquire resource sem #0"); + struct sembuf ops; + ops.sem_num = 0; + ops.sem_op = -8; + ops.sem_flg = 0; + status_t status = semop(returnedID, &ops, 1); + assert_posix_bool_success(status != -1); + + TEST("semop(IPC_NOWAIT) - acquire zero sem #0"); + ops.sem_num = 0; + ops.sem_op = 0; + ops.sem_flg = 0; + status = semop(returnedID, &ops, 1); + + TEST("semop(IPC_NOWAIT) - revert semop sem #0"); + ops.sem_num = 0; + ops.sem_op = 8; + ops.sem_flg = 0; + status = semop(returnedID, &ops, 1); + + // Decrease to zero even semaphores and + // use SEM_UNDO flag on odd semaphores in order + // to wake up the father on exit + // Set up array of semaphores + for (int i = 0; i < NUM_OF_SEMS; i++) { + array[i].sem_num = i; + array[i].sem_op = -8; + if (i % 2) + array[i].sem_flg = 0; + else + array[i].sem_flg = SEM_UNDO; + } + TEST("semop() - father"); + status = semop(returnedID, array, NUM_OF_SEMS); + assert_posix_bool_success(status != -1); + + TEST("done"); +} + + +static void +test_semop() +{ + TEST_SET("semop()"); + const char* currentTest = NULL; + + // Open non-private non-existing set with IPC_CREAT + TEST("semget(IPC_CREATE) non-existing"); + int semID = semget(KEY, NUM_OF_SEMS, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR + | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); + assert_posix_bool_success(semID != -1); + + // SETALL + TEST("semctl(SETALL)"); + union semun args; + args.array = (unsigned short *)malloc(sizeof(unsigned short) * NUM_OF_SEMS); + for (int i = 0; i < NUM_OF_SEMS; i++) + args.array[i] = 8; + status_t status = semctl(semID, 0, SETALL, args); + assert_posix_bool_success(status != -1); + free(args.array); + + pid_t child = fork(); + if (child == 0) { + // The child first will test the IPC_NOWAIT + // feature, while the father waits for him, + // by waiting for zero on even semaphores, + // and to increase for odd semaphores, which + // will happen on process exit due to SEM_UNDO + // feature. + test_semop2(); + exit(0); + } + + wait_for_child(child); + + // Set up array of semaphores + struct sembuf array[NUM_OF_SEMS]; + for (int i = 0; i < NUM_OF_SEMS; i++) { + array[i].sem_num = i; + if (i % 2) + array[i].sem_op = 0; // wait for zero + else + array[i].sem_op = -8; // wait to increase + array[i].sem_flg = 0; + } + TEST("semop() - father acquired set"); + status = semop(semID, array, NUM_OF_SEMS); + assert_posix_bool_success(status != -1); + + // Destroy non-private semaphore + TEST("semctl(IPC_RMID)"); + status = remove_semaphore(semID); + assert_posix_bool_success(status != 1); + + TEST("done"); +} + + +static void +test_semctl() +{ + TEST_SET("semctl({GETVAL, SETVAL, GETPID, GETNCNT, GETZCNT, GETALL, SETALL, IPC_STAT, IPC_SET, IPC_RMID})"); + + const char* currentTest = NULL; + + // Open non-private non-existing set with IPC_CREAT + TEST("semget(IPC_CREATE) non-existing"); + int semID = semget(KEY, NUM_OF_SEMS, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR + | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); + assert_posix_bool_success(semID != -1); + + // GETVAL + TEST("semctl(GETVAL)"); + union semun args; + status_t status = semctl(semID, NUM_OF_SEMS - 1, GETVAL, args); + // Semaphore is not initialized. Value is unknown. + // We care about not crashing into KDL. + assert_posix_bool_success(status != -1); + + // SETALL + TEST("semctl(SETALL)"); + args.array = (unsigned short *)malloc(sizeof(unsigned short) * NUM_OF_SEMS); + for (int i = 0; i < NUM_OF_SEMS; i++) + args.array[i] = 5; + status = semctl(semID, 0, SETALL, args); + assert_posix_bool_success(status != -1); + free(args.array); + + // GETVAL semaphore 4 + int returnedValue = semctl(semID, 4, GETVAL, 0); + assert_equals((unsigned short)returnedValue, (unsigned short)5); + + // GETALL + TEST("semctl(GETALL)"); + args.array = (unsigned short *)malloc(sizeof(unsigned short) * NUM_OF_SEMS); + semctl(semID, 0, GETALL, args); + // Check only last semaphore value + assert_equals(args.array[NUM_OF_SEMS - 1], (unsigned short)5); + free(args.array); + + // SETVAL semaphore 2 + TEST("semctl(SETVAL) - semaphore #2"); + args.val = 7; + status = semctl(semID, 2, SETVAL, args); + assert_posix_bool_success(status != 1); + + // GETALL + TEST("semctl(GETALL)"); + args.array = (unsigned short *)malloc(sizeof(unsigned short) * NUM_OF_SEMS); + status = semctl(semID, 0, GETALL, args); + assert_posix_bool_success(status != -1); + TEST("semctl(GETALL) - semaphore #10"); + assert_equals(args.array[NUM_OF_SEMS - 1], (unsigned short)5); + TEST("semctl(GETALL) - semaphore #2"); + assert_equals(args.array[NUM_OF_SEMS - 1], (unsigned short)5); + free(args.array); + + // IPC_SET + TEST("semctl(IPC_SET)"); + struct semid_ds semaphore; + memset(&semaphore, 0, sizeof(struct semid_ds)); + semaphore.sem_perm.uid = getuid() + 3; + semaphore.sem_perm.gid = getgid() + 3; + semaphore.sem_perm.mode = 0666; + args.buf = &semaphore; + status = semctl(semID, 0, IPC_SET, args); + assert_posix_bool_success(status != 1); + + // IPC_STAT set + TEST("semctl(IPC_STAT)"); + memset(&semaphore, 0, sizeof(struct semid_ds)); + args.buf = &semaphore; + status = semctl(semID, 0, IPC_STAT, args); + assert_posix_bool_success(status != 1); + TEST("semctl(IPC_STAT): number of sems"); + assert_equals((unsigned short)args.buf->sem_nsems, (unsigned short)NUM_OF_SEMS); + TEST("semctl(IPC_STAT): uid"); + assert_equals(args.buf->sem_perm.uid, getuid() + 3); + TEST("semctl(IPC_STAT): gid"); + assert_equals(args.buf->sem_perm.gid, getgid() + 3); + + // Destroy non-private semaphore + TEST("semctl(IPC_RMID)"); + status = remove_semaphore(semID); + assert_posix_bool_success(status != 1); + + TEST("done"); +} + + +int +main() +{ + test_semget(); + test_semctl(); + test_semop(); + + printf("\nAll tests OK\n"); +}