1 /* $FreeBSD: src/sys/kern/sysv_sem.c,v 1.69 2004/03/17 09:37:13 cperciva Exp $ */
2 /* $DragonFly: src/sys/kern/sysv_sem.c,v 1.18 2006/12/23 23:47:54 swildner Exp $ */
5 * Implementation of SVID semaphores
7 * Author: Daniel Boulet
9 * This software is provided ``AS IS'' without any warranties of any kind.
12 #include "opt_sysvipc.h"
14 #include <sys/param.h>
15 #include <sys/systm.h>
16 #include <sys/sysproto.h>
17 #include <sys/kernel.h>
20 #include <sys/sysent.h>
21 #include <sys/sysctl.h>
22 #include <sys/malloc.h>
25 static MALLOC_DEFINE(M_SEM
, "sem", "SVID compatible semaphores");
27 static void seminit (void *);
29 static struct sem_undo
*semu_alloc (struct proc
*p
);
30 static int semundo_adjust (struct proc
*p
, struct sem_undo
**supptr
,
31 int semid
, int semnum
, int adjval
);
32 static void semundo_clear (int semid
, int semnum
);
34 /* XXX casting to (sy_call_t *) is bogus, as usual. */
35 static sy_call_t
*semcalls
[] = {
36 (sy_call_t
*)sys___semctl
, (sy_call_t
*)sys_semget
,
37 (sy_call_t
*)sys_semop
40 static int semtot
= 0;
41 static struct semid_ds
*sema
; /* semaphore id pool */
42 static struct sem
*sem
; /* semaphore pool */
43 static struct sem_undo
*semu_list
; /* list of active undo structures */
44 static int *semu
; /* undo structure pool */
47 u_short semval
; /* semaphore value */
48 pid_t sempid
; /* pid of last operation */
49 u_short semncnt
; /* # awaiting semval > cval */
50 u_short semzcnt
; /* # awaiting semval = 0 */
54 * Undo structure (one per process)
57 struct sem_undo
*un_next
; /* ptr to next active undo structure */
58 struct proc
*un_proc
; /* owner of this structure */
59 short un_cnt
; /* # of active entries */
61 short un_adjval
; /* adjust on exit values */
62 short un_num
; /* semaphore # */
63 int un_id
; /* semid */
64 } un_ent
[1]; /* undo entries */
68 * Configuration parameters
71 #define SEMMNI 10 /* # of semaphore identifiers */
74 #define SEMMNS 60 /* # of semaphores in system */
77 #define SEMUME 10 /* max # of undo entries per process */
80 #define SEMMNU 30 /* # of undo structures in system */
83 /* shouldn't need tuning */
85 #define SEMMAP 30 /* # of entries in semaphore map */
88 #define SEMMSL SEMMNS /* max # of semaphores per id */
91 #define SEMOPM 100 /* max # of operations per semop call */
94 #define SEMVMX 32767 /* semaphore maximum value */
95 #define SEMAEM 16384 /* adjust on exit max value */
98 * Due to the way semaphore memory is allocated, we have to ensure that
99 * SEMUSZ is properly aligned.
102 #define SEM_ALIGN(bytes) (((bytes) + (sizeof(long) - 1)) & ~(sizeof(long) - 1))
104 /* actual size of an undo structure */
105 #define SEMUSZ SEM_ALIGN(offsetof(struct sem_undo, un_ent[SEMUME]))
108 * Macro to find a particular sem_undo vector
110 #define SEMU(ix) ((struct sem_undo *)(((intptr_t)semu)+ix * seminfo.semusz))
113 * semaphore info struct
115 struct seminfo seminfo
= {
116 SEMMAP
, /* # of entries in semaphore map */
117 SEMMNI
, /* # of semaphore identifiers */
118 SEMMNS
, /* # of semaphores in system */
119 SEMMNU
, /* # of undo structures in system */
120 SEMMSL
, /* max # of semaphores per id */
121 SEMOPM
, /* max # of operations per semop call */
122 SEMUME
, /* max # of undo entries per process */
123 SEMUSZ
, /* size in bytes of undo structure */
124 SEMVMX
, /* semaphore maximum value */
125 SEMAEM
/* adjust on exit max value */
128 TUNABLE_INT("kern.ipc.semmap", &seminfo
.semmap
);
129 TUNABLE_INT("kern.ipc.semmni", &seminfo
.semmni
);
130 TUNABLE_INT("kern.ipc.semmns", &seminfo
.semmns
);
131 TUNABLE_INT("kern.ipc.semmnu", &seminfo
.semmnu
);
132 TUNABLE_INT("kern.ipc.semmsl", &seminfo
.semmsl
);
133 TUNABLE_INT("kern.ipc.semopm", &seminfo
.semopm
);
134 TUNABLE_INT("kern.ipc.semume", &seminfo
.semume
);
135 TUNABLE_INT("kern.ipc.semusz", &seminfo
.semusz
);
136 TUNABLE_INT("kern.ipc.semvmx", &seminfo
.semvmx
);
137 TUNABLE_INT("kern.ipc.semaem", &seminfo
.semaem
);
139 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semmap
, CTLFLAG_RW
, &seminfo
.semmap
, 0, "");
140 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semmni
, CTLFLAG_RD
, &seminfo
.semmni
, 0, "");
141 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semmns
, CTLFLAG_RD
, &seminfo
.semmns
, 0, "");
142 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semmnu
, CTLFLAG_RD
, &seminfo
.semmnu
, 0, "");
143 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semmsl
, CTLFLAG_RW
, &seminfo
.semmsl
, 0, "");
144 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semopm
, CTLFLAG_RD
, &seminfo
.semopm
, 0, "");
145 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semume
, CTLFLAG_RD
, &seminfo
.semume
, 0, "");
146 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semusz
, CTLFLAG_RD
, &seminfo
.semusz
, 0, "");
147 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semvmx
, CTLFLAG_RW
, &seminfo
.semvmx
, 0, "");
148 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semaem
, CTLFLAG_RW
, &seminfo
.semaem
, 0, "");
151 RO seminfo
.semmap
/* SEMMAP unused */
154 RO seminfo
.semmnu
/* undo entries per system */
156 RO seminfo
.semopm
/* SEMOPM unused */
158 RO seminfo
.semusz
/* param - derived from SEMUME for per-proc sizeof */
159 RO seminfo
.semvmx
/* SEMVMX unused - user param */
160 RO seminfo
.semaem
/* SEMAEM unused - user param */
168 sem
= kmalloc(sizeof(struct sem
) * seminfo
.semmns
, M_SEM
, M_WAITOK
);
170 panic("sem is NULL");
171 sema
= kmalloc(sizeof(struct semid_ds
) * seminfo
.semmni
, M_SEM
, M_WAITOK
);
173 panic("sema is NULL");
174 semu
= kmalloc(seminfo
.semmnu
* seminfo
.semusz
, M_SEM
, M_WAITOK
);
176 panic("semu is NULL");
178 for (i
= 0; i
< seminfo
.semmni
; i
++) {
179 sema
[i
].sem_base
= 0;
180 sema
[i
].sem_perm
.mode
= 0;
182 for (i
= 0; i
< seminfo
.semmnu
; i
++) {
183 struct sem_undo
*suptr
= SEMU(i
);
184 suptr
->un_proc
= NULL
;
188 SYSINIT(sysv_sem
, SI_SUB_SYSV_SEM
, SI_ORDER_FIRST
, seminit
, NULL
)
191 * Entry point for all SEM calls
193 * semsys_args(int which, a2, a3, ...) (VARARGS)
196 sys_semsys(struct semsys_args
*uap
)
198 struct proc
*p
= curproc
;
199 unsigned int which
= (unsigned int)uap
->which
;
201 if (!jail_sysvipc_allowed
&& p
->p_ucred
->cr_prison
!= NULL
)
204 if (which
>= sizeof(semcalls
)/sizeof(semcalls
[0]))
206 bcopy(&uap
->a2
, &uap
->which
,
207 sizeof(struct semsys_args
) - offsetof(struct semsys_args
, a2
));
208 return ((*semcalls
[which
])(uap
));
212 * Allocate a new sem_undo structure for a process
213 * (returns ptr to structure or NULL if no more room)
216 static struct sem_undo
*
217 semu_alloc(struct proc
*p
)
220 struct sem_undo
*suptr
;
221 struct sem_undo
**supptr
;
225 * Try twice to allocate something.
226 * (we'll purge any empty structures after the first pass so
227 * two passes are always enough)
230 for (attempt
= 0; attempt
< 2; attempt
++) {
232 * Look for a free structure.
233 * Fill it in and return it if we find one.
236 for (i
= 0; i
< seminfo
.semmnu
; i
++) {
238 if (suptr
->un_proc
== NULL
) {
239 suptr
->un_next
= semu_list
;
248 * We didn't find a free one, if this is the first attempt
249 * then try to free some structures.
253 /* All the structures are in use - try to free some */
254 int did_something
= 0;
257 while ((suptr
= *supptr
) != NULL
) {
258 if (suptr
->un_cnt
== 0) {
259 suptr
->un_proc
= NULL
;
260 *supptr
= suptr
->un_next
;
263 supptr
= &(suptr
->un_next
);
266 /* If we didn't free anything then just give-up */
271 * The second pass failed even though we freed
272 * something after the first pass!
273 * This is IMPOSSIBLE!
275 panic("semu_alloc - second attempt failed");
282 * Adjust a particular entry for a particular proc
286 semundo_adjust(struct proc
*p
, struct sem_undo
**supptr
, int semid
, int semnum
,
289 struct sem_undo
*suptr
;
293 /* Look for and remember the sem_undo if the caller doesn't provide
298 for (suptr
= semu_list
; suptr
!= NULL
;
299 suptr
= suptr
->un_next
) {
300 if (suptr
->un_proc
== p
) {
308 suptr
= semu_alloc(p
);
316 * Look for the requested entry and adjust it (delete if adjval becomes
319 sunptr
= &suptr
->un_ent
[0];
320 for (i
= 0; i
< suptr
->un_cnt
; i
++, sunptr
++) {
321 if (sunptr
->un_id
!= semid
|| sunptr
->un_num
!= semnum
)
324 sunptr
->un_adjval
= 0;
326 sunptr
->un_adjval
+= adjval
;
327 if (sunptr
->un_adjval
== 0) {
329 if (i
< suptr
->un_cnt
)
331 suptr
->un_ent
[suptr
->un_cnt
];
336 /* Didn't find the right entry - create it */
339 if (suptr
->un_cnt
!= seminfo
.semume
) {
340 sunptr
= &suptr
->un_ent
[suptr
->un_cnt
];
342 sunptr
->un_adjval
= adjval
;
343 sunptr
->un_id
= semid
; sunptr
->un_num
= semnum
;
350 semundo_clear(int semid
, int semnum
)
352 struct sem_undo
*suptr
;
354 for (suptr
= semu_list
; suptr
!= NULL
; suptr
= suptr
->un_next
) {
355 struct undo
*sunptr
= &suptr
->un_ent
[0];
358 while (i
< suptr
->un_cnt
) {
359 if (sunptr
->un_id
== semid
) {
360 if (semnum
== -1 || sunptr
->un_num
== semnum
) {
362 if (i
< suptr
->un_cnt
) {
364 suptr
->un_ent
[suptr
->un_cnt
];
377 * Note that the user-mode half of this passes a union, not a pointer
381 sys___semctl(struct __semctl_args
*uap
)
383 struct proc
*p
= curproc
;
384 int semid
= uap
->semid
;
385 int semnum
= uap
->semnum
;
387 union semun
*arg
= uap
->arg
;
388 union semun real_arg
;
389 struct ucred
*cred
= p
->p_ucred
;
391 struct semid_ds sbuf
;
392 struct semid_ds
*semaptr
;
395 kprintf("call to semctl(%d, %d, %d, 0x%x)\n", semid
, semnum
, cmd
, arg
);
398 if (!jail_sysvipc_allowed
&& p
->p_ucred
->cr_prison
!= NULL
)
401 semid
= IPCID_TO_IX(semid
);
402 if (semid
< 0 || semid
>= seminfo
.semmni
)
405 semaptr
= &sema
[semid
];
406 if ((semaptr
->sem_perm
.mode
& SEM_ALLOC
) == 0 ||
407 semaptr
->sem_perm
.seq
!= IPCID_TO_SEQ(uap
->semid
))
415 if ((eval
= ipcperm(p
, &semaptr
->sem_perm
, IPC_M
)))
417 semaptr
->sem_perm
.cuid
= cred
->cr_uid
;
418 semaptr
->sem_perm
.uid
= cred
->cr_uid
;
419 semtot
-= semaptr
->sem_nsems
;
420 for (i
= semaptr
->sem_base
- sem
; i
< semtot
; i
++)
421 sem
[i
] = sem
[i
+ semaptr
->sem_nsems
];
422 for (i
= 0; i
< seminfo
.semmni
; i
++) {
423 if ((sema
[i
].sem_perm
.mode
& SEM_ALLOC
) &&
424 sema
[i
].sem_base
> semaptr
->sem_base
)
425 sema
[i
].sem_base
-= semaptr
->sem_nsems
;
427 semaptr
->sem_perm
.mode
= 0;
428 semundo_clear(semid
, -1);
429 wakeup((caddr_t
)semaptr
);
433 if ((eval
= ipcperm(p
, &semaptr
->sem_perm
, IPC_M
)))
435 if ((eval
= copyin(arg
, &real_arg
, sizeof(real_arg
))) != 0)
437 if ((eval
= copyin(real_arg
.buf
, (caddr_t
)&sbuf
,
440 semaptr
->sem_perm
.uid
= sbuf
.sem_perm
.uid
;
441 semaptr
->sem_perm
.gid
= sbuf
.sem_perm
.gid
;
442 semaptr
->sem_perm
.mode
= (semaptr
->sem_perm
.mode
& ~0777) |
443 (sbuf
.sem_perm
.mode
& 0777);
444 semaptr
->sem_ctime
= time_second
;
448 if ((eval
= ipcperm(p
, &semaptr
->sem_perm
, IPC_R
)))
450 if ((eval
= copyin(arg
, &real_arg
, sizeof(real_arg
))) != 0)
452 eval
= copyout((caddr_t
)semaptr
, real_arg
.buf
,
453 sizeof(struct semid_ds
));
457 if ((eval
= ipcperm(p
, &semaptr
->sem_perm
, IPC_R
)))
459 if (semnum
< 0 || semnum
>= semaptr
->sem_nsems
)
461 rval
= semaptr
->sem_base
[semnum
].semncnt
;
465 if ((eval
= ipcperm(p
, &semaptr
->sem_perm
, IPC_R
)))
467 if (semnum
< 0 || semnum
>= semaptr
->sem_nsems
)
469 rval
= semaptr
->sem_base
[semnum
].sempid
;
473 if ((eval
= ipcperm(p
, &semaptr
->sem_perm
, IPC_R
)))
475 if (semnum
< 0 || semnum
>= semaptr
->sem_nsems
)
477 rval
= semaptr
->sem_base
[semnum
].semval
;
481 if ((eval
= ipcperm(p
, &semaptr
->sem_perm
, IPC_R
)))
483 if ((eval
= copyin(arg
, &real_arg
, sizeof(real_arg
))) != 0)
485 for (i
= 0; i
< semaptr
->sem_nsems
; i
++) {
486 eval
= copyout((caddr_t
)&semaptr
->sem_base
[i
].semval
,
487 &real_arg
.array
[i
], sizeof(real_arg
.array
[0]));
494 if ((eval
= ipcperm(p
, &semaptr
->sem_perm
, IPC_R
)))
496 if (semnum
< 0 || semnum
>= semaptr
->sem_nsems
)
498 rval
= semaptr
->sem_base
[semnum
].semzcnt
;
502 if ((eval
= ipcperm(p
, &semaptr
->sem_perm
, IPC_W
)))
504 if (semnum
< 0 || semnum
>= semaptr
->sem_nsems
)
506 if ((eval
= copyin(arg
, &real_arg
, sizeof(real_arg
))) != 0)
508 semaptr
->sem_base
[semnum
].semval
= real_arg
.val
;
509 semundo_clear(semid
, semnum
);
510 wakeup((caddr_t
)semaptr
);
514 if ((eval
= ipcperm(p
, &semaptr
->sem_perm
, IPC_W
)))
516 if ((eval
= copyin(arg
, &real_arg
, sizeof(real_arg
))) != 0)
518 for (i
= 0; i
< semaptr
->sem_nsems
; i
++) {
519 eval
= copyin(&real_arg
.array
[i
],
520 (caddr_t
)&semaptr
->sem_base
[i
].semval
,
521 sizeof(real_arg
.array
[0]));
525 semundo_clear(semid
, -1);
526 wakeup((caddr_t
)semaptr
);
534 uap
->sysmsg_result
= rval
;
539 sys_semget(struct semget_args
*uap
)
541 struct proc
*p
= curproc
;
544 int nsems
= uap
->nsems
;
545 int semflg
= uap
->semflg
;
546 struct ucred
*cred
= p
->p_ucred
;
549 kprintf("semget(0x%x, %d, 0%o)\n", key
, nsems
, semflg
);
552 if (!jail_sysvipc_allowed
&& p
->p_ucred
->cr_prison
!= NULL
)
555 if (key
!= IPC_PRIVATE
) {
556 for (semid
= 0; semid
< seminfo
.semmni
; semid
++) {
557 if ((sema
[semid
].sem_perm
.mode
& SEM_ALLOC
) &&
558 sema
[semid
].sem_perm
.key
== key
)
561 if (semid
< seminfo
.semmni
) {
563 kprintf("found public key\n");
565 if ((eval
= ipcperm(p
, &sema
[semid
].sem_perm
,
568 if (nsems
> 0 && sema
[semid
].sem_nsems
< nsems
) {
570 kprintf("too small\n");
574 if ((semflg
& IPC_CREAT
) && (semflg
& IPC_EXCL
)) {
576 kprintf("not exclusive\n");
585 kprintf("need to allocate the semid_ds\n");
587 if (key
== IPC_PRIVATE
|| (semflg
& IPC_CREAT
)) {
588 if (nsems
<= 0 || nsems
> seminfo
.semmsl
) {
590 kprintf("nsems out of range (0<%d<=%d)\n", nsems
,
595 if (nsems
> seminfo
.semmns
- semtot
) {
597 kprintf("not enough semaphores left (need %d, got %d)\n",
598 nsems
, seminfo
.semmns
- semtot
);
602 for (semid
= 0; semid
< seminfo
.semmni
; semid
++) {
603 if ((sema
[semid
].sem_perm
.mode
& SEM_ALLOC
) == 0)
606 if (semid
== seminfo
.semmni
) {
608 kprintf("no more semid_ds's available\n");
613 kprintf("semid %d is available\n", semid
);
615 sema
[semid
].sem_perm
.key
= key
;
616 sema
[semid
].sem_perm
.cuid
= cred
->cr_uid
;
617 sema
[semid
].sem_perm
.uid
= cred
->cr_uid
;
618 sema
[semid
].sem_perm
.cgid
= cred
->cr_gid
;
619 sema
[semid
].sem_perm
.gid
= cred
->cr_gid
;
620 sema
[semid
].sem_perm
.mode
= (semflg
& 0777) | SEM_ALLOC
;
621 sema
[semid
].sem_perm
.seq
=
622 (sema
[semid
].sem_perm
.seq
+ 1) & 0x7fff;
623 sema
[semid
].sem_nsems
= nsems
;
624 sema
[semid
].sem_otime
= 0;
625 sema
[semid
].sem_ctime
= time_second
;
626 sema
[semid
].sem_base
= &sem
[semtot
];
628 bzero(sema
[semid
].sem_base
,
629 sizeof(sema
[semid
].sem_base
[0])*nsems
);
631 kprintf("sembase = 0x%x, next = 0x%x\n", sema
[semid
].sem_base
,
636 kprintf("didn't find it and wasn't asked to create it\n");
642 uap
->sysmsg_result
= IXSEQ_TO_IPCID(semid
, sema
[semid
].sem_perm
);
647 sys_semop(struct semop_args
*uap
)
649 struct proc
*p
= curproc
;
650 int semid
= uap
->semid
;
651 u_int nsops
= uap
->nsops
;
652 struct sembuf sops
[MAX_SOPS
];
653 struct semid_ds
*semaptr
;
654 struct sembuf
*sopptr
;
656 struct sem_undo
*suptr
= NULL
;
658 int do_wakeup
, do_undos
;
661 kprintf("call to semop(%d, 0x%x, %u)\n", semid
, sops
, nsops
);
664 if (!jail_sysvipc_allowed
&& p
->p_ucred
->cr_prison
!= NULL
)
667 semid
= IPCID_TO_IX(semid
); /* Convert back to zero origin */
669 if (semid
< 0 || semid
>= seminfo
.semmni
)
672 semaptr
= &sema
[semid
];
673 if ((semaptr
->sem_perm
.mode
& SEM_ALLOC
) == 0)
675 if (semaptr
->sem_perm
.seq
!= IPCID_TO_SEQ(uap
->semid
))
678 if ((eval
= ipcperm(p
, &semaptr
->sem_perm
, IPC_W
))) {
680 kprintf("eval = %d from ipaccess\n", eval
);
685 if (nsops
> MAX_SOPS
) {
687 kprintf("too many sops (max=%d, nsops=%u)\n", MAX_SOPS
, nsops
);
692 if ((eval
= copyin(uap
->sops
, &sops
, nsops
* sizeof(sops
[0]))) != 0) {
694 kprintf("eval = %d from copyin(%08x, %08x, %u)\n", eval
,
695 uap
->sops
, &sops
, nsops
* sizeof(sops
[0]));
701 * Loop trying to satisfy the vector of requests.
702 * If we reach a point where we must wait, any requests already
703 * performed are rolled back and we go to sleep until some other
704 * process wakes us up. At this point, we start all over again.
706 * This ensures that from the perspective of other tasks, a set
707 * of requests is atomic (never partially satisfied).
714 for (i
= 0; i
< nsops
; i
++) {
717 if (sopptr
->sem_num
>= semaptr
->sem_nsems
)
720 semptr
= &semaptr
->sem_base
[sopptr
->sem_num
];
723 kprintf("semop: semaptr=%x, sem_base=%x, semptr=%x, sem[%d]=%d : op=%d, flag=%s\n",
724 semaptr
, semaptr
->sem_base
, semptr
,
725 sopptr
->sem_num
, semptr
->semval
, sopptr
->sem_op
,
726 (sopptr
->sem_flg
& IPC_NOWAIT
) ? "nowait" : "wait");
729 if (sopptr
->sem_op
< 0) {
730 if (semptr
->semval
+ sopptr
->sem_op
< 0) {
732 kprintf("semop: can't do it now\n");
736 semptr
->semval
+= sopptr
->sem_op
;
737 if (semptr
->semval
== 0 &&
741 if (sopptr
->sem_flg
& SEM_UNDO
)
743 } else if (sopptr
->sem_op
== 0) {
744 if (semptr
->semval
> 0) {
746 kprintf("semop: not zero now\n");
751 if (semptr
->semncnt
> 0)
753 semptr
->semval
+= sopptr
->sem_op
;
754 if (sopptr
->sem_flg
& SEM_UNDO
)
760 * Did we get through the entire vector?
766 * No ... rollback anything that we've already done
769 kprintf("semop: rollback 0 through %d\n", i
-1);
771 for (j
= 0; j
< i
; j
++)
772 semaptr
->sem_base
[sops
[j
].sem_num
].semval
-=
776 * If the request that we couldn't satisfy has the
777 * NOWAIT flag set then return with EAGAIN.
779 if (sopptr
->sem_flg
& IPC_NOWAIT
)
782 if (sopptr
->sem_op
== 0)
788 kprintf("semop: good night!\n");
790 eval
= tsleep((caddr_t
)semaptr
, PCATCH
, "semwait", 0);
792 kprintf("semop: good morning (eval=%d)!\n", eval
);
795 suptr
= NULL
; /* sem_undo may have been reallocated */
797 /* return code is checked below, after sem[nz]cnt-- */
800 * Make sure that the semaphore still exists
802 if ((semaptr
->sem_perm
.mode
& SEM_ALLOC
) == 0 ||
803 semaptr
->sem_perm
.seq
!= IPCID_TO_SEQ(uap
->semid
))
807 * The semaphore is still alive. Readjust the count of
810 if (sopptr
->sem_op
== 0)
816 * Is it really morning, or was our sleep interrupted?
817 * (Delayed check of msleep() return code because we
818 * need to decrement sem[nz]cnt either way.)
823 kprintf("semop: good morning!\n");
829 * Process any SEM_UNDO requests.
832 for (i
= 0; i
< nsops
; i
++) {
834 * We only need to deal with SEM_UNDO's for non-zero
839 if ((sops
[i
].sem_flg
& SEM_UNDO
) == 0)
841 adjval
= sops
[i
].sem_op
;
844 eval
= semundo_adjust(p
, &suptr
, semid
,
845 sops
[i
].sem_num
, -adjval
);
850 * Oh-Oh! We ran out of either sem_undo's or undo's.
851 * Rollback the adjustments to this point and then
852 * rollback the semaphore ups and down so we can return
853 * with an error with all structures restored. We
854 * rollback the undo's in the exact reverse order that
855 * we applied them. This guarantees that we won't run
856 * out of space as we roll things back out.
858 for (j
= i
- 1; j
>= 0; j
--) {
859 if ((sops
[j
].sem_flg
& SEM_UNDO
) == 0)
861 adjval
= sops
[j
].sem_op
;
864 if (semundo_adjust(p
, &suptr
, semid
,
865 sops
[j
].sem_num
, adjval
) != 0)
866 panic("semop - can't undo undos");
869 for (j
= 0; j
< nsops
; j
++)
870 semaptr
->sem_base
[sops
[j
].sem_num
].semval
-=
874 kprintf("eval = %d from semundo_adjust\n", eval
);
877 } /* loop through the sops */
878 } /* if (do_undos) */
880 /* We're definitely done - set the sempid's */
881 for (i
= 0; i
< nsops
; i
++) {
883 semptr
= &semaptr
->sem_base
[sopptr
->sem_num
];
884 semptr
->sempid
= p
->p_pid
;
887 /* Do a wakeup if any semaphore was up'd. */
890 kprintf("semop: doing wakeup\n");
892 wakeup((caddr_t
)semaptr
);
894 kprintf("semop: back from wakeup\n");
898 kprintf("semop: done\n");
900 uap
->sysmsg_result
= 0;
905 * Go through the undo structures for this process and apply the adjustments to
909 semexit(struct proc
*p
)
911 struct sem_undo
*suptr
;
912 struct sem_undo
**supptr
;
918 * Go through the chain of undo vectors looking for one
919 * associated with this process.
922 for (supptr
= &semu_list
; (suptr
= *supptr
) != NULL
;
923 supptr
= &suptr
->un_next
) {
924 if (suptr
->un_proc
== p
)
932 kprintf("proc @%08x has undo structure with %d entries\n", p
,
937 * If there are any active undo elements then process them.
939 if (suptr
->un_cnt
> 0) {
942 for (ix
= 0; ix
< suptr
->un_cnt
; ix
++) {
943 int semid
= suptr
->un_ent
[ix
].un_id
;
944 int semnum
= suptr
->un_ent
[ix
].un_num
;
945 int adjval
= suptr
->un_ent
[ix
].un_adjval
;
946 struct semid_ds
*semaptr
;
948 semaptr
= &sema
[semid
];
949 if ((semaptr
->sem_perm
.mode
& SEM_ALLOC
) == 0)
950 panic("semexit - semid not allocated");
951 if (semnum
>= semaptr
->sem_nsems
)
952 panic("semexit - semnum out of range");
955 kprintf("semexit: %08x id=%d num=%d(adj=%d) ; sem=%d\n",
956 suptr
->un_proc
, suptr
->un_ent
[ix
].un_id
,
957 suptr
->un_ent
[ix
].un_num
,
958 suptr
->un_ent
[ix
].un_adjval
,
959 semaptr
->sem_base
[semnum
].semval
);
963 if (semaptr
->sem_base
[semnum
].semval
< -adjval
)
964 semaptr
->sem_base
[semnum
].semval
= 0;
966 semaptr
->sem_base
[semnum
].semval
+=
969 semaptr
->sem_base
[semnum
].semval
+= adjval
;
971 wakeup((caddr_t
)semaptr
);
973 kprintf("semexit: back from wakeup\n");
979 * Deallocate the undo vector.
982 kprintf("removing vector\n");
984 suptr
->un_proc
= NULL
;
985 *supptr
= suptr
->un_next
;