sema.c 3.49 KB

/*
 *
 * Simple semaphore interface code, lifted from Stevens' Networking
 * book, pp. 146-148.
 *
 * Tue Feb  7 13:21:38 PST 1995
 *
 */

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <errno.h>
extern int	errno;

#include <PR/rsp_ipc.h>

extern void     exit(int);

#define BIGCOUNT	10000

/*
 * define the semaphore operation arrays.
 *
 */

static struct sembuf op_lock[2] = {
    2, 0, 0,
    2, 1, SEM_UNDO
};

static struct sembuf op_endcreate[2] = {
    1, -1, SEM_UNDO,
    2, -1, SEM_UNDO
};

static struct sembuf op_open[1] = {
    1, -1, SEM_UNDO
};

static struct sembuf op_close[3] = {
    2, 0, 0,
    2, 1, SEM_UNDO,
    1, 1, SEM_UNDO
};

static struct sembuf op_unlock[1] = {
    2, -1, SEM_UNDO
};

static struct sembuf op_op[1] = {
    0, 99, SEM_UNDO
};

/*
 * Create a semaphore with a specified value.
 * Return semaphore ID or -1 on error.
 */

int
sem_create(key_t key, int initval)
{
    int		id, semval;
    union semun {
	int	val;
	struct semid_ds *buf;
	ushort	*array;
    } semctl_arg;

    if (key == IPC_PRIVATE)
	return (-1);	/* not for private case */

  again:

    if ((id = semget(key, 3, 0666 | IPC_CREAT)) < 0)
	return(-1);

    if (semop(id, &op_lock[0], 2) < 0) {
	if (errno == EINVAL)
	    goto again;
	fprintf(stderr,"sem_create: can't lock\n");
	exit(-1);
    }

    if ((semval = semctl(id, 1, GETVAL, 0)) < 0) {
	fprintf(stderr,"sem_create: can't GETVAL\n");
	exit(-1);
    }

    if (semval == 0) {
	semctl_arg.val = initval;
	if (semctl(id, 0, SETVAL, semctl_arg) < 0) {
	    fprintf(stderr,"sem_create: can't SETVAL[0]\n");
	    exit(-1);
	}

	semctl_arg.val = BIGCOUNT;
	if (semctl(id, 1, SETVAL, semctl_arg) < 0) {
	    fprintf(stderr,"sem_create: can't SETVAL[1]\n");
	    exit(-1);
	}

    }

    if (semop(id, &op_endcreate[0], 2) < 0) {
	fprintf(stderr,"sem_create: can't end create\n");
	exit(-1);
    }

    return(id);
}


/*
 * open a semaphore that must already exist.
 */
int
sem_open(key_t key)
{
    int		id;

    if (key == IPC_PRIVATE)
	return(-1);

    if ((id = semget(key, 3, 0)) < 0) {
	return(-1);
    }

    if (semop(id, &op_open[0], 1) < 0) {
	fprintf(stderr,"sem_open: can't open\n");
	exit(-1);
    }

    return(id);
}

/*
 * remove a semaphore.
 */

int
sem_rm(int id)
{
    if (semctl(id, 0, IPC_RMID, 0) < 0) {
/*
	fprintf(stderr,"sem_rm: can't IPC_RMID (%d)\n",errno);
	exit(-1);
*/
    }
}

/*
 * close a semaphore.
 *
 */

int
sem_close(int id)
{
    int		semval;

    if (semop(id, &op_close[0], 3) < 0) {
	fprintf(stderr,"sem_close: can't semop\n");
/*
	exit(-1);
*/
    }

    if ((semval = semctl(id, 1, GETVAL, 0)) < 0) {
	fprintf(stderr,"sem_close: can't GETVAL\n");	
/*
	exit(-1);
*/
    }

    if (semval > BIGCOUNT) {
	fprintf(stderr,"sem_close: sem[1] > BIGCOUNT\n");
/*
	exit(-1);
*/
    } else if (semval == BIGCOUNT) {
	sem_rm(id);
    } else {
	if (semop(id, &op_unlock[0], 1) < 0) {
	    fprintf(stderr,"sem_close: can't unlock.\n");
/*
	    exit(-1);
*/
	}
    }
}


/*
 * wait till a semaphore's value is greater than 0, then decrement.
 *
 * A "P" operation.
 *
 */
int
sem_wait(int id)
{
    sem_op(id, -1);
}

/*
 * increment a semaphore by 1.
 *
 * A "V" operation.
 *
 */
int
sem_signal(int id)
{
    sem_op(id, 1);
}

/*
 * general semaphore op.
 *
 */
int
sem_op(int id, int value)
{
    if ((op_op[0].sem_op = value) == 0) {
	fprintf(stderr,"sem_op: can't have value of 0.\n");
/*
	exit(-1);
*/
    }

    if (semop(id, &op_op[0], 1) < 0) {
	fprintf(stderr,"sem_op: sem_op error. (%d)\n",errno);
/*
	exit(-1);
*/
    }
}