File:  [MW Coherent from dump] / coherent / b / kernel / io.386 / sem.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Wed May 29 04:56:37 2019 UTC (7 years ago) by root
Branches: MarkWilliams, MAIN
CVS tags: relic, HEAD
coherent

/*
 * System V Compatible Semaphores
 *
 *	This module provides System V compatible semaphore operations.
 *
 *	Author: Allan Cornish.
 */

#include <sys/coherent.h>
#include <sys/sched.h>
#include <sys/types.h>
#include <sys/uproc.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/con.h>
#include <sys/sem.h>

#ifndef	EIDRM
#define	EIDRM	EDOM
#endif

/*
 *	Semaphore Information
 */

#define	NSEMVAL	32767

static
struct semid_ds *semids = 0;

unsigned NSEMID = 16;
unsigned NSEM   = 16;
		    

/*
 * Semaphore Initialization.
 *
 *	Initialize semaphore ids.
 */

seminit()
{
	register struct semid_ds *semidp;

	if (semids = kalloc(NSEMID * sizeof(struct semid_ds))) {
		for (semidp = &semids[NSEMID]; --semidp >= semids;)
			semidp->sem_perm.mode = 0;
	} else {
		printf("could not allocate %u semaphore ids\n", NSEMID);
		NSEMID = 0;
	}
}

/*
 * Semctl - Semaphore Control Operations.
 */
usemctl(semid, semnum, cmd, arg)
int semid, cmd;
int semnum;
union semun {
	int val;
	struct semid_ds *buf;
	unsigned short *array;
	} arg;
{
	register struct semid_ds *semidp;
	register struct sem *semp;
	int nsems, val;

/*	printf("usemctl() called: semid = %ld semnum = %ld  cmd = %d arg = %d",
 *		semid, semnum, cmd, arg);
 */
	if (u.u_error)
		return -1;

	if (semid >= NSEMID) {
		u.u_error = EINVAL;
		return -1;
	}

	semidp = &semids[semid];
	if ((semidp->sem_perm.mode & IPC_ALLOC) == 0) {
		u.u_error = EINVAL;
		return -1;
	}

	if ((ipcaccess(&semidp->sem_perm) & SEM_R) == 0) { /* can't read */
		u.u_error = EACCES;
		return -1;
	}

	if (semnum >= semidp->sem_nsems) {
		u.u_error = EFBIG;
		return -1;
	}

	semp = &semidp->sem_base[semnum];

	switch (cmd) {
	case GETVAL:		/* Return value of semval */
		return semp->semval;
	case SETVAL:						/* Set semval */
		if ((ipcaccess(&semidp->sem_perm) & SEM_A) == 0) {
			u.u_error = EACCES;	/* can't alter */
			return -1;
		}
		if (arg.val < 0) {			/* illegal value */
			u.u_error = ERANGE;
			return -1;
		}
		if (semp->semval = arg.val) {

			if (semp->semncnt)
				wakeup(&semp->semncnt);
		} else {
			if (semp->semzcnt)
				wakeup(&semp->semzcnt);
		}
		return 0;
	case GETPID:		/* Return value of sempid */
		return semp->sempid;
	case GETNCNT:		/* Return value of semncnt */
		return semp->semncnt;
	case GETZCNT:		/* Return value of semzcnt */
		return semp->semzcnt;
	case GETALL:		/* Return semvals array */
		nsems = semidp->sem_nsems;
		semp  = semidp->sem_base;
		while (--nsems >= 0) {
			putuwd((arg.array)++, (semp++)->semval);
			if (u.u_error)
				return -1;
		}
		return 0;
	case SETALL:		/* Set semvals array */
		if ((ipcaccess(&semidp->sem_perm) & SEM_A) == 0) {
			u.u_error = EACCES;
			return -1;
		}
		nsems = semidp->sem_nsems;
		semp  = semidp->sem_base;
		while (--nsems >= 0) {
			if ((val = getuwd(arg.array)) < 0) {
				if (u.u_error == 0)
					u.u_error = ERANGE;
			} else
				semp->semval = val;
			arg.array++;
			semp++;
		}
		if (u.u_error)
			return -1;
		return 0;
	case IPC_STAT:
		kucopy(semidp, arg.buf, sizeof(struct semid_ds));
		return 0;
	case IPC_SET:
		if ((u.u_uid != 0) && (u.u_uid != semidp->sem_perm.uid)) {
			u.u_error = EPERM;
			return -1;
		}
		semidp->sem_perm.uid   = getuwd(&((arg.buf)->sem_perm.uid));
		semidp->sem_perm.gid   = getuwd(&((arg.buf)->sem_perm.gid));
		semidp->sem_perm.mode  =
			(getuwd(&((arg.buf)->sem_perm.mode))&0777) | IPC_ALLOC;
		return 0;
	case IPC_RMID:
		if ((u.u_uid != 0) && (u.u_uid != semidp->sem_perm.uid)) {
			u.u_error = EPERM;
			return -1;
		}
		semidp->sem_perm.seq++;
		semp = &semidp->sem_base[ semidp->sem_nsems ];

		while (--semp >= semidp->sem_base) {
			if (semp->semncnt)
				wakeup(&semp->semncnt);
			if (semp->semzcnt)
				wakeup(&semp->semzcnt);
		}
		kfree(semidp->sem_base);
		semidp->sem_perm.mode = 0;
		return 0;
	default:
		u.u_error = EINVAL;
		return -1;
	}
}

