/* * Description: Provides a simpler and safer interface to the UNIX * System V Release 4 semaphores. Seven functions are * provided. * * 1. id = SemCreate(key, value); * 2. id = SemOpen(key); * 3. SemWait(id); * 4. SemSignal(id); * 5. SemOp(id, amount); * 6. SemClose(id); * 7. SemRm(id); * * Portability Issues: This implementation requires System V semaphore * facility. * * Edit History: * * */ #ifndef lint static char *sccs_id="$Id: semaphore.c,v 7.2 2001/03/26 10:54:28 asealy Exp $"; #endif #include #include #include #include #include #include #include extern int errno; #define SEM_ #include #include #include #include #include #include /* General UNIX messages */ #include /* General UNIX messages */ #define BIGCOUNT 10000 /* Initial value of process counter */ #if !SEMUN_DEFINED union semun { int val; struct semid_ds *buf; ushort *array; } semctl_arg; #else union semun semctl_arg; #endif typedef struct sembuf SEMBUF; /* Prototypes for local functions */ /* * Define the semaphore operation arrays for the semop() calls. */ static SEMBUF op_lock[2] = { 2, 0, 0, /* wait for [2] (lock) to equal 0 */ 2, 1, SEM_UNDO /* then incrrement [2] to 1 - this locks it */ /* UNDO to release the lock it process exits before explicitly unblocking */ }; static SEMBUF op_endcreate[2] = { 1, -1, SEM_UNDO, 2, -1, SEM_UNDO }; static SEMBUF op_open[1] = { 1, -1, SEM_UNDO }; static SEMBUF op_close[3] = { 2, 0, 0, 2, 1, SEM_UNDO, 1, 1, SEM_UNDO }; static SEMBUF op_unlock[1] = { 2, -1, SEM_UNDO }; static SEMBUF op_op[1] = { 0, 99, SEM_UNDO }; /************************************************************************ * Name: SemCreate * * Function: * * Input: key - the IPC key that identifies the semaphore. * initval - initial value of the semaphore. * * Output *id - the identifier of this semaphore. * * Return: SUCCESS or FAIL * * Side Effects: none * * Procedure: 1. * 2. * 3. ************************************************************************/ STATUS SemCreate(int *id, key_t key, int initval) { printf(" \n in semcretae"); printf("\n SEMUN_DEFINED = %i " , SEMUN_DEFINED); register int semval; printf(" \n After Register = %i ", semval); if (key EQ IPC_PRIVATE) { printf(" \n SEM, Not intended for private semaphores"); goto ErrExit; } else if (key EQ (key_t) -1) { printf("\nSEM, probably an ftok() error by caller"); goto ErrExit; } again: if ( (*id = semget(key, 3, 0666 | IPC_CREAT)) < 0) { printf("\nSEM, SemCreate, semget access/limits errno %d", errno); goto ErrExit; } if (semop(*id, &op_lock[0], 2) < 0) { if (errno EQ EINVAL) goto again; printf("\nSEM, Can't lock...: errno = %d", errno); goto ErrExit; } /* * Get the value of the process counter. If it equals zero * then no one has initialised the semaphore yet. */ semctl_arg.val = 0; if ( (semval = semctl(*id, 1, GETVAL, semctl_arg)) < 0) { printf("\n SEM, can't GETVAL..: errno = %d", errno); goto ErrExit; } if (semval EQ 0) { /* We could initialise by doing a SETALL, but that * would clear the adjust value. */ semctl_arg.val = initval; if (semctl(*id, 0, SETVAL, semctl_arg) < 0) { printf("\nSEM, can SETVAL[0]..: errno = %d", errno); goto ErrExit; } semctl_arg.val = BIGCOUNT; if (semctl(*id, 1, SETVAL, semctl_arg) < 0) { printf("\nSEM, can SETVAL[1]..: errno = %d", errno); goto ErrExit; } } /* * Decrement the process counter and then release the lock. */ if (semop(*id, &op_endcreate[0], 2) < 0) { printf("\nSEM", "can't endcreate..: errno = %d", errno); goto ErrExit; } printf("\nSEM", "SemCreate SUCCESS id:%d tok:%x", *id, key); return(SUCCESS); ErrExit: *id = SEM_NULL; printf("\n SEM, SemCreate FAIL id:%d tok:%x", *id, key); return(FAIL); } /************************************************************************ * Name: SemOpen * * Function: * * Input: id - the identifier of this semaphore. * * Output: none. * * Return: SUCCESS or FAIL * * Side Effects: none * * Procedure: 1. * 2. * 3. ************************************************************************/ STATUS SemOpen(int *id, key_t key) { printf("\n SEM", "SemOpen Token/key tok:%x", key); if (key EQ IPC_PRIVATE) { printf("\n SEM, Not intended for private semaphores"); goto ErrExit; } else if (key EQ (key_t) -1) { printf("\n SEM", "probably an ftok() error by caller"); goto ErrExit; } if ( (*id = semget(key, 3, 0)) < 0) { printf("\n SEM, SemOpen, semget prot or tables full:..: errno = %d", errno); goto ErrExit; } /* * Decrement the process counter - we don't need a lock. */ if (semop(*id, &op_open[0], 1) < 0) { printf("\n SEM, can't open..: errno = %d", errno); goto ErrExit; } printf("\n SEM, SemOpen SUCCESS id:%d tok:%x", *id, key); return(SUCCESS); ErrExit: *id = SEM_NULL; printf("\n SEM, SemOpen FAIL id:%d tok:%x", *id, key); return(FAIL); } /************************************************************************ * Name: SemRm * * Function: * * Input: id - the identifier of this semaphore. * * Output: none. * * Return: SUCCESS or FAIL * * Side Effects: none * * Procedure: 1. * 2. * 3. ************************************************************************/ STATUS SemRm(int id) { printf("\n SEM", "SemRm( id:%d)",id); semctl_arg.val = 0; if (semctl(id, 0, IPC_RMID, semctl_arg) < 0) { printf("\n SEM", "can't IPC_RMID..: errno = %d", errno); goto ErrExit; } printf("\n SemRm Error"); return(SUCCESS); ErrExit: printf("\n SemRm Error"); return(FAIL); } /************************************************************************ * Name: SemClose * * Function: * * Input: id - the identifier of this semaphore. * * Output: none. * * Return: SUCCESS or FAIL * * Side Effects: none * * Procedure: 1. * 2. * 3. ************************************************************************/ STATUS SemClose(int id) { register int semval; /* the followung semop() first gets a lock on the semaphore, * then increments [1] - the process conuter. */ printf(" \n SEM, SemClose( id:%d)",id); if (semop(id, &op_close[0], 3) < 0) { printf("\n SEM, SemClose can't sem_op..: errno = %d", errno); goto ErrExit; } /* * Now that we have a lock, read the value of the process * counter to see if this is the last reference to the * semaphore. * There is a race condition here - see the comment in * SemCreate(). */ semctl_arg.val = 0; if ( (semval = semctl(id, 1, GETVAL, semctl_arg)) < 0) { printf("\n SEM, SemClose can't GETVAL..: errno = %d", errno); goto ErrExit; } if (semval > BIGCOUNT) { printf("\nSEM, sem[1] > BIGCOUNT"); goto ErrExit; } else if (semval EQ BIGCOUNT) { if ( SemRm(id) EQ FAIL) goto ErrExit; } else if (semop(id, &op_unlock[0], 1) < 0) { printf("\nSEM, can't unlock..: errno = %d", errno); goto ErrExit; } printf("\n SemClose Error"); return(SUCCESS); ErrExit: printf("\n SemClose Error FAIL id:%d",id); return(FAIL); } /************************************************************************ * Name: SemWait * * Function: * * Input: id - the identifier of this semaphore. * * Output: none. * * Return: SUCCESS or FAIL * * Side Effects: none * * Procedure: 1. * 2. * 3. ************************************************************************/ STATUS SemWait(int id) { if (SemOp(id, -1) EQ FAIL) goto ErrExit; printf("\n SemWait Error"); return(SUCCESS); ErrExit: printf("\n SemWait Error"); return(FAIL); } /************************************************************************ * Name: SemSignal * * Function: * * Input: id - the identifier of this semaphore. * * Output: none. * * Return: SUCCESS or FAIL * * Side Effects: none * * Procedure: 1. * 2. * 3. ************************************************************************/ STATUS SemSignal(int id) { if ( SemOp(id, 1) EQ FAIL) goto ErrExit; printf("\n SemSignal Error"); return(SUCCESS); ErrExit: printf("\n SemSignal Error"); return(FAIL); } /************************************************************************ * Name: SemOp * * Function: * * Input: id - the identifier of this semaphore. * * Output: none. * * Return: SUCCESS or FAIL * * Side Effects: none * * Procedure: 1. * 2. * 3. ************************************************************************/ STATUS SemOp(int id, int value) { if ( (op_op[0].sem_op = value) EQ 0) { printf("\n SEM, can't have value EQ 0"); goto ErrExit; } if (semop(id, &op_op[0], 1) < 0) { printf("\n SEM, semop error..: errno = %d", errno); goto ErrExit; } printf("\n SemOp Success"); return(SUCCESS); ErrExit: printf("\n SemOp Error"); return(FAIL); } /* End of file: semaphore.c */