Merge pull request #915 from knocte/master
[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/misc-private.h>
19
20 #include <mono/io-layer/event-private.h>
21
22 #include <mono/utils/mono-mutex.h>
23 #if 0
24 #define DEBUG(...) g_message(__VA_ARGS__)
25 #else
26 #define DEBUG(...)
27 #endif
28
29 static void event_signal(gpointer handle);
30 static gboolean event_own (gpointer handle);
31
32 static void namedevent_signal (gpointer handle);
33 static gboolean namedevent_own (gpointer handle);
34
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 */
42 };
43
44 struct _WapiHandleOps _wapi_namedevent_ops = {
45         NULL,                   /* close */
46         namedevent_signal,      /* signal */
47         namedevent_own,         /* own */
48         NULL,                   /* is_owned */
49 };
50
51 static gboolean event_pulse (gpointer handle);
52 static gboolean event_reset (gpointer handle);
53 static gboolean event_set (gpointer handle);
54
55 static gboolean namedevent_pulse (gpointer handle);
56 static gboolean namedevent_reset (gpointer handle);
57 static gboolean namedevent_set (gpointer handle);
58
59 static struct
60 {
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},
79 };
80
81 void _wapi_event_details (gpointer handle_info)
82 {
83         struct _WapiHandle_event *event = (struct _WapiHandle_event *)handle_info;
84         
85         g_print ("manual: %s", event->manual?"TRUE":"FALSE");
86 }
87
88 static mono_once_t event_ops_once=MONO_ONCE_INIT;
89
90 static void event_ops_init (void)
91 {
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);
98 }
99
100 static void event_signal(gpointer handle)
101 {
102         SetEvent(handle);
103 }
104
105 static gboolean event_own (gpointer handle)
106 {
107         struct _WapiHandle_event *event_handle;
108         gboolean ok;
109         
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);
116         }
117         
118         DEBUG("%s: owning event handle %p", __func__, handle);
119
120         if(event_handle->manual==FALSE) {
121                 g_assert (event_handle->set_count > 0);
122                 
123                 if (--event_handle->set_count == 0) {
124                         _wapi_handle_set_signal_state (handle, FALSE, FALSE);
125                 }
126         }
127
128         return(TRUE);
129 }
130
131 static void namedevent_signal (gpointer handle)
132 {
133         SetEvent (handle);
134 }
135
136 /* NB, always called with the shared handle lock held */
137 static gboolean namedevent_own (gpointer handle)
138 {
139         struct _WapiHandle_namedevent *namedevent_handle;
140         gboolean ok;
141         
142         DEBUG ("%s: owning named event handle %p", __func__, handle);
143
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);
150         }
151         
152         if (namedevent_handle->manual == FALSE) {
153                 g_assert (namedevent_handle->set_count > 0);
154                 
155                 if (--namedevent_handle->set_count == 0) {
156                         _wapi_shared_handle_set_signal_state (handle, FALSE);
157                 }
158         }
159         
160         return (TRUE);
161 }
162 static gpointer event_create (WapiSecurityAttributes *security G_GNUC_UNUSED,
163                               gboolean manual, gboolean initial)
164 {
165         struct _WapiHandle_event event_handle = {0};
166         gpointer handle;
167         int thr_ret;
168         
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
172          */
173         SetLastError (ERROR_SUCCESS);
174
175         DEBUG ("%s: Creating unnamed event", __func__);
176         
177         event_handle.manual = manual;
178         event_handle.set_count = 0;
179
180         if (initial == TRUE) {
181                 if (manual == FALSE) {
182                         event_handle.set_count = 1;
183                 }
184         }
185         
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);
191         }
192
193         thr_ret = _wapi_handle_lock_handle (handle);
194         g_assert (thr_ret == 0);
195         
196         if (initial == TRUE) {
197                 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
198         }
199         
200         DEBUG("%s: created new event handle %p", __func__, handle);
201
202         thr_ret = _wapi_handle_unlock_handle (handle);
203         g_assert (thr_ret == 0);
204
205         return(handle);
206 }
207
208 static gpointer namedevent_create (WapiSecurityAttributes *security G_GNUC_UNUSED,
209                                    gboolean manual, gboolean initial,
210                                    const gunichar2 *name G_GNUC_UNUSED)
211 {
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;
219         
220         /* w32 seems to guarantee that opening named objects can't
221          * race each other
222          */
223         thr_ret = _wapi_namespace_lock ();
224         g_assert (thr_ret == 0);
225
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
229          */
230         SetLastError (ERROR_SUCCESS);
231         
232         utf8_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
233         
234         DEBUG ("%s: Creating named event [%s]", __func__, utf8_name);
235         
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.
241                  */
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
247                  */
248                 SetLastError (ERROR_ALREADY_EXISTS);
249         }
250         /* Fall through to create the event handle. */
251
252         if (offset == 0) {
253                 /* A new named event, so create both the private and
254                  * shared parts
255                  */
256         
257                 if (strlen (utf8_name) < MAX_PATH) {
258                         namelen = strlen (utf8_name);
259                 } else {
260                         namelen = MAX_PATH;
261                 }
262         
263                 memcpy (&namedevent_handle.sharedns.name, utf8_name, namelen);
264
265                 namedevent_handle.manual = manual;
266                 namedevent_handle.set_count = 0;
267                 
268                 if (initial == TRUE) {
269                         if (manual == FALSE) {
270                                 namedevent_handle.set_count = 1;
271                         }
272                 }
273                 
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
279                  */
280                 handle = _wapi_handle_new_from_offset (WAPI_HANDLE_NAMEDEVENT,
281                                                        offset, TRUE);
282         }
283         
284         if (handle == _WAPI_HANDLE_INVALID) {
285                 g_warning ("%s: error creating event handle", __func__);
286                 SetLastError (ERROR_GEN_FAILURE);
287                 goto cleanup;
288         }
289         ret = handle;
290
291         if (offset == 0) {
292                 /* Set the initial state, as this is a completely new
293                  * handle
294                  */
295                 thr_ret = _wapi_handle_lock_shared_handles ();
296                 g_assert (thr_ret == 0);
297         
298                 if (initial == TRUE) {
299                         _wapi_shared_handle_set_signal_state (handle, TRUE);
300                 }
301
302                 _wapi_handle_unlock_shared_handles ();
303         }
304         
305         DEBUG ("%s: returning event handle %p", __func__, handle);
306
307 cleanup:
308         g_free (utf8_name);
309
310         _wapi_namespace_unlock (NULL);
311         
312         return(ret);
313
314 }
315
316
317 /**
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.
326  *
327  * Creates a new event handle.
328  *
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.
334  *
335  * Return value: A new handle, or %NULL on error.
336  */
337 gpointer CreateEvent(WapiSecurityAttributes *security G_GNUC_UNUSED,
338                      gboolean manual, gboolean initial,
339                      const gunichar2 *name G_GNUC_UNUSED)
340 {
341         mono_once (&event_ops_once, event_ops_init);
342
343         if (name == NULL) {
344                 return(event_create (security, manual, initial));
345         } else {
346                 return(namedevent_create (security, manual, initial, name));
347         }
348 }
349
350 static gboolean event_pulse (gpointer handle)
351 {
352         struct _WapiHandle_event *event_handle;
353         gboolean ok;
354         int thr_ret;
355         
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);
362         }
363         
364         thr_ret = _wapi_handle_lock_handle (handle);
365         g_assert (thr_ret == 0);
366
367         DEBUG ("%s: Pulsing event handle %p", __func__, handle);
368
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);
374         }
375
376         thr_ret = _wapi_handle_unlock_handle (handle);
377         g_assert (thr_ret == 0);
378         
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
383                  */
384                 sched_yield ();
385
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.
391                  */
392                 DEBUG ("%s: Obtained write lock on event handle %p",
393                            __func__, handle);
394
395                 thr_ret = _wapi_handle_lock_handle (handle);
396                 g_assert (thr_ret == 0);
397                 
398                 _wapi_handle_set_signal_state (handle, FALSE, FALSE);
399
400                 thr_ret = _wapi_handle_unlock_handle (handle);
401                 g_assert (thr_ret == 0);
402         }
403
404         return(TRUE);
405 }
406
407 static gboolean namedevent_pulse (gpointer handle)
408 {
409         struct _WapiHandle_namedevent *namedevent_handle;
410         gboolean ok;
411         int thr_ret;
412         
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);
419         }
420         
421         thr_ret = _wapi_handle_lock_shared_handles ();
422         g_assert (thr_ret == 0);
423
424         DEBUG ("%s: Pulsing named event handle %p", __func__, handle);
425
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);
431         }
432
433         _wapi_handle_unlock_shared_handles ();
434         
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
439                  */
440                 _wapi_handle_spin (200);
441
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.
447                  */
448                 DEBUG ("%s: Obtained write lock on event handle %p",
449                            __func__, handle);
450
451                 thr_ret = _wapi_handle_lock_shared_handles ();
452                 g_assert (thr_ret == 0);
453                 
454                 _wapi_shared_handle_set_signal_state (handle, FALSE);
455
456                 _wapi_handle_unlock_shared_handles ();
457         }
458
459         return(TRUE);
460 }
461
462 /**
463  * PulseEvent:
464  * @handle: The event handle.
465  *
466  * Sets the event handle @handle to the signalled state, and then
467  * resets it to unsignalled after informing any waiting threads.
468  *
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.
473  *
474  * Return value: %TRUE on success, %FALSE otherwise.  (Currently only
475  * ever returns %TRUE).
476  */
477 gboolean PulseEvent(gpointer handle)
478 {
479         WapiHandleType type;
480         
481         if (handle == NULL) {
482                 SetLastError (ERROR_INVALID_HANDLE);
483                 return(FALSE);
484         }
485         
486         type = _wapi_handle_type (handle);
487         
488         if (event_ops[type].pulse == NULL) {
489                 SetLastError (ERROR_INVALID_HANDLE);
490                 return(FALSE);
491         }
492         
493         return(event_ops[type].pulse (handle));
494 }
495
496 static gboolean event_reset (gpointer handle)
497 {
498         struct _WapiHandle_event *event_handle;
499         gboolean ok;
500         int thr_ret;
501         
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);
508         }
509
510         DEBUG ("%s: Resetting event handle %p", __func__, handle);
511
512         thr_ret = _wapi_handle_lock_handle (handle);
513         g_assert (thr_ret == 0);
514         
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);
521
522                 _wapi_handle_set_signal_state (handle, FALSE, FALSE);
523         }
524         
525         event_handle->set_count = 0;
526         
527         thr_ret = _wapi_handle_unlock_handle (handle);
528         g_assert (thr_ret == 0);
529         
530         return(TRUE);
531 }
532
533 static gboolean namedevent_reset (gpointer handle)
534 {
535         struct _WapiHandle_namedevent *namedevent_handle;
536         gboolean ok;
537         int thr_ret;
538         
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);
545         }
546
547         DEBUG ("%s: Resetting named event handle %p", __func__, handle);
548
549         thr_ret = _wapi_handle_lock_shared_handles ();
550         g_assert (thr_ret == 0);
551         
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);
558
559                 _wapi_shared_handle_set_signal_state (handle, FALSE);
560         }
561         
562         namedevent_handle->set_count = 0;
563         
564         _wapi_handle_unlock_shared_handles ();
565         
566         return(TRUE);
567 }
568
569 /**
570  * ResetEvent:
571  * @handle: The event handle.
572  *
573  * Resets the event handle @handle to the unsignalled state.
574  *
575  * Return value: %TRUE on success, %FALSE otherwise.  (Currently only
576  * ever returns %TRUE).
577  */
578 gboolean ResetEvent(gpointer handle)
579 {
580         WapiHandleType type;
581         
582         if (handle == NULL) {
583                 SetLastError (ERROR_INVALID_HANDLE);
584                 return(FALSE);
585         }
586         
587         type = _wapi_handle_type (handle);
588         
589         if (event_ops[type].reset == NULL) {
590                 SetLastError (ERROR_INVALID_HANDLE);
591                 return(FALSE);
592         }
593         
594         return(event_ops[type].reset (handle));
595 }
596
597 static gboolean event_set (gpointer handle)
598 {
599         struct _WapiHandle_event *event_handle;
600         gboolean ok;
601         int thr_ret;
602         
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);
609         }
610         
611         thr_ret = _wapi_handle_lock_handle (handle);
612         g_assert (thr_ret == 0);
613
614         DEBUG ("%s: Setting event handle %p", __func__, handle);
615
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);
621         }
622
623         thr_ret = _wapi_handle_unlock_handle (handle);
624         g_assert (thr_ret == 0);
625         
626         return(TRUE);
627 }
628
629 static gboolean namedevent_set (gpointer handle)
630 {
631         struct _WapiHandle_namedevent *namedevent_handle;
632         gboolean ok;
633         int thr_ret;
634         
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);
641         }
642         
643         thr_ret = _wapi_handle_lock_shared_handles ();
644         g_assert (thr_ret == 0);
645
646         DEBUG ("%s: Setting named event handle %p", __func__, handle);
647
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);
653         }
654
655         _wapi_handle_unlock_shared_handles ();
656
657         return(TRUE);
658 }
659
660 /**
661  * SetEvent:
662  * @handle: The event handle
663  *
664  * Sets the event handle @handle to the signalled state.
665  *
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.
670  *
671  * Return value: %TRUE on success, %FALSE otherwise.  (Currently only
672  * ever returns %TRUE).
673  */
674 gboolean SetEvent(gpointer handle)
675 {
676         WapiHandleType type;
677         
678         if (handle == NULL) {
679                 SetLastError (ERROR_INVALID_HANDLE);
680                 return(FALSE);
681         }
682         
683         type = _wapi_handle_type (handle);
684         
685         if (event_ops[type].set == NULL) {
686                 SetLastError (ERROR_INVALID_HANDLE);
687                 return(FALSE);
688         }
689         
690         return(event_ops[type].set (handle));
691 }
692
693 gpointer OpenEvent (guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, const gunichar2 *name)
694 {
695         gpointer handle;
696         gchar *utf8_name;
697         int thr_ret;
698         gpointer ret = NULL;
699         gint32 offset;
700         
701         mono_once (&event_ops_once, event_ops_init);
702
703         /* w32 seems to guarantee that opening named objects can't
704          * race each other
705          */
706         thr_ret = _wapi_namespace_lock ();
707         g_assert (thr_ret == 0);
708
709         utf8_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
710         
711         DEBUG ("%s: Opening named event [%s]", __func__, utf8_name);
712         
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.
718                  */
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;
725         }
726
727         /* A new reference to an existing named event, so just create
728          * the private part
729          */
730         handle = _wapi_handle_new_from_offset (WAPI_HANDLE_NAMEDEVENT, offset,
731                                                TRUE);
732         
733         if (handle == _WAPI_HANDLE_INVALID) {
734                 g_warning ("%s: error opening named event handle", __func__);
735                 SetLastError (ERROR_GEN_FAILURE);
736                 goto cleanup;
737         }
738         ret = handle;
739
740         DEBUG ("%s: returning named event handle %p", __func__, handle);
741
742 cleanup:
743         g_free (utf8_name);
744
745         _wapi_namespace_unlock (NULL);
746         
747         return(ret);
748
749 }