/*
 * Semget - Get set of semaphores
 */

usemget(skey, nsems, semflg)
key_t skey;
int nsems, semflg;
{
	register struct semid_ds *semidp;
	register struct sem *semp;
	struct semid_ds *freeidp = 0;

/*	printf("usemget called: skey= %x (%d) nsems= %x (%u) semflg= %x (%d)\n",
 *		skey, skey, nsems, nsems, semflg, semflg);
 *
 *	printf("NSEM is %x (%d)\n", NSEM, NSEM);
 */
	if (u.u_error)
		return -1;

	if (nsems >= NSEM) {
/*		printf("usemget(): nsems> NSEM\n");  */
		u.u_error = EINVAL;
		return -1;
	}

	for (semidp = &semids[NSEMID]; --semidp >= semids;) {
		if ((semidp->sem_perm.mode & IPC_ALLOC) == 0) {
			if ((freeidp == 0) ||
			    (freeidp->sem_ctime > semidp->sem_ctime))
				freeidp = semidp;
			continue;
		}

#ifdef	IPC_PRIVATE
		if (skey == IPC_PRIVATE)
			continue;
#endif

		if (skey == semidp->sem_perm.key) {		/* found! */
			if ((semflg & IPC_CREAT) && (semflg & IPC_EXCL)) {
				u.u_error = EEXIST;
				return -1;
			}
			if ((semidp->sem_perm.mode & semflg) != (semflg&0777)) {
				u.u_error = EACCES;
				return -1;
			}
			if (semidp->sem_nsems < nsems) {
				u.u_error = EINVAL;
				return -1;
			}
			return semidp - semids;
		}
	}

	if (!(semflg & IPC_CREAT)) {
		u.u_error = ENOENT;
		return -1;
	}

	if (freeidp == 0) {
		u.u_error = ENOSPC;
		return -1;
	}

	semidp = freeidp;
	semidp->sem_base = kalloc(nsems * sizeof(struct sem));
	if (semidp->sem_base == 0) {
		u.u_error = ENOSPC;
		return -1;
	}
	semidp->sem_nsems = nsems;
	semidp->sem_otime = 0;
	semidp->sem_ctime = timer.t_time;

	for (semp = &semidp->sem_base[nsems]; --semp >= semidp->sem_base;)
		semp->semval = semp->sempid = semp->semncnt = semp->semzcnt = 0;

	semidp->sem_perm.cuid = semidp->sem_perm.uid = u.u_uid;
	semidp->sem_perm.cgid = semidp->sem_perm.gid = u.u_gid;
	semidp->sem_perm.mode = (semflg & 0777) | IPC_ALLOC;
	semidp->sem_perm.key  = skey;

	return semidp - semids;
}

/*
 * Semop - Semaphore Operations.
 */

