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