1 /* 2 * Copyright 2008, Salvatore Benedetto, salvatore.benedetto@gmail.com. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 #include <errno.h> 7 #include <fcntl.h> 8 #include <stdint.h> 9 #include <stdio.h> 10 #include <stdlib.h> 11 #include <string.h> 12 #include <unistd.h> 13 #include <sys/mman.h> 14 #include <sys/sem.h> 15 #include <sys/stat.h> 16 #include <sys/time.h> 17 #include <sys/wait.h> 18 #include <time.h> 19 20 #include <OS.h> 21 22 #include "TestUnitUtils.h" 23 24 #define KEY ((key_t)12345) 25 #define NUM_OF_SEMS 10 26 27 union semun { 28 int val; 29 struct semid_ds *buf; 30 unsigned short *array; 31 }; 32 33 34 static status_t 35 remove_semaphore(int semID) 36 { 37 return semctl(semID, 0, IPC_RMID, 0); 38 } 39 40 41 static void 42 test_semget() 43 { 44 TEST_SET("semget({IPC_PRIVATE, key})"); 45 46 const char* currentTest = NULL; 47 48 // Open private set with IPC_PRIVATE 49 TEST("semget(IPC_PRIVATE) - private"); 50 int semID = semget(IPC_PRIVATE, NUM_OF_SEMS, S_IRUSR | S_IWUSR); 51 assert_posix_bool_success(semID != -1); 52 53 // Destroy private semaphore 54 TEST("semctl(IPC_RMID) - private"); 55 status_t status = remove_semaphore(semID); 56 assert_posix_bool_success(status != -1); 57 58 // Open non-private non-existing set with IPC_CREAT 59 TEST("semget(KEY, IPC_CREAT) non-existing"); 60 semID = semget(KEY, NUM_OF_SEMS, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR 61 | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); 62 assert_posix_bool_success(status != -1); 63 64 // Re-open non-private existing without IPC_CREAT 65 TEST("semget(KEY) re-open existing without IPC_CREAT"); 66 int returnID = semget(KEY, 0, 0); 67 assert_equals(semID, returnID); 68 69 // Re-open non-private existing with IPC_CREAT 70 TEST("semget(IPC_CREATE) re-open existing with IPC_CREAT"); 71 returnID = semget(KEY, 0, IPC_CREAT | IPC_EXCL); 72 assert_posix_bool_success(errno == EEXIST); 73 74 // Destroy non-private semaphore 75 TEST("semctl(IPC_RMID)"); 76 status = remove_semaphore(semID); 77 assert_posix_bool_success(status != -1); 78 79 // Open non-private non-existing without IPC_CREAT 80 TEST("semget(IPC_CREATE) non-existing without IPC_CREAT"); 81 semID = semget(KEY, NUM_OF_SEMS, IPC_EXCL | S_IRUSR | S_IWUSR 82 | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); 83 assert_posix_bool_success(errno == ENOENT); 84 85 // Destroy non-existing semaphore 86 TEST("semctl()"); 87 status = remove_semaphore(semID); 88 assert_posix_bool_success(errno == EINVAL); 89 90 TEST("done"); 91 } 92 93 94 static void 95 test_semop2() 96 { 97 TEST_SET("semop2()"); 98 99 const char* currentTest = NULL; 100 101 // Re-open non-private existing without IPC_CREAT 102 TEST("semget(KEY) re-open existing without IPC_CREAT"); 103 int returnedID = semget(KEY, 0, 0); 104 assert_posix_bool_success(returnedID != -1); 105 106 TEST("semop(IPC_NOWAIT) - wait for zero"); 107 // Set up array of semaphores 108 struct sembuf array[NUM_OF_SEMS]; 109 for (int i = 0; i < NUM_OF_SEMS; i++) { 110 array[i].sem_num = i; 111 array[i].sem_op = 0; 112 array[i].sem_flg = IPC_NOWAIT; 113 } 114 semop(returnedID, array, NUM_OF_SEMS); 115 assert_posix_bool_success(errno == EAGAIN); 116 117 TEST("semop(IPC_NOWAIT) - wait to increase"); 118 for (int i = 0; i < NUM_OF_SEMS; i++) { 119 array[i].sem_num = i; 120 array[i].sem_op = -9; 121 array[i].sem_flg = IPC_NOWAIT; 122 } 123 semop(returnedID, array, NUM_OF_SEMS); 124 assert_posix_bool_success(errno == EAGAIN); 125 126 TEST("semop(IPC_NOWAIT) - acquire resource sem #0"); 127 struct sembuf ops; 128 ops.sem_num = 0; 129 ops.sem_op = -8; 130 ops.sem_flg = 0; 131 status_t status = semop(returnedID, &ops, 1); 132 assert_posix_bool_success(status != -1); 133 134 TEST("semop(IPC_NOWAIT) - acquire zero sem #0"); 135 ops.sem_num = 0; 136 ops.sem_op = 0; 137 ops.sem_flg = 0; 138 status = semop(returnedID, &ops, 1); 139 140 TEST("semop(IPC_NOWAIT) - revert semop sem #0"); 141 ops.sem_num = 0; 142 ops.sem_op = 8; 143 ops.sem_flg = 0; 144 status = semop(returnedID, &ops, 1); 145 146 // Decrease to zero even semaphores and 147 // use SEM_UNDO flag on odd semaphores in order 148 // to wake up the father on exit 149 // Set up array of semaphores 150 for (int i = 0; i < NUM_OF_SEMS; i++) { 151 array[i].sem_num = i; 152 array[i].sem_op = -8; 153 if (i % 2) 154 array[i].sem_flg = 0; 155 else 156 array[i].sem_flg = SEM_UNDO; 157 } 158 TEST("semop() - father"); 159 status = semop(returnedID, array, NUM_OF_SEMS); 160 assert_posix_bool_success(status != -1); 161 162 TEST("done"); 163 } 164 165 166 static void 167 test_semop() 168 { 169 TEST_SET("semop()"); 170 const char* currentTest = NULL; 171 172 // Open non-private non-existing set with IPC_CREAT 173 TEST("semget(IPC_CREATE) non-existing"); 174 int semID = semget(KEY, NUM_OF_SEMS, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR 175 | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); 176 assert_posix_bool_success(semID != -1); 177 178 // SETALL 179 TEST("semctl(SETALL)"); 180 union semun args; 181 args.array = (unsigned short *)malloc(sizeof(unsigned short) * NUM_OF_SEMS); 182 for (int i = 0; i < NUM_OF_SEMS; i++) 183 args.array[i] = 8; 184 status_t status = semctl(semID, 0, SETALL, args); 185 assert_posix_bool_success(status != -1); 186 free(args.array); 187 188 pid_t child = fork(); 189 if (child == 0) { 190 // The child first will test the IPC_NOWAIT 191 // feature, while the father waits for him, 192 // by waiting for zero on even semaphores, 193 // and to increase for odd semaphores, which 194 // will happen on process exit due to SEM_UNDO 195 // feature. 196 test_semop2(); 197 exit(0); 198 } 199 200 wait_for_child(child); 201 202 // Set up array of semaphores 203 struct sembuf array[NUM_OF_SEMS]; 204 for (int i = 0; i < NUM_OF_SEMS; i++) { 205 array[i].sem_num = i; 206 if (i % 2) 207 array[i].sem_op = 0; // wait for zero 208 else 209 array[i].sem_op = -8; // wait to increase 210 array[i].sem_flg = 0; 211 } 212 TEST("semop() - father acquired set"); 213 status = semop(semID, array, NUM_OF_SEMS); 214 assert_posix_bool_success(status != -1); 215 216 // Destroy non-private semaphore 217 TEST("semctl(IPC_RMID)"); 218 status = remove_semaphore(semID); 219 assert_posix_bool_success(status != 1); 220 221 TEST("done"); 222 } 223 224 225 static void 226 test_semctl() 227 { 228 TEST_SET("semctl({GETVAL, SETVAL, GETPID, GETNCNT, GETZCNT, GETALL, SETALL, IPC_STAT, IPC_SET, IPC_RMID})"); 229 230 const char* currentTest = NULL; 231 232 // Open non-private non-existing set with IPC_CREAT 233 TEST("semget(IPC_CREATE) non-existing"); 234 int semID = semget(KEY, NUM_OF_SEMS, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR 235 | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); 236 assert_posix_bool_success(semID != -1); 237 238 // GETVAL 239 TEST("semctl(GETVAL)"); 240 union semun args; 241 status_t status = semctl(semID, NUM_OF_SEMS - 1, GETVAL, args); 242 // Semaphore is not initialized. Value is unknown. 243 // We care about not crashing into KDL. 244 assert_posix_bool_success(status != -1); 245 246 // SETALL 247 TEST("semctl(SETALL)"); 248 args.array = (unsigned short *)malloc(sizeof(unsigned short) * NUM_OF_SEMS); 249 for (int i = 0; i < NUM_OF_SEMS; i++) 250 args.array[i] = 5; 251 status = semctl(semID, 0, SETALL, args); 252 assert_posix_bool_success(status != -1); 253 free(args.array); 254 255 // GETVAL semaphore 4 256 int returnedValue = semctl(semID, 4, GETVAL, 0); 257 assert_equals((unsigned short)returnedValue, (unsigned short)5); 258 259 // GETALL 260 TEST("semctl(GETALL)"); 261 args.array = (unsigned short *)malloc(sizeof(unsigned short) * NUM_OF_SEMS); 262 semctl(semID, 0, GETALL, args); 263 // Check only last semaphore value 264 assert_equals(args.array[NUM_OF_SEMS - 1], (unsigned short)5); 265 free(args.array); 266 267 // SETVAL semaphore 2 268 TEST("semctl(SETVAL) - semaphore #2"); 269 args.val = 7; 270 status = semctl(semID, 2, SETVAL, args); 271 assert_posix_bool_success(status != 1); 272 273 // GETALL 274 TEST("semctl(GETALL)"); 275 args.array = (unsigned short *)malloc(sizeof(unsigned short) * NUM_OF_SEMS); 276 status = semctl(semID, 0, GETALL, args); 277 assert_posix_bool_success(status != -1); 278 TEST("semctl(GETALL) - semaphore #10"); 279 assert_equals(args.array[NUM_OF_SEMS - 1], (unsigned short)5); 280 TEST("semctl(GETALL) - semaphore #2"); 281 assert_equals(args.array[NUM_OF_SEMS - 1], (unsigned short)5); 282 free(args.array); 283 284 // IPC_SET 285 TEST("semctl(IPC_SET)"); 286 struct semid_ds semaphore; 287 memset(&semaphore, 0, sizeof(struct semid_ds)); 288 semaphore.sem_perm.uid = getuid() + 3; 289 semaphore.sem_perm.gid = getgid() + 3; 290 semaphore.sem_perm.mode = 0666; 291 args.buf = &semaphore; 292 status = semctl(semID, 0, IPC_SET, args); 293 assert_posix_bool_success(status != 1); 294 295 // IPC_STAT set 296 TEST("semctl(IPC_STAT)"); 297 memset(&semaphore, 0, sizeof(struct semid_ds)); 298 args.buf = &semaphore; 299 status = semctl(semID, 0, IPC_STAT, args); 300 assert_posix_bool_success(status != 1); 301 TEST("semctl(IPC_STAT): number of sems"); 302 assert_equals((unsigned short)args.buf->sem_nsems, (unsigned short)NUM_OF_SEMS); 303 TEST("semctl(IPC_STAT): uid"); 304 assert_equals(args.buf->sem_perm.uid, getuid() + 3); 305 TEST("semctl(IPC_STAT): gid"); 306 assert_equals(args.buf->sem_perm.gid, getgid() + 3); 307 308 // Destroy non-private semaphore 309 TEST("semctl(IPC_RMID)"); 310 status = remove_semaphore(semID); 311 assert_posix_bool_success(status != 1); 312 313 TEST("done"); 314 } 315 316 317 int 318 main() 319 { 320 test_semget(); 321 test_semctl(); 322 test_semop(); 323 324 printf("\nAll tests OK\n"); 325 } 326