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/event-private.h>
19 #include <mono/utils/mono-once.h>
22 #define DEBUG(...) g_message(__VA_ARGS__)
27 static void event_signal(gpointer handle);
28 static gboolean event_own (gpointer handle);
30 static void namedevent_signal (gpointer handle);
31 static gboolean namedevent_own (gpointer handle);
33 struct _WapiHandleOps _wapi_event_ops = {
35 event_signal, /* signal */
38 NULL, /* special_wait */
42 struct _WapiHandleOps _wapi_namedevent_ops = {
44 namedevent_signal, /* signal */
45 namedevent_own, /* own */
49 static gboolean event_pulse (gpointer handle);
50 static gboolean event_reset (gpointer handle);
51 static gboolean event_set (gpointer handle);
53 static gboolean namedevent_pulse (gpointer handle);
54 static gboolean namedevent_reset (gpointer handle);
55 static gboolean namedevent_set (gpointer handle);
59 gboolean (*pulse)(gpointer handle);
60 gboolean (*reset)(gpointer handle);
61 gboolean (*set)(gpointer handle);
62 } event_ops[WAPI_HANDLE_COUNT] = {
69 {event_pulse, event_reset, event_set},
76 {namedevent_pulse, namedevent_reset, namedevent_set},
79 void _wapi_event_details (gpointer handle_info)
81 struct _WapiHandle_event *event = (struct _WapiHandle_event *)handle_info;
83 g_print ("manual: %s", event->manual?"TRUE":"FALSE");
86 static mono_once_t event_ops_once=MONO_ONCE_INIT;
88 static void event_ops_init (void)
90 _wapi_handle_register_capabilities (WAPI_HANDLE_EVENT,
91 (WapiHandleCapability)(WAPI_HANDLE_CAP_WAIT | WAPI_HANDLE_CAP_SIGNAL));
92 _wapi_handle_register_capabilities (WAPI_HANDLE_NAMEDEVENT,
93 (WapiHandleCapability)(WAPI_HANDLE_CAP_WAIT | WAPI_HANDLE_CAP_SIGNAL));
96 static void event_signal(gpointer handle)
101 static gboolean event_own (gpointer handle)
103 struct _WapiHandle_event *event_handle;
106 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_EVENT,
107 (gpointer *)&event_handle);
109 g_warning ("%s: error looking up event handle %p", __func__,
114 DEBUG("%s: owning event handle %p", __func__, handle);
116 if(event_handle->manual==FALSE) {
117 g_assert (event_handle->set_count > 0);
119 if (--event_handle->set_count == 0) {
120 _wapi_handle_set_signal_state (handle, FALSE, FALSE);
127 static void namedevent_signal (gpointer handle)
132 /* NB, always called with the shared handle lock held */
133 static gboolean namedevent_own (gpointer handle)
135 struct _WapiHandle_namedevent *namedevent_handle;
138 DEBUG ("%s: owning named event handle %p", __func__, handle);
140 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDEVENT,
141 (gpointer *)&namedevent_handle);
143 g_warning ("%s: error looking up named event handle %p",
148 if (namedevent_handle->manual == FALSE) {
149 g_assert (namedevent_handle->set_count > 0);
151 if (--namedevent_handle->set_count == 0) {
152 _wapi_shared_handle_set_signal_state (handle, FALSE);
158 static gpointer event_create (WapiSecurityAttributes *security G_GNUC_UNUSED,
159 gboolean manual, gboolean initial)
161 struct _WapiHandle_event event_handle = {0};
165 /* Need to blow away any old errors here, because code tests
166 * for ERROR_ALREADY_EXISTS on success (!) to see if an event
167 * was freshly created
169 SetLastError (ERROR_SUCCESS);
171 DEBUG ("%s: Creating unnamed event", __func__);
173 event_handle.manual = manual;
174 event_handle.set_count = 0;
176 if (initial == TRUE) {
177 if (manual == FALSE) {
178 event_handle.set_count = 1;
182 handle = _wapi_handle_new (WAPI_HANDLE_EVENT, &event_handle);
183 if (handle == _WAPI_HANDLE_INVALID) {
184 g_warning ("%s: error creating event handle", __func__);
185 SetLastError (ERROR_GEN_FAILURE);
189 thr_ret = _wapi_handle_lock_handle (handle);
190 g_assert (thr_ret == 0);
192 if (initial == TRUE) {
193 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
196 DEBUG("%s: created new event handle %p", __func__, handle);
198 thr_ret = _wapi_handle_unlock_handle (handle);
199 g_assert (thr_ret == 0);
204 static gpointer namedevent_create (WapiSecurityAttributes *security G_GNUC_UNUSED,
205 gboolean manual, gboolean initial,
206 const gunichar2 *name G_GNUC_UNUSED)
208 struct _WapiHandle_namedevent namedevent_handle = {{{0}}, 0};
216 /* w32 seems to guarantee that opening named objects can't
219 thr_ret = _wapi_namespace_lock ();
220 g_assert (thr_ret == 0);
222 /* Need to blow away any old errors here, because code tests
223 * for ERROR_ALREADY_EXISTS on success (!) to see if an event
224 * was freshly created
226 SetLastError (ERROR_SUCCESS);
228 utf8_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
230 DEBUG ("%s: Creating named event [%s]", __func__, utf8_name);
232 offset = _wapi_search_handle_namespace (WAPI_HANDLE_NAMEDEVENT,
235 /* The name has already been used for a different
238 SetLastError (ERROR_INVALID_HANDLE);
240 } else if (offset != 0) {
241 /* Not an error, but this is how the caller is
242 * informed that the event wasn't freshly created
244 SetLastError (ERROR_ALREADY_EXISTS);
246 /* Fall through to create the event handle. */
249 /* A new named event, so create both the private and
253 if (strlen (utf8_name) < MAX_PATH) {
254 namelen = strlen (utf8_name);
259 memcpy (&namedevent_handle.sharedns.name, utf8_name, namelen);
261 namedevent_handle.manual = manual;
262 namedevent_handle.set_count = 0;
264 if (initial == TRUE) {
265 if (manual == FALSE) {
266 namedevent_handle.set_count = 1;
270 handle = _wapi_handle_new (WAPI_HANDLE_NAMEDEVENT,
273 /* A new reference to an existing named event, so just
274 * create the private part
276 handle = _wapi_handle_new_from_offset (WAPI_HANDLE_NAMEDEVENT,
280 if (handle == _WAPI_HANDLE_INVALID) {
281 g_warning ("%s: error creating event handle", __func__);
282 SetLastError (ERROR_GEN_FAILURE);
288 /* Set the initial state, as this is a completely new
291 thr_ret = _wapi_handle_lock_shared_handles ();
292 g_assert (thr_ret == 0);
294 if (initial == TRUE) {
295 _wapi_shared_handle_set_signal_state (handle, TRUE);
298 _wapi_handle_unlock_shared_handles ();
301 DEBUG ("%s: returning event handle %p", __func__, handle);
306 _wapi_namespace_unlock (NULL);
315 * @security: Ignored for now.
316 * @manual: Specifies whether the new event handle has manual or auto
318 * @initial: Specifies whether the new event handle is initially
320 * @name:Pointer to a string specifying the name of this name, or
321 * %NULL. Currently ignored.
323 * Creates a new event handle.
325 * An event handle is signalled with SetEvent(). If the new handle is
326 * a manual reset event handle, it remains signalled until it is reset
327 * with ResetEvent(). An auto reset event remains signalled until a
328 * single thread has waited for it, at which time the event handle is
329 * automatically reset to unsignalled.
331 * Return value: A new handle, or %NULL on error.
333 gpointer CreateEvent(WapiSecurityAttributes *security G_GNUC_UNUSED,
334 gboolean manual, gboolean initial,
335 const gunichar2 *name G_GNUC_UNUSED)
337 mono_once (&event_ops_once, event_ops_init);
340 return(event_create (security, manual, initial));
342 return(namedevent_create (security, manual, initial, name));
346 static gboolean event_pulse (gpointer handle)
348 struct _WapiHandle_event *event_handle;
352 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_EVENT,
353 (gpointer *)&event_handle);
355 g_warning ("%s: error looking up event handle %p", __func__,
360 thr_ret = _wapi_handle_lock_handle (handle);
361 g_assert (thr_ret == 0);
363 DEBUG ("%s: Pulsing event handle %p", __func__, handle);
365 if (event_handle->manual == TRUE) {
366 _wapi_handle_set_signal_state (handle, TRUE, TRUE);
368 event_handle->set_count = 1;
369 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
372 thr_ret = _wapi_handle_unlock_handle (handle);
373 g_assert (thr_ret == 0);
375 if (event_handle->manual == TRUE) {
376 /* For a manual-reset event, we're about to try and
377 * get the handle lock again, so give other threads a
382 /* Reset the handle signal state */
383 /* I'm not sure whether or not we need a barrier here
384 * to make sure that all threads waiting on the event
385 * have proceeded. Currently we rely on broadcasting
388 DEBUG ("%s: Obtained write lock on event handle %p",
391 thr_ret = _wapi_handle_lock_handle (handle);
392 g_assert (thr_ret == 0);
394 _wapi_handle_set_signal_state (handle, FALSE, FALSE);
396 thr_ret = _wapi_handle_unlock_handle (handle);
397 g_assert (thr_ret == 0);
403 static gboolean namedevent_pulse (gpointer handle)
405 struct _WapiHandle_namedevent *namedevent_handle;
409 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDEVENT,
410 (gpointer *)&namedevent_handle);
412 g_warning ("%s: error looking up named event handle %p",
417 thr_ret = _wapi_handle_lock_shared_handles ();
418 g_assert (thr_ret == 0);
420 DEBUG ("%s: Pulsing named event handle %p", __func__, handle);
422 if (namedevent_handle->manual == TRUE) {
423 _wapi_shared_handle_set_signal_state (handle, TRUE);
425 namedevent_handle->set_count = 1;
426 _wapi_shared_handle_set_signal_state (handle, TRUE);
429 _wapi_handle_unlock_shared_handles ();
431 if (namedevent_handle->manual == TRUE) {
432 /* For a manual-reset event, we're about to try and
433 * get the handle lock again, so give other processes
436 _wapi_handle_spin (200);
438 /* Reset the handle signal state */
439 /* I'm not sure whether or not we need a barrier here
440 * to make sure that all threads waiting on the event
441 * have proceeded. Currently we rely on waiting for
442 * twice the shared handle poll interval.
444 DEBUG ("%s: Obtained write lock on event handle %p",
447 thr_ret = _wapi_handle_lock_shared_handles ();
448 g_assert (thr_ret == 0);
450 _wapi_shared_handle_set_signal_state (handle, FALSE);
452 _wapi_handle_unlock_shared_handles ();
460 * @handle: The event handle.
462 * Sets the event handle @handle to the signalled state, and then
463 * resets it to unsignalled after informing any waiting threads.
465 * If @handle is a manual reset event, all waiting threads that can be
466 * released immediately are released. @handle is then reset. If
467 * @handle is an auto reset event, one waiting thread is released even
468 * if multiple threads are waiting.
470 * Return value: %TRUE on success, %FALSE otherwise. (Currently only
471 * ever returns %TRUE).
473 gboolean PulseEvent(gpointer handle)
477 if (handle == NULL) {
478 SetLastError (ERROR_INVALID_HANDLE);
482 type = _wapi_handle_type (handle);
484 if (event_ops[type].pulse == NULL) {
485 SetLastError (ERROR_INVALID_HANDLE);
489 return(event_ops[type].pulse (handle));
492 static gboolean event_reset (gpointer handle)
494 struct _WapiHandle_event *event_handle;
498 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_EVENT,
499 (gpointer *)&event_handle);
501 g_warning ("%s: error looking up event handle %p",
506 DEBUG ("%s: Resetting event handle %p", __func__, handle);
508 thr_ret = _wapi_handle_lock_handle (handle);
509 g_assert (thr_ret == 0);
511 if (_wapi_handle_issignalled (handle) == FALSE) {
512 DEBUG ("%s: No need to reset event handle %p", __func__,
515 DEBUG ("%s: Obtained write lock on event handle %p",
518 _wapi_handle_set_signal_state (handle, FALSE, FALSE);
521 event_handle->set_count = 0;
523 thr_ret = _wapi_handle_unlock_handle (handle);
524 g_assert (thr_ret == 0);
529 static gboolean namedevent_reset (gpointer handle)
531 struct _WapiHandle_namedevent *namedevent_handle;
535 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDEVENT,
536 (gpointer *)&namedevent_handle);
538 g_warning ("%s: error looking up named event handle %p",
543 DEBUG ("%s: Resetting named event handle %p", __func__, handle);
545 thr_ret = _wapi_handle_lock_shared_handles ();
546 g_assert (thr_ret == 0);
548 if (_wapi_handle_issignalled (handle) == FALSE) {
549 DEBUG ("%s: No need to reset named event handle %p",
552 DEBUG ("%s: Obtained write lock on named event handle %p",
555 _wapi_shared_handle_set_signal_state (handle, FALSE);
558 namedevent_handle->set_count = 0;
560 _wapi_handle_unlock_shared_handles ();
567 * @handle: The event handle.
569 * Resets the event handle @handle to the unsignalled state.
571 * Return value: %TRUE on success, %FALSE otherwise. (Currently only
572 * ever returns %TRUE).
574 gboolean ResetEvent(gpointer handle)
578 if (handle == NULL) {
579 SetLastError (ERROR_INVALID_HANDLE);
583 type = _wapi_handle_type (handle);
585 if (event_ops[type].reset == NULL) {
586 SetLastError (ERROR_INVALID_HANDLE);
590 return(event_ops[type].reset (handle));
593 static gboolean event_set (gpointer handle)
595 struct _WapiHandle_event *event_handle;
599 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_EVENT,
600 (gpointer *)&event_handle);
602 g_warning ("%s: error looking up event handle %p", __func__,
607 thr_ret = _wapi_handle_lock_handle (handle);
608 g_assert (thr_ret == 0);
610 DEBUG ("%s: Setting event handle %p", __func__, handle);
612 if (event_handle->manual == TRUE) {
613 _wapi_handle_set_signal_state (handle, TRUE, TRUE);
615 event_handle->set_count = 1;
616 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
619 thr_ret = _wapi_handle_unlock_handle (handle);
620 g_assert (thr_ret == 0);
625 static gboolean namedevent_set (gpointer handle)
627 struct _WapiHandle_namedevent *namedevent_handle;
631 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDEVENT,
632 (gpointer *)&namedevent_handle);
634 g_warning ("%s: error looking up named event handle %p",
639 thr_ret = _wapi_handle_lock_shared_handles ();
640 g_assert (thr_ret == 0);
642 DEBUG ("%s: Setting named event handle %p", __func__, handle);
644 if (namedevent_handle->manual == TRUE) {
645 _wapi_shared_handle_set_signal_state (handle, TRUE);
647 namedevent_handle->set_count = 1;
648 _wapi_shared_handle_set_signal_state (handle, TRUE);
651 _wapi_handle_unlock_shared_handles ();
658 * @handle: The event handle
660 * Sets the event handle @handle to the signalled state.
662 * If @handle is a manual reset event, it remains signalled until it
663 * is reset with ResetEvent(). An auto reset event remains signalled
664 * until a single thread has waited for it, at which time @handle is
665 * automatically reset to unsignalled.
667 * Return value: %TRUE on success, %FALSE otherwise. (Currently only
668 * ever returns %TRUE).
670 gboolean SetEvent(gpointer handle)
674 if (handle == NULL) {
675 SetLastError (ERROR_INVALID_HANDLE);
679 type = _wapi_handle_type (handle);
681 if (event_ops[type].set == NULL) {
682 SetLastError (ERROR_INVALID_HANDLE);
686 return(event_ops[type].set (handle));
689 gpointer OpenEvent (guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, const gunichar2 *name)
697 mono_once (&event_ops_once, event_ops_init);
699 /* w32 seems to guarantee that opening named objects can't
702 thr_ret = _wapi_namespace_lock ();
703 g_assert (thr_ret == 0);
705 utf8_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
707 DEBUG ("%s: Opening named event [%s]", __func__, utf8_name);
709 offset = _wapi_search_handle_namespace (WAPI_HANDLE_NAMEDEVENT,
712 /* The name has already been used for a different
715 SetLastError (ERROR_INVALID_HANDLE);
717 } else if (offset == 0) {
718 /* This name doesn't exist */
719 SetLastError (ERROR_FILE_NOT_FOUND); /* yes, really */
723 /* A new reference to an existing named event, so just create
726 handle = _wapi_handle_new_from_offset (WAPI_HANDLE_NAMEDEVENT, offset,
729 if (handle == _WAPI_HANDLE_INVALID) {
730 g_warning ("%s: error opening named event handle", __func__);
731 SetLastError (ERROR_GEN_FAILURE);
736 DEBUG ("%s: returning named event handle %p", __func__, handle);
741 _wapi_namespace_unlock (NULL);