diff --git a/lib/libc/sys/semctl.2 b/lib/libc/sys/semctl.2 index 4e3765c6349b..69503710fb06 100644 --- a/lib/libc/sys/semctl.2 +++ b/lib/libc/sys/semctl.2 @@ -1,180 +1,196 @@ .\" .\" Copyright (c) 1995 David Hovemeyer .\" .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR .\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES .\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. .\" IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT, .\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT .\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .\" $FreeBSD$ .\" .Dd September 12, 1995 .Dt SEMCTL 2 .Os .Sh NAME .Nm semctl .Nd control operations on a semaphore set .Sh LIBRARY .Lb libc .Sh SYNOPSIS .In sys/types.h .In sys/ipc.h .In sys/sem.h .Ft int .Fn semctl "int semid" "int semnum" "int cmd" ... .Sh DESCRIPTION .Fn Semctl performs the operation indicated by .Fa cmd on the semaphore set indicated by .Fa semid . A fourth argument, a .Fa "union semun arg" , is required for certain values of .Fa cmd . For the commands that use the .Fa arg parameter, .Fa "union semun" is defined as follows: .Bd -literal .\" .\" From : .\" union semun { int val; /* value for SETVAL */ struct semid_ds *buf; /* buffer for IPC_STAT & IPC_SET */ u_short *array; /* array for GETALL & SETALL */ }; .Ed .Pp Commands are performed as follows: .\" .\" This section based on Stevens, _Advanced Programming in the UNIX .\" Environment_. .\" .Bl -tag -width IPC_RMIDXXX .It Dv IPC_STAT Fetch the semaphore set's .Fa "struct semid_ds" , storing it in the memory pointed to by .Fa arg.buf . .It Dv IPC_SET Changes the .Fa sem_perm.uid , .Fa sem_perm.gid , and .Fa sem_perm.mode members of the semaphore set's .Fa "struct semid_ds" to match those of the struct pointed to by .Fa arg.buf . The calling process's effective uid must match either .Fa sem_perm.uid or .Fa sem_perm.cuid , or it must have superuser privileges. .It IPC_RMID Immediately removes the semaphore set from the system. The calling process's effective uid must equal the semaphore set's .Fa sem_perm.uid or .Fa sem_perm.cuid , or the process must have superuser privileges. .It Dv GETVAL Return the value of semaphore number .Fa semnum . .It Dv SETVAL Set the value of semaphore number .Fa semnum to .Fa arg.val . +Outstanding adjust on exit values for this semaphore in any process +are cleared. .It Dv GETPID Return the pid of the last process to perform an operation on semaphore number .Fa semnum . .It Dv GETNCNT Return the number of processes waiting for semaphore number .Fa semnum Ns 's value to become greater than its current value. .It Dv GETZCNT Return the number of processes waiting for semaphore number .Fa semnum Ns 's value to become 0. .It Dv GETALL Fetch the value of all of the semaphores in the set into the array pointed to by .Fa arg.array . .It Dv SETALL Set the values of all of the semaphores in the set to the values in the array pointed to by .Fa arg.array . +Outstanding adjust on exit values for all semaphores in this set, +in any process are cleared. .El .Pp The .Fa "struct semid_ds" is defined as follows: .Bd -literal .\" .\" Taken straight from . .\" struct semid_ds { struct ipc_perm sem_perm; /* operation permission struct */ struct sem *sem_base; /* pointer to first semaphore in set */ u_short sem_nsems; /* number of sems in set */ time_t sem_otime; /* last operation time */ long sem_pad1; /* SVABI/386 says I need this here */ time_t sem_ctime; /* last change time */ /* Times measured in secs since */ /* 00:00:00 GMT, Jan. 1, 1970 */ long sem_pad2; /* SVABI/386 says I need this here */ long sem_pad3[4]; /* SVABI/386 says I need this here */ }; .Ed .Sh RETURN VALUES On success, when .Fa cmd -is one of GETVAL, GETNCNT, or GETZCNT, +is one of +.Dv GETVAL , GETNCNT +or +.Dv GETZCNT , .Fn semctl returns the corresponding value; otherwise, 0 is returned. On failure, -1 is returned, and .Va errno is set to indicate the error. .Sh ERRORS .Fn Semctl will fail if: .Bl -tag -width Er .It Bq Er EINVAL No semaphore set corresponds to .Fa semid . .It Bq Er EINVAL .Fa semnum is not in the range of valid semaphores for given semaphore set. .It Bq Er EPERM The calling process's effective uid does not match the uid of the semaphore set's owner or creator. .It Bq Er EACCES Permission denied due to mismatch between operation and mode of semaphore set. +.It Bq Er ERANGE +.Dv SETVAL +or +.Dv SETALL +attempted to set a semaphore outside the allowable range +.Bq 0 .. Dv SEMVMX . .El .Sh SEE ALSO .Xr semget 2 , .Xr semop 2 +.Sh BUGS +.Dv SETALL +may update some semaphore elements before returning an error. diff --git a/lib/libc/sys/semop.2 b/lib/libc/sys/semop.2 index ac4e79c67b72..4e80f7cd057f 100644 --- a/lib/libc/sys/semop.2 +++ b/lib/libc/sys/semop.2 @@ -1,193 +1,274 @@ .\" .\" Copyright (c) 1995 David Hovemeyer .\" .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR .\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES .\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. .\" IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT, .\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT .\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .\" $FreeBSD$ .\" .Dd September 22, 1995 .Dt SEMOP 2 .Os .Sh NAME .Nm semop .Nd atomic array of operations on a semaphore set .Sh LIBRARY .Lb libc .Sh SYNOPSIS .In sys/types.h .In sys/ipc.h .In sys/sem.h .Ft int .Fn semop "int semid" "struct sembuf array[]" "unsigned nops" .Sh DESCRIPTION .Fn Semop atomically performs the array of operations indicated by .Fa array on the semaphore set indicated by .Fa semid . The length of .Fa array is indicated by .Fa nops . Each operation is encoded in a .Fa "struct sembuf" , which is defined as follows: .Bd -literal .\" .\" From .\" struct sembuf { u_short sem_num; /* semaphore # */ short sem_op; /* semaphore operation */ short sem_flg; /* operation flags */ }; .Ed .Pp For each element in .Fa array , .Fa sem_op and .Fa sem_flg determine an operation to be performed on semaphore number .Fa sem_num -in the set. The values SEM_UNDO and IPC_NOWAIT may be +in the set. The values +.Dv SEM_UNDO +and +.Dv IPC_NOWAIT +may be .Em OR Ns 'ed into the .Fa sem_flg member in order to modify the behavior of the given operation. .Pp The operation performed depends as follows on the value of .Fa sem_op : .\" .\" This section is based on the description of semop() in -.\" Stevens, _Advanced Programming in the UNIX Environment_. +.\" Stevens, _Advanced Programming in the UNIX Environment_, +.\" and the semop(2) description in The Open Group Unix2 specification. .\" .Bl -bullet .It When .Fa sem_op -is positive, the semaphore's value is incremented by +is positive and the process has alter permission, +the semaphore's value is incremented by .Fa sem_op Ns 's -value. If SEM_UNDO is specified, the semaphore's adjust on exit -value is decremented by +value. If +.Dv SEM_UNDO +is specified, the semaphore's adjust on exit value is decremented by .Fa sem_op Ns 's value. A positive value for .Fa sem_op generally corresponds to a process releasing a resource associated with the semaphore. .It The behavior when .Fa sem_op -is negative depends on the current value of the semaphore: +is negative and the process has alter permission, +depends on the current value of the semaphore: .Bl -bullet .It If the current value of the semaphore is greater than or equal to the absolute value of .Fa sem_op , then the value is decremented by the absolute value of .Fa sem_op . -If SEM_UNDO is specified, the semaphore's adjust on exit +If +.Dv SEM_UNDO +is specified, the semaphore's adjust on exit value is incremented by the absolute value of .Fa sem_op . .It -If the current value of the semaphore is less than -.Fa sem_op Ns 's -value, one of the following happens: +If the current value of the semaphore is less than the absolute value of +.Fa sem_op , +one of the following happens: .\" XXX a *second* sublist? .Bl -bullet .It -If IPC_NOWAIT was specified, then +If +.Dv IPC_NOWAIT +was specified, then .Fn semop returns immediately with a return value of .Er EAGAIN . .It -If some other process has removed the semaphore with the IPC_RMID +Otherwise, the calling process is put to sleep until one of the following +conditions is satisfied: +.\" XXX We already have two sublists, why not a third? +.Bl -bullet +.It +Some other process removes the semaphore with the +.Dv IPC_RMID option of -.Fn semctl , -then +.Fn semctl . +In this case, .Fn semop returns immediately with a return value of -.Er EINVAL . +.Er EIDRM . .It -Otherwise, the calling process is put to sleep until the semaphore's +The process receives a signal that is to be caught. +In this case, the process will resume execution as defined by +.Fn sigaction . +.It +The semaphore's value is greater than or equal to the absolute value of .Fa sem_op . When this condition becomes true, the semaphore's value is decremented by the absolute value of .Fa sem_op , -and the semaphore's adjust on exit value is incremented by the +the semaphore's adjust on exit value is incremented by the absolute value of .Fa sem_op . .El +.El .Pp A negative value for .Fa sem_op generally means that a process is waiting for a resource to become available. .El .Pp .It When .Fa sem_op -is zero, the process waits for the semaphore's value to become zero. -If it is already zero, the call to +is zero and the process has read permission, +one of the following will occur: +.Bl -bullet +.It +If the current value of the semaphore is equal to zero +then .Fn semop -can return immediately. Otherwise, the calling process is put to -sleep until the semaphore's value becomes zero. +can return immediately. +.It +If +.Dv IPC_NOWAIT +was specified, then +.Fn semop +returns immediately with a return value of +.Er EAGAIN . +.It +Otherwise, the calling process is put to sleep until one of the following +conditions is satisfied: +.\" XXX Another nested sublists +.Bl -bullet +.It +Some other process removes the semaphore with the +.Dv IPC_RMID +option of +.Fn semctl . +In this case, +.Fn semop +returns immediately with a return value of +.Er EIDRM . +.It +The process receives a signal that is to be caught. +In this case, the process will resume execution as defined by +.Fn sigaction +.It +The semaphore's value becomes zero. +.El .El .Pp For each semaphore a process has in use, the kernel maintains an `adjust on exit' value, as alluded to earlier. When a process exits, either voluntarily or involuntarily, the adjust on exit value for each semaphore is added to the semaphore's value. This can be used to insure that a resource is released if a process terminates unexpectedly. .Sh RETURN VALUES .Rv -std semop .Sh ERRORS .Fn Semop will fail if: .Bl -tag -width Er .It Bq Er EINVAL No semaphore set corresponds to -.Fa semid . +.Fa semid , +or the process would exceed the system-defined limit for the number of +per-process SEM_UNDO structures. .It Bq Er EACCES Permission denied due to mismatch between operation and mode of semaphore set. .It Bq Er EAGAIN -The semaphore's value was less than -.Fa sem_op , -and IPC_NOWAIT was specified. +The semaphore's value would have resulted in the process being put to sleep +and +.Dv IPC_NOWAIT +was specified. .It Bq Er E2BIG Too many operations were specified. +.Bq Dv SEMOPM .It Bq Er EFBIG .\" .\" I'd have thought this would be EINVAL, but the source says .\" EFBIG. .\" .Fa sem_num was not in the range of valid semaphores for the set. +.It Bq Er EIDRM +The semaphore set was removed from the system. +.It Bq Er EINTR +The +.Fn semop +call was interrupted by a signal. +.It Bq Er ENOSPC +The system SEM_UNDO pool +.Bq Dv SEMMNU +is full. +.It Bq Er ERANGE +The requested operation would cause either +the semaphore's current value +.Bq Dv SEMVMX +or its adjust on exit value +.Bq Dv SEMAEM +to exceed the system-imposed limits. .El .Sh SEE ALSO .Xr semctl 2 , -.Xr semget 2 +.Xr semget 2 , +.Xr sigaction 2 +.Sh BUGS +.Fn Semop +may block waiting for memory even if +.Dv IPC_NOWAIT +is specified. diff --git a/sys/kern/sysv_sem.c b/sys/kern/sysv_sem.c index 81e00b8b7d1a..fef57560643b 100644 --- a/sys/kern/sysv_sem.c +++ b/sys/kern/sysv_sem.c @@ -1,1182 +1,1217 @@ /* $FreeBSD$ */ /* * Implementation of SVID semaphores * * Author: Daniel Boulet * * This software is provided ``AS IS'' without any warranties of any kind. */ #include "opt_sysvipc.h" #include #include #include #include #include #include #include #include #include #include #include #include #include static MALLOC_DEFINE(M_SEM, "sem", "SVID compatible semaphores"); static void seminit __P((void)); static int sysvsem_modload __P((struct module *, int, void *)); static int semunload __P((void)); static void semexit_myhook __P((struct proc *p)); static int sysctl_sema __P((SYSCTL_HANDLER_ARGS)); #ifndef _SYS_SYSPROTO_H_ struct __semctl_args; int __semctl __P((struct thread *td, struct __semctl_args *uap)); struct semget_args; int semget __P((struct thread *td, struct semget_args *uap)); struct semop_args; int semop __P((struct thread *td, struct semop_args *uap)); #endif static struct sem_undo *semu_alloc __P((struct thread *td)); static int semundo_adjust __P((struct thread *td, struct sem_undo **supptr, int semid, int semnum, int adjval)); static void semundo_clear __P((int semid, int semnum)); /* XXX casting to (sy_call_t *) is bogus, as usual. */ static sy_call_t *semcalls[] = { (sy_call_t *)__semctl, (sy_call_t *)semget, (sy_call_t *)semop }; static int semtot = 0; static struct semid_ds *sema; /* semaphore id pool */ static struct sem *sem; /* semaphore pool */ static struct sem_undo *semu_list; /* list of active undo structures */ static int *semu; /* undo structure pool */ struct sem { u_short semval; /* semaphore value */ pid_t sempid; /* pid of last operation */ u_short semncnt; /* # awaiting semval > cval */ u_short semzcnt; /* # awaiting semval = 0 */ }; /* * Undo structure (one per process) */ struct sem_undo { struct sem_undo *un_next; /* ptr to next active undo structure */ struct proc *un_proc; /* owner of this structure */ short un_cnt; /* # of active entries */ struct undo { short un_adjval; /* adjust on exit values */ short un_num; /* semaphore # */ int un_id; /* semid */ } un_ent[1]; /* undo entries */ }; /* * Configuration parameters */ #ifndef SEMMNI #define SEMMNI 10 /* # of semaphore identifiers */ #endif #ifndef SEMMNS #define SEMMNS 60 /* # of semaphores in system */ #endif #ifndef SEMUME #define SEMUME 10 /* max # of undo entries per process */ #endif #ifndef SEMMNU #define SEMMNU 30 /* # of undo structures in system */ #endif /* shouldn't need tuning */ #ifndef SEMMAP #define SEMMAP 30 /* # of entries in semaphore map */ #endif #ifndef SEMMSL #define SEMMSL SEMMNS /* max # of semaphores per id */ #endif #ifndef SEMOPM #define SEMOPM 100 /* max # of operations per semop call */ #endif #define SEMVMX 32767 /* semaphore maximum value */ #define SEMAEM 16384 /* adjust on exit max value */ /* * Due to the way semaphore memory is allocated, we have to ensure that * SEMUSZ is properly aligned. */ #define SEM_ALIGN(bytes) (((bytes) + (sizeof(long) - 1)) & ~(sizeof(long) - 1)) /* actual size of an undo structure */ #define SEMUSZ SEM_ALIGN(offsetof(struct sem_undo, un_ent[SEMUME])) /* * Macro to find a particular sem_undo vector */ #define SEMU(ix) ((struct sem_undo *)(((intptr_t)semu)+ix * seminfo.semusz)) /* * semaphore info struct */ struct seminfo seminfo = { SEMMAP, /* # of entries in semaphore map */ SEMMNI, /* # of semaphore identifiers */ SEMMNS, /* # of semaphores in system */ SEMMNU, /* # of undo structures in system */ SEMMSL, /* max # of semaphores per id */ SEMOPM, /* max # of operations per semop call */ SEMUME, /* max # of undo entries per process */ SEMUSZ, /* size in bytes of undo structure */ SEMVMX, /* semaphore maximum value */ SEMAEM /* adjust on exit max value */ }; SYSCTL_DECL(_kern_ipc); SYSCTL_INT(_kern_ipc, OID_AUTO, semmap, CTLFLAG_RW, &seminfo.semmap, 0, ""); SYSCTL_INT(_kern_ipc, OID_AUTO, semmni, CTLFLAG_RD, &seminfo.semmni, 0, ""); SYSCTL_INT(_kern_ipc, OID_AUTO, semmns, CTLFLAG_RD, &seminfo.semmns, 0, ""); SYSCTL_INT(_kern_ipc, OID_AUTO, semmnu, CTLFLAG_RD, &seminfo.semmnu, 0, ""); SYSCTL_INT(_kern_ipc, OID_AUTO, semmsl, CTLFLAG_RW, &seminfo.semmsl, 0, ""); SYSCTL_INT(_kern_ipc, OID_AUTO, semopm, CTLFLAG_RD, &seminfo.semopm, 0, ""); SYSCTL_INT(_kern_ipc, OID_AUTO, semume, CTLFLAG_RD, &seminfo.semume, 0, ""); SYSCTL_INT(_kern_ipc, OID_AUTO, semusz, CTLFLAG_RD, &seminfo.semusz, 0, ""); SYSCTL_INT(_kern_ipc, OID_AUTO, semvmx, CTLFLAG_RW, &seminfo.semvmx, 0, ""); SYSCTL_INT(_kern_ipc, OID_AUTO, semaem, CTLFLAG_RW, &seminfo.semaem, 0, ""); SYSCTL_PROC(_kern_ipc, OID_AUTO, sema, CTLFLAG_RD, NULL, 0, sysctl_sema, "", ""); #if 0 RO seminfo.semmap /* SEMMAP unused */ RO seminfo.semmni RO seminfo.semmns RO seminfo.semmnu /* undo entries per system */ RW seminfo.semmsl RO seminfo.semopm /* SEMOPM unused */ RO seminfo.semume RO seminfo.semusz /* param - derived from SEMUME for per-proc sizeof */ RO seminfo.semvmx /* SEMVMX unused - user param */ RO seminfo.semaem /* SEMAEM unused - user param */ #endif static void seminit(void) { register int i; TUNABLE_INT_FETCH("kern.ipc.semmap", &seminfo.semmap); TUNABLE_INT_FETCH("kern.ipc.semmni", &seminfo.semmni); TUNABLE_INT_FETCH("kern.ipc.semmns", &seminfo.semmns); TUNABLE_INT_FETCH("kern.ipc.semmnu", &seminfo.semmnu); TUNABLE_INT_FETCH("kern.ipc.semmsl", &seminfo.semmsl); TUNABLE_INT_FETCH("kern.ipc.semopm", &seminfo.semopm); TUNABLE_INT_FETCH("kern.ipc.semume", &seminfo.semume); TUNABLE_INT_FETCH("kern.ipc.semusz", &seminfo.semusz); TUNABLE_INT_FETCH("kern.ipc.semvmx", &seminfo.semvmx); TUNABLE_INT_FETCH("kern.ipc.semaem", &seminfo.semaem); sem = malloc(sizeof(struct sem) * seminfo.semmns, M_SEM, M_WAITOK); if (sem == NULL) panic("sem is NULL"); sema = malloc(sizeof(struct semid_ds) * seminfo.semmni, M_SEM, M_WAITOK); if (sema == NULL) panic("sema is NULL"); semu = malloc(seminfo.semmnu * seminfo.semusz, M_SEM, M_WAITOK); if (semu == NULL) panic("semu is NULL"); for (i = 0; i < seminfo.semmni; i++) { sema[i].sem_base = 0; sema[i].sem_perm.mode = 0; } for (i = 0; i < seminfo.semmnu; i++) { register struct sem_undo *suptr = SEMU(i); suptr->un_proc = NULL; } semu_list = NULL; semexit_hook = &semexit_myhook; } static int semunload(void) { if (semtot != 0) return (EBUSY); free(sem, M_SEM); free(sema, M_SEM); free(semu, M_SEM); semexit_hook = NULL; return (0); } static int sysvsem_modload(struct module *module, int cmd, void *arg) { int error = 0; switch (cmd) { case MOD_LOAD: seminit(); break; case MOD_UNLOAD: error = semunload(); break; case MOD_SHUTDOWN: break; default: error = EINVAL; break; } return (error); } static moduledata_t sysvsem_mod = { "sysvsem", &sysvsem_modload, NULL }; SYSCALL_MODULE_HELPER(semsys, 5); SYSCALL_MODULE_HELPER(__semctl, 4); SYSCALL_MODULE_HELPER(semget, 3); SYSCALL_MODULE_HELPER(semop, 3); DECLARE_MODULE(sysvsem, sysvsem_mod, SI_SUB_SYSV_SEM, SI_ORDER_FIRST); MODULE_VERSION(sysvsem, 1); /* * Entry point for all SEM calls * * MPSAFE */ int semsys(td, uap) struct thread *td; /* XXX actually varargs. */ struct semsys_args /* { u_int which; int a2; int a3; int a4; int a5; } */ *uap; { int error; mtx_lock(&Giant); if (!jail_sysvipc_allowed && jailed(td->td_proc->p_ucred)) { error = ENOSYS; goto done2; } if (uap->which >= sizeof(semcalls)/sizeof(semcalls[0])) { error = EINVAL; goto done2; } error = (*semcalls[uap->which])(td, &uap->a2); done2: mtx_unlock(&Giant); return (error); } /* * Allocate a new sem_undo structure for a process * (returns ptr to structure or NULL if no more room) */ static struct sem_undo * semu_alloc(td) struct thread *td; { register int i; register struct sem_undo *suptr; register struct sem_undo **supptr; int attempt; /* * Try twice to allocate something. * (we'll purge any empty structures after the first pass so * two passes are always enough) */ for (attempt = 0; attempt < 2; attempt++) { /* * Look for a free structure. * Fill it in and return it if we find one. */ for (i = 0; i < seminfo.semmnu; i++) { suptr = SEMU(i); if (suptr->un_proc == NULL) { suptr->un_next = semu_list; semu_list = suptr; suptr->un_cnt = 0; suptr->un_proc = td->td_proc; return(suptr); } } /* * We didn't find a free one, if this is the first attempt * then try to free some structures. */ if (attempt == 0) { /* All the structures are in use - try to free some */ int did_something = 0; supptr = &semu_list; while ((suptr = *supptr) != NULL) { if (suptr->un_cnt == 0) { suptr->un_proc = NULL; *supptr = suptr->un_next; did_something = 1; } else supptr = &(suptr->un_next); } /* If we didn't free anything then just give-up */ if (!did_something) return(NULL); } else { /* * The second pass failed even though we freed * something after the first pass! * This is IMPOSSIBLE! */ panic("semu_alloc - second attempt failed"); } } return (NULL); } /* * Adjust a particular entry for a particular proc */ static int semundo_adjust(td, supptr, semid, semnum, adjval) register struct thread *td; struct sem_undo **supptr; int semid, semnum; int adjval; { struct proc *p = td->td_proc; register struct sem_undo *suptr; register struct undo *sunptr; int i; /* Look for and remember the sem_undo if the caller doesn't provide it */ suptr = *supptr; if (suptr == NULL) { for (suptr = semu_list; suptr != NULL; suptr = suptr->un_next) { if (suptr->un_proc == p) { *supptr = suptr; break; } } if (suptr == NULL) { if (adjval == 0) return(0); suptr = semu_alloc(td); if (suptr == NULL) return(ENOSPC); *supptr = suptr; } } /* * Look for the requested entry and adjust it (delete if adjval becomes * 0). */ sunptr = &suptr->un_ent[0]; for (i = 0; i < suptr->un_cnt; i++, sunptr++) { if (sunptr->un_id != semid || sunptr->un_num != semnum) continue; - if (adjval == 0) - sunptr->un_adjval = 0; - else - sunptr->un_adjval += adjval; + if (adjval != 0) { + adjval += sunptr->un_adjval; + if (adjval > seminfo.semaem || adjval < -seminfo.semaem) + return (ERANGE); + } + sunptr->un_adjval = adjval; if (sunptr->un_adjval == 0) { suptr->un_cnt--; if (i < suptr->un_cnt) suptr->un_ent[i] = suptr->un_ent[suptr->un_cnt]; } return(0); } /* Didn't find the right entry - create it */ if (adjval == 0) return(0); + if (adjval > seminfo.semaem || adjval < -seminfo.semaem) + return (ERANGE); if (suptr->un_cnt != seminfo.semume) { sunptr = &suptr->un_ent[suptr->un_cnt]; suptr->un_cnt++; sunptr->un_adjval = adjval; sunptr->un_id = semid; sunptr->un_num = semnum; } else return(EINVAL); return(0); } static void semundo_clear(semid, semnum) int semid, semnum; { register struct sem_undo *suptr; for (suptr = semu_list; suptr != NULL; suptr = suptr->un_next) { register struct undo *sunptr = &suptr->un_ent[0]; register int i = 0; while (i < suptr->un_cnt) { if (sunptr->un_id == semid) { if (semnum == -1 || sunptr->un_num == semnum) { suptr->un_cnt--; if (i < suptr->un_cnt) { suptr->un_ent[i] = suptr->un_ent[suptr->un_cnt]; continue; } } if (semnum != -1) break; } i++, sunptr++; } } } /* * Note that the user-mode half of this passes a union, not a pointer */ #ifndef _SYS_SYSPROTO_H_ struct __semctl_args { int semid; int semnum; int cmd; union semun *arg; }; #endif /* * MPSAFE */ int __semctl(td, uap) struct thread *td; register struct __semctl_args *uap; { int semid = uap->semid; int semnum = uap->semnum; int cmd = uap->cmd; union semun *arg = uap->arg; union semun real_arg; struct ucred *cred = td->td_proc->p_ucred; int i, rval, error; struct semid_ds sbuf; register struct semid_ds *semaptr; + u_short usval; #ifdef SEM_DEBUG printf("call to semctl(%d, %d, %d, 0x%x)\n", semid, semnum, cmd, arg); #endif mtx_lock(&Giant); if (!jail_sysvipc_allowed && jailed(td->td_proc->p_ucred)) { error = ENOSYS; goto done2; } switch(cmd) { case SEM_STAT: if (semid < 0 || semid >= seminfo.semmsl) return(EINVAL); semaptr = &sema[semid]; if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0 ) return(EINVAL); if ((error = ipcperm(td, &semaptr->sem_perm, IPC_R))) return(error); if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0) return(error); error = copyout((caddr_t)semaptr, real_arg.buf, sizeof(struct semid_ds)); rval = IXSEQ_TO_IPCID(semid,semaptr->sem_perm); if (error == 0) td->td_retval[0] = rval; goto done2; } semid = IPCID_TO_IX(semid); if (semid < 0 || semid >= seminfo.semmsl) { error = EINVAL; goto done2; } semaptr = &sema[semid]; if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0 || semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid)) { error = EINVAL; goto done2; } error = 0; rval = 0; switch (cmd) { case IPC_RMID: if ((error = ipcperm(td, &semaptr->sem_perm, IPC_M))) goto done2; semaptr->sem_perm.cuid = cred->cr_uid; semaptr->sem_perm.uid = cred->cr_uid; semtot -= semaptr->sem_nsems; for (i = semaptr->sem_base - sem; i < semtot; i++) sem[i] = sem[i + semaptr->sem_nsems]; for (i = 0; i < seminfo.semmni; i++) { if ((sema[i].sem_perm.mode & SEM_ALLOC) && sema[i].sem_base > semaptr->sem_base) sema[i].sem_base -= semaptr->sem_nsems; } semaptr->sem_perm.mode = 0; semundo_clear(semid, -1); wakeup((caddr_t)semaptr); break; case IPC_SET: if ((error = ipcperm(td, &semaptr->sem_perm, IPC_M))) goto done2; if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0) goto done2; if ((error = copyin(real_arg.buf, (caddr_t)&sbuf, sizeof(sbuf))) != 0) { goto done2; } semaptr->sem_perm.uid = sbuf.sem_perm.uid; semaptr->sem_perm.gid = sbuf.sem_perm.gid; semaptr->sem_perm.mode = (semaptr->sem_perm.mode & ~0777) | (sbuf.sem_perm.mode & 0777); semaptr->sem_ctime = time_second; break; case IPC_STAT: if ((error = ipcperm(td, &semaptr->sem_perm, IPC_R))) goto done2; if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0) goto done2; error = copyout((caddr_t)semaptr, real_arg.buf, sizeof(struct semid_ds)); break; case GETNCNT: if ((error = ipcperm(td, &semaptr->sem_perm, IPC_R))) goto done2; if (semnum < 0 || semnum >= semaptr->sem_nsems) { error = EINVAL; goto done2; } rval = semaptr->sem_base[semnum].semncnt; break; case GETPID: if ((error = ipcperm(td, &semaptr->sem_perm, IPC_R))) goto done2; if (semnum < 0 || semnum >= semaptr->sem_nsems) { error = EINVAL; goto done2; } rval = semaptr->sem_base[semnum].sempid; break; case GETVAL: if ((error = ipcperm(td, &semaptr->sem_perm, IPC_R))) goto done2; if (semnum < 0 || semnum >= semaptr->sem_nsems) { error = EINVAL; goto done2; } rval = semaptr->sem_base[semnum].semval; break; case GETALL: if ((error = ipcperm(td, &semaptr->sem_perm, IPC_R))) goto done2; if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0) goto done2; for (i = 0; i < semaptr->sem_nsems; i++) { error = copyout((caddr_t)&semaptr->sem_base[i].semval, &real_arg.array[i], sizeof(real_arg.array[0])); if (error != 0) break; } break; case GETZCNT: if ((error = ipcperm(td, &semaptr->sem_perm, IPC_R))) goto done2; if (semnum < 0 || semnum >= semaptr->sem_nsems) { error = EINVAL; goto done2; } rval = semaptr->sem_base[semnum].semzcnt; break; case SETVAL: if ((error = ipcperm(td, &semaptr->sem_perm, IPC_W))) goto done2; if (semnum < 0 || semnum >= semaptr->sem_nsems) { error = EINVAL; goto done2; } if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0) goto done2; + if (real_arg.val < 0 || real_arg.val > seminfo.semvmx) { + error = ERANGE; + goto done2; + } semaptr->sem_base[semnum].semval = real_arg.val; semundo_clear(semid, semnum); wakeup((caddr_t)semaptr); break; case SETALL: if ((error = ipcperm(td, &semaptr->sem_perm, IPC_W))) goto done2; if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0) goto done2; for (i = 0; i < semaptr->sem_nsems; i++) { error = copyin(&real_arg.array[i], - (caddr_t)&semaptr->sem_base[i].semval, - sizeof(real_arg.array[0])); + (caddr_t)&usval, sizeof(real_arg.array[0])); if (error != 0) break; + if (usval > seminfo.semvmx) { + error = ERANGE; + break; + } + semaptr->sem_base[i].semval = usval; } semundo_clear(semid, -1); wakeup((caddr_t)semaptr); break; default: error = EINVAL; break; } if (error == 0) td->td_retval[0] = rval; done2: mtx_unlock(&Giant); return(error); } #ifndef _SYS_SYSPROTO_H_ struct semget_args { key_t key; int nsems; int semflg; }; #endif /* * MPSAFE */ int semget(td, uap) struct thread *td; register struct semget_args *uap; { int semid, error = 0; int key = uap->key; int nsems = uap->nsems; int semflg = uap->semflg; struct ucred *cred = td->td_proc->p_ucred; #ifdef SEM_DEBUG printf("semget(0x%x, %d, 0%o)\n", key, nsems, semflg); #endif mtx_lock(&Giant); if (!jail_sysvipc_allowed && jailed(td->td_proc->p_ucred)) { error = ENOSYS; goto done2; } if (key != IPC_PRIVATE) { for (semid = 0; semid < seminfo.semmni; semid++) { if ((sema[semid].sem_perm.mode & SEM_ALLOC) && sema[semid].sem_perm.key == key) break; } if (semid < seminfo.semmni) { #ifdef SEM_DEBUG printf("found public key\n"); #endif if ((error = ipcperm(td, &sema[semid].sem_perm, semflg & 0700))) { goto done2; } if (nsems > 0 && sema[semid].sem_nsems < nsems) { #ifdef SEM_DEBUG printf("too small\n"); #endif error = EINVAL; goto done2; } if ((semflg & IPC_CREAT) && (semflg & IPC_EXCL)) { #ifdef SEM_DEBUG printf("not exclusive\n"); #endif error = EEXIST; goto done2; } goto found; } } #ifdef SEM_DEBUG printf("need to allocate the semid_ds\n"); #endif if (key == IPC_PRIVATE || (semflg & IPC_CREAT)) { if (nsems <= 0 || nsems > seminfo.semmsl) { #ifdef SEM_DEBUG printf("nsems out of range (0<%d<=%d)\n", nsems, seminfo.semmsl); #endif error = EINVAL; goto done2; } if (nsems > seminfo.semmns - semtot) { #ifdef SEM_DEBUG printf("not enough semaphores left (need %d, got %d)\n", nsems, seminfo.semmns - semtot); #endif error = ENOSPC; goto done2; } for (semid = 0; semid < seminfo.semmni; semid++) { if ((sema[semid].sem_perm.mode & SEM_ALLOC) == 0) break; } if (semid == seminfo.semmni) { #ifdef SEM_DEBUG printf("no more semid_ds's available\n"); #endif error = ENOSPC; goto done2; } #ifdef SEM_DEBUG printf("semid %d is available\n", semid); #endif sema[semid].sem_perm.key = key; sema[semid].sem_perm.cuid = cred->cr_uid; sema[semid].sem_perm.uid = cred->cr_uid; sema[semid].sem_perm.cgid = cred->cr_gid; sema[semid].sem_perm.gid = cred->cr_gid; sema[semid].sem_perm.mode = (semflg & 0777) | SEM_ALLOC; sema[semid].sem_perm.seq = (sema[semid].sem_perm.seq + 1) & 0x7fff; sema[semid].sem_nsems = nsems; sema[semid].sem_otime = 0; sema[semid].sem_ctime = time_second; sema[semid].sem_base = &sem[semtot]; semtot += nsems; bzero(sema[semid].sem_base, sizeof(sema[semid].sem_base[0])*nsems); #ifdef SEM_DEBUG printf("sembase = 0x%x, next = 0x%x\n", sema[semid].sem_base, &sem[semtot]); #endif } else { #ifdef SEM_DEBUG printf("didn't find it and wasn't asked to create it\n"); #endif error = ENOENT; goto done2; } found: td->td_retval[0] = IXSEQ_TO_IPCID(semid, sema[semid].sem_perm); done2: mtx_unlock(&Giant); return (error); } #ifndef _SYS_SYSPROTO_H_ struct semop_args { int semid; struct sembuf *sops; u_int nsops; }; #endif /* * MPSAFE */ int semop(td, uap) struct thread *td; register struct semop_args *uap; { int semid = uap->semid; u_int nsops = uap->nsops; - struct sembuf sops[MAX_SOPS]; + struct sembuf *sops = NULL; register struct semid_ds *semaptr; register struct sembuf *sopptr; register struct sem *semptr; - struct sem_undo *suptr = NULL; - int i, j, error = 0; + struct sem_undo *suptr; + int i, j, error; int do_wakeup, do_undos; #ifdef SEM_DEBUG printf("call to semop(%d, 0x%x, %u)\n", semid, sops, nsops); #endif mtx_lock(&Giant); if (!jail_sysvipc_allowed && jailed(td->td_proc->p_ucred)) { error = ENOSYS; goto done2; } semid = IPCID_TO_IX(semid); /* Convert back to zero origin */ if (semid < 0 || semid >= seminfo.semmsl) { error = EINVAL; goto done2; } semaptr = &sema[semid]; if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0) { error = EINVAL; goto done2; } if (semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid)) { error = EINVAL; goto done2; } - - if ((error = ipcperm(td, &semaptr->sem_perm, IPC_W))) { + if (nsops > seminfo.semopm) { #ifdef SEM_DEBUG - printf("error = %d from ipcperm\n", error); + printf("too many sops (max=%d, nsops=%d)\n", seminfo.semopm, + nsops); #endif + error = E2BIG; goto done2; } - if (nsops > MAX_SOPS) { + /* Allocate memory for sem_ops */ + sops = malloc(nsops * sizeof(sops[0]), M_SEM, M_WAITOK); + if (!sops) + panic("Failed to allocate %d sem_ops", nsops); + + if ((error = copyin(uap->sops, sops, nsops * sizeof(sops[0]))) != 0) { #ifdef SEM_DEBUG - printf("too many sops (max=%d, nsops=%u)\n", MAX_SOPS, nsops); + printf("error = %d from copyin(%08x, %08x, %d)\n", error, + uap->sops, sops, nsops * sizeof(sops[0])); #endif - error = E2BIG; goto done2; } - if ((error = copyin(uap->sops, &sops, nsops * sizeof(sops[0]))) != 0) { + /* + * Initial pass thru sops to see what permissions are needed. + * Also perform any checks that don't need repeating on each + * attempt to satisfy the request vector. + */ + j = 0; /* permission needed */ + do_undos = 0; + for (i = 0; i < nsops; i++) { + sopptr = &sops[i]; + if (sopptr->sem_num >= semaptr->sem_nsems) { + error = EFBIG; + goto done2; + } + if (sopptr->sem_flg & SEM_UNDO && sopptr->sem_op != 0) + do_undos = 1; + j |= (sopptr->sem_op == 0) ? SEM_R : SEM_A; + } + + if ((error = ipcperm(td, &semaptr->sem_perm, j))) { #ifdef SEM_DEBUG - printf("error = %d from copyin(%08x, %08x, %u)\n", error, - uap->sops, &sops, nsops * sizeof(sops[0])); + printf("error = %d from ipaccess\n", error); #endif goto done2; } /* * Loop trying to satisfy the vector of requests. * If we reach a point where we must wait, any requests already * performed are rolled back and we go to sleep until some other * process wakes us up. At this point, we start all over again. * * This ensures that from the perspective of other tasks, a set * of requests is atomic (never partially satisfied). */ - do_undos = 0; - for (;;) { do_wakeup = 0; + error = 0; /* error return if necessary */ for (i = 0; i < nsops; i++) { sopptr = &sops[i]; - - if (sopptr->sem_num >= semaptr->sem_nsems) { - error = EFBIG; - goto done2; - } - semptr = &semaptr->sem_base[sopptr->sem_num]; #ifdef SEM_DEBUG printf("semop: semaptr=%x, sem_base=%x, semptr=%x, sem[%d]=%d : op=%d, flag=%s\n", semaptr, semaptr->sem_base, semptr, sopptr->sem_num, semptr->semval, sopptr->sem_op, (sopptr->sem_flg & IPC_NOWAIT) ? "nowait" : "wait"); #endif if (sopptr->sem_op < 0) { if (semptr->semval + sopptr->sem_op < 0) { #ifdef SEM_DEBUG printf("semop: can't do it now\n"); #endif break; } else { semptr->semval += sopptr->sem_op; if (semptr->semval == 0 && semptr->semzcnt > 0) do_wakeup = 1; } - if (sopptr->sem_flg & SEM_UNDO) - do_undos = 1; } else if (sopptr->sem_op == 0) { - if (semptr->semval > 0) { + if (semptr->semval != 0) { #ifdef SEM_DEBUG printf("semop: not zero now\n"); #endif break; } + } else if (semptr->semval + sopptr->sem_op > + seminfo.semvmx) { + error = ERANGE; + break; } else { if (semptr->semncnt > 0) do_wakeup = 1; semptr->semval += sopptr->sem_op; - if (sopptr->sem_flg & SEM_UNDO) - do_undos = 1; } } /* * Did we get through the entire vector? */ if (i >= nsops) goto done; /* * No ... rollback anything that we've already done */ #ifdef SEM_DEBUG printf("semop: rollback 0 through %d\n", i-1); #endif for (j = 0; j < i; j++) semaptr->sem_base[sops[j].sem_num].semval -= sops[j].sem_op; + /* If we detected an error, return it */ + if (error != 0) + goto done2; + /* * If the request that we couldn't satisfy has the * NOWAIT flag set then return with EAGAIN. */ if (sopptr->sem_flg & IPC_NOWAIT) { error = EAGAIN; goto done2; } if (sopptr->sem_op == 0) semptr->semzcnt++; else semptr->semncnt++; #ifdef SEM_DEBUG printf("semop: good night!\n"); #endif error = tsleep((caddr_t)semaptr, (PZERO - 4) | PCATCH, "semwait", 0); #ifdef SEM_DEBUG printf("semop: good morning (error=%d)!\n", error); #endif - suptr = NULL; /* sem_undo may have been reallocated */ - if (error != 0) { error = EINTR; goto done2; } #ifdef SEM_DEBUG printf("semop: good morning!\n"); #endif /* * Make sure that the semaphore still exists */ if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0 || semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid)) { error = EIDRM; goto done2; } /* * The semaphore is still alive. Readjust the count of * waiting processes. */ if (sopptr->sem_op == 0) semptr->semzcnt--; else semptr->semncnt--; } done: /* * Process any SEM_UNDO requests. */ if (do_undos) { + suptr = NULL; for (i = 0; i < nsops; i++) { /* * We only need to deal with SEM_UNDO's for non-zero * op's. */ int adjval; if ((sops[i].sem_flg & SEM_UNDO) == 0) continue; adjval = sops[i].sem_op; if (adjval == 0) continue; error = semundo_adjust(td, &suptr, semid, sops[i].sem_num, -adjval); if (error == 0) continue; /* * Oh-Oh! We ran out of either sem_undo's or undo's. * Rollback the adjustments to this point and then * rollback the semaphore ups and down so we can return * with an error with all structures restored. We * rollback the undo's in the exact reverse order that * we applied them. This guarantees that we won't run * out of space as we roll things back out. */ for (j = i - 1; j >= 0; j--) { if ((sops[j].sem_flg & SEM_UNDO) == 0) continue; adjval = sops[j].sem_op; if (adjval == 0) continue; if (semundo_adjust(td, &suptr, semid, sops[j].sem_num, adjval) != 0) panic("semop - can't undo undos"); } for (j = 0; j < nsops; j++) semaptr->sem_base[sops[j].sem_num].semval -= sops[j].sem_op; #ifdef SEM_DEBUG printf("error = %d from semundo_adjust\n", error); #endif goto done2; } /* loop through the sops */ } /* if (do_undos) */ - /* We're definitely done - set the sempid's */ + /* We're definitely done - set the sempid's and time */ for (i = 0; i < nsops; i++) { sopptr = &sops[i]; semptr = &semaptr->sem_base[sopptr->sem_num]; semptr->sempid = td->td_proc->p_pid; } + semaptr->sem_otime = time_second; - /* Do a wakeup if any semaphore was up'd. */ + /* + * Do a wakeup if any semaphore was up'd whilst something was + * sleeping on it. + */ if (do_wakeup) { #ifdef SEM_DEBUG printf("semop: doing wakeup\n"); #endif wakeup((caddr_t)semaptr); #ifdef SEM_DEBUG printf("semop: back from wakeup\n"); #endif } #ifdef SEM_DEBUG printf("semop: done\n"); #endif td->td_retval[0] = 0; done2: + if (sops) + free(sops, M_SEM); mtx_unlock(&Giant); return (error); } /* * Go through the undo structures for this process and apply the adjustments to * semaphores. */ static void semexit_myhook(p) struct proc *p; { register struct sem_undo *suptr; register struct sem_undo **supptr; - int did_something; - - did_something = 0; /* * Go through the chain of undo vectors looking for one * associated with this process. */ for (supptr = &semu_list; (suptr = *supptr) != NULL; supptr = &suptr->un_next) { if (suptr->un_proc == p) break; } if (suptr == NULL) return; #ifdef SEM_DEBUG printf("proc @%08x has undo structure with %d entries\n", p, suptr->un_cnt); #endif /* * If there are any active undo elements then process them. */ if (suptr->un_cnt > 0) { int ix; for (ix = 0; ix < suptr->un_cnt; ix++) { int semid = suptr->un_ent[ix].un_id; int semnum = suptr->un_ent[ix].un_num; int adjval = suptr->un_ent[ix].un_adjval; struct semid_ds *semaptr; semaptr = &sema[semid]; if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0) panic("semexit - semid not allocated"); if (semnum >= semaptr->sem_nsems) panic("semexit - semnum out of range"); #ifdef SEM_DEBUG printf("semexit: %08x id=%d num=%d(adj=%d) ; sem=%d\n", suptr->un_proc, suptr->un_ent[ix].un_id, suptr->un_ent[ix].un_num, suptr->un_ent[ix].un_adjval, semaptr->sem_base[semnum].semval); #endif if (adjval < 0) { if (semaptr->sem_base[semnum].semval < -adjval) semaptr->sem_base[semnum].semval = 0; else semaptr->sem_base[semnum].semval += adjval; } else semaptr->sem_base[semnum].semval += adjval; wakeup((caddr_t)semaptr); #ifdef SEM_DEBUG printf("semexit: back from wakeup\n"); #endif } } /* * Deallocate the undo vector. */ #ifdef SEM_DEBUG printf("removing vector\n"); #endif suptr->un_proc = NULL; *supptr = suptr->un_next; } static int sysctl_sema(SYSCTL_HANDLER_ARGS) { return (SYSCTL_OUT(req, sema, sizeof(struct semid_ds) * seminfo.semmni)); } diff --git a/sys/sys/sem.h b/sys/sys/sem.h index 1bed0c31591e..4e6336469d9b 100644 --- a/sys/sys/sem.h +++ b/sys/sys/sem.h @@ -1,110 +1,108 @@ /* $FreeBSD$ */ /* $NetBSD: sem.h,v 1.5 1994/06/29 06:45:15 cgd Exp $ */ /* * SVID compatible sem.h file * * Author: Daniel Boulet */ #ifndef _SYS_SEM_H_ #define _SYS_SEM_H_ #include struct sem; struct semid_ds { struct ipc_perm sem_perm; /* operation permission struct */ struct sem *sem_base; /* pointer to first semaphore in set */ u_short sem_nsems; /* number of sems in set */ time_t sem_otime; /* last operation time */ long sem_pad1; /* SVABI/386 says I need this here */ time_t sem_ctime; /* last change time */ /* Times measured in secs since */ /* 00:00:00 GMT, Jan. 1, 1970 */ long sem_pad2; /* SVABI/386 says I need this here */ long sem_pad3[4]; /* SVABI/386 says I need this here */ }; /* * semop's sops parameter structure */ struct sembuf { u_short sem_num; /* semaphore # */ short sem_op; /* semaphore operation */ short sem_flg; /* operation flags */ }; #define SEM_UNDO 010000 -#define MAX_SOPS 5 /* maximum # of sembuf's per semop call */ - /* * semctl's arg parameter structure */ union semun { int val; /* value for SETVAL */ struct semid_ds *buf; /* buffer for IPC_STAT & IPC_SET */ u_short *array; /* array for GETALL & SETALL */ }; /* * commands for semctl */ #define GETNCNT 3 /* Return the value of semncnt {READ} */ #define GETPID 4 /* Return the value of sempid {READ} */ #define GETVAL 5 /* Return the value of semval {READ} */ #define GETALL 6 /* Return semvals into arg.array {READ} */ #define GETZCNT 7 /* Return the value of semzcnt {READ} */ #define SETVAL 8 /* Set the value of semval to arg.val {ALTER} */ #define SETALL 9 /* Set semvals from arg.array {ALTER} */ #define SEM_STAT 10 /* Like IPC_STAT but treats semid as sema-index */ #define SEM_INFO 11 /* Like IPC_INFO but treats semid as sema-index */ /* * Permissions */ -#define SEM_A 0200 /* alter permission */ -#define SEM_R 0400 /* read permission */ +#define SEM_A IPC_W /* alter permission */ +#define SEM_R IPC_R /* read permission */ #ifdef _KERNEL /* * semaphore info struct */ struct seminfo { int semmap, /* # of entries in semaphore map */ semmni, /* # of semaphore identifiers */ semmns, /* # of semaphores in system */ semmnu, /* # of undo structures in system */ semmsl, /* max # of semaphores per id */ semopm, /* max # of operations per semop call */ semume, /* max # of undo entries per process */ semusz, /* size in bytes of undo structure */ semvmx, /* semaphore maximum value */ semaem; /* adjust on exit max value */ }; extern struct seminfo seminfo; /* internal "mode" bits */ #define SEM_ALLOC 01000 /* semaphore is allocated */ #define SEM_DEST 02000 /* semaphore will be destroyed on last detach */ /* * Process sem_undo vectors at proc exit. */ void semexit __P((struct proc *p)); #endif /* _KERNEL */ #ifndef _KERNEL #include __BEGIN_DECLS int semsys __P((int, ...)); int semctl __P((int, int, int, ...)); int semget __P((key_t, int, int)); int semop __P((int, struct sembuf *,unsigned)); __END_DECLS #endif /* !_KERNEL */ #endif /* !_SEM_H_ */