usemop(semid, sops, nsops)
int semid;
struct sembuf *sops;
unsigned nsops;
{
	register struct semid_ds *semidp;
	register struct sem *semp;
	struct sembuf *sp;
	unsigned short n, semnum, semflg;
	short semop, oval;

	if (u.u_error)
		return -1;

	if (semid >= NSEMID) {
		u.u_error = EINVAL;
		return -1;
	}

	if (nsops >= NSEM) {
		u.u_error = E2BIG;
		return -1;
	}

	semidp = &semids[semid];

	if ((semidp->sem_perm.mode & IPC_ALLOC) == 0) {
		u.u_error = EINVAL;
		return -1;
	}

	if ((ipcaccess(&semidp->sem_perm) & SEM_A) == 0) {
		u.u_error = EACCES;
		return -1;
	}

	sp = sops;
	n  = nsops;

	while (n > 0) {				/* do semaphore ops  */
		semnum = getuwd(& (sp->sem_num));
		semop  = getuwd(& (sp->sem_op));
		semflg = getuwd(& (sp->sem_flg));

		if ((u.u_error != 0) || (semnum >= semidp->sem_nsems)) {
			while (--sp >= sops) {	/* undo prev semops  */
				semnum = getuwd(&sp->sem_num);
				semop  = getuwd(&sp->sem_op );
				semp   = &semidp->sem_base[ semnum ];
				semundo(semp, semop);
			}
			if (u.u_error == 0)
				u.u_error = EFBIG;
			return -1;
		}

		semp = &semidp->sem_base[semnum];

		if ((oval = semdo(semp, semop)) < 0) { /* can't do semop */
			while (--sp >= sops) {	/* undo prev semops  */
				unsigned unnum = getuwd(&sp->sem_num);
				int	 unop  = getuwd(&sp->sem_op );
				semundo(&semidp->sem_base[ unnum ], unop);
			}

			if (u.u_error)
				return -1;

			if (semflg & IPC_NOWAIT) {
				u.u_error = EAGAIN;
				return -1;
			}

			if (semop < 0) {	/* wait for non-zero */
				if (semwait(semidp, &semp->semncnt) < 0)
					return -1;
			} else {			/* wait for zero */

				if (semwait(semidp, &semp->semzcnt) < 0)
					return -1;
			}

			sp = sops;	/* retry set of semaphore operations */
			n = nsops;
			continue;
		}

		++sp;
		--n;
	}

	for (sp=sops,n=nsops; n > 0; --n,++sp) {/* save pid in each semaphore */
		semnum = getuwd(&sp->sem_num);
		semidp->sem_base[ semnum ].sempid = SELF->p_pid;
	}

	semidp->sem_otime = timer.t_time;	/* ajust operation time */
	return oval;				/* return last prev semval */
}

/*
 * Do a Semaphore Operation.
 *
 *	Input:	semp  = pointer to semaphore
 *		semop = semaphore operation
 *
 *	Action:	If semop < 0 and semval > semop then add semop to semval.
 *		If semop > 0 then add semop to semval.
 *
 *	Return:	Previous semval.
 */
static
semdo(semp, semop)
register struct sem * semp;
register int semop;
{
	int ret;

	ret = semp->semval;

	if (semop < 0) {			/* want to decrement semval */
		semop = -semop;

		if (semp->semval < semop)	/* can't decrement semval */
			return -1;

		semp->semval -= semop;

		if ((semp->semval == 0)  && (semp->semzcnt != 0))
			wakeup(&semp->semzcnt);
	} else if (semop > 0) {			/* want to increment semval */
		if ((semp->semval + semop) > NSEMVAL) {
			u.u_error = ERANGE;
			return -1;
		}

		semp->semval += semop;

		if (semp->semncnt)
			wakeup(&semp->semncnt);
	} else /* if (semop == 0) */ {
		if (semp->semval != 0)
			return -1;
	}
	return ret;
}

/*
 * Undo a Semaphore Operation.
 */
static
semundo(semp, semop)
register struct sem * semp;
register int semop;
{
	if (semp->semval -= semop) {
		if (semp->semncnt)
			wakeup(&semp->semncnt);
	} else {
		if (semp->semzcnt)
			wakeup(&semp->semzcnt);
	}
}

/*
 * Wait on Semaphore Event
 *
 *	Input:	semidp = pointer to semaphore id structure.
 *		ep     = pointer to semncnt or semzcnt event to wait for.
 *
 *	Action:	Sleep on a semaphore event.
 *		If semaphore id has been deleted, error return.
 *		If signal has been received, error return.
 *
 *	Output:	 0 = Status ok.
 *		-1 = Error occurred, errno is set.
 */

static
semwait(semidp, ep)
register struct semid_ds * semidp;
register unsigned short *ep;
{
	unsigned seqn;

	seqn = semidp->sem_perm.seq;
	++(*ep);
#ifdef _I386
	x_sleep(ep, pritty, slpriSigCatch, "semwait");
#else
	v_sleep(ep, CVTTOUT, IVTTOUT, SVTTOUT, "semwait");
#endif

	if (semidp->sem_perm.seq != seqn) {	/* semaphore id gone */
		u.u_error = EIDRM;
		return -1;
	}

	--(*ep);

	if (SELF->p_ssig && nondsig()) {	/* signal received */
		u.u_error = EINTR;
		return -1;
	}
	return 0;
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.