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