]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/sysv_sem.c
xnu-517.12.7.tar.gz
[apple/xnu.git] / bsd / kern / sysv_sem.c
CommitLineData
1c79356b 1/*
e5568f75 2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
1c79356b
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
e5568f75
A
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
1c79356b 11 *
e5568f75
A
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
1c79356b
A
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
e5568f75
A
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
1c79356b
A
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/*
23 * Implementation of SVID semaphores
24 *
25 * Author: Daniel Boulet
26 *
27 * This software is provided ``AS IS'' without any warranties of any kind.
28 */
9bccf70c
A
29/*
30 * John Bellardo modified the implementation for Darwin. 12/2000
31 */
1c79356b
A
32
33#include <sys/param.h>
34#include <sys/systm.h>
1c79356b
A
35#include <sys/kernel.h>
36#include <sys/proc.h>
37#include <sys/sem.h>
9bccf70c 38#include <sys/malloc.h>
9bccf70c
A
39#include <sys/filedesc.h>
40#include <sys/file.h>
55e303ae 41#include <sys/sysctl.h>
9bccf70c 42
e5568f75
A
43#include <bsm/audit_kernel.h>
44
45#include <mach/mach_types.h>
46
9bccf70c
A
47/*#include <sys/sysproto.h>*/
48/*#include <sys/sysent.h>*/
49
50/* Uncomment this line to see the debugging output */
51/* #define SEM_DEBUG */
52
53/* Macros to deal with the semaphore subsystem lock. The lock currently uses
54 * the semlock_holder static variable as a mutex. NULL means no lock, any
55 * value other than NULL means locked. semlock_holder is used because it was
56 * present in the code before the Darwin port, and for no other reason.
57 * When the time comes to relax the funnel requirements of the kernel only
58 * these macros should need to be changed. A spin lock would work well.
59 */
60/* Aquire the lock */
61#define SUBSYSTEM_LOCK_AQUIRE(p) { sysv_sem_aquiring_threads++; \
62 while (semlock_holder != NULL) \
63 (void) tsleep((caddr_t)&semlock_holder, (PZERO - 4), "sysvsem", 0); \
64 semlock_holder = p; \
65 sysv_sem_aquiring_threads--; }
66
67/* Release the lock */
68#define SUBSYSTEM_LOCK_RELEASE { semlock_holder = NULL; wakeup((caddr_t)&semlock_holder); }
69
70/* Release the lock and return a value */
71#define UNLOCK_AND_RETURN(ret) { SUBSYSTEM_LOCK_RELEASE; return(ret); }
72
73#define M_SYSVSEM M_SUBPROC
1c79356b 74
9bccf70c 75#if 0
1c79356b
A
76static void seminit __P((void *));
77SYSINIT(sysv_sem, SI_SUB_SYSV_SEM, SI_ORDER_FIRST, seminit, NULL)
9bccf70c 78#endif 0
1c79356b 79
9bccf70c
A
80/* Hard system limits to avoid resource starvation / DOS attacks.
81 * These are not needed if we can make the semaphore pages swappable.
82 */
83static struct seminfo limitseminfo = {
84 SEMMAP, /* # of entries in semaphore map */
85 SEMMNI, /* # of semaphore identifiers */
86 SEMMNS, /* # of semaphores in system */
87 SEMMNU, /* # of undo structures in system */
88 SEMMSL, /* max # of semaphores per id */
89 SEMOPM, /* max # of operations per semop call */
90 SEMUME, /* max # of undo entries per process */
91 SEMUSZ, /* size in bytes of undo structure */
92 SEMVMX, /* semaphore maximum value */
93 SEMAEM /* adjust on exit max value */
94};
95
96/* Current system allocations. We use this structure to track how many
97 * resources we have allocated so far. This way we can set large hard limits
98 * and not allocate the memory for them up front.
99 */
100struct seminfo seminfo = {
101 SEMMAP, /* Unused, # of entries in semaphore map */
102 0, /* # of semaphore identifiers */
103 0, /* # of semaphores in system */
104 0, /* # of undo entries in system */
105 SEMMSL, /* max # of semaphores per id */
106 SEMOPM, /* max # of operations per semop call */
107 SEMUME, /* max # of undo entries per process */
108 SEMUSZ, /* size in bytes of undo structure */
109 SEMVMX, /* semaphore maximum value */
110 SEMAEM /* adjust on exit max value */
111};
112
113/* A counter so the module unload code knows when there are no more processes using
114 * the sysv_sem code */
115static long sysv_sem_sleeping_threads = 0;
116static long sysv_sem_aquiring_threads = 0;
117
118struct semctl_args;
119int semctl __P((struct proc *p, struct semctl_args *uap, int *));
1c79356b 120struct semget_args;
9bccf70c 121int semget __P((struct proc *p, struct semget_args *uap, int *));
1c79356b 122struct semop_args;
9bccf70c 123int semop __P((struct proc *p, struct semop_args *uap, int *));
1c79356b 124struct semconfig_args;
9bccf70c
A
125int semconfig __P((struct proc *p, struct semconfig_args *uap, int *));
126
1c79356b
A
127
128static struct sem_undo *semu_alloc __P((struct proc *p));
129static int semundo_adjust __P((struct proc *p, struct sem_undo **supptr,
130 int semid, int semnum, int adjval));
131static void semundo_clear __P((int semid, int semnum));
132
9bccf70c
A
133typedef int sy_call_t __P((struct proc *, void *, int *));
134
1c79356b
A
135/* XXX casting to (sy_call_t *) is bogus, as usual. */
136static sy_call_t *semcalls[] = {
9bccf70c 137 (sy_call_t *)semctl, (sy_call_t *)semget,
1c79356b
A
138 (sy_call_t *)semop, (sy_call_t *)semconfig
139};
140
9bccf70c
A
141static int semtot = 0; /* # of used semaphores */
142struct semid_ds *sema = NULL; /* semaphore id pool */
143struct sem *sem = NULL; /* semaphore pool */
144static struct sem_undo *semu_list = NULL; /* list of active undo structures */
145struct sem_undo *semu = NULL; /* semaphore undo pool */
1c79356b
A
146
147static struct proc *semlock_holder = NULL;
148
9bccf70c 149/* seminit no longer needed. The data structures are grown dynamically */
1c79356b 150void
9bccf70c 151seminit()
1c79356b 152{
1c79356b
A
153}
154
155/*
156 * Entry point for all SEM calls
9bccf70c
A
157 *
158 * In Darwin this is no longer the entry point. It will be removed after
159 * the code has been tested better.
1c79356b 160 */
9bccf70c
A
161struct semsys_args {
162 u_int which;
163 int a2;
164 int a3;
165 int a4;
166 int a5;
167};
1c79356b 168int
9bccf70c 169semsys(p, uap, retval)
1c79356b
A
170 struct proc *p;
171 /* XXX actually varargs. */
9bccf70c
A
172 struct semsys_args *uap;
173 register_t *retval;
1c79356b
A
174{
175
9bccf70c
A
176 /* The individual calls handling the locking now */
177 /*while (semlock_holder != NULL && semlock_holder != p)
1c79356b 178 (void) tsleep((caddr_t)&semlock_holder, (PZERO - 4), "semsys", 0);
9bccf70c 179 */
1c79356b
A
180
181 if (uap->which >= sizeof(semcalls)/sizeof(semcalls[0]))
182 return (EINVAL);
9bccf70c 183 return ((*semcalls[uap->which])(p, &uap->a2, retval));
1c79356b
A
184}
185
186/*
187 * Lock or unlock the entire semaphore facility.
188 *
189 * This will probably eventually evolve into a general purpose semaphore
190 * facility status enquiry mechanism (I don't like the "read /dev/kmem"
191 * approach currently taken by ipcs and the amount of info that we want
192 * to be able to extract for ipcs is probably beyond what the capability
193 * of the getkerninfo facility.
194 *
195 * At the time that the current version of semconfig was written, ipcs is
196 * the only user of the semconfig facility. It uses it to ensure that the
197 * semaphore facility data structures remain static while it fishes around
198 * in /dev/kmem.
199 */
200
201#ifndef _SYS_SYSPROTO_H_
202struct semconfig_args {
203 semconfig_ctl_t flag;
204};
205#endif
206
207int
9bccf70c 208semconfig(p, uap, retval)
1c79356b
A
209 struct proc *p;
210 struct semconfig_args *uap;
9bccf70c 211 register_t *retval;
1c79356b
A
212{
213 int eval = 0;
214
215 switch (uap->flag) {
216 case SEM_CONFIG_FREEZE:
9bccf70c 217 SUBSYSTEM_LOCK_AQUIRE(p);
1c79356b
A
218 break;
219
220 case SEM_CONFIG_THAW:
9bccf70c 221 SUBSYSTEM_LOCK_RELEASE;
1c79356b
A
222 break;
223
224 default:
225 printf("semconfig: unknown flag parameter value (%d) - ignored\n",
226 uap->flag);
227 eval = EINVAL;
228 break;
229 }
230
9bccf70c 231 *retval = 0;
1c79356b
A
232 return(eval);
233}
234
9bccf70c
A
235/* Expand the semu array to the given capacity. If the expansion fails
236 * return 0, otherwise return 1.
237 *
238 * Assumes we already have the subsystem lock.
239 */
240static int
241grow_semu_array(newSize)
242 int newSize;
243{
244 register int i, j;
245 register struct sem_undo *newSemu;
246 if (newSize <= seminfo.semmnu)
247 return 0;
248 if (newSize > limitseminfo.semmnu) /* enforce hard limit */
249 {
250#ifdef SEM_DEBUG
251 printf("undo structure hard limit of %d reached, requested %d\n",
252 limitseminfo.semmnu, newSize);
253#endif
254 return 0;
255 }
256 newSize = (newSize/SEMMNU_INC + 1) * SEMMNU_INC;
257 newSize = newSize > limitseminfo.semmnu ? limitseminfo.semmnu : newSize;
258
259#ifdef SEM_DEBUG
260 printf("growing semu[] from %d to %d\n", seminfo.semmnu, newSize);
261#endif
262 MALLOC(newSemu, struct sem_undo*, sizeof(struct sem_undo)*newSize,
263 M_SYSVSEM, M_WAITOK);
264 if (NULL == newSemu)
265 {
266#ifdef SEM_DEBUG
267 printf("allocation failed. no changes made.\n");
268#endif
269 return 0;
270 }
271
272 /* Initialize our structure. */
273 for (i = 0; i < seminfo.semmnu; i++)
274 {
275 newSemu[i] = semu[i];
276 for(j = 0; j < SEMUME; j++) /* Is this really needed? */
277 newSemu[i].un_ent[j] = semu[i].un_ent[j];
278 }
279 for (i = seminfo.semmnu; i < newSize; i++)
280 {
281 newSemu[i].un_proc = NULL;
282 }
283
284 /* Clean up the old array */
285 if (semu)
286 FREE(semu, M_SYSVSEM);
287
288 semu = newSemu;
289 seminfo.semmnu = newSize;
290#ifdef SEM_DEBUG
291 printf("expansion successful\n");
292#endif
293 return 1;
294}
295
296/*
297 * Expand the sema array to the given capacity. If the expansion fails
298 * we return 0, otherwise we return 1.
299 *
300 * Assumes we already have the subsystem lock.
301 */
302static int
303grow_sema_array(newSize)
304 int newSize;
305{
306 register struct semid_ds *newSema;
307 register int i;
308
309 if (newSize <= seminfo.semmni)
310 return 0;
311 if (newSize > limitseminfo.semmni) /* enforce hard limit */
312 {
313#ifdef SEM_DEBUG
314 printf("identifier hard limit of %d reached, requested %d\n",
315 limitseminfo.semmni, newSize);
316#endif
317 return 0;
318 }
319 newSize = (newSize/SEMMNI_INC + 1) * SEMMNI_INC;
320 newSize = newSize > limitseminfo.semmni ? limitseminfo.semmni : newSize;
321
322#ifdef SEM_DEBUG
323 printf("growing sema[] from %d to %d\n", seminfo.semmni, newSize);
324#endif
325 MALLOC(newSema, struct semid_ds*, sizeof(struct semid_ds)*newSize,
326 M_SYSVSEM, M_WAITOK);
327 if (NULL == newSema)
328 {
329#ifdef SEM_DEBUG
330 printf("allocation failed. no changes made.\n");
331#endif
332 return 0;
333 }
334
335 /* Initialize our new ids, and copy over the old ones */
336 for (i = 0; i < seminfo.semmni; i++)
337 {
338 newSema[i] = sema[i];
339 /* This is a hack. What we really want to be able to
340 * do is change the value a process is waiting on
341 * without waking it up, but I don't know how to do
342 * this with the existing code, so we wake up the
343 * process and let it do a lot of work to determine the
344 * semaphore set is really not available yet, and then
345 * sleep on the correct, reallocated semid_ds pointer.
346 */
347 if (sema[i].sem_perm.mode & SEM_ALLOC)
348 wakeup((caddr_t)&sema[i]);
349 }
350
351 for (i = seminfo.semmni; i < newSize; i++)
352 {
353 newSema[i].sem_base = 0;
354 newSema[i].sem_perm.mode = 0;
355 }
356
357 /* Clean up the old array */
358 if (sema)
359 FREE(sema, M_SYSVSEM);
360
361 sema = newSema;
362 seminfo.semmni = newSize;
363#ifdef SEM_DEBUG
364 printf("expansion successful\n");
365#endif
366 return 1;
367}
368
369/*
370 * Expand the sem array to the given capacity. If the expansion fails
371 * we return 0 (fail), otherwise we return 1 (success).
372 *
373 * Assumes we already hold the subsystem lock.
374 */
375static int
376grow_sem_array(newSize)
377 int newSize;
378{
379 register struct sem *newSem = NULL;
380 register int i;
381
382 if (newSize < semtot)
383 return 0;
384 if (newSize > limitseminfo.semmns) /* enforce hard limit */
385 {
386#ifdef SEM_DEBUG
387 printf("semaphore hard limit of %d reached, requested %d\n",
388 limitseminfo.semmns, newSize);
389#endif
390 return 0;
391 }
392 newSize = (newSize/SEMMNS_INC + 1) * SEMMNS_INC;
393 newSize = newSize > limitseminfo.semmns ? limitseminfo.semmns : newSize;
394
395#ifdef SEM_DEBUG
396 printf("growing sem array from %d to %d\n", seminfo.semmns, newSize);
397#endif
398 MALLOC(newSem, struct sem*, sizeof(struct sem)*newSize,
399 M_SYSVSEM, M_WAITOK);
400 if (NULL == newSem)
401 {
402#ifdef SEM_DEBUG
403 printf("allocation failed. no changes made.\n");
404#endif
405 return 0;
406 }
407
408 /* We have our new memory, now copy the old contents over */
409 if (sem)
410 for(i = 0; i < seminfo.semmns; i++)
411 newSem[i] = sem[i];
412
413 /* Update our id structures to point to the new semaphores */
414 for(i = 0; i < seminfo.semmni; i++)
415 if (sema[i].sem_perm.mode & SEM_ALLOC) /* ID in use */
416 {
417 if (newSem > sem)
418 sema[i].sem_base += newSem - sem;
419 else
420 sema[i].sem_base -= sem - newSem;
421 }
422
423 /* clean up the old array */
424 if (sem)
425 FREE(sem, M_SYSVSEM);
426
427 sem = newSem;
428 seminfo.semmns = newSize;
429#ifdef SEM_DEBUG
430 printf("expansion complete\n");
431#endif
432 return 1;
433}
434
1c79356b
A
435/*
436 * Allocate a new sem_undo structure for a process
437 * (returns ptr to structure or NULL if no more room)
9bccf70c
A
438 *
439 * Assumes we already hold the subsystem lock.
1c79356b
A
440 */
441
442static struct sem_undo *
443semu_alloc(p)
444 struct proc *p;
445{
446 register int i;
447 register struct sem_undo *suptr;
448 register struct sem_undo **supptr;
449 int attempt;
450
451 /*
452 * Try twice to allocate something.
453 * (we'll purge any empty structures after the first pass so
454 * two passes are always enough)
455 */
456
457 for (attempt = 0; attempt < 2; attempt++) {
458 /*
459 * Look for a free structure.
460 * Fill it in and return it if we find one.
461 */
462
463 for (i = 0; i < seminfo.semmnu; i++) {
464 suptr = SEMU(i);
465 if (suptr->un_proc == NULL) {
466 suptr->un_next = semu_list;
467 semu_list = suptr;
468 suptr->un_cnt = 0;
469 suptr->un_proc = p;
470 return(suptr);
471 }
472 }
473
474 /*
475 * We didn't find a free one, if this is the first attempt
476 * then try to free some structures.
477 */
478
479 if (attempt == 0) {
480 /* All the structures are in use - try to free some */
481 int did_something = 0;
482
483 supptr = &semu_list;
484 while ((suptr = *supptr) != NULL) {
485 if (suptr->un_cnt == 0) {
486 suptr->un_proc = NULL;
487 *supptr = suptr->un_next;
488 did_something = 1;
489 } else
490 supptr = &(suptr->un_next);
491 }
492
9bccf70c
A
493 /* If we didn't free anything. Try expanding
494 * the semu[] array. If that doesn't work
495 * then fail. We expand last to get the
496 * most reuse out of existing resources.
497 */
1c79356b 498 if (!did_something)
9bccf70c
A
499 if (!grow_semu_array(seminfo.semmnu + 1))
500 return(NULL);
1c79356b
A
501 } else {
502 /*
503 * The second pass failed even though we freed
504 * something after the first pass!
505 * This is IMPOSSIBLE!
506 */
507 panic("semu_alloc - second attempt failed");
508 }
509 }
510 return (NULL);
511}
512
513/*
514 * Adjust a particular entry for a particular proc
9bccf70c
A
515 *
516 * Assumes we already hold the subsystem lock.
1c79356b
A
517 */
518
519static int
520semundo_adjust(p, supptr, semid, semnum, adjval)
521 register struct proc *p;
522 struct sem_undo **supptr;
523 int semid, semnum;
524 int adjval;
525{
526 register struct sem_undo *suptr;
527 register struct undo *sunptr;
528 int i;
529
530 /* Look for and remember the sem_undo if the caller doesn't provide
531 it */
532
533 suptr = *supptr;
534 if (suptr == NULL) {
535 for (suptr = semu_list; suptr != NULL;
536 suptr = suptr->un_next) {
537 if (suptr->un_proc == p) {
538 *supptr = suptr;
539 break;
540 }
541 }
542 if (suptr == NULL) {
543 if (adjval == 0)
544 return(0);
545 suptr = semu_alloc(p);
546 if (suptr == NULL)
547 return(ENOSPC);
548 *supptr = suptr;
549 }
550 }
551
552 /*
553 * Look for the requested entry and adjust it (delete if adjval becomes
554 * 0).
555 */
556 sunptr = &suptr->un_ent[0];
557 for (i = 0; i < suptr->un_cnt; i++, sunptr++) {
558 if (sunptr->un_id != semid || sunptr->un_num != semnum)
559 continue;
560 if (adjval == 0)
561 sunptr->un_adjval = 0;
562 else
563 sunptr->un_adjval += adjval;
564 if (sunptr->un_adjval == 0) {
565 suptr->un_cnt--;
566 if (i < suptr->un_cnt)
567 suptr->un_ent[i] =
568 suptr->un_ent[suptr->un_cnt];
569 }
570 return(0);
571 }
572
573 /* Didn't find the right entry - create it */
574 if (adjval == 0)
575 return(0);
55e303ae 576 if (suptr->un_cnt != limitseminfo.semume) {
1c79356b
A
577 sunptr = &suptr->un_ent[suptr->un_cnt];
578 suptr->un_cnt++;
579 sunptr->un_adjval = adjval;
580 sunptr->un_id = semid; sunptr->un_num = semnum;
581 } else
582 return(EINVAL);
583 return(0);
584}
585
9bccf70c
A
586/* Assumes we already hold the subsystem lock.
587 */
1c79356b
A
588static void
589semundo_clear(semid, semnum)
590 int semid, semnum;
591{
592 register struct sem_undo *suptr;
593
594 for (suptr = semu_list; suptr != NULL; suptr = suptr->un_next) {
595 register struct undo *sunptr = &suptr->un_ent[0];
596 register int i = 0;
597
598 while (i < suptr->un_cnt) {
599 if (sunptr->un_id == semid) {
600 if (semnum == -1 || sunptr->un_num == semnum) {
601 suptr->un_cnt--;
602 if (i < suptr->un_cnt) {
603 suptr->un_ent[i] =
604 suptr->un_ent[suptr->un_cnt];
605 continue;
606 }
607 }
608 if (semnum != -1)
609 break;
610 }
611 i++, sunptr++;
612 }
613 }
614}
615
616/*
617 * Note that the user-mode half of this passes a union, not a pointer
618 */
619#ifndef _SYS_SYSPROTO_H_
9bccf70c 620struct semctl_args {
1c79356b
A
621 int semid;
622 int semnum;
623 int cmd;
9bccf70c 624 union semun arg;
1c79356b
A
625};
626#endif
627
628int
9bccf70c 629semctl(p, uap, retval)
1c79356b 630 struct proc *p;
9bccf70c
A
631 register struct semctl_args *uap;
632 register_t *retval;
1c79356b
A
633{
634 int semid = uap->semid;
635 int semnum = uap->semnum;
636 int cmd = uap->cmd;
9bccf70c 637 union semun arg = uap->arg;
1c79356b
A
638 union semun real_arg;
639 struct ucred *cred = p->p_ucred;
640 int i, rval, eval;
641 struct semid_ds sbuf;
642 register struct semid_ds *semaptr;
643
55e303ae
A
644 AUDIT_ARG(svipc_cmd, cmd);
645 AUDIT_ARG(svipc_id, semid);
9bccf70c 646 SUBSYSTEM_LOCK_AQUIRE(p);
1c79356b
A
647#ifdef SEM_DEBUG
648 printf("call to semctl(%d, %d, %d, 0x%x)\n", semid, semnum, cmd, arg);
649#endif
650
651 semid = IPCID_TO_IX(semid);
55e303ae 652 if (semid < 0 || semid >= seminfo.semmni)
9bccf70c
A
653{
654#ifdef SEM_DEBUG
655 printf("Invalid semid\n");
656#endif
657 UNLOCK_AND_RETURN(EINVAL);
658}
1c79356b
A
659
660 semaptr = &sema[semid];
661 if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0 ||
662 semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid))
9bccf70c 663 UNLOCK_AND_RETURN(EINVAL);
1c79356b
A
664
665 eval = 0;
666 rval = 0;
667
668 switch (cmd) {
669 case IPC_RMID:
670 if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_M)))
9bccf70c 671 UNLOCK_AND_RETURN(eval);
1c79356b
A
672 semaptr->sem_perm.cuid = cred->cr_uid;
673 semaptr->sem_perm.uid = cred->cr_uid;
674 semtot -= semaptr->sem_nsems;
675 for (i = semaptr->sem_base - sem; i < semtot; i++)
676 sem[i] = sem[i + semaptr->sem_nsems];
677 for (i = 0; i < seminfo.semmni; i++) {
678 if ((sema[i].sem_perm.mode & SEM_ALLOC) &&
679 sema[i].sem_base > semaptr->sem_base)
680 sema[i].sem_base -= semaptr->sem_nsems;
681 }
682 semaptr->sem_perm.mode = 0;
683 semundo_clear(semid, -1);
684 wakeup((caddr_t)semaptr);
685 break;
686
687 case IPC_SET:
688 if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_M)))
9bccf70c
A
689 UNLOCK_AND_RETURN(eval);
690 /*if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
691 UNLOCK_AND_RETURN(eval);*/
692 if ((eval = copyin(arg.buf, (caddr_t)&sbuf,
1c79356b 693 sizeof(sbuf))) != 0)
9bccf70c 694 UNLOCK_AND_RETURN(eval);
1c79356b
A
695 semaptr->sem_perm.uid = sbuf.sem_perm.uid;
696 semaptr->sem_perm.gid = sbuf.sem_perm.gid;
697 semaptr->sem_perm.mode = (semaptr->sem_perm.mode & ~0777) |
698 (sbuf.sem_perm.mode & 0777);
699 semaptr->sem_ctime = time_second;
700 break;
701
702 case IPC_STAT:
703 if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
9bccf70c
A
704 UNLOCK_AND_RETURN(eval);
705 /*if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
706 UNLOCK_AND_RETURN(eval);*/
707 eval = copyout((caddr_t)semaptr, arg.buf,
1c79356b
A
708 sizeof(struct semid_ds));
709 break;
710
711 case GETNCNT:
712 if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
9bccf70c 713 UNLOCK_AND_RETURN(eval);
1c79356b 714 if (semnum < 0 || semnum >= semaptr->sem_nsems)
9bccf70c 715 UNLOCK_AND_RETURN(EINVAL);
1c79356b
A
716 rval = semaptr->sem_base[semnum].semncnt;
717 break;
718
719 case GETPID:
720 if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
9bccf70c 721 UNLOCK_AND_RETURN(eval);
1c79356b 722 if (semnum < 0 || semnum >= semaptr->sem_nsems)
9bccf70c 723 UNLOCK_AND_RETURN(EINVAL);
1c79356b
A
724 rval = semaptr->sem_base[semnum].sempid;
725 break;
726
727 case GETVAL:
728 if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
9bccf70c 729 UNLOCK_AND_RETURN(eval);
1c79356b 730 if (semnum < 0 || semnum >= semaptr->sem_nsems)
9bccf70c 731 UNLOCK_AND_RETURN(EINVAL);
1c79356b
A
732 rval = semaptr->sem_base[semnum].semval;
733 break;
734
735 case GETALL:
736 if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
9bccf70c
A
737 UNLOCK_AND_RETURN(eval);
738 /*if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
739 UNLOCK_AND_RETURN(eval);*/
1c79356b
A
740 for (i = 0; i < semaptr->sem_nsems; i++) {
741 eval = copyout((caddr_t)&semaptr->sem_base[i].semval,
9bccf70c 742 &arg.array[i], sizeof(arg.array[0]));
1c79356b
A
743 if (eval != 0)
744 break;
745 }
746 break;
747
748 case GETZCNT:
749 if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
9bccf70c 750 UNLOCK_AND_RETURN(eval);
1c79356b 751 if (semnum < 0 || semnum >= semaptr->sem_nsems)
9bccf70c 752 UNLOCK_AND_RETURN(EINVAL);
1c79356b
A
753 rval = semaptr->sem_base[semnum].semzcnt;
754 break;
755
756 case SETVAL:
757 if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_W)))
9bccf70c
A
758 {
759#ifdef SEM_DEBUG
760 printf("Invalid credentials for write\n");
761#endif
762 UNLOCK_AND_RETURN(eval);
763 }
1c79356b 764 if (semnum < 0 || semnum >= semaptr->sem_nsems)
9bccf70c
A
765 {
766#ifdef SEM_DEBUG
767 printf("Invalid number out of range for set\n");
768#endif
769 UNLOCK_AND_RETURN(EINVAL);
770 }
771 /*if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
772 {
773#ifdef SEM_DEBUG
774 printf("Error during value copyin\n");
775#endif
776 UNLOCK_AND_RETURN(eval);
777 }*/
778 semaptr->sem_base[semnum].semval = arg.val;
1c79356b
A
779 semundo_clear(semid, semnum);
780 wakeup((caddr_t)semaptr);
781 break;
782
783 case SETALL:
784 if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_W)))
9bccf70c
A
785 UNLOCK_AND_RETURN(eval);
786 /*if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
787 UNLOCK_AND_RETURN(eval);*/
1c79356b 788 for (i = 0; i < semaptr->sem_nsems; i++) {
9bccf70c 789 eval = copyin(&arg.array[i],
1c79356b 790 (caddr_t)&semaptr->sem_base[i].semval,
9bccf70c 791 sizeof(arg.array[0]));
1c79356b
A
792 if (eval != 0)
793 break;
794 }
795 semundo_clear(semid, -1);
796 wakeup((caddr_t)semaptr);
797 break;
798
799 default:
9bccf70c 800 UNLOCK_AND_RETURN(EINVAL);
1c79356b
A
801 }
802
803 if (eval == 0)
9bccf70c
A
804 *retval = rval;
805 UNLOCK_AND_RETURN(eval);
1c79356b
A
806}
807
808#ifndef _SYS_SYSPROTO_H_
809struct semget_args {
810 key_t key;
811 int nsems;
812 int semflg;
813};
814#endif
815
816int
9bccf70c 817semget(p, uap, retval)
1c79356b
A
818 struct proc *p;
819 register struct semget_args *uap;
9bccf70c 820 register_t *retval;
1c79356b
A
821{
822 int semid, eval;
823 int key = uap->key;
824 int nsems = uap->nsems;
825 int semflg = uap->semflg;
826 struct ucred *cred = p->p_ucred;
827
9bccf70c 828 SUBSYSTEM_LOCK_AQUIRE(p);
1c79356b 829#ifdef SEM_DEBUG
9bccf70c
A
830 if (key != IPC_PRIVATE)
831 printf("semget(0x%x, %d, 0%o)\n", key, nsems, semflg);
832 else
833 printf("semget(IPC_PRIVATE, %d, 0%o)\n", nsems, semflg);
1c79356b 834#endif
9bccf70c 835
1c79356b
A
836 if (key != IPC_PRIVATE) {
837 for (semid = 0; semid < seminfo.semmni; semid++) {
838 if ((sema[semid].sem_perm.mode & SEM_ALLOC) &&
839 sema[semid].sem_perm.key == key)
840 break;
841 }
842 if (semid < seminfo.semmni) {
843#ifdef SEM_DEBUG
844 printf("found public key\n");
845#endif
846 if ((eval = ipcperm(cred, &sema[semid].sem_perm,
847 semflg & 0700)))
9bccf70c 848 UNLOCK_AND_RETURN(eval);
1c79356b
A
849 if (nsems > 0 && sema[semid].sem_nsems < nsems) {
850#ifdef SEM_DEBUG
851 printf("too small\n");
852#endif
9bccf70c 853 UNLOCK_AND_RETURN(EINVAL);
1c79356b
A
854 }
855 if ((semflg & IPC_CREAT) && (semflg & IPC_EXCL)) {
856#ifdef SEM_DEBUG
857 printf("not exclusive\n");
858#endif
9bccf70c 859 UNLOCK_AND_RETURN(EEXIST);
1c79356b
A
860 }
861 goto found;
862 }
863 }
864
865#ifdef SEM_DEBUG
9bccf70c 866 printf("need to allocate an id for the request\n");
1c79356b
A
867#endif
868 if (key == IPC_PRIVATE || (semflg & IPC_CREAT)) {
55e303ae 869 if (nsems <= 0 || nsems > limitseminfo.semmsl) {
1c79356b
A
870#ifdef SEM_DEBUG
871 printf("nsems out of range (0<%d<=%d)\n", nsems,
872 seminfo.semmsl);
873#endif
9bccf70c 874 UNLOCK_AND_RETURN(EINVAL);
1c79356b
A
875 }
876 if (nsems > seminfo.semmns - semtot) {
877#ifdef SEM_DEBUG
878 printf("not enough semaphores left (need %d, got %d)\n",
879 nsems, seminfo.semmns - semtot);
880#endif
9bccf70c
A
881 if (!grow_sem_array(semtot + nsems))
882 {
883#ifdef SEM_DEBUG
884 printf("failed to grow the sem array\n");
885#endif
886 UNLOCK_AND_RETURN(ENOSPC);
887 }
1c79356b
A
888 }
889 for (semid = 0; semid < seminfo.semmni; semid++) {
890 if ((sema[semid].sem_perm.mode & SEM_ALLOC) == 0)
891 break;
892 }
893 if (semid == seminfo.semmni) {
894#ifdef SEM_DEBUG
9bccf70c 895 printf("no more id's available\n");
1c79356b 896#endif
9bccf70c
A
897 if (!grow_sema_array(seminfo.semmni + 1))
898 {
899#ifdef SEM_DEBUG
900 printf("failed to grow sema array\n");
901#endif
902 UNLOCK_AND_RETURN(ENOSPC);
903 }
1c79356b
A
904 }
905#ifdef SEM_DEBUG
906 printf("semid %d is available\n", semid);
907#endif
908 sema[semid].sem_perm.key = key;
909 sema[semid].sem_perm.cuid = cred->cr_uid;
910 sema[semid].sem_perm.uid = cred->cr_uid;
911 sema[semid].sem_perm.cgid = cred->cr_gid;
912 sema[semid].sem_perm.gid = cred->cr_gid;
913 sema[semid].sem_perm.mode = (semflg & 0777) | SEM_ALLOC;
914 sema[semid].sem_perm.seq =
915 (sema[semid].sem_perm.seq + 1) & 0x7fff;
916 sema[semid].sem_nsems = nsems;
917 sema[semid].sem_otime = 0;
918 sema[semid].sem_ctime = time_second;
919 sema[semid].sem_base = &sem[semtot];
920 semtot += nsems;
921 bzero(sema[semid].sem_base,
922 sizeof(sema[semid].sem_base[0])*nsems);
923#ifdef SEM_DEBUG
924 printf("sembase = 0x%x, next = 0x%x\n", sema[semid].sem_base,
925 &sem[semtot]);
926#endif
927 } else {
928#ifdef SEM_DEBUG
929 printf("didn't find it and wasn't asked to create it\n");
930#endif
9bccf70c 931 UNLOCK_AND_RETURN(ENOENT);
1c79356b
A
932 }
933
934found:
9bccf70c 935 *retval = IXSEQ_TO_IPCID(semid, sema[semid].sem_perm);
55e303ae 936 AUDIT_ARG(svipc_id, *retval);
9bccf70c
A
937#ifdef SEM_DEBUG
938 printf("semget is done, returning %d\n", *retval);
939#endif
940 SUBSYSTEM_LOCK_RELEASE;
1c79356b
A
941 return(0);
942}
943
944#ifndef _SYS_SYSPROTO_H_
945struct semop_args {
946 int semid;
947 struct sembuf *sops;
948 int nsops;
949};
950#endif
951
952int
9bccf70c 953semop(p, uap, retval)
1c79356b
A
954 struct proc *p;
955 register struct semop_args *uap;
9bccf70c 956 register_t *retval;
1c79356b
A
957{
958 int semid = uap->semid;
959 int nsops = uap->nsops;
960 struct sembuf sops[MAX_SOPS];
961 register struct semid_ds *semaptr;
962 register struct sembuf *sopptr;
963 register struct sem *semptr;
964 struct sem_undo *suptr = NULL;
965 struct ucred *cred = p->p_ucred;
966 int i, j, eval;
967 int do_wakeup, do_undos;
968
55e303ae 969 AUDIT_ARG(svipc_id, uap->semid);
9bccf70c 970 SUBSYSTEM_LOCK_AQUIRE(p);
1c79356b
A
971#ifdef SEM_DEBUG
972 printf("call to semop(%d, 0x%x, %d)\n", semid, sops, nsops);
973#endif
974
975 semid = IPCID_TO_IX(semid); /* Convert back to zero origin */
976
55e303ae 977 if (semid < 0 || semid >= seminfo.semmni)
9bccf70c 978 UNLOCK_AND_RETURN(EINVAL);
1c79356b
A
979
980 semaptr = &sema[semid];
981 if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0)
9bccf70c 982 UNLOCK_AND_RETURN(EINVAL);
1c79356b 983 if (semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid))
9bccf70c 984 UNLOCK_AND_RETURN(EINVAL);
1c79356b
A
985
986 if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_W))) {
987#ifdef SEM_DEBUG
988 printf("eval = %d from ipaccess\n", eval);
989#endif
9bccf70c 990 UNLOCK_AND_RETURN(eval);
1c79356b
A
991 }
992
a3d08fcd 993 if (nsops < 0 || nsops > MAX_SOPS) {
1c79356b
A
994#ifdef SEM_DEBUG
995 printf("too many sops (max=%d, nsops=%d)\n", MAX_SOPS, nsops);
996#endif
9bccf70c 997 UNLOCK_AND_RETURN(E2BIG);
1c79356b
A
998 }
999
1000 if ((eval = copyin(uap->sops, &sops, nsops * sizeof(sops[0]))) != 0) {
1001#ifdef SEM_DEBUG
9bccf70c 1002 printf("eval = %d from copyin(%08x, %08x, %ld)\n", eval,
1c79356b
A
1003 uap->sops, &sops, nsops * sizeof(sops[0]));
1004#endif
9bccf70c 1005 UNLOCK_AND_RETURN(eval);
1c79356b
A
1006 }
1007
1008 /*
1009 * Loop trying to satisfy the vector of requests.
1010 * If we reach a point where we must wait, any requests already
1011 * performed are rolled back and we go to sleep until some other
1012 * process wakes us up. At this point, we start all over again.
1013 *
1014 * This ensures that from the perspective of other tasks, a set
1015 * of requests is atomic (never partially satisfied).
1016 */
1017 do_undos = 0;
1018
1019 for (;;) {
1020 do_wakeup = 0;
1021
1022 for (i = 0; i < nsops; i++) {
1023 sopptr = &sops[i];
1024
1025 if (sopptr->sem_num >= semaptr->sem_nsems)
9bccf70c 1026 UNLOCK_AND_RETURN(EFBIG);
1c79356b
A
1027
1028 semptr = &semaptr->sem_base[sopptr->sem_num];
1029
1030#ifdef SEM_DEBUG
1031 printf("semop: semaptr=%x, sem_base=%x, semptr=%x, sem[%d]=%d : op=%d, flag=%s\n",
1032 semaptr, semaptr->sem_base, semptr,
1033 sopptr->sem_num, semptr->semval, sopptr->sem_op,
1034 (sopptr->sem_flg & IPC_NOWAIT) ? "nowait" : "wait");
1035#endif
1036
1037 if (sopptr->sem_op < 0) {
1038 if (semptr->semval + sopptr->sem_op < 0) {
1039#ifdef SEM_DEBUG
1040 printf("semop: can't do it now\n");
1041#endif
1042 break;
1043 } else {
1044 semptr->semval += sopptr->sem_op;
1045 if (semptr->semval == 0 &&
1046 semptr->semzcnt > 0)
1047 do_wakeup = 1;
1048 }
1049 if (sopptr->sem_flg & SEM_UNDO)
1050 do_undos = 1;
1051 } else if (sopptr->sem_op == 0) {
1052 if (semptr->semval > 0) {
1053#ifdef SEM_DEBUG
1054 printf("semop: not zero now\n");
1055#endif
1056 break;
1057 }
1058 } else {
1059 if (semptr->semncnt > 0)
1060 do_wakeup = 1;
1061 semptr->semval += sopptr->sem_op;
1062 if (sopptr->sem_flg & SEM_UNDO)
1063 do_undos = 1;
1064 }
1065 }
1066
1067 /*
1068 * Did we get through the entire vector?
1069 */
1070 if (i >= nsops)
1071 goto done;
1072
1073 /*
1074 * No ... rollback anything that we've already done
1075 */
1076#ifdef SEM_DEBUG
1077 printf("semop: rollback 0 through %d\n", i-1);
1078#endif
1079 for (j = 0; j < i; j++)
1080 semaptr->sem_base[sops[j].sem_num].semval -=
1081 sops[j].sem_op;
1082
1083 /*
1084 * If the request that we couldn't satisfy has the
1085 * NOWAIT flag set then return with EAGAIN.
1086 */
1087 if (sopptr->sem_flg & IPC_NOWAIT)
9bccf70c 1088 UNLOCK_AND_RETURN(EAGAIN);
1c79356b
A
1089
1090 if (sopptr->sem_op == 0)
1091 semptr->semzcnt++;
1092 else
1093 semptr->semncnt++;
1094
1095#ifdef SEM_DEBUG
1096 printf("semop: good night!\n");
1097#endif
9bccf70c
A
1098 /* Release our lock on the semaphore subsystem so
1099 * another thread can get at the semaphore we are
1100 * waiting for. We will get the lock back after we
1101 * wake up.
1102 */
1103 SUBSYSTEM_LOCK_RELEASE;
1104 sysv_sem_sleeping_threads++;
1c79356b
A
1105 eval = tsleep((caddr_t)semaptr, (PZERO - 4) | PCATCH,
1106 "semwait", 0);
9bccf70c
A
1107 sysv_sem_sleeping_threads--;
1108
1c79356b
A
1109#ifdef SEM_DEBUG
1110 printf("semop: good morning (eval=%d)!\n", eval);
1111#endif
9bccf70c
A
1112 /* There is no need to get the lock if we are just
1113 * going to return without performing more semaphore
1114 * operations.
1115 */
1116 if (eval != 0)
1117 return(EINTR);
1c79356b 1118
9bccf70c 1119 SUBSYSTEM_LOCK_AQUIRE(p); /* Get it back */
1c79356b 1120 suptr = NULL; /* sem_undo may have been reallocated */
9bccf70c
A
1121 semaptr = &sema[semid]; /* sema may have been reallocated */
1122
1c79356b 1123
1c79356b
A
1124#ifdef SEM_DEBUG
1125 printf("semop: good morning!\n");
1126#endif
1127
1128 /*
1129 * Make sure that the semaphore still exists
1130 */
1131 if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0 ||
1132 semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid)) {
1133 /* The man page says to return EIDRM. */
1134 /* Unfortunately, BSD doesn't define that code! */
1135#ifdef EIDRM
9bccf70c 1136 UNLOCK_AND_RETURN(EIDRM);
1c79356b 1137#else
9bccf70c 1138 UNLOCK_AND_RETURN(EINVAL);
1c79356b
A
1139#endif
1140 }
1141
1142 /*
1143 * The semaphore is still alive. Readjust the count of
9bccf70c
A
1144 * waiting processes. semptr needs to be recomputed
1145 * because the sem[] may have been reallocated while
1146 * we were sleeping, updating our sem_base pointer.
1c79356b 1147 */
9bccf70c 1148 semptr = &semaptr->sem_base[sopptr->sem_num];
1c79356b
A
1149 if (sopptr->sem_op == 0)
1150 semptr->semzcnt--;
1151 else
1152 semptr->semncnt--;
1153 }
1154
1155done:
1156 /*
1157 * Process any SEM_UNDO requests.
1158 */
1159 if (do_undos) {
1160 for (i = 0; i < nsops; i++) {
1161 /*
1162 * We only need to deal with SEM_UNDO's for non-zero
1163 * op's.
1164 */
1165 int adjval;
1166
1167 if ((sops[i].sem_flg & SEM_UNDO) == 0)
1168 continue;
1169 adjval = sops[i].sem_op;
1170 if (adjval == 0)
1171 continue;
1172 eval = semundo_adjust(p, &suptr, semid,
1173 sops[i].sem_num, -adjval);
1174 if (eval == 0)
1175 continue;
1176
1177 /*
1178 * Oh-Oh! We ran out of either sem_undo's or undo's.
1179 * Rollback the adjustments to this point and then
1180 * rollback the semaphore ups and down so we can return
1181 * with an error with all structures restored. We
1182 * rollback the undo's in the exact reverse order that
1183 * we applied them. This guarantees that we won't run
1184 * out of space as we roll things back out.
1185 */
1186 for (j = i - 1; j >= 0; j--) {
1187 if ((sops[j].sem_flg & SEM_UNDO) == 0)
1188 continue;
1189 adjval = sops[j].sem_op;
1190 if (adjval == 0)
1191 continue;
1192 if (semundo_adjust(p, &suptr, semid,
1193 sops[j].sem_num, adjval) != 0)
1194 panic("semop - can't undo undos");
1195 }
1196
1197 for (j = 0; j < nsops; j++)
1198 semaptr->sem_base[sops[j].sem_num].semval -=
1199 sops[j].sem_op;
1200
1201#ifdef SEM_DEBUG
1202 printf("eval = %d from semundo_adjust\n", eval);
1203#endif
9bccf70c 1204 UNLOCK_AND_RETURN(eval);
1c79356b
A
1205 } /* loop through the sops */
1206 } /* if (do_undos) */
1207
1208 /* We're definitely done - set the sempid's */
1209 for (i = 0; i < nsops; i++) {
1210 sopptr = &sops[i];
1211 semptr = &semaptr->sem_base[sopptr->sem_num];
1212 semptr->sempid = p->p_pid;
1213 }
1214
9bccf70c
A
1215 /* Do a wakeup if any semaphore was up'd.
1216 * we will release our lock on the semaphore subsystem before
1217 * we wakeup other processes to prevent a little thrashing.
1218 * Note that this is fine because we are done using the
1219 * semaphore structures at this point in time. We only use
1220 * a local variable pointer value, and the retval
1221 * parameter.
1222 * Note 2: Future use of sem_wakeup may reqiure the lock.
1223 */
1224 SUBSYSTEM_LOCK_RELEASE;
1c79356b
A
1225 if (do_wakeup) {
1226#ifdef SEM_DEBUG
1227 printf("semop: doing wakeup\n");
1228#ifdef SEM_WAKEUP
1229 sem_wakeup((caddr_t)semaptr);
1230#else
1231 wakeup((caddr_t)semaptr);
1232#endif
1233 printf("semop: back from wakeup\n");
1234#else
1235 wakeup((caddr_t)semaptr);
1236#endif
1237 }
1238#ifdef SEM_DEBUG
1239 printf("semop: done\n");
1240#endif
9bccf70c 1241 *retval = 0;
1c79356b
A
1242 return(0);
1243}
1244
1245/*
1246 * Go through the undo structures for this process and apply the adjustments to
1247 * semaphores.
1248 */
1249void
1250semexit(p)
1251 struct proc *p;
1252{
1253 register struct sem_undo *suptr;
1254 register struct sem_undo **supptr;
1255 int did_something;
1256
9bccf70c
A
1257 /* If we have not allocated our semaphores yet there can't be
1258 * anything to undo, but we need the lock to prevent
1259 * dynamic memory race conditions.
1c79356b 1260 */
9bccf70c
A
1261 SUBSYSTEM_LOCK_AQUIRE(p);
1262 if (!sem)
1263 {
1264 SUBSYSTEM_LOCK_RELEASE;
1265 return;
1c79356b 1266 }
1c79356b
A
1267 did_something = 0;
1268
1269 /*
1270 * Go through the chain of undo vectors looking for one
1271 * associated with this process.
1272 */
1273
1274 for (supptr = &semu_list; (suptr = *supptr) != NULL;
1275 supptr = &suptr->un_next) {
1276 if (suptr->un_proc == p)
1277 break;
1278 }
1279
1280 if (suptr == NULL)
1281 goto unlock;
1282
1283#ifdef SEM_DEBUG
1284 printf("proc @%08x has undo structure with %d entries\n", p,
1285 suptr->un_cnt);
1286#endif
1287
1288 /*
1289 * If there are any active undo elements then process them.
1290 */
1291 if (suptr->un_cnt > 0) {
1292 int ix;
1293
1294 for (ix = 0; ix < suptr->un_cnt; ix++) {
1295 int semid = suptr->un_ent[ix].un_id;
1296 int semnum = suptr->un_ent[ix].un_num;
1297 int adjval = suptr->un_ent[ix].un_adjval;
1298 struct semid_ds *semaptr;
1299
1300 semaptr = &sema[semid];
1301 if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0)
1302 panic("semexit - semid not allocated");
1303 if (semnum >= semaptr->sem_nsems)
1304 panic("semexit - semnum out of range");
1305
1306#ifdef SEM_DEBUG
1307 printf("semexit: %08x id=%d num=%d(adj=%d) ; sem=%d\n",
1308 suptr->un_proc, suptr->un_ent[ix].un_id,
1309 suptr->un_ent[ix].un_num,
1310 suptr->un_ent[ix].un_adjval,
1311 semaptr->sem_base[semnum].semval);
1312#endif
1313
1314 if (adjval < 0) {
1315 if (semaptr->sem_base[semnum].semval < -adjval)
1316 semaptr->sem_base[semnum].semval = 0;
1317 else
1318 semaptr->sem_base[semnum].semval +=
1319 adjval;
1320 } else
1321 semaptr->sem_base[semnum].semval += adjval;
1322
9bccf70c
A
1323 /* Maybe we should build a list of semaptr's to wake
1324 * up, finish all access to data structures, release the
1325 * subsystem lock, and wake all the processes. Something
1326 * to think about. It wouldn't buy us anything unless
1327 * wakeup had the potential to block, or the syscall
1328 * funnel state was changed to allow multiple threads
1329 * in the BSD code at once.
1330 */
1c79356b
A
1331#ifdef SEM_WAKEUP
1332 sem_wakeup((caddr_t)semaptr);
1333#else
1334 wakeup((caddr_t)semaptr);
1335#endif
1336#ifdef SEM_DEBUG
1337 printf("semexit: back from wakeup\n");
1338#endif
1339 }
1340 }
1341
1342 /*
1343 * Deallocate the undo vector.
1344 */
1345#ifdef SEM_DEBUG
1346 printf("removing vector\n");
1347#endif
1348 suptr->un_proc = NULL;
1349 *supptr = suptr->un_next;
1350
1351unlock:
1352 /*
9bccf70c
A
1353 * There is a semaphore leak (i.e. memory leak) in this code.
1354 * We should be deleting the IPC_PRIVATE semaphores when they are
1355 * no longer needed, and we dont. We would have to track which processes
1356 * know about which IPC_PRIVATE semaphores, updating the list after
1357 * every fork. We can't just delete them semaphore when the process
1358 * that created it dies, because that process may well have forked
1359 * some children. So we need to wait until all of it's children have
1360 * died, and so on. Maybe we should tag each IPC_PRIVATE sempahore
1361 * with the creating group ID, count the number of processes left in
1362 * that group, and delete the semaphore when the group is gone.
1363 * Until that code gets implemented we will leak IPC_PRIVATE semaphores.
1364 * There is an upper bound on the size of our semaphore array, so
1365 * leaking the semaphores should not work as a DOS attack.
1366 *
1367 * Please note that the original BSD code this file is based on had the
1368 * same leaky semaphore problem.
1369 */
1370
1371 SUBSYSTEM_LOCK_RELEASE;
1c79356b 1372}
55e303ae
A
1373/* (struct sysctl_oid *oidp, void *arg1, int arg2, \
1374 struct sysctl_req *req) */
1375static int
1376sysctl_seminfo SYSCTL_HANDLER_ARGS
1377{
1378 int error = 0;
1379
1380 error = SYSCTL_OUT(req, arg1, sizeof(int));
1381 if (error || !req->newptr)
1382 return(error);
1383
1384 SUBSYSTEM_LOCK_AQUIRE(current_proc());
1385 /* Set the values only if shared memory is not initialised */
1386 if ((sem == (struct sem *) 0) &&
1387 (sema == (struct semid_ds *) 0) &&
1388 (semu == (struct semid_ds *) 0) &&
1389 (semu_list == (struct sem_undo *) 0)) {
1390 if (error = SYSCTL_IN(req, arg1, sizeof(int))) {
1391 goto out;
1392 }
1393 } else
1394 error = EINVAL;
1395out:
1396 SUBSYSTEM_LOCK_RELEASE;
1397 return(error);
1398
1399}
1400
1401/* SYSCTL_NODE(_kern, KERN_SYSV, sysv, CTLFLAG_RW, 0, "SYSV"); */
1402extern struct sysctl_oid_list sysctl__kern_sysv_children;
1403SYSCTL_PROC(_kern_sysv, KSYSV_SEMMNI, semmni, CTLTYPE_INT | CTLFLAG_RW,
1404 &limitseminfo.semmni, 0, &sysctl_seminfo ,"I","semmni");
1405
1406SYSCTL_PROC(_kern_sysv, KSYSV_SEMMNS, semmns, CTLTYPE_INT | CTLFLAG_RW,
1407 &limitseminfo.semmns, 0, &sysctl_seminfo ,"I","semmns");
1408
1409SYSCTL_PROC(_kern_sysv, KSYSV_SEMMNU, semmnu, CTLTYPE_INT | CTLFLAG_RW,
1410 &limitseminfo.semmnu, 0, &sysctl_seminfo ,"I","semmnu");
1411
1412SYSCTL_PROC(_kern_sysv, KSYSV_SEMMSL, semmsl, CTLTYPE_INT | CTLFLAG_RW,
1413 &limitseminfo.semmsl, 0, &sysctl_seminfo ,"I","semmsl");
1414
1415SYSCTL_PROC(_kern_sysv, KSYSV_SEMUNE, semume, CTLTYPE_INT | CTLFLAG_RW,
1416 &limitseminfo.semume, 0, &sysctl_seminfo ,"I","semume");
1417
9bccf70c 1418