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/utils/mono-once.h>
27 #define DEBUG(...) g_message(__VA_ARGS__)
32 static void sema_signal(gpointer handle);
33 static gboolean sema_own (gpointer handle);
35 static void namedsema_signal (gpointer handle);
36 static gboolean namedsema_own (gpointer handle);
38 struct _WapiHandleOps _wapi_sem_ops = {
40 sema_signal, /* signal */
43 NULL, /* special_wait */
47 void _wapi_sem_details (gpointer handle_info)
49 struct _WapiHandle_sem *sem = (struct _WapiHandle_sem *)handle_info;
51 g_print ("val: %5u, max: %5d", sem->val, sem->max);
54 struct _WapiHandleOps _wapi_namedsem_ops = {
56 namedsema_signal, /* signal */
57 namedsema_own, /* own */
59 NULL, /* special_wait */
63 static gboolean sem_release (gpointer handle, gint32 count, gint32 *prev);
64 static gboolean namedsem_release (gpointer handle, gint32 count, gint32 *prev);
68 gboolean (*release)(gpointer handle, gint32 count, gint32 *prev);
69 } sem_ops[WAPI_HANDLE_COUNT] = {
85 static mono_once_t sem_ops_once=MONO_ONCE_INIT;
87 static void sem_ops_init (void)
89 _wapi_handle_register_capabilities (WAPI_HANDLE_SEM,
90 (WapiHandleCapability)(WAPI_HANDLE_CAP_WAIT | WAPI_HANDLE_CAP_SIGNAL));
91 _wapi_handle_register_capabilities (WAPI_HANDLE_NAMEDSEM,
92 (WapiHandleCapability)(WAPI_HANDLE_CAP_WAIT | WAPI_HANDLE_CAP_SIGNAL));
95 static void sema_signal(gpointer handle)
97 ReleaseSemaphore(handle, 1, NULL);
100 static gboolean sema_own (gpointer handle)
102 struct _WapiHandle_sem *sem_handle;
105 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_SEM,
106 (gpointer *)&sem_handle);
108 g_warning ("%s: error looking up sem handle %p", __func__,
113 DEBUG("%s: owning sem handle %p", __func__, handle);
117 DEBUG ("%s: sem %p val now %d", __func__, handle, sem_handle->val);
119 if(sem_handle->val==0) {
120 _wapi_handle_set_signal_state (handle, FALSE, FALSE);
126 static void namedsema_signal (gpointer handle)
128 ReleaseSemaphore (handle, 1, NULL);
131 /* NB, always called with the shared handle lock held */
132 static gboolean namedsema_own (gpointer handle)
134 struct _WapiHandle_namedsem *namedsem_handle;
137 DEBUG ("%s: owning named sem handle %p", __func__, handle);
139 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDSEM,
140 (gpointer *)&namedsem_handle);
142 g_warning ("%s: error looking up named sem handle %p",
147 namedsem_handle->val--;
149 DEBUG ("%s: named sem %p val now %d", __func__, handle,
150 namedsem_handle->val);
152 if (namedsem_handle->val == 0) {
153 _wapi_shared_handle_set_signal_state (handle, FALSE);
158 static gpointer sem_create (WapiSecurityAttributes *security G_GNUC_UNUSED,
159 gint32 initial, gint32 max)
161 struct _WapiHandle_sem sem_handle = {0};
165 /* Need to blow away any old errors here, because code tests
166 * for ERROR_ALREADY_EXISTS on success (!) to see if a
167 * semaphore was freshly created
169 SetLastError (ERROR_SUCCESS);
171 sem_handle.val = initial;
172 sem_handle.max = max;
174 handle = _wapi_handle_new (WAPI_HANDLE_SEM, &sem_handle);
175 if (handle == _WAPI_HANDLE_INVALID) {
176 g_warning ("%s: error creating semaphore handle", __func__);
177 SetLastError (ERROR_GEN_FAILURE);
181 thr_ret = _wapi_handle_lock_handle (handle);
182 g_assert (thr_ret == 0);
185 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
188 DEBUG ("%s: Created semaphore handle %p initial %d max %d",
189 __func__, handle, initial, max);
191 thr_ret = _wapi_handle_unlock_handle (handle);
192 g_assert (thr_ret == 0);
197 static gpointer namedsem_create (WapiSecurityAttributes *security G_GNUC_UNUSED, gint32 initial, gint32 max, const gunichar2 *name G_GNUC_UNUSED)
199 struct _WapiHandle_namedsem namedsem_handle = {{{0}}, 0};
207 /* w32 seems to guarantee that opening named objects can't
210 thr_ret = _wapi_namespace_lock ();
211 g_assert (thr_ret == 0);
213 /* Need to blow away any old errors here, because code tests
214 * for ERROR_ALREADY_EXISTS on success (!) to see if a
215 * semaphore was freshly created
217 SetLastError (ERROR_SUCCESS);
219 utf8_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
221 DEBUG ("%s: Creating named sem [%s]", __func__, utf8_name);
223 offset = _wapi_search_handle_namespace (WAPI_HANDLE_NAMEDSEM,
226 /* The name has already been used for a different
229 SetLastError (ERROR_INVALID_HANDLE);
231 } else if (offset != 0) {
232 /* Not an error, but this is how the caller is
233 * informed that the semaphore wasn't freshly created
235 SetLastError (ERROR_ALREADY_EXISTS);
237 /* Fall through to create the semaphore handle */
240 /* A new named semaphore, so create both the private
243 if (strlen (utf8_name) < MAX_PATH) {
244 namelen = strlen (utf8_name);
249 memcpy (&namedsem_handle.sharedns.name, utf8_name, namelen);
251 namedsem_handle.val = initial;
252 namedsem_handle.max = max;
254 handle = _wapi_handle_new (WAPI_HANDLE_NAMEDSEM,
257 /* A new reference to an existing named semaphore, so
258 * just create the private part
260 handle = _wapi_handle_new_from_offset (WAPI_HANDLE_NAMEDSEM,
264 if (handle == _WAPI_HANDLE_INVALID) {
265 g_warning ("%s: error creating named sem handle", __func__);
266 SetLastError (ERROR_GEN_FAILURE);
272 /* Set the initial state, as this is a completely new
275 thr_ret = _wapi_handle_lock_shared_handles ();
276 g_assert (thr_ret == 0);
279 _wapi_shared_handle_set_signal_state (handle, TRUE);
282 _wapi_handle_unlock_shared_handles ();
285 DEBUG ("%s: returning named sem handle %p", __func__, handle);
290 _wapi_namespace_unlock (NULL);
298 * @security: Ignored for now.
299 * @initial: The initial count for the semaphore. The value must be
300 * greater than or equal to zero, and less than or equal to @max.
301 * @max: The maximum count for this semaphore. The value must be
303 * @name: Pointer to a string specifying the name of this semaphore,
304 * or %NULL. Currently ignored.
306 * Creates a new semaphore handle. A semaphore is signalled when its
307 * count is greater than zero, and unsignalled otherwise. The count
308 * is decreased by one whenever a wait function releases a thread that
309 * was waiting for the semaphore. The count is increased by calling
310 * ReleaseSemaphore().
312 * Return value: a new handle, or NULL
314 gpointer CreateSemaphore(WapiSecurityAttributes *security G_GNUC_UNUSED, gint32 initial, gint32 max, const gunichar2 *name)
316 mono_once (&sem_ops_once, sem_ops_init);
319 DEBUG ("%s: max <= 0", __func__);
321 SetLastError (ERROR_INVALID_PARAMETER);
325 if (initial > max || initial < 0) {
326 DEBUG ("%s: initial>max or < 0", __func__);
328 SetLastError (ERROR_INVALID_PARAMETER);
333 return (sem_create (security, initial, max));
335 return (namedsem_create (security, initial, max, name));
339 static gboolean sem_release (gpointer handle, gint32 count, gint32 *prevcount)
341 struct _WapiHandle_sem *sem_handle;
346 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_SEM,
347 (gpointer *)&sem_handle);
349 g_warning ("%s: error looking up sem handle %p", __func__,
354 thr_ret = _wapi_handle_lock_handle (handle);
355 g_assert (thr_ret == 0);
357 DEBUG ("%s: sem %p val %d count %d", __func__, handle,
358 sem_handle->val, count);
360 /* Do this before checking for count overflow, because overflowing max
361 * is a listed technique for finding the current value
363 if (prevcount != NULL) {
364 *prevcount = sem_handle->val;
367 /* No idea why max is signed, but thats the spec :-( */
368 if (sem_handle->val + count > (guint32)sem_handle->max) {
369 DEBUG ("%s: sem %p max value would be exceeded: max %d current %d count %d", __func__, handle, sem_handle->max, sem_handle->val, count);
374 sem_handle->val += count;
375 _wapi_handle_set_signal_state (handle, TRUE, TRUE);
379 DEBUG ("%s: sem %p val now %d", __func__, handle, sem_handle->val);
382 thr_ret = _wapi_handle_unlock_handle (handle);
383 g_assert (thr_ret == 0);
388 static gboolean namedsem_release (gpointer handle, gint32 count,
391 struct _WapiHandle_namedsem *sem_handle;
396 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDSEM,
397 (gpointer *)&sem_handle);
399 g_warning ("%s: error looking up sem handle %p", __func__,
404 thr_ret = _wapi_handle_lock_shared_handles ();
405 g_assert (thr_ret == 0);
407 DEBUG("%s: named sem %p val %d count %d", __func__, handle,
408 sem_handle->val, count);
410 /* Do this before checking for count overflow, because overflowing max
411 * is a listed technique for finding the current value
413 if (prevcount != NULL) {
414 *prevcount = sem_handle->val;
417 /* No idea why max is signed, but thats the spec :-( */
418 if (sem_handle->val + count > (guint32)sem_handle->max) {
419 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);
424 sem_handle->val += count;
425 _wapi_shared_handle_set_signal_state (handle, TRUE);
429 DEBUG("%s: named sem %p val now %d", __func__, handle,
433 _wapi_handle_unlock_shared_handles ();
440 * @handle: The semaphore handle to release.
441 * @count: The amount by which the semaphore's count should be
443 * @prevcount: Pointer to a location to store the previous count of
444 * the semaphore, or %NULL.
446 * Increases the count of semaphore @handle by @count.
448 * Return value: %TRUE on success, %FALSE otherwise.
450 gboolean ReleaseSemaphore(gpointer handle, gint32 count, gint32 *prevcount)
454 if (handle == NULL) {
455 SetLastError (ERROR_INVALID_HANDLE);
459 type = _wapi_handle_type (handle);
461 if (sem_ops[type].release == NULL) {
462 SetLastError (ERROR_INVALID_HANDLE);
466 return (sem_ops[type].release (handle, count, prevcount));
469 gpointer OpenSemaphore (guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED,
470 const gunichar2 *name)
478 mono_once (&sem_ops_once, sem_ops_init);
480 /* w32 seems to guarantee that opening named objects can't
483 thr_ret = _wapi_namespace_lock ();
484 g_assert (thr_ret == 0);
486 utf8_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
488 DEBUG ("%s: Opening named sem [%s]", __func__, utf8_name);
490 offset = _wapi_search_handle_namespace (WAPI_HANDLE_NAMEDSEM,
493 /* The name has already been used for a different
496 SetLastError (ERROR_INVALID_HANDLE);
498 } else if (offset == 0) {
499 /* This name doesn't exist */
500 SetLastError (ERROR_FILE_NOT_FOUND); /* yes, really */
504 /* A new reference to an existing named semaphore, so just
505 * create the private part
507 handle = _wapi_handle_new_from_offset (WAPI_HANDLE_NAMEDSEM, offset,
510 if (handle == _WAPI_HANDLE_INVALID) {
511 g_warning ("%s: error opening named sem handle", __func__);
512 SetLastError (ERROR_GEN_FAILURE);
517 DEBUG ("%s: returning named sem handle %p", __func__, handle);
522 _wapi_namespace_unlock (NULL);