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>
26 static void event_signal(gpointer handle
);
27 static gboolean
event_own (gpointer handle
);
29 static void namedevent_signal (gpointer handle
);
30 static gboolean
namedevent_own (gpointer handle
);
32 struct _WapiHandleOps _wapi_event_ops
= {
34 event_signal
, /* signal */
37 NULL
, /* special_wait */
41 struct _WapiHandleOps _wapi_namedevent_ops
= {
43 namedevent_signal
, /* signal */
44 namedevent_own
, /* own */
48 static gboolean
event_pulse (gpointer handle
);
49 static gboolean
event_reset (gpointer handle
);
50 static gboolean
event_set (gpointer handle
);
52 static gboolean
namedevent_pulse (gpointer handle
);
53 static gboolean
namedevent_reset (gpointer handle
);
54 static gboolean
namedevent_set (gpointer handle
);
58 gboolean (*pulse
)(gpointer handle
);
59 gboolean (*reset
)(gpointer handle
);
60 gboolean (*set
)(gpointer handle
);
61 } event_ops
[WAPI_HANDLE_COUNT
] = {
68 {event_pulse
, event_reset
, event_set
},
75 {namedevent_pulse
, namedevent_reset
, namedevent_set
},
78 void _wapi_event_details (gpointer handle_info
)
80 struct _WapiHandle_event
*event
= (struct _WapiHandle_event
*)handle_info
;
82 g_print ("manual: %s", event
->manual
?"TRUE":"FALSE");
85 static mono_once_t event_ops_once
=MONO_ONCE_INIT
;
87 static void event_ops_init (void)
89 _wapi_handle_register_capabilities (WAPI_HANDLE_EVENT
,
90 WAPI_HANDLE_CAP_WAIT
|
91 WAPI_HANDLE_CAP_SIGNAL
);
92 _wapi_handle_register_capabilities (WAPI_HANDLE_NAMEDEVENT
,
93 WAPI_HANDLE_CAP_WAIT
|
94 WAPI_HANDLE_CAP_SIGNAL
);
97 static void event_signal(gpointer handle
)
102 static gboolean
event_own (gpointer handle
)
104 struct _WapiHandle_event
*event_handle
;
107 ok
=_wapi_lookup_handle (handle
, WAPI_HANDLE_EVENT
,
108 (gpointer
*)&event_handle
);
110 g_warning ("%s: error looking up event handle %p", __func__
,
116 g_message("%s: owning event handle %p", __func__
, handle
);
119 if(event_handle
->manual
==FALSE
) {
120 g_assert (event_handle
->set_count
> 0);
122 if (--event_handle
->set_count
== 0) {
123 _wapi_handle_set_signal_state (handle
, FALSE
, FALSE
);
130 static void namedevent_signal (gpointer handle
)
135 /* NB, always called with the shared handle lock held */
136 static gboolean
namedevent_own (gpointer handle
)
138 struct _WapiHandle_namedevent
*namedevent_handle
;
142 g_message ("%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
);
177 g_message ("%s: Creating unnamed event", __func__
);
180 event_handle
.manual
= manual
;
181 event_handle
.set_count
= 0;
183 if (initial
== TRUE
) {
184 if (manual
== FALSE
) {
185 event_handle
.set_count
= 1;
189 handle
= _wapi_handle_new (WAPI_HANDLE_EVENT
, &event_handle
);
190 if (handle
== _WAPI_HANDLE_INVALID
) {
191 g_warning ("%s: error creating event handle", __func__
);
192 SetLastError (ERROR_GEN_FAILURE
);
196 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle
,
198 thr_ret
= _wapi_handle_lock_handle (handle
);
199 g_assert (thr_ret
== 0);
201 if (initial
== TRUE
) {
202 _wapi_handle_set_signal_state (handle
, TRUE
, FALSE
);
206 g_message("%s: created new event handle %p", __func__
, handle
);
209 thr_ret
= _wapi_handle_unlock_handle (handle
);
210 g_assert (thr_ret
== 0);
211 pthread_cleanup_pop (0);
216 static gpointer
namedevent_create (WapiSecurityAttributes
*security G_GNUC_UNUSED
,
217 gboolean manual
, gboolean initial
,
218 const gunichar2
*name G_GNUC_UNUSED
)
220 struct _WapiHandle_namedevent namedevent_handle
= {{{0}}, 0};
228 /* w32 seems to guarantee that opening named objects can't
231 thr_ret
= _wapi_namespace_lock ();
232 g_assert (thr_ret
== 0);
234 /* Need to blow away any old errors here, because code tests
235 * for ERROR_ALREADY_EXISTS on success (!) to see if an event
236 * was freshly created
238 SetLastError (ERROR_SUCCESS
);
240 utf8_name
= g_utf16_to_utf8 (name
, -1, NULL
, NULL
, NULL
);
243 g_message ("%s: Creating named event [%s]", __func__
, utf8_name
);
246 offset
= _wapi_search_handle_namespace (WAPI_HANDLE_NAMEDEVENT
,
249 /* The name has already been used for a different
252 SetLastError (ERROR_INVALID_HANDLE
);
254 } else if (offset
!= 0) {
255 /* Not an error, but this is how the caller is
256 * informed that the event wasn't freshly created
258 SetLastError (ERROR_ALREADY_EXISTS
);
260 /* Fall through to create the event handle. */
263 /* A new named event, so create both the private and
267 if (strlen (utf8_name
) < MAX_PATH
) {
268 namelen
= strlen (utf8_name
);
273 memcpy (&namedevent_handle
.sharedns
.name
, utf8_name
, namelen
);
275 namedevent_handle
.manual
= manual
;
276 namedevent_handle
.set_count
= 0;
278 if (initial
== TRUE
) {
279 if (manual
== FALSE
) {
280 namedevent_handle
.set_count
= 1;
284 handle
= _wapi_handle_new (WAPI_HANDLE_NAMEDEVENT
,
287 /* A new reference to an existing named event, so just
288 * create the private part
290 handle
= _wapi_handle_new_from_offset (WAPI_HANDLE_NAMEDEVENT
,
294 if (handle
== _WAPI_HANDLE_INVALID
) {
295 g_warning ("%s: error creating event handle", __func__
);
296 SetLastError (ERROR_GEN_FAILURE
);
302 /* Set the initial state, as this is a completely new
305 thr_ret
= _wapi_handle_lock_shared_handles ();
306 g_assert (thr_ret
== 0);
308 if (initial
== TRUE
) {
309 _wapi_shared_handle_set_signal_state (handle
, TRUE
);
312 _wapi_handle_unlock_shared_handles ();
316 g_message ("%s: returning event handle %p", __func__
, handle
);
322 _wapi_namespace_unlock (NULL
);
331 * @security: Ignored for now.
332 * @manual: Specifies whether the new event handle has manual or auto
334 * @initial: Specifies whether the new event handle is initially
336 * @name:Pointer to a string specifying the name of this name, or
337 * %NULL. Currently ignored.
339 * Creates a new event handle.
341 * An event handle is signalled with SetEvent(). If the new handle is
342 * a manual reset event handle, it remains signalled until it is reset
343 * with ResetEvent(). An auto reset event remains signalled until a
344 * single thread has waited for it, at which time the event handle is
345 * automatically reset to unsignalled.
347 * Return value: A new handle, or %NULL on error.
349 gpointer
CreateEvent(WapiSecurityAttributes
*security G_GNUC_UNUSED
,
350 gboolean manual
, gboolean initial
,
351 const gunichar2
*name G_GNUC_UNUSED
)
353 mono_once (&event_ops_once
, event_ops_init
);
356 return(event_create (security
, manual
, initial
));
358 return(namedevent_create (security
, manual
, initial
, name
));
362 static gboolean
event_pulse (gpointer handle
)
364 struct _WapiHandle_event
*event_handle
;
368 ok
= _wapi_lookup_handle (handle
, WAPI_HANDLE_EVENT
,
369 (gpointer
*)&event_handle
);
371 g_warning ("%s: error looking up event handle %p", __func__
,
376 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle
,
378 thr_ret
= _wapi_handle_lock_handle (handle
);
379 g_assert (thr_ret
== 0);
382 g_message ("%s: Pulsing event handle %p", __func__
, handle
);
385 if (event_handle
->manual
== TRUE
) {
386 _wapi_handle_set_signal_state (handle
, TRUE
, TRUE
);
388 event_handle
->set_count
= 1;
389 _wapi_handle_set_signal_state (handle
, TRUE
, FALSE
);
392 thr_ret
= _wapi_handle_unlock_handle (handle
);
393 g_assert (thr_ret
== 0);
395 pthread_cleanup_pop (0);
397 if (event_handle
->manual
== TRUE
) {
398 /* For a manual-reset event, we're about to try and
399 * get the handle lock again, so give other threads a
404 /* Reset the handle signal state */
405 /* I'm not sure whether or not we need a barrier here
406 * to make sure that all threads waiting on the event
407 * have proceeded. Currently we rely on broadcasting
411 g_message ("%s: Obtained write lock on event handle %p",
415 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle
, handle
);
416 thr_ret
= _wapi_handle_lock_handle (handle
);
417 g_assert (thr_ret
== 0);
419 _wapi_handle_set_signal_state (handle
, FALSE
, FALSE
);
421 thr_ret
= _wapi_handle_unlock_handle (handle
);
422 g_assert (thr_ret
== 0);
423 pthread_cleanup_pop (0);
429 static gboolean
namedevent_pulse (gpointer handle
)
431 struct _WapiHandle_namedevent
*namedevent_handle
;
435 ok
= _wapi_lookup_handle (handle
, WAPI_HANDLE_NAMEDEVENT
,
436 (gpointer
*)&namedevent_handle
);
438 g_warning ("%s: error looking up named event handle %p",
443 thr_ret
= _wapi_handle_lock_shared_handles ();
444 g_assert (thr_ret
== 0);
447 g_message ("%s: Pulsing named event handle %p", __func__
, handle
);
450 if (namedevent_handle
->manual
== TRUE
) {
451 _wapi_shared_handle_set_signal_state (handle
, TRUE
);
453 namedevent_handle
->set_count
= 1;
454 _wapi_shared_handle_set_signal_state (handle
, TRUE
);
457 _wapi_handle_unlock_shared_handles ();
459 if (namedevent_handle
->manual
== TRUE
) {
460 /* For a manual-reset event, we're about to try and
461 * get the handle lock again, so give other processes
464 _wapi_handle_spin (200);
466 /* Reset the handle signal state */
467 /* I'm not sure whether or not we need a barrier here
468 * to make sure that all threads waiting on the event
469 * have proceeded. Currently we rely on waiting for
470 * twice the shared handle poll interval.
473 g_message ("%s: Obtained write lock on event handle %p",
477 thr_ret
= _wapi_handle_lock_shared_handles ();
478 g_assert (thr_ret
== 0);
480 _wapi_shared_handle_set_signal_state (handle
, FALSE
);
482 _wapi_handle_unlock_shared_handles ();
490 * @handle: The event handle.
492 * Sets the event handle @handle to the signalled state, and then
493 * resets it to unsignalled after informing any waiting threads.
495 * If @handle is a manual reset event, all waiting threads that can be
496 * released immediately are released. @handle is then reset. If
497 * @handle is an auto reset event, one waiting thread is released even
498 * if multiple threads are waiting.
500 * Return value: %TRUE on success, %FALSE otherwise. (Currently only
501 * ever returns %TRUE).
503 gboolean
PulseEvent(gpointer handle
)
507 if (handle
== NULL
) {
508 SetLastError (ERROR_INVALID_HANDLE
);
512 type
= _wapi_handle_type (handle
);
514 if (event_ops
[type
].pulse
== NULL
) {
515 SetLastError (ERROR_INVALID_HANDLE
);
519 return(event_ops
[type
].pulse (handle
));
522 static gboolean
event_reset (gpointer handle
)
524 struct _WapiHandle_event
*event_handle
;
528 ok
= _wapi_lookup_handle (handle
, WAPI_HANDLE_EVENT
,
529 (gpointer
*)&event_handle
);
531 g_warning ("%s: error looking up event handle %p",
537 g_message ("%s: Resetting event handle %p", __func__
, handle
);
540 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle
,
542 thr_ret
= _wapi_handle_lock_handle (handle
);
543 g_assert (thr_ret
== 0);
545 if (_wapi_handle_issignalled (handle
) == FALSE
) {
547 g_message ("%s: No need to reset event handle %p", __func__
,
552 g_message ("%s: Obtained write lock on event handle %p",
556 _wapi_handle_set_signal_state (handle
, FALSE
, FALSE
);
559 event_handle
->set_count
= 0;
561 thr_ret
= _wapi_handle_unlock_handle (handle
);
562 g_assert (thr_ret
== 0);
564 pthread_cleanup_pop (0);
569 static gboolean
namedevent_reset (gpointer handle
)
571 struct _WapiHandle_namedevent
*namedevent_handle
;
575 ok
= _wapi_lookup_handle (handle
, WAPI_HANDLE_NAMEDEVENT
,
576 (gpointer
*)&namedevent_handle
);
578 g_warning ("%s: error looking up named event handle %p",
584 g_message ("%s: Resetting named event handle %p", __func__
, handle
);
587 thr_ret
= _wapi_handle_lock_shared_handles ();
588 g_assert (thr_ret
== 0);
590 if (_wapi_handle_issignalled (handle
) == FALSE
) {
592 g_message ("%s: No need to reset named event handle %p",
597 g_message ("%s: Obtained write lock on named event handle %p",
601 _wapi_shared_handle_set_signal_state (handle
, FALSE
);
604 namedevent_handle
->set_count
= 0;
606 _wapi_handle_unlock_shared_handles ();
613 * @handle: The event handle.
615 * Resets the event handle @handle to the unsignalled state.
617 * Return value: %TRUE on success, %FALSE otherwise. (Currently only
618 * ever returns %TRUE).
620 gboolean
ResetEvent(gpointer handle
)
624 if (handle
== NULL
) {
625 SetLastError (ERROR_INVALID_HANDLE
);
629 type
= _wapi_handle_type (handle
);
631 if (event_ops
[type
].reset
== NULL
) {
632 SetLastError (ERROR_INVALID_HANDLE
);
636 return(event_ops
[type
].reset (handle
));
639 static gboolean
event_set (gpointer handle
)
641 struct _WapiHandle_event
*event_handle
;
645 ok
= _wapi_lookup_handle (handle
, WAPI_HANDLE_EVENT
,
646 (gpointer
*)&event_handle
);
648 g_warning ("%s: error looking up event handle %p", __func__
,
653 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle
,
655 thr_ret
= _wapi_handle_lock_handle (handle
);
656 g_assert (thr_ret
== 0);
659 g_message ("%s: Setting event handle %p", __func__
, handle
);
662 if (event_handle
->manual
== TRUE
) {
663 _wapi_handle_set_signal_state (handle
, TRUE
, TRUE
);
665 event_handle
->set_count
= 1;
666 _wapi_handle_set_signal_state (handle
, TRUE
, FALSE
);
669 thr_ret
= _wapi_handle_unlock_handle (handle
);
670 g_assert (thr_ret
== 0);
672 pthread_cleanup_pop (0);
677 static gboolean
namedevent_set (gpointer handle
)
679 struct _WapiHandle_namedevent
*namedevent_handle
;
683 ok
= _wapi_lookup_handle (handle
, WAPI_HANDLE_NAMEDEVENT
,
684 (gpointer
*)&namedevent_handle
);
686 g_warning ("%s: error looking up named event handle %p",
691 thr_ret
= _wapi_handle_lock_shared_handles ();
692 g_assert (thr_ret
== 0);
695 g_message ("%s: Setting named event handle %p", __func__
, handle
);
698 if (namedevent_handle
->manual
== TRUE
) {
699 _wapi_shared_handle_set_signal_state (handle
, TRUE
);
701 namedevent_handle
->set_count
= 1;
702 _wapi_shared_handle_set_signal_state (handle
, TRUE
);
705 _wapi_handle_unlock_shared_handles ();
712 * @handle: The event handle
714 * Sets the event handle @handle to the signalled state.
716 * If @handle is a manual reset event, it remains signalled until it
717 * is reset with ResetEvent(). An auto reset event remains signalled
718 * until a single thread has waited for it, at which time @handle is
719 * automatically reset to unsignalled.
721 * Return value: %TRUE on success, %FALSE otherwise. (Currently only
722 * ever returns %TRUE).
724 gboolean
SetEvent(gpointer handle
)
728 if (handle
== NULL
) {
729 SetLastError (ERROR_INVALID_HANDLE
);
733 type
= _wapi_handle_type (handle
);
735 if (event_ops
[type
].set
== NULL
) {
736 SetLastError (ERROR_INVALID_HANDLE
);
740 return(event_ops
[type
].set (handle
));
743 gpointer
OpenEvent (guint32 access G_GNUC_UNUSED
, gboolean inherit G_GNUC_UNUSED
, const gunichar2
*name
)
751 mono_once (&event_ops_once
, event_ops_init
);
753 /* w32 seems to guarantee that opening named objects can't
756 thr_ret
= _wapi_namespace_lock ();
757 g_assert (thr_ret
== 0);
759 utf8_name
= g_utf16_to_utf8 (name
, -1, NULL
, NULL
, NULL
);
762 g_message ("%s: Opening named event [%s]", __func__
, utf8_name
);
765 offset
= _wapi_search_handle_namespace (WAPI_HANDLE_NAMEDEVENT
,
768 /* The name has already been used for a different
771 SetLastError (ERROR_INVALID_HANDLE
);
773 } else if (offset
== 0) {
774 /* This name doesn't exist */
775 SetLastError (ERROR_FILE_NOT_FOUND
); /* yes, really */
779 /* A new reference to an existing named event, so just create
782 handle
= _wapi_handle_new_from_offset (WAPI_HANDLE_NAMEDEVENT
, offset
,
785 if (handle
== _WAPI_HANDLE_INVALID
) {
786 g_warning ("%s: error opening named event handle", __func__
);
787 SetLastError (ERROR_GEN_FAILURE
);
793 g_message ("%s: returning named event handle %p", __func__
, handle
);
799 _wapi_namespace_unlock (NULL
);