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/io-layer/io-trace.h>
20 #include <mono/utils/mono-once.h>
21 #include <mono/utils/mono-logger-internals.h>
23 static void event_signal(gpointer handle);
24 static gboolean event_own (gpointer handle);
26 static void namedevent_signal (gpointer handle);
27 static gboolean namedevent_own (gpointer handle);
29 struct _WapiHandleOps _wapi_event_ops = {
31 event_signal, /* signal */
34 NULL, /* special_wait */
38 struct _WapiHandleOps _wapi_namedevent_ops = {
40 namedevent_signal, /* signal */
41 namedevent_own, /* own */
45 static gboolean event_pulse (gpointer handle);
46 static gboolean event_reset (gpointer handle);
47 static gboolean event_set (gpointer handle);
49 static gboolean namedevent_pulse (gpointer handle);
50 static gboolean namedevent_reset (gpointer handle);
51 static gboolean namedevent_set (gpointer handle);
55 gboolean (*pulse)(gpointer handle);
56 gboolean (*reset)(gpointer handle);
57 gboolean (*set)(gpointer handle);
58 } event_ops[WAPI_HANDLE_COUNT] = {
65 {event_pulse, event_reset, event_set},
72 {namedevent_pulse, namedevent_reset, namedevent_set},
75 void _wapi_event_details (gpointer handle_info)
77 struct _WapiHandle_event *event = (struct _WapiHandle_event *)handle_info;
79 g_print ("manual: %s", event->manual?"TRUE":"FALSE");
82 static mono_once_t event_ops_once=MONO_ONCE_INIT;
84 static void event_ops_init (void)
86 _wapi_handle_register_capabilities (WAPI_HANDLE_EVENT,
87 (WapiHandleCapability)(WAPI_HANDLE_CAP_WAIT | WAPI_HANDLE_CAP_SIGNAL));
88 _wapi_handle_register_capabilities (WAPI_HANDLE_NAMEDEVENT,
89 (WapiHandleCapability)(WAPI_HANDLE_CAP_WAIT | WAPI_HANDLE_CAP_SIGNAL));
92 static void event_signal(gpointer handle)
97 static gboolean event_own (gpointer handle)
99 struct _WapiHandle_event *event_handle;
102 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_EVENT,
103 (gpointer *)&event_handle);
105 g_warning ("%s: error looking up event handle %p", __func__,
110 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: owning event handle %p", __func__, handle);
112 if(event_handle->manual==FALSE) {
113 g_assert (event_handle->set_count > 0);
115 if (--event_handle->set_count == 0) {
116 _wapi_handle_set_signal_state (handle, FALSE, FALSE);
123 static void namedevent_signal (gpointer handle)
128 /* NB, always called with the shared handle lock held */
129 static gboolean namedevent_own (gpointer handle)
131 struct _WapiHandle_namedevent *namedevent_handle;
134 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: owning named event handle %p", __func__, handle);
136 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDEVENT,
137 (gpointer *)&namedevent_handle);
139 g_warning ("%s: error looking up named event handle %p",
144 if (namedevent_handle->manual == FALSE) {
145 g_assert (namedevent_handle->set_count > 0);
147 if (--namedevent_handle->set_count == 0) {
148 _wapi_shared_handle_set_signal_state (handle, FALSE);
154 static gpointer event_create (WapiSecurityAttributes *security G_GNUC_UNUSED,
155 gboolean manual, gboolean initial)
157 struct _WapiHandle_event event_handle = {0};
161 /* Need to blow away any old errors here, because code tests
162 * for ERROR_ALREADY_EXISTS on success (!) to see if an event
163 * was freshly created
165 SetLastError (ERROR_SUCCESS);
167 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Creating unnamed event", __func__);
169 event_handle.manual = manual;
170 event_handle.set_count = 0;
172 if (initial == TRUE) {
173 if (manual == FALSE) {
174 event_handle.set_count = 1;
178 handle = _wapi_handle_new (WAPI_HANDLE_EVENT, &event_handle);
179 if (handle == _WAPI_HANDLE_INVALID) {
180 g_warning ("%s: error creating event handle", __func__);
181 SetLastError (ERROR_GEN_FAILURE);
185 thr_ret = _wapi_handle_lock_handle (handle);
186 g_assert (thr_ret == 0);
188 if (initial == TRUE) {
189 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
192 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: created new event handle %p", __func__, handle);
194 thr_ret = _wapi_handle_unlock_handle (handle);
195 g_assert (thr_ret == 0);
200 static gpointer namedevent_create (WapiSecurityAttributes *security G_GNUC_UNUSED,
201 gboolean manual, gboolean initial,
202 const gunichar2 *name G_GNUC_UNUSED)
204 struct _WapiHandle_namedevent namedevent_handle = {{{0}}, 0};
212 /* w32 seems to guarantee that opening named objects can't
215 thr_ret = _wapi_namespace_lock ();
216 g_assert (thr_ret == 0);
218 /* Need to blow away any old errors here, because code tests
219 * for ERROR_ALREADY_EXISTS on success (!) to see if an event
220 * was freshly created
222 SetLastError (ERROR_SUCCESS);
224 utf8_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
226 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Creating named event [%s]", __func__, utf8_name);
228 offset = _wapi_search_handle_namespace (WAPI_HANDLE_NAMEDEVENT,
231 /* The name has already been used for a different
234 SetLastError (ERROR_INVALID_HANDLE);
236 } else if (offset != 0) {
237 /* Not an error, but this is how the caller is
238 * informed that the event wasn't freshly created
240 SetLastError (ERROR_ALREADY_EXISTS);
242 /* Fall through to create the event handle. */
245 /* A new named event, so create both the private and
249 if (strlen (utf8_name) < MAX_PATH) {
250 namelen = strlen (utf8_name);
255 memcpy (&namedevent_handle.sharedns.name, utf8_name, namelen);
257 namedevent_handle.manual = manual;
258 namedevent_handle.set_count = 0;
260 if (initial == TRUE) {
261 if (manual == FALSE) {
262 namedevent_handle.set_count = 1;
266 handle = _wapi_handle_new (WAPI_HANDLE_NAMEDEVENT,
269 /* A new reference to an existing named event, so just
270 * create the private part
272 handle = _wapi_handle_new_from_offset (WAPI_HANDLE_NAMEDEVENT,
276 if (handle == _WAPI_HANDLE_INVALID) {
277 g_warning ("%s: error creating event handle", __func__);
278 SetLastError (ERROR_GEN_FAILURE);
284 /* Set the initial state, as this is a completely new
287 thr_ret = _wapi_handle_lock_shared_handles ();
288 g_assert (thr_ret == 0);
290 if (initial == TRUE) {
291 _wapi_shared_handle_set_signal_state (handle, TRUE);
294 _wapi_handle_unlock_shared_handles ();
297 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning event handle %p", __func__, handle);
302 _wapi_namespace_unlock (NULL);
311 * @security: Ignored for now.
312 * @manual: Specifies whether the new event handle has manual or auto
314 * @initial: Specifies whether the new event handle is initially
316 * @name:Pointer to a string specifying the name of this name, or
317 * %NULL. Currently ignored.
319 * Creates a new event handle.
321 * An event handle is signalled with SetEvent(). If the new handle is
322 * a manual reset event handle, it remains signalled until it is reset
323 * with ResetEvent(). An auto reset event remains signalled until a
324 * single thread has waited for it, at which time the event handle is
325 * automatically reset to unsignalled.
327 * Return value: A new handle, or %NULL on error.
329 gpointer CreateEvent(WapiSecurityAttributes *security G_GNUC_UNUSED,
330 gboolean manual, gboolean initial,
331 const gunichar2 *name G_GNUC_UNUSED)
333 mono_once (&event_ops_once, event_ops_init);
336 return(event_create (security, manual, initial));
338 return(namedevent_create (security, manual, initial, name));
342 static gboolean event_pulse (gpointer handle)
344 struct _WapiHandle_event *event_handle;
348 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_EVENT,
349 (gpointer *)&event_handle);
351 g_warning ("%s: error looking up event handle %p", __func__,
356 thr_ret = _wapi_handle_lock_handle (handle);
357 g_assert (thr_ret == 0);
359 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Pulsing event handle %p", __func__, handle);
361 if (event_handle->manual == TRUE) {
362 _wapi_handle_set_signal_state (handle, TRUE, TRUE);
364 event_handle->set_count = 1;
365 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
368 thr_ret = _wapi_handle_unlock_handle (handle);
369 g_assert (thr_ret == 0);
371 if (event_handle->manual == TRUE) {
372 /* For a manual-reset event, we're about to try and
373 * get the handle lock again, so give other threads a
378 /* Reset the handle signal state */
379 /* I'm not sure whether or not we need a barrier here
380 * to make sure that all threads waiting on the event
381 * have proceeded. Currently we rely on broadcasting
384 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Obtained write lock on event handle %p",
387 thr_ret = _wapi_handle_lock_handle (handle);
388 g_assert (thr_ret == 0);
390 _wapi_handle_set_signal_state (handle, FALSE, FALSE);
392 thr_ret = _wapi_handle_unlock_handle (handle);
393 g_assert (thr_ret == 0);
399 static gboolean namedevent_pulse (gpointer handle)
401 struct _WapiHandle_namedevent *namedevent_handle;
405 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDEVENT,
406 (gpointer *)&namedevent_handle);
408 g_warning ("%s: error looking up named event handle %p",
413 thr_ret = _wapi_handle_lock_shared_handles ();
414 g_assert (thr_ret == 0);
416 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Pulsing named event handle %p", __func__, handle);
418 if (namedevent_handle->manual == TRUE) {
419 _wapi_shared_handle_set_signal_state (handle, TRUE);
421 namedevent_handle->set_count = 1;
422 _wapi_shared_handle_set_signal_state (handle, TRUE);
425 _wapi_handle_unlock_shared_handles ();
427 if (namedevent_handle->manual == TRUE) {
428 /* For a manual-reset event, we're about to try and
429 * get the handle lock again, so give other processes
432 _wapi_handle_spin (200);
434 /* Reset the handle signal state */
435 /* I'm not sure whether or not we need a barrier here
436 * to make sure that all threads waiting on the event
437 * have proceeded. Currently we rely on waiting for
438 * twice the shared handle poll interval.
440 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Obtained write lock on event handle %p",
443 thr_ret = _wapi_handle_lock_shared_handles ();
444 g_assert (thr_ret == 0);
446 _wapi_shared_handle_set_signal_state (handle, FALSE);
448 _wapi_handle_unlock_shared_handles ();
456 * @handle: The event handle.
458 * Sets the event handle @handle to the signalled state, and then
459 * resets it to unsignalled after informing any waiting threads.
461 * If @handle is a manual reset event, all waiting threads that can be
462 * released immediately are released. @handle is then reset. If
463 * @handle is an auto reset event, one waiting thread is released even
464 * if multiple threads are waiting.
466 * Return value: %TRUE on success, %FALSE otherwise. (Currently only
467 * ever returns %TRUE).
469 gboolean PulseEvent(gpointer handle)
473 if (handle == NULL) {
474 SetLastError (ERROR_INVALID_HANDLE);
478 type = _wapi_handle_type (handle);
480 if (event_ops[type].pulse == NULL) {
481 SetLastError (ERROR_INVALID_HANDLE);
485 return(event_ops[type].pulse (handle));
488 static gboolean event_reset (gpointer handle)
490 struct _WapiHandle_event *event_handle;
494 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_EVENT,
495 (gpointer *)&event_handle);
497 g_warning ("%s: error looking up event handle %p",
502 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Resetting event handle %p", __func__, handle);
504 thr_ret = _wapi_handle_lock_handle (handle);
505 g_assert (thr_ret == 0);
507 if (_wapi_handle_issignalled (handle) == FALSE) {
508 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: No need to reset event handle %p", __func__,
511 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Obtained write lock on event handle %p",
514 _wapi_handle_set_signal_state (handle, FALSE, FALSE);
517 event_handle->set_count = 0;
519 thr_ret = _wapi_handle_unlock_handle (handle);
520 g_assert (thr_ret == 0);
525 static gboolean namedevent_reset (gpointer handle)
527 struct _WapiHandle_namedevent *namedevent_handle;
531 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDEVENT,
532 (gpointer *)&namedevent_handle);
534 g_warning ("%s: error looking up named event handle %p",
539 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Resetting named event handle %p", __func__, handle);
541 thr_ret = _wapi_handle_lock_shared_handles ();
542 g_assert (thr_ret == 0);
544 if (_wapi_handle_issignalled (handle) == FALSE) {
545 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: No need to reset named event handle %p",
548 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Obtained write lock on named event handle %p",
551 _wapi_shared_handle_set_signal_state (handle, FALSE);
554 namedevent_handle->set_count = 0;
556 _wapi_handle_unlock_shared_handles ();
563 * @handle: The event handle.
565 * Resets the event handle @handle to the unsignalled state.
567 * Return value: %TRUE on success, %FALSE otherwise. (Currently only
568 * ever returns %TRUE).
570 gboolean ResetEvent(gpointer handle)
574 if (handle == NULL) {
575 SetLastError (ERROR_INVALID_HANDLE);
579 type = _wapi_handle_type (handle);
581 if (event_ops[type].reset == NULL) {
582 SetLastError (ERROR_INVALID_HANDLE);
586 return(event_ops[type].reset (handle));
589 static gboolean event_set (gpointer handle)
591 struct _WapiHandle_event *event_handle;
595 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_EVENT,
596 (gpointer *)&event_handle);
598 g_warning ("%s: error looking up event handle %p", __func__,
603 thr_ret = _wapi_handle_lock_handle (handle);
604 g_assert (thr_ret == 0);
606 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Setting event handle %p", __func__, handle);
608 if (event_handle->manual == TRUE) {
609 _wapi_handle_set_signal_state (handle, TRUE, TRUE);
611 event_handle->set_count = 1;
612 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
615 thr_ret = _wapi_handle_unlock_handle (handle);
616 g_assert (thr_ret == 0);
621 static gboolean namedevent_set (gpointer handle)
623 struct _WapiHandle_namedevent *namedevent_handle;
627 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDEVENT,
628 (gpointer *)&namedevent_handle);
630 g_warning ("%s: error looking up named event handle %p",
635 thr_ret = _wapi_handle_lock_shared_handles ();
636 g_assert (thr_ret == 0);
638 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Setting named event handle %p", __func__, handle);
640 if (namedevent_handle->manual == TRUE) {
641 _wapi_shared_handle_set_signal_state (handle, TRUE);
643 namedevent_handle->set_count = 1;
644 _wapi_shared_handle_set_signal_state (handle, TRUE);
647 _wapi_handle_unlock_shared_handles ();
654 * @handle: The event handle
656 * Sets the event handle @handle to the signalled state.
658 * If @handle is a manual reset event, it remains signalled until it
659 * is reset with ResetEvent(). An auto reset event remains signalled
660 * until a single thread has waited for it, at which time @handle is
661 * automatically reset to unsignalled.
663 * Return value: %TRUE on success, %FALSE otherwise. (Currently only
664 * ever returns %TRUE).
666 gboolean SetEvent(gpointer handle)
670 if (handle == NULL) {
671 SetLastError (ERROR_INVALID_HANDLE);
675 type = _wapi_handle_type (handle);
677 if (event_ops[type].set == NULL) {
678 SetLastError (ERROR_INVALID_HANDLE);
682 return(event_ops[type].set (handle));
685 gpointer OpenEvent (guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, const gunichar2 *name)
693 mono_once (&event_ops_once, event_ops_init);
695 /* w32 seems to guarantee that opening named objects can't
698 thr_ret = _wapi_namespace_lock ();
699 g_assert (thr_ret == 0);
701 utf8_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
703 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Opening named event [%s]", __func__, utf8_name);
705 offset = _wapi_search_handle_namespace (WAPI_HANDLE_NAMEDEVENT,
708 /* The name has already been used for a different
711 SetLastError (ERROR_INVALID_HANDLE);
713 } else if (offset == 0) {
714 /* This name doesn't exist */
715 SetLastError (ERROR_FILE_NOT_FOUND); /* yes, really */
719 /* A new reference to an existing named event, so just create
722 handle = _wapi_handle_new_from_offset (WAPI_HANDLE_NAMEDEVENT, offset,
725 if (handle == _WAPI_HANDLE_INVALID) {
726 g_warning ("%s: error opening named event handle", __func__);
727 SetLastError (ERROR_GEN_FAILURE);
732 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning named event handle %p", __func__, handle);
737 _wapi_namespace_unlock (NULL);