sysv_sem.c revision 83413
150477Speter/* $FreeBSD: head/sys/kern/sysv_sem.c 83413 2001-09-13 20:20:09Z mr $ */
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
24969449SalfredSYSCALL_MODULE_HELPER(semsys, 5);
25069449SalfredSYSCALL_MODULE_HELPER(__semctl, 4);
25169449SalfredSYSCALL_MODULE_HELPER(semget, 3);
25269449SalfredSYSCALL_MODULE_HELPER(semop, 3);
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;
4092729Sdfr		if (adjval == 0)
4102729Sdfr			sunptr->un_adjval = 0;
4112729Sdfr		else
4122729Sdfr			sunptr->un_adjval += adjval;
4132729Sdfr		if (sunptr->un_adjval == 0) {
4142729Sdfr			suptr->un_cnt--;
4152729Sdfr			if (i < suptr->un_cnt)
4162729Sdfr				suptr->un_ent[i] =
4172729Sdfr				    suptr->un_ent[suptr->un_cnt];
4182729Sdfr		}
4192729Sdfr		return(0);
4202729Sdfr	}
4212729Sdfr
4222729Sdfr	/* Didn't find the right entry - create it */
4232729Sdfr	if (adjval == 0)
4242729Sdfr		return(0);
42541774Sdillon	if (suptr->un_cnt != seminfo.semume) {
4262729Sdfr		sunptr = &suptr->un_ent[suptr->un_cnt];
4272729Sdfr		suptr->un_cnt++;
4282729Sdfr		sunptr->un_adjval = adjval;
4292729Sdfr		sunptr->un_id = semid; sunptr->un_num = semnum;
4302729Sdfr	} else
4312729Sdfr		return(EINVAL);
4322729Sdfr	return(0);
4332729Sdfr}
4342729Sdfr
43512819Sphkstatic void
4362729Sdfrsemundo_clear(semid, semnum)
4372729Sdfr	int semid, semnum;
4382729Sdfr{
4392729Sdfr	register struct sem_undo *suptr;
4402729Sdfr
4412729Sdfr	for (suptr = semu_list; suptr != NULL; suptr = suptr->un_next) {
4422729Sdfr		register struct undo *sunptr = &suptr->un_ent[0];
4432729Sdfr		register int i = 0;
4442729Sdfr
4452729Sdfr		while (i < suptr->un_cnt) {
4462729Sdfr			if (sunptr->un_id == semid) {
4472729Sdfr				if (semnum == -1 || sunptr->un_num == semnum) {
4482729Sdfr					suptr->un_cnt--;
4492729Sdfr					if (i < suptr->un_cnt) {
4502729Sdfr						suptr->un_ent[i] =
4512729Sdfr						  suptr->un_ent[suptr->un_cnt];
4522729Sdfr						continue;
4532729Sdfr					}
4542729Sdfr				}
4552729Sdfr				if (semnum != -1)
4562729Sdfr					break;
4572729Sdfr			}
4582729Sdfr			i++, sunptr++;
4592729Sdfr		}
4602729Sdfr	}
4612729Sdfr}
4622729Sdfr
46312866Speter/*
46412866Speter * Note that the user-mode half of this passes a union, not a pointer
46512866Speter */
46612866Speter#ifndef _SYS_SYSPROTO_H_
46712866Speterstruct __semctl_args {
4682729Sdfr	int	semid;
4692729Sdfr	int	semnum;
4702729Sdfr	int	cmd;
4712729Sdfr	union	semun *arg;
4722729Sdfr};
47312866Speter#endif
4742729Sdfr
47582607Sdillon/*
47682607Sdillon * MPSAFE
47782607Sdillon */
47812866Speterint
47983366Sjulian__semctl(td, uap)
48083366Sjulian	struct thread *td;
48112866Speter	register struct __semctl_args *uap;
4822729Sdfr{
4832729Sdfr	int semid = uap->semid;
4842729Sdfr	int semnum = uap->semnum;
4852729Sdfr	int cmd = uap->cmd;
4862729Sdfr	union semun *arg = uap->arg;
4872729Sdfr	union semun real_arg;
48883366Sjulian	struct ucred *cred = td->td_proc->p_ucred;
48982607Sdillon	int i, rval, error;
4902729Sdfr	struct semid_ds sbuf;
4912729Sdfr	register struct semid_ds *semaptr;
4922729Sdfr
4932729Sdfr#ifdef SEM_DEBUG
4942729Sdfr	printf("call to semctl(%d, %d, %d, 0x%x)\n", semid, semnum, cmd, arg);
4952729Sdfr#endif
49682607Sdillon	mtx_lock(&Giant);
49783366Sjulian	if (!jail_sysvipc_allowed && jailed(td->td_proc->p_ucred)) {
49882607Sdillon		error = ENOSYS;
49982607Sdillon		goto done2;
50082607Sdillon	}
50168024Srwatson
5022729Sdfr	semid = IPCID_TO_IX(semid);
50382607Sdillon	if (semid < 0 || semid >= seminfo.semmsl) {
50482607Sdillon		error = EINVAL;
50582607Sdillon		goto done2;
50682607Sdillon	}
5072729Sdfr
5082729Sdfr	semaptr = &sema[semid];
5092729Sdfr	if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0 ||
51082607Sdillon	    semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid)) {
51182607Sdillon		error = EINVAL;
51282607Sdillon		goto done2;
51382607Sdillon	}
5142729Sdfr
51582607Sdillon	error = 0;
5162729Sdfr	rval = 0;
5172729Sdfr
5182729Sdfr	switch (cmd) {
5192729Sdfr	case IPC_RMID:
52083366Sjulian		if ((error = ipcperm(td, &semaptr->sem_perm, IPC_M)))
52182607Sdillon			goto done2;
5222729Sdfr		semaptr->sem_perm.cuid = cred->cr_uid;
5232729Sdfr		semaptr->sem_perm.uid = cred->cr_uid;
5242729Sdfr		semtot -= semaptr->sem_nsems;
5252729Sdfr		for (i = semaptr->sem_base - sem; i < semtot; i++)
5262729Sdfr			sem[i] = sem[i + semaptr->sem_nsems];
5272729Sdfr		for (i = 0; i < seminfo.semmni; i++) {
5282729Sdfr			if ((sema[i].sem_perm.mode & SEM_ALLOC) &&
5292729Sdfr			    sema[i].sem_base > semaptr->sem_base)
5302729Sdfr				sema[i].sem_base -= semaptr->sem_nsems;
5312729Sdfr		}
5322729Sdfr		semaptr->sem_perm.mode = 0;
5332729Sdfr		semundo_clear(semid, -1);
5342729Sdfr		wakeup((caddr_t)semaptr);
5352729Sdfr		break;
5362729Sdfr
5372729Sdfr	case IPC_SET:
53883366Sjulian		if ((error = ipcperm(td, &semaptr->sem_perm, IPC_M)))
53982607Sdillon			goto done2;
54082607Sdillon		if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
54182607Sdillon			goto done2;
54282607Sdillon		if ((error = copyin(real_arg.buf, (caddr_t)&sbuf,
54382607Sdillon		    sizeof(sbuf))) != 0) {
54482607Sdillon			goto done2;
54582607Sdillon		}
5462729Sdfr		semaptr->sem_perm.uid = sbuf.sem_perm.uid;
5472729Sdfr		semaptr->sem_perm.gid = sbuf.sem_perm.gid;
5482729Sdfr		semaptr->sem_perm.mode = (semaptr->sem_perm.mode & ~0777) |
5492729Sdfr		    (sbuf.sem_perm.mode & 0777);
55034961Sphk		semaptr->sem_ctime = time_second;
5512729Sdfr		break;
5522729Sdfr
5532729Sdfr	case IPC_STAT:
55483366Sjulian		if ((error = ipcperm(td, &semaptr->sem_perm, IPC_R)))
55582607Sdillon			goto done2;
55682607Sdillon		if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
55782607Sdillon			goto done2;
55882607Sdillon		error = copyout((caddr_t)semaptr, real_arg.buf,
55982607Sdillon				sizeof(struct semid_ds));
5602729Sdfr		break;
5612729Sdfr
5622729Sdfr	case GETNCNT:
56383366Sjulian		if ((error = ipcperm(td, &semaptr->sem_perm, IPC_R)))
56482607Sdillon			goto done2;
56582607Sdillon		if (semnum < 0 || semnum >= semaptr->sem_nsems) {
56682607Sdillon			error = EINVAL;
56782607Sdillon			goto done2;
56882607Sdillon		}
5692729Sdfr		rval = semaptr->sem_base[semnum].semncnt;
5702729Sdfr		break;
5712729Sdfr
5722729Sdfr	case GETPID:
57383366Sjulian		if ((error = ipcperm(td, &semaptr->sem_perm, IPC_R)))
57482607Sdillon			goto done2;
57582607Sdillon		if (semnum < 0 || semnum >= semaptr->sem_nsems) {
57682607Sdillon			error = EINVAL;
57782607Sdillon			goto done2;
57882607Sdillon		}
5792729Sdfr		rval = semaptr->sem_base[semnum].sempid;
5802729Sdfr		break;
5812729Sdfr
5822729Sdfr	case GETVAL:
58383366Sjulian		if ((error = ipcperm(td, &semaptr->sem_perm, IPC_R)))
58482607Sdillon			goto done2;
58582607Sdillon		if (semnum < 0 || semnum >= semaptr->sem_nsems) {
58682607Sdillon			error = EINVAL;
58782607Sdillon			goto done2;
58882607Sdillon		}
5892729Sdfr		rval = semaptr->sem_base[semnum].semval;
5902729Sdfr		break;
5912729Sdfr
5922729Sdfr	case GETALL:
59383366Sjulian		if ((error = ipcperm(td, &semaptr->sem_perm, IPC_R)))
59482607Sdillon			goto done2;
59582607Sdillon		if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
59682607Sdillon			goto done2;
5972729Sdfr		for (i = 0; i < semaptr->sem_nsems; i++) {
59882607Sdillon			error = copyout((caddr_t)&semaptr->sem_base[i].semval,
5992729Sdfr			    &real_arg.array[i], sizeof(real_arg.array[0]));
60082607Sdillon			if (error != 0)
6012729Sdfr				break;
6022729Sdfr		}
6032729Sdfr		break;
6042729Sdfr
6052729Sdfr	case GETZCNT:
60683366Sjulian		if ((error = ipcperm(td, &semaptr->sem_perm, IPC_R)))
60782607Sdillon			goto done2;
60882607Sdillon		if (semnum < 0 || semnum >= semaptr->sem_nsems) {
60982607Sdillon			error = EINVAL;
61082607Sdillon			goto done2;
61182607Sdillon		}
6122729Sdfr		rval = semaptr->sem_base[semnum].semzcnt;
6132729Sdfr		break;
6142729Sdfr
6152729Sdfr	case SETVAL:
61683366Sjulian		if ((error = ipcperm(td, &semaptr->sem_perm, IPC_W)))
61782607Sdillon			goto done2;
61882607Sdillon		if (semnum < 0 || semnum >= semaptr->sem_nsems) {
61982607Sdillon			error = EINVAL;
62082607Sdillon			goto done2;
62182607Sdillon		}
62282607Sdillon		if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
62382607Sdillon			goto done2;
6242729Sdfr		semaptr->sem_base[semnum].semval = real_arg.val;
6252729Sdfr		semundo_clear(semid, semnum);
6262729Sdfr		wakeup((caddr_t)semaptr);
6272729Sdfr		break;
6282729Sdfr
6292729Sdfr	case SETALL:
63083366Sjulian		if ((error = ipcperm(td, &semaptr->sem_perm, IPC_W)))
63182607Sdillon			goto done2;
63282607Sdillon		if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
63382607Sdillon			goto done2;
6342729Sdfr		for (i = 0; i < semaptr->sem_nsems; i++) {
63582607Sdillon			error = copyin(&real_arg.array[i],
6362729Sdfr			    (caddr_t)&semaptr->sem_base[i].semval,
6372729Sdfr			    sizeof(real_arg.array[0]));
63882607Sdillon			if (error != 0)
6392729Sdfr				break;
6402729Sdfr		}
6412729Sdfr		semundo_clear(semid, -1);
6422729Sdfr		wakeup((caddr_t)semaptr);
6432729Sdfr		break;
6442729Sdfr
6452729Sdfr	default:
64682607Sdillon		error = EINVAL;
64782607Sdillon		break;
6482729Sdfr	}
6492729Sdfr
65082607Sdillon	if (error == 0)
65183366Sjulian		td->td_retval[0] = rval;
65282607Sdillondone2:
65382607Sdillon	mtx_unlock(&Giant);
65482607Sdillon	return(error);
6552729Sdfr}
6562729Sdfr
65712866Speter#ifndef _SYS_SYSPROTO_H_
6582729Sdfrstruct semget_args {
6592729Sdfr	key_t	key;
6602729Sdfr	int	nsems;
6612729Sdfr	int	semflg;
6622729Sdfr};
66312866Speter#endif
6642729Sdfr
66582607Sdillon/*
66682607Sdillon * MPSAFE
66782607Sdillon */
66812866Speterint
66983366Sjuliansemget(td, uap)
67083366Sjulian	struct thread *td;
6712729Sdfr	register struct semget_args *uap;
6722729Sdfr{
67382607Sdillon	int semid, error = 0;
6742729Sdfr	int key = uap->key;
6752729Sdfr	int nsems = uap->nsems;
6762729Sdfr	int semflg = uap->semflg;
67783366Sjulian	struct ucred *cred = td->td_proc->p_ucred;
6782729Sdfr
6792729Sdfr#ifdef SEM_DEBUG
6802729Sdfr	printf("semget(0x%x, %d, 0%o)\n", key, nsems, semflg);
6812729Sdfr#endif
68282607Sdillon	mtx_lock(&Giant);
68383366Sjulian	if (!jail_sysvipc_allowed && jailed(td->td_proc->p_ucred)) {
68482607Sdillon		error = ENOSYS;
68582607Sdillon		goto done2;
68682607Sdillon	}
68768024Srwatson
6882729Sdfr	if (key != IPC_PRIVATE) {
6892729Sdfr		for (semid = 0; semid < seminfo.semmni; semid++) {
6902729Sdfr			if ((sema[semid].sem_perm.mode & SEM_ALLOC) &&
6912729Sdfr			    sema[semid].sem_perm.key == key)
6922729Sdfr				break;
6932729Sdfr		}
6942729Sdfr		if (semid < seminfo.semmni) {
6952729Sdfr#ifdef SEM_DEBUG
6962729Sdfr			printf("found public key\n");
6972729Sdfr#endif
69883366Sjulian			if ((error = ipcperm(td, &sema[semid].sem_perm,
69982607Sdillon			    semflg & 0700))) {
70082607Sdillon				goto done2;
70182607Sdillon			}
7022729Sdfr			if (nsems > 0 && sema[semid].sem_nsems < nsems) {
7032729Sdfr#ifdef SEM_DEBUG
7042729Sdfr				printf("too small\n");
7052729Sdfr#endif
70682607Sdillon				error = EINVAL;
70782607Sdillon				goto done2;
7082729Sdfr			}
7092729Sdfr			if ((semflg & IPC_CREAT) && (semflg & IPC_EXCL)) {
7102729Sdfr#ifdef SEM_DEBUG
7112729Sdfr				printf("not exclusive\n");
7122729Sdfr#endif
71382607Sdillon				error = EEXIST;
71482607Sdillon				goto done2;
7152729Sdfr			}
7162729Sdfr			goto found;
7172729Sdfr		}
7182729Sdfr	}
7192729Sdfr
7202729Sdfr#ifdef SEM_DEBUG
7212729Sdfr	printf("need to allocate the semid_ds\n");
7222729Sdfr#endif
7232729Sdfr	if (key == IPC_PRIVATE || (semflg & IPC_CREAT)) {
7242729Sdfr		if (nsems <= 0 || nsems > seminfo.semmsl) {
7252729Sdfr#ifdef SEM_DEBUG
7262729Sdfr			printf("nsems out of range (0<%d<=%d)\n", nsems,
7272729Sdfr			    seminfo.semmsl);
7282729Sdfr#endif
72982607Sdillon			error = EINVAL;
73082607Sdillon			goto done2;
7312729Sdfr		}
7322729Sdfr		if (nsems > seminfo.semmns - semtot) {
7332729Sdfr#ifdef SEM_DEBUG
7342729Sdfr			printf("not enough semaphores left (need %d, got %d)\n",
7352729Sdfr			    nsems, seminfo.semmns - semtot);
7362729Sdfr#endif
73782607Sdillon			error = ENOSPC;
73882607Sdillon			goto done2;
7392729Sdfr		}
7402729Sdfr		for (semid = 0; semid < seminfo.semmni; semid++) {
7412729Sdfr			if ((sema[semid].sem_perm.mode & SEM_ALLOC) == 0)
7422729Sdfr				break;
7432729Sdfr		}
7442729Sdfr		if (semid == seminfo.semmni) {
7452729Sdfr#ifdef SEM_DEBUG
7462729Sdfr			printf("no more semid_ds's available\n");
7472729Sdfr#endif
74882607Sdillon			error = ENOSPC;
74982607Sdillon			goto done2;
7502729Sdfr		}
7512729Sdfr#ifdef SEM_DEBUG
7522729Sdfr		printf("semid %d is available\n", semid);
7532729Sdfr#endif
7542729Sdfr		sema[semid].sem_perm.key = key;
7552729Sdfr		sema[semid].sem_perm.cuid = cred->cr_uid;
7562729Sdfr		sema[semid].sem_perm.uid = cred->cr_uid;
7572729Sdfr		sema[semid].sem_perm.cgid = cred->cr_gid;
7582729Sdfr		sema[semid].sem_perm.gid = cred->cr_gid;
7592729Sdfr		sema[semid].sem_perm.mode = (semflg & 0777) | SEM_ALLOC;
7602729Sdfr		sema[semid].sem_perm.seq =
7612729Sdfr		    (sema[semid].sem_perm.seq + 1) & 0x7fff;
7622729Sdfr		sema[semid].sem_nsems = nsems;
7632729Sdfr		sema[semid].sem_otime = 0;
76434961Sphk		sema[semid].sem_ctime = time_second;
7652729Sdfr		sema[semid].sem_base = &sem[semtot];
7662729Sdfr		semtot += nsems;
7672729Sdfr		bzero(sema[semid].sem_base,
7682729Sdfr		    sizeof(sema[semid].sem_base[0])*nsems);
7692729Sdfr#ifdef SEM_DEBUG
7702729Sdfr		printf("sembase = 0x%x, next = 0x%x\n", sema[semid].sem_base,
7712729Sdfr		    &sem[semtot]);
7722729Sdfr#endif
7732729Sdfr	} else {
7742729Sdfr#ifdef SEM_DEBUG
7752729Sdfr		printf("didn't find it and wasn't asked to create it\n");
7762729Sdfr#endif
77782607Sdillon		error = ENOENT;
77882607Sdillon		goto done2;
7792729Sdfr	}
7802729Sdfr
7812729Sdfrfound:
78283366Sjulian	td->td_retval[0] = IXSEQ_TO_IPCID(semid, sema[semid].sem_perm);
78382607Sdillondone2:
78482607Sdillon	mtx_unlock(&Giant);
78582607Sdillon	return (error);
7862729Sdfr}
7872729Sdfr
78812866Speter#ifndef _SYS_SYSPROTO_H_
7892729Sdfrstruct semop_args {
7902729Sdfr	int	semid;
7912729Sdfr	struct	sembuf *sops;
79283292Sdd	u_int	nsops;
7932729Sdfr};
79412866Speter#endif
7952729Sdfr
79682607Sdillon/*
79782607Sdillon * MPSAFE
79882607Sdillon */
79912866Speterint
80083366Sjuliansemop(td, uap)
80183366Sjulian	struct thread *td;
8022729Sdfr	register struct semop_args *uap;
8032729Sdfr{
8042729Sdfr	int semid = uap->semid;
80583292Sdd	u_int nsops = uap->nsops;
8062729Sdfr	struct sembuf sops[MAX_SOPS];
8072729Sdfr	register struct semid_ds *semaptr;
8082729Sdfr	register struct sembuf *sopptr;
8092729Sdfr	register struct sem *semptr;
8102729Sdfr	struct sem_undo *suptr = NULL;
81182607Sdillon	int i, j, error = 0;
8123308Sphk	int do_wakeup, do_undos;
8132729Sdfr
8142729Sdfr#ifdef SEM_DEBUG
81583292Sdd	printf("call to semop(%d, 0x%x, %u)\n", semid, sops, nsops);
8162729Sdfr#endif
8172729Sdfr
81882607Sdillon	mtx_lock(&Giant);
81983366Sjulian	if (!jail_sysvipc_allowed && jailed(td->td_proc->p_ucred)) {
82082607Sdillon		error = ENOSYS;
82182607Sdillon		goto done2;
82282607Sdillon	}
82382607Sdillon
8242729Sdfr	semid = IPCID_TO_IX(semid);	/* Convert back to zero origin */
8252729Sdfr
82682607Sdillon	if (semid < 0 || semid >= seminfo.semmsl) {
82782607Sdillon		error = EINVAL;
82882607Sdillon		goto done2;
82982607Sdillon	}
8302729Sdfr
8312729Sdfr	semaptr = &sema[semid];
83282607Sdillon	if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0) {
83382607Sdillon		error = EINVAL;
83482607Sdillon		goto done2;
83582607Sdillon	}
83682607Sdillon	if (semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid)) {
83782607Sdillon		error = EINVAL;
83882607Sdillon		goto done2;
83982607Sdillon	}
8402729Sdfr
84183366Sjulian	if ((error = ipcperm(td, &semaptr->sem_perm, IPC_W))) {
8422729Sdfr#ifdef SEM_DEBUG
84383341Sdd		printf("error = %d from ipcperm\n", error);
8442729Sdfr#endif
84582607Sdillon		goto done2;
8462729Sdfr	}
8472729Sdfr
8482729Sdfr	if (nsops > MAX_SOPS) {
8492729Sdfr#ifdef SEM_DEBUG
85083292Sdd		printf("too many sops (max=%d, nsops=%u)\n", MAX_SOPS, nsops);
8512729Sdfr#endif
85282607Sdillon		error = E2BIG;
85382607Sdillon		goto done2;
8542729Sdfr	}
8552729Sdfr
85682607Sdillon	if ((error = copyin(uap->sops, &sops, nsops * sizeof(sops[0]))) != 0) {
8572729Sdfr#ifdef SEM_DEBUG
85883292Sdd		printf("error = %d from copyin(%08x, %08x, %u)\n", error,
8592729Sdfr		    uap->sops, &sops, nsops * sizeof(sops[0]));
8602729Sdfr#endif
86182607Sdillon		goto done2;
8622729Sdfr	}
8632729Sdfr
8648876Srgrimes	/*
8652729Sdfr	 * Loop trying to satisfy the vector of requests.
8662729Sdfr	 * If we reach a point where we must wait, any requests already
8672729Sdfr	 * performed are rolled back and we go to sleep until some other
8682729Sdfr	 * process wakes us up.  At this point, we start all over again.
8692729Sdfr	 *
8702729Sdfr	 * This ensures that from the perspective of other tasks, a set
8712729Sdfr	 * of requests is atomic (never partially satisfied).
8722729Sdfr	 */
8732729Sdfr	do_undos = 0;
8742729Sdfr
8752729Sdfr	for (;;) {
8762729Sdfr		do_wakeup = 0;
8772729Sdfr
8782729Sdfr		for (i = 0; i < nsops; i++) {
8792729Sdfr			sopptr = &sops[i];
8802729Sdfr
88182607Sdillon			if (sopptr->sem_num >= semaptr->sem_nsems) {
88282607Sdillon				error = EFBIG;
88382607Sdillon				goto done2;
88482607Sdillon			}
8852729Sdfr
8862729Sdfr			semptr = &semaptr->sem_base[sopptr->sem_num];
8872729Sdfr
8882729Sdfr#ifdef SEM_DEBUG
8892729Sdfr			printf("semop:  semaptr=%x, sem_base=%x, semptr=%x, sem[%d]=%d : op=%d, flag=%s\n",
8902729Sdfr			    semaptr, semaptr->sem_base, semptr,
8912729Sdfr			    sopptr->sem_num, semptr->semval, sopptr->sem_op,
8922729Sdfr			    (sopptr->sem_flg & IPC_NOWAIT) ? "nowait" : "wait");
8932729Sdfr#endif
8942729Sdfr
8952729Sdfr			if (sopptr->sem_op < 0) {
8962729Sdfr				if (semptr->semval + sopptr->sem_op < 0) {
8972729Sdfr#ifdef SEM_DEBUG
8982729Sdfr					printf("semop:  can't do it now\n");
8992729Sdfr#endif
9002729Sdfr					break;
9012729Sdfr				} else {
9022729Sdfr					semptr->semval += sopptr->sem_op;
9032729Sdfr					if (semptr->semval == 0 &&
9042729Sdfr					    semptr->semzcnt > 0)
9052729Sdfr						do_wakeup = 1;
9062729Sdfr				}
9072729Sdfr				if (sopptr->sem_flg & SEM_UNDO)
9082729Sdfr					do_undos = 1;
9092729Sdfr			} else if (sopptr->sem_op == 0) {
9102729Sdfr				if (semptr->semval > 0) {
9112729Sdfr#ifdef SEM_DEBUG
9122729Sdfr					printf("semop:  not zero now\n");
9132729Sdfr#endif
9142729Sdfr					break;
9152729Sdfr				}
9162729Sdfr			} else {
9172729Sdfr				if (semptr->semncnt > 0)
9182729Sdfr					do_wakeup = 1;
9192729Sdfr				semptr->semval += sopptr->sem_op;
9202729Sdfr				if (sopptr->sem_flg & SEM_UNDO)
9212729Sdfr					do_undos = 1;
9222729Sdfr			}
9232729Sdfr		}
9242729Sdfr
9252729Sdfr		/*
9262729Sdfr		 * Did we get through the entire vector?
9272729Sdfr		 */
9282729Sdfr		if (i >= nsops)
9292729Sdfr			goto done;
9302729Sdfr
9312729Sdfr		/*
9322729Sdfr		 * No ... rollback anything that we've already done
9332729Sdfr		 */
9342729Sdfr#ifdef SEM_DEBUG
9352729Sdfr		printf("semop:  rollback 0 through %d\n", i-1);
9362729Sdfr#endif
9372729Sdfr		for (j = 0; j < i; j++)
9382729Sdfr			semaptr->sem_base[sops[j].sem_num].semval -=
9392729Sdfr			    sops[j].sem_op;
9402729Sdfr
9412729Sdfr		/*
9422729Sdfr		 * If the request that we couldn't satisfy has the
9432729Sdfr		 * NOWAIT flag set then return with EAGAIN.
9442729Sdfr		 */
94582607Sdillon		if (sopptr->sem_flg & IPC_NOWAIT) {
94682607Sdillon			error = EAGAIN;
94782607Sdillon			goto done2;
94882607Sdillon		}
9492729Sdfr
9502729Sdfr		if (sopptr->sem_op == 0)
9512729Sdfr			semptr->semzcnt++;
9522729Sdfr		else
9532729Sdfr			semptr->semncnt++;
9542729Sdfr
9552729Sdfr#ifdef SEM_DEBUG
9562729Sdfr		printf("semop:  good night!\n");
9572729Sdfr#endif
95882607Sdillon		error = tsleep((caddr_t)semaptr, (PZERO - 4) | PCATCH,
9592729Sdfr		    "semwait", 0);
9602729Sdfr#ifdef SEM_DEBUG
96182607Sdillon		printf("semop:  good morning (error=%d)!\n", error);
9622729Sdfr#endif
9632729Sdfr
9642729Sdfr		suptr = NULL;	/* sem_undo may have been reallocated */
9652729Sdfr
96682607Sdillon		if (error != 0) {
96782607Sdillon			error = EINTR;
96882607Sdillon			goto done2;
96982607Sdillon		}
9702729Sdfr#ifdef SEM_DEBUG
9712729Sdfr		printf("semop:  good morning!\n");
9722729Sdfr#endif
9732729Sdfr
9742729Sdfr		/*
9752729Sdfr		 * Make sure that the semaphore still exists
9762729Sdfr		 */
9772729Sdfr		if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0 ||
97882607Sdillon		    semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid)) {
97982607Sdillon			error = EIDRM;
98082607Sdillon			goto done2;
98182607Sdillon		}
9822729Sdfr
9832729Sdfr		/*
9842729Sdfr		 * The semaphore is still alive.  Readjust the count of
9852729Sdfr		 * waiting processes.
9862729Sdfr		 */
9872729Sdfr		if (sopptr->sem_op == 0)
9882729Sdfr			semptr->semzcnt--;
9892729Sdfr		else
9902729Sdfr			semptr->semncnt--;
9912729Sdfr	}
9922729Sdfr
9932729Sdfrdone:
9942729Sdfr	/*
9952729Sdfr	 * Process any SEM_UNDO requests.
9962729Sdfr	 */
9972729Sdfr	if (do_undos) {
9982729Sdfr		for (i = 0; i < nsops; i++) {
9992729Sdfr			/*
10002729Sdfr			 * We only need to deal with SEM_UNDO's for non-zero
10012729Sdfr			 * op's.
10022729Sdfr			 */
10032729Sdfr			int adjval;
10042729Sdfr
10052729Sdfr			if ((sops[i].sem_flg & SEM_UNDO) == 0)
10062729Sdfr				continue;
10072729Sdfr			adjval = sops[i].sem_op;
10082729Sdfr			if (adjval == 0)
10092729Sdfr				continue;
101083366Sjulian			error = semundo_adjust(td, &suptr, semid,
10112729Sdfr			    sops[i].sem_num, -adjval);
101282607Sdillon			if (error == 0)
10132729Sdfr				continue;
10142729Sdfr
10152729Sdfr			/*
10162729Sdfr			 * Oh-Oh!  We ran out of either sem_undo's or undo's.
10172729Sdfr			 * Rollback the adjustments to this point and then
10182729Sdfr			 * rollback the semaphore ups and down so we can return
10192729Sdfr			 * with an error with all structures restored.  We
10202729Sdfr			 * rollback the undo's in the exact reverse order that
10212729Sdfr			 * we applied them.  This guarantees that we won't run
10222729Sdfr			 * out of space as we roll things back out.
10232729Sdfr			 */
10242729Sdfr			for (j = i - 1; j >= 0; j--) {
10252729Sdfr				if ((sops[j].sem_flg & SEM_UNDO) == 0)
10262729Sdfr					continue;
10272729Sdfr				adjval = sops[j].sem_op;
10282729Sdfr				if (adjval == 0)
10292729Sdfr					continue;
103083366Sjulian				if (semundo_adjust(td, &suptr, semid,
10312729Sdfr				    sops[j].sem_num, adjval) != 0)
10322729Sdfr					panic("semop - can't undo undos");
10332729Sdfr			}
10342729Sdfr
10352729Sdfr			for (j = 0; j < nsops; j++)
10362729Sdfr				semaptr->sem_base[sops[j].sem_num].semval -=
10372729Sdfr				    sops[j].sem_op;
10382729Sdfr
10392729Sdfr#ifdef SEM_DEBUG
104082607Sdillon			printf("error = %d from semundo_adjust\n", error);
10412729Sdfr#endif
104282607Sdillon			goto done2;
10432729Sdfr		} /* loop through the sops */
10442729Sdfr	} /* if (do_undos) */
10452729Sdfr
10462729Sdfr	/* We're definitely done - set the sempid's */
10472729Sdfr	for (i = 0; i < nsops; i++) {
10482729Sdfr		sopptr = &sops[i];
10492729Sdfr		semptr = &semaptr->sem_base[sopptr->sem_num];
105083366Sjulian		semptr->sempid = td->td_proc->p_pid;
10512729Sdfr	}
10522729Sdfr
10532729Sdfr	/* Do a wakeup if any semaphore was up'd. */
10542729Sdfr	if (do_wakeup) {
10552729Sdfr#ifdef SEM_DEBUG
10562729Sdfr		printf("semop:  doing wakeup\n");
105758831Speter#endif
10582729Sdfr		wakeup((caddr_t)semaptr);
105958831Speter#ifdef SEM_DEBUG
10602729Sdfr		printf("semop:  back from wakeup\n");
10612729Sdfr#endif
10622729Sdfr	}
10632729Sdfr#ifdef SEM_DEBUG
10642729Sdfr	printf("semop:  done\n");
10652729Sdfr#endif
106683366Sjulian	td->td_retval[0] = 0;
106782607Sdillondone2:
106882607Sdillon	mtx_unlock(&Giant);
106982607Sdillon	return (error);
10702729Sdfr}
10712729Sdfr
10722729Sdfr/*
10732729Sdfr * Go through the undo structures for this process and apply the adjustments to
10742729Sdfr * semaphores.
10752729Sdfr */
107669449Salfredstatic void
107769449Salfredsemexit_myhook(p)
10782729Sdfr	struct proc *p;
10792729Sdfr{
10802729Sdfr	register struct sem_undo *suptr;
10812729Sdfr	register struct sem_undo **supptr;
10822729Sdfr	int did_something;
10832729Sdfr
10842729Sdfr	did_something = 0;
10852729Sdfr
10862729Sdfr	/*
10872729Sdfr	 * Go through the chain of undo vectors looking for one
10882729Sdfr	 * associated with this process.
10892729Sdfr	 */
10902729Sdfr
10912729Sdfr	for (supptr = &semu_list; (suptr = *supptr) != NULL;
10922729Sdfr	    supptr = &suptr->un_next) {
10932729Sdfr		if (suptr->un_proc == p)
10942729Sdfr			break;
10952729Sdfr	}
10962729Sdfr
10972729Sdfr	if (suptr == NULL)
109859828Speter		return;
10992729Sdfr
11002729Sdfr#ifdef SEM_DEBUG
11012729Sdfr	printf("proc @%08x has undo structure with %d entries\n", p,
11022729Sdfr	    suptr->un_cnt);
11032729Sdfr#endif
11042729Sdfr
11052729Sdfr	/*
11062729Sdfr	 * If there are any active undo elements then process them.
11072729Sdfr	 */
11082729Sdfr	if (suptr->un_cnt > 0) {
11092729Sdfr		int ix;
11102729Sdfr
11112729Sdfr		for (ix = 0; ix < suptr->un_cnt; ix++) {
11122729Sdfr			int semid = suptr->un_ent[ix].un_id;
11132729Sdfr			int semnum = suptr->un_ent[ix].un_num;
11142729Sdfr			int adjval = suptr->un_ent[ix].un_adjval;
11152729Sdfr			struct semid_ds *semaptr;
11162729Sdfr
11172729Sdfr			semaptr = &sema[semid];
11182729Sdfr			if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0)
11192729Sdfr				panic("semexit - semid not allocated");
11202729Sdfr			if (semnum >= semaptr->sem_nsems)
11212729Sdfr				panic("semexit - semnum out of range");
11222729Sdfr
11232729Sdfr#ifdef SEM_DEBUG
11242729Sdfr			printf("semexit:  %08x id=%d num=%d(adj=%d) ; sem=%d\n",
11252729Sdfr			    suptr->un_proc, suptr->un_ent[ix].un_id,
11262729Sdfr			    suptr->un_ent[ix].un_num,
11272729Sdfr			    suptr->un_ent[ix].un_adjval,
11282729Sdfr			    semaptr->sem_base[semnum].semval);
11292729Sdfr#endif
11302729Sdfr
11312729Sdfr			if (adjval < 0) {
11322729Sdfr				if (semaptr->sem_base[semnum].semval < -adjval)
11332729Sdfr					semaptr->sem_base[semnum].semval = 0;
11342729Sdfr				else
11352729Sdfr					semaptr->sem_base[semnum].semval +=
11362729Sdfr					    adjval;
11372729Sdfr			} else
11382729Sdfr				semaptr->sem_base[semnum].semval += adjval;
11392729Sdfr
11402729Sdfr			wakeup((caddr_t)semaptr);
11412729Sdfr#ifdef SEM_DEBUG
11422729Sdfr			printf("semexit:  back from wakeup\n");
11432729Sdfr#endif
11442729Sdfr		}
11452729Sdfr	}
11462729Sdfr
11472729Sdfr	/*
11482729Sdfr	 * Deallocate the undo vector.
11492729Sdfr	 */
11502729Sdfr#ifdef SEM_DEBUG
11512729Sdfr	printf("removing vector\n");
11522729Sdfr#endif
11532729Sdfr	suptr->un_proc = NULL;
11542729Sdfr	*supptr = suptr->un_next;
11552729Sdfr}
115677461Sdd
115777461Sddstatic int
115877461Sddsysctl_sema(SYSCTL_HANDLER_ARGS)
115977461Sdd{
116077461Sdd
116177461Sdd	return (SYSCTL_OUT(req, sema,
116277461Sdd	    sizeof(struct semid_ds) * seminfo.semmni));
116377461Sdd}
1164