1 /* $NetBSD: mach_semaphore.c,v 1.18 2007/12/20 23:02:59 dsl Exp $ */
4 * Copyright (c) 2002-2003 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: mach_semaphore.c,v 1.18 2007/12/20 23:02:59 dsl Exp $");
35 #include <sys/types.h>
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/signal.h>
40 #include <sys/rwlock.h>
41 #include <sys/malloc.h>
44 #include <compat/mach/mach_types.h>
45 #include <compat/mach/mach_message.h>
46 #include <compat/mach/mach_semaphore.h>
47 #include <compat/mach/mach_clock.h>
48 #include <compat/mach/mach_errno.h>
49 #include <compat/mach/mach_port.h>
50 #include <compat/mach/mach_services.h>
51 #include <compat/mach/mach_syscallargs.h>
53 /* Semaphore list, lock, pools */
54 static LIST_HEAD(mach_semaphore_list
, mach_semaphore
) mach_semaphore_list
;
55 static krwlock_t mach_semaphore_list_lock
;
56 static struct pool mach_semaphore_list_pool
;
57 static struct pool mach_waiting_lwp_pool
;
59 /* Function to manipulate them */
60 static struct mach_semaphore
*mach_semaphore_get(int, int);
61 static void mach_semaphore_put(struct mach_semaphore
*);
62 static struct mach_waiting_lwp
*mach_waiting_lwp_get
63 (struct lwp
*, struct mach_semaphore
*);
64 static void mach_waiting_lwp_put
65 (struct mach_waiting_lwp
*, struct mach_semaphore
*, int);
68 mach_sys_semaphore_wait_trap(struct lwp
*l
, const struct mach_sys_semaphore_wait_trap_args
*uap
, register_t
*retval
)
71 syscallarg(mach_port_name_t) wait_name;
73 struct mach_semaphore
*ms
;
74 struct mach_waiting_lwp
*mwl
;
75 struct mach_right
*mr
;
79 mn
= SCARG(uap
, wait_name
);
80 if ((mr
= mach_right_check(mn
, l
, MACH_PORT_TYPE_ALL_RIGHTS
)) == 0)
83 if (mr
->mr_port
->mp_datatype
!= MACH_MP_SEMAPHORE
)
86 ms
= (struct mach_semaphore
*)mr
->mr_port
->mp_data
;
88 rw_enter(&ms
->ms_lock
, RW_WRITER
);
92 rw_exit(&ms
->ms_lock
);
95 mwl
= mach_waiting_lwp_get(l
, ms
);
96 while (ms
->ms_value
< 0)
97 tsleep(mwl
, PZERO
|PCATCH
, "sem_wait", 0);
98 mach_waiting_lwp_put(mwl
, ms
, 0);
104 mach_sys_semaphore_signal_trap(struct lwp
*l
, const struct mach_sys_semaphore_signal_trap_args
*uap
, register_t
*retval
)
107 syscallarg(mach_port_name_t) signal_name;
109 struct mach_semaphore
*ms
;
110 struct mach_waiting_lwp
*mwl
;
111 struct mach_right
*mr
;
115 mn
= SCARG(uap
, signal_name
);
116 if ((mr
= mach_right_check(mn
, l
, MACH_PORT_TYPE_ALL_RIGHTS
)) == 0)
119 if (mr
->mr_port
->mp_datatype
!= MACH_MP_SEMAPHORE
)
122 ms
= (struct mach_semaphore
*)mr
->mr_port
->mp_data
;
124 rw_enter(&ms
->ms_lock
, RW_WRITER
);
126 if (ms
->ms_value
>= 0)
128 rw_exit(&ms
->ms_lock
);
130 if (unblocked
!= 0) {
131 rw_enter(&ms
->ms_lock
, RW_READER
);
132 mwl
= TAILQ_FIRST(&ms
->ms_waiting
);
134 rw_exit(&ms
->ms_lock
);
140 mach_semaphore_create(struct mach_trap_args
*args
)
142 mach_semaphore_create_request_t
*req
= args
->smsg
;
143 mach_semaphore_create_reply_t
*rep
= args
->rmsg
;
144 size_t *msglen
= args
->rsize
;
145 struct lwp
*l
= args
->l
;
146 struct mach_semaphore
*ms
;
147 struct mach_port
*mp
;
148 struct mach_right
*mr
;
150 ms
= mach_semaphore_get(req
->req_value
, req
->req_policy
);
152 mp
= mach_port_get();
153 mp
->mp_datatype
= MACH_MP_SEMAPHORE
;
154 mp
->mp_data
= (void *)ms
;
156 mr
= mach_right_get(mp
, l
, MACH_PORT_TYPE_SEND
, 0);
158 *msglen
= sizeof(*rep
);
159 mach_set_header(rep
, req
, *msglen
);
160 mach_add_port_desc(rep
, mr
->mr_name
);
161 mach_set_trailer(rep
, *msglen
);
167 mach_semaphore_destroy(struct mach_trap_args
*args
)
169 mach_semaphore_destroy_request_t
*req
= args
->smsg
;
170 mach_semaphore_destroy_reply_t
*rep
= args
->rmsg
;
171 struct lwp
*l
= args
->l
;
172 size_t *msglen
= args
->rsize
;
173 struct mach_semaphore
*ms
;
174 struct mach_right
*mr
;
177 mn
= req
->req_sem
.name
;
178 if ((mr
= mach_right_check(mn
, l
, MACH_PORT_TYPE_ALL_RIGHTS
)) == 0)
179 return mach_msg_error(args
, EPERM
);
181 if (mr
->mr_port
->mp_datatype
!= MACH_MP_SEMAPHORE
)
182 return mach_msg_error(args
, EINVAL
);
184 ms
= (struct mach_semaphore
*)mr
->mr_port
->mp_data
;
185 mach_semaphore_put(ms
);
186 mach_right_put(mr
, MACH_PORT_TYPE_REF_RIGHTS
);
188 *msglen
= sizeof(*rep
);
189 mach_set_header(rep
, req
, *msglen
);
193 mach_set_trailer(rep
, *msglen
);
199 mach_semaphore_init(void)
201 LIST_INIT(&mach_semaphore_list
);
202 rw_init(&mach_semaphore_list_lock
);
203 pool_init(&mach_semaphore_list_pool
, sizeof (struct mach_semaphore
),
204 0, 0, 0, "mach_sem_pool", NULL
, IPL_NONE
);
205 pool_init(&mach_waiting_lwp_pool
, sizeof (struct mach_waiting_lwp
),
206 0, 0, 0, "mach_waitp_pool", NULL
, IPL_NONE
);
211 static struct mach_semaphore
*
212 mach_semaphore_get(int value
, int policy
)
214 struct mach_semaphore
*ms
;
216 ms
= (struct mach_semaphore
*)pool_get(&mach_semaphore_list_pool
,
218 ms
->ms_value
= value
;
219 ms
->ms_policy
= policy
;
220 TAILQ_INIT(&ms
->ms_waiting
);
221 rw_init(&ms
->ms_lock
);
223 rw_enter(&mach_semaphore_list_lock
, RW_WRITER
);
224 LIST_INSERT_HEAD(&mach_semaphore_list
, ms
, ms_list
);
225 rw_exit(&mach_semaphore_list_lock
);
231 mach_semaphore_put(struct mach_semaphore
*ms
)
233 struct mach_waiting_lwp
*mwl
;
235 rw_enter(&ms
->ms_lock
, RW_WRITER
);
236 while ((mwl
= TAILQ_FIRST(&ms
->ms_waiting
)) != NULL
)
237 mach_waiting_lwp_put(mwl
, ms
, 0);
238 rw_exit(&ms
->ms_lock
);
239 rw_destroy(&ms
->ms_lock
);
241 rw_enter(&mach_semaphore_list_lock
, RW_WRITER
);
242 LIST_REMOVE(ms
, ms_list
);
243 rw_exit(&mach_semaphore_list_lock
);
245 pool_put(&mach_semaphore_list_pool
, ms
);
250 static struct mach_waiting_lwp
*
251 mach_waiting_lwp_get(struct lwp
*l
, struct mach_semaphore
*ms
)
253 struct mach_waiting_lwp
*mwl
;
255 mwl
= (struct mach_waiting_lwp
*)pool_get(&mach_waiting_lwp_pool
,
259 rw_enter(&ms
->ms_lock
, RW_WRITER
);
260 TAILQ_INSERT_TAIL(&ms
->ms_waiting
, mwl
, mwl_list
);
261 rw_exit(&ms
->ms_lock
);
267 mach_waiting_lwp_put(struct mach_waiting_lwp
*mwl
, struct mach_semaphore
*ms
, int locked
)
270 rw_enter(&ms
->ms_lock
, RW_WRITER
);
271 TAILQ_REMOVE(&ms
->ms_waiting
, mwl
, mwl_list
);
273 rw_exit(&ms
->ms_lock
);
274 pool_put(&mach_waiting_lwp_pool
, mwl
);
280 * Cleanup after process exit. Need improvements, there
281 * can be some memory leaks here.
284 mach_semaphore_cleanup(struct lwp
*l
)
286 struct mach_semaphore
*ms
;
287 struct mach_waiting_lwp
*mwl
;
289 rw_enter(&mach_semaphore_list_lock
, RW_READER
);
290 LIST_FOREACH(ms
, &mach_semaphore_list
, ms_list
) {
291 rw_enter(&ms
->ms_lock
, RW_WRITER
);
292 TAILQ_FOREACH(mwl
, &ms
->ms_waiting
, mwl_list
)
293 if (mwl
->mwl_l
== l
) {
294 mach_waiting_lwp_put(mwl
, ms
, 0);
296 if (ms
->ms_value
>= 0)
297 wakeup(TAILQ_FIRST(&ms
->ms_waiting
));
299 rw_exit(&ms
->ms_lock
);
301 rw_exit(&mach_semaphore_list_lock
);
307 mach_sys_semaphore_wait_signal_trap(struct lwp
*l
, const struct mach_sys_semaphore_wait_signal_trap_args
*uap
, register_t
*retval
)
310 syscallarg(mach_port_name_t) wait_name;
311 syscallarg(mach_port_name_t) signal_name;
313 struct mach_sys_semaphore_wait_trap_args cupwait
;
314 struct mach_sys_semaphore_signal_trap_args cupsig
;
317 SCARG(&cupsig
, signal_name
) = SCARG(uap
, signal_name
);
318 if ((error
= mach_sys_semaphore_signal_trap(l
, &cupsig
, retval
)) != 0)
321 SCARG(&cupwait
, wait_name
) = SCARG(uap
, wait_name
);
322 if ((error
= mach_sys_semaphore_wait_trap(l
, &cupwait
, retval
)) != 0)
330 mach_sys_semaphore_signal_thread_trap(struct lwp
*l
, const struct mach_sys_semaphore_signal_thread_trap_args
*uap
, register_t
*retval
)
333 syscallarg(mach_port_name_t) signal_name;
334 syscallarg(mach_port_name_t) thread;
336 struct mach_right
*mr
;
337 struct mach_semaphore
*ms
;
339 struct mach_waiting_lwp
*mwl
;
345 mn
= SCARG(uap
, signal_name
);
346 if ((mr
= mach_right_check(mn
, l
, MACH_PORT_TYPE_ALL_RIGHTS
)) == NULL
)
349 if (mr
->mr_port
->mp_datatype
!= MACH_MP_SEMAPHORE
)
352 ms
= (struct mach_semaphore
*)mr
->mr_port
->mp_data
;
355 * Get the thread, and check that it is waiting for our semaphore
356 * If no thread was supplied, pick up the first one.
358 mn
= SCARG(uap
, thread
);
360 if ((mr
= mach_right_check(mn
, l
,
361 MACH_PORT_TYPE_ALL_RIGHTS
)) == NULL
)
364 if (mr
->mr_port
->mp_datatype
!= MACH_MP_LWP
)
367 rw_enter(&ms
->ms_lock
, RW_WRITER
);
368 TAILQ_FOREACH(mwl
, &ms
->ms_waiting
, mwl_list
)
369 if (mwl
->mwl_l
== (struct lwp
*)mr
->mr_port
->mp_data
)
372 rw_enter(&ms
->ms_lock
, RW_WRITER
);
373 mwl
= TAILQ_FIRST(&ms
->ms_waiting
);
377 * No thread was awaiting for this semaphore,
378 * exit without touching the semaphore.
381 rw_exit(&ms
->ms_lock
);
382 return 0; /* Should be KERN_NOT_WAITING */
386 if (ms
->ms_value
>= 0)
388 rw_exit(&ms
->ms_lock
);
398 mach_sys_semaphore_signal_all_trap(struct lwp
*l
, const struct mach_sys_semaphore_signal_all_trap_args
*uap
, register_t
*retval
)
401 syscallarg(mach_port_name_t) signal_name;
403 struct mach_right
*mr
;
404 struct mach_semaphore
*ms
;
406 struct mach_waiting_lwp
*mwl
;
412 mn
= SCARG(uap
, signal_name
);
413 if ((mr
= mach_right_check(mn
, l
, MACH_PORT_TYPE_ALL_RIGHTS
)) == NULL
)
416 if (mr
->mr_port
->mp_datatype
!= MACH_MP_SEMAPHORE
)
419 ms
= (struct mach_semaphore
*)mr
->mr_port
->mp_data
;
421 rw_enter(&ms
->ms_lock
, RW_WRITER
);
423 if (ms
->ms_value
>= 0)
427 * Wakeup all threads sleeping on it.
430 TAILQ_FOREACH(mwl
, &ms
->ms_waiting
, mwl_list
)
433 rw_exit(&ms
->ms_lock
);