1 /* $NetBSD: sysv_sem.c,v 1.85 2009/01/11 02:45:53 christos Exp $ */
4 * Copyright (c) 1999, 2007 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9 * NASA Ames Research Center, and by Andrew Doran.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
34 * Implementation of SVID semaphores
36 * Author: Daniel Boulet
38 * This software is provided ``AS IS'' without any warranties of any kind.
41 #include <sys/cdefs.h>
42 __KERNEL_RCSID(0, "$NetBSD: sysv_sem.c,v 1.85 2009/01/11 02:45:53 christos Exp $");
46 #include <sys/param.h>
47 #include <sys/kernel.h>
49 #include <sys/sysctl.h>
51 #include <sys/mount.h> /* XXX for <sys/syscallargs.h> */
52 #include <sys/syscallargs.h>
53 #include <sys/kauth.h>
57 * 1st: Pool of semaphore identifiers
59 * 3rd: Conditional variables
60 * 4th: Undo structures
62 struct semid_ds
*sema
;
63 static struct __sem
*sem
;
64 static kcondvar_t
*semcv
;
67 static kmutex_t semlock
;
68 static struct sem_undo
*semu_list
; /* list of active undo structures */
69 static u_int semtot
= 0; /* total number of semaphores */
71 static u_int sem_waiters
= 0; /* total number of semop waiters */
72 static bool sem_realloc_state
;
73 static kcondvar_t sem_realloc_cv
;
75 /* Macro to find a particular sem_undo vector */
76 #define SEMU(s, ix) ((struct sem_undo *)(((long)s) + ix * seminfo.semusz))
79 #define SEM_PRINTF(a) printf a
84 struct sem_undo
*semu_alloc(struct proc
*);
85 int semundo_adjust(struct proc
*, struct sem_undo
**, int, int, int);
86 void semundo_clear(int, int);
94 mutex_init(&semlock
, MUTEX_DEFAULT
, IPL_NONE
);
95 cv_init(&sem_realloc_cv
, "semrealc");
96 sem_realloc_state
= false;
98 /* Allocate the wired memory for our structures */
99 sz
= ALIGN(seminfo
.semmni
* sizeof(struct semid_ds
)) +
100 ALIGN(seminfo
.semmns
* sizeof(struct __sem
)) +
101 ALIGN(seminfo
.semmni
* sizeof(kcondvar_t
)) +
102 ALIGN(seminfo
.semmnu
* seminfo
.semusz
);
103 v
= uvm_km_alloc(kernel_map
, round_page(sz
), 0,
104 UVM_KMF_WIRED
|UVM_KMF_ZERO
);
106 panic("sysv_sem: cannot allocate memory");
108 sem
= (void *)((uintptr_t)sema
+
109 ALIGN(seminfo
.semmni
* sizeof(struct semid_ds
)));
110 semcv
= (void *)((uintptr_t)sem
+
111 ALIGN(seminfo
.semmns
* sizeof(struct __sem
)));
112 semu
= (void *)((uintptr_t)semcv
+
113 ALIGN(seminfo
.semmni
* sizeof(kcondvar_t
)));
115 for (i
= 0; i
< seminfo
.semmni
; i
++) {
116 sema
[i
]._sem_base
= 0;
117 sema
[i
].sem_perm
.mode
= 0;
118 cv_init(&semcv
[i
], "semwait");
120 for (i
= 0; i
< seminfo
.semmnu
; i
++) {
121 struct sem_undo
*suptr
= SEMU(semu
, i
);
122 suptr
->un_proc
= NULL
;
125 exithook_establish(semexit
, NULL
);
129 semrealloc(int newsemmni
, int newsemmns
, int newsemmnu
)
131 struct semid_ds
*new_sema
, *old_sema
;
132 struct __sem
*new_sem
;
133 struct sem_undo
*new_semu_list
, *suptr
, *nsuptr
;
135 kcondvar_t
*new_semcv
;
137 int i
, j
, lsemid
, nmnus
, sz
;
139 if (newsemmni
< 1 || newsemmns
< 1 || newsemmnu
< 1)
142 /* Allocate the wired memory for our structures */
143 sz
= ALIGN(newsemmni
* sizeof(struct semid_ds
)) +
144 ALIGN(newsemmns
* sizeof(struct __sem
)) +
145 ALIGN(newsemmni
* sizeof(kcondvar_t
)) +
146 ALIGN(newsemmnu
* seminfo
.semusz
);
147 v
= uvm_km_alloc(kernel_map
, round_page(sz
), 0,
148 UVM_KMF_WIRED
|UVM_KMF_ZERO
);
152 mutex_enter(&semlock
);
153 if (sem_realloc_state
) {
154 mutex_exit(&semlock
);
155 uvm_km_free(kernel_map
, v
, sz
, UVM_KMF_WIRED
);
158 sem_realloc_state
= true;
161 * Mark reallocation state, wake-up all waiters,
162 * and wait while they will all exit.
164 for (i
= 0; i
< seminfo
.semmni
; i
++)
165 cv_broadcast(&semcv
[i
]);
167 cv_wait(&sem_realloc_cv
, &semlock
);
171 /* Get the number of last slot */
173 for (i
= 0; i
< seminfo
.semmni
; i
++)
174 if (sema
[i
].sem_perm
.mode
& SEM_ALLOC
)
177 /* Get the number of currently used undo structures */
179 for (i
= 0; i
< seminfo
.semmnu
; i
++) {
180 suptr
= SEMU(semu
, i
);
181 if (suptr
->un_proc
== NULL
)
186 /* We cannot reallocate less memory than we use */
187 if (lsemid
>= newsemmni
|| semtot
> newsemmns
|| nmnus
> newsemmnu
) {
188 mutex_exit(&semlock
);
189 uvm_km_free(kernel_map
, v
, sz
, UVM_KMF_WIRED
);
193 new_sema
= (void *)v
;
194 new_sem
= (void *)((uintptr_t)new_sema
+
195 ALIGN(newsemmni
* sizeof(struct semid_ds
)));
196 new_semcv
= (void *)((uintptr_t)new_sem
+
197 ALIGN(newsemmns
* sizeof(struct __sem
)));
198 new_semu
= (void *)((uintptr_t)new_semcv
+
199 ALIGN(newsemmni
* sizeof(kcondvar_t
)));
201 /* Initialize all semaphore identifiers and condvars */
202 for (i
= 0; i
< newsemmni
; i
++) {
203 new_sema
[i
]._sem_base
= 0;
204 new_sema
[i
].sem_perm
.mode
= 0;
205 cv_init(&new_semcv
[i
], "semwait");
207 for (i
= 0; i
< newsemmnu
; i
++) {
208 nsuptr
= SEMU(new_semu
, i
);
209 nsuptr
->un_proc
= NULL
;
213 * Copy all identifiers, semaphores and list of the
214 * undo structures to the new memory allocation.
217 for (i
= 0; i
<= lsemid
; i
++) {
218 if ((sema
[i
].sem_perm
.mode
& SEM_ALLOC
) == 0)
220 memcpy(&new_sema
[i
], &sema
[i
], sizeof(struct semid_ds
));
221 new_sema
[i
]._sem_base
= &new_sem
[j
];
222 memcpy(new_sema
[i
]._sem_base
, sema
[i
]._sem_base
,
223 (sizeof(struct __sem
) * sema
[i
].sem_nsems
));
224 j
+= sema
[i
].sem_nsems
;
226 KASSERT(j
== semtot
);
229 new_semu_list
= NULL
;
230 for (suptr
= semu_list
; suptr
!= NULL
; suptr
= suptr
->un_next
) {
231 KASSERT(j
< newsemmnu
);
232 nsuptr
= SEMU(new_semu
, j
);
233 memcpy(nsuptr
, suptr
, SEMUSZ
);
234 nsuptr
->un_next
= new_semu_list
;
235 new_semu_list
= nsuptr
;
239 for (i
= 0; i
< seminfo
.semmni
; i
++) {
240 KASSERT(cv_has_waiters(&semcv
[i
]) == false);
241 cv_destroy(&semcv
[i
]);
244 sz
= ALIGN(seminfo
.semmni
* sizeof(struct semid_ds
)) +
245 ALIGN(seminfo
.semmns
* sizeof(struct __sem
)) +
246 ALIGN(seminfo
.semmni
* sizeof(kcondvar_t
)) +
247 ALIGN(seminfo
.semmnu
* seminfo
.semusz
);
249 /* Set the pointers and update the new values */
254 semu_list
= new_semu_list
;
256 seminfo
.semmni
= newsemmni
;
257 seminfo
.semmns
= newsemmns
;
258 seminfo
.semmnu
= newsemmnu
;
260 /* Reallocation completed - notify all waiters, if any */
261 sem_realloc_state
= false;
262 cv_broadcast(&sem_realloc_cv
);
263 mutex_exit(&semlock
);
265 uvm_km_free(kernel_map
, (vaddr_t
)old_sema
, sz
, UVM_KMF_WIRED
);
274 sys_semconfig(struct lwp
*l
, const struct sys_semconfig_args
*uap
, register_t
*retval
)
282 * Allocate a new sem_undo structure for a process.
283 * => Returns NULL on failure.
286 semu_alloc(struct proc
*p
)
288 struct sem_undo
*suptr
, **supptr
;
289 bool attempted
= false;
292 KASSERT(mutex_owned(&semlock
));
294 /* Look for a free structure. */
295 for (i
= 0; i
< seminfo
.semmnu
; i
++) {
296 suptr
= SEMU(semu
, i
);
297 if (suptr
->un_proc
== NULL
) {
298 /* Found. Fill it in and return. */
299 suptr
->un_next
= semu_list
;
307 /* Not found. Attempt to free some structures. */
313 while ((suptr
= *supptr
) != NULL
) {
314 if (suptr
->un_cnt
== 0) {
315 suptr
->un_proc
= NULL
;
316 *supptr
= suptr
->un_next
;
319 supptr
= &suptr
->un_next
;
330 * Adjust a particular entry for a particular proc
334 semundo_adjust(struct proc
*p
, struct sem_undo
**supptr
, int semid
, int semnum
,
337 struct sem_undo
*suptr
;
341 KASSERT(mutex_owned(&semlock
));
344 * Look for and remember the sem_undo if the caller doesn't
350 for (suptr
= semu_list
; suptr
!= NULL
; suptr
= suptr
->un_next
)
351 if (suptr
->un_proc
== p
)
355 suptr
= semu_alloc(p
);
363 * Look for the requested entry and adjust it (delete if
366 sunptr
= &suptr
->un_ent
[0];
367 for (i
= 0; i
< suptr
->un_cnt
; i
++, sunptr
++) {
368 if (sunptr
->un_id
!= semid
|| sunptr
->un_num
!= semnum
)
370 sunptr
->un_adjval
+= adjval
;
371 if (sunptr
->un_adjval
== 0) {
373 if (i
< suptr
->un_cnt
)
375 suptr
->un_ent
[suptr
->un_cnt
];
380 /* Didn't find the right entry - create it */
381 if (suptr
->un_cnt
== SEMUME
)
384 sunptr
= &suptr
->un_ent
[suptr
->un_cnt
];
386 sunptr
->un_adjval
= adjval
;
387 sunptr
->un_id
= semid
;
388 sunptr
->un_num
= semnum
;
393 semundo_clear(int semid
, int semnum
)
395 struct sem_undo
*suptr
;
396 struct undo
*sunptr
, *sunend
;
398 KASSERT(mutex_owned(&semlock
));
400 for (suptr
= semu_list
; suptr
!= NULL
; suptr
= suptr
->un_next
)
401 for (sunptr
= &suptr
->un_ent
[0],
402 sunend
= sunptr
+ suptr
->un_cnt
; sunptr
< sunend
;) {
403 if (sunptr
->un_id
== semid
) {
404 if (semnum
== -1 || sunptr
->un_num
== semnum
) {
407 if (sunptr
!= sunend
)
420 sys_____semctl50(struct lwp
*l
, const struct sys_____semctl50_args
*uap
,
424 syscallarg(int) semid;
425 syscallarg(int) semnum;
427 syscallarg(union __semun *) arg;
429 struct semid_ds sembuf
;
434 cmd
= SCARG(uap
, cmd
);
436 pass_arg
= get_semctl_arg(cmd
, &sembuf
, &karg
);
439 error
= copyin(SCARG(uap
, arg
), &karg
, sizeof(karg
));
442 if (cmd
== IPC_SET
) {
443 error
= copyin(karg
.buf
, &sembuf
, sizeof(sembuf
));
449 error
= semctl1(l
, SCARG(uap
, semid
), SCARG(uap
, semnum
), cmd
,
452 if (error
== 0 && cmd
== IPC_STAT
)
453 error
= copyout(&sembuf
, karg
.buf
, sizeof(sembuf
));
459 semctl1(struct lwp
*l
, int semid
, int semnum
, int cmd
, void *v
,
462 kauth_cred_t cred
= l
->l_cred
;
463 union __semun
*arg
= v
;
464 struct semid_ds
*sembuf
= v
, *semaptr
;
467 SEM_PRINTF(("call to semctl(%d, %d, %d, %p)\n",
468 semid
, semnum
, cmd
, v
));
470 mutex_enter(&semlock
);
472 ix
= IPCID_TO_IX(semid
);
473 if (ix
< 0 || ix
>= seminfo
.semmni
) {
474 mutex_exit(&semlock
);
479 if ((semaptr
->sem_perm
.mode
& SEM_ALLOC
) == 0 ||
480 semaptr
->sem_perm
._seq
!= IPCID_TO_SEQ(semid
)) {
481 mutex_exit(&semlock
);
487 if ((error
= ipcperm(cred
, &semaptr
->sem_perm
, IPC_M
)) != 0)
489 semaptr
->sem_perm
.cuid
= kauth_cred_geteuid(cred
);
490 semaptr
->sem_perm
.uid
= kauth_cred_geteuid(cred
);
491 semtot
-= semaptr
->sem_nsems
;
492 for (i
= semaptr
->_sem_base
- sem
; i
< semtot
; i
++)
493 sem
[i
] = sem
[i
+ semaptr
->sem_nsems
];
494 for (i
= 0; i
< seminfo
.semmni
; i
++) {
495 if ((sema
[i
].sem_perm
.mode
& SEM_ALLOC
) &&
496 sema
[i
]._sem_base
> semaptr
->_sem_base
)
497 sema
[i
]._sem_base
-= semaptr
->sem_nsems
;
499 semaptr
->sem_perm
.mode
= 0;
500 semundo_clear(ix
, -1);
501 cv_broadcast(&semcv
[ix
]);
505 if ((error
= ipcperm(cred
, &semaptr
->sem_perm
, IPC_M
)))
507 KASSERT(sembuf
!= NULL
);
508 semaptr
->sem_perm
.uid
= sembuf
->sem_perm
.uid
;
509 semaptr
->sem_perm
.gid
= sembuf
->sem_perm
.gid
;
510 semaptr
->sem_perm
.mode
= (semaptr
->sem_perm
.mode
& ~0777) |
511 (sembuf
->sem_perm
.mode
& 0777);
512 semaptr
->sem_ctime
= time_second
;
516 if ((error
= ipcperm(cred
, &semaptr
->sem_perm
, IPC_R
)))
518 KASSERT(sembuf
!= NULL
);
519 memcpy(sembuf
, semaptr
, sizeof(struct semid_ds
));
520 sembuf
->sem_perm
.mode
&= 0777;
524 if ((error
= ipcperm(cred
, &semaptr
->sem_perm
, IPC_R
)))
526 if (semnum
< 0 || semnum
>= semaptr
->sem_nsems
) {
530 *retval
= semaptr
->_sem_base
[semnum
].semncnt
;
534 if ((error
= ipcperm(cred
, &semaptr
->sem_perm
, IPC_R
)))
536 if (semnum
< 0 || semnum
>= semaptr
->sem_nsems
) {
540 *retval
= semaptr
->_sem_base
[semnum
].sempid
;
544 if ((error
= ipcperm(cred
, &semaptr
->sem_perm
, IPC_R
)))
546 if (semnum
< 0 || semnum
>= semaptr
->sem_nsems
) {
550 *retval
= semaptr
->_sem_base
[semnum
].semval
;
554 if ((error
= ipcperm(cred
, &semaptr
->sem_perm
, IPC_R
)))
556 KASSERT(arg
!= NULL
);
557 for (i
= 0; i
< semaptr
->sem_nsems
; i
++) {
558 error
= copyout(&semaptr
->_sem_base
[i
].semval
,
559 &arg
->array
[i
], sizeof(arg
->array
[i
]));
566 if ((error
= ipcperm(cred
, &semaptr
->sem_perm
, IPC_R
)))
568 if (semnum
< 0 || semnum
>= semaptr
->sem_nsems
) {
572 *retval
= semaptr
->_sem_base
[semnum
].semzcnt
;
576 if ((error
= ipcperm(cred
, &semaptr
->sem_perm
, IPC_W
)))
578 if (semnum
< 0 || semnum
>= semaptr
->sem_nsems
) {
582 KASSERT(arg
!= NULL
);
583 if ((unsigned int)arg
->val
> seminfo
.semvmx
) {
587 semaptr
->_sem_base
[semnum
].semval
= arg
->val
;
588 semundo_clear(ix
, semnum
);
589 cv_broadcast(&semcv
[ix
]);
593 if ((error
= ipcperm(cred
, &semaptr
->sem_perm
, IPC_W
)))
595 KASSERT(arg
!= NULL
);
596 for (i
= 0; i
< semaptr
->sem_nsems
; i
++) {
597 unsigned short semval
;
598 error
= copyin(&arg
->array
[i
], &semval
,
599 sizeof(arg
->array
[i
]));
602 if ((unsigned int)semval
> seminfo
.semvmx
) {
606 semaptr
->_sem_base
[i
].semval
= semval
;
608 semundo_clear(ix
, -1);
609 cv_broadcast(&semcv
[ix
]);
617 mutex_exit(&semlock
);
622 sys_semget(struct lwp
*l
, const struct sys_semget_args
*uap
, register_t
*retval
)
625 syscallarg(key_t) key;
626 syscallarg(int) nsems;
627 syscallarg(int) semflg;
629 int semid
, error
= 0;
630 int key
= SCARG(uap
, key
);
631 int nsems
= SCARG(uap
, nsems
);
632 int semflg
= SCARG(uap
, semflg
);
633 kauth_cred_t cred
= l
->l_cred
;
635 SEM_PRINTF(("semget(0x%x, %d, 0%o)\n", key
, nsems
, semflg
));
637 mutex_enter(&semlock
);
639 if (key
!= IPC_PRIVATE
) {
640 for (semid
= 0; semid
< seminfo
.semmni
; semid
++) {
641 if ((sema
[semid
].sem_perm
.mode
& SEM_ALLOC
) &&
642 sema
[semid
].sem_perm
._key
== key
)
645 if (semid
< seminfo
.semmni
) {
646 SEM_PRINTF(("found public key\n"));
647 if ((error
= ipcperm(cred
, &sema
[semid
].sem_perm
,
650 if (nsems
> 0 && sema
[semid
].sem_nsems
< nsems
) {
651 SEM_PRINTF(("too small\n"));
655 if ((semflg
& IPC_CREAT
) && (semflg
& IPC_EXCL
)) {
656 SEM_PRINTF(("not exclusive\n"));
664 SEM_PRINTF(("need to allocate the semid_ds\n"));
665 if (key
== IPC_PRIVATE
|| (semflg
& IPC_CREAT
)) {
666 if (nsems
<= 0 || nsems
> seminfo
.semmsl
) {
667 SEM_PRINTF(("nsems out of range (0<%d<=%d)\n", nsems
,
672 if (nsems
> seminfo
.semmns
- semtot
) {
673 SEM_PRINTF(("not enough semaphores left "
674 "(need %d, got %d)\n",
675 nsems
, seminfo
.semmns
- semtot
));
679 for (semid
= 0; semid
< seminfo
.semmni
; semid
++) {
680 if ((sema
[semid
].sem_perm
.mode
& SEM_ALLOC
) == 0)
683 if (semid
== seminfo
.semmni
) {
684 SEM_PRINTF(("no more semid_ds's available\n"));
688 SEM_PRINTF(("semid %d is available\n", semid
));
689 sema
[semid
].sem_perm
._key
= key
;
690 sema
[semid
].sem_perm
.cuid
= kauth_cred_geteuid(cred
);
691 sema
[semid
].sem_perm
.uid
= kauth_cred_geteuid(cred
);
692 sema
[semid
].sem_perm
.cgid
= kauth_cred_getegid(cred
);
693 sema
[semid
].sem_perm
.gid
= kauth_cred_getegid(cred
);
694 sema
[semid
].sem_perm
.mode
= (semflg
& 0777) | SEM_ALLOC
;
695 sema
[semid
].sem_perm
._seq
=
696 (sema
[semid
].sem_perm
._seq
+ 1) & 0x7fff;
697 sema
[semid
].sem_nsems
= nsems
;
698 sema
[semid
].sem_otime
= 0;
699 sema
[semid
].sem_ctime
= time_second
;
700 sema
[semid
]._sem_base
= &sem
[semtot
];
702 memset(sema
[semid
]._sem_base
, 0,
703 sizeof(sema
[semid
]._sem_base
[0]) * nsems
);
704 SEM_PRINTF(("sembase = %p, next = %p\n", sema
[semid
]._sem_base
,
707 SEM_PRINTF(("didn't find it and wasn't asked to create it\n"));
713 *retval
= IXSEQ_TO_IPCID(semid
, sema
[semid
].sem_perm
);
715 mutex_exit(&semlock
);
722 sys_semop(struct lwp
*l
, const struct sys_semop_args
*uap
, register_t
*retval
)
725 syscallarg(int) semid;
726 syscallarg(struct sembuf *) sops;
727 syscallarg(size_t) nsops;
729 struct proc
*p
= l
->l_proc
;
730 int semid
= SCARG(uap
, semid
), seq
;
731 size_t nsops
= SCARG(uap
, nsops
);
732 struct sembuf small_sops
[SMALL_SOPS
];
734 struct semid_ds
*semaptr
;
735 struct sembuf
*sopptr
= NULL
;
736 struct __sem
*semptr
= NULL
;
737 struct sem_undo
*suptr
= NULL
;
738 kauth_cred_t cred
= l
->l_cred
;
740 int do_wakeup
, do_undos
;
742 SEM_PRINTF(("call to semop(%d, %p, %zd)\n", semid
, SCARG(uap
,sops
), nsops
));
744 if (__predict_false((p
->p_flag
& PK_SYSVSEM
) == 0)) {
745 mutex_enter(p
->p_lock
);
746 p
->p_flag
|= PK_SYSVSEM
;
747 mutex_exit(p
->p_lock
);
751 if (nsops
<= SMALL_SOPS
) {
753 } else if (nsops
<= seminfo
.semopm
) {
754 sops
= kmem_alloc(nsops
* sizeof(*sops
), KM_SLEEP
);
756 SEM_PRINTF(("too many sops (max=%d, nsops=%zd)\n",
757 seminfo
.semopm
, nsops
));
761 error
= copyin(SCARG(uap
, sops
), sops
, nsops
* sizeof(sops
[0]));
763 SEM_PRINTF(("error = %d from copyin(%p, %p, %zd)\n", error
,
764 SCARG(uap
, sops
), &sops
, nsops
* sizeof(sops
[0])));
765 if (sops
!= small_sops
)
766 kmem_free(sops
, nsops
* sizeof(*sops
));
770 mutex_enter(&semlock
);
771 /* In case of reallocation, we will wait for completion */
772 while (__predict_false(sem_realloc_state
))
773 cv_wait(&sem_realloc_cv
, &semlock
);
775 semid
= IPCID_TO_IX(semid
); /* Convert back to zero origin */
776 if (semid
< 0 || semid
>= seminfo
.semmni
) {
781 semaptr
= &sema
[semid
];
782 seq
= IPCID_TO_SEQ(SCARG(uap
, semid
));
783 if ((semaptr
->sem_perm
.mode
& SEM_ALLOC
) == 0 ||
784 semaptr
->sem_perm
._seq
!= seq
) {
789 if ((error
= ipcperm(cred
, &semaptr
->sem_perm
, IPC_W
))) {
790 SEM_PRINTF(("error = %d from ipaccess\n", error
));
794 for (i
= 0; i
< nsops
; i
++)
795 if (sops
[i
].sem_num
>= semaptr
->sem_nsems
) {
801 * Loop trying to satisfy the vector of requests.
802 * If we reach a point where we must wait, any requests already
803 * performed are rolled back and we go to sleep until some other
804 * process wakes us up. At this point, we start all over again.
806 * This ensures that from the perspective of other tasks, a set
807 * of requests is atomic (never partially satisfied).
814 for (i
= 0; i
< nsops
; i
++) {
816 semptr
= &semaptr
->_sem_base
[sopptr
->sem_num
];
818 SEM_PRINTF(("semop: semaptr=%p, sem_base=%p, "
819 "semptr=%p, sem[%d]=%d : op=%d, flag=%s\n",
820 semaptr
, semaptr
->_sem_base
, semptr
,
821 sopptr
->sem_num
, semptr
->semval
, sopptr
->sem_op
,
822 (sopptr
->sem_flg
& IPC_NOWAIT
) ?
825 if (sopptr
->sem_op
< 0) {
826 if ((int)(semptr
->semval
+
827 sopptr
->sem_op
) < 0) {
828 SEM_PRINTF(("semop: "
829 "can't do it now\n"));
832 semptr
->semval
+= sopptr
->sem_op
;
833 if (semptr
->semval
== 0 &&
837 if (sopptr
->sem_flg
& SEM_UNDO
)
839 } else if (sopptr
->sem_op
== 0) {
840 if (semptr
->semval
> 0) {
841 SEM_PRINTF(("semop: not zero now\n"));
845 if (semptr
->semncnt
> 0)
847 semptr
->semval
+= sopptr
->sem_op
;
848 if (sopptr
->sem_flg
& SEM_UNDO
)
854 * Did we get through the entire vector?
860 * No ... rollback anything that we've already done
862 SEM_PRINTF(("semop: rollback 0 through %d\n", i
- 1));
864 semaptr
->_sem_base
[sops
[i
].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 SEM_PRINTF(("semop: good night!\n"));
883 error
= cv_wait_sig(&semcv
[semid
], &semlock
);
884 SEM_PRINTF(("semop: good morning (error=%d)!\n", error
));
887 /* Notify reallocator, if it is waiting */
888 cv_broadcast(&sem_realloc_cv
);
891 * Make sure that the semaphore still exists
893 if ((semaptr
->sem_perm
.mode
& SEM_ALLOC
) == 0 ||
894 semaptr
->sem_perm
._seq
!= seq
) {
900 * The semaphore is still alive. Readjust the count of
903 semptr
= &semaptr
->_sem_base
[sopptr
->sem_num
];
904 if (sopptr
->sem_op
== 0)
909 /* In case of such state, restart the call */
910 if (sem_realloc_state
) {
911 mutex_exit(&semlock
);
915 /* Is it really morning, or was our sleep interrupted? */
920 SEM_PRINTF(("semop: good morning!\n"));
925 * Process any SEM_UNDO requests.
928 for (i
= 0; i
< nsops
; i
++) {
930 * We only need to deal with SEM_UNDO's for non-zero
935 if ((sops
[i
].sem_flg
& SEM_UNDO
) == 0)
937 adjval
= sops
[i
].sem_op
;
940 error
= semundo_adjust(p
, &suptr
, semid
,
941 sops
[i
].sem_num
, -adjval
);
946 * Oh-Oh! We ran out of either sem_undo's or undo's.
947 * Rollback the adjustments to this point and then
948 * rollback the semaphore ups and down so we can return
949 * with an error with all structures restored. We
950 * rollback the undo's in the exact reverse order that
951 * we applied them. This guarantees that we won't run
952 * out of space as we roll things back out.
955 if ((sops
[i
].sem_flg
& SEM_UNDO
) == 0)
957 adjval
= sops
[i
].sem_op
;
960 if (semundo_adjust(p
, &suptr
, semid
,
961 sops
[i
].sem_num
, adjval
) != 0)
962 panic("semop - can't undo undos");
965 for (i
= 0; i
< nsops
; i
++)
966 semaptr
->_sem_base
[sops
[i
].sem_num
].semval
-=
969 SEM_PRINTF(("error = %d from semundo_adjust\n", error
));
971 } /* loop through the sops */
972 } /* if (do_undos) */
974 /* We're definitely done - set the sempid's */
975 for (i
= 0; i
< nsops
; i
++) {
977 semptr
= &semaptr
->_sem_base
[sopptr
->sem_num
];
978 semptr
->sempid
= p
->p_pid
;
981 /* Update sem_otime */
982 semaptr
->sem_otime
= time_second
;
984 /* Do a wakeup if any semaphore was up'd. */
986 SEM_PRINTF(("semop: doing wakeup\n"));
987 cv_broadcast(&semcv
[semid
]);
988 SEM_PRINTF(("semop: back from wakeup\n"));
990 SEM_PRINTF(("semop: done\n"));
994 mutex_exit(&semlock
);
995 if (sops
!= small_sops
)
996 kmem_free(sops
, nsops
* sizeof(*sops
));
1001 * Go through the undo structures for this process and apply the
1002 * adjustments to semaphores.
1006 semexit(struct proc
*p
, void *v
)
1008 struct sem_undo
*suptr
;
1009 struct sem_undo
**supptr
;
1011 if ((p
->p_flag
& PK_SYSVSEM
) == 0)
1014 mutex_enter(&semlock
);
1017 * Go through the chain of undo vectors looking for one
1018 * associated with this process.
1021 for (supptr
= &semu_list
; (suptr
= *supptr
) != NULL
;
1022 supptr
= &suptr
->un_next
) {
1023 if (suptr
->un_proc
== p
)
1028 * If there is no undo vector, skip to the end.
1031 if (suptr
== NULL
) {
1032 mutex_exit(&semlock
);
1037 * We now have an undo vector for this process.
1040 SEM_PRINTF(("proc @%p has undo structure with %d entries\n", p
,
1044 * If there are any active undo elements then process them.
1046 if (suptr
->un_cnt
> 0) {
1049 for (ix
= 0; ix
< suptr
->un_cnt
; ix
++) {
1050 int semid
= suptr
->un_ent
[ix
].un_id
;
1051 int semnum
= suptr
->un_ent
[ix
].un_num
;
1052 int adjval
= suptr
->un_ent
[ix
].un_adjval
;
1053 struct semid_ds
*semaptr
;
1055 semaptr
= &sema
[semid
];
1056 if ((semaptr
->sem_perm
.mode
& SEM_ALLOC
) == 0)
1057 panic("semexit - semid not allocated");
1058 if (semnum
>= semaptr
->sem_nsems
)
1059 panic("semexit - semnum out of range");
1061 SEM_PRINTF(("semexit: %p id=%d num=%d(adj=%d) ; "
1063 suptr
->un_proc
, suptr
->un_ent
[ix
].un_id
,
1064 suptr
->un_ent
[ix
].un_num
,
1065 suptr
->un_ent
[ix
].un_adjval
,
1066 semaptr
->_sem_base
[semnum
].semval
));
1069 semaptr
->_sem_base
[semnum
].semval
< -adjval
)
1070 semaptr
->_sem_base
[semnum
].semval
= 0;
1072 semaptr
->_sem_base
[semnum
].semval
+= adjval
;
1074 cv_broadcast(&semcv
[semid
]);
1075 SEM_PRINTF(("semexit: back from wakeup\n"));
1080 * Deallocate the undo vector.
1082 SEM_PRINTF(("removing vector\n"));
1083 suptr
->un_proc
= NULL
;
1084 *supptr
= suptr
->un_next
;
1085 mutex_exit(&semlock
);
1089 * Sysctl initialization and nodes.
1093 sysctl_ipc_semmni(SYSCTLFN_ARGS
)
1096 struct sysctlnode node
;
1098 node
.sysctl_data
= &newsize
;
1100 newsize
= seminfo
.semmni
;
1101 error
= sysctl_lookup(SYSCTLFN_CALL(&node
));
1102 if (error
|| newp
== NULL
)
1105 return semrealloc(newsize
, seminfo
.semmns
, seminfo
.semmnu
);
1109 sysctl_ipc_semmns(SYSCTLFN_ARGS
)
1112 struct sysctlnode node
;
1114 node
.sysctl_data
= &newsize
;
1116 newsize
= seminfo
.semmns
;
1117 error
= sysctl_lookup(SYSCTLFN_CALL(&node
));
1118 if (error
|| newp
== NULL
)
1121 return semrealloc(seminfo
.semmni
, newsize
, seminfo
.semmnu
);
1125 sysctl_ipc_semmnu(SYSCTLFN_ARGS
)
1128 struct sysctlnode node
;
1130 node
.sysctl_data
= &newsize
;
1132 newsize
= seminfo
.semmnu
;
1133 error
= sysctl_lookup(SYSCTLFN_CALL(&node
));
1134 if (error
|| newp
== NULL
)
1137 return semrealloc(seminfo
.semmni
, seminfo
.semmns
, newsize
);
1140 SYSCTL_SETUP(sysctl_ipc_sem_setup
, "sysctl kern.ipc subtree setup")
1142 const struct sysctlnode
*node
= NULL
;
1144 sysctl_createv(clog
, 0, NULL
, NULL
,
1146 CTLTYPE_NODE
, "kern", NULL
,
1149 sysctl_createv(clog
, 0, NULL
, &node
,
1151 CTLTYPE_NODE
, "ipc",
1152 SYSCTL_DESCR("SysV IPC options"),
1154 CTL_KERN
, KERN_SYSVIPC
, CTL_EOL
);
1159 sysctl_createv(clog
, 0, &node
, NULL
,
1160 CTLFLAG_PERMANENT
| CTLFLAG_READWRITE
,
1161 CTLTYPE_INT
, "semmni",
1162 SYSCTL_DESCR("Max number of number of semaphore identifiers"),
1163 sysctl_ipc_semmni
, 0, &seminfo
.semmni
, 0,
1164 CTL_CREATE
, CTL_EOL
);
1165 sysctl_createv(clog
, 0, &node
, NULL
,
1166 CTLFLAG_PERMANENT
| CTLFLAG_READWRITE
,
1167 CTLTYPE_INT
, "semmns",
1168 SYSCTL_DESCR("Max number of number of semaphores in system"),
1169 sysctl_ipc_semmns
, 0, &seminfo
.semmns
, 0,
1170 CTL_CREATE
, CTL_EOL
);
1171 sysctl_createv(clog
, 0, &node
, NULL
,
1172 CTLFLAG_PERMANENT
| CTLFLAG_READWRITE
,
1173 CTLTYPE_INT
, "semmnu",
1174 SYSCTL_DESCR("Max number of undo structures in system"),
1175 sysctl_ipc_semmnu
, 0, &seminfo
.semmnu
, 0,
1176 CTL_CREATE
, CTL_EOL
);