* 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;
TEST("semget(IPC_PRIVATE) - private");
int semID = semget(IPC_PRIVATE, NUM_OF_SEMS, S_IRUSR | S_IWUSR);
assert_posix_bool_success(semID != -1);
TEST("semctl(IPC_RMID) - private");
status_t status = remove_semaphore(semID);
assert_posix_bool_success(status != -1);
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);
TEST("semget(KEY) re-open existing without IPC_CREAT");
int returnID = semget(KEY, 0, 0);
assert_equals(semID, returnID);
TEST("semget(IPC_CREATE) re-open existing with IPC_CREAT");
returnID = semget(KEY, 0, IPC_CREAT | IPC_EXCL);
assert_posix_bool_success(errno == EEXIST);
TEST("semctl(IPC_RMID)");
status = remove_semaphore(semID);
assert_posix_bool_success(status != -1);
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);
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;
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");
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);
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;
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);
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) {
test_semop2();
exit(0);
}
wait_for_child(child);
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;
else
array[i].sem_op = -8;
array[i].sem_flg = 0;
}
TEST("semop() - father acquired set");
status = semop(semID, array, NUM_OF_SEMS);
assert_posix_bool_success(status != -1);
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;
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);
TEST("semctl(GETVAL)");
union semun args;
status_t status = semctl(semID, NUM_OF_SEMS - 1, GETVAL, args);
assert_posix_bool_success(status != -1);
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);
int returnedValue = semctl(semID, 4, GETVAL, 0);
assert_equals((unsigned short)returnedValue, (unsigned short)5);
TEST("semctl(GETALL)");
args.array = (unsigned short *)malloc(sizeof(unsigned short) * NUM_OF_SEMS);
semctl(semID, 0, GETALL, args);
assert_equals(args.array[NUM_OF_SEMS - 1], (unsigned short)5);
free(args.array);
TEST("semctl(SETVAL) - semaphore #2");
args.val = 7;
status = semctl(semID, 2, SETVAL, args);
assert_posix_bool_success(status != 1);
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);
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);
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);
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");
}