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 WAPI_HANDLE_CAP_WAIT |
92 WAPI_HANDLE_CAP_SIGNAL);
93 _wapi_handle_register_capabilities (WAPI_HANDLE_NAMEDEVENT,
94 WAPI_HANDLE_CAP_WAIT |
95 WAPI_HANDLE_CAP_SIGNAL);
98 static void event_signal(gpointer handle)
103 static gboolean event_own (gpointer handle)
105 struct _WapiHandle_event *event_handle;
108 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_EVENT,
109 (gpointer *)&event_handle);
111 g_warning ("%s: error looking up event handle %p", __func__,
116 DEBUG("%s: owning event handle %p", __func__, handle);
118 if(event_handle->manual==FALSE) {
119 g_assert (event_handle->set_count > 0);
121 if (--event_handle->set_count == 0) {
122 _wapi_handle_set_signal_state (handle, FALSE, FALSE);
129 static void namedevent_signal (gpointer handle)
134 /* NB, always called with the shared handle lock held */
135 static gboolean namedevent_own (gpointer handle)
137 struct _WapiHandle_namedevent *namedevent_handle;
140 DEBUG ("%s: owning named event handle %p", __func__, handle);
142 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDEVENT,
143 (gpointer *)&namedevent_handle);
145 g_warning ("%s: error looking up named event handle %p",
150 if (namedevent_handle->manual == FALSE) {
151 g_assert (namedevent_handle->set_count > 0);
153 if (--namedevent_handle->set_count == 0) {
154 _wapi_shared_handle_set_signal_state (handle, FALSE);
160 static gpointer event_create (WapiSecurityAttributes *security G_GNUC_UNUSED,
161 gboolean manual, gboolean initial)
163 struct _WapiHandle_event event_handle = {0};
167 /* Need to blow away any old errors here, because code tests
168 * for ERROR_ALREADY_EXISTS on success (!) to see if an event
169 * was freshly created
171 SetLastError (ERROR_SUCCESS);
173 DEBUG ("%s: Creating unnamed event", __func__);
175 event_handle.manual = manual;
176 event_handle.set_count = 0;
178 if (initial == TRUE) {
179 if (manual == FALSE) {
180 event_handle.set_count = 1;
184 handle = _wapi_handle_new (WAPI_HANDLE_EVENT, &event_handle);
185 if (handle == _WAPI_HANDLE_INVALID) {
186 g_warning ("%s: error creating event handle", __func__);
187 SetLastError (ERROR_GEN_FAILURE);
191 thr_ret = _wapi_handle_lock_handle (handle);
192 g_assert (thr_ret == 0);
194 if (initial == TRUE) {
195 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
198 DEBUG("%s: created new event handle %p", __func__, handle);
200 thr_ret = _wapi_handle_unlock_handle (handle);
201 g_assert (thr_ret == 0);
206 static gpointer namedevent_create (WapiSecurityAttributes *security G_GNUC_UNUSED,
207 gboolean manual, gboolean initial,
208 const gunichar2 *name G_GNUC_UNUSED)
210 struct _WapiHandle_namedevent namedevent_handle = {{{0}}, 0};
218 /* w32 seems to guarantee that opening named objects can't
221 thr_ret = _wapi_namespace_lock ();
222 g_assert (thr_ret == 0);
224 /* Need to blow away any old errors here, because code tests
225 * for ERROR_ALREADY_EXISTS on success (!) to see if an event
226 * was freshly created
228 SetLastError (ERROR_SUCCESS);
230 utf8_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
232 DEBUG ("%s: Creating named event [%s]", __func__, utf8_name);
234 offset = _wapi_search_handle_namespace (WAPI_HANDLE_NAMEDEVENT,
237 /* The name has already been used for a different
240 SetLastError (ERROR_INVALID_HANDLE);
242 } else if (offset != 0) {
243 /* Not an error, but this is how the caller is
244 * informed that the event wasn't freshly created
246 SetLastError (ERROR_ALREADY_EXISTS);
248 /* Fall through to create the event handle. */
251 /* A new named event, so create both the private and
255 if (strlen (utf8_name) < MAX_PATH) {
256 namelen = strlen (utf8_name);
261 memcpy (&namedevent_handle.sharedns.name, utf8_name, namelen);
263 namedevent_handle.manual = manual;
264 namedevent_handle.set_count = 0;
266 if (initial == TRUE) {
267 if (manual == FALSE) {
268 namedevent_handle.set_count = 1;
272 handle = _wapi_handle_new (WAPI_HANDLE_NAMEDEVENT,
275 /* A new reference to an existing named event, so just
276 * create the private part
278 handle = _wapi_handle_new_from_offset (WAPI_HANDLE_NAMEDEVENT,
282 if (handle == _WAPI_HANDLE_INVALID) {
283 g_warning ("%s: error creating event handle", __func__);
284 SetLastError (ERROR_GEN_FAILURE);
290 /* Set the initial state, as this is a completely new
293 thr_ret = _wapi_handle_lock_shared_handles ();
294 g_assert (thr_ret == 0);
296 if (initial == TRUE) {
297 _wapi_shared_handle_set_signal_state (handle, TRUE);
300 _wapi_handle_unlock_shared_handles ();
303 DEBUG ("%s: returning event handle %p", __func__, handle);
308 _wapi_namespace_unlock (NULL);
317 * @security: Ignored for now.
318 * @manual: Specifies whether the new event handle has manual or auto
320 * @initial: Specifies whether the new event handle is initially
322 * @name:Pointer to a string specifying the name of this name, or
323 * %NULL. Currently ignored.
325 * Creates a new event handle.
327 * An event handle is signalled with SetEvent(). If the new handle is
328 * a manual reset event handle, it remains signalled until it is reset
329 * with ResetEvent(). An auto reset event remains signalled until a
330 * single thread has waited for it, at which time the event handle is
331 * automatically reset to unsignalled.
333 * Return value: A new handle, or %NULL on error.
335 gpointer CreateEvent(WapiSecurityAttributes *security G_GNUC_UNUSED,
336 gboolean manual, gboolean initial,
337 const gunichar2 *name G_GNUC_UNUSED)
339 mono_once (&event_ops_once, event_ops_init);
342 return(event_create (security, manual, initial));
344 return(namedevent_create (security, manual, initial, name));
348 static gboolean event_pulse (gpointer handle)
350 struct _WapiHandle_event *event_handle;
354 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_EVENT,
355 (gpointer *)&event_handle);
357 g_warning ("%s: error looking up event handle %p", __func__,
362 thr_ret = _wapi_handle_lock_handle (handle);
363 g_assert (thr_ret == 0);
365 DEBUG ("%s: Pulsing event handle %p", __func__, handle);
367 if (event_handle->manual == TRUE) {
368 _wapi_handle_set_signal_state (handle, TRUE, TRUE);
370 event_handle->set_count = 1;
371 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
374 thr_ret = _wapi_handle_unlock_handle (handle);
375 g_assert (thr_ret == 0);
377 if (event_handle->manual == TRUE) {
378 /* For a manual-reset event, we're about to try and
379 * get the handle lock again, so give other threads a
384 /* Reset the handle signal state */
385 /* I'm not sure whether or not we need a barrier here
386 * to make sure that all threads waiting on the event
387 * have proceeded. Currently we rely on broadcasting
390 DEBUG ("%s: Obtained write lock on event handle %p",
393 thr_ret = _wapi_handle_lock_handle (handle);
394 g_assert (thr_ret == 0);
396 _wapi_handle_set_signal_state (handle, FALSE, FALSE);
398 thr_ret = _wapi_handle_unlock_handle (handle);
399 g_assert (thr_ret == 0);
405 static gboolean namedevent_pulse (gpointer handle)
407 struct _WapiHandle_namedevent *namedevent_handle;
411 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDEVENT,
412 (gpointer *)&namedevent_handle);
414 g_warning ("%s: error looking up named event handle %p",
419 thr_ret = _wapi_handle_lock_shared_handles ();
420 g_assert (thr_ret == 0);
422 DEBUG ("%s: Pulsing named event handle %p", __func__, handle);
424 if (namedevent_handle->manual == TRUE) {
425 _wapi_shared_handle_set_signal_state (handle, TRUE);
427 namedevent_handle->set_count = 1;
428 _wapi_shared_handle_set_signal_state (handle, TRUE);
431 _wapi_handle_unlock_shared_handles ();
433 if (namedevent_handle->manual == TRUE) {
434 /* For a manual-reset event, we're about to try and
435 * get the handle lock again, so give other processes
438 _wapi_handle_spin (200);
440 /* Reset the handle signal state */
441 /* I'm not sure whether or not we need a barrier here
442 * to make sure that all threads waiting on the event
443 * have proceeded. Currently we rely on waiting for
444 * twice the shared handle poll interval.
446 DEBUG ("%s: Obtained write lock on event handle %p",
449 thr_ret = _wapi_handle_lock_shared_handles ();
450 g_assert (thr_ret == 0);
452 _wapi_shared_handle_set_signal_state (handle, FALSE);
454 _wapi_handle_unlock_shared_handles ();
462 * @handle: The event handle.
464 * Sets the event handle @handle to the signalled state, and then
465 * resets it to unsignalled after informing any waiting threads.
467 * If @handle is a manual reset event, all waiting threads that can be
468 * released immediately are released. @handle is then reset. If
469 * @handle is an auto reset event, one waiting thread is released even
470 * if multiple threads are waiting.
472 * Return value: %TRUE on success, %FALSE otherwise. (Currently only
473 * ever returns %TRUE).
475 gboolean PulseEvent(gpointer handle)
479 if (handle == NULL) {
480 SetLastError (ERROR_INVALID_HANDLE);
484 type = _wapi_handle_type (handle);
486 if (event_ops[type].pulse == NULL) {
487 SetLastError (ERROR_INVALID_HANDLE);
491 return(event_ops[type].pulse (handle));
494 static gboolean event_reset (gpointer handle)
496 struct _WapiHandle_event *event_handle;
500 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_EVENT,
501 (gpointer *)&event_handle);
503 g_warning ("%s: error looking up event handle %p",
508 DEBUG ("%s: Resetting event handle %p", __func__, handle);
510 thr_ret = _wapi_handle_lock_handle (handle);
511 g_assert (thr_ret == 0);
513 if (_wapi_handle_issignalled (handle) == FALSE) {
514 DEBUG ("%s: No need to reset event handle %p", __func__,
517 DEBUG ("%s: Obtained write lock on event handle %p",
520 _wapi_handle_set_signal_state (handle, FALSE, FALSE);
523 event_handle->set_count = 0;
525 thr_ret = _wapi_handle_unlock_handle (handle);
526 g_assert (thr_ret == 0);
531 static gboolean namedevent_reset (gpointer handle)
533 struct _WapiHandle_namedevent *namedevent_handle;
537 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDEVENT,
538 (gpointer *)&namedevent_handle);
540 g_warning ("%s: error looking up named event handle %p",
545 DEBUG ("%s: Resetting named event handle %p", __func__, handle);
547 thr_ret = _wapi_handle_lock_shared_handles ();
548 g_assert (thr_ret == 0);
550 if (_wapi_handle_issignalled (handle) == FALSE) {
551 DEBUG ("%s: No need to reset named event handle %p",
554 DEBUG ("%s: Obtained write lock on named event handle %p",
557 _wapi_shared_handle_set_signal_state (handle, FALSE);
560 namedevent_handle->set_count = 0;
562 _wapi_handle_unlock_shared_handles ();
569 * @handle: The event handle.
571 * Resets the event handle @handle to the unsignalled state.
573 * Return value: %TRUE on success, %FALSE otherwise. (Currently only
574 * ever returns %TRUE).
576 gboolean ResetEvent(gpointer handle)
580 if (handle == NULL) {
581 SetLastError (ERROR_INVALID_HANDLE);
585 type = _wapi_handle_type (handle);
587 if (event_ops[type].reset == NULL) {
588 SetLastError (ERROR_INVALID_HANDLE);
592 return(event_ops[type].reset (handle));
595 static gboolean event_set (gpointer handle)
597 struct _WapiHandle_event *event_handle;
601 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_EVENT,
602 (gpointer *)&event_handle);
604 g_warning ("%s: error looking up event handle %p", __func__,
609 thr_ret = _wapi_handle_lock_handle (handle);
610 g_assert (thr_ret == 0);
612 DEBUG ("%s: Setting event handle %p", __func__, handle);
614 if (event_handle->manual == TRUE) {
615 _wapi_handle_set_signal_state (handle, TRUE, TRUE);
617 event_handle->set_count = 1;
618 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
621 thr_ret = _wapi_handle_unlock_handle (handle);
622 g_assert (thr_ret == 0);
627 static gboolean namedevent_set (gpointer handle)
629 struct _WapiHandle_namedevent *namedevent_handle;
633 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDEVENT,
634 (gpointer *)&namedevent_handle);
636 g_warning ("%s: error looking up named event handle %p",
641 thr_ret = _wapi_handle_lock_shared_handles ();
642 g_assert (thr_ret == 0);
644 DEBUG ("%s: Setting named event handle %p", __func__, handle);
646 if (namedevent_handle->manual == TRUE) {
647 _wapi_shared_handle_set_signal_state (handle, TRUE);
649 namedevent_handle->set_count = 1;
650 _wapi_shared_handle_set_signal_state (handle, TRUE);
653 _wapi_handle_unlock_shared_handles ();
660 * @handle: The event handle
662 * Sets the event handle @handle to the signalled state.
664 * If @handle is a manual reset event, it remains signalled until it
665 * is reset with ResetEvent(). An auto reset event remains signalled
666 * until a single thread has waited for it, at which time @handle is
667 * automatically reset to unsignalled.
669 * Return value: %TRUE on success, %FALSE otherwise. (Currently only
670 * ever returns %TRUE).
672 gboolean SetEvent(gpointer handle)
676 if (handle == NULL) {
677 SetLastError (ERROR_INVALID_HANDLE);
681 type = _wapi_handle_type (handle);
683 if (event_ops[type].set == NULL) {
684 SetLastError (ERROR_INVALID_HANDLE);
688 return(event_ops[type].set (handle));
691 gpointer OpenEvent (guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, const gunichar2 *name)
699 mono_once (&event_ops_once, event_ops_init);
701 /* w32 seems to guarantee that opening named objects can't
704 thr_ret = _wapi_namespace_lock ();
705 g_assert (thr_ret == 0);
707 utf8_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
709 DEBUG ("%s: Opening named event [%s]", __func__, utf8_name);
711 offset = _wapi_search_handle_namespace (WAPI_HANDLE_NAMEDEVENT,
714 /* The name has already been used for a different
717 SetLastError (ERROR_INVALID_HANDLE);
719 } else if (offset == 0) {
720 /* This name doesn't exist */
721 SetLastError (ERROR_FILE_NOT_FOUND); /* yes, really */
725 /* A new reference to an existing named event, so just create
728 handle = _wapi_handle_new_from_offset (WAPI_HANDLE_NAMEDEVENT, offset,
731 if (handle == _WAPI_HANDLE_INVALID) {
732 g_warning ("%s: error opening named event handle", __func__);
733 SetLastError (ERROR_GEN_FAILURE);
738 DEBUG ("%s: returning named event handle %p", __func__, handle);
743 _wapi_namespace_unlock (NULL);