[runtime] Fix "make distcheck"
[mono-project.git] / mono / io-layer / events.c
blobac8068d41a472696b34584307a22d514cfe4f6b8
1 /*
2 * events.c: Event handles
4 * Author:
5 * Dick Porter (dick@ximian.com)
7 * (C) 2002 Ximian, Inc.
8 */
10 #include <config.h>
11 #include <glib.h>
12 #include <pthread.h>
13 #include <string.h>
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>
23 #if 0
24 #define DEBUG(...) g_message(__VA_ARGS__)
25 #else
26 #define DEBUG(...)
27 #endif
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 = {
36 NULL, /* close */
37 event_signal, /* signal */
38 event_own, /* own */
39 NULL, /* is_owned */
40 NULL, /* special_wait */
41 NULL /* prewait */
44 struct _WapiHandleOps _wapi_namedevent_ops = {
45 NULL, /* close */
46 namedevent_signal, /* signal */
47 namedevent_own, /* own */
48 NULL, /* is_owned */
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);
59 static struct
61 gboolean (*pulse)(gpointer handle);
62 gboolean (*reset)(gpointer handle);
63 gboolean (*set)(gpointer handle);
64 } event_ops[WAPI_HANDLE_COUNT] = {
65 {NULL},
66 {NULL},
67 {NULL},
68 {NULL},
69 {NULL},
70 {NULL},
71 {event_pulse, event_reset, event_set},
72 {NULL},
73 {NULL},
74 {NULL},
75 {NULL},
76 {NULL},
77 {NULL},
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)
102 SetEvent(handle);
105 static gboolean event_own (gpointer handle)
107 struct _WapiHandle_event *event_handle;
108 gboolean ok;
110 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_EVENT,
111 (gpointer *)&event_handle);
112 if(ok==FALSE) {
113 g_warning ("%s: error looking up event handle %p", __func__,
114 handle);
115 return (FALSE);
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);
128 return(TRUE);
131 static void namedevent_signal (gpointer handle)
133 SetEvent (handle);
136 /* NB, always called with the shared handle lock held */
137 static gboolean namedevent_own (gpointer handle)
139 struct _WapiHandle_namedevent *namedevent_handle;
140 gboolean ok;
142 DEBUG ("%s: owning named event handle %p", __func__, handle);
144 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDEVENT,
145 (gpointer *)&namedevent_handle);
146 if (ok == FALSE) {
147 g_warning ("%s: error looking up named event handle %p",
148 __func__, handle);
149 return(FALSE);
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);
160 return (TRUE);
162 static gpointer event_create (WapiSecurityAttributes *security G_GNUC_UNUSED,
163 gboolean manual, gboolean initial)
165 struct _WapiHandle_event event_handle = {0};
166 gpointer handle;
167 int thr_ret;
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);
190 return(NULL);
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);
205 return(handle);
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};
213 gpointer handle;
214 gchar *utf8_name;
215 int thr_ret;
216 gpointer ret = NULL;
217 guint32 namelen;
218 gint32 offset;
220 /* w32 seems to guarantee that opening named objects can't
221 * race each other
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,
237 utf8_name);
238 if (offset == -1) {
239 /* The name has already been used for a different
240 * object.
242 SetLastError (ERROR_INVALID_HANDLE);
243 goto cleanup;
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. */
252 if (offset == 0) {
253 /* A new named event, so create both the private and
254 * shared parts
257 if (strlen (utf8_name) < MAX_PATH) {
258 namelen = strlen (utf8_name);
259 } else {
260 namelen = MAX_PATH;
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,
275 &namedevent_handle);
276 } else {
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,
281 offset, TRUE);
284 if (handle == _WAPI_HANDLE_INVALID) {
285 g_warning ("%s: error creating event handle", __func__);
286 SetLastError (ERROR_GEN_FAILURE);
287 goto cleanup;
289 ret = handle;
291 if (offset == 0) {
292 /* Set the initial state, as this is a completely new
293 * handle
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);
307 cleanup:
308 g_free (utf8_name);
310 _wapi_namespace_unlock (NULL);
312 return(ret);
318 * CreateEvent:
319 * @security: Ignored for now.
320 * @manual: Specifies whether the new event handle has manual or auto
321 * reset behaviour.
322 * @initial: Specifies whether the new event handle is initially
323 * signalled or not.
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);
343 if (name == NULL) {
344 return(event_create (security, manual, initial));
345 } else {
346 return(namedevent_create (security, manual, initial, name));
350 static gboolean event_pulse (gpointer handle)
352 struct _WapiHandle_event *event_handle;
353 gboolean ok;
354 int thr_ret;
356 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_EVENT,
357 (gpointer *)&event_handle);
358 if (ok == FALSE) {
359 g_warning ("%s: error looking up event handle %p", __func__,
360 handle);
361 return(FALSE);
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);
371 } else {
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
382 * chance
384 sched_yield ();
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
390 * a condition.
392 DEBUG ("%s: Obtained write lock on event handle %p",
393 __func__, handle);
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);
404 return(TRUE);
407 static gboolean namedevent_pulse (gpointer handle)
409 struct _WapiHandle_namedevent *namedevent_handle;
410 gboolean ok;
411 int thr_ret;
413 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDEVENT,
414 (gpointer *)&namedevent_handle);
415 if (ok == FALSE) {
416 g_warning ("%s: error looking up named event handle %p",
417 __func__, handle);
418 return(FALSE);
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);
428 } else {
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
438 * a chance
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",
449 __func__, handle);
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 ();
459 return(TRUE);
463 * PulseEvent:
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)
479 WapiHandleType type;
481 if (handle == NULL) {
482 SetLastError (ERROR_INVALID_HANDLE);
483 return(FALSE);
486 type = _wapi_handle_type (handle);
488 if (event_ops[type].pulse == NULL) {
489 SetLastError (ERROR_INVALID_HANDLE);
490 return(FALSE);
493 return(event_ops[type].pulse (handle));
496 static gboolean event_reset (gpointer handle)
498 struct _WapiHandle_event *event_handle;
499 gboolean ok;
500 int thr_ret;
502 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_EVENT,
503 (gpointer *)&event_handle);
504 if (ok == FALSE) {
505 g_warning ("%s: error looking up event handle %p",
506 __func__, handle);
507 return(FALSE);
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__,
517 handle);
518 } else {
519 DEBUG ("%s: Obtained write lock on event handle %p",
520 __func__, handle);
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);
530 return(TRUE);
533 static gboolean namedevent_reset (gpointer handle)
535 struct _WapiHandle_namedevent *namedevent_handle;
536 gboolean ok;
537 int thr_ret;
539 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDEVENT,
540 (gpointer *)&namedevent_handle);
541 if (ok == FALSE) {
542 g_warning ("%s: error looking up named event handle %p",
543 __func__, handle);
544 return(FALSE);
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",
554 __func__, handle);
555 } else {
556 DEBUG ("%s: Obtained write lock on named event handle %p",
557 __func__, handle);
559 _wapi_shared_handle_set_signal_state (handle, FALSE);
562 namedevent_handle->set_count = 0;
564 _wapi_handle_unlock_shared_handles ();
566 return(TRUE);
570 * ResetEvent:
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)
580 WapiHandleType type;
582 if (handle == NULL) {
583 SetLastError (ERROR_INVALID_HANDLE);
584 return(FALSE);
587 type = _wapi_handle_type (handle);
589 if (event_ops[type].reset == NULL) {
590 SetLastError (ERROR_INVALID_HANDLE);
591 return(FALSE);
594 return(event_ops[type].reset (handle));
597 static gboolean event_set (gpointer handle)
599 struct _WapiHandle_event *event_handle;
600 gboolean ok;
601 int thr_ret;
603 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_EVENT,
604 (gpointer *)&event_handle);
605 if (ok == FALSE) {
606 g_warning ("%s: error looking up event handle %p", __func__,
607 handle);
608 return(FALSE);
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);
618 } else {
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);
626 return(TRUE);
629 static gboolean namedevent_set (gpointer handle)
631 struct _WapiHandle_namedevent *namedevent_handle;
632 gboolean ok;
633 int thr_ret;
635 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDEVENT,
636 (gpointer *)&namedevent_handle);
637 if (ok == FALSE) {
638 g_warning ("%s: error looking up named event handle %p",
639 __func__, handle);
640 return(FALSE);
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);
650 } else {
651 namedevent_handle->set_count = 1;
652 _wapi_shared_handle_set_signal_state (handle, TRUE);
655 _wapi_handle_unlock_shared_handles ();
657 return(TRUE);
661 * SetEvent:
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)
676 WapiHandleType type;
678 if (handle == NULL) {
679 SetLastError (ERROR_INVALID_HANDLE);
680 return(FALSE);
683 type = _wapi_handle_type (handle);
685 if (event_ops[type].set == NULL) {
686 SetLastError (ERROR_INVALID_HANDLE);
687 return(FALSE);
690 return(event_ops[type].set (handle));
693 gpointer OpenEvent (guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, const gunichar2 *name)
695 gpointer handle;
696 gchar *utf8_name;
697 int thr_ret;
698 gpointer ret = NULL;
699 gint32 offset;
701 mono_once (&event_ops_once, event_ops_init);
703 /* w32 seems to guarantee that opening named objects can't
704 * race each other
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,
714 utf8_name);
715 if (offset == -1) {
716 /* The name has already been used for a different
717 * object.
719 SetLastError (ERROR_INVALID_HANDLE);
720 goto cleanup;
721 } else if (offset == 0) {
722 /* This name doesn't exist */
723 SetLastError (ERROR_FILE_NOT_FOUND); /* yes, really */
724 goto cleanup;
727 /* A new reference to an existing named event, so just create
728 * the private part
730 handle = _wapi_handle_new_from_offset (WAPI_HANDLE_NAMEDEVENT, offset,
731 TRUE);
733 if (handle == _WAPI_HANDLE_INVALID) {
734 g_warning ("%s: error opening named event handle", __func__);
735 SetLastError (ERROR_GEN_FAILURE);
736 goto cleanup;
738 ret = handle;
740 DEBUG ("%s: returning named event handle %p", __func__, handle);
742 cleanup:
743 g_free (utf8_name);
745 _wapi_namespace_unlock (NULL);
747 return(ret);