2 * events.c: Event handles
5 * Dick Porter (dick@ximian.com)
7 * (C) 2002 Ximian, Inc.
15 #include <mono/io-layer/wapi.h>
16 #include <mono/io-layer/wapi-private.h>
17 #include <mono/io-layer/handles-private.h>
18 #include <mono/io-layer/misc-private.h>
20 #include <mono/io-layer/mono-mutex.h>
22 #include <mono/io-layer/event-private.h>
25 #define DEBUG(...) g_message(__VA_ARGS__)
30 static void event_signal(gpointer handle);
31 static gboolean event_own (gpointer handle);
33 static void namedevent_signal (gpointer handle);
34 static gboolean namedevent_own (gpointer handle);
36 struct _WapiHandleOps _wapi_event_ops = {
38 event_signal, /* signal */
41 NULL, /* special_wait */
45 struct _WapiHandleOps _wapi_namedevent_ops = {
47 namedevent_signal, /* signal */
48 namedevent_own, /* own */
52 static gboolean event_pulse (gpointer handle);
53 static gboolean event_reset (gpointer handle);
54 static gboolean event_set (gpointer handle);
56 static gboolean namedevent_pulse (gpointer handle);
57 static gboolean namedevent_reset (gpointer handle);
58 static gboolean namedevent_set (gpointer handle);
62 gboolean (*pulse)(gpointer handle);
63 gboolean (*reset)(gpointer handle);
64 gboolean (*set)(gpointer handle);
65 } event_ops[WAPI_HANDLE_COUNT] = {
72 {event_pulse, event_reset, event_set},
79 {namedevent_pulse, namedevent_reset, namedevent_set},
82 void _wapi_event_details (gpointer handle_info)
84 struct _WapiHandle_event *event = (struct _WapiHandle_event *)handle_info;
86 g_print ("manual: %s", event->manual?"TRUE":"FALSE");
89 static mono_once_t event_ops_once=MONO_ONCE_INIT;
91 static void event_ops_init (void)
93 _wapi_handle_register_capabilities (WAPI_HANDLE_EVENT,
94 WAPI_HANDLE_CAP_WAIT |
95 WAPI_HANDLE_CAP_SIGNAL);
96 _wapi_handle_register_capabilities (WAPI_HANDLE_NAMEDEVENT,
97 WAPI_HANDLE_CAP_WAIT |
98 WAPI_HANDLE_CAP_SIGNAL);
101 static void event_signal(gpointer handle)
106 static gboolean event_own (gpointer handle)
108 struct _WapiHandle_event *event_handle;
111 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_EVENT,
112 (gpointer *)&event_handle);
114 g_warning ("%s: error looking up event handle %p", __func__,
119 DEBUG("%s: owning event handle %p", __func__, handle);
121 if(event_handle->manual==FALSE) {
122 g_assert (event_handle->set_count > 0);
124 if (--event_handle->set_count == 0) {
125 _wapi_handle_set_signal_state (handle, FALSE, FALSE);
132 static void namedevent_signal (gpointer handle)
137 /* NB, always called with the shared handle lock held */
138 static gboolean namedevent_own (gpointer handle)
140 struct _WapiHandle_namedevent *namedevent_handle;
143 DEBUG ("%s: owning named event handle %p", __func__, handle);
145 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDEVENT,
146 (gpointer *)&namedevent_handle);
148 g_warning ("%s: error looking up named event handle %p",
153 if (namedevent_handle->manual == FALSE) {
154 g_assert (namedevent_handle->set_count > 0);
156 if (--namedevent_handle->set_count == 0) {
157 _wapi_shared_handle_set_signal_state (handle, FALSE);
163 static gpointer event_create (WapiSecurityAttributes *security G_GNUC_UNUSED,
164 gboolean manual, gboolean initial)
166 struct _WapiHandle_event event_handle = {0};
170 /* Need to blow away any old errors here, because code tests
171 * for ERROR_ALREADY_EXISTS on success (!) to see if an event
172 * was freshly created
174 SetLastError (ERROR_SUCCESS);
176 DEBUG ("%s: Creating unnamed event", __func__);
178 event_handle.manual = manual;
179 event_handle.set_count = 0;
181 if (initial == TRUE) {
182 if (manual == FALSE) {
183 event_handle.set_count = 1;
187 handle = _wapi_handle_new (WAPI_HANDLE_EVENT, &event_handle);
188 if (handle == _WAPI_HANDLE_INVALID) {
189 g_warning ("%s: error creating event handle", __func__);
190 SetLastError (ERROR_GEN_FAILURE);
194 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
196 thr_ret = _wapi_handle_lock_handle (handle);
197 g_assert (thr_ret == 0);
199 if (initial == TRUE) {
200 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
203 DEBUG("%s: created new event handle %p", __func__, handle);
205 thr_ret = _wapi_handle_unlock_handle (handle);
206 g_assert (thr_ret == 0);
207 pthread_cleanup_pop (0);
212 static gpointer namedevent_create (WapiSecurityAttributes *security G_GNUC_UNUSED,
213 gboolean manual, gboolean initial,
214 const gunichar2 *name G_GNUC_UNUSED)
216 struct _WapiHandle_namedevent namedevent_handle = {{{0}}, 0};
224 /* w32 seems to guarantee that opening named objects can't
227 thr_ret = _wapi_namespace_lock ();
228 g_assert (thr_ret == 0);
230 /* Need to blow away any old errors here, because code tests
231 * for ERROR_ALREADY_EXISTS on success (!) to see if an event
232 * was freshly created
234 SetLastError (ERROR_SUCCESS);
236 utf8_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
238 DEBUG ("%s: Creating named event [%s]", __func__, utf8_name);
240 offset = _wapi_search_handle_namespace (WAPI_HANDLE_NAMEDEVENT,
243 /* The name has already been used for a different
246 SetLastError (ERROR_INVALID_HANDLE);
248 } else if (offset != 0) {
249 /* Not an error, but this is how the caller is
250 * informed that the event wasn't freshly created
252 SetLastError (ERROR_ALREADY_EXISTS);
254 /* Fall through to create the event handle. */
257 /* A new named event, so create both the private and
261 if (strlen (utf8_name) < MAX_PATH) {
262 namelen = strlen (utf8_name);
267 memcpy (&namedevent_handle.sharedns.name, utf8_name, namelen);
269 namedevent_handle.manual = manual;
270 namedevent_handle.set_count = 0;
272 if (initial == TRUE) {
273 if (manual == FALSE) {
274 namedevent_handle.set_count = 1;
278 handle = _wapi_handle_new (WAPI_HANDLE_NAMEDEVENT,
281 /* A new reference to an existing named event, so just
282 * create the private part
284 handle = _wapi_handle_new_from_offset (WAPI_HANDLE_NAMEDEVENT,
288 if (handle == _WAPI_HANDLE_INVALID) {
289 g_warning ("%s: error creating event handle", __func__);
290 SetLastError (ERROR_GEN_FAILURE);
296 /* Set the initial state, as this is a completely new
299 thr_ret = _wapi_handle_lock_shared_handles ();
300 g_assert (thr_ret == 0);
302 if (initial == TRUE) {
303 _wapi_shared_handle_set_signal_state (handle, TRUE);
306 _wapi_handle_unlock_shared_handles ();
309 DEBUG ("%s: returning event handle %p", __func__, handle);
314 _wapi_namespace_unlock (NULL);
323 * @security: Ignored for now.
324 * @manual: Specifies whether the new event handle has manual or auto
326 * @initial: Specifies whether the new event handle is initially
328 * @name:Pointer to a string specifying the name of this name, or
329 * %NULL. Currently ignored.
331 * Creates a new event handle.
333 * An event handle is signalled with SetEvent(). If the new handle is
334 * a manual reset event handle, it remains signalled until it is reset
335 * with ResetEvent(). An auto reset event remains signalled until a
336 * single thread has waited for it, at which time the event handle is
337 * automatically reset to unsignalled.
339 * Return value: A new handle, or %NULL on error.
341 gpointer CreateEvent(WapiSecurityAttributes *security G_GNUC_UNUSED,
342 gboolean manual, gboolean initial,
343 const gunichar2 *name G_GNUC_UNUSED)
345 mono_once (&event_ops_once, event_ops_init);
348 return(event_create (security, manual, initial));
350 return(namedevent_create (security, manual, initial, name));
354 static gboolean event_pulse (gpointer handle)
356 struct _WapiHandle_event *event_handle;
360 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_EVENT,
361 (gpointer *)&event_handle);
363 g_warning ("%s: error looking up event handle %p", __func__,
368 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
370 thr_ret = _wapi_handle_lock_handle (handle);
371 g_assert (thr_ret == 0);
373 DEBUG ("%s: Pulsing event handle %p", __func__, handle);
375 if (event_handle->manual == TRUE) {
376 _wapi_handle_set_signal_state (handle, TRUE, TRUE);
378 event_handle->set_count = 1;
379 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
382 thr_ret = _wapi_handle_unlock_handle (handle);
383 g_assert (thr_ret == 0);
385 pthread_cleanup_pop (0);
387 if (event_handle->manual == TRUE) {
388 /* For a manual-reset event, we're about to try and
389 * get the handle lock again, so give other threads a
394 /* Reset the handle signal state */
395 /* I'm not sure whether or not we need a barrier here
396 * to make sure that all threads waiting on the event
397 * have proceeded. Currently we rely on broadcasting
400 DEBUG ("%s: Obtained write lock on event handle %p",
403 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle, handle);
404 thr_ret = _wapi_handle_lock_handle (handle);
405 g_assert (thr_ret == 0);
407 _wapi_handle_set_signal_state (handle, FALSE, FALSE);
409 thr_ret = _wapi_handle_unlock_handle (handle);
410 g_assert (thr_ret == 0);
411 pthread_cleanup_pop (0);
417 static gboolean namedevent_pulse (gpointer handle)
419 struct _WapiHandle_namedevent *namedevent_handle;
423 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDEVENT,
424 (gpointer *)&namedevent_handle);
426 g_warning ("%s: error looking up named event handle %p",
431 thr_ret = _wapi_handle_lock_shared_handles ();
432 g_assert (thr_ret == 0);
434 DEBUG ("%s: Pulsing named event handle %p", __func__, handle);
436 if (namedevent_handle->manual == TRUE) {
437 _wapi_shared_handle_set_signal_state (handle, TRUE);
439 namedevent_handle->set_count = 1;
440 _wapi_shared_handle_set_signal_state (handle, TRUE);
443 _wapi_handle_unlock_shared_handles ();
445 if (namedevent_handle->manual == TRUE) {
446 /* For a manual-reset event, we're about to try and
447 * get the handle lock again, so give other processes
450 _wapi_handle_spin (200);
452 /* Reset the handle signal state */
453 /* I'm not sure whether or not we need a barrier here
454 * to make sure that all threads waiting on the event
455 * have proceeded. Currently we rely on waiting for
456 * twice the shared handle poll interval.
458 DEBUG ("%s: Obtained write lock on event handle %p",
461 thr_ret = _wapi_handle_lock_shared_handles ();
462 g_assert (thr_ret == 0);
464 _wapi_shared_handle_set_signal_state (handle, FALSE);
466 _wapi_handle_unlock_shared_handles ();
474 * @handle: The event handle.
476 * Sets the event handle @handle to the signalled state, and then
477 * resets it to unsignalled after informing any waiting threads.
479 * If @handle is a manual reset event, all waiting threads that can be
480 * released immediately are released. @handle is then reset. If
481 * @handle is an auto reset event, one waiting thread is released even
482 * if multiple threads are waiting.
484 * Return value: %TRUE on success, %FALSE otherwise. (Currently only
485 * ever returns %TRUE).
487 gboolean PulseEvent(gpointer handle)
491 if (handle == NULL) {
492 SetLastError (ERROR_INVALID_HANDLE);
496 type = _wapi_handle_type (handle);
498 if (event_ops[type].pulse == NULL) {
499 SetLastError (ERROR_INVALID_HANDLE);
503 return(event_ops[type].pulse (handle));
506 static gboolean event_reset (gpointer handle)
508 struct _WapiHandle_event *event_handle;
512 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_EVENT,
513 (gpointer *)&event_handle);
515 g_warning ("%s: error looking up event handle %p",
520 DEBUG ("%s: Resetting event handle %p", __func__, handle);
522 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
524 thr_ret = _wapi_handle_lock_handle (handle);
525 g_assert (thr_ret == 0);
527 if (_wapi_handle_issignalled (handle) == FALSE) {
528 DEBUG ("%s: No need to reset event handle %p", __func__,
531 DEBUG ("%s: Obtained write lock on event handle %p",
534 _wapi_handle_set_signal_state (handle, FALSE, FALSE);
537 event_handle->set_count = 0;
539 thr_ret = _wapi_handle_unlock_handle (handle);
540 g_assert (thr_ret == 0);
542 pthread_cleanup_pop (0);
547 static gboolean namedevent_reset (gpointer handle)
549 struct _WapiHandle_namedevent *namedevent_handle;
553 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDEVENT,
554 (gpointer *)&namedevent_handle);
556 g_warning ("%s: error looking up named event handle %p",
561 DEBUG ("%s: Resetting named event handle %p", __func__, handle);
563 thr_ret = _wapi_handle_lock_shared_handles ();
564 g_assert (thr_ret == 0);
566 if (_wapi_handle_issignalled (handle) == FALSE) {
567 DEBUG ("%s: No need to reset named event handle %p",
570 DEBUG ("%s: Obtained write lock on named event handle %p",
573 _wapi_shared_handle_set_signal_state (handle, FALSE);
576 namedevent_handle->set_count = 0;
578 _wapi_handle_unlock_shared_handles ();
585 * @handle: The event handle.
587 * Resets the event handle @handle to the unsignalled state.
589 * Return value: %TRUE on success, %FALSE otherwise. (Currently only
590 * ever returns %TRUE).
592 gboolean ResetEvent(gpointer handle)
596 if (handle == NULL) {
597 SetLastError (ERROR_INVALID_HANDLE);
601 type = _wapi_handle_type (handle);
603 if (event_ops[type].reset == NULL) {
604 SetLastError (ERROR_INVALID_HANDLE);
608 return(event_ops[type].reset (handle));
611 static gboolean event_set (gpointer handle)
613 struct _WapiHandle_event *event_handle;
617 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_EVENT,
618 (gpointer *)&event_handle);
620 g_warning ("%s: error looking up event handle %p", __func__,
625 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
627 thr_ret = _wapi_handle_lock_handle (handle);
628 g_assert (thr_ret == 0);
630 DEBUG ("%s: Setting event handle %p", __func__, handle);
632 if (event_handle->manual == TRUE) {
633 _wapi_handle_set_signal_state (handle, TRUE, TRUE);
635 event_handle->set_count = 1;
636 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
639 thr_ret = _wapi_handle_unlock_handle (handle);
640 g_assert (thr_ret == 0);
642 pthread_cleanup_pop (0);
647 static gboolean namedevent_set (gpointer handle)
649 struct _WapiHandle_namedevent *namedevent_handle;
653 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDEVENT,
654 (gpointer *)&namedevent_handle);
656 g_warning ("%s: error looking up named event handle %p",
661 thr_ret = _wapi_handle_lock_shared_handles ();
662 g_assert (thr_ret == 0);
664 DEBUG ("%s: Setting named event handle %p", __func__, handle);
666 if (namedevent_handle->manual == TRUE) {
667 _wapi_shared_handle_set_signal_state (handle, TRUE);
669 namedevent_handle->set_count = 1;
670 _wapi_shared_handle_set_signal_state (handle, TRUE);
673 _wapi_handle_unlock_shared_handles ();
680 * @handle: The event handle
682 * Sets the event handle @handle to the signalled state.
684 * If @handle is a manual reset event, it remains signalled until it
685 * is reset with ResetEvent(). An auto reset event remains signalled
686 * until a single thread has waited for it, at which time @handle is
687 * automatically reset to unsignalled.
689 * Return value: %TRUE on success, %FALSE otherwise. (Currently only
690 * ever returns %TRUE).
692 gboolean SetEvent(gpointer handle)
696 if (handle == NULL) {
697 SetLastError (ERROR_INVALID_HANDLE);
701 type = _wapi_handle_type (handle);
703 if (event_ops[type].set == NULL) {
704 SetLastError (ERROR_INVALID_HANDLE);
708 return(event_ops[type].set (handle));
711 gpointer OpenEvent (guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, const gunichar2 *name)
719 mono_once (&event_ops_once, event_ops_init);
721 /* w32 seems to guarantee that opening named objects can't
724 thr_ret = _wapi_namespace_lock ();
725 g_assert (thr_ret == 0);
727 utf8_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
729 DEBUG ("%s: Opening named event [%s]", __func__, utf8_name);
731 offset = _wapi_search_handle_namespace (WAPI_HANDLE_NAMEDEVENT,
734 /* The name has already been used for a different
737 SetLastError (ERROR_INVALID_HANDLE);
739 } else if (offset == 0) {
740 /* This name doesn't exist */
741 SetLastError (ERROR_FILE_NOT_FOUND); /* yes, really */
745 /* A new reference to an existing named event, so just create
748 handle = _wapi_handle_new_from_offset (WAPI_HANDLE_NAMEDEVENT, offset,
751 if (handle == _WAPI_HANDLE_INVALID) {
752 g_warning ("%s: error opening named event handle", __func__);
753 SetLastError (ERROR_GEN_FAILURE);
758 DEBUG ("%s: returning named event handle %p", __func__, handle);
763 _wapi_namespace_unlock (NULL);