Merge pull request #2288 from evincarofautumn/c++-compat
[mono.git] / mono / io-layer / events.c
1 /*
2  * events.c:  Event handles
3  *
4  * Author:
5  *      Dick Porter (dick@ximian.com)
6  *
7  * (C) 2002 Ximian, Inc.
8  */
9
10 #include <config.h>
11 #include <glib.h>
12 #include <pthread.h>
13 #include <string.h>
14
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/event-private.h>
19 #include <mono/utils/mono-once.h>
20
21 #if 0
22 #define DEBUG(...) g_message(__VA_ARGS__)
23 #else
24 #define DEBUG(...)
25 #endif
26
27 static void event_signal(gpointer handle);
28 static gboolean event_own (gpointer handle);
29
30 static void namedevent_signal (gpointer handle);
31 static gboolean namedevent_own (gpointer handle);
32
33 struct _WapiHandleOps _wapi_event_ops = {
34         NULL,                   /* close */
35         event_signal,           /* signal */
36         event_own,              /* own */
37         NULL,                   /* is_owned */
38         NULL,                   /* special_wait */
39         NULL                    /* prewait */
40 };
41
42 struct _WapiHandleOps _wapi_namedevent_ops = {
43         NULL,                   /* close */
44         namedevent_signal,      /* signal */
45         namedevent_own,         /* own */
46         NULL,                   /* is_owned */
47 };
48
49 static gboolean event_pulse (gpointer handle);
50 static gboolean event_reset (gpointer handle);
51 static gboolean event_set (gpointer handle);
52
53 static gboolean namedevent_pulse (gpointer handle);
54 static gboolean namedevent_reset (gpointer handle);
55 static gboolean namedevent_set (gpointer handle);
56
57 static struct
58 {
59         gboolean (*pulse)(gpointer handle);
60         gboolean (*reset)(gpointer handle);
61         gboolean (*set)(gpointer handle);
62 } event_ops[WAPI_HANDLE_COUNT] = {
63                 {NULL},
64                 {NULL},
65                 {NULL},
66                 {NULL},
67                 {NULL},
68                 {NULL},
69                 {event_pulse, event_reset, event_set},
70                 {NULL},
71                 {NULL},
72                 {NULL},
73                 {NULL},
74                 {NULL},
75                 {NULL},
76                 {namedevent_pulse, namedevent_reset, namedevent_set},
77 };
78
79 void _wapi_event_details (gpointer handle_info)
80 {
81         struct _WapiHandle_event *event = (struct _WapiHandle_event *)handle_info;
82         
83         g_print ("manual: %s", event->manual?"TRUE":"FALSE");
84 }
85
86 static mono_once_t event_ops_once=MONO_ONCE_INIT;
87
88 static void event_ops_init (void)
89 {
90         _wapi_handle_register_capabilities (WAPI_HANDLE_EVENT,
91                 (WapiHandleCapability)(WAPI_HANDLE_CAP_WAIT | WAPI_HANDLE_CAP_SIGNAL));
92         _wapi_handle_register_capabilities (WAPI_HANDLE_NAMEDEVENT,
93                 (WapiHandleCapability)(WAPI_HANDLE_CAP_WAIT | WAPI_HANDLE_CAP_SIGNAL));
94 }
95
96 static void event_signal(gpointer handle)
97 {
98         SetEvent(handle);
99 }
100
101 static gboolean event_own (gpointer handle)
102 {
103         struct _WapiHandle_event *event_handle;
104         gboolean ok;
105         
106         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_EVENT,
107                                 (gpointer *)&event_handle);
108         if(ok==FALSE) {
109                 g_warning ("%s: error looking up event handle %p", __func__,
110                            handle);
111                 return (FALSE);
112         }
113         
114         DEBUG("%s: owning event handle %p", __func__, handle);
115
116         if(event_handle->manual==FALSE) {
117                 g_assert (event_handle->set_count > 0);
118                 
119                 if (--event_handle->set_count == 0) {
120                         _wapi_handle_set_signal_state (handle, FALSE, FALSE);
121                 }
122         }
123
124         return(TRUE);
125 }
126
127 static void namedevent_signal (gpointer handle)
128 {
129         SetEvent (handle);
130 }
131
132 /* NB, always called with the shared handle lock held */
133 static gboolean namedevent_own (gpointer handle)
134 {
135         struct _WapiHandle_namedevent *namedevent_handle;
136         gboolean ok;
137         
138         DEBUG ("%s: owning named event handle %p", __func__, handle);
139
140         ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDEVENT,
141                                   (gpointer *)&namedevent_handle);
142         if (ok == FALSE) {
143                 g_warning ("%s: error looking up named event handle %p",
144                            __func__, handle);
145                 return(FALSE);
146         }
147         
148         if (namedevent_handle->manual == FALSE) {
149                 g_assert (namedevent_handle->set_count > 0);
150                 
151                 if (--namedevent_handle->set_count == 0) {
152                         _wapi_shared_handle_set_signal_state (handle, FALSE);
153                 }
154         }
155         
156         return (TRUE);
157 }
158 static gpointer event_create (WapiSecurityAttributes *security G_GNUC_UNUSED,
159                               gboolean manual, gboolean initial)
160 {
161         struct _WapiHandle_event event_handle = {0};
162         gpointer handle;
163         int thr_ret;
164         
165         /* Need to blow away any old errors here, because code tests
166          * for ERROR_ALREADY_EXISTS on success (!) to see if an event
167          * was freshly created
168          */
169         SetLastError (ERROR_SUCCESS);
170
171         DEBUG ("%s: Creating unnamed event", __func__);
172         
173         event_handle.manual = manual;
174         event_handle.set_count = 0;
175
176         if (initial == TRUE) {
177                 if (manual == FALSE) {
178                         event_handle.set_count = 1;
179                 }
180         }
181         
182         handle = _wapi_handle_new (WAPI_HANDLE_EVENT, &event_handle);
183         if (handle == _WAPI_HANDLE_INVALID) {
184                 g_warning ("%s: error creating event handle", __func__);
185                 SetLastError (ERROR_GEN_FAILURE);
186                 return(NULL);
187         }
188
189         thr_ret = _wapi_handle_lock_handle (handle);
190         g_assert (thr_ret == 0);
191         
192         if (initial == TRUE) {
193                 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
194         }
195         
196         DEBUG("%s: created new event handle %p", __func__, handle);
197
198         thr_ret = _wapi_handle_unlock_handle (handle);
199         g_assert (thr_ret == 0);
200
201         return(handle);
202 }
203
204 static gpointer namedevent_create (WapiSecurityAttributes *security G_GNUC_UNUSED,
205                                    gboolean manual, gboolean initial,
206                                    const gunichar2 *name G_GNUC_UNUSED)
207 {
208         struct _WapiHandle_namedevent namedevent_handle = {{{0}}, 0};
209         gpointer handle;
210         gchar *utf8_name;
211         int thr_ret;
212         gpointer ret = NULL;
213         guint32 namelen;
214         gint32 offset;
215         
216         /* w32 seems to guarantee that opening named objects can't
217          * race each other
218          */
219         thr_ret = _wapi_namespace_lock ();
220         g_assert (thr_ret == 0);
221
222         /* Need to blow away any old errors here, because code tests
223          * for ERROR_ALREADY_EXISTS on success (!) to see if an event
224          * was freshly created
225          */
226         SetLastError (ERROR_SUCCESS);
227         
228         utf8_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
229         
230         DEBUG ("%s: Creating named event [%s]", __func__, utf8_name);
231         
232         offset = _wapi_search_handle_namespace (WAPI_HANDLE_NAMEDEVENT,
233                                                 utf8_name);
234         if (offset == -1) {
235                 /* The name has already been used for a different
236                  * object.
237                  */
238                 SetLastError (ERROR_INVALID_HANDLE);
239                 goto cleanup;
240         } else if (offset != 0) {
241                 /* Not an error, but this is how the caller is
242                  * informed that the event wasn't freshly created
243                  */
244                 SetLastError (ERROR_ALREADY_EXISTS);
245         }
246         /* Fall through to create the event handle. */
247
248         if (offset == 0) {
249                 /* A new named event, so create both the private and
250                  * shared parts
251                  */
252         
253                 if (strlen (utf8_name) < MAX_PATH) {
254                         namelen = strlen (utf8_name);
255                 } else {
256                         namelen = MAX_PATH;
257                 }
258         
259                 memcpy (&namedevent_handle.sharedns.name, utf8_name, namelen);
260
261                 namedevent_handle.manual = manual;
262                 namedevent_handle.set_count = 0;
263                 
264                 if (initial == TRUE) {
265                         if (manual == FALSE) {
266                                 namedevent_handle.set_count = 1;
267                         }
268                 }
269                 
270                 handle = _wapi_handle_new (WAPI_HANDLE_NAMEDEVENT,
271                                            &namedevent_handle);
272         } else {
273                 /* A new reference to an existing named event, so just
274                  * create the private part
275                  */
276                 handle = _wapi_handle_new_from_offset (WAPI_HANDLE_NAMEDEVENT,
277                                                        offset, TRUE);
278         }
279         
280         if (handle == _WAPI_HANDLE_INVALID) {
281                 g_warning ("%s: error creating event handle", __func__);
282                 SetLastError (ERROR_GEN_FAILURE);
283                 goto cleanup;
284         }
285         ret = handle;
286
287         if (offset == 0) {
288                 /* Set the initial state, as this is a completely new
289                  * handle
290                  */
291                 thr_ret = _wapi_handle_lock_shared_handles ();
292                 g_assert (thr_ret == 0);
293         
294                 if (initial == TRUE) {
295                         _wapi_shared_handle_set_signal_state (handle, TRUE);
296                 }
297
298                 _wapi_handle_unlock_shared_handles ();
299         }
300         
301         DEBUG ("%s: returning event handle %p", __func__, handle);
302
303 cleanup:
304         g_free (utf8_name);
305
306         _wapi_namespace_unlock (NULL);
307         
308         return(ret);
309
310 }
311
312
313 /**
314  * CreateEvent:
315  * @security: Ignored for now.
316  * @manual: Specifies whether the new event handle has manual or auto
317  * reset behaviour.
318  * @initial: Specifies whether the new event handle is initially
319  * signalled or not.
320  * @name:Pointer to a string specifying the name of this name, or
321  * %NULL.  Currently ignored.
322  *
323  * Creates a new event handle.
324  *
325  * An event handle is signalled with SetEvent().  If the new handle is
326  * a manual reset event handle, it remains signalled until it is reset
327  * with ResetEvent().  An auto reset event remains signalled until a
328  * single thread has waited for it, at which time the event handle is
329  * automatically reset to unsignalled.
330  *
331  * Return value: A new handle, or %NULL on error.
332  */
333 gpointer CreateEvent(WapiSecurityAttributes *security G_GNUC_UNUSED,
334                      gboolean manual, gboolean initial,
335                      const gunichar2 *name G_GNUC_UNUSED)
336 {
337         mono_once (&event_ops_once, event_ops_init);
338
339         if (name == NULL) {
340                 return(event_create (security, manual, initial));
341         } else {
342                 return(namedevent_create (security, manual, initial, name));
343         }
344 }
345
346 static gboolean event_pulse (gpointer handle)
347 {
348         struct _WapiHandle_event *event_handle;
349         gboolean ok;
350         int thr_ret;
351         
352         ok = _wapi_lookup_handle (handle, WAPI_HANDLE_EVENT,
353                                   (gpointer *)&event_handle);
354         if (ok == FALSE) {
355                 g_warning ("%s: error looking up event handle %p", __func__,
356                            handle);
357                 return(FALSE);
358         }
359         
360         thr_ret = _wapi_handle_lock_handle (handle);
361         g_assert (thr_ret == 0);
362
363         DEBUG ("%s: Pulsing event handle %p", __func__, handle);
364
365         if (event_handle->manual == TRUE) {
366                 _wapi_handle_set_signal_state (handle, TRUE, TRUE);
367         } else {
368                 event_handle->set_count = 1;
369                 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
370         }
371
372         thr_ret = _wapi_handle_unlock_handle (handle);
373         g_assert (thr_ret == 0);
374         
375         if (event_handle->manual == TRUE) {
376                 /* For a manual-reset event, we're about to try and
377                  * get the handle lock again, so give other threads a
378                  * chance
379                  */
380                 sched_yield ();
381
382                 /* Reset the handle signal state */
383                 /* I'm not sure whether or not we need a barrier here
384                  * to make sure that all threads waiting on the event
385                  * have proceeded.  Currently we rely on broadcasting
386                  * a condition.
387                  */
388                 DEBUG ("%s: Obtained write lock on event handle %p",
389                            __func__, handle);
390
391                 thr_ret = _wapi_handle_lock_handle (handle);
392                 g_assert (thr_ret == 0);
393                 
394                 _wapi_handle_set_signal_state (handle, FALSE, FALSE);
395
396                 thr_ret = _wapi_handle_unlock_handle (handle);
397                 g_assert (thr_ret == 0);
398         }
399
400         return(TRUE);
401 }
402
403 static gboolean namedevent_pulse (gpointer handle)
404 {
405         struct _WapiHandle_namedevent *namedevent_handle;
406         gboolean ok;
407         int thr_ret;
408         
409         ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDEVENT,
410                                   (gpointer *)&namedevent_handle);
411         if (ok == FALSE) {
412                 g_warning ("%s: error looking up named event handle %p",
413                            __func__, handle);
414                 return(FALSE);
415         }
416         
417         thr_ret = _wapi_handle_lock_shared_handles ();
418         g_assert (thr_ret == 0);
419
420         DEBUG ("%s: Pulsing named event handle %p", __func__, handle);
421
422         if (namedevent_handle->manual == TRUE) {
423                 _wapi_shared_handle_set_signal_state (handle, TRUE);
424         } else {
425                 namedevent_handle->set_count = 1;
426                 _wapi_shared_handle_set_signal_state (handle, TRUE);
427         }
428
429         _wapi_handle_unlock_shared_handles ();
430         
431         if (namedevent_handle->manual == TRUE) {
432                 /* For a manual-reset event, we're about to try and
433                  * get the handle lock again, so give other processes
434                  * a chance
435                  */
436                 _wapi_handle_spin (200);
437
438                 /* Reset the handle signal state */
439                 /* I'm not sure whether or not we need a barrier here
440                  * to make sure that all threads waiting on the event
441                  * have proceeded.  Currently we rely on waiting for
442                  * twice the shared handle poll interval.
443                  */
444                 DEBUG ("%s: Obtained write lock on event handle %p",
445                            __func__, handle);
446
447                 thr_ret = _wapi_handle_lock_shared_handles ();
448                 g_assert (thr_ret == 0);
449                 
450                 _wapi_shared_handle_set_signal_state (handle, FALSE);
451
452                 _wapi_handle_unlock_shared_handles ();
453         }
454
455         return(TRUE);
456 }
457
458 /**
459  * PulseEvent:
460  * @handle: The event handle.
461  *
462  * Sets the event handle @handle to the signalled state, and then
463  * resets it to unsignalled after informing any waiting threads.
464  *
465  * If @handle is a manual reset event, all waiting threads that can be
466  * released immediately are released.  @handle is then reset.  If
467  * @handle is an auto reset event, one waiting thread is released even
468  * if multiple threads are waiting.
469  *
470  * Return value: %TRUE on success, %FALSE otherwise.  (Currently only
471  * ever returns %TRUE).
472  */
473 gboolean PulseEvent(gpointer handle)
474 {
475         WapiHandleType type;
476         
477         if (handle == NULL) {
478                 SetLastError (ERROR_INVALID_HANDLE);
479                 return(FALSE);
480         }
481         
482         type = _wapi_handle_type (handle);
483         
484         if (event_ops[type].pulse == NULL) {
485                 SetLastError (ERROR_INVALID_HANDLE);
486                 return(FALSE);
487         }
488         
489         return(event_ops[type].pulse (handle));
490 }
491
492 static gboolean event_reset (gpointer handle)
493 {
494         struct _WapiHandle_event *event_handle;
495         gboolean ok;
496         int thr_ret;
497         
498         ok = _wapi_lookup_handle (handle, WAPI_HANDLE_EVENT,
499                                   (gpointer *)&event_handle);
500         if (ok == FALSE) {
501                 g_warning ("%s: error looking up event handle %p",
502                            __func__, handle);
503                 return(FALSE);
504         }
505
506         DEBUG ("%s: Resetting event handle %p", __func__, handle);
507
508         thr_ret = _wapi_handle_lock_handle (handle);
509         g_assert (thr_ret == 0);
510         
511         if (_wapi_handle_issignalled (handle) == FALSE) {
512                 DEBUG ("%s: No need to reset event handle %p", __func__,
513                            handle);
514         } else {
515                 DEBUG ("%s: Obtained write lock on event handle %p",
516                            __func__, handle);
517
518                 _wapi_handle_set_signal_state (handle, FALSE, FALSE);
519         }
520         
521         event_handle->set_count = 0;
522         
523         thr_ret = _wapi_handle_unlock_handle (handle);
524         g_assert (thr_ret == 0);
525         
526         return(TRUE);
527 }
528
529 static gboolean namedevent_reset (gpointer handle)
530 {
531         struct _WapiHandle_namedevent *namedevent_handle;
532         gboolean ok;
533         int thr_ret;
534         
535         ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDEVENT,
536                                   (gpointer *)&namedevent_handle);
537         if (ok == FALSE) {
538                 g_warning ("%s: error looking up named event handle %p",
539                            __func__, handle);
540                 return(FALSE);
541         }
542
543         DEBUG ("%s: Resetting named event handle %p", __func__, handle);
544
545         thr_ret = _wapi_handle_lock_shared_handles ();
546         g_assert (thr_ret == 0);
547         
548         if (_wapi_handle_issignalled (handle) == FALSE) {
549                 DEBUG ("%s: No need to reset named event handle %p",
550                            __func__, handle);
551         } else {
552                 DEBUG ("%s: Obtained write lock on named event handle %p",
553                            __func__, handle);
554
555                 _wapi_shared_handle_set_signal_state (handle, FALSE);
556         }
557         
558         namedevent_handle->set_count = 0;
559         
560         _wapi_handle_unlock_shared_handles ();
561         
562         return(TRUE);
563 }
564
565 /**
566  * ResetEvent:
567  * @handle: The event handle.
568  *
569  * Resets the event handle @handle to the unsignalled state.
570  *
571  * Return value: %TRUE on success, %FALSE otherwise.  (Currently only
572  * ever returns %TRUE).
573  */
574 gboolean ResetEvent(gpointer handle)
575 {
576         WapiHandleType type;
577         
578         if (handle == NULL) {
579                 SetLastError (ERROR_INVALID_HANDLE);
580                 return(FALSE);
581         }
582         
583         type = _wapi_handle_type (handle);
584         
585         if (event_ops[type].reset == NULL) {
586                 SetLastError (ERROR_INVALID_HANDLE);
587                 return(FALSE);
588         }
589         
590         return(event_ops[type].reset (handle));
591 }
592
593 static gboolean event_set (gpointer handle)
594 {
595         struct _WapiHandle_event *event_handle;
596         gboolean ok;
597         int thr_ret;
598         
599         ok = _wapi_lookup_handle (handle, WAPI_HANDLE_EVENT,
600                                   (gpointer *)&event_handle);
601         if (ok == FALSE) {
602                 g_warning ("%s: error looking up event handle %p", __func__,
603                            handle);
604                 return(FALSE);
605         }
606         
607         thr_ret = _wapi_handle_lock_handle (handle);
608         g_assert (thr_ret == 0);
609
610         DEBUG ("%s: Setting event handle %p", __func__, handle);
611
612         if (event_handle->manual == TRUE) {
613                 _wapi_handle_set_signal_state (handle, TRUE, TRUE);
614         } else {
615                 event_handle->set_count = 1;
616                 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
617         }
618
619         thr_ret = _wapi_handle_unlock_handle (handle);
620         g_assert (thr_ret == 0);
621         
622         return(TRUE);
623 }
624
625 static gboolean namedevent_set (gpointer handle)
626 {
627         struct _WapiHandle_namedevent *namedevent_handle;
628         gboolean ok;
629         int thr_ret;
630         
631         ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDEVENT,
632                                   (gpointer *)&namedevent_handle);
633         if (ok == FALSE) {
634                 g_warning ("%s: error looking up named event handle %p",
635                            __func__, handle);
636                 return(FALSE);
637         }
638         
639         thr_ret = _wapi_handle_lock_shared_handles ();
640         g_assert (thr_ret == 0);
641
642         DEBUG ("%s: Setting named event handle %p", __func__, handle);
643
644         if (namedevent_handle->manual == TRUE) {
645                 _wapi_shared_handle_set_signal_state (handle, TRUE);
646         } else {
647                 namedevent_handle->set_count = 1;
648                 _wapi_shared_handle_set_signal_state (handle, TRUE);
649         }
650
651         _wapi_handle_unlock_shared_handles ();
652
653         return(TRUE);
654 }
655
656 /**
657  * SetEvent:
658  * @handle: The event handle
659  *
660  * Sets the event handle @handle to the signalled state.
661  *
662  * If @handle is a manual reset event, it remains signalled until it
663  * is reset with ResetEvent().  An auto reset event remains signalled
664  * until a single thread has waited for it, at which time @handle is
665  * automatically reset to unsignalled.
666  *
667  * Return value: %TRUE on success, %FALSE otherwise.  (Currently only
668  * ever returns %TRUE).
669  */
670 gboolean SetEvent(gpointer handle)
671 {
672         WapiHandleType type;
673         
674         if (handle == NULL) {
675                 SetLastError (ERROR_INVALID_HANDLE);
676                 return(FALSE);
677         }
678         
679         type = _wapi_handle_type (handle);
680         
681         if (event_ops[type].set == NULL) {
682                 SetLastError (ERROR_INVALID_HANDLE);
683                 return(FALSE);
684         }
685         
686         return(event_ops[type].set (handle));
687 }
688
689 gpointer OpenEvent (guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, const gunichar2 *name)
690 {
691         gpointer handle;
692         gchar *utf8_name;
693         int thr_ret;
694         gpointer ret = NULL;
695         gint32 offset;
696         
697         mono_once (&event_ops_once, event_ops_init);
698
699         /* w32 seems to guarantee that opening named objects can't
700          * race each other
701          */
702         thr_ret = _wapi_namespace_lock ();
703         g_assert (thr_ret == 0);
704
705         utf8_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
706         
707         DEBUG ("%s: Opening named event [%s]", __func__, utf8_name);
708         
709         offset = _wapi_search_handle_namespace (WAPI_HANDLE_NAMEDEVENT,
710                                                 utf8_name);
711         if (offset == -1) {
712                 /* The name has already been used for a different
713                  * object.
714                  */
715                 SetLastError (ERROR_INVALID_HANDLE);
716                 goto cleanup;
717         } else if (offset == 0) {
718                 /* This name doesn't exist */
719                 SetLastError (ERROR_FILE_NOT_FOUND);    /* yes, really */
720                 goto cleanup;
721         }
722
723         /* A new reference to an existing named event, so just create
724          * the private part
725          */
726         handle = _wapi_handle_new_from_offset (WAPI_HANDLE_NAMEDEVENT, offset,
727                                                TRUE);
728         
729         if (handle == _WAPI_HANDLE_INVALID) {
730                 g_warning ("%s: error opening named event handle", __func__);
731                 SetLastError (ERROR_GEN_FAILURE);
732                 goto cleanup;
733         }
734         ret = handle;
735
736         DEBUG ("%s: returning named event handle %p", __func__, handle);
737
738 cleanup:
739         g_free (utf8_name);
740
741         _wapi_namespace_unlock (NULL);
742         
743         return(ret);
744
745 }