2 * Implementation of SVID semaphores
4 * Author: Daniel Boulet
6 * This software is provided ``AS IS'' without any warranties of any kind.
10 * This file is heavily changed to become part of Cygwin's cygserver.
13 #ifdef __OUTSIDE_CYGWIN__
15 #include <sys/cygwin.h>
16 #include <sys/cdefs.h>
18 #define __FBSDID(s) const char version[] = (s)
20 __FBSDID("$FreeBSD: /repoman/r/ncvs/src/sys/kern/sysv_sem.c,v 1.70 2004/05/30 20:34:58 phk Exp $");
23 #define __BSD_VISIBLE 1
24 #include <sys/types.h>
27 #include <sys/param.h>
28 #include <sys/sysproto.h>
31 #include <sys/queue.h>
35 #include "cygserver.h"
37 #include "cygserver_ipc.h"
38 #include <sys/smallprint.h>
41 #define __semctl semctl
42 #define __semctl_args semctl_args
44 #endif /* __CYGWIN__ */
47 #define DPRINTF(a) debug_printf a
52 static int semvalid(int semid
, struct semid_ds
*semaptr
);
54 static struct sem_undo
*semu_alloc(struct thread
*td
);
55 static int semundo_adjust(struct thread
*td
, struct sem_undo
**supptr
,
56 int semid
, int semnum
, int adjval
);
57 static void semundo_clear(int semid
, int semnum
, struct thread
*td
);
59 #ifndef _SYS_SYSPROTO_H_
61 int __semctl(struct thread
*td
, struct __semctl_args
*uap
);
63 int semget(struct thread
*td
, struct semget_args
*uap
);
65 int semop(struct thread
*td
, struct semop_args
*uap
);
69 /* XXX casting to (sy_call_t *) is bogus, as usual. */
70 static sy_call_t
*semcalls
[] = {
71 (sy_call_t
*)__semctl
, (sy_call_t
*)semget
,
76 static struct mtx sem_mtx
; /* semaphore global lock */
77 static int semtots
= 0;
78 static int semtot
= 0;
79 static struct semid_ds
*sema
; /* semaphore id pool */
80 static struct mtx
*sema_mtx
; /* semaphore id pool mutexes*/
81 static struct sem
*sem
; /* semaphore pool */
82 SLIST_HEAD(, sem_undo
) semu_list
; /* list of active undo structures */
83 static int *semu
; /* undo structure pool */
85 static eventhandler_tag semexit_tag
;
86 #endif /* __CYGWIN__ */
88 #define SEMUNDO_MTX sem_mtx
89 #define SEMUNDO_LOCK() mtx_lock(&SEMUNDO_MTX);
90 #define SEMUNDO_HOOKLOCK() _mtx_lock(&SEMUNDO_MTX, p->winpid, __FILE__, __LINE__);
91 #define SEMUNDO_UNLOCK() mtx_unlock(&SEMUNDO_MTX);
92 #define SEMUNDO_LOCKASSERT(how,pid) mtx_assert(&SEMUNDO_MTX, (how), (pid));
95 u_short semval
; /* semaphore value */
96 pid_t sempid
; /* pid of last operation */
97 u_short semncnt
; /* # awaiting semval > cval */
98 u_short semzcnt
; /* # awaiting semval = 0 */
102 * Undo structure (one per process)
105 short un_adjval
; /* adjust on exit values */
106 short un_num
; /* semaphore # */
107 int un_id
; /* semid */
108 } un_ent
[1]; /* undo entries */
111 SLIST_ENTRY(sem_undo
) un_next
; /* ptr to next active undo structure */
113 DWORD un_proc
; /* owner of this structure */
115 struct proc
*un_proc
; /* owner of this structure */
117 short un_cnt
; /* # of active entries */
118 struct undo un_ent
[1]; /* undo entries */
122 * Configuration parameters
125 #define SEMMNI 10 /* # of semaphore identifiers */
128 #define SEMMNS 60 /* # of semaphores in system */
131 #define SEMUME 10 /* max # of undo entries per process */
134 #define SEMMNU 30 /* # of undo structures in system */
137 /* shouldn't need tuning */
139 #define SEMMAP 30 /* # of entries in semaphore map */
142 #define SEMMSL SEMMNS /* max # of semaphores per id */
145 #define SEMOPM 100 /* max # of operations per semop call */
149 #define SEMVMX 32767 /* semaphore maximum value */
152 #define SEMAEM 16384 /* adjust on exit max value */
156 /* gcc 3.4 defines a new offsetof which is different for C++. Since this
157 file is just a derived plain-C file, we need to revert to the plain-C
158 definition of offsetof. */
162 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
163 #endif /* __CYGWIN__ */
165 * Due to the way semaphore memory is allocated, we have to ensure that
166 * SEMUSZ is properly aligned.
169 #define SEM_ALIGN(bytes) (((bytes) + (sizeof(long) - 1)) & ~(sizeof(long) - 1))
171 /* actual size of an undo structure */
172 #define SEMUSZ SEM_ALIGN(offsetof(struct sem_undo, un_ent[SEMUME]))
175 * Macro to find a particular sem_undo vector
178 ((struct sem_undo *)(((intptr_t)semu)+ix * seminfo.semusz))
181 * semaphore info struct
183 struct seminfo seminfo
= {
184 SEMMNI
, /* # of semaphore identifiers */
185 SEMMNS
, /* # of semaphores in system */
186 SEMMSL
, /* max # of semaphores per id */
187 SEMOPM
, /* max # of operations per semop call */
188 SEMMNU
, /* # of undo structures in system */
189 SEMUME
, /* max # of undo entries per process */
190 SEMVMX
, /* semaphore maximum value */
191 SEMAEM
, /* adjust on exit max value */
192 SEMMAP
, /* # of entries in semaphore map */
193 SEMUSZ
/* size in bytes of undo structure */
197 SYSCTL_DECL(_kern_ipc
);
198 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semmap
, CTLFLAG_RW
, &seminfo
.semmap
, 0, "");
199 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semmni
, CTLFLAG_RDTUN
, &seminfo
.semmni
, 0, "");
200 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semmns
, CTLFLAG_RDTUN
, &seminfo
.semmns
, 0, "");
201 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semmnu
, CTLFLAG_RDTUN
, &seminfo
.semmnu
, 0, "");
202 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semmsl
, CTLFLAG_RW
, &seminfo
.semmsl
, 0, "");
203 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semopm
, CTLFLAG_RDTUN
, &seminfo
.semopm
, 0, "");
204 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semume
, CTLFLAG_RDTUN
, &seminfo
.semume
, 0, "");
205 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semusz
, CTLFLAG_RDTUN
, &seminfo
.semusz
, 0, "");
206 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semvmx
, CTLFLAG_RW
, &seminfo
.semvmx
, 0, "");
207 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semaem
, CTLFLAG_RW
, &seminfo
.semaem
, 0, "");
208 SYSCTL_PROC(_kern_ipc
, OID_AUTO
, sema
, CTLFLAG_RD
,
209 NULL
, 0, sysctl_sema
, "", "");
210 #endif /* __CYGWIN__ */
217 TUNABLE_INT_FETCH("kern.ipc.semmap", &seminfo
.semmap
);
218 TUNABLE_INT_FETCH("kern.ipc.semmni", &seminfo
.semmni
);
219 TUNABLE_INT_FETCH("kern.ipc.semmns", &seminfo
.semmns
);
220 TUNABLE_INT_FETCH("kern.ipc.semmnu", &seminfo
.semmnu
);
221 TUNABLE_INT_FETCH("kern.ipc.semmsl", &seminfo
.semmsl
);
222 TUNABLE_INT_FETCH("kern.ipc.semopm", &seminfo
.semopm
);
223 TUNABLE_INT_FETCH("kern.ipc.semume", &seminfo
.semume
);
224 TUNABLE_INT_FETCH("kern.ipc.semusz", &seminfo
.semusz
);
225 TUNABLE_INT_FETCH("kern.ipc.semvmx", &seminfo
.semvmx
);
226 TUNABLE_INT_FETCH("kern.ipc.semaem", &seminfo
.semaem
);
229 /* It's too dangerous a setting to leave it alone.
230 Keep that clean here. */
231 seminfo
.semusz
= SEM_ALIGN(offsetof(struct sem_undo
,
232 un_ent
[seminfo
.semume
]));
233 #endif /* __CYGWIN__ */
235 sem
= (struct sem
*) sys_malloc(sizeof(struct sem
) * seminfo
.semmns
, M_SEM
, M_WAITOK
);
236 sema
= (struct semid_ds
*) sys_malloc(sizeof(struct semid_ds
) * seminfo
.semmni
, M_SEM
,
238 sema_mtx
= (struct mtx
*) sys_malloc(sizeof(struct mtx
) * seminfo
.semmni
, M_SEM
,
240 semu
= (int *) sys_malloc(seminfo
.semmnu
* seminfo
.semusz
, M_SEM
, M_WAITOK
);
242 for (i
= 0; i
< seminfo
.semmni
; i
++) {
243 sema
[i
].sem_base
= 0;
244 sema
[i
].sem_perm
.mode
= 0;
245 sema
[i
].sem_perm
.seq
= 0;
247 for (i
= 0; i
< seminfo
.semmni
; i
++)
249 char *buf
= (char *)malloc (16);
250 __small_sprintf (buf
, "semid[%d]", i
);
251 mtx_init(&sema_mtx
[i
], buf
, NULL
, MTX_DEF
);
253 for (i
= 0; i
< seminfo
.semmnu
; i
++) {
254 struct sem_undo
*suptr
= SEMU(i
);
258 suptr
->un_proc
= NULL
;
261 SLIST_INIT(&semu_list
);
262 mtx_init(&sem_mtx
, "sem", NULL
, MTX_DEF
);
264 semexit_tag
= EVENTHANDLER_REGISTER(process_exit
, semexit_myhook
, NULL
,
265 EVENTHANDLER_PRI_ANY
);
266 #endif /* __CYGWIN__ */
272 #ifndef __CYGWIN__ /* Would result in being unable to shutdown the
273 server gracefully. */
277 EVENTHANDLER_DEREGISTER(process_exit
, semexit_tag
);
278 #endif /* __CYGWIN__ */
279 sys_free(sem
, M_SEM
);
280 sys_free(sema
, M_SEM
);
281 sys_free(semu
, M_SEM
);
282 for (int i
= 0; i
< seminfo
.semmni
; i
++)
283 mtx_destroy(&sema_mtx
[i
]);
284 mtx_destroy(&sem_mtx
);
290 sysvsem_modload(struct module
*module
, int cmd
, void *arg
)
310 static moduledata_t sysvsem_mod
= {
316 SYSCALL_MODULE_HELPER(semsys
);
317 SYSCALL_MODULE_HELPER(__semctl
);
318 SYSCALL_MODULE_HELPER(semget
);
319 SYSCALL_MODULE_HELPER(semop
);
321 DECLARE_MODULE(sysvsem
, sysvsem_mod
,
322 SI_SUB_SYSV_SEM
, SI_ORDER_FIRST
);
323 MODULE_VERSION(sysvsem
, 1);
326 * Entry point for all SEM calls
333 /* XXX actually varargs. */
334 struct semsys_args
/* {
344 if (!jail_sysvipc_allowed
&& jailed(td
->td_ucred
))
346 if (uap
->which
< 0 ||
347 uap
->which
>= sizeof(semcalls
)/sizeof(semcalls
[0]))
349 error
= (*semcalls
[uap
->which
])(td
, &uap
->a2
);
352 #endif /* __CYGWIN__ */
355 * Allocate a new sem_undo structure for a process
356 * (returns ptr to structure or NULL if no more room)
359 static struct sem_undo
*
360 semu_alloc(struct thread
*td
)
363 struct sem_undo
*suptr
;
364 struct sem_undo
**supptr
;
367 SEMUNDO_LOCKASSERT(MA_OWNED
, td
->td_proc
->winpid
);
369 * Try twice to allocate something.
370 * (we'll purge an empty structure after the first pass so
371 * two passes are always enough)
374 for (attempt
= 0; attempt
< 2; attempt
++) {
376 * Look for a free structure.
377 * Fill it in and return it if we find one.
380 for (i
= 0; i
< seminfo
.semmnu
; i
++) {
383 if (suptr
->un_proc
== 0) {
385 if (suptr
->un_proc
== NULL
) {
387 SLIST_INSERT_HEAD(&semu_list
, suptr
, un_next
);
389 suptr
->un_proc
= td
->td_proc
->winpid
;
395 * We didn't find a free one, if this is the first attempt
396 * then try to free a structure.
400 /* All the structures are in use - try to free one */
401 int did_something
= 0;
403 SLIST_FOREACH_PREVPTR(suptr
, supptr
, &semu_list
,
405 if (suptr
->un_cnt
== 0) {
409 suptr
->un_proc
= NULL
;
412 *supptr
= SLIST_NEXT(suptr
, un_next
);
417 /* If we didn't free anything then just give-up */
422 * The second pass failed even though we freed
423 * something after the first pass!
424 * This is IMPOSSIBLE!
426 panic("semu_alloc - second attempt failed");
433 * Adjust a particular entry for a particular proc
437 semundo_adjust(struct thread
*td
, struct sem_undo
**supptr
, int semid
,
438 int semnum
, int adjval
)
440 struct proc
*p
= td
->td_proc
;
441 struct sem_undo
*suptr
;
445 SEMUNDO_LOCKASSERT(MA_OWNED
, td
->td_proc
->winpid
);
446 /* Look for and remember the sem_undo if the caller doesn't provide
451 SLIST_FOREACH(suptr
, &semu_list
, un_next
) {
453 if (suptr
->un_proc
== p
->winpid
) {
455 if (suptr
->un_proc
== p
) {
464 suptr
= semu_alloc(td
);
472 * Look for the requested entry and adjust it (delete if adjval becomes
475 sunptr
= &suptr
->un_ent
[0];
476 for (i
= 0; i
< suptr
->un_cnt
; i
++, sunptr
++) {
477 if (sunptr
->un_id
!= semid
|| sunptr
->un_num
!= semnum
)
480 adjval
+= sunptr
->un_adjval
;
481 if (adjval
> seminfo
.semaem
|| adjval
< -seminfo
.semaem
)
484 sunptr
->un_adjval
= adjval
;
485 if (sunptr
->un_adjval
== 0) {
487 if (i
< suptr
->un_cnt
)
489 suptr
->un_ent
[suptr
->un_cnt
];
494 /* Didn't find the right entry - create it */
497 if (adjval
> seminfo
.semaem
|| adjval
< -seminfo
.semaem
)
499 if (suptr
->un_cnt
!= seminfo
.semume
) {
500 sunptr
= &suptr
->un_ent
[suptr
->un_cnt
];
502 sunptr
->un_adjval
= adjval
;
503 sunptr
->un_id
= semid
; sunptr
->un_num
= semnum
;
510 semundo_clear(int semid
, int semnum
, struct thread
*td
)
512 struct sem_undo
*suptr
;
514 SEMUNDO_LOCKASSERT(MA_OWNED
, td
->td_proc
->winpid
);
515 SLIST_FOREACH(suptr
, &semu_list
, un_next
) {
516 struct undo
*sunptr
= &suptr
->un_ent
[0];
519 while (i
< suptr
->un_cnt
) {
520 if (sunptr
->un_id
== semid
) {
521 if (semnum
== -1 || sunptr
->un_num
== semnum
) {
523 if (i
< suptr
->un_cnt
) {
525 suptr
->un_ent
[suptr
->un_cnt
];
538 semvalid(int semid
, struct semid_ds
*semaptr
)
541 return ((semaptr
->sem_perm
.mode
& SEM_ALLOC
) == 0 ||
542 semaptr
->sem_perm
.seq
!= IPCID_TO_SEQ(semid
) ? EINVAL
: 0);
546 * Note that the user-mode half of this passes a union, not a pointer
548 #ifndef _SYS_SYSPROTO_H_
549 struct __semctl_args
{
561 __semctl(struct thread
*td
, struct __semctl_args
*uap
)
563 int semid
= uap
->semid
;
564 int semnum
= uap
->semnum
;
567 union semun
*arg
= uap
->arg
;
568 union semun real_arg
;
570 struct ucred
*cred
= td
->td_ucred
;
573 struct semid_ds sbuf
;
574 struct semid_ds
*semaptr
;
575 struct mtx
*sema_mtxp
;
576 u_short usval
, count
;
578 DPRINTF(("call to semctl(%d, %d, %d, 0x%x)\n",
579 semid
, semnum
, cmd
, arg
));
580 if (!jail_sysvipc_allowed
&& jailed(td
->td_ucred
))
588 if ((error
= copyin(arg
, &real_arg
, sizeof(real_arg
))) != 0)
591 error
= copyout(&seminfo
, real_arg
.buf
,
592 sizeof(struct seminfo
));
593 td
->td_retval
[0] = error
? -1 : 0;
596 if (semid
> seminfo
.semmni
)
597 semid
= seminfo
.semmni
;
598 error
= copyout(sema
, real_arg
.buf
,
599 semid
* sizeof(struct semid_ds
));
600 td
->td_retval
[0] = error
? -1 : 0;
603 if (!(error
= copyin(arg
, &real_arg
, sizeof(real_arg
)))) {
604 struct sem_info sem_info
;
605 sem_info
.sem_ids
= semtots
;
606 sem_info
.sem_num
= semtot
;
607 error
= copyout(&sem_info
, real_arg
.buf
,
608 sizeof(struct sem_info
));
610 td
->td_retval
[0] = error
? -1 : 0;
613 #endif /* __CYGWIN__ */
615 if (semid
< 0 || semid
>= seminfo
.semmni
)
617 if ((error
= copyin(arg
, &real_arg
, sizeof(real_arg
))) != 0)
619 semaptr
= &sema
[semid
];
620 sema_mtxp
= &sema_mtx
[semid
];
622 if ((semaptr
->sem_perm
.mode
& SEM_ALLOC
) == 0) {
626 if ((error
= ipcperm(td
, &semaptr
->sem_perm
, IPC_R
)))
628 mtx_unlock(sema_mtxp
);
629 error
= copyout(semaptr
, real_arg
.buf
, sizeof(struct semid_ds
));
630 rval
= IXSEQ_TO_IPCID(semid
,semaptr
->sem_perm
);
632 td
->td_retval
[0] = rval
;
636 semid
= IPCID_TO_IX(semid
);
637 if (semid
< 0 || semid
>= seminfo
.semmni
)
640 semaptr
= &sema
[semid
];
641 sema_mtxp
= &sema_mtx
[semid
];
649 if ((error
= semvalid(uap
->semid
, semaptr
)) != 0)
651 if ((error
= ipcperm(td
, &semaptr
->sem_perm
, IPC_M
)))
654 semaptr
->sem_perm
.cuid
= td
->ipcblk
->uid
;
655 semaptr
->sem_perm
.uid
= td
->ipcblk
->uid
;
657 semaptr
->sem_perm
.cuid
= cred
->cr_uid
;
658 semaptr
->sem_perm
.uid
= cred
->cr_uid
;
660 semtot
-= semaptr
->sem_nsems
;
662 for (i
= semaptr
->sem_base
- sem
; i
< semtot
; i
++)
663 sem
[i
] = sem
[i
+ semaptr
->sem_nsems
];
664 for (i
= 0; i
< seminfo
.semmni
; i
++) {
665 if ((sema
[i
].sem_perm
.mode
& SEM_ALLOC
) &&
666 sema
[i
].sem_base
> semaptr
->sem_base
)
667 sema
[i
].sem_base
-= semaptr
->sem_nsems
;
669 semaptr
->sem_perm
.mode
= 0;
671 semundo_clear(semid
, -1, td
);
677 if ((error
= copyin(arg
, &real_arg
, sizeof(real_arg
))) != 0)
679 if ((error
= copyin(real_arg
.buf
, &sbuf
, sizeof(sbuf
))) != 0)
682 if ((error
= semvalid(uap
->semid
, semaptr
)) != 0)
684 if ((error
= ipcperm(td
, &semaptr
->sem_perm
, IPC_M
)))
686 semaptr
->sem_perm
.uid
= sbuf
.sem_perm
.uid
;
687 semaptr
->sem_perm
.gid
= sbuf
.sem_perm
.gid
;
688 semaptr
->sem_perm
.mode
= (semaptr
->sem_perm
.mode
& ~0777) |
689 (sbuf
.sem_perm
.mode
& 0777);
690 semaptr
->sem_ctime
= time (NULL
);
694 if ((error
= copyin(arg
, &real_arg
, sizeof(real_arg
))) != 0)
697 if ((error
= semvalid(uap
->semid
, semaptr
)) != 0)
699 if ((error
= ipcperm(td
, &semaptr
->sem_perm
, IPC_R
)))
702 mtx_unlock(sema_mtxp
);
703 error
= copyout(semaptr
, real_arg
.buf
,
704 sizeof(struct semid_ds
));
709 if ((error
= semvalid(uap
->semid
, semaptr
)) != 0)
711 if ((error
= ipcperm(td
, &semaptr
->sem_perm
, IPC_R
)))
713 if (semnum
< 0 || semnum
>= semaptr
->sem_nsems
) {
717 rval
= semaptr
->sem_base
[semnum
].semncnt
;
722 if ((error
= semvalid(uap
->semid
, semaptr
)) != 0)
724 if ((error
= ipcperm(td
, &semaptr
->sem_perm
, IPC_R
)))
726 if (semnum
< 0 || semnum
>= semaptr
->sem_nsems
) {
730 rval
= semaptr
->sem_base
[semnum
].sempid
;
735 if ((error
= semvalid(uap
->semid
, semaptr
)) != 0)
737 if ((error
= ipcperm(td
, &semaptr
->sem_perm
, IPC_R
)))
739 if (semnum
< 0 || semnum
>= semaptr
->sem_nsems
) {
743 rval
= semaptr
->sem_base
[semnum
].semval
;
747 if ((error
= copyin(arg
, &real_arg
, sizeof(real_arg
))) != 0)
749 array
= (u_short
*) sys_malloc(sizeof(*array
) * semaptr
->sem_nsems
, M_TEMP
,
752 if ((error
= semvalid(uap
->semid
, semaptr
)) != 0)
754 if ((error
= ipcperm(td
, &semaptr
->sem_perm
, IPC_R
)))
756 for (i
= 0; i
< semaptr
->sem_nsems
; i
++)
757 array
[i
] = semaptr
->sem_base
[i
].semval
;
758 mtx_unlock(sema_mtxp
);
759 error
= copyout(array
, real_arg
.array
,
760 i
* sizeof(real_arg
.array
[0]));
765 if ((error
= semvalid(uap
->semid
, semaptr
)) != 0)
767 if ((error
= ipcperm(td
, &semaptr
->sem_perm
, IPC_R
)))
769 if (semnum
< 0 || semnum
>= semaptr
->sem_nsems
) {
773 rval
= semaptr
->sem_base
[semnum
].semzcnt
;
777 if ((error
= copyin(arg
, &real_arg
, sizeof(real_arg
))) != 0)
780 if ((error
= semvalid(uap
->semid
, semaptr
)) != 0)
782 if ((error
= ipcperm(td
, &semaptr
->sem_perm
, IPC_W
)))
784 if (semnum
< 0 || semnum
>= semaptr
->sem_nsems
) {
788 if (real_arg
.val
< 0 || real_arg
.val
> seminfo
.semvmx
) {
792 semaptr
->sem_base
[semnum
].semval
= real_arg
.val
;
794 semundo_clear(semid
, semnum
, td
);
802 if ((error
= semvalid(uap
->semid
, semaptr
)) != 0)
804 count
= semaptr
->sem_nsems
;
805 mtx_unlock(sema_mtxp
);
806 if ((error
= copyin(arg
, &real_arg
, sizeof(real_arg
))) != 0)
808 array
= (u_short
*) sys_malloc(sizeof(*array
) * count
, M_TEMP
, M_WAITOK
);
809 copyin(real_arg
.array
, array
, count
* sizeof(*array
));
813 if ((error
= semvalid(uap
->semid
, semaptr
)) != 0)
815 /* we could have raced? */
816 if (count
!= semaptr
->sem_nsems
) {
817 sys_free(array
, M_TEMP
);
821 if ((error
= ipcperm(td
, &semaptr
->sem_perm
, IPC_W
)))
823 for (i
= 0; i
< semaptr
->sem_nsems
; i
++) {
825 if (usval
> seminfo
.semvmx
) {
829 semaptr
->sem_base
[i
].semval
= usval
;
832 semundo_clear(semid
, -1, td
);
843 td
->td_retval
[0] = rval
;
845 if (mtx_owned(sema_mtxp
, td
->td_proc
->winpid
))
846 mtx_unlock(sema_mtxp
);
848 sys_free(array
, M_TEMP
);
852 #ifndef _SYS_SYSPROTO_H_
864 semget(struct thread
*td
, struct semget_args
*uap
)
866 int semid
, error
= 0;
867 key_t key
= uap
->key
;
868 int nsems
= uap
->nsems
;
869 int semflg
= uap
->semflg
;
871 struct ucred
*cred
= td
->td_ucred
;
874 DPRINTF(("semget(0x%X, %d, 0%o)\n", key
, nsems
, semflg
));
875 if (!jail_sysvipc_allowed
&& jailed(td
->td_ucred
))
879 if (key
!= IPC_PRIVATE
) {
880 for (semid
= 0; semid
< seminfo
.semmni
; semid
++) {
881 if ((sema
[semid
].sem_perm
.mode
& SEM_ALLOC
) &&
882 sema
[semid
].sem_perm
.key
== key
)
885 if (semid
< seminfo
.semmni
) {
886 DPRINTF(("found public key\n"));
887 if ((error
= ipcperm(td
, &sema
[semid
].sem_perm
,
891 if (nsems
> 0 && sema
[semid
].sem_nsems
< nsems
) {
892 DPRINTF(("too small\n"));
896 if ((semflg
& IPC_CREAT
) && (semflg
& IPC_EXCL
)) {
897 DPRINTF(("not exclusive\n"));
905 DPRINTF(("need to allocate the semid_ds\n"));
906 if (key
== IPC_PRIVATE
|| (semflg
& IPC_CREAT
)) {
907 if (nsems
<= 0 || nsems
> seminfo
.semmsl
) {
908 DPRINTF(("nsems out of range (0<%d<=%d)\n", nsems
,
913 if (nsems
> seminfo
.semmns
- semtot
) {
915 "not enough semaphores left (need %d, got %d)\n",
916 nsems
, seminfo
.semmns
- semtot
));
920 for (semid
= 0; semid
< seminfo
.semmni
; semid
++) {
921 if ((sema
[semid
].sem_perm
.mode
& SEM_ALLOC
) == 0)
924 if (semid
== seminfo
.semmni
) {
925 DPRINTF(("no more semid_ds's available\n"));
929 DPRINTF(("semid %d is available\n", semid
));
930 sema
[semid
].sem_perm
.key
= key
;
932 sema
[semid
].sem_perm
.cuid
= td
->ipcblk
->uid
;
933 sema
[semid
].sem_perm
.uid
= td
->ipcblk
->uid
;
934 sema
[semid
].sem_perm
.cgid
= td
->ipcblk
->gid
;
935 sema
[semid
].sem_perm
.gid
= td
->ipcblk
->gid
;
937 sema
[semid
].sem_perm
.cuid
= cred
->cr_uid
;
938 sema
[semid
].sem_perm
.uid
= cred
->cr_uid
;
939 sema
[semid
].sem_perm
.cgid
= cred
->cr_gid
;
940 sema
[semid
].sem_perm
.gid
= cred
->cr_gid
;
942 sema
[semid
].sem_perm
.mode
= (semflg
& 0777) | SEM_ALLOC
;
943 sema
[semid
].sem_perm
.seq
=
944 (sema
[semid
].sem_perm
.seq
+ 1) & 0x7fff;
945 sema
[semid
].sem_nsems
= nsems
;
946 sema
[semid
].sem_otime
= 0;
947 sema
[semid
].sem_ctime
= time (NULL
);
948 sema
[semid
].sem_base
= &sem
[semtot
];
951 bzero(sema
[semid
].sem_base
,
952 sizeof(sema
[semid
].sem_base
[0])*nsems
);
953 DPRINTF(("sembase = 0x%x, next = 0x%x\n", sema
[semid
].sem_base
,
956 DPRINTF(("didn't find it and wasn't asked to create it\n"));
962 td
->td_retval
[0] = IXSEQ_TO_IPCID(semid
, sema
[semid
].sem_perm
);
966 ipcexit_creat_hookthread (td
);
972 #ifndef _SYS_SYSPROTO_H_
984 semop(struct thread
*td
, struct semop_args
*uap
)
987 struct sembuf small_sops
[SMALL_SOPS
];
988 int semid
= uap
->semid
;
989 size_t nsops
= uap
->nsops
;
991 struct semid_ds
*semaptr
;
992 struct sembuf
*sopptr
= 0;
993 struct sem
*semptr
= 0;
994 struct sem_undo
*suptr
;
995 struct mtx
*sema_mtxp
;
998 int do_wakeup
, do_undos
;
1000 DPRINTF(("call to semop(%d, 0x%x, %u)\n", semid
, uap
->sops
, nsops
));
1002 if (!jail_sysvipc_allowed
&& jailed(td
->td_ucred
))
1005 semid
= IPCID_TO_IX(semid
); /* Convert back to zero origin */
1007 if (semid
< 0 || semid
>= seminfo
.semmni
)
1010 /* Allocate memory for sem_ops */
1011 if (nsops
<= SMALL_SOPS
)
1013 else if (nsops
<= (unsigned long) seminfo
.semopm
)
1014 sops
= (struct sembuf
*) sys_malloc(nsops
* sizeof(*sops
), M_SEM
, M_WAITOK
);
1016 DPRINTF(("too many sops (max=%d, nsops=%d)\n", seminfo
.semopm
,
1020 if ((error
= copyin(uap
->sops
, sops
, nsops
* sizeof(sops
[0]))) != 0) {
1021 DPRINTF(("error = %d from copyin(%08x, %08x, %d)\n", error
,
1022 uap
->sops
, sops
, nsops
* sizeof(sops
[0])));
1023 if (sops
!= small_sops
)
1024 sys_free(sops
, M_SEM
);
1028 semaptr
= &sema
[semid
];
1029 sema_mtxp
= &sema_mtx
[semid
];
1030 mtx_lock(sema_mtxp
);
1031 if ((semaptr
->sem_perm
.mode
& SEM_ALLOC
) == 0) {
1035 if (semaptr
->sem_perm
.seq
!= IPCID_TO_SEQ(uap
->semid
)) {
1040 * Initial pass thru sops to see what permissions are needed.
1041 * Also perform any checks that don't need repeating on each
1042 * attempt to satisfy the request vector.
1044 j
= 0; /* permission needed */
1046 for (i
= 0; i
< nsops
; i
++) {
1048 if (sopptr
->sem_num
>= semaptr
->sem_nsems
) {
1052 if (sopptr
->sem_flg
& SEM_UNDO
&& sopptr
->sem_op
!= 0)
1054 j
|= (sopptr
->sem_op
== 0) ? SEM_R
: SEM_A
;
1057 if ((error
= ipcperm(td
, &semaptr
->sem_perm
, j
))) {
1058 DPRINTF(("error = %d from ipaccess\n", error
));
1063 * Loop trying to satisfy the vector of requests.
1064 * If we reach a point where we must wait, any requests already
1065 * performed are rolled back and we go to sleep until some other
1066 * process wakes us up. At this point, we start all over again.
1068 * This ensures that from the perspective of other tasks, a set
1069 * of requests is atomic (never partially satisfied).
1073 error
= 0; /* error return if necessary */
1075 for (i
= 0; i
< nsops
; i
++) {
1077 semptr
= &semaptr
->sem_base
[sopptr
->sem_num
];
1080 "semop: semaptr=%x, sem_base=%x, "
1081 "semptr=%x, sem[%d]=%d : op=%d, flag=%s\n",
1082 semaptr
, semaptr
->sem_base
, semptr
,
1083 sopptr
->sem_num
, semptr
->semval
, sopptr
->sem_op
,
1084 (sopptr
->sem_flg
& IPC_NOWAIT
) ?
1085 "nowait" : "wait"));
1087 if (sopptr
->sem_op
< 0) {
1088 if (semptr
->semval
+ sopptr
->sem_op
< 0) {
1089 DPRINTF(("semop: can't do it now\n"));
1092 semptr
->semval
+= sopptr
->sem_op
;
1093 if (semptr
->semval
== 0 &&
1094 semptr
->semzcnt
> 0)
1097 } else if (sopptr
->sem_op
== 0) {
1098 if (semptr
->semval
!= 0) {
1099 DPRINTF(("semop: not zero now\n"));
1102 } else if (semptr
->semval
+ sopptr
->sem_op
>
1107 if (semptr
->semncnt
> 0)
1109 semptr
->semval
+= sopptr
->sem_op
;
1114 * Did we get through the entire vector?
1120 * No ... rollback anything that we've already done
1122 DPRINTF(("semop: rollback 0 through %d\n", i
-1));
1123 for (j
= 0; j
< i
; j
++)
1124 semaptr
->sem_base
[sops
[j
].sem_num
].semval
-=
1127 /* If we detected an error, return it */
1132 * If the request that we couldn't satisfy has the
1133 * NOWAIT flag set then return with EAGAIN.
1135 if (sopptr
->sem_flg
& IPC_NOWAIT
) {
1140 if (sopptr
->sem_op
== 0)
1145 DPRINTF(("semop: good night!\n"));
1146 error
= msleep(semaptr
, sema_mtxp
, (PZERO
- 4) | PCATCH
,
1148 DPRINTF(("semop: good morning (error=%d)!\n", error
));
1149 /* return code is checked below, after sem[nz]cnt-- */
1152 * Make sure that the semaphore still exists
1154 if ((semaptr
->sem_perm
.mode
& SEM_ALLOC
) == 0 ||
1155 semaptr
->sem_perm
.seq
!= IPCID_TO_SEQ(uap
->semid
)) {
1161 * The semaphore is still alive. Readjust the count of
1162 * waiting processes.
1164 if (sopptr
->sem_op
== 0)
1170 * Is it really morning, or was our sleep interrupted?
1171 * (Delayed check of msleep() return code because we
1172 * need to decrement sem[nz]cnt either way.)
1177 #endif /* __CYGWIN__ */
1181 DPRINTF(("semop: good morning!\n"));
1186 * Process any SEM_UNDO requests.
1191 for (i
= 0; i
< nsops
; i
++) {
1193 * We only need to deal with SEM_UNDO's for non-zero
1198 if ((sops
[i
].sem_flg
& SEM_UNDO
) == 0)
1200 adjval
= sops
[i
].sem_op
;
1203 error
= semundo_adjust(td
, &suptr
, semid
,
1204 sops
[i
].sem_num
, -adjval
);
1209 * Oh-Oh! We ran out of either sem_undo's or undo's.
1210 * Rollback the adjustments to this point and then
1211 * rollback the semaphore ups and down so we can return
1212 * with an error with all structures restored. We
1213 * rollback the undo's in the exact reverse order that
1214 * we applied them. This guarantees that we won't run
1215 * out of space as we roll things back out.
1217 for (j
= 0; j
< i
; j
++) {
1219 if ((sops
[k
].sem_flg
& SEM_UNDO
) == 0)
1221 adjval
= sops
[k
].sem_op
;
1224 if (semundo_adjust(td
, &suptr
, semid
,
1225 sops
[k
].sem_num
, adjval
) != 0)
1226 panic("semop - can't undo undos");
1229 for (j
= 0; j
< nsops
; j
++)
1230 semaptr
->sem_base
[sops
[j
].sem_num
].semval
-=
1233 DPRINTF(("error = %d from semundo_adjust\n", error
));
1236 } /* loop through the sops */
1238 } /* if (do_undos) */
1240 /* We're definitely done - set the sempid's and time */
1241 for (i
= 0; i
< nsops
; i
++) {
1243 semptr
= &semaptr
->sem_base
[sopptr
->sem_num
];
1244 semptr
->sempid
= td
->td_proc
->p_pid
;
1246 semaptr
->sem_otime
= time (NULL
);
1249 * Do a wakeup if any semaphore was up'd whilst something was
1253 DPRINTF(("semop: doing wakeup\n"));
1255 DPRINTF(("semop: back from wakeup\n"));
1257 DPRINTF(("semop: done\n"));
1258 td
->td_retval
[0] = 0;
1260 mtx_unlock(sema_mtxp
);
1261 if (sops
!= small_sops
)
1262 sys_free(sops
, M_SEM
);
1267 * Go through the undo structures for this process and apply the adjustments to
1271 semexit_myhook(void *arg
, struct proc
*p
)
1273 struct sem_undo
*suptr
;
1274 struct sem_undo
**supptr
;
1277 * Go through the chain of undo vectors looking for one
1278 * associated with this process.
1281 SLIST_FOREACH_PREVPTR(suptr
, supptr
, &semu_list
, un_next
) {
1283 if (suptr
->un_proc
== p
->winpid
)
1285 if (suptr
->un_proc
== p
)
1293 if (suptr
== NULL
) {
1299 DPRINTF(("proc @%u(%u) has undo structure with %d entries\n",
1300 p
->cygpid
, p
->winpid
, suptr
->un_cnt
));
1302 DPRINTF(("proc @%08x has undo structure with %d entries\n", p
,
1307 * If there are any active undo elements then process them.
1309 if (suptr
->un_cnt
> 0) {
1312 for (ix
= 0; ix
< suptr
->un_cnt
; ix
++) {
1313 int semid
= suptr
->un_ent
[ix
].un_id
;
1314 int semnum
= suptr
->un_ent
[ix
].un_num
;
1315 int adjval
= suptr
->un_ent
[ix
].un_adjval
;
1316 struct semid_ds
*semaptr
;
1317 struct mtx
*sema_mtxp
;
1319 semaptr
= &sema
[semid
];
1320 sema_mtxp
= &sema_mtx
[semid
];
1322 _mtx_lock(sema_mtxp
, p
->winpid
, __FILE__
, __LINE__
);
1324 mtx_lock(sema_mtxp
);
1327 if ((semaptr
->sem_perm
.mode
& SEM_ALLOC
) == 0)
1328 panic("semexit - semid not allocated");
1329 if (semnum
>= semaptr
->sem_nsems
)
1330 panic("semexit - semnum out of range");
1334 "semexit: %u id=%d num=%d(adj=%d) ; sem=%d\n",
1336 "semexit: %08x id=%d num=%d(adj=%d) ; sem=%d\n",
1338 suptr
->un_proc
, suptr
->un_ent
[ix
].un_id
,
1339 suptr
->un_ent
[ix
].un_num
,
1340 suptr
->un_ent
[ix
].un_adjval
,
1341 semaptr
->sem_base
[semnum
].semval
));
1344 if (semaptr
->sem_base
[semnum
].semval
< -adjval
)
1345 semaptr
->sem_base
[semnum
].semval
= 0;
1347 semaptr
->sem_base
[semnum
].semval
+=
1350 semaptr
->sem_base
[semnum
].semval
+= adjval
;
1353 DPRINTF(("semexit: back from wakeup\n"));
1354 _mtx_unlock(sema_mtxp
, __FILE__
, __LINE__
);
1362 * Deallocate the undo vector.
1364 DPRINTF(("removing vector (%u)\n", suptr
->un_proc
));
1368 suptr
->un_proc
= NULL
;
1370 *supptr
= SLIST_NEXT(suptr
, un_next
);
1378 sysctl_sema(SYSCTL_HANDLER_ARGS
)
1381 return (SYSCTL_OUT(req
, sema
,
1382 sizeof(struct semid_ds
) * seminfo
.semmni
));
1384 #endif /* __CYGWIN__ */
1385 #endif /* __OUTSIDE_CYGWIN__ */