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