/* * 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"); }