#include "pcsem.h" int pcsem::init(key_t key, unsigned int value) { int semid, perms; perms = S_IRUSR | S_IWUSR; semid = semget(key, 1, IPC_CREAT | IPC_EXCL | perms); if (semid != -1) { /* Successfully created the semaphore */ union semun arg; struct sembuf sop; fprintf(stderr, "%ld: created semaphore\n", (long) getpid()); arg.val = 0; /* So initialize it to 0 */ if (semctl(semid, 0, SETVAL, arg) == -1) err_exit(errno, "semctl 1"); fprintf(stderr, "%ld: initialized semaphore\n", (long) getpid()); /* Perform a "no-op" semaphore operation - changes sem_otime so other processes can see we've initialized the set. */ sop.sem_num = 0; /* Operate on semaphore 0 */ sop.sem_op = value; sop.sem_flg = 0; if (semop(semid, &sop, 1) == -1) err_exit(errno, "semop"); fprintf(stderr, "%ld: completed dummy semop()\n", (long) getpid()); } else { /* We didn't create the semaphore set */ if (errno != EEXIST) { /* Unexpected error from semget() */ err_exit(errno, "semget 1"); } else { /* Someone else already created it */ const int MAX_TRIES = 10; int j; union semun arg; struct semid_ds ds; semid = semget(key, 1, perms); /* So just get ID */ if (semid == -1) err_exit(errno, "semget 2"); fprintf(stderr, "%ld: got semaphore key\n", (long) getpid()); /* Wait until another process has called semop() */ arg.buf = &ds; for (j = 0; j < MAX_TRIES; j++) { fprintf(stderr, "Try %d\n", j); if (semctl(semid, 0, IPC_STAT, arg) == -1) err_exit(errno, "semctl 2"); if (ds.sem_otime != 0) /* Semop() performed? */ break; /* Yes, quit loop */ sleep(1); /* If not, wait and retry */ } if (ds.sem_otime == 0) /* Loop ran to completion! */ err_exit(errno, "Existing semaphore not initialized"); } } return semid; } /* Reserve semaphore (blocking), return 0 on success, or -1 with 'errno' set to EINTR if operation was interrupted by a signal handler */ /* Reserve semaphore - decrement it by 1 */ int pcsem::dec(int semId) { struct sembuf sops; sops.sem_num = 0; sops.sem_op = -1; sops.sem_flg = 0; while (semop(semId, &sops, 1) == -1) if (errno != EINTR ) return -1; return 0; } int pcsem::dec_nowait(int semId) { struct sembuf sops; sops.sem_num = 0; sops.sem_op = -1; sops.sem_flg = IPC_NOWAIT; while (semop(semId, &sops, 1) == -1) if (errno != EINTR ) return -1; return 0; } int pcsem::dec_timeout(int semId, struct timespec * timeout) { struct sembuf sops; sops.sem_num = 0; sops.sem_op = -1; sops.sem_flg = 0; while ( semtimedop(semId, &sops, 1, timeout) == -1) if (errno != EINTR ) return -1; return 0; } /* Release semaphore - increment it by 1 */ int pcsem::inc(int semId) { struct sembuf sops; sops.sem_num = 0; sops.sem_op = 1; sops.sem_flg = 0; return semop(semId, &sops, 1); } void pcsem::remove(int semid) { union semun dummy; if (semctl(semid, 0, IPC_RMID, dummy) == -1) err_exit(errno, "semctl"); }