1 /* $FreeBSD: src/sys/kern/sysv_sem.c,v 1.69 2004/03/17 09:37:13 cperciva Exp $ */
4 * Implementation of SVID semaphores
6 * Author: Daniel Boulet
8 * This software is provided ``AS IS'' without any warranties of any kind.
11 #include "opt_sysvipc.h"
13 #include <sys/param.h>
14 #include <sys/systm.h>
15 #include <sys/sysproto.h>
16 #include <sys/kernel.h>
19 #include <sys/sysent.h>
20 #include <sys/sysctl.h>
21 #include <sys/malloc.h>
24 #include <sys/mplock2.h>
26 static MALLOC_DEFINE(M_SEM
, "sem", "SVID compatible semaphores");
28 static void seminit (void *);
30 static struct sem_undo
*semu_alloc (struct proc
*p
);
31 static int semundo_adjust (struct proc
*p
, struct sem_undo
**supptr
,
32 int semid
, int semnum
, int adjval
);
33 static void semundo_clear (int semid
, int semnum
);
35 /* XXX casting to (sy_call_t *) is bogus, as usual. */
36 static sy_call_t
*semcalls
[] = {
37 (sy_call_t
*)sys___semctl
, (sy_call_t
*)sys_semget
,
38 (sy_call_t
*)sys_semop
41 static int semtot
= 0;
42 static struct semid_ds
*sema
; /* semaphore id pool */
43 static struct sem
*sem
; /* semaphore pool */
44 static struct sem_undo
*semu_list
; /* list of active undo structures */
45 static int *semu
; /* undo structure pool */
48 u_short semval
; /* semaphore value */
49 pid_t sempid
; /* pid of last operation */
50 u_short semncnt
; /* # awaiting semval > cval */
51 u_short semzcnt
; /* # awaiting semval = 0 */
55 * Undo structure (one per process)
58 struct sem_undo
*un_next
; /* ptr to next active undo structure */
59 struct proc
*un_proc
; /* owner of this structure */
60 short un_cnt
; /* # of active entries */
62 short un_adjval
; /* adjust on exit values */
63 short un_num
; /* semaphore # */
64 int un_id
; /* semid */
65 } un_ent
[1]; /* undo entries */
69 * Configuration parameters
72 #define SEMMNI 10 /* # of semaphore identifiers */
75 #define SEMMNS 60 /* # of semaphores in system */
78 #define SEMUME 10 /* max # of undo entries per process */
81 #define SEMMNU 30 /* # of undo structures in system */
84 /* shouldn't need tuning */
86 #define SEMMAP 30 /* # of entries in semaphore map */
89 #define SEMMSL SEMMNS /* max # of semaphores per id */
92 #define SEMOPM 100 /* max # of operations per semop call */
95 #define SEMVMX 32767 /* semaphore maximum value */
96 #define SEMAEM 16384 /* adjust on exit max value */
99 * Due to the way semaphore memory is allocated, we have to ensure that
100 * SEMUSZ is properly aligned.
103 #define SEM_ALIGN(bytes) (((bytes) + (sizeof(long) - 1)) & ~(sizeof(long) - 1))
105 /* actual size of an undo structure */
106 #define SEMUSZ SEM_ALIGN(offsetof(struct sem_undo, un_ent[SEMUME]))
109 * Macro to find a particular sem_undo vector
111 #define SEMU(ix) ((struct sem_undo *)(((intptr_t)semu)+ix * seminfo.semusz))
114 * semaphore info struct
116 struct seminfo seminfo
= {
117 SEMMAP
, /* # of entries in semaphore map */
118 SEMMNI
, /* # of semaphore identifiers */
119 SEMMNS
, /* # of semaphores in system */
120 SEMMNU
, /* # of undo structures in system */
121 SEMMSL
, /* max # of semaphores per id */
122 SEMOPM
, /* max # of operations per semop call */
123 SEMUME
, /* max # of undo entries per process */
124 SEMUSZ
, /* size in bytes of undo structure */
125 SEMVMX
, /* semaphore maximum value */
126 SEMAEM
/* adjust on exit max value */
129 TUNABLE_INT("kern.ipc.semmap", &seminfo
.semmap
);
130 TUNABLE_INT("kern.ipc.semmni", &seminfo
.semmni
);
131 TUNABLE_INT("kern.ipc.semmns", &seminfo
.semmns
);
132 TUNABLE_INT("kern.ipc.semmnu", &seminfo
.semmnu
);
133 TUNABLE_INT("kern.ipc.semmsl", &seminfo
.semmsl
);
134 TUNABLE_INT("kern.ipc.semopm", &seminfo
.semopm
);
135 TUNABLE_INT("kern.ipc.semume", &seminfo
.semume
);
136 TUNABLE_INT("kern.ipc.semusz", &seminfo
.semusz
);
137 TUNABLE_INT("kern.ipc.semvmx", &seminfo
.semvmx
);
138 TUNABLE_INT("kern.ipc.semaem", &seminfo
.semaem
);
140 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semmap
, CTLFLAG_RW
, &seminfo
.semmap
, 0,
141 "Number of entries in semaphore map");
142 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semmni
, CTLFLAG_RD
, &seminfo
.semmni
, 0,
143 "Number of semaphore identifiers");
144 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semmns
, CTLFLAG_RD
, &seminfo
.semmns
, 0,
145 "Total number of semaphores");
146 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semmnu
, CTLFLAG_RD
, &seminfo
.semmnu
, 0,
147 "Total number of undo structures");
148 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semmsl
, CTLFLAG_RW
, &seminfo
.semmsl
, 0,
149 "Max number of semaphores per id");
150 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semopm
, CTLFLAG_RD
, &seminfo
.semopm
, 0,
151 "Max number of operations per semop call");
152 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semume
, CTLFLAG_RD
, &seminfo
.semume
, 0,
153 "Max number of undo entries per process");
154 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semusz
, CTLFLAG_RD
, &seminfo
.semusz
, 0,
155 "Size in bytes of undo structure");
156 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semvmx
, CTLFLAG_RW
, &seminfo
.semvmx
, 0,
157 "Semaphore maximum value");
158 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semaem
, CTLFLAG_RW
, &seminfo
.semaem
, 0,
159 "Adjust on exit max value");
162 RO seminfo
.semmap
/* SEMMAP unused */
165 RO seminfo
.semmnu
/* undo entries per system */
167 RO seminfo
.semopm
/* SEMOPM unused */
169 RO seminfo
.semusz
/* param - derived from SEMUME for per-proc sizeof */
170 RO seminfo
.semvmx
/* SEMVMX unused - user param */
171 RO seminfo
.semaem
/* SEMAEM unused - user param */
179 sem
= kmalloc(sizeof(struct sem
) * seminfo
.semmns
, M_SEM
, M_WAITOK
);
180 sema
= kmalloc(sizeof(struct semid_ds
) * seminfo
.semmni
, M_SEM
, M_WAITOK
);
181 semu
= kmalloc(seminfo
.semmnu
* seminfo
.semusz
, M_SEM
, M_WAITOK
);
183 for (i
= 0; i
< seminfo
.semmni
; i
++) {
184 sema
[i
].sem_base
= 0;
185 sema
[i
].sem_perm
.mode
= 0;
187 for (i
= 0; i
< seminfo
.semmnu
; i
++) {
188 struct sem_undo
*suptr
= SEMU(i
);
189 suptr
->un_proc
= NULL
;
193 SYSINIT(sysv_sem
, SI_SUB_SYSV_SEM
, SI_ORDER_FIRST
, seminit
, NULL
)
196 * Entry point for all SEM calls
198 * semsys_args(int which, a2, a3, ...) (VARARGS)
203 sys_semsys(struct semsys_args
*uap
)
205 struct thread
*td
= curthread
;
206 unsigned int which
= (unsigned int)uap
->which
;
209 if (!jail_sysvipc_allowed
&& td
->td_ucred
->cr_prison
!= NULL
)
212 if (which
>= NELEM(semcalls
))
214 bcopy(&uap
->a2
, &uap
->which
,
215 sizeof(struct semsys_args
) - offsetof(struct semsys_args
, a2
));
217 error
= (*semcalls
[which
])(uap
);
223 * Allocate a new sem_undo structure for a process
224 * (returns ptr to structure or NULL if no more room)
227 static struct sem_undo
*
228 semu_alloc(struct proc
*p
)
231 struct sem_undo
*suptr
;
232 struct sem_undo
**supptr
;
236 * Try twice to allocate something.
237 * (we'll purge any empty structures after the first pass so
238 * two passes are always enough)
241 for (attempt
= 0; attempt
< 2; attempt
++) {
243 * Look for a free structure.
244 * Fill it in and return it if we find one.
247 for (i
= 0; i
< seminfo
.semmnu
; i
++) {
249 if (suptr
->un_proc
== NULL
) {
250 suptr
->un_next
= semu_list
;
259 * We didn't find a free one, if this is the first attempt
260 * then try to free some structures.
264 /* All the structures are in use - try to free some */
265 int did_something
= 0;
268 while ((suptr
= *supptr
) != NULL
) {
269 if (suptr
->un_cnt
== 0) {
270 suptr
->un_proc
= NULL
;
271 *supptr
= suptr
->un_next
;
274 supptr
= &(suptr
->un_next
);
277 /* If we didn't free anything then just give-up */
282 * The second pass failed even though we freed
283 * something after the first pass!
284 * This is IMPOSSIBLE!
286 panic("semu_alloc - second attempt failed");
293 * Adjust a particular entry for a particular proc
297 semundo_adjust(struct proc
*p
, struct sem_undo
**supptr
, int semid
, int semnum
,
300 struct sem_undo
*suptr
;
304 /* Look for and remember the sem_undo if the caller doesn't provide
309 for (suptr
= semu_list
; suptr
!= NULL
;
310 suptr
= suptr
->un_next
) {
311 if (suptr
->un_proc
== p
) {
319 suptr
= semu_alloc(p
);
327 * Look for the requested entry and adjust it (delete if adjval becomes
330 sunptr
= &suptr
->un_ent
[0];
331 for (i
= 0; i
< suptr
->un_cnt
; i
++, sunptr
++) {
332 if (sunptr
->un_id
!= semid
|| sunptr
->un_num
!= semnum
)
335 sunptr
->un_adjval
= 0;
337 sunptr
->un_adjval
+= adjval
;
338 if (sunptr
->un_adjval
== 0) {
340 if (i
< suptr
->un_cnt
)
342 suptr
->un_ent
[suptr
->un_cnt
];
347 /* Didn't find the right entry - create it */
350 if (suptr
->un_cnt
!= seminfo
.semume
) {
351 sunptr
= &suptr
->un_ent
[suptr
->un_cnt
];
353 sunptr
->un_adjval
= adjval
;
354 sunptr
->un_id
= semid
; sunptr
->un_num
= semnum
;
361 semundo_clear(int semid
, int semnum
)
363 struct sem_undo
*suptr
;
365 for (suptr
= semu_list
; suptr
!= NULL
; suptr
= suptr
->un_next
) {
366 struct undo
*sunptr
= &suptr
->un_ent
[0];
369 while (i
< suptr
->un_cnt
) {
370 if (sunptr
->un_id
== semid
) {
371 if (semnum
== -1 || sunptr
->un_num
== semnum
) {
373 if (i
< suptr
->un_cnt
) {
375 suptr
->un_ent
[suptr
->un_cnt
];
388 * Note that the user-mode half of this passes a union, not a pointer
393 sys___semctl(struct __semctl_args
*uap
)
395 struct thread
*td
= curthread
;
396 int semid
= uap
->semid
;
397 int semnum
= uap
->semnum
;
399 union semun
*arg
= uap
->arg
;
400 union semun real_arg
;
401 struct ucred
*cred
= td
->td_ucred
;
403 struct semid_ds sbuf
;
404 struct semid_ds
*semaptr
;
405 struct semid_ds
*semakptr
;
408 kprintf("call to semctl(%d, %d, %d, 0x%x)\n", semid
, semnum
, cmd
, arg
);
411 if (!jail_sysvipc_allowed
&& cred
->cr_prison
!= NULL
)
418 * For this command we assume semid is an array index
419 * rather than an IPC id.
421 if (semid
< 0 || semid
>= seminfo
.semmni
) {
425 semakptr
= &sema
[semid
];
426 if ((semakptr
->sem_perm
.mode
& SEM_ALLOC
) == 0) {
430 if ((eval
= ipcperm(td
->td_proc
, &semakptr
->sem_perm
, IPC_R
)))
433 bcopy(&semakptr
, arg
->buf
, sizeof(struct semid_ds
));
434 rval
= IXSEQ_TO_IPCID(semid
, semakptr
->sem_perm
);
438 semid
= IPCID_TO_IX(semid
);
439 if (semid
< 0 || semid
>= seminfo
.semmni
) {
444 semaptr
= &sema
[semid
];
445 if ((semaptr
->sem_perm
.mode
& SEM_ALLOC
) == 0 ||
446 semaptr
->sem_perm
.seq
!= IPCID_TO_SEQ(uap
->semid
)) {
456 if ((eval
= ipcperm(td
->td_proc
, &semaptr
->sem_perm
, IPC_M
)) != 0)
458 semaptr
->sem_perm
.cuid
= cred
->cr_uid
;
459 semaptr
->sem_perm
.uid
= cred
->cr_uid
;
460 semtot
-= semaptr
->sem_nsems
;
461 for (i
= semaptr
->sem_base
- sem
; i
< semtot
; i
++)
462 sem
[i
] = sem
[i
+ semaptr
->sem_nsems
];
463 for (i
= 0; i
< seminfo
.semmni
; i
++) {
464 if ((sema
[i
].sem_perm
.mode
& SEM_ALLOC
) &&
465 sema
[i
].sem_base
> semaptr
->sem_base
)
466 sema
[i
].sem_base
-= semaptr
->sem_nsems
;
468 semaptr
->sem_perm
.mode
= 0;
469 semundo_clear(semid
, -1);
470 wakeup((caddr_t
)semaptr
);
474 eval
= ipcperm(td
->td_proc
, &semaptr
->sem_perm
, IPC_M
);
477 if ((eval
= copyin(arg
, &real_arg
, sizeof(real_arg
))) != 0)
479 if ((eval
= copyin(real_arg
.buf
, (caddr_t
)&sbuf
,
480 sizeof(sbuf
))) != 0) {
483 semaptr
->sem_perm
.uid
= sbuf
.sem_perm
.uid
;
484 semaptr
->sem_perm
.gid
= sbuf
.sem_perm
.gid
;
485 semaptr
->sem_perm
.mode
= (semaptr
->sem_perm
.mode
& ~0777) |
486 (sbuf
.sem_perm
.mode
& 0777);
487 semaptr
->sem_ctime
= time_second
;
491 if ((eval
= ipcperm(td
->td_proc
, &semaptr
->sem_perm
, IPC_R
)))
493 if ((eval
= copyin(arg
, &real_arg
, sizeof(real_arg
))) != 0)
495 eval
= copyout(semaptr
, real_arg
.buf
, sizeof(struct semid_ds
));
499 eval
= ipcperm(td
->td_proc
, &semaptr
->sem_perm
, IPC_R
);
502 if (semnum
< 0 || semnum
>= semaptr
->sem_nsems
) {
506 rval
= semaptr
->sem_base
[semnum
].semncnt
;
510 eval
= ipcperm(td
->td_proc
, &semaptr
->sem_perm
, IPC_R
);
513 if (semnum
< 0 || semnum
>= semaptr
->sem_nsems
) {
517 rval
= semaptr
->sem_base
[semnum
].sempid
;
521 eval
= ipcperm(td
->td_proc
, &semaptr
->sem_perm
, IPC_R
);
524 if (semnum
< 0 || semnum
>= semaptr
->sem_nsems
) {
528 rval
= semaptr
->sem_base
[semnum
].semval
;
532 eval
= ipcperm(td
->td_proc
, &semaptr
->sem_perm
, IPC_R
);
535 if ((eval
= copyin(arg
, &real_arg
, sizeof(real_arg
))) != 0)
537 for (i
= 0; i
< semaptr
->sem_nsems
; i
++) {
538 eval
= copyout(&semaptr
->sem_base
[i
].semval
,
540 sizeof(real_arg
.array
[0]));
547 eval
= ipcperm(td
->td_proc
, &semaptr
->sem_perm
, IPC_R
);
550 if (semnum
< 0 || semnum
>= semaptr
->sem_nsems
) {
554 rval
= semaptr
->sem_base
[semnum
].semzcnt
;
558 eval
= ipcperm(td
->td_proc
, &semaptr
->sem_perm
, IPC_W
);
561 if (semnum
< 0 || semnum
>= semaptr
->sem_nsems
) {
565 if ((eval
= copyin(arg
, &real_arg
, sizeof(real_arg
))) != 0)
567 semaptr
->sem_base
[semnum
].semval
= real_arg
.val
;
568 semundo_clear(semid
, semnum
);
569 wakeup((caddr_t
)semaptr
);
573 eval
= ipcperm(td
->td_proc
, &semaptr
->sem_perm
, IPC_W
);
576 if ((eval
= copyin(arg
, &real_arg
, sizeof(real_arg
))) != 0)
578 for (i
= 0; i
< semaptr
->sem_nsems
; i
++) {
579 eval
= copyin(&real_arg
.array
[i
],
580 (caddr_t
)&semaptr
->sem_base
[i
].semval
,
581 sizeof(real_arg
.array
[0]));
585 semundo_clear(semid
, -1);
586 wakeup((caddr_t
)semaptr
);
596 uap
->sysmsg_result
= rval
;
604 sys_semget(struct semget_args
*uap
)
606 struct thread
*td
= curthread
;
609 int nsems
= uap
->nsems
;
610 int semflg
= uap
->semflg
;
611 struct ucred
*cred
= td
->td_ucred
;
614 kprintf("semget(0x%x, %d, 0%o)\n", key
, nsems
, semflg
);
617 if (!jail_sysvipc_allowed
&& cred
->cr_prison
!= NULL
)
623 if (key
!= IPC_PRIVATE
) {
624 for (semid
= 0; semid
< seminfo
.semmni
; semid
++) {
625 if ((sema
[semid
].sem_perm
.mode
& SEM_ALLOC
) &&
626 sema
[semid
].sem_perm
.key
== key
)
629 if (semid
< seminfo
.semmni
) {
631 kprintf("found public key\n");
633 if ((eval
= ipcperm(td
->td_proc
,
634 &sema
[semid
].sem_perm
,
638 if (nsems
> 0 && sema
[semid
].sem_nsems
< nsems
) {
640 kprintf("too small\n");
645 if ((semflg
& IPC_CREAT
) && (semflg
& IPC_EXCL
)) {
647 kprintf("not exclusive\n");
657 kprintf("need to allocate the semid_ds\n");
659 if (key
== IPC_PRIVATE
|| (semflg
& IPC_CREAT
)) {
660 if (nsems
<= 0 || nsems
> seminfo
.semmsl
) {
662 kprintf("nsems out of range (0<%d<=%d)\n", nsems
,
668 if (nsems
> seminfo
.semmns
- semtot
) {
670 kprintf("not enough semaphores left (need %d, got %d)\n",
671 nsems
, seminfo
.semmns
- semtot
);
676 for (semid
= 0; semid
< seminfo
.semmni
; semid
++) {
677 if ((sema
[semid
].sem_perm
.mode
& SEM_ALLOC
) == 0)
680 if (semid
== seminfo
.semmni
) {
682 kprintf("no more semid_ds's available\n");
688 kprintf("semid %d is available\n", semid
);
690 sema
[semid
].sem_perm
.key
= key
;
691 sema
[semid
].sem_perm
.cuid
= cred
->cr_uid
;
692 sema
[semid
].sem_perm
.uid
= cred
->cr_uid
;
693 sema
[semid
].sem_perm
.cgid
= cred
->cr_gid
;
694 sema
[semid
].sem_perm
.gid
= cred
->cr_gid
;
695 sema
[semid
].sem_perm
.mode
= (semflg
& 0777) | SEM_ALLOC
;
696 sema
[semid
].sem_perm
.seq
=
697 (sema
[semid
].sem_perm
.seq
+ 1) & 0x7fff;
698 sema
[semid
].sem_nsems
= nsems
;
699 sema
[semid
].sem_otime
= 0;
700 sema
[semid
].sem_ctime
= time_second
;
701 sema
[semid
].sem_base
= &sem
[semtot
];
703 bzero(sema
[semid
].sem_base
,
704 sizeof(sema
[semid
].sem_base
[0])*nsems
);
706 kprintf("sembase = 0x%x, next = 0x%x\n", sema
[semid
].sem_base
,
711 kprintf("didn't find it and wasn't asked to create it\n");
718 uap
->sysmsg_result
= IXSEQ_TO_IPCID(semid
,
719 sema
[semid
].sem_perm
);
729 sys_semop(struct semop_args
*uap
)
731 struct thread
*td
= curthread
;
732 int semid
= uap
->semid
;
733 u_int nsops
= uap
->nsops
;
734 struct sembuf sops
[MAX_SOPS
];
735 struct semid_ds
*semaptr
;
736 struct sembuf
*sopptr
;
738 struct sem_undo
*suptr
= NULL
;
740 int do_wakeup
, do_undos
;
743 kprintf("call to semop(%d, 0x%x, %u)\n", semid
, sops
, nsops
);
746 if (!jail_sysvipc_allowed
&& td
->td_ucred
->cr_prison
!= NULL
)
750 semid
= IPCID_TO_IX(semid
); /* Convert back to zero origin */
752 if (semid
< 0 || semid
>= seminfo
.semmni
) {
757 semaptr
= &sema
[semid
];
758 if ((semaptr
->sem_perm
.mode
& SEM_ALLOC
) == 0) {
762 if (semaptr
->sem_perm
.seq
!= IPCID_TO_SEQ(uap
->semid
)) {
767 if ((eval
= ipcperm(td
->td_proc
, &semaptr
->sem_perm
, IPC_W
))) {
769 kprintf("eval = %d from ipaccess\n", eval
);
774 if (nsops
> MAX_SOPS
) {
776 kprintf("too many sops (max=%d, nsops=%u)\n", MAX_SOPS
, nsops
);
782 if ((eval
= copyin(uap
->sops
, &sops
, nsops
* sizeof(sops
[0]))) != 0) {
784 kprintf("eval = %d from copyin(%08x, %08x, %u)\n", eval
,
785 uap
->sops
, &sops
, nsops
* sizeof(sops
[0]));
791 * Loop trying to satisfy the vector of requests.
792 * If we reach a point where we must wait, any requests already
793 * performed are rolled back and we go to sleep until some other
794 * process wakes us up. At this point, we start all over again.
796 * This ensures that from the perspective of other tasks, a set
797 * of requests is atomic (never partially satisfied).
804 for (i
= 0; i
< nsops
; i
++) {
807 if (sopptr
->sem_num
>= semaptr
->sem_nsems
) {
812 semptr
= &semaptr
->sem_base
[sopptr
->sem_num
];
815 kprintf("semop: semaptr=%x, sem_base=%x, semptr=%x, sem[%d]=%d : op=%d, flag=%s\n",
816 semaptr
, semaptr
->sem_base
, semptr
,
817 sopptr
->sem_num
, semptr
->semval
, sopptr
->sem_op
,
818 (sopptr
->sem_flg
& IPC_NOWAIT
) ? "nowait" : "wait");
821 if (sopptr
->sem_op
< 0) {
822 if (semptr
->semval
+ sopptr
->sem_op
< 0) {
824 kprintf("semop: can't do it now\n");
828 semptr
->semval
+= sopptr
->sem_op
;
829 if (semptr
->semval
== 0 &&
833 if (sopptr
->sem_flg
& SEM_UNDO
)
835 } else if (sopptr
->sem_op
== 0) {
836 if (semptr
->semval
> 0) {
838 kprintf("semop: not zero now\n");
843 if (semptr
->semncnt
> 0)
845 semptr
->semval
+= sopptr
->sem_op
;
846 if (sopptr
->sem_flg
& SEM_UNDO
)
852 * Did we get through the entire vector?
858 * No ... rollback anything that we've already done
861 kprintf("semop: rollback 0 through %d\n", i
-1);
863 for (j
= 0; j
< i
; j
++)
864 semaptr
->sem_base
[sops
[j
].sem_num
].semval
-=
868 * If the request that we couldn't satisfy has the
869 * NOWAIT flag set then return with EAGAIN.
871 if (sopptr
->sem_flg
& IPC_NOWAIT
) {
876 if (sopptr
->sem_op
== 0)
882 kprintf("semop: good night!\n");
884 eval
= tsleep((caddr_t
)semaptr
, PCATCH
, "semwait", 0);
886 kprintf("semop: good morning (eval=%d)!\n", eval
);
889 suptr
= NULL
; /* sem_undo may have been reallocated */
891 /* return code is checked below, after sem[nz]cnt-- */
894 * Make sure that the semaphore still exists
896 if ((semaptr
->sem_perm
.mode
& SEM_ALLOC
) == 0 ||
897 semaptr
->sem_perm
.seq
!= IPCID_TO_SEQ(uap
->semid
)) {
903 * The semaphore is still alive. Readjust the count of
906 if (sopptr
->sem_op
== 0)
912 * Is it really morning, or was our sleep interrupted?
913 * (Delayed check of tsleep() return code because we
914 * need to decrement sem[nz]cnt either way.)
921 kprintf("semop: good morning!\n");
927 * Process any SEM_UNDO requests.
930 for (i
= 0; i
< nsops
; i
++) {
932 * We only need to deal with SEM_UNDO's for non-zero
937 if ((sops
[i
].sem_flg
& SEM_UNDO
) == 0)
939 adjval
= sops
[i
].sem_op
;
942 eval
= semundo_adjust(td
->td_proc
, &suptr
, semid
,
943 sops
[i
].sem_num
, -adjval
);
948 * Oh-Oh! We ran out of either sem_undo's or undo's.
949 * Rollback the adjustments to this point and then
950 * rollback the semaphore ups and down so we can return
951 * with an error with all structures restored. We
952 * rollback the undo's in the exact reverse order that
953 * we applied them. This guarantees that we won't run
954 * out of space as we roll things back out.
956 for (j
= i
- 1; j
>= 0; j
--) {
957 if ((sops
[j
].sem_flg
& SEM_UNDO
) == 0)
959 adjval
= sops
[j
].sem_op
;
962 if (semundo_adjust(td
->td_proc
, &suptr
, semid
,
963 sops
[j
].sem_num
, adjval
) != 0)
964 panic("semop - can't undo undos");
967 for (j
= 0; j
< nsops
; j
++)
968 semaptr
->sem_base
[sops
[j
].sem_num
].semval
-=
972 kprintf("eval = %d from semundo_adjust\n", eval
);
975 } /* loop through the sops */
976 } /* if (do_undos) */
978 /* We're definitely done - set the sempid's */
979 for (i
= 0; i
< nsops
; i
++) {
981 semptr
= &semaptr
->sem_base
[sopptr
->sem_num
];
982 semptr
->sempid
= td
->td_proc
->p_pid
;
985 /* Do a wakeup if any semaphore was up'd. */
988 kprintf("semop: doing wakeup\n");
990 wakeup((caddr_t
)semaptr
);
992 kprintf("semop: back from wakeup\n");
996 kprintf("semop: done\n");
998 uap
->sysmsg_result
= 0;
1006 * Go through the undo structures for this process and apply the adjustments to
1010 semexit(struct proc
*p
)
1012 struct sem_undo
*suptr
;
1013 struct sem_undo
**supptr
;
1019 * Go through the chain of undo vectors looking for one
1020 * associated with this process.
1023 for (supptr
= &semu_list
; (suptr
= *supptr
) != NULL
;
1024 supptr
= &suptr
->un_next
) {
1025 if (suptr
->un_proc
== p
)
1033 kprintf("proc @%08x has undo structure with %d entries\n", p
,
1038 * If there are any active undo elements then process them.
1040 if (suptr
->un_cnt
> 0) {
1043 for (ix
= 0; ix
< suptr
->un_cnt
; ix
++) {
1044 int semid
= suptr
->un_ent
[ix
].un_id
;
1045 int semnum
= suptr
->un_ent
[ix
].un_num
;
1046 int adjval
= suptr
->un_ent
[ix
].un_adjval
;
1047 struct semid_ds
*semaptr
;
1049 semaptr
= &sema
[semid
];
1050 if ((semaptr
->sem_perm
.mode
& SEM_ALLOC
) == 0)
1051 panic("semexit - semid not allocated");
1052 if (semnum
>= semaptr
->sem_nsems
)
1053 panic("semexit - semnum out of range");
1056 kprintf("semexit: %08x id=%d num=%d(adj=%d) ; sem=%d\n",
1057 suptr
->un_proc
, suptr
->un_ent
[ix
].un_id
,
1058 suptr
->un_ent
[ix
].un_num
,
1059 suptr
->un_ent
[ix
].un_adjval
,
1060 semaptr
->sem_base
[semnum
].semval
);
1064 if (semaptr
->sem_base
[semnum
].semval
< -adjval
)
1065 semaptr
->sem_base
[semnum
].semval
= 0;
1067 semaptr
->sem_base
[semnum
].semval
+=
1070 semaptr
->sem_base
[semnum
].semval
+= adjval
;
1072 wakeup((caddr_t
)semaptr
);
1074 kprintf("semexit: back from wakeup\n");
1080 * Deallocate the undo vector.
1083 kprintf("removing vector\n");
1085 suptr
->un_proc
= NULL
;
1086 *supptr
= suptr
->un_next
;