* Adding xsi semaphore test unit

* Moving common functions and macros used in realtime_sem_test1
  to a shared header as they are probably going to be used for other test unit



git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@26854 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Salvatore Benedetto 2008-08-07 08:09:56 +00:00
parent a89962b923
commit cefb069022
4 changed files with 480 additions and 143 deletions

View File

@ -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

View File

@ -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<typename Type>
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<typename Type>
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

View File

@ -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<typename Type>
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<typename Type>
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";

View File

@ -0,0 +1,325 @@
/*
* Copyright 2008, Salvatore Benedetto, salvatore.benedetto@gmail.com.
* Distributed under the terms of the MIT License.
*/
#include <errno.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/sem.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <time.h>
#include <OS.h>
#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");
}