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>
23 #include <sys/thread.h>
25 #include <sys/thread2.h>
27 static MALLOC_DEFINE(M_SEM
, "sem", "SVID compatible semaphores");
29 static void seminit (void *);
31 static struct sem_undo
*semu_alloc (struct proc
*p
);
32 static int semundo_adjust (struct proc
*p
, int semid
, int semnum
, int adjval
);
33 static void semundo_clear (int semid
, int semnum
);
35 static struct lwkt_token semu_token
= LWKT_TOKEN_INITIALIZER(semu_token
);
36 static int semtot
= 0;
37 static struct semid_pool
*sema
; /* semaphore id pool */
38 static TAILQ_HEAD(, sem_undo
) semu_list
= TAILQ_HEAD_INITIALIZER(semu_list
);
39 static struct lock sema_lk
;
42 u_short semval
; /* semaphore value */
43 pid_t sempid
; /* pid of last operation */
44 u_short semncnt
; /* # awaiting semval > cval */
45 u_short semzcnt
; /* # awaiting semval = 0 */
49 * Undo structure (one per process)
52 TAILQ_ENTRY(sem_undo
) un_entry
; /* linked list for semundo_clear() */
53 struct proc
*un_proc
; /* owner of this structure */
54 int un_refs
; /* prevent unlink/kfree */
55 short un_cnt
; /* # of active entries */
58 short un_adjval
; /* adjust on exit values */
59 short un_num
; /* semaphore # */
60 int un_id
; /* semid */
61 } un_ent
[1]; /* undo entries */
65 * Configuration parameters
68 #define SEMMNI 1024 /* # of semaphore identifiers */
71 #define SEMMNS 32767 /* # of semaphores in system */
74 #define SEMUME 25 /* max # of undo entries per process */
77 #define SEMMNU 1024 /* # of undo structures in system */
81 /* shouldn't need tuning */
83 #define SEMMAP 128 /* # of entries in semaphore map */
86 #define SEMMSL SEMMNS /* max # of semaphores per id */
89 #define SEMOPM 100 /* max # of operations per semop call */
92 #define SEMVMX 32767 /* semaphore maximum value */
93 #define SEMAEM 16384 /* adjust on exit max value */
96 * Due to the way semaphore memory is allocated, we have to ensure that
97 * SEMUSZ is properly aligned.
100 #define SEM_ALIGN(bytes) roundup2(bytes, sizeof(long))
102 /* actual size of an undo structure */
103 #define SEMUSZ(nent) SEM_ALIGN(offsetof(struct sem_undo, un_ent[nent]))
106 * semaphore info struct
108 struct seminfo seminfo
= {
109 SEMMAP
, /* # of entries in semaphore map */
110 SEMMNI
, /* # of semaphore identifiers */
111 SEMMNS
, /* # of semaphores in system */
112 SEMMNU
, /* # of undo structures in system */
113 SEMMSL
, /* max # of semaphores per id */
114 SEMOPM
, /* max # of operations per semop call */
115 SEMUME
, /* max # of undo entries per process */
116 SEMUSZ(SEMUME
), /* size in bytes of undo structure */
117 SEMVMX
, /* semaphore maximum value */
118 SEMAEM
/* adjust on exit max value */
121 TUNABLE_INT("kern.ipc.semmap", &seminfo
.semmap
);
122 TUNABLE_INT("kern.ipc.semmni", &seminfo
.semmni
);
123 TUNABLE_INT("kern.ipc.semmns", &seminfo
.semmns
);
124 TUNABLE_INT("kern.ipc.semmnu", &seminfo
.semmnu
);
125 TUNABLE_INT("kern.ipc.semmsl", &seminfo
.semmsl
);
126 TUNABLE_INT("kern.ipc.semopm", &seminfo
.semopm
);
127 TUNABLE_INT("kern.ipc.semume", &seminfo
.semume
);
128 TUNABLE_INT("kern.ipc.semusz", &seminfo
.semusz
);
129 TUNABLE_INT("kern.ipc.semvmx", &seminfo
.semvmx
);
130 TUNABLE_INT("kern.ipc.semaem", &seminfo
.semaem
);
132 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semmap
, CTLFLAG_RW
, &seminfo
.semmap
, 0,
133 "Number of entries in semaphore map");
134 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semmni
, CTLFLAG_RD
, &seminfo
.semmni
, 0,
135 "Number of semaphore identifiers");
136 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semmns
, CTLFLAG_RD
, &seminfo
.semmns
, 0,
137 "Total number of semaphores");
138 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semmnu
, CTLFLAG_RD
, &seminfo
.semmnu
, 0,
139 "Total number of undo structures");
140 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semmsl
, CTLFLAG_RW
, &seminfo
.semmsl
, 0,
141 "Max number of semaphores per id");
142 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semopm
, CTLFLAG_RD
, &seminfo
.semopm
, 0,
143 "Max number of operations per semop call");
144 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semume
, CTLFLAG_RD
, &seminfo
.semume
, 0,
145 "Max number of undo entries per process");
146 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semusz
, CTLFLAG_RD
, &seminfo
.semusz
, 0,
147 "Size in bytes of undo structure");
148 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semvmx
, CTLFLAG_RW
, &seminfo
.semvmx
, 0,
149 "Semaphore maximum value");
150 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semaem
, CTLFLAG_RW
, &seminfo
.semaem
, 0,
151 "Adjust on exit max value");
154 RO seminfo
.semmap
/* SEMMAP unused */
157 RO seminfo
.semmnu
/* undo entries per system */
159 RO seminfo
.semopm
/* SEMOPM unused */
161 RO seminfo
.semusz
/* param - derived from SEMUME for per-proc sizeof */
162 RO seminfo
.semvmx
/* SEMVMX unused - user param */
163 RO seminfo
.semaem
/* SEMAEM unused - user param */
171 sema
= kmalloc(sizeof(struct semid_pool
) * seminfo
.semmni
,
172 M_SEM
, M_WAITOK
| M_ZERO
);
174 lockinit(&sema_lk
, "semglb", 0, 0);
175 for (i
= 0; i
< seminfo
.semmni
; i
++) {
176 struct semid_pool
*semaptr
= &sema
[i
];
178 lockinit(&semaptr
->lk
, "semary", 0, 0);
179 semaptr
->ds
.sem_base
= NULL
;
180 semaptr
->ds
.sem_perm
.mode
= 0;
183 SYSINIT(sysv_sem
, SI_SUB_SYSV_SEM
, SI_ORDER_FIRST
, seminit
, NULL
);
186 * Allocate a new sem_undo structure for a process
187 * (returns ptr to structure or NULL if no more room)
189 static struct sem_undo
*
190 semu_alloc(struct proc
*p
)
192 struct sem_undo
*semu
;
195 * Allocate the semu structure and associate it with the process,
198 while ((semu
= p
->p_sem_undo
) == NULL
) {
199 semu
= kmalloc(SEMUSZ(seminfo
.semume
), M_SEM
,
201 lwkt_gettoken(&semu_token
);
202 lwkt_gettoken(&p
->p_token
);
203 if (p
->p_sem_undo
== NULL
) {
204 p
->p_sem_undo
= semu
;
205 p
->p_flags
|= P_SYSVSEM
;
207 TAILQ_INSERT_TAIL(&semu_list
, semu
, un_entry
);
211 lwkt_reltoken(&p
->p_token
);
212 lwkt_reltoken(&semu_token
);
218 * Adjust a particular entry for a particular proc
221 semundo_adjust(struct proc
*p
, int semid
, int semnum
, int adjval
)
223 struct sem_undo
*suptr
;
229 * Look for and remember the sem_undo if the caller doesn't
232 suptr
= semu_alloc(p
);
233 lwkt_gettoken(&p
->p_token
);
236 * Look for the requested entry and adjust it (delete if adjval becomes
239 sunptr
= &suptr
->un_ent
[0];
240 for (i
= 0; i
< suptr
->un_cnt
; i
++, sunptr
++) {
241 if (sunptr
->un_id
!= semid
|| sunptr
->un_num
!= semnum
)
244 sunptr
->un_adjval
= 0;
246 sunptr
->un_adjval
+= adjval
;
247 if (sunptr
->un_adjval
== 0) {
249 if (i
< suptr
->un_cnt
)
250 suptr
->un_ent
[i
] = suptr
->un_ent
[suptr
->un_cnt
];
255 /* Didn't find the right entry - create it */
258 if (suptr
->un_cnt
!= seminfo
.semume
) {
259 sunptr
= &suptr
->un_ent
[suptr
->un_cnt
];
261 sunptr
->un_adjval
= adjval
;
262 sunptr
->un_id
= semid
;
263 sunptr
->un_num
= semnum
;
268 lwkt_reltoken(&p
->p_token
);
274 * This is rather expensive
277 semundo_clear(int semid
, int semnum
)
280 struct sem_undo
*suptr
;
281 struct sem_undo
*sunext
;
285 lwkt_gettoken(&semu_token
);
286 sunext
= TAILQ_FIRST(&semu_list
);
287 while ((suptr
= sunext
) != NULL
) {
288 if ((p
= suptr
->un_proc
) == NULL
) {
289 suptr
= TAILQ_NEXT(suptr
, un_entry
);
294 lwkt_gettoken(&p
->p_token
);
296 sunptr
= &suptr
->un_ent
[0];
299 while (i
< suptr
->un_cnt
) {
300 if (sunptr
->un_id
== semid
) {
301 if (semnum
== -1 || sunptr
->un_num
== semnum
) {
303 if (i
< suptr
->un_cnt
) {
305 suptr
->un_ent
[suptr
->un_cnt
];
308 * or sunptr after copydown.
320 lwkt_reltoken(&p
->p_token
);
324 * Handle deletion races
326 sunext
= TAILQ_NEXT(suptr
, un_entry
);
327 if (--suptr
->un_refs
== 0 && suptr
->un_proc
== NULL
) {
328 KKASSERT(suptr
->un_cnt
== 0);
329 TAILQ_REMOVE(&semu_list
, suptr
, un_entry
);
333 lwkt_reltoken(&semu_token
);
337 * Note that the user-mode half of this passes a union, not a pointer
342 sys___semctl(struct __semctl_args
*uap
)
344 struct thread
*td
= curthread
;
345 int semid
= uap
->semid
;
346 int semnum
= uap
->semnum
;
348 union semun
*arg
= uap
->arg
;
349 union semun real_arg
;
350 struct ucred
*cred
= td
->td_ucred
;
352 struct semid_ds sbuf
;
353 struct semid_pool
*semaptr
;
354 struct semid_pool
*semakptr
;
358 kprintf("call to semctl(%d, %d, %d, 0x%x)\n", semid
, semnum
, cmd
, arg
);
361 if (!jail_sysvipc_allowed
&& cred
->cr_prison
!= NULL
)
367 * For this command we assume semid is an array index
368 * rather than an IPC id.
370 if (semid
< 0 || semid
>= seminfo
.semmni
) {
374 semakptr
= &sema
[semid
];
375 lockmgr(&semakptr
->lk
, LK_EXCLUSIVE
);
376 if ((semakptr
->ds
.sem_perm
.mode
& SEM_ALLOC
) == 0) {
378 lockmgr(&semakptr
->lk
, LK_RELEASE
);
381 if ((eval
= ipcperm(td
->td_proc
, &semakptr
->ds
.sem_perm
, IPC_R
))) {
382 lockmgr(&semakptr
->lk
, LK_RELEASE
);
385 bcopy(&semakptr
->ds
, arg
->buf
, sizeof(struct semid_ds
));
386 rval
= IXSEQ_TO_IPCID(semid
, semakptr
->ds
.sem_perm
);
387 lockmgr(&semakptr
->lk
, LK_RELEASE
);
391 semid
= IPCID_TO_IX(semid
);
392 if (semid
< 0 || semid
>= seminfo
.semmni
) {
395 semaptr
= &sema
[semid
];
396 lockmgr(&semaptr
->lk
, LK_EXCLUSIVE
);
398 if ((semaptr
->ds
.sem_perm
.mode
& SEM_ALLOC
) == 0 ||
399 semaptr
->ds
.sem_perm
.seq
!= IPCID_TO_SEQ(uap
->semid
)) {
400 lockmgr(&semaptr
->lk
, LK_RELEASE
);
409 eval
= ipcperm(td
->td_proc
, &semaptr
->ds
.sem_perm
, IPC_M
);
412 semaptr
->ds
.sem_perm
.cuid
= cred
->cr_uid
;
413 semaptr
->ds
.sem_perm
.uid
= cred
->cr_uid
;
416 * NOTE: Nobody will be waiting on the semaphores since
417 * we have an exclusive lock on semaptr->lk).
419 lockmgr(&sema_lk
, LK_EXCLUSIVE
);
420 semtot
-= semaptr
->ds
.sem_nsems
;
421 kfree(semaptr
->ds
.sem_base
, M_SEM
);
422 semaptr
->ds
.sem_base
= NULL
;
423 semaptr
->ds
.sem_perm
.mode
= 0; /* clears SEM_ALLOC */
424 lockmgr(&sema_lk
, LK_RELEASE
);
426 semundo_clear(semid
, -1);
430 eval
= ipcperm(td
->td_proc
, &semaptr
->ds
.sem_perm
, IPC_M
);
433 if ((eval
= copyin(arg
, &real_arg
, sizeof(real_arg
))) != 0)
435 if ((eval
= copyin(real_arg
.buf
, (caddr_t
)&sbuf
,
436 sizeof(sbuf
))) != 0) {
439 semaptr
->ds
.sem_perm
.uid
= sbuf
.sem_perm
.uid
;
440 semaptr
->ds
.sem_perm
.gid
= sbuf
.sem_perm
.gid
;
441 semaptr
->ds
.sem_perm
.mode
=
442 (semaptr
->ds
.sem_perm
.mode
& ~0777) |
443 (sbuf
.sem_perm
.mode
& 0777);
444 semaptr
->ds
.sem_ctime
= time_second
;
448 eval
= ipcperm(td
->td_proc
, &semaptr
->ds
.sem_perm
, IPC_R
);
451 if ((eval
= copyin(arg
, &real_arg
, sizeof(real_arg
))) != 0)
453 eval
= copyout(&semaptr
->ds
, real_arg
.buf
,
454 sizeof(struct semid_ds
));
458 eval
= ipcperm(td
->td_proc
, &semaptr
->ds
.sem_perm
, IPC_R
);
461 if (semnum
< 0 || semnum
>= semaptr
->ds
.sem_nsems
) {
465 rval
= semaptr
->ds
.sem_base
[semnum
].semncnt
;
469 eval
= ipcperm(td
->td_proc
, &semaptr
->ds
.sem_perm
, IPC_R
);
472 if (semnum
< 0 || semnum
>= semaptr
->ds
.sem_nsems
) {
476 rval
= semaptr
->ds
.sem_base
[semnum
].sempid
;
480 eval
= ipcperm(td
->td_proc
, &semaptr
->ds
.sem_perm
, IPC_R
);
483 if (semnum
< 0 || semnum
>= semaptr
->ds
.sem_nsems
) {
487 rval
= semaptr
->ds
.sem_base
[semnum
].semval
;
491 eval
= ipcperm(td
->td_proc
, &semaptr
->ds
.sem_perm
, IPC_R
);
494 if ((eval
= copyin(arg
, &real_arg
, sizeof(real_arg
))) != 0)
496 for (i
= 0; i
< semaptr
->ds
.sem_nsems
; i
++) {
497 eval
= copyout(&semaptr
->ds
.sem_base
[i
].semval
,
499 sizeof(real_arg
.array
[0]));
506 eval
= ipcperm(td
->td_proc
, &semaptr
->ds
.sem_perm
, IPC_R
);
509 if (semnum
< 0 || semnum
>= semaptr
->ds
.sem_nsems
) {
513 rval
= semaptr
->ds
.sem_base
[semnum
].semzcnt
;
517 eval
= ipcperm(td
->td_proc
, &semaptr
->ds
.sem_perm
, IPC_W
);
520 if (semnum
< 0 || semnum
>= semaptr
->ds
.sem_nsems
) {
524 if ((eval
= copyin(arg
, &real_arg
, sizeof(real_arg
))) != 0)
528 * Because we hold semaptr->lk exclusively we can safely
529 * modify any semptr content without acquiring its token.
531 semptr
= &semaptr
->ds
.sem_base
[semnum
];
532 semptr
->semval
= real_arg
.val
;
533 semundo_clear(semid
, semnum
);
534 if (semptr
->semzcnt
|| semptr
->semncnt
)
539 eval
= ipcperm(td
->td_proc
, &semaptr
->ds
.sem_perm
, IPC_W
);
542 if ((eval
= copyin(arg
, &real_arg
, sizeof(real_arg
))) != 0)
545 * Because we hold semaptr->lk exclusively we can safely
546 * modify any semptr content without acquiring its token.
548 for (i
= 0; i
< semaptr
->ds
.sem_nsems
; i
++) {
549 semptr
= &semaptr
->ds
.sem_base
[i
];
550 eval
= copyin(&real_arg
.array
[i
],
551 (caddr_t
)&semptr
->semval
,
552 sizeof(real_arg
.array
[0]));
553 if (semptr
->semzcnt
|| semptr
->semncnt
)
558 semundo_clear(semid
, -1);
565 lockmgr(&semaptr
->lk
, LK_RELEASE
);
568 uap
->sysmsg_result
= rval
;
576 sys_semget(struct semget_args
*uap
)
578 struct thread
*td
= curthread
;
581 int nsems
= uap
->nsems
;
582 int semflg
= uap
->semflg
;
583 struct ucred
*cred
= td
->td_ucred
;
586 kprintf("semget(0x%x, %d, 0%o)\n", key
, nsems
, semflg
);
589 if (!jail_sysvipc_allowed
&& cred
->cr_prison
!= NULL
)
594 if (key
!= IPC_PRIVATE
) {
595 for (semid
= 0; semid
< seminfo
.semmni
; semid
++) {
596 if ((sema
[semid
].ds
.sem_perm
.mode
& SEM_ALLOC
) == 0 ||
597 sema
[semid
].ds
.sem_perm
.key
!= key
) {
600 lockmgr(&sema
[semid
].lk
, LK_EXCLUSIVE
);
601 if ((sema
[semid
].ds
.sem_perm
.mode
& SEM_ALLOC
) == 0 ||
602 sema
[semid
].ds
.sem_perm
.key
!= key
) {
603 lockmgr(&sema
[semid
].lk
, LK_RELEASE
);
608 if (semid
< seminfo
.semmni
) {
609 /* sema[semid].lk still locked from above */
611 kprintf("found public key\n");
613 if ((eval
= ipcperm(td
->td_proc
,
614 &sema
[semid
].ds
.sem_perm
,
616 lockmgr(&sema
[semid
].lk
, LK_RELEASE
);
619 if (nsems
> 0 && sema
[semid
].ds
.sem_nsems
< nsems
) {
621 kprintf("too small\n");
624 lockmgr(&sema
[semid
].lk
, LK_RELEASE
);
627 if ((semflg
& IPC_CREAT
) && (semflg
& IPC_EXCL
)) {
629 kprintf("not exclusive\n");
632 lockmgr(&sema
[semid
].lk
, LK_RELEASE
);
639 lockmgr(&sema
[semid
].lk
, LK_RELEASE
);
645 kprintf("need to allocate the semid_ds\n");
647 if (key
== IPC_PRIVATE
|| (semflg
& IPC_CREAT
)) {
648 if (nsems
<= 0 || nsems
> seminfo
.semmsl
) {
650 kprintf("nsems out of range (0<%d<=%d)\n",
651 nsems
, seminfo
.semmsl
);
658 * SEM_ALLOC flag cannot be set unless sema_lk is locked.
659 * semtot field also protected by sema_lk.
661 lockmgr(&sema_lk
, LK_EXCLUSIVE
);
662 if (nsems
> seminfo
.semmns
- semtot
) {
664 kprintf("not enough semaphores left "
665 "(need %d, got %d)\n",
666 nsems
, seminfo
.semmns
- semtot
);
669 lockmgr(&sema_lk
, LK_RELEASE
);
672 for (semid
= 0; semid
< seminfo
.semmni
; semid
++) {
673 if ((sema
[semid
].ds
.sem_perm
.mode
& SEM_ALLOC
) == 0)
676 if (semid
== seminfo
.semmni
) {
678 kprintf("no more semid_ds's available\n");
681 lockmgr(&sema_lk
, LK_RELEASE
);
685 kprintf("semid %d is available\n", semid
);
687 lockmgr(&sema
[semid
].lk
, LK_EXCLUSIVE
);
688 sema
[semid
].ds
.sem_perm
.key
= key
;
689 sema
[semid
].ds
.sem_perm
.cuid
= cred
->cr_uid
;
690 sema
[semid
].ds
.sem_perm
.uid
= cred
->cr_uid
;
691 sema
[semid
].ds
.sem_perm
.cgid
= cred
->cr_gid
;
692 sema
[semid
].ds
.sem_perm
.gid
= cred
->cr_gid
;
693 sema
[semid
].ds
.sem_perm
.mode
= (semflg
& 0777) | SEM_ALLOC
;
694 sema
[semid
].ds
.sem_perm
.seq
=
695 (sema
[semid
].ds
.sem_perm
.seq
+ 1) & 0x7fff;
696 sema
[semid
].ds
.sem_nsems
= nsems
;
697 sema
[semid
].ds
.sem_otime
= 0;
698 sema
[semid
].ds
.sem_ctime
= time_second
;
699 sema
[semid
].ds
.sem_base
= kmalloc(sizeof(struct sem
) * nsems
,
700 M_SEM
, M_WAITOK
|M_ZERO
);
703 lockmgr(&sema
[semid
].lk
, LK_RELEASE
);
704 lockmgr(&sema_lk
, LK_RELEASE
);
706 kprintf("sembase = 0x%x, next = 0x%x\n",
707 sema
[semid
].ds
.sem_base
, &sem
[semtot
]);
712 kprintf("didn't find it and wasn't asked to create it\n");
720 IXSEQ_TO_IPCID(semid
, sema
[semid
].ds
.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_pool
*semaptr
;
736 struct sembuf
*sopptr
;
743 kprintf("call to semop(%d, 0x%x, %u)\n", semid
, sops
, nsops
);
745 if (!jail_sysvipc_allowed
&& td
->td_ucred
->cr_prison
!= NULL
)
748 semid
= IPCID_TO_IX(semid
); /* Convert back to zero origin */
750 if (semid
< 0 || semid
>= seminfo
.semmni
) {
755 wakeup_start_delayed();
756 semaptr
= &sema
[semid
];
757 lockmgr(&semaptr
->lk
, LK_SHARED
);
759 if ((semaptr
->ds
.sem_perm
.mode
& SEM_ALLOC
) == 0) {
763 if (semaptr
->ds
.sem_perm
.seq
!= IPCID_TO_SEQ(uap
->semid
)) {
768 if ((eval
= ipcperm(td
->td_proc
, &semaptr
->ds
.sem_perm
, IPC_W
))) {
770 kprintf("eval = %d from ipaccess\n", eval
);
775 if (nsops
> MAX_SOPS
) {
777 kprintf("too many sops (max=%d, nsops=%u)\n", MAX_SOPS
, nsops
);
783 if ((eval
= copyin(uap
->sops
, &sops
, nsops
* sizeof(sops
[0]))) != 0) {
785 kprintf("eval = %d from copyin(%08x, %08x, %u)\n", eval
,
786 uap
->sops
, &sops
, nsops
* sizeof(sops
[0]));
792 * Loop trying to satisfy the vector of requests.
793 * If we reach a point where we must wait, any requests already
794 * performed are rolled back and we go to sleep until some other
795 * process wakes us up. At this point, we start all over again.
797 * This ensures that from the perspective of other tasks, a set
798 * of requests is atomic (never partially satisfied).
807 for (i
= 0; i
< nsops
; i
++) {
810 if (sopptr
->sem_num
>= semaptr
->ds
.sem_nsems
) {
815 semptr
= &semaptr
->ds
.sem_base
[sopptr
->sem_num
];
816 lwkt_getpooltoken(semptr
);
819 kprintf("semop: semaptr=%x, sem_base=%x, semptr=%x, "
820 "sem[%d]=%d : op=%d, flag=%s\n",
821 semaptr
, semaptr
->ds
.sem_base
, semptr
,
822 sopptr
->sem_num
, semptr
->semval
, sopptr
->sem_op
,
823 (sopptr
->sem_flg
& IPC_NOWAIT
) ? "nowait" : "wait");
826 if (sopptr
->sem_op
< 0) {
827 if (semptr
->semval
+ sopptr
->sem_op
< 0) {
829 kprintf("semop: can't do it now\n");
833 semptr
->semval
+= sopptr
->sem_op
;
834 if (semptr
->semval
== 0 &&
835 semptr
->semzcnt
> 0) {
839 if (sopptr
->sem_flg
& SEM_UNDO
)
841 } else if (sopptr
->sem_op
== 0) {
842 if (semptr
->semval
> 0) {
844 kprintf("semop: not zero now\n");
849 semptr
->semval
+= sopptr
->sem_op
;
850 if (sopptr
->sem_flg
& SEM_UNDO
)
852 if (semptr
->semncnt
> 0)
855 lwkt_relpooltoken(semptr
);
859 * Did we get through the entire vector?
865 * No, protect the semaphore request which also flags that
866 * a wakeup is needed, then release semptr since we know
867 * another process is likely going to need to access it
870 if (sopptr
->sem_op
== 0)
874 tsleep_interlock(semptr
, PCATCH
);
875 lwkt_relpooltoken(semptr
);
878 * Rollback the semaphores we had acquired.
881 kprintf("semop: rollback 0 through %d\n", i
-1);
883 for (j
= 0; j
< i
; j
++) {
884 xsemptr
= &semaptr
->ds
.sem_base
[sops
[j
].sem_num
];
885 lwkt_getpooltoken(xsemptr
);
886 xsemptr
->semval
-= sops
[j
].sem_op
;
887 if (xsemptr
->semval
== 0 && xsemptr
->semzcnt
> 0)
889 if (xsemptr
->semval
<= 0 && xsemptr
->semncnt
> 0)
891 lwkt_relpooltoken(xsemptr
);
895 * If the request that we couldn't satisfy has the
896 * NOWAIT flag set then return with EAGAIN.
898 if (sopptr
->sem_flg
& IPC_NOWAIT
) {
904 * Release semaptr->lk while sleeping, allowing other
905 * semops (like SETVAL, SETALL, etc), which require an
906 * exclusive lock and might wake us up.
908 * Reload and recheck the validity of semaptr on return.
909 * Note that semptr itself might have changed too, but
910 * we've already interlocked for semptr and that is what
911 * will be woken up if it wakes up the tsleep on a MP
914 * gen protects against destroy/re-create races where the
918 kprintf("semop: good night!\n");
921 lockmgr(&semaptr
->lk
, LK_RELEASE
);
922 eval
= tsleep(semptr
, PCATCH
| PINTERLOCKED
, "semwait", hz
);
923 lockmgr(&semaptr
->lk
, LK_SHARED
);
925 kprintf("semop: good morning (eval=%d)!\n", eval
);
928 /* return code is checked below, after sem[nz]cnt-- */
931 * Make sure that the semaphore still exists
933 if (semaptr
->gen
!= gen
||
934 (semaptr
->ds
.sem_perm
.mode
& SEM_ALLOC
) == 0 ||
935 semaptr
->ds
.sem_perm
.seq
!= IPCID_TO_SEQ(uap
->semid
)) {
941 * The semaphore is still alive. Readjust the count of
944 semptr
= &semaptr
->ds
.sem_base
[sopptr
->sem_num
];
945 lwkt_getpooltoken(semptr
);
946 if (sopptr
->sem_op
== 0)
950 lwkt_relpooltoken(semptr
);
953 * Is it really morning, or was our sleep interrupted?
954 * (Delayed check of tsleep() return code because we
955 * need to decrement sem[nz]cnt either way.)
962 kprintf("semop: good morning!\n");
969 * Process any SEM_UNDO requests.
972 for (i
= 0; i
< nsops
; i
++) {
974 * We only need to deal with SEM_UNDO's for non-zero
979 if ((sops
[i
].sem_flg
& SEM_UNDO
) == 0)
981 adjval
= sops
[i
].sem_op
;
984 eval
= semundo_adjust(td
->td_proc
, semid
,
985 sops
[i
].sem_num
, -adjval
);
990 * Oh-Oh! We ran out of either sem_undo's or undo's.
991 * Rollback the adjustments to this point and then
992 * rollback the semaphore ups and down so we can return
993 * with an error with all structures restored. We
994 * rollback the undo's in the exact reverse order that
995 * we applied them. This guarantees that we won't run
996 * out of space as we roll things back out.
998 for (j
= i
- 1; j
>= 0; j
--) {
999 if ((sops
[j
].sem_flg
& SEM_UNDO
) == 0)
1001 adjval
= sops
[j
].sem_op
;
1004 if (semundo_adjust(td
->td_proc
, semid
,
1005 sops
[j
].sem_num
, adjval
) != 0)
1006 panic("semop - can't undo undos");
1009 for (j
= 0; j
< nsops
; j
++) {
1010 xsemptr
= &semaptr
->ds
.sem_base
[
1012 lwkt_getpooltoken(xsemptr
);
1013 xsemptr
->semval
-= sops
[j
].sem_op
;
1014 if (xsemptr
->semval
== 0 &&
1015 xsemptr
->semzcnt
> 0)
1017 if (xsemptr
->semval
<= 0 &&
1018 xsemptr
->semncnt
> 0)
1020 lwkt_relpooltoken(xsemptr
);
1024 kprintf("eval = %d from semundo_adjust\n", eval
);
1027 } /* loop through the sops */
1028 } /* if (do_undos) */
1030 /* We're definitely done - set the sempid's */
1031 for (i
= 0; i
< nsops
; i
++) {
1033 semptr
= &semaptr
->ds
.sem_base
[sopptr
->sem_num
];
1034 lwkt_getpooltoken(semptr
);
1035 semptr
->sempid
= td
->td_proc
->p_pid
;
1036 lwkt_relpooltoken(semptr
);
1039 /* Do a wakeup if any semaphore was up'd. */
1041 kprintf("semop: done\n");
1043 uap
->sysmsg_result
= 0;
1046 lockmgr(&semaptr
->lk
, LK_RELEASE
);
1047 wakeup_end_delayed();
1053 * Go through the undo structures for this process and apply the adjustments to
1056 * (p->p_token is held by the caller)
1059 semexit(struct proc
*p
)
1061 struct sem_undo
*suptr
;
1065 * We're getting a global token, don't do it if we couldn't
1066 * possibly have any semaphores.
1068 if ((p
->p_flags
& P_SYSVSEM
) == 0)
1070 suptr
= p
->p_sem_undo
;
1071 KKASSERT(suptr
!= NULL
);
1074 * Disconnect suptr from the process and increment un_refs to
1075 * prevent anyone else from being able to destroy the structure.
1076 * Do not remove it from the linked list until after we are through
1077 * scanning it as other semaphore calls might still effect it.
1079 lwkt_gettoken(&semu_token
);
1080 p
->p_sem_undo
= NULL
;
1081 p
->p_flags
&= ~P_SYSVSEM
;
1082 suptr
->un_proc
= NULL
;
1084 lwkt_reltoken(&semu_token
);
1086 while (suptr
->un_cnt
) {
1087 struct semid_pool
*semaptr
;
1094 * These values are stable because we hold p->p_token.
1095 * However, they can get ripped out from under us when
1096 * we block or obtain other tokens so we have to re-check.
1098 ix
= suptr
->un_cnt
- 1;
1099 semid
= suptr
->un_ent
[ix
].un_id
;
1100 semnum
= suptr
->un_ent
[ix
].un_num
;
1101 adjval
= suptr
->un_ent
[ix
].un_adjval
;
1103 semaptr
= &sema
[semid
];
1106 * Recheck after locking, then execute the undo
1107 * operation. semptr remains valid due to the
1110 lockmgr(&semaptr
->lk
, LK_SHARED
);
1111 semptr
= &semaptr
->ds
.sem_base
[semnum
];
1112 lwkt_getpooltoken(semptr
);
1114 if (ix
== suptr
->un_cnt
- 1 &&
1115 semid
== suptr
->un_ent
[ix
].un_id
&&
1116 semnum
== suptr
->un_ent
[ix
].un_num
&&
1117 adjval
== suptr
->un_ent
[ix
].un_adjval
) {
1119 * Only do assertions when we aren't in a SMP race.
1121 if ((semaptr
->ds
.sem_perm
.mode
& SEM_ALLOC
) == 0)
1122 panic("semexit - semid not allocated");
1123 if (semnum
>= semaptr
->ds
.sem_nsems
)
1124 panic("semexit - semnum out of range");
1128 if (semptr
->semval
< -adjval
)
1131 semptr
->semval
+= adjval
;
1133 semptr
->semval
+= adjval
;
1137 lwkt_relpooltoken(semptr
);
1138 lockmgr(&semaptr
->lk
, LK_RELEASE
);
1142 * Final cleanup, remove from the list and deallocate on the
1145 lwkt_gettoken(&semu_token
);
1146 if (--suptr
->un_refs
== 0) {
1147 TAILQ_REMOVE(&semu_list
, suptr
, un_entry
);
1148 KKASSERT(suptr
->un_cnt
== 0);
1149 kfree(suptr
, M_SEM
);
1151 lwkt_reltoken(&semu_token
);