[haiku-gsoc] XSI test unit application
- From: "Salvatore Benedetto" <emitrax@xxxxxxxxx>
- To: haiku-gsoc@xxxxxxxxxxxxx
- Date: Tue, 5 Aug 2008 09:02:27 +0000
Hi there,
sorry for the delay, but I had a busy real-life week-end.
I'm attaching a first patch of the test unit application.
Regards,
--
Salvatore Benedetto (a.k.a. emitrax)
Student of Computer Engineer
University of Pisa
www.haiku-os.it
/*
* Copyright 2008, Salvatore Benedetto, salvatore.benedetto@xxxxxxxxxx
* 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>
#define KEY ((key_t)12345)
#define NUM_OF_SEMS 10
typedef int64_t bigtime_t;
union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
};
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_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);
}
static status_t
remove_semaphore(int semID)
{
return semctl(semID, 0, IPC_RMID, 0);
}
#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_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 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");
}
Other related posts:
- » [haiku-gsoc] XSI test unit application