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/event-private.h>
22 #include <mono/utils/mono-mutex.h>
24 #define DEBUG(...) g_message(__VA_ARGS__)
29 static void event_signal(gpointer handle
);
30 static gboolean
event_own (gpointer handle
);
32 static void namedevent_signal (gpointer handle
);
33 static gboolean
namedevent_own (gpointer handle
);
35 struct _WapiHandleOps _wapi_event_ops
= {
37 event_signal
, /* signal */
40 NULL
, /* special_wait */
44 struct _WapiHandleOps _wapi_namedevent_ops
= {
46 namedevent_signal
, /* signal */
47 namedevent_own
, /* own */
51 static gboolean
event_pulse (gpointer handle
);
52 static gboolean
event_reset (gpointer handle
);
53 static gboolean
event_set (gpointer handle
);
55 static gboolean
namedevent_pulse (gpointer handle
);
56 static gboolean
namedevent_reset (gpointer handle
);
57 static gboolean
namedevent_set (gpointer handle
);
61 gboolean (*pulse
)(gpointer handle
);
62 gboolean (*reset
)(gpointer handle
);
63 gboolean (*set
)(gpointer handle
);
64 } event_ops
[WAPI_HANDLE_COUNT
] = {
71 {event_pulse
, event_reset
, event_set
},
78 {namedevent_pulse
, namedevent_reset
, namedevent_set
},
81 void _wapi_event_details (gpointer handle_info
)
83 struct _WapiHandle_event
*event
= (struct _WapiHandle_event
*)handle_info
;
85 g_print ("manual: %s", event
->manual
?"TRUE":"FALSE");
88 static mono_once_t event_ops_once
=MONO_ONCE_INIT
;
90 static void event_ops_init (void)
92 _wapi_handle_register_capabilities (WAPI_HANDLE_EVENT
,
93 WAPI_HANDLE_CAP_WAIT
|
94 WAPI_HANDLE_CAP_SIGNAL
);
95 _wapi_handle_register_capabilities (WAPI_HANDLE_NAMEDEVENT
,
96 WAPI_HANDLE_CAP_WAIT
|
97 WAPI_HANDLE_CAP_SIGNAL
);
100 static void event_signal(gpointer handle
)
105 static gboolean
event_own (gpointer handle
)
107 struct _WapiHandle_event
*event_handle
;
110 ok
=_wapi_lookup_handle (handle
, WAPI_HANDLE_EVENT
,
111 (gpointer
*)&event_handle
);
113 g_warning ("%s: error looking up event handle %p", __func__
,
118 DEBUG("%s: owning event handle %p", __func__
, handle
);
120 if(event_handle
->manual
==FALSE
) {
121 g_assert (event_handle
->set_count
> 0);
123 if (--event_handle
->set_count
== 0) {
124 _wapi_handle_set_signal_state (handle
, FALSE
, FALSE
);
131 static void namedevent_signal (gpointer handle
)
136 /* NB, always called with the shared handle lock held */
137 static gboolean
namedevent_own (gpointer handle
)
139 struct _WapiHandle_namedevent
*namedevent_handle
;
142 DEBUG ("%s: owning named event handle %p", __func__
, handle
);
144 ok
= _wapi_lookup_handle (handle
, WAPI_HANDLE_NAMEDEVENT
,
145 (gpointer
*)&namedevent_handle
);
147 g_warning ("%s: error looking up named event handle %p",
152 if (namedevent_handle
->manual
== FALSE
) {
153 g_assert (namedevent_handle
->set_count
> 0);
155 if (--namedevent_handle
->set_count
== 0) {
156 _wapi_shared_handle_set_signal_state (handle
, FALSE
);
162 static gpointer
event_create (WapiSecurityAttributes
*security G_GNUC_UNUSED
,
163 gboolean manual
, gboolean initial
)
165 struct _WapiHandle_event event_handle
= {0};
169 /* Need to blow away any old errors here, because code tests
170 * for ERROR_ALREADY_EXISTS on success (!) to see if an event
171 * was freshly created
173 SetLastError (ERROR_SUCCESS
);
175 DEBUG ("%s: Creating unnamed event", __func__
);
177 event_handle
.manual
= manual
;
178 event_handle
.set_count
= 0;
180 if (initial
== TRUE
) {
181 if (manual
== FALSE
) {
182 event_handle
.set_count
= 1;
186 handle
= _wapi_handle_new (WAPI_HANDLE_EVENT
, &event_handle
);
187 if (handle
== _WAPI_HANDLE_INVALID
) {
188 g_warning ("%s: error creating event handle", __func__
);
189 SetLastError (ERROR_GEN_FAILURE
);
193 thr_ret
= _wapi_handle_lock_handle (handle
);
194 g_assert (thr_ret
== 0);
196 if (initial
== TRUE
) {
197 _wapi_handle_set_signal_state (handle
, TRUE
, FALSE
);
200 DEBUG("%s: created new event handle %p", __func__
, handle
);
202 thr_ret
= _wapi_handle_unlock_handle (handle
);
203 g_assert (thr_ret
== 0);
208 static gpointer
namedevent_create (WapiSecurityAttributes
*security G_GNUC_UNUSED
,
209 gboolean manual
, gboolean initial
,
210 const gunichar2
*name G_GNUC_UNUSED
)
212 struct _WapiHandle_namedevent namedevent_handle
= {{{0}}, 0};
220 /* w32 seems to guarantee that opening named objects can't
223 thr_ret
= _wapi_namespace_lock ();
224 g_assert (thr_ret
== 0);
226 /* Need to blow away any old errors here, because code tests
227 * for ERROR_ALREADY_EXISTS on success (!) to see if an event
228 * was freshly created
230 SetLastError (ERROR_SUCCESS
);
232 utf8_name
= g_utf16_to_utf8 (name
, -1, NULL
, NULL
, NULL
);
234 DEBUG ("%s: Creating named event [%s]", __func__
, utf8_name
);
236 offset
= _wapi_search_handle_namespace (WAPI_HANDLE_NAMEDEVENT
,
239 /* The name has already been used for a different
242 SetLastError (ERROR_INVALID_HANDLE
);
244 } else if (offset
!= 0) {
245 /* Not an error, but this is how the caller is
246 * informed that the event wasn't freshly created
248 SetLastError (ERROR_ALREADY_EXISTS
);
250 /* Fall through to create the event handle. */
253 /* A new named event, so create both the private and
257 if (strlen (utf8_name
) < MAX_PATH
) {
258 namelen
= strlen (utf8_name
);
263 memcpy (&namedevent_handle
.sharedns
.name
, utf8_name
, namelen
);
265 namedevent_handle
.manual
= manual
;
266 namedevent_handle
.set_count
= 0;
268 if (initial
== TRUE
) {
269 if (manual
== FALSE
) {
270 namedevent_handle
.set_count
= 1;
274 handle
= _wapi_handle_new (WAPI_HANDLE_NAMEDEVENT
,
277 /* A new reference to an existing named event, so just
278 * create the private part
280 handle
= _wapi_handle_new_from_offset (WAPI_HANDLE_NAMEDEVENT
,
284 if (handle
== _WAPI_HANDLE_INVALID
) {
285 g_warning ("%s: error creating event handle", __func__
);
286 SetLastError (ERROR_GEN_FAILURE
);
292 /* Set the initial state, as this is a completely new
295 thr_ret
= _wapi_handle_lock_shared_handles ();
296 g_assert (thr_ret
== 0);
298 if (initial
== TRUE
) {
299 _wapi_shared_handle_set_signal_state (handle
, TRUE
);
302 _wapi_handle_unlock_shared_handles ();
305 DEBUG ("%s: returning event handle %p", __func__
, handle
);
310 _wapi_namespace_unlock (NULL
);
319 * @security: Ignored for now.
320 * @manual: Specifies whether the new event handle has manual or auto
322 * @initial: Specifies whether the new event handle is initially
324 * @name:Pointer to a string specifying the name of this name, or
325 * %NULL. Currently ignored.
327 * Creates a new event handle.
329 * An event handle is signalled with SetEvent(). If the new handle is
330 * a manual reset event handle, it remains signalled until it is reset
331 * with ResetEvent(). An auto reset event remains signalled until a
332 * single thread has waited for it, at which time the event handle is
333 * automatically reset to unsignalled.
335 * Return value: A new handle, or %NULL on error.
337 gpointer
CreateEvent(WapiSecurityAttributes
*security G_GNUC_UNUSED
,
338 gboolean manual
, gboolean initial
,
339 const gunichar2
*name G_GNUC_UNUSED
)
341 mono_once (&event_ops_once
, event_ops_init
);
344 return(event_create (security
, manual
, initial
));
346 return(namedevent_create (security
, manual
, initial
, name
));
350 static gboolean
event_pulse (gpointer handle
)
352 struct _WapiHandle_event
*event_handle
;
356 ok
= _wapi_lookup_handle (handle
, WAPI_HANDLE_EVENT
,
357 (gpointer
*)&event_handle
);
359 g_warning ("%s: error looking up event handle %p", __func__
,
364 thr_ret
= _wapi_handle_lock_handle (handle
);
365 g_assert (thr_ret
== 0);
367 DEBUG ("%s: Pulsing event handle %p", __func__
, handle
);
369 if (event_handle
->manual
== TRUE
) {
370 _wapi_handle_set_signal_state (handle
, TRUE
, TRUE
);
372 event_handle
->set_count
= 1;
373 _wapi_handle_set_signal_state (handle
, TRUE
, FALSE
);
376 thr_ret
= _wapi_handle_unlock_handle (handle
);
377 g_assert (thr_ret
== 0);
379 if (event_handle
->manual
== TRUE
) {
380 /* For a manual-reset event, we're about to try and
381 * get the handle lock again, so give other threads a
386 /* Reset the handle signal state */
387 /* I'm not sure whether or not we need a barrier here
388 * to make sure that all threads waiting on the event
389 * have proceeded. Currently we rely on broadcasting
392 DEBUG ("%s: Obtained write lock on event handle %p",
395 thr_ret
= _wapi_handle_lock_handle (handle
);
396 g_assert (thr_ret
== 0);
398 _wapi_handle_set_signal_state (handle
, FALSE
, FALSE
);
400 thr_ret
= _wapi_handle_unlock_handle (handle
);
401 g_assert (thr_ret
== 0);
407 static gboolean
namedevent_pulse (gpointer handle
)
409 struct _WapiHandle_namedevent
*namedevent_handle
;
413 ok
= _wapi_lookup_handle (handle
, WAPI_HANDLE_NAMEDEVENT
,
414 (gpointer
*)&namedevent_handle
);
416 g_warning ("%s: error looking up named event handle %p",
421 thr_ret
= _wapi_handle_lock_shared_handles ();
422 g_assert (thr_ret
== 0);
424 DEBUG ("%s: Pulsing named event handle %p", __func__
, handle
);
426 if (namedevent_handle
->manual
== TRUE
) {
427 _wapi_shared_handle_set_signal_state (handle
, TRUE
);
429 namedevent_handle
->set_count
= 1;
430 _wapi_shared_handle_set_signal_state (handle
, TRUE
);
433 _wapi_handle_unlock_shared_handles ();
435 if (namedevent_handle
->manual
== TRUE
) {
436 /* For a manual-reset event, we're about to try and
437 * get the handle lock again, so give other processes
440 _wapi_handle_spin (200);
442 /* Reset the handle signal state */
443 /* I'm not sure whether or not we need a barrier here
444 * to make sure that all threads waiting on the event
445 * have proceeded. Currently we rely on waiting for
446 * twice the shared handle poll interval.
448 DEBUG ("%s: Obtained write lock on event handle %p",
451 thr_ret
= _wapi_handle_lock_shared_handles ();
452 g_assert (thr_ret
== 0);
454 _wapi_shared_handle_set_signal_state (handle
, FALSE
);
456 _wapi_handle_unlock_shared_handles ();
464 * @handle: The event handle.
466 * Sets the event handle @handle to the signalled state, and then
467 * resets it to unsignalled after informing any waiting threads.
469 * If @handle is a manual reset event, all waiting threads that can be
470 * released immediately are released. @handle is then reset. If
471 * @handle is an auto reset event, one waiting thread is released even
472 * if multiple threads are waiting.
474 * Return value: %TRUE on success, %FALSE otherwise. (Currently only
475 * ever returns %TRUE).
477 gboolean
PulseEvent(gpointer handle
)
481 if (handle
== NULL
) {
482 SetLastError (ERROR_INVALID_HANDLE
);
486 type
= _wapi_handle_type (handle
);
488 if (event_ops
[type
].pulse
== NULL
) {
489 SetLastError (ERROR_INVALID_HANDLE
);
493 return(event_ops
[type
].pulse (handle
));
496 static gboolean
event_reset (gpointer handle
)
498 struct _WapiHandle_event
*event_handle
;
502 ok
= _wapi_lookup_handle (handle
, WAPI_HANDLE_EVENT
,
503 (gpointer
*)&event_handle
);
505 g_warning ("%s: error looking up event handle %p",
510 DEBUG ("%s: Resetting event handle %p", __func__
, handle
);
512 thr_ret
= _wapi_handle_lock_handle (handle
);
513 g_assert (thr_ret
== 0);
515 if (_wapi_handle_issignalled (handle
) == FALSE
) {
516 DEBUG ("%s: No need to reset event handle %p", __func__
,
519 DEBUG ("%s: Obtained write lock on event handle %p",
522 _wapi_handle_set_signal_state (handle
, FALSE
, FALSE
);
525 event_handle
->set_count
= 0;
527 thr_ret
= _wapi_handle_unlock_handle (handle
);
528 g_assert (thr_ret
== 0);
533 static gboolean
namedevent_reset (gpointer handle
)
535 struct _WapiHandle_namedevent
*namedevent_handle
;
539 ok
= _wapi_lookup_handle (handle
, WAPI_HANDLE_NAMEDEVENT
,
540 (gpointer
*)&namedevent_handle
);
542 g_warning ("%s: error looking up named event handle %p",
547 DEBUG ("%s: Resetting named event handle %p", __func__
, handle
);
549 thr_ret
= _wapi_handle_lock_shared_handles ();
550 g_assert (thr_ret
== 0);
552 if (_wapi_handle_issignalled (handle
) == FALSE
) {
553 DEBUG ("%s: No need to reset named event handle %p",
556 DEBUG ("%s: Obtained write lock on named event handle %p",
559 _wapi_shared_handle_set_signal_state (handle
, FALSE
);
562 namedevent_handle
->set_count
= 0;
564 _wapi_handle_unlock_shared_handles ();
571 * @handle: The event handle.
573 * Resets the event handle @handle to the unsignalled state.
575 * Return value: %TRUE on success, %FALSE otherwise. (Currently only
576 * ever returns %TRUE).
578 gboolean
ResetEvent(gpointer handle
)
582 if (handle
== NULL
) {
583 SetLastError (ERROR_INVALID_HANDLE
);
587 type
= _wapi_handle_type (handle
);
589 if (event_ops
[type
].reset
== NULL
) {
590 SetLastError (ERROR_INVALID_HANDLE
);
594 return(event_ops
[type
].reset (handle
));
597 static gboolean
event_set (gpointer handle
)
599 struct _WapiHandle_event
*event_handle
;
603 ok
= _wapi_lookup_handle (handle
, WAPI_HANDLE_EVENT
,
604 (gpointer
*)&event_handle
);
606 g_warning ("%s: error looking up event handle %p", __func__
,
611 thr_ret
= _wapi_handle_lock_handle (handle
);
612 g_assert (thr_ret
== 0);
614 DEBUG ("%s: Setting event handle %p", __func__
, handle
);
616 if (event_handle
->manual
== TRUE
) {
617 _wapi_handle_set_signal_state (handle
, TRUE
, TRUE
);
619 event_handle
->set_count
= 1;
620 _wapi_handle_set_signal_state (handle
, TRUE
, FALSE
);
623 thr_ret
= _wapi_handle_unlock_handle (handle
);
624 g_assert (thr_ret
== 0);
629 static gboolean
namedevent_set (gpointer handle
)
631 struct _WapiHandle_namedevent
*namedevent_handle
;
635 ok
= _wapi_lookup_handle (handle
, WAPI_HANDLE_NAMEDEVENT
,
636 (gpointer
*)&namedevent_handle
);
638 g_warning ("%s: error looking up named event handle %p",
643 thr_ret
= _wapi_handle_lock_shared_handles ();
644 g_assert (thr_ret
== 0);
646 DEBUG ("%s: Setting named event handle %p", __func__
, handle
);
648 if (namedevent_handle
->manual
== TRUE
) {
649 _wapi_shared_handle_set_signal_state (handle
, TRUE
);
651 namedevent_handle
->set_count
= 1;
652 _wapi_shared_handle_set_signal_state (handle
, TRUE
);
655 _wapi_handle_unlock_shared_handles ();
662 * @handle: The event handle
664 * Sets the event handle @handle to the signalled state.
666 * If @handle is a manual reset event, it remains signalled until it
667 * is reset with ResetEvent(). An auto reset event remains signalled
668 * until a single thread has waited for it, at which time @handle is
669 * automatically reset to unsignalled.
671 * Return value: %TRUE on success, %FALSE otherwise. (Currently only
672 * ever returns %TRUE).
674 gboolean
SetEvent(gpointer handle
)
678 if (handle
== NULL
) {
679 SetLastError (ERROR_INVALID_HANDLE
);
683 type
= _wapi_handle_type (handle
);
685 if (event_ops
[type
].set
== NULL
) {
686 SetLastError (ERROR_INVALID_HANDLE
);
690 return(event_ops
[type
].set (handle
));
693 gpointer
OpenEvent (guint32 access G_GNUC_UNUSED
, gboolean inherit G_GNUC_UNUSED
, const gunichar2
*name
)
701 mono_once (&event_ops_once
, event_ops_init
);
703 /* w32 seems to guarantee that opening named objects can't
706 thr_ret
= _wapi_namespace_lock ();
707 g_assert (thr_ret
== 0);
709 utf8_name
= g_utf16_to_utf8 (name
, -1, NULL
, NULL
, NULL
);
711 DEBUG ("%s: Opening named event [%s]", __func__
, utf8_name
);
713 offset
= _wapi_search_handle_namespace (WAPI_HANDLE_NAMEDEVENT
,
716 /* The name has already been used for a different
719 SetLastError (ERROR_INVALID_HANDLE
);
721 } else if (offset
== 0) {
722 /* This name doesn't exist */
723 SetLastError (ERROR_FILE_NOT_FOUND
); /* yes, really */
727 /* A new reference to an existing named event, so just create
730 handle
= _wapi_handle_new_from_offset (WAPI_HANDLE_NAMEDEVENT
, offset
,
733 if (handle
== _WAPI_HANDLE_INVALID
) {
734 g_warning ("%s: error opening named event handle", __func__
);
735 SetLastError (ERROR_GEN_FAILURE
);
740 DEBUG ("%s: returning named event handle %p", __func__
, handle
);
745 _wapi_namespace_unlock (NULL
);