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__
16 #include <sys/cygwin.h>
17 #include <sys/cdefs.h>
19 #define __FBSDID(s) const char version[] = (s)
21 __FBSDID("$FreeBSD: /repoman/r/ncvs/src/sys/kern/sysv_sem.c,v 1.70 2004/05/30 20:34:58 phk Exp $");
22 /* CV, 2006-01-09: Inspected upstream up to version 1.78. */
25 #define __BSD_VISIBLE 1
26 #include <sys/types.h>
29 #include <sys/param.h>
30 #include <sys/sysproto.h>
33 #include <sys/queue.h>
37 #include "cygserver.h"
39 #include "cygserver_ipc.h"
40 #include <sys/smallprint.h>
43 #define __semctl semctl
44 #define __semctl_args semctl_args
46 #endif /* __CYGWIN__ */
49 #define DPRINTF(a) debug_printf a
54 static int semvalid(int semid
, struct semid_ds
*semaptr
);
56 static struct sem_undo
*semu_alloc(struct thread
*td
);
57 static int semundo_adjust(struct thread
*td
, struct sem_undo
**supptr
,
58 int semid
, int semnum
, int adjval
);
59 static void semundo_clear(int semid
, int semnum
, struct thread
*td
);
61 #ifndef _SYS_SYSPROTO_H_
63 int __semctl(struct thread
*td
, struct __semctl_args
*uap
);
65 int semget(struct thread
*td
, struct semget_args
*uap
);
67 int semop(struct thread
*td
, struct semop_args
*uap
);
71 /* XXX casting to (sy_call_t *) is bogus, as usual. */
72 static sy_call_t
*semcalls
[] = {
73 (sy_call_t
*)__semctl
, (sy_call_t
*)semget
,
78 static struct mtx sem_mtx
; /* semaphore global lock */
79 static int semtots
= 0;
80 static int semtot
= 0;
81 static struct semid_ds
*sema
; /* semaphore id pool */
82 static struct mtx
*sema_mtx
; /* semaphore id pool mutexes*/
83 static struct sem
*sem
; /* semaphore pool */
84 static SLIST_HEAD(, sem_undo
) semu_list
; /* list of active undo structures */
85 static int *semu
; /* undo structure pool */
87 static eventhandler_tag semexit_tag
;
88 #endif /* __CYGWIN__ */
90 #define SEMUNDO_MTX sem_mtx
91 #define SEMUNDO_LOCK() mtx_lock(&SEMUNDO_MTX);
92 #define SEMUNDO_HOOKLOCK() _mtx_lock(&SEMUNDO_MTX, p->winpid, __FILE__, __LINE__);
93 #define SEMUNDO_UNLOCK() mtx_unlock(&SEMUNDO_MTX);
94 #define SEMUNDO_LOCKASSERT(how,pid) mtx_assert(&SEMUNDO_MTX, (how), (pid));
97 u_short semval
; /* semaphore value */
98 pid_t sempid
; /* pid of last operation */
99 u_short semncnt
; /* # awaiting semval > cval */
100 u_short semzcnt
; /* # awaiting semval = 0 */
104 * Undo structure (one per process)
107 short un_adjval
; /* adjust on exit values */
108 short un_num
; /* semaphore # */
109 int un_id
; /* semid */
110 } un_ent
[1]; /* undo entries */
113 SLIST_ENTRY(sem_undo
) un_next
; /* ptr to next active undo structure */
115 DWORD un_proc
; /* owner of this structure */
117 struct proc
*un_proc
; /* owner of this structure */
119 short un_cnt
; /* # of active entries */
120 struct undo un_ent
[1]; /* undo entries */
124 * Configuration parameters
127 #define SEMMNI 10 /* # of semaphore identifiers */
130 #define SEMMNS 60 /* # of semaphores in system */
133 #define SEMUME 10 /* max # of undo entries per process */
136 #define SEMMNU 30 /* # of undo structures in system */
139 /* shouldn't need tuning */
141 #define SEMMAP 30 /* # of entries in semaphore map */
144 #define SEMMSL SEMMNS /* max # of semaphores per id */
147 #define SEMOPM 100 /* max # of operations per semop call */
151 #define SEMVMX 32767 /* semaphore maximum value */
154 #define SEMAEM 16384 /* adjust on exit max value */
158 /* gcc 3.4 defines a new offsetof which is different for C++. Since this
159 file is just a derived plain-C file, we need to revert to the plain-C
160 definition of offsetof. */
164 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
165 #endif /* __CYGWIN__ */
167 * Due to the way semaphore memory is allocated, we have to ensure that
168 * SEMUSZ is properly aligned.
171 #define SEM_ALIGN(bytes) (((bytes) + (sizeof(long) - 1)) & ~(sizeof(long) - 1))
173 /* actual size of an undo structure */
174 #define SEMUSZ SEM_ALIGN(offsetof(struct sem_undo, un_ent[SEMUME]))
177 * Macro to find a particular sem_undo vector
180 ((struct sem_undo *)(((intptr_t)semu)+ix * seminfo.semusz))
183 * semaphore info struct
185 struct seminfo seminfo
= {
186 SEMMNI
, /* # of semaphore identifiers */
187 SEMMNS
, /* # of semaphores in system */
188 SEMMSL
, /* max # of semaphores per id */
189 SEMOPM
, /* max # of operations per semop call */
190 SEMMNU
, /* # of undo structures in system */
191 SEMUME
, /* max # of undo entries per process */
192 SEMVMX
, /* semaphore maximum value */
193 SEMAEM
, /* adjust on exit max value */
194 SEMMAP
, /* # of entries in semaphore map */
195 SEMUSZ
/* size in bytes of undo structure */
199 SYSCTL_DECL(_kern_ipc
);
200 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semmap
, CTLFLAG_RW
, &seminfo
.semmap
, 0, "");
201 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semmni
, CTLFLAG_RDTUN
, &seminfo
.semmni
, 0, "");
202 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semmns
, CTLFLAG_RDTUN
, &seminfo
.semmns
, 0, "");
203 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semmnu
, CTLFLAG_RDTUN
, &seminfo
.semmnu
, 0, "");
204 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semmsl
, CTLFLAG_RW
, &seminfo
.semmsl
, 0, "");
205 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semopm
, CTLFLAG_RDTUN
, &seminfo
.semopm
, 0, "");
206 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semume
, CTLFLAG_RDTUN
, &seminfo
.semume
, 0, "");
207 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semusz
, CTLFLAG_RDTUN
, &seminfo
.semusz
, 0, "");
208 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semvmx
, CTLFLAG_RW
, &seminfo
.semvmx
, 0, "");
209 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semaem
, CTLFLAG_RW
, &seminfo
.semaem
, 0, "");
210 SYSCTL_PROC(_kern_ipc
, OID_AUTO
, sema
, CTLFLAG_RD
,
211 NULL
, 0, sysctl_sema
, "", "");
212 #endif /* __CYGWIN__ */
219 TUNABLE_INT_FETCH("kern.ipc.semmap", &seminfo
.semmap
);
220 TUNABLE_INT_FETCH("kern.ipc.semmni", &seminfo
.semmni
);
221 TUNABLE_INT_FETCH("kern.ipc.semmns", &seminfo
.semmns
);
222 TUNABLE_INT_FETCH("kern.ipc.semmnu", &seminfo
.semmnu
);
223 TUNABLE_INT_FETCH("kern.ipc.semmsl", &seminfo
.semmsl
);
224 TUNABLE_INT_FETCH("kern.ipc.semopm", &seminfo
.semopm
);
225 TUNABLE_INT_FETCH("kern.ipc.semume", &seminfo
.semume
);
226 TUNABLE_INT_FETCH("kern.ipc.semusz", &seminfo
.semusz
);
227 TUNABLE_INT_FETCH("kern.ipc.semvmx", &seminfo
.semvmx
);
228 TUNABLE_INT_FETCH("kern.ipc.semaem", &seminfo
.semaem
);
231 /* It's too dangerous a setting to leave it alone.
232 Keep that clean here. */
233 seminfo
.semusz
= SEM_ALIGN(offsetof(struct sem_undo
,
234 un_ent
[seminfo
.semume
]));
235 #endif /* __CYGWIN__ */
237 sem
= (struct sem
*) sys_malloc(sizeof(struct sem
) * seminfo
.semmns
, M_SEM
, M_WAITOK
);
238 sema
= (struct semid_ds
*) sys_malloc(sizeof(struct semid_ds
) * seminfo
.semmni
, M_SEM
,
240 sema_mtx
= (struct mtx
*) sys_malloc(sizeof(struct mtx
) * seminfo
.semmni
, M_SEM
,
242 semu
= (int *) sys_malloc(seminfo
.semmnu
* seminfo
.semusz
, M_SEM
, M_WAITOK
);
244 for (i
= 0; i
< seminfo
.semmni
; i
++) {
245 sema
[i
].sem_base
= 0;
246 sema
[i
].sem_perm
.mode
= 0;
247 sema
[i
].sem_perm
.seq
= 0;
249 for (i
= 0; i
< seminfo
.semmni
; i
++)
251 char *buf
= (char *) sys_malloc(16, M_SEM
, M_WAITOK
);
252 snprintf(buf
, 16, "semid[%d]", (short) i
);
253 mtx_init(&sema_mtx
[i
], buf
, NULL
, MTX_DEF
);
255 for (i
= 0; i
< seminfo
.semmnu
; i
++) {
256 struct sem_undo
*suptr
= SEMU(i
);
260 suptr
->un_proc
= NULL
;
263 SLIST_INIT(&semu_list
);
264 mtx_init(&sem_mtx
, "sem", NULL
, MTX_DEF
);
266 semexit_tag
= EVENTHANDLER_REGISTER(process_exit
, semexit_myhook
, NULL
,
267 EVENTHANDLER_PRI_ANY
);
268 #endif /* __CYGWIN__ */
274 #ifndef __CYGWIN__ /* Would result in being unable to shutdown the
275 server gracefully. */
279 EVENTHANDLER_DEREGISTER(process_exit
, semexit_tag
);
280 #endif /* __CYGWIN__ */
281 sys_free(sem
, M_SEM
);
282 sys_free(sema
, M_SEM
);
283 sys_free(semu
, M_SEM
);
284 for (int i
= 0; i
< seminfo
.semmni
; i
++) {
285 sys_free((void *) sema_mtx
[i
].name
, M_SEM
);
286 mtx_destroy(&sema_mtx
[i
]);
288 mtx_destroy(&sem_mtx
);
294 sysvsem_modload(struct module
*module
, int cmd
, void *arg
)
314 static moduledata_t sysvsem_mod
= {
320 SYSCALL_MODULE_HELPER(semsys
);
321 SYSCALL_MODULE_HELPER(__semctl
);
322 SYSCALL_MODULE_HELPER(semget
);
323 SYSCALL_MODULE_HELPER(semop
);
325 DECLARE_MODULE(sysvsem
, sysvsem_mod
,
326 SI_SUB_SYSV_SEM
, SI_ORDER_FIRST
);
327 MODULE_VERSION(sysvsem
, 1);
330 * Entry point for all SEM calls
337 /* XXX actually varargs. */
338 struct semsys_args
/* {
348 if (!jail_sysvipc_allowed
&& jailed(td
->td_ucred
))
350 if (uap
->which
< 0 ||
351 uap
->which
>= sizeof(semcalls
)/sizeof(semcalls
[0]))
353 error
= (*semcalls
[uap
->which
])(td
, &uap
->a2
);
356 #endif /* __CYGWIN__ */
359 * Allocate a new sem_undo structure for a process
360 * (returns ptr to structure or NULL if no more room)
363 static struct sem_undo
*
364 semu_alloc(struct thread
*td
)
367 struct sem_undo
*suptr
;
368 struct sem_undo
**supptr
;
371 SEMUNDO_LOCKASSERT(MA_OWNED
, td
->td_proc
->winpid
);
373 * Try twice to allocate something.
374 * (we'll purge an empty structure after the first pass so
375 * two passes are always enough)
378 for (attempt
= 0; attempt
< 2; attempt
++) {
380 * Look for a free structure.
381 * Fill it in and return it if we find one.
384 for (i
= 0; i
< seminfo
.semmnu
; i
++) {
387 if (suptr
->un_proc
== 0) {
389 if (suptr
->un_proc
== NULL
) {
391 SLIST_INSERT_HEAD(&semu_list
, suptr
, un_next
);
393 suptr
->un_proc
= td
->td_proc
->winpid
;
399 * We didn't find a free one, if this is the first attempt
400 * then try to free a structure.
404 /* All the structures are in use - try to free one */
405 int did_something
= 0;
407 SLIST_FOREACH_PREVPTR(suptr
, supptr
, &semu_list
,
409 if (suptr
->un_cnt
== 0) {
413 suptr
->un_proc
= NULL
;
416 *supptr
= SLIST_NEXT(suptr
, un_next
);
421 /* If we didn't free anything then just give-up */
426 * The second pass failed even though we freed
427 * something after the first pass!
428 * This is IMPOSSIBLE!
430 panic("semu_alloc - second attempt failed");
437 * Adjust a particular entry for a particular proc
441 semundo_adjust(struct thread
*td
, struct sem_undo
**supptr
, int semid
,
442 int semnum
, int adjval
)
444 struct proc
*p
= td
->td_proc
;
445 struct sem_undo
*suptr
;
449 SEMUNDO_LOCKASSERT(MA_OWNED
, td
->td_proc
->winpid
);
450 /* Look for and remember the sem_undo if the caller doesn't provide
455 SLIST_FOREACH(suptr
, &semu_list
, un_next
) {
457 if (suptr
->un_proc
== p
->winpid
) {
459 if (suptr
->un_proc
== p
) {
468 suptr
= semu_alloc(td
);
476 * Look for the requested entry and adjust it (delete if adjval becomes
479 sunptr
= &suptr
->un_ent
[0];
480 for (i
= 0; i
< suptr
->un_cnt
; i
++, sunptr
++) {
481 if (sunptr
->un_id
!= semid
|| sunptr
->un_num
!= semnum
)
484 adjval
+= sunptr
->un_adjval
;
485 if (adjval
> seminfo
.semaem
|| adjval
< -seminfo
.semaem
)
488 sunptr
->un_adjval
= adjval
;
489 if (sunptr
->un_adjval
== 0) {
491 if (i
< suptr
->un_cnt
)
493 suptr
->un_ent
[suptr
->un_cnt
];
498 /* Didn't find the right entry - create it */
501 if (adjval
> seminfo
.semaem
|| adjval
< -seminfo
.semaem
)
503 if (suptr
->un_cnt
!= seminfo
.semume
) {
504 sunptr
= &suptr
->un_ent
[suptr
->un_cnt
];
506 sunptr
->un_adjval
= adjval
;
507 sunptr
->un_id
= semid
; sunptr
->un_num
= semnum
;
514 semundo_clear(int semid
, int semnum
, struct thread
*td
)
516 struct sem_undo
*suptr
;
518 SEMUNDO_LOCKASSERT(MA_OWNED
, td
->td_proc
->winpid
);
519 SLIST_FOREACH(suptr
, &semu_list
, un_next
) {
520 struct undo
*sunptr
= &suptr
->un_ent
[0];
523 while (i
< suptr
->un_cnt
) {
524 if (sunptr
->un_id
== semid
) {
525 if (semnum
== -1 || sunptr
->un_num
== semnum
) {
527 if (i
< suptr
->un_cnt
) {
529 suptr
->un_ent
[suptr
->un_cnt
];
542 semvalid(int semid
, struct semid_ds
*semaptr
)
545 return ((semaptr
->sem_perm
.mode
& SEM_ALLOC
) == 0 ||
546 semaptr
->sem_perm
.seq
!= IPCID_TO_SEQ(semid
) ? EINVAL
: 0);
550 * Note that the user-mode half of this passes a union, not a pointer
552 #ifndef _SYS_SYSPROTO_H_
553 struct __semctl_args
{
565 __semctl(struct thread
*td
, struct __semctl_args
*uap
)
567 int semid
= uap
->semid
;
568 int semnum
= uap
->semnum
;
571 union semun
*arg
= uap
->arg
;
572 union semun real_arg
;
574 struct ucred
*cred
= td
->td_ucred
;
577 struct semid_ds sbuf
;
578 struct semid_ds
*semaptr
;
579 struct mtx
*sema_mtxp
;
580 u_short usval
, count
;
582 DPRINTF(("call to semctl(%d, %d, %d, 0x%x)\n",
583 semid
, semnum
, cmd
, arg
));
584 if (!jail_sysvipc_allowed
&& jailed(td
->td_ucred
))
592 if ((error
= copyin(arg
, &real_arg
, sizeof(real_arg
))) != 0)
595 error
= copyout(&seminfo
, real_arg
.buf
,
596 sizeof(struct seminfo
));
597 td
->td_retval
[0] = error
? -1 : 0;
600 if (semid
> seminfo
.semmni
)
601 semid
= seminfo
.semmni
;
602 error
= copyout(sema
, real_arg
.buf
,
603 semid
* sizeof(struct semid_ds
));
604 td
->td_retval
[0] = error
? -1 : 0;
607 if (!(error
= copyin(arg
, &real_arg
, sizeof(real_arg
)))) {
608 struct sem_info sem_info
;
609 sem_info
.sem_ids
= semtots
;
610 sem_info
.sem_num
= semtot
;
611 error
= copyout(&sem_info
, real_arg
.buf
,
612 sizeof(struct sem_info
));
614 td
->td_retval
[0] = error
? -1 : 0;
617 #endif /* __CYGWIN__ */
619 if (semid
< 0 || semid
>= seminfo
.semmni
)
621 if ((error
= copyin(arg
, &real_arg
, sizeof(real_arg
))) != 0)
623 semaptr
= &sema
[semid
];
624 sema_mtxp
= &sema_mtx
[semid
];
626 if ((semaptr
->sem_perm
.mode
& SEM_ALLOC
) == 0) {
630 if ((error
= ipcperm(td
, &semaptr
->sem_perm
, IPC_R
)))
632 mtx_unlock(sema_mtxp
);
633 error
= copyout(semaptr
, real_arg
.buf
, sizeof(struct semid_ds
));
634 rval
= IXSEQ_TO_IPCID(semid
,semaptr
->sem_perm
);
636 td
->td_retval
[0] = rval
;
640 semid
= IPCID_TO_IX(semid
);
641 if (semid
< 0 || semid
>= seminfo
.semmni
)
644 semaptr
= &sema
[semid
];
645 sema_mtxp
= &sema_mtx
[semid
];
653 if ((error
= semvalid(uap
->semid
, semaptr
)) != 0)
655 if ((error
= ipcperm(td
, &semaptr
->sem_perm
, IPC_M
)))
658 semaptr
->sem_perm
.cuid
= td
->ipcblk
->uid
;
659 semaptr
->sem_perm
.uid
= td
->ipcblk
->uid
;
661 semaptr
->sem_perm
.cuid
= cred
->cr_uid
;
662 semaptr
->sem_perm
.uid
= cred
->cr_uid
;
664 semtot
-= semaptr
->sem_nsems
;
666 for (i
= semaptr
->sem_base
- sem
; i
< semtot
; i
++)
667 sem
[i
] = sem
[i
+ semaptr
->sem_nsems
];
668 for (i
= 0; i
< seminfo
.semmni
; i
++) {
669 if ((sema
[i
].sem_perm
.mode
& SEM_ALLOC
) &&
670 sema
[i
].sem_base
> semaptr
->sem_base
)
671 sema
[i
].sem_base
-= semaptr
->sem_nsems
;
673 semaptr
->sem_perm
.mode
= 0;
675 semundo_clear(semid
, -1, td
);
681 if ((error
= copyin(arg
, &real_arg
, sizeof(real_arg
))) != 0)
683 if ((error
= copyin(real_arg
.buf
, &sbuf
, sizeof(sbuf
))) != 0)
686 if ((error
= semvalid(uap
->semid
, semaptr
)) != 0)
688 if ((error
= ipcperm(td
, &semaptr
->sem_perm
, IPC_M
)))
690 semaptr
->sem_perm
.uid
= sbuf
.sem_perm
.uid
;
691 semaptr
->sem_perm
.gid
= sbuf
.sem_perm
.gid
;
692 semaptr
->sem_perm
.mode
= (semaptr
->sem_perm
.mode
& ~0777) |
693 (sbuf
.sem_perm
.mode
& 0777);
694 semaptr
->sem_ctime
= time (NULL
);
698 if ((error
= copyin(arg
, &real_arg
, sizeof(real_arg
))) != 0)
701 if ((error
= semvalid(uap
->semid
, semaptr
)) != 0)
703 if ((error
= ipcperm(td
, &semaptr
->sem_perm
, IPC_R
)))
706 mtx_unlock(sema_mtxp
);
707 error
= copyout(semaptr
, real_arg
.buf
,
708 sizeof(struct semid_ds
));
713 if ((error
= semvalid(uap
->semid
, semaptr
)) != 0)
715 if ((error
= ipcperm(td
, &semaptr
->sem_perm
, IPC_R
)))
717 if (semnum
< 0 || semnum
>= semaptr
->sem_nsems
) {
721 rval
= semaptr
->sem_base
[semnum
].semncnt
;
726 if ((error
= semvalid(uap
->semid
, semaptr
)) != 0)
728 if ((error
= ipcperm(td
, &semaptr
->sem_perm
, IPC_R
)))
730 if (semnum
< 0 || semnum
>= semaptr
->sem_nsems
) {
734 rval
= semaptr
->sem_base
[semnum
].sempid
;
739 if ((error
= semvalid(uap
->semid
, semaptr
)) != 0)
741 if ((error
= ipcperm(td
, &semaptr
->sem_perm
, IPC_R
)))
743 if (semnum
< 0 || semnum
>= semaptr
->sem_nsems
) {
747 rval
= semaptr
->sem_base
[semnum
].semval
;
751 if ((error
= copyin(arg
, &real_arg
, sizeof(real_arg
))) != 0)
753 array
= (u_short
*) sys_malloc(sizeof(*array
) * semaptr
->sem_nsems
, M_TEMP
,
756 if ((error
= semvalid(uap
->semid
, semaptr
)) != 0)
758 if ((error
= ipcperm(td
, &semaptr
->sem_perm
, IPC_R
)))
760 for (i
= 0; i
< semaptr
->sem_nsems
; i
++)
761 array
[i
] = semaptr
->sem_base
[i
].semval
;
762 mtx_unlock(sema_mtxp
);
763 error
= copyout(array
, real_arg
.array
,
764 i
* sizeof(real_arg
.array
[0]));
769 if ((error
= semvalid(uap
->semid
, semaptr
)) != 0)
771 if ((error
= ipcperm(td
, &semaptr
->sem_perm
, IPC_R
)))
773 if (semnum
< 0 || semnum
>= semaptr
->sem_nsems
) {
777 rval
= semaptr
->sem_base
[semnum
].semzcnt
;
781 if ((error
= copyin(arg
, &real_arg
, sizeof(real_arg
))) != 0)
784 if ((error
= semvalid(uap
->semid
, semaptr
)) != 0)
786 if ((error
= ipcperm(td
, &semaptr
->sem_perm
, IPC_W
)))
788 if (semnum
< 0 || semnum
>= semaptr
->sem_nsems
) {
792 if (real_arg
.val
< 0 || real_arg
.val
> seminfo
.semvmx
) {
796 semaptr
->sem_base
[semnum
].semval
= real_arg
.val
;
798 semundo_clear(semid
, semnum
, td
);
806 if ((error
= semvalid(uap
->semid
, semaptr
)) != 0)
808 count
= semaptr
->sem_nsems
;
809 mtx_unlock(sema_mtxp
);
810 if ((error
= copyin(arg
, &real_arg
, sizeof(real_arg
))) != 0)
812 array
= (u_short
*) sys_malloc(sizeof(*array
) * count
, M_TEMP
, M_WAITOK
);
813 error
= copyin(real_arg
.array
, array
, count
* sizeof(*array
));
817 if ((error
= semvalid(uap
->semid
, semaptr
)) != 0)
819 /* we could have raced? */
820 if (count
!= semaptr
->sem_nsems
) {
821 sys_free(array
, M_TEMP
);
825 if ((error
= ipcperm(td
, &semaptr
->sem_perm
, IPC_W
)))
827 for (i
= 0; i
< semaptr
->sem_nsems
; i
++) {
829 if (usval
> seminfo
.semvmx
) {
833 semaptr
->sem_base
[i
].semval
= usval
;
836 semundo_clear(semid
, -1, td
);
847 td
->td_retval
[0] = rval
;
849 if (mtx_owned(sema_mtxp
, td
->td_proc
->winpid
))
850 mtx_unlock(sema_mtxp
);
852 sys_free(array
, M_TEMP
);
856 #ifndef _SYS_SYSPROTO_H_
868 semget(struct thread
*td
, struct semget_args
*uap
)
870 int semid
, error
= 0;
871 key_t key
= uap
->key
;
872 int nsems
= uap
->nsems
;
873 int semflg
= uap
->semflg
;
875 struct ucred
*cred
= td
->td_ucred
;
878 DPRINTF(("semget(0x%llx, %d, 0%o)\n", key
, nsems
, semflg
));
879 if (!jail_sysvipc_allowed
&& jailed(td
->td_ucred
))
883 if (key
!= IPC_PRIVATE
) {
884 for (semid
= 0; semid
< seminfo
.semmni
; semid
++) {
885 if ((sema
[semid
].sem_perm
.mode
& SEM_ALLOC
) &&
886 sema
[semid
].sem_perm
.key
== key
)
889 if (semid
< seminfo
.semmni
) {
890 DPRINTF(("found public key\n"));
891 if ((error
= ipcperm(td
, &sema
[semid
].sem_perm
,
895 if (nsems
> 0 && sema
[semid
].sem_nsems
< nsems
) {
896 DPRINTF(("too small\n"));
900 if ((semflg
& IPC_CREAT
) && (semflg
& IPC_EXCL
)) {
901 DPRINTF(("not exclusive\n"));
909 DPRINTF(("need to allocate the semid_ds\n"));
910 if (key
== IPC_PRIVATE
|| (semflg
& IPC_CREAT
)) {
911 if (nsems
<= 0 || nsems
> seminfo
.semmsl
) {
912 DPRINTF(("nsems out of range (0<%d<=%d)\n", nsems
,
917 if (nsems
> seminfo
.semmns
- semtot
) {
919 "not enough semaphores left (need %d, got %d)\n",
920 nsems
, seminfo
.semmns
- semtot
));
924 for (semid
= 0; semid
< seminfo
.semmni
; semid
++) {
925 if ((sema
[semid
].sem_perm
.mode
& SEM_ALLOC
) == 0)
928 if (semid
== seminfo
.semmni
) {
929 DPRINTF(("no more semid_ds's available\n"));
933 DPRINTF(("semid %d is available\n", semid
));
934 sema
[semid
].sem_perm
.key
= key
;
936 sema
[semid
].sem_perm
.cuid
= td
->ipcblk
->uid
;
937 sema
[semid
].sem_perm
.uid
= td
->ipcblk
->uid
;
938 sema
[semid
].sem_perm
.cgid
= td
->ipcblk
->gid
;
939 sema
[semid
].sem_perm
.gid
= td
->ipcblk
->gid
;
941 sema
[semid
].sem_perm
.cuid
= cred
->cr_uid
;
942 sema
[semid
].sem_perm
.uid
= cred
->cr_uid
;
943 sema
[semid
].sem_perm
.cgid
= cred
->cr_gid
;
944 sema
[semid
].sem_perm
.gid
= cred
->cr_gid
;
946 sema
[semid
].sem_perm
.mode
= (semflg
& 0777) | SEM_ALLOC
;
947 sema
[semid
].sem_perm
.seq
=
948 (sema
[semid
].sem_perm
.seq
+ 1) & 0x7fff;
949 sema
[semid
].sem_nsems
= nsems
;
950 sema
[semid
].sem_otime
= 0;
951 sema
[semid
].sem_ctime
= time (NULL
);
952 sema
[semid
].sem_base
= &sem
[semtot
];
955 bzero(sema
[semid
].sem_base
,
956 sizeof(sema
[semid
].sem_base
[0])*nsems
);
957 DPRINTF(("sembase = 0x%x, next = 0x%x\n", sema
[semid
].sem_base
,
960 DPRINTF(("didn't find it and wasn't asked to create it\n"));
966 td
->td_retval
[0] = IXSEQ_TO_IPCID(semid
, sema
[semid
].sem_perm
);
970 ipcexit_creat_hookthread (td
);
976 #ifndef _SYS_SYSPROTO_H_
988 semop(struct thread
*td
, struct semop_args
*uap
)
991 struct sembuf small_sops
[SMALL_SOPS
];
992 int semid
= uap
->semid
;
993 size_t nsops
= uap
->nsops
;
995 struct semid_ds
*semaptr
;
996 struct sembuf
*sopptr
= 0;
997 struct sem
*semptr
= 0;
998 struct sem_undo
*suptr
;
999 struct mtx
*sema_mtxp
;
1002 int do_wakeup
, do_undos
;
1004 DPRINTF(("call to semop(%d, 0x%x, %u)\n", semid
, uap
->sops
, nsops
));
1006 if (!jail_sysvipc_allowed
&& jailed(td
->td_ucred
))
1009 semid
= IPCID_TO_IX(semid
); /* Convert back to zero origin */
1011 if (semid
< 0 || semid
>= seminfo
.semmni
)
1014 /* Allocate memory for sem_ops */
1015 if (nsops
<= SMALL_SOPS
)
1017 else if (nsops
<= (unsigned long) seminfo
.semopm
)
1018 sops
= (struct sembuf
*) sys_malloc(nsops
* sizeof(*sops
), M_SEM
, M_WAITOK
);
1020 DPRINTF(("too many sops (max=%d, nsops=%d)\n", seminfo
.semopm
,
1024 if ((error
= copyin(uap
->sops
, sops
, nsops
* sizeof(sops
[0]))) != 0) {
1025 DPRINTF(("error = %d from copyin(%08x, %08x, %d)\n", error
,
1026 uap
->sops
, sops
, nsops
* sizeof(sops
[0])));
1027 if (sops
!= small_sops
)
1028 sys_free(sops
, M_SEM
);
1032 semaptr
= &sema
[semid
];
1033 sema_mtxp
= &sema_mtx
[semid
];
1034 mtx_lock(sema_mtxp
);
1035 if ((semaptr
->sem_perm
.mode
& SEM_ALLOC
) == 0) {
1039 if (semaptr
->sem_perm
.seq
!= IPCID_TO_SEQ(uap
->semid
)) {
1044 * Initial pass thru sops to see what permissions are needed.
1045 * Also perform any checks that don't need repeating on each
1046 * attempt to satisfy the request vector.
1048 j
= 0; /* permission needed */
1050 for (i
= 0; i
< nsops
; i
++) {
1052 if (sopptr
->sem_num
>= semaptr
->sem_nsems
) {
1056 if (sopptr
->sem_flg
& SEM_UNDO
&& sopptr
->sem_op
!= 0)
1058 j
|= (sopptr
->sem_op
== 0) ? SEM_R
: SEM_A
;
1061 if ((error
= ipcperm(td
, &semaptr
->sem_perm
, j
))) {
1062 DPRINTF(("error = %d from ipaccess\n", error
));
1067 * Loop trying to satisfy the vector of requests.
1068 * If we reach a point where we must wait, any requests already
1069 * performed are rolled back and we go to sleep until some other
1070 * process wakes us up. At this point, we start all over again.
1072 * This ensures that from the perspective of other tasks, a set
1073 * of requests is atomic (never partially satisfied).
1077 error
= 0; /* error return if necessary */
1079 for (i
= 0; i
< nsops
; i
++) {
1081 semptr
= &semaptr
->sem_base
[sopptr
->sem_num
];
1084 "semop: semaptr=%x, sem_base=%x, "
1085 "semptr=%x, sem[%d]=%d : op=%d, flag=%s\n",
1086 semaptr
, semaptr
->sem_base
, semptr
,
1087 sopptr
->sem_num
, semptr
->semval
, sopptr
->sem_op
,
1088 (sopptr
->sem_flg
& IPC_NOWAIT
) ?
1089 "nowait" : "wait"));
1091 if (sopptr
->sem_op
< 0) {
1092 if (semptr
->semval
+ sopptr
->sem_op
< 0) {
1093 DPRINTF(("semop: can't do it now\n"));
1096 semptr
->semval
+= sopptr
->sem_op
;
1097 if (semptr
->semval
== 0 &&
1098 semptr
->semzcnt
> 0)
1101 } else if (sopptr
->sem_op
== 0) {
1102 if (semptr
->semval
!= 0) {
1103 DPRINTF(("semop: not zero now\n"));
1106 } else if (semptr
->semval
+ sopptr
->sem_op
>
1111 if (semptr
->semncnt
> 0)
1113 semptr
->semval
+= sopptr
->sem_op
;
1118 * Did we get through the entire vector?
1124 * No ... rollback anything that we've already done
1126 DPRINTF(("semop: rollback 0 through %d\n", i
-1));
1127 for (j
= 0; j
< i
; j
++)
1128 semaptr
->sem_base
[sops
[j
].sem_num
].semval
-=
1131 /* If we detected an error, return it */
1136 * If the request that we couldn't satisfy has the
1137 * NOWAIT flag set then return with EAGAIN.
1139 if (sopptr
->sem_flg
& IPC_NOWAIT
) {
1144 if (sopptr
->sem_op
== 0)
1149 DPRINTF(("semop: good night!\n"));
1150 error
= msleep(semaptr
, sema_mtxp
, (PZERO
- 4) | PCATCH
,
1152 DPRINTF(("semop: good morning (error=%d)!\n", error
));
1153 /* return code is checked below, after sem[nz]cnt-- */
1156 * Make sure that the semaphore still exists
1158 if ((semaptr
->sem_perm
.mode
& SEM_ALLOC
) == 0 ||
1159 semaptr
->sem_perm
.seq
!= IPCID_TO_SEQ(uap
->semid
)) {
1165 * The semaphore is still alive. Readjust the count of
1166 * waiting processes.
1168 if (sopptr
->sem_op
== 0)
1174 * Is it really morning, or was our sleep interrupted?
1175 * (Delayed check of msleep() return code because we
1176 * need to decrement sem[nz]cnt either way.)
1182 #endif /* __CYGWIN__ */
1186 DPRINTF(("semop: good morning!\n"));
1191 * Process any SEM_UNDO requests.
1196 for (i
= 0; i
< nsops
; i
++) {
1198 * We only need to deal with SEM_UNDO's for non-zero
1203 if ((sops
[i
].sem_flg
& SEM_UNDO
) == 0)
1205 adjval
= sops
[i
].sem_op
;
1208 error
= semundo_adjust(td
, &suptr
, semid
,
1209 sops
[i
].sem_num
, -adjval
);
1214 * Oh-Oh! We ran out of either sem_undo's or undo's.
1215 * Rollback the adjustments to this point and then
1216 * rollback the semaphore ups and down so we can return
1217 * with an error with all structures restored. We
1218 * rollback the undo's in the exact reverse order that
1219 * we applied them. This guarantees that we won't run
1220 * out of space as we roll things back out.
1222 for (j
= 0; j
< i
; j
++) {
1224 if ((sops
[k
].sem_flg
& SEM_UNDO
) == 0)
1226 adjval
= sops
[k
].sem_op
;
1229 if (semundo_adjust(td
, &suptr
, semid
,
1230 sops
[k
].sem_num
, adjval
) != 0)
1231 panic("semop - can't undo undos");
1234 for (j
= 0; j
< nsops
; j
++)
1235 semaptr
->sem_base
[sops
[j
].sem_num
].semval
-=
1238 DPRINTF(("error = %d from semundo_adjust\n", error
));
1241 } /* loop through the sops */
1243 } /* if (do_undos) */
1245 /* We're definitely done - set the sempid's and time */
1246 for (i
= 0; i
< nsops
; i
++) {
1248 semptr
= &semaptr
->sem_base
[sopptr
->sem_num
];
1249 semptr
->sempid
= td
->td_proc
->p_pid
;
1251 semaptr
->sem_otime
= time (NULL
);
1254 * Do a wakeup if any semaphore was up'd whilst something was
1258 DPRINTF(("semop: doing wakeup\n"));
1260 DPRINTF(("semop: back from wakeup\n"));
1262 DPRINTF(("semop: done\n"));
1263 td
->td_retval
[0] = 0;
1265 mtx_unlock(sema_mtxp
);
1266 if (sops
!= small_sops
)
1267 sys_free(sops
, M_SEM
);
1272 * Go through the undo structures for this process and apply the adjustments to
1276 semexit_myhook(void *arg
, struct proc
*p
)
1278 struct sem_undo
*suptr
;
1279 struct sem_undo
**supptr
;
1282 * Go through the chain of undo vectors looking for one
1283 * associated with this process.
1286 SLIST_FOREACH_PREVPTR(suptr
, supptr
, &semu_list
, un_next
) {
1288 if (suptr
->un_proc
== p
->winpid
)
1290 if (suptr
->un_proc
== p
)
1298 if (suptr
== NULL
) {
1304 DPRINTF(("proc @%u(%u) has undo structure with %d entries\n",
1305 p
->cygpid
, p
->winpid
, suptr
->un_cnt
));
1307 DPRINTF(("proc @%08x has undo structure with %d entries\n", p
,
1312 * If there are any active undo elements then process them.
1314 if (suptr
->un_cnt
> 0) {
1317 for (ix
= 0; ix
< suptr
->un_cnt
; ix
++) {
1318 int semid
= suptr
->un_ent
[ix
].un_id
;
1319 int semnum
= suptr
->un_ent
[ix
].un_num
;
1320 int adjval
= suptr
->un_ent
[ix
].un_adjval
;
1321 struct semid_ds
*semaptr
;
1322 struct mtx
*sema_mtxp
;
1324 semaptr
= &sema
[semid
];
1325 sema_mtxp
= &sema_mtx
[semid
];
1327 _mtx_lock(sema_mtxp
, p
->winpid
, __FILE__
, __LINE__
);
1329 mtx_lock(sema_mtxp
);
1332 if ((semaptr
->sem_perm
.mode
& SEM_ALLOC
) == 0)
1333 panic("semexit - semid not allocated");
1334 if (semnum
>= semaptr
->sem_nsems
)
1335 panic("semexit - semnum out of range");
1339 "semexit: %u id=%d num=%d(adj=%d) ; sem=%d\n",
1341 "semexit: %08x id=%d num=%d(adj=%d) ; sem=%d\n",
1343 suptr
->un_proc
, suptr
->un_ent
[ix
].un_id
,
1344 suptr
->un_ent
[ix
].un_num
,
1345 suptr
->un_ent
[ix
].un_adjval
,
1346 semaptr
->sem_base
[semnum
].semval
));
1349 if (semaptr
->sem_base
[semnum
].semval
< -adjval
)
1350 semaptr
->sem_base
[semnum
].semval
= 0;
1352 semaptr
->sem_base
[semnum
].semval
+=
1355 semaptr
->sem_base
[semnum
].semval
+= adjval
;
1358 DPRINTF(("semexit: back from wakeup\n"));
1359 _mtx_unlock(sema_mtxp
, __FILE__
, __LINE__
);
1367 * Deallocate the undo vector.
1369 DPRINTF(("removing vector (%u)\n", suptr
->un_proc
));
1373 suptr
->un_proc
= NULL
;
1375 *supptr
= SLIST_NEXT(suptr
, un_next
);
1383 sysctl_sema(SYSCTL_HANDLER_ARGS
)
1386 return (SYSCTL_OUT(req
, sema
,
1387 sizeof(struct semid_ds
) * seminfo
.semmni
));
1389 #endif /* __CYGWIN__ */
1390 #endif /* __OUTSIDE_CYGWIN__ */