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.14 2004/05/26 14:12:34 hmp 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 #ifndef _SYS_SYSPROTO_H_
31 int __semctl (struct proc
*p
, struct __semctl_args
*uap
);
33 int semget (struct proc
*p
, struct semget_args
*uap
);
35 int semop (struct proc
*p
, struct semop_args
*uap
);
38 static struct sem_undo
*semu_alloc (struct proc
*p
);
39 static int semundo_adjust (struct proc
*p
, struct sem_undo
**supptr
,
40 int semid
, int semnum
, int adjval
);
41 static void semundo_clear (int semid
, int semnum
);
43 /* XXX casting to (sy_call_t *) is bogus, as usual. */
44 static sy_call_t
*semcalls
[] = {
45 (sy_call_t
*)__semctl
, (sy_call_t
*)semget
,
49 static int semtot
= 0;
50 static struct semid_ds
*sema
; /* semaphore id pool */
51 static struct sem
*sem
; /* semaphore pool */
52 static struct sem_undo
*semu_list
; /* list of active undo structures */
53 static int *semu
; /* undo structure pool */
56 u_short semval
; /* semaphore value */
57 pid_t sempid
; /* pid of last operation */
58 u_short semncnt
; /* # awaiting semval > cval */
59 u_short semzcnt
; /* # awaiting semval = 0 */
63 * Undo structure (one per process)
66 struct sem_undo
*un_next
; /* ptr to next active undo structure */
67 struct proc
*un_proc
; /* owner of this structure */
68 short un_cnt
; /* # of active entries */
70 short un_adjval
; /* adjust on exit values */
71 short un_num
; /* semaphore # */
72 int un_id
; /* semid */
73 } un_ent
[1]; /* undo entries */
77 * Configuration parameters
80 #define SEMMNI 10 /* # of semaphore identifiers */
83 #define SEMMNS 60 /* # of semaphores in system */
86 #define SEMUME 10 /* max # of undo entries per process */
89 #define SEMMNU 30 /* # of undo structures in system */
92 /* shouldn't need tuning */
94 #define SEMMAP 30 /* # of entries in semaphore map */
97 #define SEMMSL SEMMNS /* max # of semaphores per id */
100 #define SEMOPM 100 /* max # of operations per semop call */
103 #define SEMVMX 32767 /* semaphore maximum value */
104 #define SEMAEM 16384 /* adjust on exit max value */
107 * Due to the way semaphore memory is allocated, we have to ensure that
108 * SEMUSZ is properly aligned.
111 #define SEM_ALIGN(bytes) (((bytes) + (sizeof(long) - 1)) & ~(sizeof(long) - 1))
113 /* actual size of an undo structure */
114 #define SEMUSZ SEM_ALIGN(offsetof(struct sem_undo, un_ent[SEMUME]))
117 * Macro to find a particular sem_undo vector
119 #define SEMU(ix) ((struct sem_undo *)(((intptr_t)semu)+ix * seminfo.semusz))
122 * semaphore info struct
124 struct seminfo seminfo
= {
125 SEMMAP
, /* # of entries in semaphore map */
126 SEMMNI
, /* # of semaphore identifiers */
127 SEMMNS
, /* # of semaphores in system */
128 SEMMNU
, /* # of undo structures in system */
129 SEMMSL
, /* max # of semaphores per id */
130 SEMOPM
, /* max # of operations per semop call */
131 SEMUME
, /* max # of undo entries per process */
132 SEMUSZ
, /* size in bytes of undo structure */
133 SEMVMX
, /* semaphore maximum value */
134 SEMAEM
/* adjust on exit max value */
137 TUNABLE_INT("kern.ipc.semmap", &seminfo
.semmap
);
138 TUNABLE_INT("kern.ipc.semmni", &seminfo
.semmni
);
139 TUNABLE_INT("kern.ipc.semmns", &seminfo
.semmns
);
140 TUNABLE_INT("kern.ipc.semmnu", &seminfo
.semmnu
);
141 TUNABLE_INT("kern.ipc.semmsl", &seminfo
.semmsl
);
142 TUNABLE_INT("kern.ipc.semopm", &seminfo
.semopm
);
143 TUNABLE_INT("kern.ipc.semume", &seminfo
.semume
);
144 TUNABLE_INT("kern.ipc.semusz", &seminfo
.semusz
);
145 TUNABLE_INT("kern.ipc.semvmx", &seminfo
.semvmx
);
146 TUNABLE_INT("kern.ipc.semaem", &seminfo
.semaem
);
148 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semmap
, CTLFLAG_RW
, &seminfo
.semmap
, 0, "");
149 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semmni
, CTLFLAG_RD
, &seminfo
.semmni
, 0, "");
150 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semmns
, CTLFLAG_RD
, &seminfo
.semmns
, 0, "");
151 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semmnu
, CTLFLAG_RD
, &seminfo
.semmnu
, 0, "");
152 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semmsl
, CTLFLAG_RW
, &seminfo
.semmsl
, 0, "");
153 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semopm
, CTLFLAG_RD
, &seminfo
.semopm
, 0, "");
154 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semume
, CTLFLAG_RD
, &seminfo
.semume
, 0, "");
155 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semusz
, CTLFLAG_RD
, &seminfo
.semusz
, 0, "");
156 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semvmx
, CTLFLAG_RW
, &seminfo
.semvmx
, 0, "");
157 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semaem
, CTLFLAG_RW
, &seminfo
.semaem
, 0, "");
160 RO seminfo
.semmap
/* SEMMAP unused */
163 RO seminfo
.semmnu
/* undo entries per system */
165 RO seminfo
.semopm
/* SEMOPM unused */
167 RO seminfo
.semusz
/* param - derived from SEMUME for per-proc sizeof */
168 RO seminfo
.semvmx
/* SEMVMX unused - user param */
169 RO seminfo
.semaem
/* SEMAEM unused - user param */
178 sem
= malloc(sizeof(struct sem
) * seminfo
.semmns
, M_SEM
, M_WAITOK
);
180 panic("sem is NULL");
181 sema
= malloc(sizeof(struct semid_ds
) * seminfo
.semmni
, M_SEM
, M_WAITOK
);
183 panic("sema is NULL");
184 semu
= malloc(seminfo
.semmnu
* seminfo
.semusz
, M_SEM
, M_WAITOK
);
186 panic("semu is NULL");
188 for (i
= 0; i
< seminfo
.semmni
; i
++) {
189 sema
[i
].sem_base
= 0;
190 sema
[i
].sem_perm
.mode
= 0;
192 for (i
= 0; i
< seminfo
.semmnu
; i
++) {
193 struct sem_undo
*suptr
= SEMU(i
);
194 suptr
->un_proc
= NULL
;
198 SYSINIT(sysv_sem
, SI_SUB_SYSV_SEM
, SI_ORDER_FIRST
, seminit
, NULL
)
201 * Entry point for all SEM calls
203 * semsys_args(int which, a2, a3, ...) (VARARGS)
206 semsys(struct semsys_args
*uap
)
208 struct proc
*p
= curproc
;
209 unsigned int which
= (unsigned int)uap
->which
;
211 if (!jail_sysvipc_allowed
&& p
->p_ucred
->cr_prison
!= NULL
)
214 if (which
>= sizeof(semcalls
)/sizeof(semcalls
[0]))
216 bcopy(&uap
->a2
, &uap
->which
,
217 sizeof(struct semsys_args
) - offsetof(struct semsys_args
, a2
));
218 return ((*semcalls
[which
])(uap
));
222 * Allocate a new sem_undo structure for a process
223 * (returns ptr to structure or NULL if no more room)
226 static struct sem_undo
*
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(p
, supptr
, semid
, semnum
, adjval
)
299 struct sem_undo
**supptr
;
303 struct sem_undo
*suptr
;
307 /* Look for and remember the sem_undo if the caller doesn't provide
312 for (suptr
= semu_list
; suptr
!= NULL
;
313 suptr
= suptr
->un_next
) {
314 if (suptr
->un_proc
== p
) {
322 suptr
= semu_alloc(p
);
330 * Look for the requested entry and adjust it (delete if adjval becomes
333 sunptr
= &suptr
->un_ent
[0];
334 for (i
= 0; i
< suptr
->un_cnt
; i
++, sunptr
++) {
335 if (sunptr
->un_id
!= semid
|| sunptr
->un_num
!= semnum
)
338 sunptr
->un_adjval
= 0;
340 sunptr
->un_adjval
+= adjval
;
341 if (sunptr
->un_adjval
== 0) {
343 if (i
< suptr
->un_cnt
)
345 suptr
->un_ent
[suptr
->un_cnt
];
350 /* Didn't find the right entry - create it */
353 if (suptr
->un_cnt
!= seminfo
.semume
) {
354 sunptr
= &suptr
->un_ent
[suptr
->un_cnt
];
356 sunptr
->un_adjval
= adjval
;
357 sunptr
->un_id
= semid
; sunptr
->un_num
= semnum
;
364 semundo_clear(semid
, semnum
)
367 struct sem_undo
*suptr
;
369 for (suptr
= semu_list
; suptr
!= NULL
; suptr
= suptr
->un_next
) {
370 struct undo
*sunptr
= &suptr
->un_ent
[0];
373 while (i
< suptr
->un_cnt
) {
374 if (sunptr
->un_id
== semid
) {
375 if (semnum
== -1 || sunptr
->un_num
== semnum
) {
377 if (i
< suptr
->un_cnt
) {
379 suptr
->un_ent
[suptr
->un_cnt
];
392 * Note that the user-mode half of this passes a union, not a pointer
396 __semctl(struct __semctl_args
*uap
)
398 struct proc
*p
= curproc
;
399 int semid
= uap
->semid
;
400 int semnum
= uap
->semnum
;
402 union semun
*arg
= uap
->arg
;
403 union semun real_arg
;
404 struct ucred
*cred
= p
->p_ucred
;
406 struct semid_ds sbuf
;
407 struct semid_ds
*semaptr
;
410 printf("call to semctl(%d, %d, %d, 0x%x)\n", semid
, semnum
, cmd
, arg
);
413 if (!jail_sysvipc_allowed
&& p
->p_ucred
->cr_prison
!= NULL
)
416 semid
= IPCID_TO_IX(semid
);
417 if (semid
< 0 || semid
>= seminfo
.semmni
)
420 semaptr
= &sema
[semid
];
421 if ((semaptr
->sem_perm
.mode
& SEM_ALLOC
) == 0 ||
422 semaptr
->sem_perm
.seq
!= IPCID_TO_SEQ(uap
->semid
))
430 if ((eval
= ipcperm(p
, &semaptr
->sem_perm
, IPC_M
)))
432 semaptr
->sem_perm
.cuid
= cred
->cr_uid
;
433 semaptr
->sem_perm
.uid
= cred
->cr_uid
;
434 semtot
-= semaptr
->sem_nsems
;
435 for (i
= semaptr
->sem_base
- sem
; i
< semtot
; i
++)
436 sem
[i
] = sem
[i
+ semaptr
->sem_nsems
];
437 for (i
= 0; i
< seminfo
.semmni
; i
++) {
438 if ((sema
[i
].sem_perm
.mode
& SEM_ALLOC
) &&
439 sema
[i
].sem_base
> semaptr
->sem_base
)
440 sema
[i
].sem_base
-= semaptr
->sem_nsems
;
442 semaptr
->sem_perm
.mode
= 0;
443 semundo_clear(semid
, -1);
444 wakeup((caddr_t
)semaptr
);
448 if ((eval
= ipcperm(p
, &semaptr
->sem_perm
, IPC_M
)))
450 if ((eval
= copyin(arg
, &real_arg
, sizeof(real_arg
))) != 0)
452 if ((eval
= copyin(real_arg
.buf
, (caddr_t
)&sbuf
,
455 semaptr
->sem_perm
.uid
= sbuf
.sem_perm
.uid
;
456 semaptr
->sem_perm
.gid
= sbuf
.sem_perm
.gid
;
457 semaptr
->sem_perm
.mode
= (semaptr
->sem_perm
.mode
& ~0777) |
458 (sbuf
.sem_perm
.mode
& 0777);
459 semaptr
->sem_ctime
= time_second
;
463 if ((eval
= ipcperm(p
, &semaptr
->sem_perm
, IPC_R
)))
465 if ((eval
= copyin(arg
, &real_arg
, sizeof(real_arg
))) != 0)
467 eval
= copyout((caddr_t
)semaptr
, real_arg
.buf
,
468 sizeof(struct semid_ds
));
472 if ((eval
= ipcperm(p
, &semaptr
->sem_perm
, IPC_R
)))
474 if (semnum
< 0 || semnum
>= semaptr
->sem_nsems
)
476 rval
= semaptr
->sem_base
[semnum
].semncnt
;
480 if ((eval
= ipcperm(p
, &semaptr
->sem_perm
, IPC_R
)))
482 if (semnum
< 0 || semnum
>= semaptr
->sem_nsems
)
484 rval
= semaptr
->sem_base
[semnum
].sempid
;
488 if ((eval
= ipcperm(p
, &semaptr
->sem_perm
, IPC_R
)))
490 if (semnum
< 0 || semnum
>= semaptr
->sem_nsems
)
492 rval
= semaptr
->sem_base
[semnum
].semval
;
496 if ((eval
= ipcperm(p
, &semaptr
->sem_perm
, IPC_R
)))
498 if ((eval
= copyin(arg
, &real_arg
, sizeof(real_arg
))) != 0)
500 for (i
= 0; i
< semaptr
->sem_nsems
; i
++) {
501 eval
= copyout((caddr_t
)&semaptr
->sem_base
[i
].semval
,
502 &real_arg
.array
[i
], sizeof(real_arg
.array
[0]));
509 if ((eval
= ipcperm(p
, &semaptr
->sem_perm
, IPC_R
)))
511 if (semnum
< 0 || semnum
>= semaptr
->sem_nsems
)
513 rval
= semaptr
->sem_base
[semnum
].semzcnt
;
517 if ((eval
= ipcperm(p
, &semaptr
->sem_perm
, IPC_W
)))
519 if (semnum
< 0 || semnum
>= semaptr
->sem_nsems
)
521 if ((eval
= copyin(arg
, &real_arg
, sizeof(real_arg
))) != 0)
523 semaptr
->sem_base
[semnum
].semval
= real_arg
.val
;
524 semundo_clear(semid
, semnum
);
525 wakeup((caddr_t
)semaptr
);
529 if ((eval
= ipcperm(p
, &semaptr
->sem_perm
, IPC_W
)))
531 if ((eval
= copyin(arg
, &real_arg
, sizeof(real_arg
))) != 0)
533 for (i
= 0; i
< semaptr
->sem_nsems
; i
++) {
534 eval
= copyin(&real_arg
.array
[i
],
535 (caddr_t
)&semaptr
->sem_base
[i
].semval
,
536 sizeof(real_arg
.array
[0]));
540 semundo_clear(semid
, -1);
541 wakeup((caddr_t
)semaptr
);
549 uap
->sysmsg_result
= rval
;
554 semget(struct semget_args
*uap
)
556 struct proc
*p
= curproc
;
559 int nsems
= uap
->nsems
;
560 int semflg
= uap
->semflg
;
561 struct ucred
*cred
= p
->p_ucred
;
564 printf("semget(0x%x, %d, 0%o)\n", key
, nsems
, semflg
);
567 if (!jail_sysvipc_allowed
&& p
->p_ucred
->cr_prison
!= NULL
)
570 if (key
!= IPC_PRIVATE
) {
571 for (semid
= 0; semid
< seminfo
.semmni
; semid
++) {
572 if ((sema
[semid
].sem_perm
.mode
& SEM_ALLOC
) &&
573 sema
[semid
].sem_perm
.key
== key
)
576 if (semid
< seminfo
.semmni
) {
578 printf("found public key\n");
580 if ((eval
= ipcperm(p
, &sema
[semid
].sem_perm
,
583 if (nsems
> 0 && sema
[semid
].sem_nsems
< nsems
) {
585 printf("too small\n");
589 if ((semflg
& IPC_CREAT
) && (semflg
& IPC_EXCL
)) {
591 printf("not exclusive\n");
600 printf("need to allocate the semid_ds\n");
602 if (key
== IPC_PRIVATE
|| (semflg
& IPC_CREAT
)) {
603 if (nsems
<= 0 || nsems
> seminfo
.semmsl
) {
605 printf("nsems out of range (0<%d<=%d)\n", nsems
,
610 if (nsems
> seminfo
.semmns
- semtot
) {
612 printf("not enough semaphores left (need %d, got %d)\n",
613 nsems
, seminfo
.semmns
- semtot
);
617 for (semid
= 0; semid
< seminfo
.semmni
; semid
++) {
618 if ((sema
[semid
].sem_perm
.mode
& SEM_ALLOC
) == 0)
621 if (semid
== seminfo
.semmni
) {
623 printf("no more semid_ds's available\n");
628 printf("semid %d is available\n", semid
);
630 sema
[semid
].sem_perm
.key
= key
;
631 sema
[semid
].sem_perm
.cuid
= cred
->cr_uid
;
632 sema
[semid
].sem_perm
.uid
= cred
->cr_uid
;
633 sema
[semid
].sem_perm
.cgid
= cred
->cr_gid
;
634 sema
[semid
].sem_perm
.gid
= cred
->cr_gid
;
635 sema
[semid
].sem_perm
.mode
= (semflg
& 0777) | SEM_ALLOC
;
636 sema
[semid
].sem_perm
.seq
=
637 (sema
[semid
].sem_perm
.seq
+ 1) & 0x7fff;
638 sema
[semid
].sem_nsems
= nsems
;
639 sema
[semid
].sem_otime
= 0;
640 sema
[semid
].sem_ctime
= time_second
;
641 sema
[semid
].sem_base
= &sem
[semtot
];
643 bzero(sema
[semid
].sem_base
,
644 sizeof(sema
[semid
].sem_base
[0])*nsems
);
646 printf("sembase = 0x%x, next = 0x%x\n", sema
[semid
].sem_base
,
651 printf("didn't find it and wasn't asked to create it\n");
657 uap
->sysmsg_result
= IXSEQ_TO_IPCID(semid
, sema
[semid
].sem_perm
);
662 semop(struct semop_args
*uap
)
664 struct proc
*p
= curproc
;
665 int semid
= uap
->semid
;
666 u_int nsops
= uap
->nsops
;
667 struct sembuf sops
[MAX_SOPS
];
668 struct semid_ds
*semaptr
;
669 struct sembuf
*sopptr
;
671 struct sem_undo
*suptr
= NULL
;
673 int do_wakeup
, do_undos
;
676 printf("call to semop(%d, 0x%x, %u)\n", semid
, sops
, nsops
);
679 if (!jail_sysvipc_allowed
&& p
->p_ucred
->cr_prison
!= NULL
)
682 semid
= IPCID_TO_IX(semid
); /* Convert back to zero origin */
684 if (semid
< 0 || semid
>= seminfo
.semmni
)
687 semaptr
= &sema
[semid
];
688 if ((semaptr
->sem_perm
.mode
& SEM_ALLOC
) == 0)
690 if (semaptr
->sem_perm
.seq
!= IPCID_TO_SEQ(uap
->semid
))
693 if ((eval
= ipcperm(p
, &semaptr
->sem_perm
, IPC_W
))) {
695 printf("eval = %d from ipaccess\n", eval
);
700 if (nsops
> MAX_SOPS
) {
702 printf("too many sops (max=%d, nsops=%u)\n", MAX_SOPS
, nsops
);
707 if ((eval
= copyin(uap
->sops
, &sops
, nsops
* sizeof(sops
[0]))) != 0) {
709 printf("eval = %d from copyin(%08x, %08x, %u)\n", eval
,
710 uap
->sops
, &sops
, nsops
* sizeof(sops
[0]));
716 * Loop trying to satisfy the vector of requests.
717 * If we reach a point where we must wait, any requests already
718 * performed are rolled back and we go to sleep until some other
719 * process wakes us up. At this point, we start all over again.
721 * This ensures that from the perspective of other tasks, a set
722 * of requests is atomic (never partially satisfied).
729 for (i
= 0; i
< nsops
; i
++) {
732 if (sopptr
->sem_num
>= semaptr
->sem_nsems
)
735 semptr
= &semaptr
->sem_base
[sopptr
->sem_num
];
738 printf("semop: semaptr=%x, sem_base=%x, semptr=%x, sem[%d]=%d : op=%d, flag=%s\n",
739 semaptr
, semaptr
->sem_base
, semptr
,
740 sopptr
->sem_num
, semptr
->semval
, sopptr
->sem_op
,
741 (sopptr
->sem_flg
& IPC_NOWAIT
) ? "nowait" : "wait");
744 if (sopptr
->sem_op
< 0) {
745 if (semptr
->semval
+ sopptr
->sem_op
< 0) {
747 printf("semop: can't do it now\n");
751 semptr
->semval
+= sopptr
->sem_op
;
752 if (semptr
->semval
== 0 &&
756 if (sopptr
->sem_flg
& SEM_UNDO
)
758 } else if (sopptr
->sem_op
== 0) {
759 if (semptr
->semval
> 0) {
761 printf("semop: not zero now\n");
766 if (semptr
->semncnt
> 0)
768 semptr
->semval
+= sopptr
->sem_op
;
769 if (sopptr
->sem_flg
& SEM_UNDO
)
775 * Did we get through the entire vector?
781 * No ... rollback anything that we've already done
784 printf("semop: rollback 0 through %d\n", i
-1);
786 for (j
= 0; j
< i
; j
++)
787 semaptr
->sem_base
[sops
[j
].sem_num
].semval
-=
791 * If the request that we couldn't satisfy has the
792 * NOWAIT flag set then return with EAGAIN.
794 if (sopptr
->sem_flg
& IPC_NOWAIT
)
797 if (sopptr
->sem_op
== 0)
803 printf("semop: good night!\n");
805 eval
= tsleep((caddr_t
)semaptr
, PCATCH
, "semwait", 0);
807 printf("semop: good morning (eval=%d)!\n", eval
);
810 suptr
= NULL
; /* sem_undo may have been reallocated */
812 /* return code is checked below, after sem[nz]cnt-- */
815 * Make sure that the semaphore still exists
817 if ((semaptr
->sem_perm
.mode
& SEM_ALLOC
) == 0 ||
818 semaptr
->sem_perm
.seq
!= IPCID_TO_SEQ(uap
->semid
))
822 * The semaphore is still alive. Readjust the count of
825 if (sopptr
->sem_op
== 0)
831 * Is it really morning, or was our sleep interrupted?
832 * (Delayed check of msleep() return code because we
833 * need to decrement sem[nz]cnt either way.)
838 printf("semop: good morning!\n");
844 * Process any SEM_UNDO requests.
847 for (i
= 0; i
< nsops
; i
++) {
849 * We only need to deal with SEM_UNDO's for non-zero
854 if ((sops
[i
].sem_flg
& SEM_UNDO
) == 0)
856 adjval
= sops
[i
].sem_op
;
859 eval
= semundo_adjust(p
, &suptr
, semid
,
860 sops
[i
].sem_num
, -adjval
);
865 * Oh-Oh! We ran out of either sem_undo's or undo's.
866 * Rollback the adjustments to this point and then
867 * rollback the semaphore ups and down so we can return
868 * with an error with all structures restored. We
869 * rollback the undo's in the exact reverse order that
870 * we applied them. This guarantees that we won't run
871 * out of space as we roll things back out.
873 for (j
= i
- 1; j
>= 0; j
--) {
874 if ((sops
[j
].sem_flg
& SEM_UNDO
) == 0)
876 adjval
= sops
[j
].sem_op
;
879 if (semundo_adjust(p
, &suptr
, semid
,
880 sops
[j
].sem_num
, adjval
) != 0)
881 panic("semop - can't undo undos");
884 for (j
= 0; j
< nsops
; j
++)
885 semaptr
->sem_base
[sops
[j
].sem_num
].semval
-=
889 printf("eval = %d from semundo_adjust\n", eval
);
892 } /* loop through the sops */
893 } /* if (do_undos) */
895 /* We're definitely done - set the sempid's */
896 for (i
= 0; i
< nsops
; i
++) {
898 semptr
= &semaptr
->sem_base
[sopptr
->sem_num
];
899 semptr
->sempid
= p
->p_pid
;
902 /* Do a wakeup if any semaphore was up'd. */
905 printf("semop: doing wakeup\n");
907 wakeup((caddr_t
)semaptr
);
909 printf("semop: back from wakeup\n");
913 printf("semop: done\n");
915 uap
->sysmsg_result
= 0;
920 * Go through the undo structures for this process and apply the adjustments to
927 struct sem_undo
*suptr
;
928 struct sem_undo
**supptr
;
934 * Go through the chain of undo vectors looking for one
935 * associated with this process.
938 for (supptr
= &semu_list
; (suptr
= *supptr
) != NULL
;
939 supptr
= &suptr
->un_next
) {
940 if (suptr
->un_proc
== p
)
948 printf("proc @%08x has undo structure with %d entries\n", p
,
953 * If there are any active undo elements then process them.
955 if (suptr
->un_cnt
> 0) {
958 for (ix
= 0; ix
< suptr
->un_cnt
; ix
++) {
959 int semid
= suptr
->un_ent
[ix
].un_id
;
960 int semnum
= suptr
->un_ent
[ix
].un_num
;
961 int adjval
= suptr
->un_ent
[ix
].un_adjval
;
962 struct semid_ds
*semaptr
;
964 semaptr
= &sema
[semid
];
965 if ((semaptr
->sem_perm
.mode
& SEM_ALLOC
) == 0)
966 panic("semexit - semid not allocated");
967 if (semnum
>= semaptr
->sem_nsems
)
968 panic("semexit - semnum out of range");
971 printf("semexit: %08x id=%d num=%d(adj=%d) ; sem=%d\n",
972 suptr
->un_proc
, suptr
->un_ent
[ix
].un_id
,
973 suptr
->un_ent
[ix
].un_num
,
974 suptr
->un_ent
[ix
].un_adjval
,
975 semaptr
->sem_base
[semnum
].semval
);
979 if (semaptr
->sem_base
[semnum
].semval
< -adjval
)
980 semaptr
->sem_base
[semnum
].semval
= 0;
982 semaptr
->sem_base
[semnum
].semval
+=
985 semaptr
->sem_base
[semnum
].semval
+= adjval
;
987 wakeup((caddr_t
)semaptr
);
989 printf("semexit: back from wakeup\n");
995 * Deallocate the undo vector.
998 printf("removing vector\n");
1000 suptr
->un_proc
= NULL
;
1001 *supptr
= suptr
->un_next
;