2 * semaphores.c: Semaphore handles
5 * Dick Porter (dick@ximian.com)
7 * (C) 2002 Ximian, Inc.
13 #ifdef HAVE_SEMAPHORE_H
14 #include <semaphore.h>
20 #include <mono/io-layer/wapi.h>
21 #include <mono/io-layer/wapi-private.h>
22 #include <mono/io-layer/misc-private.h>
23 #include <mono/io-layer/handles-private.h>
24 #include <mono/io-layer/semaphore-private.h>
26 #include <mono/utils/mono-mutex.h>
29 #define DEBUG(...) g_message(__VA_ARGS__)
34 static void sema_signal(gpointer handle
);
35 static gboolean
sema_own (gpointer handle
);
37 static void namedsema_signal (gpointer handle
);
38 static gboolean
namedsema_own (gpointer handle
);
40 struct _WapiHandleOps _wapi_sem_ops
= {
42 sema_signal
, /* signal */
45 NULL
, /* special_wait */
49 void _wapi_sem_details (gpointer handle_info
)
51 struct _WapiHandle_sem
*sem
= (struct _WapiHandle_sem
*)handle_info
;
53 g_print ("val: %5u, max: %5d", sem
->val
, sem
->max
);
56 struct _WapiHandleOps _wapi_namedsem_ops
= {
58 namedsema_signal
, /* signal */
59 namedsema_own
, /* own */
61 NULL
, /* special_wait */
65 static gboolean
sem_release (gpointer handle
, gint32 count
, gint32
*prev
);
66 static gboolean
namedsem_release (gpointer handle
, gint32 count
, gint32
*prev
);
70 gboolean (*release
)(gpointer handle
, gint32 count
, gint32
*prev
);
71 } sem_ops
[WAPI_HANDLE_COUNT
] = {
87 static mono_once_t sem_ops_once
=MONO_ONCE_INIT
;
89 static void sem_ops_init (void)
91 _wapi_handle_register_capabilities (WAPI_HANDLE_SEM
,
92 WAPI_HANDLE_CAP_WAIT
|
93 WAPI_HANDLE_CAP_SIGNAL
);
94 _wapi_handle_register_capabilities (WAPI_HANDLE_NAMEDSEM
,
95 WAPI_HANDLE_CAP_WAIT
|
96 WAPI_HANDLE_CAP_SIGNAL
);
99 static void sema_signal(gpointer handle
)
101 ReleaseSemaphore(handle
, 1, NULL
);
104 static gboolean
sema_own (gpointer handle
)
106 struct _WapiHandle_sem
*sem_handle
;
109 ok
=_wapi_lookup_handle (handle
, WAPI_HANDLE_SEM
,
110 (gpointer
*)&sem_handle
);
112 g_warning ("%s: error looking up sem handle %p", __func__
,
117 DEBUG("%s: owning sem handle %p", __func__
, handle
);
121 DEBUG ("%s: sem %p val now %d", __func__
, handle
, sem_handle
->val
);
123 if(sem_handle
->val
==0) {
124 _wapi_handle_set_signal_state (handle
, FALSE
, FALSE
);
130 static void namedsema_signal (gpointer handle
)
132 ReleaseSemaphore (handle
, 1, NULL
);
135 /* NB, always called with the shared handle lock held */
136 static gboolean
namedsema_own (gpointer handle
)
138 struct _WapiHandle_namedsem
*namedsem_handle
;
141 DEBUG ("%s: owning named sem handle %p", __func__
, handle
);
143 ok
= _wapi_lookup_handle (handle
, WAPI_HANDLE_NAMEDSEM
,
144 (gpointer
*)&namedsem_handle
);
146 g_warning ("%s: error looking up named sem handle %p",
151 namedsem_handle
->val
--;
153 DEBUG ("%s: named sem %p val now %d", __func__
, handle
,
154 namedsem_handle
->val
);
156 if (namedsem_handle
->val
== 0) {
157 _wapi_shared_handle_set_signal_state (handle
, FALSE
);
162 static gpointer
sem_create (WapiSecurityAttributes
*security G_GNUC_UNUSED
,
163 gint32 initial
, gint32 max
)
165 struct _WapiHandle_sem sem_handle
= {0};
169 /* Need to blow away any old errors here, because code tests
170 * for ERROR_ALREADY_EXISTS on success (!) to see if a
171 * semaphore was freshly created
173 SetLastError (ERROR_SUCCESS
);
175 sem_handle
.val
= initial
;
176 sem_handle
.max
= max
;
178 handle
= _wapi_handle_new (WAPI_HANDLE_SEM
, &sem_handle
);
179 if (handle
== _WAPI_HANDLE_INVALID
) {
180 g_warning ("%s: error creating semaphore handle", __func__
);
181 SetLastError (ERROR_GEN_FAILURE
);
185 thr_ret
= _wapi_handle_lock_handle (handle
);
186 g_assert (thr_ret
== 0);
189 _wapi_handle_set_signal_state (handle
, TRUE
, FALSE
);
192 DEBUG ("%s: Created semaphore handle %p initial %d max %d",
193 __func__
, handle
, initial
, max
);
195 thr_ret
= _wapi_handle_unlock_handle (handle
);
196 g_assert (thr_ret
== 0);
201 static gpointer
namedsem_create (WapiSecurityAttributes
*security G_GNUC_UNUSED
, gint32 initial
, gint32 max
, const gunichar2
*name G_GNUC_UNUSED
)
203 struct _WapiHandle_namedsem namedsem_handle
= {{{0}}, 0};
211 /* w32 seems to guarantee that opening named objects can't
214 thr_ret
= _wapi_namespace_lock ();
215 g_assert (thr_ret
== 0);
217 /* Need to blow away any old errors here, because code tests
218 * for ERROR_ALREADY_EXISTS on success (!) to see if a
219 * semaphore was freshly created
221 SetLastError (ERROR_SUCCESS
);
223 utf8_name
= g_utf16_to_utf8 (name
, -1, NULL
, NULL
, NULL
);
225 DEBUG ("%s: Creating named sem [%s]", __func__
, utf8_name
);
227 offset
= _wapi_search_handle_namespace (WAPI_HANDLE_NAMEDSEM
,
230 /* The name has already been used for a different
233 SetLastError (ERROR_INVALID_HANDLE
);
235 } else if (offset
!= 0) {
236 /* Not an error, but this is how the caller is
237 * informed that the semaphore wasn't freshly created
239 SetLastError (ERROR_ALREADY_EXISTS
);
241 /* Fall through to create the semaphore handle */
244 /* A new named semaphore, so create both the private
247 if (strlen (utf8_name
) < MAX_PATH
) {
248 namelen
= strlen (utf8_name
);
253 memcpy (&namedsem_handle
.sharedns
.name
, utf8_name
, namelen
);
255 namedsem_handle
.val
= initial
;
256 namedsem_handle
.max
= max
;
258 handle
= _wapi_handle_new (WAPI_HANDLE_NAMEDSEM
,
261 /* A new reference to an existing named semaphore, so
262 * just create the private part
264 handle
= _wapi_handle_new_from_offset (WAPI_HANDLE_NAMEDSEM
,
268 if (handle
== _WAPI_HANDLE_INVALID
) {
269 g_warning ("%s: error creating named sem handle", __func__
);
270 SetLastError (ERROR_GEN_FAILURE
);
276 /* Set the initial state, as this is a completely new
279 thr_ret
= _wapi_handle_lock_shared_handles ();
280 g_assert (thr_ret
== 0);
283 _wapi_shared_handle_set_signal_state (handle
, TRUE
);
286 _wapi_handle_unlock_shared_handles ();
289 DEBUG ("%s: returning named sem handle %p", __func__
, handle
);
294 _wapi_namespace_unlock (NULL
);
302 * @security: Ignored for now.
303 * @initial: The initial count for the semaphore. The value must be
304 * greater than or equal to zero, and less than or equal to @max.
305 * @max: The maximum count for this semaphore. The value must be
307 * @name: Pointer to a string specifying the name of this semaphore,
308 * or %NULL. Currently ignored.
310 * Creates a new semaphore handle. A semaphore is signalled when its
311 * count is greater than zero, and unsignalled otherwise. The count
312 * is decreased by one whenever a wait function releases a thread that
313 * was waiting for the semaphore. The count is increased by calling
314 * ReleaseSemaphore().
316 * Return value: a new handle, or NULL
318 gpointer
CreateSemaphore(WapiSecurityAttributes
*security G_GNUC_UNUSED
, gint32 initial
, gint32 max
, const gunichar2
*name
)
320 mono_once (&sem_ops_once
, sem_ops_init
);
323 DEBUG ("%s: max <= 0", __func__
);
325 SetLastError (ERROR_INVALID_PARAMETER
);
329 if (initial
> max
|| initial
< 0) {
330 DEBUG ("%s: initial>max or < 0", __func__
);
332 SetLastError (ERROR_INVALID_PARAMETER
);
337 return (sem_create (security
, initial
, max
));
339 return (namedsem_create (security
, initial
, max
, name
));
343 static gboolean
sem_release (gpointer handle
, gint32 count
, gint32
*prevcount
)
345 struct _WapiHandle_sem
*sem_handle
;
350 ok
= _wapi_lookup_handle (handle
, WAPI_HANDLE_SEM
,
351 (gpointer
*)&sem_handle
);
353 g_warning ("%s: error looking up sem handle %p", __func__
,
358 thr_ret
= _wapi_handle_lock_handle (handle
);
359 g_assert (thr_ret
== 0);
361 DEBUG ("%s: sem %p val %d count %d", __func__
, handle
,
362 sem_handle
->val
, count
);
364 /* Do this before checking for count overflow, because overflowing max
365 * is a listed technique for finding the current value
367 if (prevcount
!= NULL
) {
368 *prevcount
= sem_handle
->val
;
371 /* No idea why max is signed, but thats the spec :-( */
372 if (sem_handle
->val
+ count
> (guint32
)sem_handle
->max
) {
373 DEBUG ("%s: sem %p max value would be exceeded: max %d current %d count %d", __func__
, handle
, sem_handle
->max
, sem_handle
->val
, count
);
378 sem_handle
->val
+= count
;
379 _wapi_handle_set_signal_state (handle
, TRUE
, TRUE
);
383 DEBUG ("%s: sem %p val now %d", __func__
, handle
, sem_handle
->val
);
386 thr_ret
= _wapi_handle_unlock_handle (handle
);
387 g_assert (thr_ret
== 0);
392 static gboolean
namedsem_release (gpointer handle
, gint32 count
,
395 struct _WapiHandle_namedsem
*sem_handle
;
400 ok
= _wapi_lookup_handle (handle
, WAPI_HANDLE_NAMEDSEM
,
401 (gpointer
*)&sem_handle
);
403 g_warning ("%s: error looking up sem handle %p", __func__
,
408 thr_ret
= _wapi_handle_lock_shared_handles ();
409 g_assert (thr_ret
== 0);
411 DEBUG("%s: named sem %p val %d count %d", __func__
, handle
,
412 sem_handle
->val
, count
);
414 /* Do this before checking for count overflow, because overflowing max
415 * is a listed technique for finding the current value
417 if (prevcount
!= NULL
) {
418 *prevcount
= sem_handle
->val
;
421 /* No idea why max is signed, but thats the spec :-( */
422 if (sem_handle
->val
+ count
> (guint32
)sem_handle
->max
) {
423 DEBUG ("%s: named sem %p max value would be exceeded: max %d current %d count %d", __func__
, handle
, sem_handle
->max
, sem_handle
->val
, count
);
428 sem_handle
->val
+= count
;
429 _wapi_shared_handle_set_signal_state (handle
, TRUE
);
433 DEBUG("%s: named sem %p val now %d", __func__
, handle
,
437 _wapi_handle_unlock_shared_handles ();
444 * @handle: The semaphore handle to release.
445 * @count: The amount by which the semaphore's count should be
447 * @prevcount: Pointer to a location to store the previous count of
448 * the semaphore, or %NULL.
450 * Increases the count of semaphore @handle by @count.
452 * Return value: %TRUE on success, %FALSE otherwise.
454 gboolean
ReleaseSemaphore(gpointer handle
, gint32 count
, gint32
*prevcount
)
458 if (handle
== NULL
) {
459 SetLastError (ERROR_INVALID_HANDLE
);
463 type
= _wapi_handle_type (handle
);
465 if (sem_ops
[type
].release
== NULL
) {
466 SetLastError (ERROR_INVALID_HANDLE
);
470 return (sem_ops
[type
].release (handle
, count
, prevcount
));
473 gpointer
OpenSemaphore (guint32 access G_GNUC_UNUSED
, gboolean inherit G_GNUC_UNUSED
,
474 const gunichar2
*name
)
482 mono_once (&sem_ops_once
, sem_ops_init
);
484 /* w32 seems to guarantee that opening named objects can't
487 thr_ret
= _wapi_namespace_lock ();
488 g_assert (thr_ret
== 0);
490 utf8_name
= g_utf16_to_utf8 (name
, -1, NULL
, NULL
, NULL
);
492 DEBUG ("%s: Opening named sem [%s]", __func__
, utf8_name
);
494 offset
= _wapi_search_handle_namespace (WAPI_HANDLE_NAMEDSEM
,
497 /* The name has already been used for a different
500 SetLastError (ERROR_INVALID_HANDLE
);
502 } else if (offset
== 0) {
503 /* This name doesn't exist */
504 SetLastError (ERROR_FILE_NOT_FOUND
); /* yes, really */
508 /* A new reference to an existing named semaphore, so just
509 * create the private part
511 handle
= _wapi_handle_new_from_offset (WAPI_HANDLE_NAMEDSEM
, offset
,
514 if (handle
== _WAPI_HANDLE_INVALID
) {
515 g_warning ("%s: error opening named sem handle", __func__
);
516 SetLastError (ERROR_GEN_FAILURE
);
521 DEBUG ("%s: returning named sem handle %p", __func__
, handle
);
526 _wapi_namespace_unlock (NULL
);