sysv_sem.c revision 88633
150477Speter/* $FreeBSD: head/sys/kern/sysv_sem.c 88633 2001-12-29 07:13:47Z alfred $ */
22729Sdfr
32729Sdfr/*
42729Sdfr * Implementation of SVID semaphores
52729Sdfr *
62729Sdfr * Author:  Daniel Boulet
72729Sdfr *
82729Sdfr * This software is provided ``AS IS'' without any warranties of any kind.
92729Sdfr */
102729Sdfr
1159839Speter#include "opt_sysvipc.h"
1259839Speter
132729Sdfr#include <sys/param.h>
142729Sdfr#include <sys/systm.h>
1511626Sbde#include <sys/sysproto.h>
162729Sdfr#include <sys/kernel.h>
172729Sdfr#include <sys/proc.h>
1882607Sdillon#include <sys/lock.h>
1982607Sdillon#include <sys/mutex.h>
202729Sdfr#include <sys/sem.h>
2169449Salfred#include <sys/syscall.h>
2211626Sbde#include <sys/sysent.h>
2359839Speter#include <sys/sysctl.h>
2459839Speter#include <sys/malloc.h>
2568024Srwatson#include <sys/jail.h>
262729Sdfr
2759839Speterstatic MALLOC_DEFINE(M_SEM, "sem", "SVID compatible semaphores");
2859839Speter
2969449Salfredstatic void seminit __P((void));
3069449Salfredstatic int sysvsem_modload __P((struct module *, int, void *));
3169449Salfredstatic int semunload __P((void));
3269449Salfredstatic void semexit_myhook __P((struct proc *p));
3377461Sddstatic int sysctl_sema __P((SYSCTL_HANDLER_ARGS));
3410358Sjulian
3512866Speter#ifndef _SYS_SYSPROTO_H_
3612866Speterstruct __semctl_args;
3783366Sjulianint __semctl __P((struct thread *td, struct __semctl_args *uap));
3811626Sbdestruct semget_args;
3983366Sjulianint semget __P((struct thread *td, struct semget_args *uap));
4011626Sbdestruct semop_args;
4183366Sjulianint semop __P((struct thread *td, struct semop_args *uap));
4212866Speter#endif
4311626Sbde
4483366Sjulianstatic struct sem_undo *semu_alloc __P((struct thread *td));
4583366Sjulianstatic int semundo_adjust __P((struct thread *td, struct sem_undo **supptr,
4612819Sphk		int semid, int semnum, int adjval));
4712819Sphkstatic void semundo_clear __P((int semid, int semnum));
4811626Sbde
4911626Sbde/* XXX casting to (sy_call_t *) is bogus, as usual. */
5012819Sphkstatic sy_call_t *semcalls[] = {
5112866Speter	(sy_call_t *)__semctl, (sy_call_t *)semget,
5259828Speter	(sy_call_t *)semop
5311626Sbde};
5411626Sbde
5512819Sphkstatic int	semtot = 0;
5659839Speterstatic struct semid_ds *sema;	/* semaphore id pool */
5759839Speterstatic struct sem *sem;		/* semaphore pool */
5859839Speterstatic struct sem_undo *semu_list; /* list of active undo structures */
5959839Speterstatic int	*semu;		/* undo structure pool */
602729Sdfr
6159839Speterstruct sem {
6259839Speter	u_short	semval;		/* semaphore value */
6359839Speter	pid_t	sempid;		/* pid of last operation */
6459839Speter	u_short	semncnt;	/* # awaiting semval > cval */
6559839Speter	u_short	semzcnt;	/* # awaiting semval = 0 */
6659839Speter};
6759839Speter
6859839Speter/*
6959839Speter * Undo structure (one per process)
7059839Speter */
7159839Speterstruct sem_undo {
7259839Speter	struct	sem_undo *un_next;	/* ptr to next active undo structure */
7359839Speter	struct	proc *un_proc;		/* owner of this structure */
7459839Speter	short	un_cnt;			/* # of active entries */
7559839Speter	struct undo {
7659839Speter		short	un_adjval;	/* adjust on exit values */
7759839Speter		short	un_num;		/* semaphore # */
7859839Speter		int	un_id;		/* semid */
7959839Speter	} un_ent[1];			/* undo entries */
8059839Speter};
8159839Speter
8259839Speter/*
8359839Speter * Configuration parameters
8459839Speter */
8559839Speter#ifndef SEMMNI
8659839Speter#define SEMMNI	10		/* # of semaphore identifiers */
8759839Speter#endif
8859839Speter#ifndef SEMMNS
8959839Speter#define SEMMNS	60		/* # of semaphores in system */
9059839Speter#endif
9159839Speter#ifndef SEMUME
9259839Speter#define SEMUME	10		/* max # of undo entries per process */
9359839Speter#endif
9459839Speter#ifndef SEMMNU
9559839Speter#define SEMMNU	30		/* # of undo structures in system */
9659839Speter#endif
9759839Speter
9859839Speter/* shouldn't need tuning */
9959839Speter#ifndef SEMMAP
10059839Speter#define SEMMAP	30		/* # of entries in semaphore map */
10159839Speter#endif
10259839Speter#ifndef SEMMSL
10359839Speter#define SEMMSL	SEMMNS		/* max # of semaphores per id */
10459839Speter#endif
10559839Speter#ifndef SEMOPM
10659839Speter#define SEMOPM	100		/* max # of operations per semop call */
10759839Speter#endif
10859839Speter
10959839Speter#define SEMVMX	32767		/* semaphore maximum value */
11059839Speter#define SEMAEM	16384		/* adjust on exit max value */
11159839Speter
11259839Speter/*
11359839Speter * Due to the way semaphore memory is allocated, we have to ensure that
11459839Speter * SEMUSZ is properly aligned.
11559839Speter */
11659839Speter
11759839Speter#define SEM_ALIGN(bytes) (((bytes) + (sizeof(long) - 1)) & ~(sizeof(long) - 1))
11859839Speter
11959839Speter/* actual size of an undo structure */
12059839Speter#define SEMUSZ	SEM_ALIGN(offsetof(struct sem_undo, un_ent[SEMUME]))
12159839Speter
12259839Speter/*
12359839Speter * Macro to find a particular sem_undo vector
12459839Speter */
12559839Speter#define SEMU(ix)	((struct sem_undo *)(((intptr_t)semu)+ix * seminfo.semusz))
12659839Speter
12759839Speter/*
12859839Speter * semaphore info struct
12959839Speter */
13059839Speterstruct seminfo seminfo = {
13159839Speter                SEMMAP,         /* # of entries in semaphore map */
13259839Speter                SEMMNI,         /* # of semaphore identifiers */
13359839Speter                SEMMNS,         /* # of semaphores in system */
13459839Speter                SEMMNU,         /* # of undo structures in system */
13559839Speter                SEMMSL,         /* max # of semaphores per id */
13659839Speter                SEMOPM,         /* max # of operations per semop call */
13759839Speter                SEMUME,         /* max # of undo entries per process */
13859839Speter                SEMUSZ,         /* size in bytes of undo structure */
13959839Speter                SEMVMX,         /* semaphore maximum value */
14059839Speter                SEMAEM          /* adjust on exit max value */
14159839Speter};
14259839Speter
14359839SpeterSYSCTL_DECL(_kern_ipc);
14459839SpeterSYSCTL_INT(_kern_ipc, OID_AUTO, semmap, CTLFLAG_RW, &seminfo.semmap, 0, "");
14559839SpeterSYSCTL_INT(_kern_ipc, OID_AUTO, semmni, CTLFLAG_RD, &seminfo.semmni, 0, "");
14659839SpeterSYSCTL_INT(_kern_ipc, OID_AUTO, semmns, CTLFLAG_RD, &seminfo.semmns, 0, "");
14759839SpeterSYSCTL_INT(_kern_ipc, OID_AUTO, semmnu, CTLFLAG_RD, &seminfo.semmnu, 0, "");
14859839SpeterSYSCTL_INT(_kern_ipc, OID_AUTO, semmsl, CTLFLAG_RW, &seminfo.semmsl, 0, "");
14959839SpeterSYSCTL_INT(_kern_ipc, OID_AUTO, semopm, CTLFLAG_RD, &seminfo.semopm, 0, "");
15059839SpeterSYSCTL_INT(_kern_ipc, OID_AUTO, semume, CTLFLAG_RD, &seminfo.semume, 0, "");
15159839SpeterSYSCTL_INT(_kern_ipc, OID_AUTO, semusz, CTLFLAG_RD, &seminfo.semusz, 0, "");
15259839SpeterSYSCTL_INT(_kern_ipc, OID_AUTO, semvmx, CTLFLAG_RW, &seminfo.semvmx, 0, "");
15359839SpeterSYSCTL_INT(_kern_ipc, OID_AUTO, semaem, CTLFLAG_RW, &seminfo.semaem, 0, "");
15477461SddSYSCTL_PROC(_kern_ipc, OID_AUTO, sema, CTLFLAG_RD,
15577461Sdd    NULL, 0, sysctl_sema, "", "");
15659839Speter
15759839Speter#if 0
15859839SpeterRO seminfo.semmap	/* SEMMAP unused */
15959839SpeterRO seminfo.semmni
16059839SpeterRO seminfo.semmns
16159839SpeterRO seminfo.semmnu	/* undo entries per system */
16259839SpeterRW seminfo.semmsl
16359839SpeterRO seminfo.semopm	/* SEMOPM unused */
16459839SpeterRO seminfo.semume
16559839SpeterRO seminfo.semusz	/* param - derived from SEMUME for per-proc sizeof */
16659839SpeterRO seminfo.semvmx	/* SEMVMX unused - user param */
16759839SpeterRO seminfo.semaem	/* SEMAEM unused - user param */
16859839Speter#endif
16959839Speter
17059839Speterstatic void
17169449Salfredseminit(void)
1722729Sdfr{
1732729Sdfr	register int i;
1742729Sdfr
17583413Smr	TUNABLE_INT_FETCH("kern.ipc.semmap", &seminfo.semmap);
17683413Smr	TUNABLE_INT_FETCH("kern.ipc.semmni", &seminfo.semmni);
17783413Smr	TUNABLE_INT_FETCH("kern.ipc.semmns", &seminfo.semmns);
17883413Smr	TUNABLE_INT_FETCH("kern.ipc.semmnu", &seminfo.semmnu);
17983413Smr	TUNABLE_INT_FETCH("kern.ipc.semmsl", &seminfo.semmsl);
18083413Smr	TUNABLE_INT_FETCH("kern.ipc.semopm", &seminfo.semopm);
18183413Smr	TUNABLE_INT_FETCH("kern.ipc.semume", &seminfo.semume);
18283413Smr	TUNABLE_INT_FETCH("kern.ipc.semusz", &seminfo.semusz);
18383413Smr	TUNABLE_INT_FETCH("kern.ipc.semvmx", &seminfo.semvmx);
18483413Smr	TUNABLE_INT_FETCH("kern.ipc.semaem", &seminfo.semaem);
18583413Smr
18659839Speter	sem = malloc(sizeof(struct sem) * seminfo.semmns, M_SEM, M_WAITOK);
18759839Speter	if (sem == NULL)
18859839Speter		panic("sem is NULL");
18959839Speter	sema = malloc(sizeof(struct semid_ds) * seminfo.semmni, M_SEM, M_WAITOK);
1902729Sdfr	if (sema == NULL)
1912729Sdfr		panic("sema is NULL");
19259839Speter	semu = malloc(seminfo.semmnu * seminfo.semusz, M_SEM, M_WAITOK);
1932729Sdfr	if (semu == NULL)
1942729Sdfr		panic("semu is NULL");
1952729Sdfr
1962729Sdfr	for (i = 0; i < seminfo.semmni; i++) {
1972729Sdfr		sema[i].sem_base = 0;
1982729Sdfr		sema[i].sem_perm.mode = 0;
1992729Sdfr	}
2002729Sdfr	for (i = 0; i < seminfo.semmnu; i++) {
2012729Sdfr		register struct sem_undo *suptr = SEMU(i);
2022729Sdfr		suptr->un_proc = NULL;
2032729Sdfr	}
2042729Sdfr	semu_list = NULL;
20569449Salfred	semexit_hook = &semexit_myhook;
2062729Sdfr}
2072729Sdfr
20869449Salfredstatic int
20969449Salfredsemunload(void)
21069449Salfred{
21169449Salfred
21269449Salfred	if (semtot != 0)
21369449Salfred		return (EBUSY);
21469449Salfred
21569449Salfred	free(sem, M_SEM);
21669449Salfred	free(sema, M_SEM);
21769449Salfred	free(semu, M_SEM);
21869449Salfred	semexit_hook = NULL;
21969449Salfred	return (0);
22069449Salfred}
22169449Salfred
22269449Salfredstatic int
22369449Salfredsysvsem_modload(struct module *module, int cmd, void *arg)
22469449Salfred{
22569449Salfred	int error = 0;
22669449Salfred
22769449Salfred	switch (cmd) {
22869449Salfred	case MOD_LOAD:
22969449Salfred		seminit();
23069449Salfred		break;
23169449Salfred	case MOD_UNLOAD:
23269449Salfred		error = semunload();
23369449Salfred		break;
23469449Salfred	case MOD_SHUTDOWN:
23569449Salfred		break;
23669449Salfred	default:
23769449Salfred		error = EINVAL;
23869449Salfred		break;
23969449Salfred	}
24069449Salfred	return (error);
24169449Salfred}
24269449Salfred
24371038Sdesstatic moduledata_t sysvsem_mod = {
24471038Sdes	"sysvsem",
24569449Salfred	&sysvsem_modload,
24669449Salfred	NULL
24769449Salfred};
24869449Salfred
24988633SalfredSYSCALL_MODULE_HELPER(semsys);
25088633SalfredSYSCALL_MODULE_HELPER(__semctl);
25188633SalfredSYSCALL_MODULE_HELPER(semget);
25288633SalfredSYSCALL_MODULE_HELPER(semop);
25369449Salfred
25471038SdesDECLARE_MODULE(sysvsem, sysvsem_mod,
25569449Salfred	SI_SUB_SYSV_SEM, SI_ORDER_FIRST);
25671038SdesMODULE_VERSION(sysvsem, 1);
25769449Salfred
2582729Sdfr/*
2592729Sdfr * Entry point for all SEM calls
26082607Sdillon *
26182607Sdillon * MPSAFE
2622729Sdfr */
2632729Sdfrint
26483366Sjuliansemsys(td, uap)
26583366Sjulian	struct thread *td;
26611626Sbde	/* XXX actually varargs. */
26711626Sbde	struct semsys_args /* {
26811626Sbde		u_int	which;
26911626Sbde		int	a2;
27011626Sbde		int	a3;
27111626Sbde		int	a4;
27211626Sbde		int	a5;
27311626Sbde	} */ *uap;
2742729Sdfr{
27582607Sdillon	int error;
2762729Sdfr
27782607Sdillon	mtx_lock(&Giant);
27883366Sjulian	if (!jail_sysvipc_allowed && jailed(td->td_proc->p_ucred)) {
27982607Sdillon		error = ENOSYS;
28082607Sdillon		goto done2;
28182607Sdillon	}
28282607Sdillon	if (uap->which >= sizeof(semcalls)/sizeof(semcalls[0])) {
28382607Sdillon		error = EINVAL;
28482607Sdillon		goto done2;
28582607Sdillon	}
28683366Sjulian	error = (*semcalls[uap->which])(td, &uap->a2);
28782607Sdillondone2:
28882607Sdillon	mtx_unlock(&Giant);
28982607Sdillon	return (error);
2902729Sdfr}
2912729Sdfr
2922729Sdfr/*
2932729Sdfr * Allocate a new sem_undo structure for a process
2942729Sdfr * (returns ptr to structure or NULL if no more room)
2952729Sdfr */
2962729Sdfr
29712819Sphkstatic struct sem_undo *
29883366Sjuliansemu_alloc(td)
29983366Sjulian	struct thread *td;
3002729Sdfr{
3012729Sdfr	register int i;
3022729Sdfr	register struct sem_undo *suptr;
3032729Sdfr	register struct sem_undo **supptr;
3042729Sdfr	int attempt;
3052729Sdfr
3062729Sdfr	/*
3072729Sdfr	 * Try twice to allocate something.
3082729Sdfr	 * (we'll purge any empty structures after the first pass so
3092729Sdfr	 * two passes are always enough)
3102729Sdfr	 */
3112729Sdfr
3122729Sdfr	for (attempt = 0; attempt < 2; attempt++) {
3132729Sdfr		/*
3142729Sdfr		 * Look for a free structure.
3152729Sdfr		 * Fill it in and return it if we find one.
3162729Sdfr		 */
3172729Sdfr
3182729Sdfr		for (i = 0; i < seminfo.semmnu; i++) {
3192729Sdfr			suptr = SEMU(i);
3202729Sdfr			if (suptr->un_proc == NULL) {
3212729Sdfr				suptr->un_next = semu_list;
3222729Sdfr				semu_list = suptr;
3232729Sdfr				suptr->un_cnt = 0;
32483366Sjulian				suptr->un_proc = td->td_proc;
3252729Sdfr				return(suptr);
3262729Sdfr			}
3272729Sdfr		}
3282729Sdfr
3292729Sdfr		/*
3302729Sdfr		 * We didn't find a free one, if this is the first attempt
3312729Sdfr		 * then try to free some structures.
3322729Sdfr		 */
3332729Sdfr
3342729Sdfr		if (attempt == 0) {
3352729Sdfr			/* All the structures are in use - try to free some */
3362729Sdfr			int did_something = 0;
3372729Sdfr
3382729Sdfr			supptr = &semu_list;
3392729Sdfr			while ((suptr = *supptr) != NULL) {
3402729Sdfr				if (suptr->un_cnt == 0)  {
3412729Sdfr					suptr->un_proc = NULL;
3422729Sdfr					*supptr = suptr->un_next;
3432729Sdfr					did_something = 1;
3442729Sdfr				} else
3452729Sdfr					supptr = &(suptr->un_next);
3462729Sdfr			}
3472729Sdfr
3482729Sdfr			/* If we didn't free anything then just give-up */
3492729Sdfr			if (!did_something)
3502729Sdfr				return(NULL);
3512729Sdfr		} else {
3522729Sdfr			/*
3532729Sdfr			 * The second pass failed even though we freed
3542729Sdfr			 * something after the first pass!
3552729Sdfr			 * This is IMPOSSIBLE!
3562729Sdfr			 */
3572729Sdfr			panic("semu_alloc - second attempt failed");
3582729Sdfr		}
3592729Sdfr	}
3602836Sdg	return (NULL);
3612729Sdfr}
3622729Sdfr
3632729Sdfr/*
3642729Sdfr * Adjust a particular entry for a particular proc
3652729Sdfr */
3662729Sdfr
36712819Sphkstatic int
36883366Sjuliansemundo_adjust(td, supptr, semid, semnum, adjval)
36983366Sjulian	register struct thread *td;
3702729Sdfr	struct sem_undo **supptr;
3712729Sdfr	int semid, semnum;
3722729Sdfr	int adjval;
3732729Sdfr{
37483366Sjulian	struct proc *p = td->td_proc;
3752729Sdfr	register struct sem_undo *suptr;
3762729Sdfr	register struct undo *sunptr;
3772729Sdfr	int i;
3782729Sdfr
3792729Sdfr	/* Look for and remember the sem_undo if the caller doesn't provide
3802729Sdfr	   it */
3812729Sdfr
3822729Sdfr	suptr = *supptr;
3832729Sdfr	if (suptr == NULL) {
3842729Sdfr		for (suptr = semu_list; suptr != NULL;
3852729Sdfr		    suptr = suptr->un_next) {
3862729Sdfr			if (suptr->un_proc == p) {
3872729Sdfr				*supptr = suptr;
3882729Sdfr				break;
3892729Sdfr			}
3902729Sdfr		}
3912729Sdfr		if (suptr == NULL) {
3922729Sdfr			if (adjval == 0)
3932729Sdfr				return(0);
39483366Sjulian			suptr = semu_alloc(td);
3952729Sdfr			if (suptr == NULL)
3962729Sdfr				return(ENOSPC);
3972729Sdfr			*supptr = suptr;
3982729Sdfr		}
3992729Sdfr	}
4002729Sdfr
4012729Sdfr	/*
4022729Sdfr	 * Look for the requested entry and adjust it (delete if adjval becomes
4032729Sdfr	 * 0).
4042729Sdfr	 */
4052729Sdfr	sunptr = &suptr->un_ent[0];
4062729Sdfr	for (i = 0; i < suptr->un_cnt; i++, sunptr++) {
4072729Sdfr		if (sunptr->un_id != semid || sunptr->un_num != semnum)
4082729Sdfr			continue;
40984789Smr		if (adjval != 0) {
41084789Smr			adjval += sunptr->un_adjval;
41184789Smr			if (adjval > seminfo.semaem || adjval < -seminfo.semaem)
41284789Smr				return (ERANGE);
41384789Smr		}
41484789Smr		sunptr->un_adjval = adjval;
4152729Sdfr		if (sunptr->un_adjval == 0) {
4162729Sdfr			suptr->un_cnt--;
4172729Sdfr			if (i < suptr->un_cnt)
4182729Sdfr				suptr->un_ent[i] =
4192729Sdfr				    suptr->un_ent[suptr->un_cnt];
4202729Sdfr		}
4212729Sdfr		return(0);
4222729Sdfr	}
4232729Sdfr
4242729Sdfr	/* Didn't find the right entry - create it */
4252729Sdfr	if (adjval == 0)
4262729Sdfr		return(0);
42784789Smr	if (adjval > seminfo.semaem || adjval < -seminfo.semaem)
42884789Smr		return (ERANGE);
42941774Sdillon	if (suptr->un_cnt != seminfo.semume) {
4302729Sdfr		sunptr = &suptr->un_ent[suptr->un_cnt];
4312729Sdfr		suptr->un_cnt++;
4322729Sdfr		sunptr->un_adjval = adjval;
4332729Sdfr		sunptr->un_id = semid; sunptr->un_num = semnum;
4342729Sdfr	} else
4352729Sdfr		return(EINVAL);
4362729Sdfr	return(0);
4372729Sdfr}
4382729Sdfr
43912819Sphkstatic void
4402729Sdfrsemundo_clear(semid, semnum)
4412729Sdfr	int semid, semnum;
4422729Sdfr{
4432729Sdfr	register struct sem_undo *suptr;
4442729Sdfr
4452729Sdfr	for (suptr = semu_list; suptr != NULL; suptr = suptr->un_next) {
4462729Sdfr		register struct undo *sunptr = &suptr->un_ent[0];
4472729Sdfr		register int i = 0;
4482729Sdfr
4492729Sdfr		while (i < suptr->un_cnt) {
4502729Sdfr			if (sunptr->un_id == semid) {
4512729Sdfr				if (semnum == -1 || sunptr->un_num == semnum) {
4522729Sdfr					suptr->un_cnt--;
4532729Sdfr					if (i < suptr->un_cnt) {
4542729Sdfr						suptr->un_ent[i] =
4552729Sdfr						  suptr->un_ent[suptr->un_cnt];
4562729Sdfr						continue;
4572729Sdfr					}
4582729Sdfr				}
4592729Sdfr				if (semnum != -1)
4602729Sdfr					break;
4612729Sdfr			}
4622729Sdfr			i++, sunptr++;
4632729Sdfr		}
4642729Sdfr	}
4652729Sdfr}
4662729Sdfr
46712866Speter/*
46812866Speter * Note that the user-mode half of this passes a union, not a pointer
46912866Speter */
47012866Speter#ifndef _SYS_SYSPROTO_H_
47112866Speterstruct __semctl_args {
4722729Sdfr	int	semid;
4732729Sdfr	int	semnum;
4742729Sdfr	int	cmd;
4752729Sdfr	union	semun *arg;
4762729Sdfr};
47712866Speter#endif
4782729Sdfr
47982607Sdillon/*
48082607Sdillon * MPSAFE
48182607Sdillon */
48212866Speterint
48383366Sjulian__semctl(td, uap)
48483366Sjulian	struct thread *td;
48512866Speter	register struct __semctl_args *uap;
4862729Sdfr{
4872729Sdfr	int semid = uap->semid;
4882729Sdfr	int semnum = uap->semnum;
4892729Sdfr	int cmd = uap->cmd;
4902729Sdfr	union semun *arg = uap->arg;
4912729Sdfr	union semun real_arg;
49283366Sjulian	struct ucred *cred = td->td_proc->p_ucred;
49382607Sdillon	int i, rval, error;
4942729Sdfr	struct semid_ds sbuf;
4952729Sdfr	register struct semid_ds *semaptr;
49684789Smr	u_short usval;
4972729Sdfr
4982729Sdfr#ifdef SEM_DEBUG
4992729Sdfr	printf("call to semctl(%d, %d, %d, 0x%x)\n", semid, semnum, cmd, arg);
5002729Sdfr#endif
50182607Sdillon	mtx_lock(&Giant);
50283366Sjulian	if (!jail_sysvipc_allowed && jailed(td->td_proc->p_ucred)) {
50382607Sdillon		error = ENOSYS;
50482607Sdillon		goto done2;
50582607Sdillon	}
50668024Srwatson
50783414Smr	switch(cmd) {
50883414Smr	case SEM_STAT:
50983414Smr		if (semid < 0 || semid >= seminfo.semmsl)
51083414Smr			return(EINVAL);
51183414Smr		semaptr = &sema[semid];
51283414Smr		if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0 )
51383414Smr			return(EINVAL);
51483414Smr		if ((error = ipcperm(td, &semaptr->sem_perm, IPC_R)))
51583414Smr			return(error);
51683414Smr		if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
51783414Smr			return(error);
51883414Smr		error = copyout((caddr_t)semaptr, real_arg.buf,
51983414Smr			sizeof(struct semid_ds));
52083414Smr		rval = IXSEQ_TO_IPCID(semid,semaptr->sem_perm);
52183414Smr		if (error == 0)
52283414Smr			td->td_retval[0] = rval;
52383414Smr		goto done2;
52483414Smr	}
52583414Smr
5262729Sdfr	semid = IPCID_TO_IX(semid);
52782607Sdillon	if (semid < 0 || semid >= seminfo.semmsl) {
52882607Sdillon		error = EINVAL;
52982607Sdillon		goto done2;
53082607Sdillon	}
5312729Sdfr
5322729Sdfr	semaptr = &sema[semid];
5332729Sdfr	if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0 ||
53482607Sdillon	    semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid)) {
53582607Sdillon		error = EINVAL;
53682607Sdillon		goto done2;
53782607Sdillon	}
5382729Sdfr
53982607Sdillon	error = 0;
5402729Sdfr	rval = 0;
5412729Sdfr
5422729Sdfr	switch (cmd) {
5432729Sdfr	case IPC_RMID:
54483366Sjulian		if ((error = ipcperm(td, &semaptr->sem_perm, IPC_M)))
54582607Sdillon			goto done2;
5462729Sdfr		semaptr->sem_perm.cuid = cred->cr_uid;
5472729Sdfr		semaptr->sem_perm.uid = cred->cr_uid;
5482729Sdfr		semtot -= semaptr->sem_nsems;
5492729Sdfr		for (i = semaptr->sem_base - sem; i < semtot; i++)
5502729Sdfr			sem[i] = sem[i + semaptr->sem_nsems];
5512729Sdfr		for (i = 0; i < seminfo.semmni; i++) {
5522729Sdfr			if ((sema[i].sem_perm.mode & SEM_ALLOC) &&
5532729Sdfr			    sema[i].sem_base > semaptr->sem_base)
5542729Sdfr				sema[i].sem_base -= semaptr->sem_nsems;
5552729Sdfr		}
5562729Sdfr		semaptr->sem_perm.mode = 0;
5572729Sdfr		semundo_clear(semid, -1);
5582729Sdfr		wakeup((caddr_t)semaptr);
5592729Sdfr		break;
5602729Sdfr
5612729Sdfr	case IPC_SET:
56283366Sjulian		if ((error = ipcperm(td, &semaptr->sem_perm, IPC_M)))
56382607Sdillon			goto done2;
56482607Sdillon		if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
56582607Sdillon			goto done2;
56682607Sdillon		if ((error = copyin(real_arg.buf, (caddr_t)&sbuf,
56782607Sdillon		    sizeof(sbuf))) != 0) {
56882607Sdillon			goto done2;
56982607Sdillon		}
5702729Sdfr		semaptr->sem_perm.uid = sbuf.sem_perm.uid;
5712729Sdfr		semaptr->sem_perm.gid = sbuf.sem_perm.gid;
5722729Sdfr		semaptr->sem_perm.mode = (semaptr->sem_perm.mode & ~0777) |
5732729Sdfr		    (sbuf.sem_perm.mode & 0777);
57434961Sphk		semaptr->sem_ctime = time_second;
5752729Sdfr		break;
5762729Sdfr
5772729Sdfr	case IPC_STAT:
57883366Sjulian		if ((error = ipcperm(td, &semaptr->sem_perm, IPC_R)))
57982607Sdillon			goto done2;
58082607Sdillon		if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
58182607Sdillon			goto done2;
58282607Sdillon		error = copyout((caddr_t)semaptr, real_arg.buf,
58382607Sdillon				sizeof(struct semid_ds));
5842729Sdfr		break;
5852729Sdfr
5862729Sdfr	case GETNCNT:
58783366Sjulian		if ((error = ipcperm(td, &semaptr->sem_perm, IPC_R)))
58882607Sdillon			goto done2;
58982607Sdillon		if (semnum < 0 || semnum >= semaptr->sem_nsems) {
59082607Sdillon			error = EINVAL;
59182607Sdillon			goto done2;
59282607Sdillon		}
5932729Sdfr		rval = semaptr->sem_base[semnum].semncnt;
5942729Sdfr		break;
5952729Sdfr
5962729Sdfr	case GETPID:
59783366Sjulian		if ((error = ipcperm(td, &semaptr->sem_perm, IPC_R)))
59882607Sdillon			goto done2;
59982607Sdillon		if (semnum < 0 || semnum >= semaptr->sem_nsems) {
60082607Sdillon			error = EINVAL;
60182607Sdillon			goto done2;
60282607Sdillon		}
6032729Sdfr		rval = semaptr->sem_base[semnum].sempid;
6042729Sdfr		break;
6052729Sdfr
6062729Sdfr	case GETVAL:
60783366Sjulian		if ((error = ipcperm(td, &semaptr->sem_perm, IPC_R)))
60882607Sdillon			goto done2;
60982607Sdillon		if (semnum < 0 || semnum >= semaptr->sem_nsems) {
61082607Sdillon			error = EINVAL;
61182607Sdillon			goto done2;
61282607Sdillon		}
6132729Sdfr		rval = semaptr->sem_base[semnum].semval;
6142729Sdfr		break;
6152729Sdfr
6162729Sdfr	case GETALL:
61783366Sjulian		if ((error = ipcperm(td, &semaptr->sem_perm, IPC_R)))
61882607Sdillon			goto done2;
61982607Sdillon		if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
62082607Sdillon			goto done2;
6212729Sdfr		for (i = 0; i < semaptr->sem_nsems; i++) {
62282607Sdillon			error = copyout((caddr_t)&semaptr->sem_base[i].semval,
6232729Sdfr			    &real_arg.array[i], sizeof(real_arg.array[0]));
62482607Sdillon			if (error != 0)
6252729Sdfr				break;
6262729Sdfr		}
6272729Sdfr		break;
6282729Sdfr
6292729Sdfr	case GETZCNT:
63083366Sjulian		if ((error = ipcperm(td, &semaptr->sem_perm, IPC_R)))
63182607Sdillon			goto done2;
63282607Sdillon		if (semnum < 0 || semnum >= semaptr->sem_nsems) {
63382607Sdillon			error = EINVAL;
63482607Sdillon			goto done2;
63582607Sdillon		}
6362729Sdfr		rval = semaptr->sem_base[semnum].semzcnt;
6372729Sdfr		break;
6382729Sdfr
6392729Sdfr	case SETVAL:
64083366Sjulian		if ((error = ipcperm(td, &semaptr->sem_perm, IPC_W)))
64182607Sdillon			goto done2;
64282607Sdillon		if (semnum < 0 || semnum >= semaptr->sem_nsems) {
64382607Sdillon			error = EINVAL;
64482607Sdillon			goto done2;
64582607Sdillon		}
64682607Sdillon		if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
64782607Sdillon			goto done2;
64884789Smr		if (real_arg.val < 0 || real_arg.val > seminfo.semvmx) {
64984789Smr			error = ERANGE;
65084789Smr			goto done2;
65184789Smr		}
6522729Sdfr		semaptr->sem_base[semnum].semval = real_arg.val;
6532729Sdfr		semundo_clear(semid, semnum);
6542729Sdfr		wakeup((caddr_t)semaptr);
6552729Sdfr		break;
6562729Sdfr
6572729Sdfr	case SETALL:
65883366Sjulian		if ((error = ipcperm(td, &semaptr->sem_perm, IPC_W)))
65982607Sdillon			goto done2;
66082607Sdillon		if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
66182607Sdillon			goto done2;
6622729Sdfr		for (i = 0; i < semaptr->sem_nsems; i++) {
66382607Sdillon			error = copyin(&real_arg.array[i],
66484789Smr			    (caddr_t)&usval, sizeof(real_arg.array[0]));
66582607Sdillon			if (error != 0)
6662729Sdfr				break;
66784789Smr			if (usval > seminfo.semvmx) {
66884789Smr				error = ERANGE;
66984789Smr				break;
67084789Smr			}
67184789Smr			semaptr->sem_base[i].semval = usval;
6722729Sdfr		}
6732729Sdfr		semundo_clear(semid, -1);
6742729Sdfr		wakeup((caddr_t)semaptr);
6752729Sdfr		break;
6762729Sdfr
6772729Sdfr	default:
67882607Sdillon		error = EINVAL;
67982607Sdillon		break;
6802729Sdfr	}
6812729Sdfr
68282607Sdillon	if (error == 0)
68383366Sjulian		td->td_retval[0] = rval;
68482607Sdillondone2:
68582607Sdillon	mtx_unlock(&Giant);
68682607Sdillon	return(error);
6872729Sdfr}
6882729Sdfr
68912866Speter#ifndef _SYS_SYSPROTO_H_
6902729Sdfrstruct semget_args {
6912729Sdfr	key_t	key;
6922729Sdfr	int	nsems;
6932729Sdfr	int	semflg;
6942729Sdfr};
69512866Speter#endif
6962729Sdfr
69782607Sdillon/*
69882607Sdillon * MPSAFE
69982607Sdillon */
70012866Speterint
70183366Sjuliansemget(td, uap)
70283366Sjulian	struct thread *td;
7032729Sdfr	register struct semget_args *uap;
7042729Sdfr{
70582607Sdillon	int semid, error = 0;
7062729Sdfr	int key = uap->key;
7072729Sdfr	int nsems = uap->nsems;
7082729Sdfr	int semflg = uap->semflg;
70983366Sjulian	struct ucred *cred = td->td_proc->p_ucred;
7102729Sdfr
7112729Sdfr#ifdef SEM_DEBUG
7122729Sdfr	printf("semget(0x%x, %d, 0%o)\n", key, nsems, semflg);
7132729Sdfr#endif
71482607Sdillon	mtx_lock(&Giant);
71583366Sjulian	if (!jail_sysvipc_allowed && jailed(td->td_proc->p_ucred)) {
71682607Sdillon		error = ENOSYS;
71782607Sdillon		goto done2;
71882607Sdillon	}
71968024Srwatson
7202729Sdfr	if (key != IPC_PRIVATE) {
7212729Sdfr		for (semid = 0; semid < seminfo.semmni; semid++) {
7222729Sdfr			if ((sema[semid].sem_perm.mode & SEM_ALLOC) &&
7232729Sdfr			    sema[semid].sem_perm.key == key)
7242729Sdfr				break;
7252729Sdfr		}
7262729Sdfr		if (semid < seminfo.semmni) {
7272729Sdfr#ifdef SEM_DEBUG
7282729Sdfr			printf("found public key\n");
7292729Sdfr#endif
73083366Sjulian			if ((error = ipcperm(td, &sema[semid].sem_perm,
73182607Sdillon			    semflg & 0700))) {
73282607Sdillon				goto done2;
73382607Sdillon			}
7342729Sdfr			if (nsems > 0 && sema[semid].sem_nsems < nsems) {
7352729Sdfr#ifdef SEM_DEBUG
7362729Sdfr				printf("too small\n");
7372729Sdfr#endif
73882607Sdillon				error = EINVAL;
73982607Sdillon				goto done2;
7402729Sdfr			}
7412729Sdfr			if ((semflg & IPC_CREAT) && (semflg & IPC_EXCL)) {
7422729Sdfr#ifdef SEM_DEBUG
7432729Sdfr				printf("not exclusive\n");
7442729Sdfr#endif
74582607Sdillon				error = EEXIST;
74682607Sdillon				goto done2;
7472729Sdfr			}
7482729Sdfr			goto found;
7492729Sdfr		}
7502729Sdfr	}
7512729Sdfr
7522729Sdfr#ifdef SEM_DEBUG
7532729Sdfr	printf("need to allocate the semid_ds\n");
7542729Sdfr#endif
7552729Sdfr	if (key == IPC_PRIVATE || (semflg & IPC_CREAT)) {
7562729Sdfr		if (nsems <= 0 || nsems > seminfo.semmsl) {
7572729Sdfr#ifdef SEM_DEBUG
7582729Sdfr			printf("nsems out of range (0<%d<=%d)\n", nsems,
7592729Sdfr			    seminfo.semmsl);
7602729Sdfr#endif
76182607Sdillon			error = EINVAL;
76282607Sdillon			goto done2;
7632729Sdfr		}
7642729Sdfr		if (nsems > seminfo.semmns - semtot) {
7652729Sdfr#ifdef SEM_DEBUG
7662729Sdfr			printf("not enough semaphores left (need %d, got %d)\n",
7672729Sdfr			    nsems, seminfo.semmns - semtot);
7682729Sdfr#endif
76982607Sdillon			error = ENOSPC;
77082607Sdillon			goto done2;
7712729Sdfr		}
7722729Sdfr		for (semid = 0; semid < seminfo.semmni; semid++) {
7732729Sdfr			if ((sema[semid].sem_perm.mode & SEM_ALLOC) == 0)
7742729Sdfr				break;
7752729Sdfr		}
7762729Sdfr		if (semid == seminfo.semmni) {
7772729Sdfr#ifdef SEM_DEBUG
7782729Sdfr			printf("no more semid_ds's available\n");
7792729Sdfr#endif
78082607Sdillon			error = ENOSPC;
78182607Sdillon			goto done2;
7822729Sdfr		}
7832729Sdfr#ifdef SEM_DEBUG
7842729Sdfr		printf("semid %d is available\n", semid);
7852729Sdfr#endif
7862729Sdfr		sema[semid].sem_perm.key = key;
7872729Sdfr		sema[semid].sem_perm.cuid = cred->cr_uid;
7882729Sdfr		sema[semid].sem_perm.uid = cred->cr_uid;
7892729Sdfr		sema[semid].sem_perm.cgid = cred->cr_gid;
7902729Sdfr		sema[semid].sem_perm.gid = cred->cr_gid;
7912729Sdfr		sema[semid].sem_perm.mode = (semflg & 0777) | SEM_ALLOC;
7922729Sdfr		sema[semid].sem_perm.seq =
7932729Sdfr		    (sema[semid].sem_perm.seq + 1) & 0x7fff;
7942729Sdfr		sema[semid].sem_nsems = nsems;
7952729Sdfr		sema[semid].sem_otime = 0;
79634961Sphk		sema[semid].sem_ctime = time_second;
7972729Sdfr		sema[semid].sem_base = &sem[semtot];
7982729Sdfr		semtot += nsems;
7992729Sdfr		bzero(sema[semid].sem_base,
8002729Sdfr		    sizeof(sema[semid].sem_base[0])*nsems);
8012729Sdfr#ifdef SEM_DEBUG
8022729Sdfr		printf("sembase = 0x%x, next = 0x%x\n", sema[semid].sem_base,
8032729Sdfr		    &sem[semtot]);
8042729Sdfr#endif
8052729Sdfr	} else {
8062729Sdfr#ifdef SEM_DEBUG
8072729Sdfr		printf("didn't find it and wasn't asked to create it\n");
8082729Sdfr#endif
80982607Sdillon		error = ENOENT;
81082607Sdillon		goto done2;
8112729Sdfr	}
8122729Sdfr
8132729Sdfrfound:
81483366Sjulian	td->td_retval[0] = IXSEQ_TO_IPCID(semid, sema[semid].sem_perm);
81582607Sdillondone2:
81682607Sdillon	mtx_unlock(&Giant);
81782607Sdillon	return (error);
8182729Sdfr}
8192729Sdfr
82012866Speter#ifndef _SYS_SYSPROTO_H_
8212729Sdfrstruct semop_args {
8222729Sdfr	int	semid;
8232729Sdfr	struct	sembuf *sops;
82483292Sdd	u_int	nsops;
8252729Sdfr};
82612866Speter#endif
8272729Sdfr
82882607Sdillon/*
82982607Sdillon * MPSAFE
83082607Sdillon */
83112866Speterint
83283366Sjuliansemop(td, uap)
83383366Sjulian	struct thread *td;
8342729Sdfr	register struct semop_args *uap;
8352729Sdfr{
8362729Sdfr	int semid = uap->semid;
83783292Sdd	u_int nsops = uap->nsops;
83884789Smr	struct sembuf *sops = NULL;
8392729Sdfr	register struct semid_ds *semaptr;
8402729Sdfr	register struct sembuf *sopptr;
8412729Sdfr	register struct sem *semptr;
84284789Smr	struct sem_undo *suptr;
84384789Smr	int i, j, error;
8443308Sphk	int do_wakeup, do_undos;
8452729Sdfr
8462729Sdfr#ifdef SEM_DEBUG
84783292Sdd	printf("call to semop(%d, 0x%x, %u)\n", semid, sops, nsops);
8482729Sdfr#endif
8492729Sdfr
85082607Sdillon	mtx_lock(&Giant);
85183366Sjulian	if (!jail_sysvipc_allowed && jailed(td->td_proc->p_ucred)) {
85282607Sdillon		error = ENOSYS;
85382607Sdillon		goto done2;
85482607Sdillon	}
85582607Sdillon
8562729Sdfr	semid = IPCID_TO_IX(semid);	/* Convert back to zero origin */
8572729Sdfr
85882607Sdillon	if (semid < 0 || semid >= seminfo.semmsl) {
85982607Sdillon		error = EINVAL;
86082607Sdillon		goto done2;
86182607Sdillon	}
8622729Sdfr
8632729Sdfr	semaptr = &sema[semid];
86482607Sdillon	if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0) {
86582607Sdillon		error = EINVAL;
86682607Sdillon		goto done2;
86782607Sdillon	}
86882607Sdillon	if (semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid)) {
86982607Sdillon		error = EINVAL;
87082607Sdillon		goto done2;
87182607Sdillon	}
87284789Smr	if (nsops > seminfo.semopm) {
8732729Sdfr#ifdef SEM_DEBUG
87484789Smr		printf("too many sops (max=%d, nsops=%d)\n", seminfo.semopm,
87584789Smr		    nsops);
8762729Sdfr#endif
87784789Smr		error = E2BIG;
87882607Sdillon		goto done2;
8792729Sdfr	}
8802729Sdfr
88184789Smr	/* Allocate memory for sem_ops */
88284789Smr	sops = malloc(nsops * sizeof(sops[0]), M_SEM, M_WAITOK);
88384789Smr	if (!sops)
88484789Smr		panic("Failed to allocate %d sem_ops", nsops);
88584789Smr
88684789Smr	if ((error = copyin(uap->sops, sops, nsops * sizeof(sops[0]))) != 0) {
8872729Sdfr#ifdef SEM_DEBUG
88884789Smr		printf("error = %d from copyin(%08x, %08x, %d)\n", error,
88984789Smr		    uap->sops, sops, nsops * sizeof(sops[0]));
8902729Sdfr#endif
89182607Sdillon		goto done2;
8922729Sdfr	}
8932729Sdfr
89484789Smr	/*
89584789Smr	 * Initial pass thru sops to see what permissions are needed.
89684789Smr	 * Also perform any checks that don't need repeating on each
89784789Smr	 * attempt to satisfy the request vector.
89884789Smr	 */
89984789Smr	j = 0;		/* permission needed */
90084789Smr	do_undos = 0;
90184789Smr	for (i = 0; i < nsops; i++) {
90284789Smr		sopptr = &sops[i];
90384789Smr		if (sopptr->sem_num >= semaptr->sem_nsems) {
90484789Smr			error = EFBIG;
90584789Smr			goto done2;
90684789Smr		}
90784789Smr		if (sopptr->sem_flg & SEM_UNDO && sopptr->sem_op != 0)
90884789Smr			do_undos = 1;
90984789Smr		j |= (sopptr->sem_op == 0) ? SEM_R : SEM_A;
91084789Smr	}
91184789Smr
91284789Smr	if ((error = ipcperm(td, &semaptr->sem_perm, j))) {
9132729Sdfr#ifdef SEM_DEBUG
91484789Smr		printf("error = %d from ipaccess\n", error);
9152729Sdfr#endif
91682607Sdillon		goto done2;
9172729Sdfr	}
9182729Sdfr
9198876Srgrimes	/*
9202729Sdfr	 * Loop trying to satisfy the vector of requests.
9212729Sdfr	 * If we reach a point where we must wait, any requests already
9222729Sdfr	 * performed are rolled back and we go to sleep until some other
9232729Sdfr	 * process wakes us up.  At this point, we start all over again.
9242729Sdfr	 *
9252729Sdfr	 * This ensures that from the perspective of other tasks, a set
9262729Sdfr	 * of requests is atomic (never partially satisfied).
9272729Sdfr	 */
9282729Sdfr	for (;;) {
9292729Sdfr		do_wakeup = 0;
93084789Smr		error = 0;	/* error return if necessary */
9312729Sdfr
9322729Sdfr		for (i = 0; i < nsops; i++) {
9332729Sdfr			sopptr = &sops[i];
9342729Sdfr			semptr = &semaptr->sem_base[sopptr->sem_num];
9352729Sdfr
9362729Sdfr#ifdef SEM_DEBUG
9372729Sdfr			printf("semop:  semaptr=%x, sem_base=%x, semptr=%x, sem[%d]=%d : op=%d, flag=%s\n",
9382729Sdfr			    semaptr, semaptr->sem_base, semptr,
9392729Sdfr			    sopptr->sem_num, semptr->semval, sopptr->sem_op,
9402729Sdfr			    (sopptr->sem_flg & IPC_NOWAIT) ? "nowait" : "wait");
9412729Sdfr#endif
9422729Sdfr
9432729Sdfr			if (sopptr->sem_op < 0) {
9442729Sdfr				if (semptr->semval + sopptr->sem_op < 0) {
9452729Sdfr#ifdef SEM_DEBUG
9462729Sdfr					printf("semop:  can't do it now\n");
9472729Sdfr#endif
9482729Sdfr					break;
9492729Sdfr				} else {
9502729Sdfr					semptr->semval += sopptr->sem_op;
9512729Sdfr					if (semptr->semval == 0 &&
9522729Sdfr					    semptr->semzcnt > 0)
9532729Sdfr						do_wakeup = 1;
9542729Sdfr				}
9552729Sdfr			} else if (sopptr->sem_op == 0) {
95684789Smr				if (semptr->semval != 0) {
9572729Sdfr#ifdef SEM_DEBUG
9582729Sdfr					printf("semop:  not zero now\n");
9592729Sdfr#endif
9602729Sdfr					break;
9612729Sdfr				}
96284789Smr			} else if (semptr->semval + sopptr->sem_op >
96384789Smr			    seminfo.semvmx) {
96484789Smr				error = ERANGE;
96584789Smr				break;
9662729Sdfr			} else {
9672729Sdfr				if (semptr->semncnt > 0)
9682729Sdfr					do_wakeup = 1;
9692729Sdfr				semptr->semval += sopptr->sem_op;
9702729Sdfr			}
9712729Sdfr		}
9722729Sdfr
9732729Sdfr		/*
9742729Sdfr		 * Did we get through the entire vector?
9752729Sdfr		 */
9762729Sdfr		if (i >= nsops)
9772729Sdfr			goto done;
9782729Sdfr
9792729Sdfr		/*
9802729Sdfr		 * No ... rollback anything that we've already done
9812729Sdfr		 */
9822729Sdfr#ifdef SEM_DEBUG
9832729Sdfr		printf("semop:  rollback 0 through %d\n", i-1);
9842729Sdfr#endif
9852729Sdfr		for (j = 0; j < i; j++)
9862729Sdfr			semaptr->sem_base[sops[j].sem_num].semval -=
9872729Sdfr			    sops[j].sem_op;
9882729Sdfr
98984789Smr		/* If we detected an error, return it */
99084789Smr		if (error != 0)
99184789Smr			goto done2;
99284789Smr
9932729Sdfr		/*
9942729Sdfr		 * If the request that we couldn't satisfy has the
9952729Sdfr		 * NOWAIT flag set then return with EAGAIN.
9962729Sdfr		 */
99782607Sdillon		if (sopptr->sem_flg & IPC_NOWAIT) {
99882607Sdillon			error = EAGAIN;
99982607Sdillon			goto done2;
100082607Sdillon		}
10012729Sdfr
10022729Sdfr		if (sopptr->sem_op == 0)
10032729Sdfr			semptr->semzcnt++;
10042729Sdfr		else
10052729Sdfr			semptr->semncnt++;
10062729Sdfr
10072729Sdfr#ifdef SEM_DEBUG
10082729Sdfr		printf("semop:  good night!\n");
10092729Sdfr#endif
101082607Sdillon		error = tsleep((caddr_t)semaptr, (PZERO - 4) | PCATCH,
10112729Sdfr		    "semwait", 0);
10122729Sdfr#ifdef SEM_DEBUG
101382607Sdillon		printf("semop:  good morning (error=%d)!\n", error);
10142729Sdfr#endif
10152729Sdfr
101682607Sdillon		if (error != 0) {
101782607Sdillon			error = EINTR;
101882607Sdillon			goto done2;
101982607Sdillon		}
10202729Sdfr#ifdef SEM_DEBUG
10212729Sdfr		printf("semop:  good morning!\n");
10222729Sdfr#endif
10232729Sdfr
10242729Sdfr		/*
10252729Sdfr		 * Make sure that the semaphore still exists
10262729Sdfr		 */
10272729Sdfr		if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0 ||
102882607Sdillon		    semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid)) {
102982607Sdillon			error = EIDRM;
103082607Sdillon			goto done2;
103182607Sdillon		}
10322729Sdfr
10332729Sdfr		/*
10342729Sdfr		 * The semaphore is still alive.  Readjust the count of
10352729Sdfr		 * waiting processes.
10362729Sdfr		 */
10372729Sdfr		if (sopptr->sem_op == 0)
10382729Sdfr			semptr->semzcnt--;
10392729Sdfr		else
10402729Sdfr			semptr->semncnt--;
10412729Sdfr	}
10422729Sdfr
10432729Sdfrdone:
10442729Sdfr	/*
10452729Sdfr	 * Process any SEM_UNDO requests.
10462729Sdfr	 */
10472729Sdfr	if (do_undos) {
104884789Smr		suptr = NULL;
10492729Sdfr		for (i = 0; i < nsops; i++) {
10502729Sdfr			/*
10512729Sdfr			 * We only need to deal with SEM_UNDO's for non-zero
10522729Sdfr			 * op's.
10532729Sdfr			 */
10542729Sdfr			int adjval;
10552729Sdfr
10562729Sdfr			if ((sops[i].sem_flg & SEM_UNDO) == 0)
10572729Sdfr				continue;
10582729Sdfr			adjval = sops[i].sem_op;
10592729Sdfr			if (adjval == 0)
10602729Sdfr				continue;
106183366Sjulian			error = semundo_adjust(td, &suptr, semid,
10622729Sdfr			    sops[i].sem_num, -adjval);
106382607Sdillon			if (error == 0)
10642729Sdfr				continue;
10652729Sdfr
10662729Sdfr			/*
10672729Sdfr			 * Oh-Oh!  We ran out of either sem_undo's or undo's.
10682729Sdfr			 * Rollback the adjustments to this point and then
10692729Sdfr			 * rollback the semaphore ups and down so we can return
10702729Sdfr			 * with an error with all structures restored.  We
10712729Sdfr			 * rollback the undo's in the exact reverse order that
10722729Sdfr			 * we applied them.  This guarantees that we won't run
10732729Sdfr			 * out of space as we roll things back out.
10742729Sdfr			 */
10752729Sdfr			for (j = i - 1; j >= 0; j--) {
10762729Sdfr				if ((sops[j].sem_flg & SEM_UNDO) == 0)
10772729Sdfr					continue;
10782729Sdfr				adjval = sops[j].sem_op;
10792729Sdfr				if (adjval == 0)
10802729Sdfr					continue;
108183366Sjulian				if (semundo_adjust(td, &suptr, semid,
10822729Sdfr				    sops[j].sem_num, adjval) != 0)
10832729Sdfr					panic("semop - can't undo undos");
10842729Sdfr			}
10852729Sdfr
10862729Sdfr			for (j = 0; j < nsops; j++)
10872729Sdfr				semaptr->sem_base[sops[j].sem_num].semval -=
10882729Sdfr				    sops[j].sem_op;
10892729Sdfr
10902729Sdfr#ifdef SEM_DEBUG
109182607Sdillon			printf("error = %d from semundo_adjust\n", error);
10922729Sdfr#endif
109382607Sdillon			goto done2;
10942729Sdfr		} /* loop through the sops */
10952729Sdfr	} /* if (do_undos) */
10962729Sdfr
109784789Smr	/* We're definitely done - set the sempid's and time */
10982729Sdfr	for (i = 0; i < nsops; i++) {
10992729Sdfr		sopptr = &sops[i];
11002729Sdfr		semptr = &semaptr->sem_base[sopptr->sem_num];
110183366Sjulian		semptr->sempid = td->td_proc->p_pid;
11022729Sdfr	}
110384789Smr	semaptr->sem_otime = time_second;
11042729Sdfr
110584789Smr	/*
110684789Smr	 * Do a wakeup if any semaphore was up'd whilst something was
110784789Smr	 * sleeping on it.
110884789Smr	 */
11092729Sdfr	if (do_wakeup) {
11102729Sdfr#ifdef SEM_DEBUG
11112729Sdfr		printf("semop:  doing wakeup\n");
111258831Speter#endif
11132729Sdfr		wakeup((caddr_t)semaptr);
111458831Speter#ifdef SEM_DEBUG
11152729Sdfr		printf("semop:  back from wakeup\n");
11162729Sdfr#endif
11172729Sdfr	}
11182729Sdfr#ifdef SEM_DEBUG
11192729Sdfr	printf("semop:  done\n");
11202729Sdfr#endif
112183366Sjulian	td->td_retval[0] = 0;
112282607Sdillondone2:
112384789Smr	if (sops)
112484789Smr	    free(sops, M_SEM);
112582607Sdillon	mtx_unlock(&Giant);
112682607Sdillon	return (error);
11272729Sdfr}
11282729Sdfr
11292729Sdfr/*
11302729Sdfr * Go through the undo structures for this process and apply the adjustments to
11312729Sdfr * semaphores.
11322729Sdfr */
113369449Salfredstatic void
113469449Salfredsemexit_myhook(p)
11352729Sdfr	struct proc *p;
11362729Sdfr{
11372729Sdfr	register struct sem_undo *suptr;
11382729Sdfr	register struct sem_undo **supptr;
11392729Sdfr
11402729Sdfr	/*
11412729Sdfr	 * Go through the chain of undo vectors looking for one
11422729Sdfr	 * associated with this process.
11432729Sdfr	 */
11442729Sdfr
11452729Sdfr	for (supptr = &semu_list; (suptr = *supptr) != NULL;
11462729Sdfr	    supptr = &suptr->un_next) {
11472729Sdfr		if (suptr->un_proc == p)
11482729Sdfr			break;
11492729Sdfr	}
11502729Sdfr
11512729Sdfr	if (suptr == NULL)
115259828Speter		return;
11532729Sdfr
11542729Sdfr#ifdef SEM_DEBUG
11552729Sdfr	printf("proc @%08x has undo structure with %d entries\n", p,
11562729Sdfr	    suptr->un_cnt);
11572729Sdfr#endif
11582729Sdfr
11592729Sdfr	/*
11602729Sdfr	 * If there are any active undo elements then process them.
11612729Sdfr	 */
11622729Sdfr	if (suptr->un_cnt > 0) {
11632729Sdfr		int ix;
11642729Sdfr
11652729Sdfr		for (ix = 0; ix < suptr->un_cnt; ix++) {
11662729Sdfr			int semid = suptr->un_ent[ix].un_id;
11672729Sdfr			int semnum = suptr->un_ent[ix].un_num;
11682729Sdfr			int adjval = suptr->un_ent[ix].un_adjval;
11692729Sdfr			struct semid_ds *semaptr;
11702729Sdfr
11712729Sdfr			semaptr = &sema[semid];
11722729Sdfr			if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0)
11732729Sdfr				panic("semexit - semid not allocated");
11742729Sdfr			if (semnum >= semaptr->sem_nsems)
11752729Sdfr				panic("semexit - semnum out of range");
11762729Sdfr
11772729Sdfr#ifdef SEM_DEBUG
11782729Sdfr			printf("semexit:  %08x id=%d num=%d(adj=%d) ; sem=%d\n",
11792729Sdfr			    suptr->un_proc, suptr->un_ent[ix].un_id,
11802729Sdfr			    suptr->un_ent[ix].un_num,
11812729Sdfr			    suptr->un_ent[ix].un_adjval,
11822729Sdfr			    semaptr->sem_base[semnum].semval);
11832729Sdfr#endif
11842729Sdfr
11852729Sdfr			if (adjval < 0) {
11862729Sdfr				if (semaptr->sem_base[semnum].semval < -adjval)
11872729Sdfr					semaptr->sem_base[semnum].semval = 0;
11882729Sdfr				else
11892729Sdfr					semaptr->sem_base[semnum].semval +=
11902729Sdfr					    adjval;
11912729Sdfr			} else
11922729Sdfr				semaptr->sem_base[semnum].semval += adjval;
11932729Sdfr
11942729Sdfr			wakeup((caddr_t)semaptr);
11952729Sdfr#ifdef SEM_DEBUG
11962729Sdfr			printf("semexit:  back from wakeup\n");
11972729Sdfr#endif
11982729Sdfr		}
11992729Sdfr	}
12002729Sdfr
12012729Sdfr	/*
12022729Sdfr	 * Deallocate the undo vector.
12032729Sdfr	 */
12042729Sdfr#ifdef SEM_DEBUG
12052729Sdfr	printf("removing vector\n");
12062729Sdfr#endif
12072729Sdfr	suptr->un_proc = NULL;
12082729Sdfr	*supptr = suptr->un_next;
12092729Sdfr}
121077461Sdd
121177461Sddstatic int
121277461Sddsysctl_sema(SYSCTL_HANDLER_ARGS)
121377461Sdd{
121477461Sdd
121577461Sdd	return (SYSCTL_OUT(req, sema,
121677461Sdd	    sizeof(struct semid_ds) * seminfo.semmni));
121777461Sdd}
1218