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/mono-mutex.h>
25 #include <mono/io-layer/semaphore-private.h>
29 static void sema_signal(gpointer handle
);
30 static gboolean
sema_own (gpointer handle
);
32 static void namedsema_signal (gpointer handle
);
33 static gboolean
namedsema_own (gpointer handle
);
35 struct _WapiHandleOps _wapi_sem_ops
= {
37 sema_signal
, /* signal */
40 NULL
, /* special_wait */
44 void _wapi_sem_details (gpointer handle_info
)
46 struct _WapiHandle_sem
*sem
= (struct _WapiHandle_sem
*)handle_info
;
48 g_print ("val: %5u, max: %5d", sem
->val
, sem
->max
);
51 struct _WapiHandleOps _wapi_namedsem_ops
= {
53 namedsema_signal
, /* signal */
54 namedsema_own
, /* own */
56 NULL
, /* special_wait */
60 static gboolean
sem_release (gpointer handle
, gint32 count
, gint32
*prev
);
61 static gboolean
namedsem_release (gpointer handle
, gint32 count
, gint32
*prev
);
65 gboolean (*release
)(gpointer handle
, gint32 count
, gint32
*prev
);
66 } sem_ops
[WAPI_HANDLE_COUNT
] = {
82 static mono_once_t sem_ops_once
=MONO_ONCE_INIT
;
84 static void sem_ops_init (void)
86 _wapi_handle_register_capabilities (WAPI_HANDLE_SEM
,
87 WAPI_HANDLE_CAP_WAIT
|
88 WAPI_HANDLE_CAP_SIGNAL
);
89 _wapi_handle_register_capabilities (WAPI_HANDLE_NAMEDSEM
,
90 WAPI_HANDLE_CAP_WAIT
|
91 WAPI_HANDLE_CAP_SIGNAL
);
94 static void sema_signal(gpointer handle
)
96 ReleaseSemaphore(handle
, 1, NULL
);
99 static gboolean
sema_own (gpointer handle
)
101 struct _WapiHandle_sem
*sem_handle
;
104 ok
=_wapi_lookup_handle (handle
, WAPI_HANDLE_SEM
,
105 (gpointer
*)&sem_handle
);
107 g_warning ("%s: error looking up sem handle %p", __func__
,
113 g_message("%s: owning sem handle %p", __func__
, handle
);
119 g_message ("%s: sem %p val now %d", __func__
, handle
, sem_handle
->val
);
122 if(sem_handle
->val
==0) {
123 _wapi_handle_set_signal_state (handle
, FALSE
, FALSE
);
129 static void namedsema_signal (gpointer handle
)
131 ReleaseSemaphore (handle
, 1, NULL
);
134 /* NB, always called with the shared handle lock held */
135 static gboolean
namedsema_own (gpointer handle
)
137 struct _WapiHandle_namedsem
*namedsem_handle
;
141 g_message ("%s: owning named sem handle %p", __func__
, handle
);
144 ok
= _wapi_lookup_handle (handle
, WAPI_HANDLE_NAMEDSEM
,
145 (gpointer
*)&namedsem_handle
);
147 g_warning ("%s: error looking up named sem handle %p",
152 namedsem_handle
->val
--;
155 g_message ("%s: named sem %p val now %d", __func__
, handle
,
156 namedsem_handle
->val
);
159 if (namedsem_handle
->val
== 0) {
160 _wapi_shared_handle_set_signal_state (handle
, FALSE
);
165 static gpointer
sem_create (WapiSecurityAttributes
*security G_GNUC_UNUSED
,
166 gint32 initial
, gint32 max
)
168 struct _WapiHandle_sem sem_handle
= {0};
172 /* Need to blow away any old errors here, because code tests
173 * for ERROR_ALREADY_EXISTS on success (!) to see if a
174 * semaphore was freshly created
176 SetLastError (ERROR_SUCCESS
);
178 sem_handle
.val
= initial
;
179 sem_handle
.max
= max
;
181 handle
= _wapi_handle_new (WAPI_HANDLE_SEM
, &sem_handle
);
182 if (handle
== _WAPI_HANDLE_INVALID
) {
183 g_warning ("%s: error creating semaphore handle", __func__
);
184 SetLastError (ERROR_GEN_FAILURE
);
188 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle
,
190 thr_ret
= _wapi_handle_lock_handle (handle
);
191 g_assert (thr_ret
== 0);
194 _wapi_handle_set_signal_state (handle
, TRUE
, FALSE
);
198 g_message ("%s: Created semaphore handle %p initial %d max %d",
199 __func__
, handle
, initial
, max
);
202 thr_ret
= _wapi_handle_unlock_handle (handle
);
203 g_assert (thr_ret
== 0);
204 pthread_cleanup_pop (0);
209 static gpointer
namedsem_create (WapiSecurityAttributes
*security G_GNUC_UNUSED
, gint32 initial
, gint32 max
, const gunichar2
*name G_GNUC_UNUSED
)
211 struct _WapiHandle_namedsem namedsem_handle
= {{{0}}, 0};
219 /* w32 seems to guarantee that opening named objects can't
222 thr_ret
= _wapi_namespace_lock ();
223 g_assert (thr_ret
== 0);
225 /* Need to blow away any old errors here, because code tests
226 * for ERROR_ALREADY_EXISTS on success (!) to see if a
227 * semaphore was freshly created
229 SetLastError (ERROR_SUCCESS
);
231 utf8_name
= g_utf16_to_utf8 (name
, -1, NULL
, NULL
, NULL
);
234 g_message ("%s: Creating named sem [%s]", __func__
, utf8_name
);
237 offset
= _wapi_search_handle_namespace (WAPI_HANDLE_NAMEDSEM
,
240 /* The name has already been used for a different
243 SetLastError (ERROR_INVALID_HANDLE
);
245 } else if (offset
!= 0) {
246 /* Not an error, but this is how the caller is
247 * informed that the semaphore wasn't freshly created
249 SetLastError (ERROR_ALREADY_EXISTS
);
251 /* Fall through to create the semaphore handle */
254 /* A new named semaphore, so create both the private
257 if (strlen (utf8_name
) < MAX_PATH
) {
258 namelen
= strlen (utf8_name
);
263 memcpy (&namedsem_handle
.sharedns
.name
, utf8_name
, namelen
);
265 namedsem_handle
.val
= initial
;
266 namedsem_handle
.max
= max
;
268 handle
= _wapi_handle_new (WAPI_HANDLE_NAMEDSEM
,
271 /* A new reference to an existing named semaphore, so
272 * just create the private part
274 handle
= _wapi_handle_new_from_offset (WAPI_HANDLE_NAMEDSEM
,
278 if (handle
== _WAPI_HANDLE_INVALID
) {
279 g_warning ("%s: error creating named sem handle", __func__
);
280 SetLastError (ERROR_GEN_FAILURE
);
286 /* Set the initial state, as this is a completely new
289 thr_ret
= _wapi_handle_lock_shared_handles ();
290 g_assert (thr_ret
== 0);
293 _wapi_shared_handle_set_signal_state (handle
, TRUE
);
296 _wapi_handle_unlock_shared_handles ();
300 g_message ("%s: returning named sem handle %p", __func__
, handle
);
306 _wapi_namespace_unlock (NULL
);
314 * @security: Ignored for now.
315 * @initial: The initial count for the semaphore. The value must be
316 * greater than or equal to zero, and less than or equal to @max.
317 * @max: The maximum count for this semaphore. The value must be
319 * @name: Pointer to a string specifying the name of this semaphore,
320 * or %NULL. Currently ignored.
322 * Creates a new semaphore handle. A semaphore is signalled when its
323 * count is greater than zero, and unsignalled otherwise. The count
324 * is decreased by one whenever a wait function releases a thread that
325 * was waiting for the semaphore. The count is increased by calling
326 * ReleaseSemaphore().
328 * Return value: a new handle, or NULL
330 gpointer
CreateSemaphore(WapiSecurityAttributes
*security G_GNUC_UNUSED
, gint32 initial
, gint32 max
, const gunichar2
*name
)
332 mono_once (&sem_ops_once
, sem_ops_init
);
336 g_message ("%s: max <= 0", __func__
);
339 SetLastError (ERROR_INVALID_PARAMETER
);
343 if (initial
> max
|| initial
< 0) {
345 g_message ("%s: initial>max or < 0", __func__
);
348 SetLastError (ERROR_INVALID_PARAMETER
);
353 return (sem_create (security
, initial
, max
));
355 return (namedsem_create (security
, initial
, max
, name
));
359 static gboolean
sem_release (gpointer handle
, gint32 count
, gint32
*prevcount
)
361 struct _WapiHandle_sem
*sem_handle
;
366 ok
= _wapi_lookup_handle (handle
, WAPI_HANDLE_SEM
,
367 (gpointer
*)&sem_handle
);
369 g_warning ("%s: error looking up sem handle %p", __func__
,
374 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle
,
376 thr_ret
= _wapi_handle_lock_handle (handle
);
377 g_assert (thr_ret
== 0);
380 g_message ("%s: sem %p val %d count %d", __func__
, handle
,
381 sem_handle
->val
, count
);
384 /* Do this before checking for count overflow, because overflowing max
385 * is a listed technique for finding the current value
387 if (prevcount
!= NULL
) {
388 *prevcount
= sem_handle
->val
;
391 /* No idea why max is signed, but thats the spec :-( */
392 if (sem_handle
->val
+ count
> (guint32
)sem_handle
->max
) {
394 g_message ("%s: sem %p max value would be exceeded: max %d current %d count %d", __func__
, handle
, sem_handle
->max
, sem_handle
->val
, count
);
400 sem_handle
->val
+= count
;
401 _wapi_handle_set_signal_state (handle
, TRUE
, TRUE
);
406 g_message ("%s: sem %p val now %d", __func__
, handle
, sem_handle
->val
);
410 thr_ret
= _wapi_handle_unlock_handle (handle
);
411 g_assert (thr_ret
== 0);
412 pthread_cleanup_pop (0);
417 static gboolean
namedsem_release (gpointer handle
, gint32 count
,
420 struct _WapiHandle_namedsem
*sem_handle
;
425 ok
= _wapi_lookup_handle (handle
, WAPI_HANDLE_NAMEDSEM
,
426 (gpointer
*)&sem_handle
);
428 g_warning ("%s: error looking up sem handle %p", __func__
,
433 thr_ret
= _wapi_handle_lock_shared_handles ();
434 g_assert (thr_ret
== 0);
437 g_message("%s: named sem %p val %d count %d", __func__
, handle
,
438 sem_handle
->val
, count
);
441 /* Do this before checking for count overflow, because overflowing max
442 * is a listed technique for finding the current value
444 if (prevcount
!= NULL
) {
445 *prevcount
= sem_handle
->val
;
448 /* No idea why max is signed, but thats the spec :-( */
449 if (sem_handle
->val
+ count
> (guint32
)sem_handle
->max
) {
451 g_message ("%s: named sem %p max value would be exceeded: max %d current %d count %d", __func__
, handle
, sem_handle
->max
, sem_handle
->val
, count
);
457 sem_handle
->val
+= count
;
458 _wapi_shared_handle_set_signal_state (handle
, TRUE
);
463 g_message("%s: named sem %p val now %d", __func__
, handle
,
468 _wapi_handle_unlock_shared_handles ();
475 * @handle: The semaphore handle to release.
476 * @count: The amount by which the semaphore's count should be
478 * @prevcount: Pointer to a location to store the previous count of
479 * the semaphore, or %NULL.
481 * Increases the count of semaphore @handle by @count.
483 * Return value: %TRUE on success, %FALSE otherwise.
485 gboolean
ReleaseSemaphore(gpointer handle
, gint32 count
, gint32
*prevcount
)
489 if (handle
== NULL
) {
490 SetLastError (ERROR_INVALID_HANDLE
);
494 type
= _wapi_handle_type (handle
);
496 if (sem_ops
[type
].release
== NULL
) {
497 SetLastError (ERROR_INVALID_HANDLE
);
501 return (sem_ops
[type
].release (handle
, count
, prevcount
));
504 gpointer
OpenSemaphore (guint32 access G_GNUC_UNUSED
, gboolean inherit G_GNUC_UNUSED
,
505 const gunichar2
*name
)
513 mono_once (&sem_ops_once
, sem_ops_init
);
515 /* w32 seems to guarantee that opening named objects can't
518 thr_ret
= _wapi_namespace_lock ();
519 g_assert (thr_ret
== 0);
521 utf8_name
= g_utf16_to_utf8 (name
, -1, NULL
, NULL
, NULL
);
524 g_message ("%s: Opening named sem [%s]", __func__
, utf8_name
);
527 offset
= _wapi_search_handle_namespace (WAPI_HANDLE_NAMEDSEM
,
530 /* The name has already been used for a different
533 SetLastError (ERROR_INVALID_HANDLE
);
535 } else if (offset
== 0) {
536 /* This name doesn't exist */
537 SetLastError (ERROR_FILE_NOT_FOUND
); /* yes, really */
541 /* A new reference to an existing named semaphore, so just
542 * create the private part
544 handle
= _wapi_handle_new_from_offset (WAPI_HANDLE_NAMEDSEM
, offset
,
547 if (handle
== _WAPI_HANDLE_INVALID
) {
548 g_warning ("%s: error opening named sem handle", __func__
);
549 SetLastError (ERROR_GEN_FAILURE
);
555 g_message ("%s: returning named sem handle %p", __func__
, handle
);
561 _wapi_namespace_unlock (NULL
);