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/event-private.h>
18 #include <mono/io-layer/io-trace.h>
19 #include <mono/utils/mono-once.h>
20 #include <mono/utils/mono-logger-internals.h>
21 #include <mono/utils/w32handle.h>
23 static void event_signal(gpointer handle);
24 static gboolean event_own (gpointer handle);
25 static void event_details (gpointer data);
26 static const gchar* event_typename (void);
27 static gsize event_typesize (void);
29 static void namedevent_signal (gpointer handle);
30 static gboolean namedevent_own (gpointer handle);
31 static void namedevent_details (gpointer data);
32 static const gchar* namedevent_typename (void);
33 static gsize namedevent_typesize (void);
35 static MonoW32HandleOps _wapi_event_ops = {
37 event_signal, /* signal */
40 NULL, /* special_wait */
42 event_details, /* details */
43 event_typename, /* typename */
44 event_typesize, /* typesize */
47 static MonoW32HandleOps _wapi_namedevent_ops = {
49 namedevent_signal, /* signal */
50 namedevent_own, /* own */
52 NULL, /* special_wait */
54 namedevent_details, /* details */
55 namedevent_typename, /* typename */
56 namedevent_typesize, /* typesize */
60 _wapi_event_init (void)
62 mono_w32handle_register_ops (MONO_W32HANDLE_EVENT, &_wapi_event_ops);
63 mono_w32handle_register_ops (MONO_W32HANDLE_NAMEDEVENT, &_wapi_namedevent_ops);
65 mono_w32handle_register_capabilities (MONO_W32HANDLE_EVENT,
66 (MonoW32HandleCapability)(MONO_W32HANDLE_CAP_WAIT | MONO_W32HANDLE_CAP_SIGNAL));
67 mono_w32handle_register_capabilities (MONO_W32HANDLE_NAMEDEVENT,
68 (MonoW32HandleCapability)(MONO_W32HANDLE_CAP_WAIT | MONO_W32HANDLE_CAP_SIGNAL));
71 static const char* event_handle_type_to_string (MonoW32HandleType type)
74 case MONO_W32HANDLE_EVENT: return "event";
75 case MONO_W32HANDLE_NAMEDEVENT: return "named event";
77 g_assert_not_reached ();
81 static gboolean event_handle_own (gpointer handle, MonoW32HandleType type)
83 struct _WapiHandle_event *event_handle;
86 ok = mono_w32handle_lookup (handle, type, (gpointer *)&event_handle);
88 g_warning ("%s: error looking up %s handle %p",
89 __func__, event_handle_type_to_string (type), handle);
93 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: owning %s handle %p",
94 __func__, event_handle_type_to_string (type), handle);
96 if (!event_handle->manual) {
97 g_assert (event_handle->set_count > 0);
98 event_handle->set_count --;
100 if (event_handle->set_count == 0)
101 mono_w32handle_set_signal_state (handle, FALSE, FALSE);
107 static void event_signal(gpointer handle)
112 static gboolean event_own (gpointer handle)
114 return event_handle_own (handle, MONO_W32HANDLE_EVENT);
117 static void namedevent_signal (gpointer handle)
122 /* NB, always called with the shared handle lock held */
123 static gboolean namedevent_own (gpointer handle)
125 return event_handle_own (handle, MONO_W32HANDLE_NAMEDEVENT);
128 static void event_details (gpointer data)
130 struct _WapiHandle_event *event = (struct _WapiHandle_event *)data;
131 g_print ("manual: %s, set_count: %d",
132 event->manual ? "TRUE" : "FALSE", event->set_count);
135 static void namedevent_details (gpointer data)
137 struct _WapiHandle_namedevent *namedevent = (struct _WapiHandle_namedevent *)data;
138 g_print ("manual: %s, set_count: %d, name: \"%s\"",
139 namedevent->e.manual ? "TRUE" : "FALSE", namedevent->e.set_count, namedevent->sharedns.name);
142 static const gchar* event_typename (void)
147 static gsize event_typesize (void)
149 return sizeof (struct _WapiHandle_event);
152 static const gchar* namedevent_typename (void)
157 static gsize namedevent_typesize (void)
159 return sizeof (struct _WapiHandle_namedevent);
162 static gpointer event_handle_create (struct _WapiHandle_event *event_handle, MonoW32HandleType type, gboolean manual, gboolean initial)
167 event_handle->manual = manual;
168 event_handle->set_count = (initial && !manual) ? 1 : 0;
170 handle = mono_w32handle_new (type, event_handle);
171 if (handle == INVALID_HANDLE_VALUE) {
172 g_warning ("%s: error creating %s handle",
173 __func__, event_handle_type_to_string (type));
174 SetLastError (ERROR_GEN_FAILURE);
178 thr_ret = mono_w32handle_lock_handle (handle);
179 g_assert (thr_ret == 0);
182 mono_w32handle_set_signal_state (handle, TRUE, FALSE);
184 thr_ret = mono_w32handle_unlock_handle (handle);
185 g_assert (thr_ret == 0);
187 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: created %s handle %p",
188 __func__, event_handle_type_to_string (type), handle);
193 static gpointer event_create (gboolean manual, gboolean initial)
195 struct _WapiHandle_event event_handle;
196 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: creating %s handle",
197 __func__, event_handle_type_to_string (MONO_W32HANDLE_EVENT));
198 return event_handle_create (&event_handle, MONO_W32HANDLE_EVENT, manual, initial);
201 static gpointer namedevent_create (gboolean manual, gboolean initial, const gunichar2 *name G_GNUC_UNUSED)
207 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: creating %s handle",
208 __func__, event_handle_type_to_string (MONO_W32HANDLE_NAMEDEVENT));
210 /* w32 seems to guarantee that opening named objects can't race each other */
211 thr_ret = _wapi_namespace_lock ();
212 g_assert (thr_ret == 0);
214 utf8_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
216 handle = _wapi_search_handle_namespace (MONO_W32HANDLE_NAMEDEVENT, utf8_name);
217 if (handle == INVALID_HANDLE_VALUE) {
218 /* The name has already been used for a different object. */
220 SetLastError (ERROR_INVALID_HANDLE);
222 /* Not an error, but this is how the caller is informed that the event wasn't freshly created */
223 SetLastError (ERROR_ALREADY_EXISTS);
225 /* this is used as creating a new handle */
226 mono_w32handle_ref (handle);
228 /* A new named event */
229 struct _WapiHandle_namedevent namedevent_handle;
231 strncpy (&namedevent_handle.sharedns.name [0], utf8_name, MAX_PATH);
232 namedevent_handle.sharedns.name [MAX_PATH] = '\0';
234 handle = event_handle_create ((struct _WapiHandle_event*) &namedevent_handle, MONO_W32HANDLE_NAMEDEVENT, manual, initial);
239 thr_ret = _wapi_namespace_unlock (NULL);
240 g_assert (thr_ret == 0);
248 * @security: Ignored for now.
249 * @manual: Specifies whether the new event handle has manual or auto
251 * @initial: Specifies whether the new event handle is initially
253 * @name:Pointer to a string specifying the name of this name, or
254 * %NULL. Currently ignored.
256 * Creates a new event handle.
258 * An event handle is signalled with SetEvent(). If the new handle is
259 * a manual reset event handle, it remains signalled until it is reset
260 * with ResetEvent(). An auto reset event remains signalled until a
261 * single thread has waited for it, at which time the event handle is
262 * automatically reset to unsignalled.
264 * Return value: A new handle, or %NULL on error.
266 gpointer CreateEvent(WapiSecurityAttributes *security G_GNUC_UNUSED,
267 gboolean manual, gboolean initial,
268 const gunichar2 *name G_GNUC_UNUSED)
270 /* Need to blow away any old errors here, because code tests
271 * for ERROR_ALREADY_EXISTS on success (!) to see if an event
272 * was freshly created
274 SetLastError (ERROR_SUCCESS);
276 return name ? namedevent_create (manual, initial, name) : event_create (manual, initial);
281 * @handle: The event handle.
283 * Sets the event handle @handle to the signalled state, and then
284 * resets it to unsignalled after informing any waiting threads.
286 * If @handle is a manual reset event, all waiting threads that can be
287 * released immediately are released. @handle is then reset. If
288 * @handle is an auto reset event, one waiting thread is released even
289 * if multiple threads are waiting.
291 * Return value: %TRUE on success, %FALSE otherwise. (Currently only
292 * ever returns %TRUE).
294 gboolean PulseEvent(gpointer handle)
296 MonoW32HandleType type;
297 struct _WapiHandle_event *event_handle;
300 if (handle == NULL) {
301 SetLastError (ERROR_INVALID_HANDLE);
305 switch (type = mono_w32handle_get_type (handle)) {
306 case MONO_W32HANDLE_EVENT:
307 case MONO_W32HANDLE_NAMEDEVENT:
310 SetLastError (ERROR_INVALID_HANDLE);
314 if (!mono_w32handle_lookup (handle, type, (gpointer *)&event_handle)) {
315 g_warning ("%s: error looking up %s handle %p",
316 __func__, event_handle_type_to_string (type), handle);
320 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: pulsing %s handle %p",
321 __func__, event_handle_type_to_string (type), handle);
323 thr_ret = mono_w32handle_lock_handle (handle);
324 g_assert (thr_ret == 0);
326 if (!event_handle->manual) {
327 event_handle->set_count = 1;
328 mono_w32handle_set_signal_state (handle, TRUE, FALSE);
330 mono_w32handle_set_signal_state (handle, TRUE, TRUE);
332 thr_ret = mono_w32handle_unlock_handle (handle);
333 g_assert (thr_ret == 0);
335 /* For a manual-reset event, we're about to try and get the handle
336 * lock again, so give other threads a chance */
339 /* Reset the handle signal state */
341 /* I'm not sure whether or not we need a barrier here to make sure
342 * that all threads waiting on the event have proceeded. Currently
343 * we rely on broadcasting a condition. */
345 thr_ret = mono_w32handle_lock_handle (handle);
346 g_assert (thr_ret == 0);
348 mono_w32handle_set_signal_state (handle, FALSE, FALSE);
351 thr_ret = mono_w32handle_unlock_handle (handle);
352 g_assert (thr_ret == 0);
359 * @handle: The event handle.
361 * Resets the event handle @handle to the unsignalled state.
363 * Return value: %TRUE on success, %FALSE otherwise. (Currently only
364 * ever returns %TRUE).
366 gboolean ResetEvent(gpointer handle)
368 MonoW32HandleType type;
369 struct _WapiHandle_event *event_handle;
372 SetLastError (ERROR_SUCCESS);
374 if (handle == NULL) {
375 SetLastError (ERROR_INVALID_HANDLE);
379 switch (type = mono_w32handle_get_type (handle)) {
380 case MONO_W32HANDLE_EVENT:
381 case MONO_W32HANDLE_NAMEDEVENT:
384 SetLastError (ERROR_INVALID_HANDLE);
388 if (!mono_w32handle_lookup (handle, type, (gpointer *)&event_handle)) {
389 g_warning ("%s: error looking up %s handle %p",
390 __func__, event_handle_type_to_string (type), handle);
394 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: resetting %s handle %p",
395 __func__, event_handle_type_to_string (type), handle);
397 thr_ret = mono_w32handle_lock_handle (handle);
398 g_assert (thr_ret == 0);
400 if (!mono_w32handle_issignalled (handle)) {
401 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: no need to reset %s handle %p",
402 __func__, event_handle_type_to_string (type), handle);
404 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: obtained write lock on %s handle %p",
405 __func__, event_handle_type_to_string (type), handle);
407 mono_w32handle_set_signal_state (handle, FALSE, FALSE);
410 event_handle->set_count = 0;
412 thr_ret = mono_w32handle_unlock_handle (handle);
413 g_assert (thr_ret == 0);
420 * @handle: The event handle
422 * Sets the event handle @handle to the signalled state.
424 * If @handle is a manual reset event, it remains signalled until it
425 * is reset with ResetEvent(). An auto reset event remains signalled
426 * until a single thread has waited for it, at which time @handle is
427 * automatically reset to unsignalled.
429 * Return value: %TRUE on success, %FALSE otherwise. (Currently only
430 * ever returns %TRUE).
432 gboolean SetEvent(gpointer handle)
434 MonoW32HandleType type;
435 struct _WapiHandle_event *event_handle;
438 if (handle == NULL) {
439 SetLastError (ERROR_INVALID_HANDLE);
443 switch (type = mono_w32handle_get_type (handle)) {
444 case MONO_W32HANDLE_EVENT:
445 case MONO_W32HANDLE_NAMEDEVENT:
448 SetLastError (ERROR_INVALID_HANDLE);
452 if (!mono_w32handle_lookup (handle, type, (gpointer *)&event_handle)) {
453 g_warning ("%s: error looking up %s handle %p",
454 __func__, event_handle_type_to_string (type), handle);
458 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: setting %s handle %p",
459 __func__, event_handle_type_to_string (type), handle);
461 thr_ret = mono_w32handle_lock_handle (handle);
462 g_assert (thr_ret == 0);
464 if (!event_handle->manual) {
465 event_handle->set_count = 1;
466 mono_w32handle_set_signal_state (handle, TRUE, FALSE);
468 mono_w32handle_set_signal_state (handle, TRUE, TRUE);
471 thr_ret = mono_w32handle_unlock_handle (handle);
472 g_assert (thr_ret == 0);
477 gpointer OpenEvent (guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, const gunichar2 *name)
483 /* w32 seems to guarantee that opening named objects can't
486 thr_ret = _wapi_namespace_lock ();
487 g_assert (thr_ret == 0);
489 utf8_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
491 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Opening named event [%s]", __func__, utf8_name);
493 handle = _wapi_search_handle_namespace (MONO_W32HANDLE_NAMEDEVENT,
495 if (handle == INVALID_HANDLE_VALUE) {
496 /* The name has already been used for a different
499 SetLastError (ERROR_INVALID_HANDLE);
501 } else if (!handle) {
502 /* This name doesn't exist */
503 SetLastError (ERROR_FILE_NOT_FOUND); /* yes, really */
507 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning named event handle %p", __func__, handle);
512 _wapi_namespace_unlock (NULL);