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/handles-private.h>
23 #include <mono/io-layer/semaphore-private.h>
24 #include <mono/io-layer/io-trace.h>
25 #include <mono/utils/mono-once.h>
26 #include <mono/utils/mono-logger-internals.h>
28 static void sema_signal(gpointer handle);
29 static gboolean sema_own (gpointer handle);
31 static void namedsema_signal (gpointer handle);
32 static gboolean namedsema_own (gpointer handle);
34 struct _WapiHandleOps _wapi_sem_ops = {
36 sema_signal, /* signal */
39 NULL, /* special_wait */
43 void _wapi_sem_details (gpointer handle_info)
45 struct _WapiHandle_sem *sem = (struct _WapiHandle_sem *)handle_info;
47 g_print ("val: %5u, max: %5d", sem->val, sem->max);
50 struct _WapiHandleOps _wapi_namedsem_ops = {
52 namedsema_signal, /* signal */
53 namedsema_own, /* own */
55 NULL, /* special_wait */
59 static gboolean sem_release (gpointer handle, gint32 count, gint32 *prev);
60 static gboolean namedsem_release (gpointer handle, gint32 count, gint32 *prev);
64 gboolean (*release)(gpointer handle, gint32 count, gint32 *prev);
65 } sem_ops[WAPI_HANDLE_COUNT] = {
81 static mono_once_t sem_ops_once=MONO_ONCE_INIT;
83 static void sem_ops_init (void)
85 _wapi_handle_register_capabilities (WAPI_HANDLE_SEM,
86 (WapiHandleCapability)(WAPI_HANDLE_CAP_WAIT | WAPI_HANDLE_CAP_SIGNAL));
87 _wapi_handle_register_capabilities (WAPI_HANDLE_NAMEDSEM,
88 (WapiHandleCapability)(WAPI_HANDLE_CAP_WAIT | WAPI_HANDLE_CAP_SIGNAL));
91 static void sema_signal(gpointer handle)
93 ReleaseSemaphore(handle, 1, NULL);
96 static gboolean sema_own (gpointer handle)
98 struct _WapiHandle_sem *sem_handle;
101 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_SEM,
102 (gpointer *)&sem_handle);
104 g_warning ("%s: error looking up sem handle %p", __func__,
109 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: owning sem handle %p", __func__, handle);
113 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: sem %p val now %d", __func__, handle, sem_handle->val);
115 if(sem_handle->val==0) {
116 _wapi_handle_set_signal_state (handle, FALSE, FALSE);
122 static void namedsema_signal (gpointer handle)
124 ReleaseSemaphore (handle, 1, NULL);
127 /* NB, always called with the shared handle lock held */
128 static gboolean namedsema_own (gpointer handle)
130 struct _WapiHandle_namedsem *namedsem_handle;
133 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: owning named sem handle %p", __func__, handle);
135 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDSEM,
136 (gpointer *)&namedsem_handle);
138 g_warning ("%s: error looking up named sem handle %p",
143 namedsem_handle->val--;
145 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: named sem %p val now %d", __func__, handle,
146 namedsem_handle->val);
148 if (namedsem_handle->val == 0) {
149 _wapi_shared_handle_set_signal_state (handle, FALSE);
154 static gpointer sem_create (WapiSecurityAttributes *security G_GNUC_UNUSED,
155 gint32 initial, gint32 max)
157 struct _WapiHandle_sem sem_handle = {0};
161 /* Need to blow away any old errors here, because code tests
162 * for ERROR_ALREADY_EXISTS on success (!) to see if a
163 * semaphore was freshly created
165 SetLastError (ERROR_SUCCESS);
167 sem_handle.val = initial;
168 sem_handle.max = max;
170 handle = _wapi_handle_new (WAPI_HANDLE_SEM, &sem_handle);
171 if (handle == _WAPI_HANDLE_INVALID) {
172 g_warning ("%s: error creating semaphore handle", __func__);
173 SetLastError (ERROR_GEN_FAILURE);
177 thr_ret = _wapi_handle_lock_handle (handle);
178 g_assert (thr_ret == 0);
181 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
184 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Created semaphore handle %p initial %d max %d",
185 __func__, handle, initial, max);
187 thr_ret = _wapi_handle_unlock_handle (handle);
188 g_assert (thr_ret == 0);
193 static gpointer namedsem_create (WapiSecurityAttributes *security G_GNUC_UNUSED, gint32 initial, gint32 max, const gunichar2 *name G_GNUC_UNUSED)
195 struct _WapiHandle_namedsem namedsem_handle = {{{0}}, 0};
203 /* w32 seems to guarantee that opening named objects can't
206 thr_ret = _wapi_namespace_lock ();
207 g_assert (thr_ret == 0);
209 /* Need to blow away any old errors here, because code tests
210 * for ERROR_ALREADY_EXISTS on success (!) to see if a
211 * semaphore was freshly created
213 SetLastError (ERROR_SUCCESS);
215 utf8_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
217 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Creating named sem [%s]", __func__, utf8_name);
219 offset = _wapi_search_handle_namespace (WAPI_HANDLE_NAMEDSEM,
222 /* The name has already been used for a different
225 SetLastError (ERROR_INVALID_HANDLE);
227 } else if (offset != 0) {
228 /* Not an error, but this is how the caller is
229 * informed that the semaphore wasn't freshly created
231 SetLastError (ERROR_ALREADY_EXISTS);
233 /* Fall through to create the semaphore handle */
236 /* A new named semaphore, so create both the private
239 if (strlen (utf8_name) < MAX_PATH) {
240 namelen = strlen (utf8_name);
245 memcpy (&namedsem_handle.sharedns.name, utf8_name, namelen);
247 namedsem_handle.val = initial;
248 namedsem_handle.max = max;
250 handle = _wapi_handle_new (WAPI_HANDLE_NAMEDSEM,
253 /* A new reference to an existing named semaphore, so
254 * just create the private part
256 handle = _wapi_handle_new_from_offset (WAPI_HANDLE_NAMEDSEM,
260 if (handle == _WAPI_HANDLE_INVALID) {
261 g_warning ("%s: error creating named sem handle", __func__);
262 SetLastError (ERROR_GEN_FAILURE);
268 /* Set the initial state, as this is a completely new
271 thr_ret = _wapi_handle_lock_shared_handles ();
272 g_assert (thr_ret == 0);
275 _wapi_shared_handle_set_signal_state (handle, TRUE);
278 _wapi_handle_unlock_shared_handles ();
281 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning named sem handle %p", __func__, handle);
286 _wapi_namespace_unlock (NULL);
294 * @security: Ignored for now.
295 * @initial: The initial count for the semaphore. The value must be
296 * greater than or equal to zero, and less than or equal to @max.
297 * @max: The maximum count for this semaphore. The value must be
299 * @name: Pointer to a string specifying the name of this semaphore,
300 * or %NULL. Currently ignored.
302 * Creates a new semaphore handle. A semaphore is signalled when its
303 * count is greater than zero, and unsignalled otherwise. The count
304 * is decreased by one whenever a wait function releases a thread that
305 * was waiting for the semaphore. The count is increased by calling
306 * ReleaseSemaphore().
308 * Return value: a new handle, or NULL
310 gpointer CreateSemaphore(WapiSecurityAttributes *security G_GNUC_UNUSED, gint32 initial, gint32 max, const gunichar2 *name)
312 mono_once (&sem_ops_once, sem_ops_init);
315 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: max <= 0", __func__);
317 SetLastError (ERROR_INVALID_PARAMETER);
321 if (initial > max || initial < 0) {
322 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: initial>max or < 0", __func__);
324 SetLastError (ERROR_INVALID_PARAMETER);
329 return (sem_create (security, initial, max));
331 return (namedsem_create (security, initial, max, name));
335 static gboolean sem_release (gpointer handle, gint32 count, gint32 *prevcount)
337 struct _WapiHandle_sem *sem_handle;
342 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_SEM,
343 (gpointer *)&sem_handle);
345 g_warning ("%s: error looking up sem handle %p", __func__,
350 thr_ret = _wapi_handle_lock_handle (handle);
351 g_assert (thr_ret == 0);
353 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: sem %p val %d count %d", __func__, handle,
354 sem_handle->val, count);
356 /* Do this before checking for count overflow, because overflowing max
357 * is a listed technique for finding the current value
359 if (prevcount != NULL) {
360 *prevcount = sem_handle->val;
363 /* No idea why max is signed, but thats the spec :-( */
364 if (sem_handle->val + count > (guint32)sem_handle->max) {
365 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: sem %p max value would be exceeded: max %d current %d count %d", __func__, handle, sem_handle->max, sem_handle->val, count);
370 sem_handle->val += count;
371 _wapi_handle_set_signal_state (handle, TRUE, TRUE);
375 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: sem %p val now %d", __func__, handle, sem_handle->val);
378 thr_ret = _wapi_handle_unlock_handle (handle);
379 g_assert (thr_ret == 0);
384 static gboolean namedsem_release (gpointer handle, gint32 count,
387 struct _WapiHandle_namedsem *sem_handle;
392 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDSEM,
393 (gpointer *)&sem_handle);
395 g_warning ("%s: error looking up sem handle %p", __func__,
400 thr_ret = _wapi_handle_lock_shared_handles ();
401 g_assert (thr_ret == 0);
403 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: named sem %p val %d count %d", __func__, handle,
404 sem_handle->val, count);
406 /* Do this before checking for count overflow, because overflowing max
407 * is a listed technique for finding the current value
409 if (prevcount != NULL) {
410 *prevcount = sem_handle->val;
413 /* No idea why max is signed, but thats the spec :-( */
414 if (sem_handle->val + count > (guint32)sem_handle->max) {
415 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: named sem %p max value would be exceeded: max %d current %d count %d", __func__, handle, sem_handle->max, sem_handle->val, count);
420 sem_handle->val += count;
421 _wapi_shared_handle_set_signal_state (handle, TRUE);
425 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: named sem %p val now %d", __func__, handle,
429 _wapi_handle_unlock_shared_handles ();
436 * @handle: The semaphore handle to release.
437 * @count: The amount by which the semaphore's count should be
439 * @prevcount: Pointer to a location to store the previous count of
440 * the semaphore, or %NULL.
442 * Increases the count of semaphore @handle by @count.
444 * Return value: %TRUE on success, %FALSE otherwise.
446 gboolean ReleaseSemaphore(gpointer handle, gint32 count, gint32 *prevcount)
450 if (handle == NULL) {
451 SetLastError (ERROR_INVALID_HANDLE);
455 type = _wapi_handle_type (handle);
457 if (sem_ops[type].release == NULL) {
458 SetLastError (ERROR_INVALID_HANDLE);
462 return (sem_ops[type].release (handle, count, prevcount));
465 gpointer OpenSemaphore (guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED,
466 const gunichar2 *name)
474 mono_once (&sem_ops_once, sem_ops_init);
476 /* w32 seems to guarantee that opening named objects can't
479 thr_ret = _wapi_namespace_lock ();
480 g_assert (thr_ret == 0);
482 utf8_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
484 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Opening named sem [%s]", __func__, utf8_name);
486 offset = _wapi_search_handle_namespace (WAPI_HANDLE_NAMEDSEM,
489 /* The name has already been used for a different
492 SetLastError (ERROR_INVALID_HANDLE);
494 } else if (offset == 0) {
495 /* This name doesn't exist */
496 SetLastError (ERROR_FILE_NOT_FOUND); /* yes, really */
500 /* A new reference to an existing named semaphore, so just
501 * create the private part
503 handle = _wapi_handle_new_from_offset (WAPI_HANDLE_NAMEDSEM, offset,
506 if (handle == _WAPI_HANDLE_INVALID) {
507 g_warning ("%s: error opening named sem handle", __func__);
508 SetLastError (ERROR_GEN_FAILURE);
513 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning named sem handle %p", __func__, handle);
518 _wapi_namespace_unlock (NULL);