2010-02-13 Jb Evain <jbevain@novell.com>
[mono-project.git] / mono / io-layer / events.c
blobb55e8e75fbcd8ac88038640532b80587cdf4bc9e
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/mono-mutex.h>
22 #include <mono/io-layer/event-private.h>
24 #undef DEBUG
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 = {
33 NULL, /* close */
34 event_signal, /* signal */
35 event_own, /* own */
36 NULL, /* is_owned */
37 NULL, /* special_wait */
38 NULL /* prewait */
41 struct _WapiHandleOps _wapi_namedevent_ops = {
42 NULL, /* close */
43 namedevent_signal, /* signal */
44 namedevent_own, /* own */
45 NULL, /* is_owned */
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);
56 static struct
58 gboolean (*pulse)(gpointer handle);
59 gboolean (*reset)(gpointer handle);
60 gboolean (*set)(gpointer handle);
61 } event_ops[WAPI_HANDLE_COUNT] = {
62 {NULL},
63 {NULL},
64 {NULL},
65 {NULL},
66 {NULL},
67 {NULL},
68 {event_pulse, event_reset, event_set},
69 {NULL},
70 {NULL},
71 {NULL},
72 {NULL},
73 {NULL},
74 {NULL},
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)
99 SetEvent(handle);
102 static gboolean event_own (gpointer handle)
104 struct _WapiHandle_event *event_handle;
105 gboolean ok;
107 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_EVENT,
108 (gpointer *)&event_handle);
109 if(ok==FALSE) {
110 g_warning ("%s: error looking up event handle %p", __func__,
111 handle);
112 return (FALSE);
115 #ifdef DEBUG
116 g_message("%s: owning event handle %p", __func__, handle);
117 #endif
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);
127 return(TRUE);
130 static void namedevent_signal (gpointer handle)
132 SetEvent (handle);
135 /* NB, always called with the shared handle lock held */
136 static gboolean namedevent_own (gpointer handle)
138 struct _WapiHandle_namedevent *namedevent_handle;
139 gboolean ok;
141 #ifdef DEBUG
142 g_message ("%s: owning named event handle %p", __func__, handle);
143 #endif
145 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDEVENT,
146 (gpointer *)&namedevent_handle);
147 if (ok == FALSE) {
148 g_warning ("%s: error looking up named event handle %p",
149 __func__, handle);
150 return(FALSE);
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);
161 return (TRUE);
163 static gpointer event_create (WapiSecurityAttributes *security G_GNUC_UNUSED,
164 gboolean manual, gboolean initial)
166 struct _WapiHandle_event event_handle = {0};
167 gpointer handle;
168 int thr_ret;
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);
176 #ifdef DEBUG
177 g_message ("%s: Creating unnamed event", __func__);
178 #endif
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);
193 return(NULL);
196 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
197 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);
205 #ifdef DEBUG
206 g_message("%s: created new event handle %p", __func__, handle);
207 #endif
209 thr_ret = _wapi_handle_unlock_handle (handle);
210 g_assert (thr_ret == 0);
211 pthread_cleanup_pop (0);
213 return(handle);
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};
221 gpointer handle;
222 gchar *utf8_name;
223 int thr_ret;
224 gpointer ret = NULL;
225 guint32 namelen;
226 gint32 offset;
228 /* w32 seems to guarantee that opening named objects can't
229 * race each other
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);
242 #ifdef DEBUG
243 g_message ("%s: Creating named event [%s]", __func__, utf8_name);
244 #endif
246 offset = _wapi_search_handle_namespace (WAPI_HANDLE_NAMEDEVENT,
247 utf8_name);
248 if (offset == -1) {
249 /* The name has already been used for a different
250 * object.
252 SetLastError (ERROR_INVALID_HANDLE);
253 goto cleanup;
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. */
262 if (offset == 0) {
263 /* A new named event, so create both the private and
264 * shared parts
267 if (strlen (utf8_name) < MAX_PATH) {
268 namelen = strlen (utf8_name);
269 } else {
270 namelen = MAX_PATH;
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,
285 &namedevent_handle);
286 } else {
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,
291 offset, TRUE);
294 if (handle == _WAPI_HANDLE_INVALID) {
295 g_warning ("%s: error creating event handle", __func__);
296 SetLastError (ERROR_GEN_FAILURE);
297 goto cleanup;
299 ret = handle;
301 if (offset == 0) {
302 /* Set the initial state, as this is a completely new
303 * handle
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 ();
315 #ifdef DEBUG
316 g_message ("%s: returning event handle %p", __func__, handle);
317 #endif
319 cleanup:
320 g_free (utf8_name);
322 _wapi_namespace_unlock (NULL);
324 return(ret);
330 * CreateEvent:
331 * @security: Ignored for now.
332 * @manual: Specifies whether the new event handle has manual or auto
333 * reset behaviour.
334 * @initial: Specifies whether the new event handle is initially
335 * signalled or not.
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);
355 if (name == NULL) {
356 return(event_create (security, manual, initial));
357 } else {
358 return(namedevent_create (security, manual, initial, name));
362 static gboolean event_pulse (gpointer handle)
364 struct _WapiHandle_event *event_handle;
365 gboolean ok;
366 int thr_ret;
368 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_EVENT,
369 (gpointer *)&event_handle);
370 if (ok == FALSE) {
371 g_warning ("%s: error looking up event handle %p", __func__,
372 handle);
373 return(FALSE);
376 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
377 handle);
378 thr_ret = _wapi_handle_lock_handle (handle);
379 g_assert (thr_ret == 0);
381 #ifdef DEBUG
382 g_message ("%s: Pulsing event handle %p", __func__, handle);
383 #endif
385 if (event_handle->manual == TRUE) {
386 _wapi_handle_set_signal_state (handle, TRUE, TRUE);
387 } else {
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
400 * chance
402 sched_yield ();
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
408 * a condition.
410 #ifdef DEBUG
411 g_message ("%s: Obtained write lock on event handle %p",
412 __func__, handle);
413 #endif
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);
426 return(TRUE);
429 static gboolean namedevent_pulse (gpointer handle)
431 struct _WapiHandle_namedevent *namedevent_handle;
432 gboolean ok;
433 int thr_ret;
435 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDEVENT,
436 (gpointer *)&namedevent_handle);
437 if (ok == FALSE) {
438 g_warning ("%s: error looking up named event handle %p",
439 __func__, handle);
440 return(FALSE);
443 thr_ret = _wapi_handle_lock_shared_handles ();
444 g_assert (thr_ret == 0);
446 #ifdef DEBUG
447 g_message ("%s: Pulsing named event handle %p", __func__, handle);
448 #endif
450 if (namedevent_handle->manual == TRUE) {
451 _wapi_shared_handle_set_signal_state (handle, TRUE);
452 } else {
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
462 * a chance
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.
472 #ifdef DEBUG
473 g_message ("%s: Obtained write lock on event handle %p",
474 __func__, handle);
475 #endif
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 ();
485 return(TRUE);
489 * PulseEvent:
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)
505 WapiHandleType type;
507 if (handle == NULL) {
508 SetLastError (ERROR_INVALID_HANDLE);
509 return(FALSE);
512 type = _wapi_handle_type (handle);
514 if (event_ops[type].pulse == NULL) {
515 SetLastError (ERROR_INVALID_HANDLE);
516 return(FALSE);
519 return(event_ops[type].pulse (handle));
522 static gboolean event_reset (gpointer handle)
524 struct _WapiHandle_event *event_handle;
525 gboolean ok;
526 int thr_ret;
528 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_EVENT,
529 (gpointer *)&event_handle);
530 if (ok == FALSE) {
531 g_warning ("%s: error looking up event handle %p",
532 __func__, handle);
533 return(FALSE);
536 #ifdef DEBUG
537 g_message ("%s: Resetting event handle %p", __func__, handle);
538 #endif
540 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
541 handle);
542 thr_ret = _wapi_handle_lock_handle (handle);
543 g_assert (thr_ret == 0);
545 if (_wapi_handle_issignalled (handle) == FALSE) {
546 #ifdef DEBUG
547 g_message ("%s: No need to reset event handle %p", __func__,
548 handle);
549 #endif
550 } else {
551 #ifdef DEBUG
552 g_message ("%s: Obtained write lock on event handle %p",
553 __func__, handle);
554 #endif
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);
566 return(TRUE);
569 static gboolean namedevent_reset (gpointer handle)
571 struct _WapiHandle_namedevent *namedevent_handle;
572 gboolean ok;
573 int thr_ret;
575 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDEVENT,
576 (gpointer *)&namedevent_handle);
577 if (ok == FALSE) {
578 g_warning ("%s: error looking up named event handle %p",
579 __func__, handle);
580 return(FALSE);
583 #ifdef DEBUG
584 g_message ("%s: Resetting named event handle %p", __func__, handle);
585 #endif
587 thr_ret = _wapi_handle_lock_shared_handles ();
588 g_assert (thr_ret == 0);
590 if (_wapi_handle_issignalled (handle) == FALSE) {
591 #ifdef DEBUG
592 g_message ("%s: No need to reset named event handle %p",
593 __func__, handle);
594 #endif
595 } else {
596 #ifdef DEBUG
597 g_message ("%s: Obtained write lock on named event handle %p",
598 __func__, handle);
599 #endif
601 _wapi_shared_handle_set_signal_state (handle, FALSE);
604 namedevent_handle->set_count = 0;
606 _wapi_handle_unlock_shared_handles ();
608 return(TRUE);
612 * ResetEvent:
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)
622 WapiHandleType type;
624 if (handle == NULL) {
625 SetLastError (ERROR_INVALID_HANDLE);
626 return(FALSE);
629 type = _wapi_handle_type (handle);
631 if (event_ops[type].reset == NULL) {
632 SetLastError (ERROR_INVALID_HANDLE);
633 return(FALSE);
636 return(event_ops[type].reset (handle));
639 static gboolean event_set (gpointer handle)
641 struct _WapiHandle_event *event_handle;
642 gboolean ok;
643 int thr_ret;
645 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_EVENT,
646 (gpointer *)&event_handle);
647 if (ok == FALSE) {
648 g_warning ("%s: error looking up event handle %p", __func__,
649 handle);
650 return(FALSE);
653 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
654 handle);
655 thr_ret = _wapi_handle_lock_handle (handle);
656 g_assert (thr_ret == 0);
658 #ifdef DEBUG
659 g_message ("%s: Setting event handle %p", __func__, handle);
660 #endif
662 if (event_handle->manual == TRUE) {
663 _wapi_handle_set_signal_state (handle, TRUE, TRUE);
664 } else {
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);
674 return(TRUE);
677 static gboolean namedevent_set (gpointer handle)
679 struct _WapiHandle_namedevent *namedevent_handle;
680 gboolean ok;
681 int thr_ret;
683 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDEVENT,
684 (gpointer *)&namedevent_handle);
685 if (ok == FALSE) {
686 g_warning ("%s: error looking up named event handle %p",
687 __func__, handle);
688 return(FALSE);
691 thr_ret = _wapi_handle_lock_shared_handles ();
692 g_assert (thr_ret == 0);
694 #ifdef DEBUG
695 g_message ("%s: Setting named event handle %p", __func__, handle);
696 #endif
698 if (namedevent_handle->manual == TRUE) {
699 _wapi_shared_handle_set_signal_state (handle, TRUE);
700 } else {
701 namedevent_handle->set_count = 1;
702 _wapi_shared_handle_set_signal_state (handle, TRUE);
705 _wapi_handle_unlock_shared_handles ();
707 return(TRUE);
711 * SetEvent:
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)
726 WapiHandleType type;
728 if (handle == NULL) {
729 SetLastError (ERROR_INVALID_HANDLE);
730 return(FALSE);
733 type = _wapi_handle_type (handle);
735 if (event_ops[type].set == NULL) {
736 SetLastError (ERROR_INVALID_HANDLE);
737 return(FALSE);
740 return(event_ops[type].set (handle));
743 gpointer OpenEvent (guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, const gunichar2 *name)
745 gpointer handle;
746 gchar *utf8_name;
747 int thr_ret;
748 gpointer ret = NULL;
749 gint32 offset;
751 mono_once (&event_ops_once, event_ops_init);
753 /* w32 seems to guarantee that opening named objects can't
754 * race each other
756 thr_ret = _wapi_namespace_lock ();
757 g_assert (thr_ret == 0);
759 utf8_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
761 #ifdef DEBUG
762 g_message ("%s: Opening named event [%s]", __func__, utf8_name);
763 #endif
765 offset = _wapi_search_handle_namespace (WAPI_HANDLE_NAMEDEVENT,
766 utf8_name);
767 if (offset == -1) {
768 /* The name has already been used for a different
769 * object.
771 SetLastError (ERROR_INVALID_HANDLE);
772 goto cleanup;
773 } else if (offset == 0) {
774 /* This name doesn't exist */
775 SetLastError (ERROR_FILE_NOT_FOUND); /* yes, really */
776 goto cleanup;
779 /* A new reference to an existing named event, so just create
780 * the private part
782 handle = _wapi_handle_new_from_offset (WAPI_HANDLE_NAMEDEVENT, offset,
783 TRUE);
785 if (handle == _WAPI_HANDLE_INVALID) {
786 g_warning ("%s: error opening named event handle", __func__);
787 SetLastError (ERROR_GEN_FAILURE);
788 goto cleanup;
790 ret = handle;
792 #ifdef DEBUG
793 g_message ("%s: returning named event handle %p", __func__, handle);
794 #endif
796 cleanup:
797 g_free (utf8_name);
799 _wapi_namespace_unlock (NULL);
801 return(ret);