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 $");
21 /* CV, 2006-01-09: Inspected upstream up to version 1.78. */
24 #define __BSD_VISIBLE 1
25 #include <sys/types.h>
28 #include <sys/param.h>
29 #include <sys/sysproto.h>
32 #include <sys/queue.h>
36 #include "cygserver.h"
38 #include "cygserver_ipc.h"
39 #include <sys/smallprint.h>
42 #define __semctl semctl
43 #define __semctl_args semctl_args
45 #endif /* __CYGWIN__ */
48 #define DPRINTF(a) debug_printf a
53 static int semvalid(int semid
, struct semid_ds
*semaptr
);
55 static struct sem_undo
*semu_alloc(struct thread
*td
);
56 static int semundo_adjust(struct thread
*td
, struct sem_undo
**supptr
,
57 int semid
, int semnum
, int adjval
);
58 static void semundo_clear(int semid
, int semnum
, struct thread
*td
);
60 #ifndef _SYS_SYSPROTO_H_
62 int __semctl(struct thread
*td
, struct __semctl_args
*uap
);
64 int semget(struct thread
*td
, struct semget_args
*uap
);
66 int semop(struct thread
*td
, struct semop_args
*uap
);
70 /* XXX casting to (sy_call_t *) is bogus, as usual. */
71 static sy_call_t
*semcalls
[] = {
72 (sy_call_t
*)__semctl
, (sy_call_t
*)semget
,
77 static struct mtx sem_mtx
; /* semaphore global lock */
78 static int semtots
= 0;
79 static int semtot
= 0;
80 static struct semid_ds
*sema
; /* semaphore id pool */
81 static struct mtx
*sema_mtx
; /* semaphore id pool mutexes*/
82 static struct sem
*sem
; /* semaphore pool */
83 static SLIST_HEAD(, sem_undo
) semu_list
; /* list of active undo structures */
84 static int *semu
; /* undo structure pool */
86 static eventhandler_tag semexit_tag
;
87 #endif /* __CYGWIN__ */
89 #define SEMUNDO_MTX sem_mtx
90 #define SEMUNDO_LOCK() mtx_lock(&SEMUNDO_MTX);
91 #define SEMUNDO_HOOKLOCK() _mtx_lock(&SEMUNDO_MTX, p->winpid, __FILE__, __LINE__);
92 #define SEMUNDO_UNLOCK() mtx_unlock(&SEMUNDO_MTX);
93 #define SEMUNDO_LOCKASSERT(how,pid) mtx_assert(&SEMUNDO_MTX, (how), (pid));
96 u_short semval
; /* semaphore value */
97 pid_t sempid
; /* pid of last operation */
98 u_short semncnt
; /* # awaiting semval > cval */
99 u_short semzcnt
; /* # awaiting semval = 0 */
103 * Undo structure (one per process)
106 short un_adjval
; /* adjust on exit values */
107 short un_num
; /* semaphore # */
108 int un_id
; /* semid */
109 } un_ent
[1]; /* undo entries */
112 SLIST_ENTRY(sem_undo
) un_next
; /* ptr to next active undo structure */
114 DWORD un_proc
; /* owner of this structure */
116 struct proc
*un_proc
; /* owner of this structure */
118 short un_cnt
; /* # of active entries */
119 struct undo un_ent
[1]; /* undo entries */
123 * Configuration parameters
126 #define SEMMNI 10 /* # of semaphore identifiers */
129 #define SEMMNS 60 /* # of semaphores in system */
132 #define SEMUME 10 /* max # of undo entries per process */
135 #define SEMMNU 30 /* # of undo structures in system */
138 /* shouldn't need tuning */
140 #define SEMMAP 30 /* # of entries in semaphore map */
143 #define SEMMSL SEMMNS /* max # of semaphores per id */
146 #define SEMOPM 100 /* max # of operations per semop call */
150 #define SEMVMX 32767 /* semaphore maximum value */
153 #define SEMAEM 16384 /* adjust on exit max value */
157 /* gcc 3.4 defines a new offsetof which is different for C++. Since this
158 file is just a derived plain-C file, we need to revert to the plain-C
159 definition of offsetof. */
163 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
164 #endif /* __CYGWIN__ */
166 * Due to the way semaphore memory is allocated, we have to ensure that
167 * SEMUSZ is properly aligned.
170 #define SEM_ALIGN(bytes) (((bytes) + (sizeof(long) - 1)) & ~(sizeof(long) - 1))
172 /* actual size of an undo structure */
173 #define SEMUSZ SEM_ALIGN(offsetof(struct sem_undo, un_ent[SEMUME]))
176 * Macro to find a particular sem_undo vector
179 ((struct sem_undo *)(((intptr_t)semu)+ix * seminfo.semusz))
182 * semaphore info struct
184 struct seminfo seminfo
= {
185 SEMMNI
, /* # of semaphore identifiers */
186 SEMMNS
, /* # of semaphores in system */
187 SEMMSL
, /* max # of semaphores per id */
188 SEMOPM
, /* max # of operations per semop call */
189 SEMMNU
, /* # of undo structures in system */
190 SEMUME
, /* max # of undo entries per process */
191 SEMVMX
, /* semaphore maximum value */
192 SEMAEM
, /* adjust on exit max value */
193 SEMMAP
, /* # of entries in semaphore map */
194 SEMUSZ
/* size in bytes of undo structure */
198 SYSCTL_DECL(_kern_ipc
);
199 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semmap
, CTLFLAG_RW
, &seminfo
.semmap
, 0, "");
200 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semmni
, CTLFLAG_RDTUN
, &seminfo
.semmni
, 0, "");
201 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semmns
, CTLFLAG_RDTUN
, &seminfo
.semmns
, 0, "");
202 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semmnu
, CTLFLAG_RDTUN
, &seminfo
.semmnu
, 0, "");
203 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semmsl
, CTLFLAG_RW
, &seminfo
.semmsl
, 0, "");
204 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semopm
, CTLFLAG_RDTUN
, &seminfo
.semopm
, 0, "");
205 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semume
, CTLFLAG_RDTUN
, &seminfo
.semume
, 0, "");
206 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semusz
, CTLFLAG_RDTUN
, &seminfo
.semusz
, 0, "");
207 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semvmx
, CTLFLAG_RW
, &seminfo
.semvmx
, 0, "");
208 SYSCTL_INT(_kern_ipc
, OID_AUTO
, semaem
, CTLFLAG_RW
, &seminfo
.semaem
, 0, "");
209 SYSCTL_PROC(_kern_ipc
, OID_AUTO
, sema
, CTLFLAG_RD
,
210 NULL
, 0, sysctl_sema
, "", "");
211 #endif /* __CYGWIN__ */
218 TUNABLE_INT_FETCH("kern.ipc.semmap", &seminfo
.semmap
);
219 TUNABLE_INT_FETCH("kern.ipc.semmni", &seminfo
.semmni
);
220 TUNABLE_INT_FETCH("kern.ipc.semmns", &seminfo
.semmns
);
221 TUNABLE_INT_FETCH("kern.ipc.semmnu", &seminfo
.semmnu
);
222 TUNABLE_INT_FETCH("kern.ipc.semmsl", &seminfo
.semmsl
);
223 TUNABLE_INT_FETCH("kern.ipc.semopm", &seminfo
.semopm
);
224 TUNABLE_INT_FETCH("kern.ipc.semume", &seminfo
.semume
);
225 TUNABLE_INT_FETCH("kern.ipc.semusz", &seminfo
.semusz
);
226 TUNABLE_INT_FETCH("kern.ipc.semvmx", &seminfo
.semvmx
);
227 TUNABLE_INT_FETCH("kern.ipc.semaem", &seminfo
.semaem
);
230 /* It's too dangerous a setting to leave it alone.
231 Keep that clean here. */
232 seminfo
.semusz
= SEM_ALIGN(offsetof(struct sem_undo
,
233 un_ent
[seminfo
.semume
]));
234 #endif /* __CYGWIN__ */
236 sem
= (struct sem
*) sys_malloc(sizeof(struct sem
) * seminfo
.semmns
, M_SEM
, M_WAITOK
);
237 sema
= (struct semid_ds
*) sys_malloc(sizeof(struct semid_ds
) * seminfo
.semmni
, M_SEM
,
239 sema_mtx
= (struct mtx
*) sys_malloc(sizeof(struct mtx
) * seminfo
.semmni
, M_SEM
,
241 semu
= (int *) sys_malloc(seminfo
.semmnu
* seminfo
.semusz
, M_SEM
, M_WAITOK
);
243 for (i
= 0; i
< seminfo
.semmni
; i
++) {
244 sema
[i
].sem_base
= 0;
245 sema
[i
].sem_perm
.mode
= 0;
246 sema
[i
].sem_perm
.seq
= 0;
248 for (i
= 0; i
< seminfo
.semmni
; i
++)
250 char *buf
= (char *)malloc (16);
251 __small_sprintf (buf
, "semid[%d]", i
);
252 mtx_init(&sema_mtx
[i
], buf
, NULL
, MTX_DEF
);
254 for (i
= 0; i
< seminfo
.semmnu
; i
++) {
255 struct sem_undo
*suptr
= SEMU(i
);
259 suptr
->un_proc
= NULL
;
262 SLIST_INIT(&semu_list
);
263 mtx_init(&sem_mtx
, "sem", NULL
, MTX_DEF
);
265 semexit_tag
= EVENTHANDLER_REGISTER(process_exit
, semexit_myhook
, NULL
,
266 EVENTHANDLER_PRI_ANY
);
267 #endif /* __CYGWIN__ */
273 #ifndef __CYGWIN__ /* Would result in being unable to shutdown the
274 server gracefully. */
278 EVENTHANDLER_DEREGISTER(process_exit
, semexit_tag
);
279 #endif /* __CYGWIN__ */
280 sys_free(sem
, M_SEM
);
281 sys_free(sema
, M_SEM
);
282 sys_free(semu
, M_SEM
);
283 for (int i
= 0; i
< seminfo
.semmni
; i
++)
284 mtx_destroy(&sema_mtx
[i
]);
285 mtx_destroy(&sem_mtx
);
291 sysvsem_modload(struct module
*module
, int cmd
, void *arg
)
311 static moduledata_t sysvsem_mod
= {
317 SYSCALL_MODULE_HELPER(semsys
);
318 SYSCALL_MODULE_HELPER(__semctl
);
319 SYSCALL_MODULE_HELPER(semget
);
320 SYSCALL_MODULE_HELPER(semop
);
322 DECLARE_MODULE(sysvsem
, sysvsem_mod
,
323 SI_SUB_SYSV_SEM
, SI_ORDER_FIRST
);
324 MODULE_VERSION(sysvsem
, 1);
327 * Entry point for all SEM calls
334 /* XXX actually varargs. */
335 struct semsys_args
/* {
345 if (!jail_sysvipc_allowed
&& jailed(td
->td_ucred
))
347 if (uap
->which
< 0 ||
348 uap
->which
>= sizeof(semcalls
)/sizeof(semcalls
[0]))
350 error
= (*semcalls
[uap
->which
])(td
, &uap
->a2
);
353 #endif /* __CYGWIN__ */
356 * Allocate a new sem_undo structure for a process
357 * (returns ptr to structure or NULL if no more room)
360 static struct sem_undo
*
361 semu_alloc(struct thread
*td
)
364 struct sem_undo
*suptr
;
365 struct sem_undo
**supptr
;
368 SEMUNDO_LOCKASSERT(MA_OWNED
, td
->td_proc
->winpid
);
370 * Try twice to allocate something.
371 * (we'll purge an empty structure after the first pass so
372 * two passes are always enough)
375 for (attempt
= 0; attempt
< 2; attempt
++) {
377 * Look for a free structure.
378 * Fill it in and return it if we find one.
381 for (i
= 0; i
< seminfo
.semmnu
; i
++) {
384 if (suptr
->un_proc
== 0) {
386 if (suptr
->un_proc
== NULL
) {
388 SLIST_INSERT_HEAD(&semu_list
, suptr
, un_next
);
390 suptr
->un_proc
= td
->td_proc
->winpid
;
396 * We didn't find a free one, if this is the first attempt
397 * then try to free a structure.
401 /* All the structures are in use - try to free one */
402 int did_something
= 0;
404 SLIST_FOREACH_PREVPTR(suptr
, supptr
, &semu_list
,
406 if (suptr
->un_cnt
== 0) {
410 suptr
->un_proc
= NULL
;
413 *supptr
= SLIST_NEXT(suptr
, un_next
);
418 /* If we didn't free anything then just give-up */
423 * The second pass failed even though we freed
424 * something after the first pass!
425 * This is IMPOSSIBLE!
427 panic("semu_alloc - second attempt failed");
434 * Adjust a particular entry for a particular proc
438 semundo_adjust(struct thread
*td
, struct sem_undo
**supptr
, int semid
,
439 int semnum
, int adjval
)
441 struct proc
*p
= td
->td_proc
;
442 struct sem_undo
*suptr
;
446 SEMUNDO_LOCKASSERT(MA_OWNED
, td
->td_proc
->winpid
);
447 /* Look for and remember the sem_undo if the caller doesn't provide
452 SLIST_FOREACH(suptr
, &semu_list
, un_next
) {
454 if (suptr
->un_proc
== p
->winpid
) {
456 if (suptr
->un_proc
== p
) {
465 suptr
= semu_alloc(td
);
473 * Look for the requested entry and adjust it (delete if adjval becomes
476 sunptr
= &suptr
->un_ent
[0];
477 for (i
= 0; i
< suptr
->un_cnt
; i
++, sunptr
++) {
478 if (sunptr
->un_id
!= semid
|| sunptr
->un_num
!= semnum
)
481 adjval
+= sunptr
->un_adjval
;
482 if (adjval
> seminfo
.semaem
|| adjval
< -seminfo
.semaem
)
485 sunptr
->un_adjval
= adjval
;
486 if (sunptr
->un_adjval
== 0) {
488 if (i
< suptr
->un_cnt
)
490 suptr
->un_ent
[suptr
->un_cnt
];
495 /* Didn't find the right entry - create it */
498 if (adjval
> seminfo
.semaem
|| adjval
< -seminfo
.semaem
)
500 if (suptr
->un_cnt
!= seminfo
.semume
) {
501 sunptr
= &suptr
->un_ent
[suptr
->un_cnt
];
503 sunptr
->un_adjval
= adjval
;
504 sunptr
->un_id
= semid
; sunptr
->un_num
= semnum
;
511 semundo_clear(int semid
, int semnum
, struct thread
*td
)
513 struct sem_undo
*suptr
;
515 SEMUNDO_LOCKASSERT(MA_OWNED
, td
->td_proc
->winpid
);
516 SLIST_FOREACH(suptr
, &semu_list
, un_next
) {
517 struct undo
*sunptr
= &suptr
->un_ent
[0];
520 while (i
< suptr
->un_cnt
) {
521 if (sunptr
->un_id
== semid
) {
522 if (semnum
== -1 || sunptr
->un_num
== semnum
) {
524 if (i
< suptr
->un_cnt
) {
526 suptr
->un_ent
[suptr
->un_cnt
];
539 semvalid(int semid
, struct semid_ds
*semaptr
)
542 return ((semaptr
->sem_perm
.mode
& SEM_ALLOC
) == 0 ||
543 semaptr
->sem_perm
.seq
!= IPCID_TO_SEQ(semid
) ? EINVAL
: 0);
547 * Note that the user-mode half of this passes a union, not a pointer
549 #ifndef _SYS_SYSPROTO_H_
550 struct __semctl_args
{
562 __semctl(struct thread
*td
, struct __semctl_args
*uap
)
564 int semid
= uap
->semid
;
565 int semnum
= uap
->semnum
;
568 union semun
*arg
= uap
->arg
;
569 union semun real_arg
;
571 struct ucred
*cred
= td
->td_ucred
;
574 struct semid_ds sbuf
;
575 struct semid_ds
*semaptr
;
576 struct mtx
*sema_mtxp
;
577 u_short usval
, count
;
579 DPRINTF(("call to semctl(%d, %d, %d, 0x%x)\n",
580 semid
, semnum
, cmd
, arg
));
581 if (!jail_sysvipc_allowed
&& jailed(td
->td_ucred
))
589 if ((error
= copyin(arg
, &real_arg
, sizeof(real_arg
))) != 0)
592 error
= copyout(&seminfo
, real_arg
.buf
,
593 sizeof(struct seminfo
));
594 td
->td_retval
[0] = error
? -1 : 0;
597 if (semid
> seminfo
.semmni
)
598 semid
= seminfo
.semmni
;
599 error
= copyout(sema
, real_arg
.buf
,
600 semid
* sizeof(struct semid_ds
));
601 td
->td_retval
[0] = error
? -1 : 0;
604 if (!(error
= copyin(arg
, &real_arg
, sizeof(real_arg
)))) {
605 struct sem_info sem_info
;
606 sem_info
.sem_ids
= semtots
;
607 sem_info
.sem_num
= semtot
;
608 error
= copyout(&sem_info
, real_arg
.buf
,
609 sizeof(struct sem_info
));
611 td
->td_retval
[0] = error
? -1 : 0;
614 #endif /* __CYGWIN__ */
616 if (semid
< 0 || semid
>= seminfo
.semmni
)
618 if ((error
= copyin(arg
, &real_arg
, sizeof(real_arg
))) != 0)
620 semaptr
= &sema
[semid
];
621 sema_mtxp
= &sema_mtx
[semid
];
623 if ((semaptr
->sem_perm
.mode
& SEM_ALLOC
) == 0) {
627 if ((error
= ipcperm(td
, &semaptr
->sem_perm
, IPC_R
)))
629 mtx_unlock(sema_mtxp
);
630 error
= copyout(semaptr
, real_arg
.buf
, sizeof(struct semid_ds
));
631 rval
= IXSEQ_TO_IPCID(semid
,semaptr
->sem_perm
);
633 td
->td_retval
[0] = rval
;
637 semid
= IPCID_TO_IX(semid
);
638 if (semid
< 0 || semid
>= seminfo
.semmni
)
641 semaptr
= &sema
[semid
];
642 sema_mtxp
= &sema_mtx
[semid
];
650 if ((error
= semvalid(uap
->semid
, semaptr
)) != 0)
652 if ((error
= ipcperm(td
, &semaptr
->sem_perm
, IPC_M
)))
655 semaptr
->sem_perm
.cuid
= td
->ipcblk
->uid
;
656 semaptr
->sem_perm
.uid
= td
->ipcblk
->uid
;
658 semaptr
->sem_perm
.cuid
= cred
->cr_uid
;
659 semaptr
->sem_perm
.uid
= cred
->cr_uid
;
661 semtot
-= semaptr
->sem_nsems
;
663 for (i
= semaptr
->sem_base
- sem
; i
< semtot
; i
++)
664 sem
[i
] = sem
[i
+ semaptr
->sem_nsems
];
665 for (i
= 0; i
< seminfo
.semmni
; i
++) {
666 if ((sema
[i
].sem_perm
.mode
& SEM_ALLOC
) &&
667 sema
[i
].sem_base
> semaptr
->sem_base
)
668 sema
[i
].sem_base
-= semaptr
->sem_nsems
;
670 semaptr
->sem_perm
.mode
= 0;
672 semundo_clear(semid
, -1, td
);
678 if ((error
= copyin(arg
, &real_arg
, sizeof(real_arg
))) != 0)
680 if ((error
= copyin(real_arg
.buf
, &sbuf
, sizeof(sbuf
))) != 0)
683 if ((error
= semvalid(uap
->semid
, semaptr
)) != 0)
685 if ((error
= ipcperm(td
, &semaptr
->sem_perm
, IPC_M
)))
687 semaptr
->sem_perm
.uid
= sbuf
.sem_perm
.uid
;
688 semaptr
->sem_perm
.gid
= sbuf
.sem_perm
.gid
;
689 semaptr
->sem_perm
.mode
= (semaptr
->sem_perm
.mode
& ~0777) |
690 (sbuf
.sem_perm
.mode
& 0777);
691 semaptr
->sem_ctime
= time (NULL
);
695 if ((error
= copyin(arg
, &real_arg
, sizeof(real_arg
))) != 0)
698 if ((error
= semvalid(uap
->semid
, semaptr
)) != 0)
700 if ((error
= ipcperm(td
, &semaptr
->sem_perm
, IPC_R
)))
703 mtx_unlock(sema_mtxp
);
704 error
= copyout(semaptr
, real_arg
.buf
,
705 sizeof(struct semid_ds
));
710 if ((error
= semvalid(uap
->semid
, semaptr
)) != 0)
712 if ((error
= ipcperm(td
, &semaptr
->sem_perm
, IPC_R
)))
714 if (semnum
< 0 || semnum
>= semaptr
->sem_nsems
) {
718 rval
= semaptr
->sem_base
[semnum
].semncnt
;
723 if ((error
= semvalid(uap
->semid
, semaptr
)) != 0)
725 if ((error
= ipcperm(td
, &semaptr
->sem_perm
, IPC_R
)))
727 if (semnum
< 0 || semnum
>= semaptr
->sem_nsems
) {
731 rval
= semaptr
->sem_base
[semnum
].sempid
;
736 if ((error
= semvalid(uap
->semid
, semaptr
)) != 0)
738 if ((error
= ipcperm(td
, &semaptr
->sem_perm
, IPC_R
)))
740 if (semnum
< 0 || semnum
>= semaptr
->sem_nsems
) {
744 rval
= semaptr
->sem_base
[semnum
].semval
;
748 if ((error
= copyin(arg
, &real_arg
, sizeof(real_arg
))) != 0)
750 array
= (u_short
*) sys_malloc(sizeof(*array
) * semaptr
->sem_nsems
, M_TEMP
,
753 if ((error
= semvalid(uap
->semid
, semaptr
)) != 0)
755 if ((error
= ipcperm(td
, &semaptr
->sem_perm
, IPC_R
)))
757 for (i
= 0; i
< semaptr
->sem_nsems
; i
++)
758 array
[i
] = semaptr
->sem_base
[i
].semval
;
759 mtx_unlock(sema_mtxp
);
760 error
= copyout(array
, real_arg
.array
,
761 i
* sizeof(real_arg
.array
[0]));
766 if ((error
= semvalid(uap
->semid
, semaptr
)) != 0)
768 if ((error
= ipcperm(td
, &semaptr
->sem_perm
, IPC_R
)))
770 if (semnum
< 0 || semnum
>= semaptr
->sem_nsems
) {
774 rval
= semaptr
->sem_base
[semnum
].semzcnt
;
778 if ((error
= copyin(arg
, &real_arg
, sizeof(real_arg
))) != 0)
781 if ((error
= semvalid(uap
->semid
, semaptr
)) != 0)
783 if ((error
= ipcperm(td
, &semaptr
->sem_perm
, IPC_W
)))
785 if (semnum
< 0 || semnum
>= semaptr
->sem_nsems
) {
789 if (real_arg
.val
< 0 || real_arg
.val
> seminfo
.semvmx
) {
793 semaptr
->sem_base
[semnum
].semval
= real_arg
.val
;
795 semundo_clear(semid
, semnum
, td
);
803 if ((error
= semvalid(uap
->semid
, semaptr
)) != 0)
805 count
= semaptr
->sem_nsems
;
806 mtx_unlock(sema_mtxp
);
807 if ((error
= copyin(arg
, &real_arg
, sizeof(real_arg
))) != 0)
809 array
= (u_short
*) sys_malloc(sizeof(*array
) * count
, M_TEMP
, M_WAITOK
);
810 error
= copyin(real_arg
.array
, array
, count
* sizeof(*array
));
814 if ((error
= semvalid(uap
->semid
, semaptr
)) != 0)
816 /* we could have raced? */
817 if (count
!= semaptr
->sem_nsems
) {
818 sys_free(array
, M_TEMP
);
822 if ((error
= ipcperm(td
, &semaptr
->sem_perm
, IPC_W
)))
824 for (i
= 0; i
< semaptr
->sem_nsems
; i
++) {
826 if (usval
> seminfo
.semvmx
) {
830 semaptr
->sem_base
[i
].semval
= usval
;
833 semundo_clear(semid
, -1, td
);
844 td
->td_retval
[0] = rval
;
846 if (mtx_owned(sema_mtxp
, td
->td_proc
->winpid
))
847 mtx_unlock(sema_mtxp
);
849 sys_free(array
, M_TEMP
);
853 #ifndef _SYS_SYSPROTO_H_
865 semget(struct thread
*td
, struct semget_args
*uap
)
867 int semid
, error
= 0;
868 key_t key
= uap
->key
;
869 int nsems
= uap
->nsems
;
870 int semflg
= uap
->semflg
;
872 struct ucred
*cred
= td
->td_ucred
;
875 DPRINTF(("semget(0x%X, %d, 0%o)\n", key
, nsems
, semflg
));
876 if (!jail_sysvipc_allowed
&& jailed(td
->td_ucred
))
880 if (key
!= IPC_PRIVATE
) {
881 for (semid
= 0; semid
< seminfo
.semmni
; semid
++) {
882 if ((sema
[semid
].sem_perm
.mode
& SEM_ALLOC
) &&
883 sema
[semid
].sem_perm
.key
== key
)
886 if (semid
< seminfo
.semmni
) {
887 DPRINTF(("found public key\n"));
888 if ((error
= ipcperm(td
, &sema
[semid
].sem_perm
,
892 if (nsems
> 0 && sema
[semid
].sem_nsems
< nsems
) {
893 DPRINTF(("too small\n"));
897 if ((semflg
& IPC_CREAT
) && (semflg
& IPC_EXCL
)) {
898 DPRINTF(("not exclusive\n"));
906 DPRINTF(("need to allocate the semid_ds\n"));
907 if (key
== IPC_PRIVATE
|| (semflg
& IPC_CREAT
)) {
908 if (nsems
<= 0 || nsems
> seminfo
.semmsl
) {
909 DPRINTF(("nsems out of range (0<%d<=%d)\n", nsems
,
914 if (nsems
> seminfo
.semmns
- semtot
) {
916 "not enough semaphores left (need %d, got %d)\n",
917 nsems
, seminfo
.semmns
- semtot
));
921 for (semid
= 0; semid
< seminfo
.semmni
; semid
++) {
922 if ((sema
[semid
].sem_perm
.mode
& SEM_ALLOC
) == 0)
925 if (semid
== seminfo
.semmni
) {
926 DPRINTF(("no more semid_ds's available\n"));
930 DPRINTF(("semid %d is available\n", semid
));
931 sema
[semid
].sem_perm
.key
= key
;
933 sema
[semid
].sem_perm
.cuid
= td
->ipcblk
->uid
;
934 sema
[semid
].sem_perm
.uid
= td
->ipcblk
->uid
;
935 sema
[semid
].sem_perm
.cgid
= td
->ipcblk
->gid
;
936 sema
[semid
].sem_perm
.gid
= td
->ipcblk
->gid
;
938 sema
[semid
].sem_perm
.cuid
= cred
->cr_uid
;
939 sema
[semid
].sem_perm
.uid
= cred
->cr_uid
;
940 sema
[semid
].sem_perm
.cgid
= cred
->cr_gid
;
941 sema
[semid
].sem_perm
.gid
= cred
->cr_gid
;
943 sema
[semid
].sem_perm
.mode
= (semflg
& 0777) | SEM_ALLOC
;
944 sema
[semid
].sem_perm
.seq
=
945 (sema
[semid
].sem_perm
.seq
+ 1) & 0x7fff;
946 sema
[semid
].sem_nsems
= nsems
;
947 sema
[semid
].sem_otime
= 0;
948 sema
[semid
].sem_ctime
= time (NULL
);
949 sema
[semid
].sem_base
= &sem
[semtot
];
952 bzero(sema
[semid
].sem_base
,
953 sizeof(sema
[semid
].sem_base
[0])*nsems
);
954 DPRINTF(("sembase = 0x%x, next = 0x%x\n", sema
[semid
].sem_base
,
957 DPRINTF(("didn't find it and wasn't asked to create it\n"));
963 td
->td_retval
[0] = IXSEQ_TO_IPCID(semid
, sema
[semid
].sem_perm
);
967 ipcexit_creat_hookthread (td
);
973 #ifndef _SYS_SYSPROTO_H_
985 semop(struct thread
*td
, struct semop_args
*uap
)
988 struct sembuf small_sops
[SMALL_SOPS
];
989 int semid
= uap
->semid
;
990 size_t nsops
= uap
->nsops
;
992 struct semid_ds
*semaptr
;
993 struct sembuf
*sopptr
= 0;
994 struct sem
*semptr
= 0;
995 struct sem_undo
*suptr
;
996 struct mtx
*sema_mtxp
;
999 int do_wakeup
, do_undos
;
1001 DPRINTF(("call to semop(%d, 0x%x, %u)\n", semid
, uap
->sops
, nsops
));
1003 if (!jail_sysvipc_allowed
&& jailed(td
->td_ucred
))
1006 semid
= IPCID_TO_IX(semid
); /* Convert back to zero origin */
1008 if (semid
< 0 || semid
>= seminfo
.semmni
)
1011 /* Allocate memory for sem_ops */
1012 if (nsops
<= SMALL_SOPS
)
1014 else if (nsops
<= (unsigned long) seminfo
.semopm
)
1015 sops
= (struct sembuf
*) sys_malloc(nsops
* sizeof(*sops
), M_SEM
, M_WAITOK
);
1017 DPRINTF(("too many sops (max=%d, nsops=%d)\n", seminfo
.semopm
,
1021 if ((error
= copyin(uap
->sops
, sops
, nsops
* sizeof(sops
[0]))) != 0) {
1022 DPRINTF(("error = %d from copyin(%08x, %08x, %d)\n", error
,
1023 uap
->sops
, sops
, nsops
* sizeof(sops
[0])));
1024 if (sops
!= small_sops
)
1025 sys_free(sops
, M_SEM
);
1029 semaptr
= &sema
[semid
];
1030 sema_mtxp
= &sema_mtx
[semid
];
1031 mtx_lock(sema_mtxp
);
1032 if ((semaptr
->sem_perm
.mode
& SEM_ALLOC
) == 0) {
1036 if (semaptr
->sem_perm
.seq
!= IPCID_TO_SEQ(uap
->semid
)) {
1041 * Initial pass thru sops to see what permissions are needed.
1042 * Also perform any checks that don't need repeating on each
1043 * attempt to satisfy the request vector.
1045 j
= 0; /* permission needed */
1047 for (i
= 0; i
< nsops
; i
++) {
1049 if (sopptr
->sem_num
>= semaptr
->sem_nsems
) {
1053 if (sopptr
->sem_flg
& SEM_UNDO
&& sopptr
->sem_op
!= 0)
1055 j
|= (sopptr
->sem_op
== 0) ? SEM_R
: SEM_A
;
1058 if ((error
= ipcperm(td
, &semaptr
->sem_perm
, j
))) {
1059 DPRINTF(("error = %d from ipaccess\n", error
));
1064 * Loop trying to satisfy the vector of requests.
1065 * If we reach a point where we must wait, any requests already
1066 * performed are rolled back and we go to sleep until some other
1067 * process wakes us up. At this point, we start all over again.
1069 * This ensures that from the perspective of other tasks, a set
1070 * of requests is atomic (never partially satisfied).
1074 error
= 0; /* error return if necessary */
1076 for (i
= 0; i
< nsops
; i
++) {
1078 semptr
= &semaptr
->sem_base
[sopptr
->sem_num
];
1081 "semop: semaptr=%x, sem_base=%x, "
1082 "semptr=%x, sem[%d]=%d : op=%d, flag=%s\n",
1083 semaptr
, semaptr
->sem_base
, semptr
,
1084 sopptr
->sem_num
, semptr
->semval
, sopptr
->sem_op
,
1085 (sopptr
->sem_flg
& IPC_NOWAIT
) ?
1086 "nowait" : "wait"));
1088 if (sopptr
->sem_op
< 0) {
1089 if (semptr
->semval
+ sopptr
->sem_op
< 0) {
1090 DPRINTF(("semop: can't do it now\n"));
1093 semptr
->semval
+= sopptr
->sem_op
;
1094 if (semptr
->semval
== 0 &&
1095 semptr
->semzcnt
> 0)
1098 } else if (sopptr
->sem_op
== 0) {
1099 if (semptr
->semval
!= 0) {
1100 DPRINTF(("semop: not zero now\n"));
1103 } else if (semptr
->semval
+ sopptr
->sem_op
>
1108 if (semptr
->semncnt
> 0)
1110 semptr
->semval
+= sopptr
->sem_op
;
1115 * Did we get through the entire vector?
1121 * No ... rollback anything that we've already done
1123 DPRINTF(("semop: rollback 0 through %d\n", i
-1));
1124 for (j
= 0; j
< i
; j
++)
1125 semaptr
->sem_base
[sops
[j
].sem_num
].semval
-=
1128 /* If we detected an error, return it */
1133 * If the request that we couldn't satisfy has the
1134 * NOWAIT flag set then return with EAGAIN.
1136 if (sopptr
->sem_flg
& IPC_NOWAIT
) {
1141 if (sopptr
->sem_op
== 0)
1146 DPRINTF(("semop: good night!\n"));
1147 error
= msleep(semaptr
, sema_mtxp
, (PZERO
- 4) | PCATCH
,
1149 DPRINTF(("semop: good morning (error=%d)!\n", error
));
1150 /* return code is checked below, after sem[nz]cnt-- */
1153 * Make sure that the semaphore still exists
1155 if ((semaptr
->sem_perm
.mode
& SEM_ALLOC
) == 0 ||
1156 semaptr
->sem_perm
.seq
!= IPCID_TO_SEQ(uap
->semid
)) {
1162 * The semaphore is still alive. Readjust the count of
1163 * waiting processes.
1165 if (sopptr
->sem_op
== 0)
1171 * Is it really morning, or was our sleep interrupted?
1172 * (Delayed check of msleep() return code because we
1173 * need to decrement sem[nz]cnt either way.)
1178 #endif /* __CYGWIN__ */
1182 DPRINTF(("semop: good morning!\n"));
1187 * Process any SEM_UNDO requests.
1192 for (i
= 0; i
< nsops
; i
++) {
1194 * We only need to deal with SEM_UNDO's for non-zero
1199 if ((sops
[i
].sem_flg
& SEM_UNDO
) == 0)
1201 adjval
= sops
[i
].sem_op
;
1204 error
= semundo_adjust(td
, &suptr
, semid
,
1205 sops
[i
].sem_num
, -adjval
);
1210 * Oh-Oh! We ran out of either sem_undo's or undo's.
1211 * Rollback the adjustments to this point and then
1212 * rollback the semaphore ups and down so we can return
1213 * with an error with all structures restored. We
1214 * rollback the undo's in the exact reverse order that
1215 * we applied them. This guarantees that we won't run
1216 * out of space as we roll things back out.
1218 for (j
= 0; j
< i
; j
++) {
1220 if ((sops
[k
].sem_flg
& SEM_UNDO
) == 0)
1222 adjval
= sops
[k
].sem_op
;
1225 if (semundo_adjust(td
, &suptr
, semid
,
1226 sops
[k
].sem_num
, adjval
) != 0)
1227 panic("semop - can't undo undos");
1230 for (j
= 0; j
< nsops
; j
++)
1231 semaptr
->sem_base
[sops
[j
].sem_num
].semval
-=
1234 DPRINTF(("error = %d from semundo_adjust\n", error
));
1237 } /* loop through the sops */
1239 } /* if (do_undos) */
1241 /* We're definitely done - set the sempid's and time */
1242 for (i
= 0; i
< nsops
; i
++) {
1244 semptr
= &semaptr
->sem_base
[sopptr
->sem_num
];
1245 semptr
->sempid
= td
->td_proc
->p_pid
;
1247 semaptr
->sem_otime
= time (NULL
);
1250 * Do a wakeup if any semaphore was up'd whilst something was
1254 DPRINTF(("semop: doing wakeup\n"));
1256 DPRINTF(("semop: back from wakeup\n"));
1258 DPRINTF(("semop: done\n"));
1259 td
->td_retval
[0] = 0;
1261 mtx_unlock(sema_mtxp
);
1262 if (sops
!= small_sops
)
1263 sys_free(sops
, M_SEM
);
1268 * Go through the undo structures for this process and apply the adjustments to
1272 semexit_myhook(void *arg
, struct proc
*p
)
1274 struct sem_undo
*suptr
;
1275 struct sem_undo
**supptr
;
1278 * Go through the chain of undo vectors looking for one
1279 * associated with this process.
1282 SLIST_FOREACH_PREVPTR(suptr
, supptr
, &semu_list
, un_next
) {
1284 if (suptr
->un_proc
== p
->winpid
)
1286 if (suptr
->un_proc
== p
)
1294 if (suptr
== NULL
) {
1300 DPRINTF(("proc @%u(%u) has undo structure with %d entries\n",
1301 p
->cygpid
, p
->winpid
, suptr
->un_cnt
));
1303 DPRINTF(("proc @%08x has undo structure with %d entries\n", p
,
1308 * If there are any active undo elements then process them.
1310 if (suptr
->un_cnt
> 0) {
1313 for (ix
= 0; ix
< suptr
->un_cnt
; ix
++) {
1314 int semid
= suptr
->un_ent
[ix
].un_id
;
1315 int semnum
= suptr
->un_ent
[ix
].un_num
;
1316 int adjval
= suptr
->un_ent
[ix
].un_adjval
;
1317 struct semid_ds
*semaptr
;
1318 struct mtx
*sema_mtxp
;
1320 semaptr
= &sema
[semid
];
1321 sema_mtxp
= &sema_mtx
[semid
];
1323 _mtx_lock(sema_mtxp
, p
->winpid
, __FILE__
, __LINE__
);
1325 mtx_lock(sema_mtxp
);
1328 if ((semaptr
->sem_perm
.mode
& SEM_ALLOC
) == 0)
1329 panic("semexit - semid not allocated");
1330 if (semnum
>= semaptr
->sem_nsems
)
1331 panic("semexit - semnum out of range");
1335 "semexit: %u id=%d num=%d(adj=%d) ; sem=%d\n",
1337 "semexit: %08x id=%d num=%d(adj=%d) ; sem=%d\n",
1339 suptr
->un_proc
, suptr
->un_ent
[ix
].un_id
,
1340 suptr
->un_ent
[ix
].un_num
,
1341 suptr
->un_ent
[ix
].un_adjval
,
1342 semaptr
->sem_base
[semnum
].semval
));
1345 if (semaptr
->sem_base
[semnum
].semval
< -adjval
)
1346 semaptr
->sem_base
[semnum
].semval
= 0;
1348 semaptr
->sem_base
[semnum
].semval
+=
1351 semaptr
->sem_base
[semnum
].semval
+= adjval
;
1354 DPRINTF(("semexit: back from wakeup\n"));
1355 _mtx_unlock(sema_mtxp
, __FILE__
, __LINE__
);
1363 * Deallocate the undo vector.
1365 DPRINTF(("removing vector (%u)\n", suptr
->un_proc
));
1369 suptr
->un_proc
= NULL
;
1371 *supptr
= SLIST_NEXT(suptr
, un_next
);
1379 sysctl_sema(SYSCTL_HANDLER_ARGS
)
1382 return (SYSCTL_OUT(req
, sema
,
1383 sizeof(struct semid_ds
) * seminfo
.semmni
));
1385 #endif /* __CYGWIN__ */
1386 #endif /* __OUTSIDE_CYGWIN__ */