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