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