[runtime] Free rgctx_lazy_fetch_trampoline info
[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_handle_set_signal_state (handle, FALSE, 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         
209         /* w32 seems to guarantee that opening named objects can't
210          * race each other
211          */
212         thr_ret = _wapi_namespace_lock ();
213         g_assert (thr_ret == 0);
214
215         /* Need to blow away any old errors here, because code tests
216          * for ERROR_ALREADY_EXISTS on success (!) to see if an event
217          * was freshly created
218          */
219         SetLastError (ERROR_SUCCESS);
220         
221         utf8_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
222         
223         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Creating named event [%s]", __func__, utf8_name);
224         
225         handle = _wapi_search_handle_namespace (WAPI_HANDLE_NAMEDEVENT,
226                                                 utf8_name);
227         if (handle == _WAPI_HANDLE_INVALID) {
228                 /* The name has already been used for a different
229                  * object.
230                  */
231                 SetLastError (ERROR_INVALID_HANDLE);
232                 goto cleanup;
233         } else if (handle) {
234                 /* Not an error, but this is how the caller is
235                  * informed that the event wasn't freshly created
236                  */
237                 SetLastError (ERROR_ALREADY_EXISTS);
238         } else {
239                 /* A new named event, so create both the private and
240                  * shared parts
241                  */
242         
243                 strncpy (&namedevent_handle.sharedns.name [0], utf8_name, MAX_PATH);
244                 namedevent_handle.sharedns.name [MAX_PATH] = '\0';
245
246                 namedevent_handle.manual = manual;
247                 namedevent_handle.set_count = 0;
248                 
249                 if (initial == TRUE) {
250                         if (manual == FALSE) {
251                                 namedevent_handle.set_count = 1;
252                         }
253                 }
254                 
255                 handle = _wapi_handle_new (WAPI_HANDLE_NAMEDEVENT,
256                                            &namedevent_handle);
257
258                 if (handle == _WAPI_HANDLE_INVALID) {
259                         g_warning ("%s: error creating event handle", __func__);
260                         SetLastError (ERROR_GEN_FAILURE);
261                         goto cleanup;
262                 }
263
264                 /* Set the initial state, as this is a completely new
265                  * handle
266                  */
267                 thr_ret = _wapi_handle_lock_handle (handle);
268                 g_assert (thr_ret == 0);
269         
270                 if (initial == TRUE) {
271                         _wapi_handle_set_signal_state (handle, TRUE, FALSE);
272                 }
273
274                 thr_ret = _wapi_handle_unlock_handle (handle);
275                 g_assert (thr_ret == 0);
276         }
277
278         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning event handle %p", __func__, handle);
279
280 cleanup:
281         g_free (utf8_name);
282
283         _wapi_namespace_unlock (NULL);
284         
285         return handle;
286
287 }
288
289
290 /**
291  * CreateEvent:
292  * @security: Ignored for now.
293  * @manual: Specifies whether the new event handle has manual or auto
294  * reset behaviour.
295  * @initial: Specifies whether the new event handle is initially
296  * signalled or not.
297  * @name:Pointer to a string specifying the name of this name, or
298  * %NULL.  Currently ignored.
299  *
300  * Creates a new event handle.
301  *
302  * An event handle is signalled with SetEvent().  If the new handle is
303  * a manual reset event handle, it remains signalled until it is reset
304  * with ResetEvent().  An auto reset event remains signalled until a
305  * single thread has waited for it, at which time the event handle is
306  * automatically reset to unsignalled.
307  *
308  * Return value: A new handle, or %NULL on error.
309  */
310 gpointer CreateEvent(WapiSecurityAttributes *security G_GNUC_UNUSED,
311                      gboolean manual, gboolean initial,
312                      const gunichar2 *name G_GNUC_UNUSED)
313 {
314         mono_once (&event_ops_once, event_ops_init);
315
316         if (name == NULL) {
317                 return(event_create (security, manual, initial));
318         } else {
319                 return(namedevent_create (security, manual, initial, name));
320         }
321 }
322
323 static gboolean event_pulse (gpointer handle)
324 {
325         struct _WapiHandle_event *event_handle;
326         gboolean ok;
327         int thr_ret;
328         
329         ok = _wapi_lookup_handle (handle, WAPI_HANDLE_EVENT,
330                                   (gpointer *)&event_handle);
331         if (ok == FALSE) {
332                 g_warning ("%s: error looking up event handle %p", __func__,
333                            handle);
334                 return(FALSE);
335         }
336         
337         thr_ret = _wapi_handle_unlock_handle (handle);
338         g_assert (thr_ret == 0);
339
340         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Pulsing event handle %p", __func__, handle);
341
342         if (event_handle->manual == TRUE) {
343                 _wapi_handle_set_signal_state (handle, TRUE, TRUE);
344         } else {
345                 event_handle->set_count = 1;
346                 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
347         }
348
349         thr_ret = _wapi_handle_unlock_handle (handle);
350         g_assert (thr_ret == 0);
351         
352         if (event_handle->manual == TRUE) {
353                 /* For a manual-reset event, we're about to try and
354                  * get the handle lock again, so give other threads a
355                  * chance
356                  */
357                 sched_yield ();
358
359                 /* Reset the handle signal state */
360                 /* I'm not sure whether or not we need a barrier here
361                  * to make sure that all threads waiting on the event
362                  * have proceeded.  Currently we rely on broadcasting
363                  * a condition.
364                  */
365                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Obtained write lock on event handle %p",
366                            __func__, handle);
367
368                 thr_ret = _wapi_handle_lock_handle (handle);
369                 g_assert (thr_ret == 0);
370                 
371                 _wapi_handle_set_signal_state (handle, FALSE, FALSE);
372
373                 thr_ret = _wapi_handle_unlock_handle (handle);
374                 g_assert (thr_ret == 0);
375         }
376
377         return(TRUE);
378 }
379
380 static gboolean namedevent_pulse (gpointer handle)
381 {
382         struct _WapiHandle_namedevent *namedevent_handle;
383         gboolean ok;
384         int thr_ret;
385         
386         ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDEVENT,
387                                   (gpointer *)&namedevent_handle);
388         if (ok == FALSE) {
389                 g_warning ("%s: error looking up named event handle %p",
390                            __func__, handle);
391                 return(FALSE);
392         }
393         
394         thr_ret = _wapi_handle_unlock_handle (handle);
395         g_assert (thr_ret == 0);
396
397         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Pulsing named event handle %p", __func__, handle);
398
399         if (namedevent_handle->manual == TRUE) {
400                 _wapi_handle_set_signal_state (handle, TRUE, TRUE);
401         } else {
402                 namedevent_handle->set_count = 1;
403                 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
404         }
405
406         thr_ret = _wapi_handle_unlock_handle (handle);
407         g_assert (thr_ret == 0);
408         
409         if (namedevent_handle->manual == TRUE) {
410                 /* For a manual-reset event, we're about to try and
411                  * get the handle lock again, so give other processes
412                  * a chance
413                  */
414                 _wapi_handle_spin (200);
415
416                 /* Reset the handle signal state */
417                 /* I'm not sure whether or not we need a barrier here
418                  * to make sure that all threads waiting on the event
419                  * have proceeded.  Currently we rely on waiting for
420                  * twice the shared handle poll interval.
421                  */
422                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Obtained write lock on event handle %p",
423                            __func__, handle);
424
425                 thr_ret = _wapi_handle_lock_handle (handle);
426                 g_assert (thr_ret == 0);
427                 
428                 _wapi_handle_set_signal_state (handle, FALSE, FALSE);
429
430                 thr_ret = _wapi_handle_unlock_handle (handle);
431                 g_assert (thr_ret == 0);
432         }
433
434         return(TRUE);
435 }
436
437 /**
438  * PulseEvent:
439  * @handle: The event handle.
440  *
441  * Sets the event handle @handle to the signalled state, and then
442  * resets it to unsignalled after informing any waiting threads.
443  *
444  * If @handle is a manual reset event, all waiting threads that can be
445  * released immediately are released.  @handle is then reset.  If
446  * @handle is an auto reset event, one waiting thread is released even
447  * if multiple threads are waiting.
448  *
449  * Return value: %TRUE on success, %FALSE otherwise.  (Currently only
450  * ever returns %TRUE).
451  */
452 gboolean PulseEvent(gpointer handle)
453 {
454         WapiHandleType type;
455         
456         if (handle == NULL) {
457                 SetLastError (ERROR_INVALID_HANDLE);
458                 return(FALSE);
459         }
460         
461         type = _wapi_handle_type (handle);
462         
463         if (event_ops[type].pulse == NULL) {
464                 SetLastError (ERROR_INVALID_HANDLE);
465                 return(FALSE);
466         }
467         
468         return(event_ops[type].pulse (handle));
469 }
470
471 static gboolean event_reset (gpointer handle)
472 {
473         struct _WapiHandle_event *event_handle;
474         gboolean ok;
475         int thr_ret;
476         
477         ok = _wapi_lookup_handle (handle, WAPI_HANDLE_EVENT,
478                                   (gpointer *)&event_handle);
479         if (ok == FALSE) {
480                 g_warning ("%s: error looking up event handle %p",
481                            __func__, handle);
482                 return(FALSE);
483         }
484
485         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Resetting event handle %p", __func__, handle);
486
487         thr_ret = _wapi_handle_lock_handle (handle);
488         g_assert (thr_ret == 0);
489         
490         if (_wapi_handle_issignalled (handle) == FALSE) {
491                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: No need to reset event handle %p", __func__,
492                            handle);
493         } else {
494                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Obtained write lock on event handle %p",
495                            __func__, handle);
496
497                 _wapi_handle_set_signal_state (handle, FALSE, FALSE);
498         }
499         
500         event_handle->set_count = 0;
501         
502         thr_ret = _wapi_handle_unlock_handle (handle);
503         g_assert (thr_ret == 0);
504         
505         return(TRUE);
506 }
507
508 static gboolean namedevent_reset (gpointer handle)
509 {
510         struct _WapiHandle_namedevent *namedevent_handle;
511         gboolean ok;
512         int thr_ret;
513         
514         ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDEVENT,
515                                   (gpointer *)&namedevent_handle);
516         if (ok == FALSE) {
517                 g_warning ("%s: error looking up named event handle %p",
518                            __func__, handle);
519                 return(FALSE);
520         }
521
522         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Resetting named event handle %p", __func__, handle);
523
524         thr_ret = _wapi_handle_lock_handle (handle);
525         g_assert (thr_ret == 0);
526         
527         if (_wapi_handle_issignalled (handle) == FALSE) {
528                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: No need to reset named event handle %p",
529                            __func__, handle);
530         } else {
531                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Obtained write lock on named event handle %p",
532                            __func__, handle);
533
534                 _wapi_handle_set_signal_state (handle, FALSE, FALSE);
535         }
536         
537         namedevent_handle->set_count = 0;
538         
539         thr_ret = _wapi_handle_unlock_handle (handle);
540         g_assert (thr_ret == 0);
541         
542         return(TRUE);
543 }
544
545 /**
546  * ResetEvent:
547  * @handle: The event handle.
548  *
549  * Resets the event handle @handle to the unsignalled state.
550  *
551  * Return value: %TRUE on success, %FALSE otherwise.  (Currently only
552  * ever returns %TRUE).
553  */
554 gboolean ResetEvent(gpointer handle)
555 {
556         WapiHandleType type;
557         
558         if (handle == NULL) {
559                 SetLastError (ERROR_INVALID_HANDLE);
560                 return(FALSE);
561         }
562         
563         type = _wapi_handle_type (handle);
564         
565         if (event_ops[type].reset == NULL) {
566                 SetLastError (ERROR_INVALID_HANDLE);
567                 return(FALSE);
568         }
569         
570         return(event_ops[type].reset (handle));
571 }
572
573 static gboolean event_set (gpointer handle)
574 {
575         struct _WapiHandle_event *event_handle;
576         gboolean ok;
577         int thr_ret;
578         
579         ok = _wapi_lookup_handle (handle, WAPI_HANDLE_EVENT,
580                                   (gpointer *)&event_handle);
581         if (ok == FALSE) {
582                 g_warning ("%s: error looking up event handle %p", __func__,
583                            handle);
584                 return(FALSE);
585         }
586         
587         thr_ret = _wapi_handle_lock_handle (handle);
588         g_assert (thr_ret == 0);
589
590         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Setting event handle %p", __func__, handle);
591
592         if (event_handle->manual == TRUE) {
593                 _wapi_handle_set_signal_state (handle, TRUE, TRUE);
594         } else {
595                 event_handle->set_count = 1;
596                 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
597         }
598
599         thr_ret = _wapi_handle_unlock_handle (handle);
600         g_assert (thr_ret == 0);
601         
602         return(TRUE);
603 }
604
605 static gboolean namedevent_set (gpointer handle)
606 {
607         struct _WapiHandle_namedevent *namedevent_handle;
608         gboolean ok;
609         int thr_ret;
610         
611         ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDEVENT,
612                                   (gpointer *)&namedevent_handle);
613         if (ok == FALSE) {
614                 g_warning ("%s: error looking up named event handle %p",
615                            __func__, handle);
616                 return(FALSE);
617         }
618         
619         thr_ret = _wapi_handle_lock_handle (handle);
620         g_assert (thr_ret == 0);
621
622         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Setting named event handle %p", __func__, handle);
623
624         if (namedevent_handle->manual == TRUE) {
625                 _wapi_handle_set_signal_state (handle, TRUE, TRUE);
626         } else {
627                 namedevent_handle->set_count = 1;
628                 _wapi_handle_set_signal_state (handle, TRUE, TRUE);
629         }
630
631         thr_ret = _wapi_handle_unlock_handle (handle);
632         g_assert (thr_ret == 0);
633
634         return(TRUE);
635 }
636
637 /**
638  * SetEvent:
639  * @handle: The event handle
640  *
641  * Sets the event handle @handle to the signalled state.
642  *
643  * If @handle is a manual reset event, it remains signalled until it
644  * is reset with ResetEvent().  An auto reset event remains signalled
645  * until a single thread has waited for it, at which time @handle is
646  * automatically reset to unsignalled.
647  *
648  * Return value: %TRUE on success, %FALSE otherwise.  (Currently only
649  * ever returns %TRUE).
650  */
651 gboolean SetEvent(gpointer handle)
652 {
653         WapiHandleType type;
654         
655         if (handle == NULL) {
656                 SetLastError (ERROR_INVALID_HANDLE);
657                 return(FALSE);
658         }
659         
660         type = _wapi_handle_type (handle);
661         
662         if (event_ops[type].set == NULL) {
663                 SetLastError (ERROR_INVALID_HANDLE);
664                 return(FALSE);
665         }
666         
667         return(event_ops[type].set (handle));
668 }
669
670 gpointer OpenEvent (guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, const gunichar2 *name)
671 {
672         gpointer handle;
673         gchar *utf8_name;
674         int thr_ret;
675         
676         mono_once (&event_ops_once, event_ops_init);
677
678         /* w32 seems to guarantee that opening named objects can't
679          * race each other
680          */
681         thr_ret = _wapi_namespace_lock ();
682         g_assert (thr_ret == 0);
683
684         utf8_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
685         
686         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Opening named event [%s]", __func__, utf8_name);
687         
688         handle = _wapi_search_handle_namespace (WAPI_HANDLE_NAMEDEVENT,
689                                                 utf8_name);
690         if (handle == _WAPI_HANDLE_INVALID) {
691                 /* The name has already been used for a different
692                  * object.
693                  */
694                 SetLastError (ERROR_INVALID_HANDLE);
695                 goto cleanup;
696         } else if (!handle) {
697                 /* This name doesn't exist */
698                 SetLastError (ERROR_FILE_NOT_FOUND);    /* yes, really */
699                 goto cleanup;
700         }
701
702         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning named event handle %p", __func__, handle);
703
704 cleanup:
705         g_free (utf8_name);
706
707         _wapi_namespace_unlock (NULL);
708         
709         return handle;
710
711 }