Added Mono.Tasklets test
[mono.git] / mono / io-layer / mutexes.c
1 /*
2  * mutexes.c:  Mutex handles
3  *
4  * Author:
5  *      Dick Porter (dick@ximian.com)
6  *
7  * (C) 2002-2006 Ximian, Inc.
8  */
9
10 #include <config.h>
11 #include <glib.h>
12 #include <pthread.h>
13 #include <string.h>
14 #include <unistd.h>
15
16 #include <mono/io-layer/wapi.h>
17 #include <mono/io-layer/wapi-private.h>
18 #include <mono/io-layer/handles-private.h>
19 #include <mono/io-layer/mutex-private.h>
20 #include <mono/io-layer/io-trace.h>
21 #include <mono/utils/mono-once.h>
22 #include <mono/utils/mono-logger-internals.h>
23
24 static void mutex_signal(gpointer handle);
25 static gboolean mutex_own (gpointer handle);
26 static gboolean mutex_is_owned (gpointer handle);
27
28 static void namedmutex_signal (gpointer handle);
29 static gboolean namedmutex_own (gpointer handle);
30 static gboolean namedmutex_is_owned (gpointer handle);
31 static void namedmutex_prewait (gpointer handle);
32
33 struct _WapiHandleOps _wapi_mutex_ops = {
34         NULL,                   /* close */
35         mutex_signal,           /* signal */
36         mutex_own,              /* own */
37         mutex_is_owned,         /* is_owned */
38         NULL,                   /* special_wait */
39         NULL                    /* prewait */
40 };
41
42 void _wapi_mutex_details (gpointer handle_info)
43 {
44         struct _WapiHandle_mutex *mut = (struct _WapiHandle_mutex *)handle_info;
45         
46 #ifdef PTHREAD_POINTER_ID
47         g_print ("own: %5p, count: %5u", mut->tid, mut->recursion);
48 #else
49         g_print ("own: %5ld, count: %5u", mut->tid, mut->recursion);
50 #endif
51 }
52
53 struct _WapiHandleOps _wapi_namedmutex_ops = {
54         NULL,                   /* close */
55         namedmutex_signal,      /* signal */
56         namedmutex_own,         /* own */
57         namedmutex_is_owned,    /* is_owned */
58         NULL,                   /* special_wait */
59         namedmutex_prewait      /* prewait */
60 };
61
62 static gboolean mutex_release (gpointer handle);
63 static gboolean namedmutex_release (gpointer handle);
64
65 static struct 
66 {
67         gboolean (*release)(gpointer handle);
68 } mutex_ops[WAPI_HANDLE_COUNT] = {
69         {NULL},
70         {NULL},
71         {NULL},
72         {NULL},
73         {NULL},
74         {mutex_release},
75         {NULL},
76         {NULL},
77         {NULL},
78         {NULL},
79         {NULL},
80         {namedmutex_release},
81 };
82
83 static mono_once_t mutex_ops_once=MONO_ONCE_INIT;
84
85 static void mutex_ops_init (void)
86 {
87         _wapi_handle_register_capabilities (WAPI_HANDLE_MUTEX,
88                 (WapiHandleCapability)(WAPI_HANDLE_CAP_WAIT | WAPI_HANDLE_CAP_SIGNAL | WAPI_HANDLE_CAP_OWN));
89         _wapi_handle_register_capabilities (WAPI_HANDLE_NAMEDMUTEX,
90                 (WapiHandleCapability)(WAPI_HANDLE_CAP_WAIT | WAPI_HANDLE_CAP_SIGNAL | WAPI_HANDLE_CAP_OWN));
91 }
92
93 static void mutex_signal(gpointer handle)
94 {
95         ReleaseMutex(handle);
96 }
97
98 static gboolean mutex_own (gpointer handle)
99 {
100         struct _WapiHandle_mutex *mutex_handle;
101         gboolean ok;
102         
103         ok = _wapi_lookup_handle (handle, WAPI_HANDLE_MUTEX,
104                                   (gpointer *)&mutex_handle);
105         if (ok == FALSE) {
106                 g_warning ("%s: error looking up mutex handle %p", __func__,
107                            handle);
108                 return(FALSE);
109         }
110
111         _wapi_thread_own_mutex (handle);
112         
113         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: owning mutex handle %p", __func__, handle);
114
115         _wapi_handle_set_signal_state (handle, FALSE, FALSE);
116         
117         mutex_handle->tid = pthread_self ();
118         mutex_handle->recursion++;
119
120         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: mutex handle %p locked %d times by %ld", __func__,
121                 handle, mutex_handle->recursion, mutex_handle->tid);
122
123         return(TRUE);
124 }
125
126 static gboolean mutex_is_owned (gpointer handle)
127 {
128         struct _WapiHandle_mutex *mutex_handle;
129         gboolean ok;
130         
131         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_MUTEX,
132                                 (gpointer *)&mutex_handle);
133         if(ok==FALSE) {
134                 g_warning ("%s: error looking up mutex handle %p", __func__,
135                            handle);
136                 return(FALSE);
137         }
138         
139         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: testing ownership mutex handle %p", __func__, handle);
140
141         if (mutex_handle->recursion > 0 && pthread_equal (mutex_handle->tid, pthread_self ())) {
142                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: mutex handle %p owned by %ld", __func__,
143                         handle, pthread_self ());
144
145                 return(TRUE);
146         } else {
147                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: mutex handle %p not owned by %ld, but locked %d times by %ld", __func__,
148                         handle, pthread_self (), mutex_handle->recursion, mutex_handle->tid);
149
150                 return(FALSE);
151         }
152 }
153
154 static void namedmutex_signal (gpointer handle)
155 {
156         ReleaseMutex(handle);
157 }
158
159 /* NB, always called with the shared handle lock held */
160 static gboolean namedmutex_own (gpointer handle)
161 {
162         struct _WapiHandle_namedmutex *namedmutex_handle;
163         gboolean ok;
164         
165         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: owning named mutex handle %p", __func__, handle);
166         
167         ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDMUTEX,
168                                   (gpointer *)&namedmutex_handle);
169         if (ok == FALSE) {
170                 g_warning ("%s: error looking up named mutex handle %p",
171                            __func__, handle);
172                 return(FALSE);
173         }
174
175         _wapi_thread_own_mutex (handle);
176
177         namedmutex_handle->tid = pthread_self ();
178         namedmutex_handle->recursion++;
179
180         _wapi_handle_set_signal_state (handle, FALSE, FALSE);
181
182         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: mutex handle %p locked %d times by %ld", __func__,
183                 handle, namedmutex_handle->recursion, namedmutex_handle->tid);
184         
185         return(TRUE);
186 }
187
188 static gboolean namedmutex_is_owned (gpointer handle)
189 {
190         struct _WapiHandle_namedmutex *namedmutex_handle;
191         gboolean ok;
192         
193         ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDMUTEX,
194                                   (gpointer *)&namedmutex_handle);
195         if (ok == FALSE) {
196                 g_warning ("%s: error looking up mutex handle %p", __func__,
197                            handle);
198                 return(FALSE);
199         }
200         
201         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: testing ownership mutex handle %p", __func__, handle);
202
203         if (namedmutex_handle->recursion > 0 && pthread_equal (namedmutex_handle->tid, pthread_self ())) {
204                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: mutex handle %p owned by %ld", __func__,
205                         handle, pthread_self ());
206
207                 return(TRUE);
208         } else {
209                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: mutex handle %p not owned by %ld, but locked %d times by %ld", __func__,
210                         handle, pthread_self (), namedmutex_handle->recursion, namedmutex_handle->tid);
211
212                 return(FALSE);
213         }
214 }
215
216 /* The shared state is not locked when prewait methods are called */
217 static void namedmutex_prewait (gpointer handle)
218 {
219         /* If the mutex is not currently owned, do nothing and let the
220          * usual wait carry on.  If it is owned, check that the owner
221          * is still alive; if it isn't we override the previous owner
222          * and assume that process exited abnormally and failed to
223          * clean up.
224          */
225         struct _WapiHandle_namedmutex *namedmutex_handle;
226         gboolean ok;
227         
228         ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDMUTEX,
229                                   (gpointer *)&namedmutex_handle);
230         if (ok == FALSE) {
231                 g_warning ("%s: error looking up named mutex handle %p",
232                            __func__, handle);
233                 return;
234         }
235         
236         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Checking ownership of named mutex handle %p", __func__,
237                    handle);
238
239         if (namedmutex_handle->recursion == 0) {
240                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Named mutex handle %p not owned", __func__,
241                            handle);
242         } else {
243                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Named mutex handle %p owned by this process", __func__,
244                         handle);
245         }
246 }
247
248 static void mutex_abandon (gpointer handle, pid_t pid, pthread_t tid)
249 {
250         struct _WapiHandle_mutex *mutex_handle;
251         gboolean ok;
252         int thr_ret;
253         
254         ok = _wapi_lookup_handle (handle, WAPI_HANDLE_MUTEX,
255                                   (gpointer *)&mutex_handle);
256         if (ok == FALSE) {
257                 g_warning ("%s: error looking up mutex handle %p", __func__,
258                            handle);
259                 return;
260         }
261
262         thr_ret = _wapi_handle_lock_handle (handle);
263         g_assert (thr_ret == 0);
264         
265         if (pthread_equal (mutex_handle->tid, tid)) {
266                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Mutex handle %p abandoned!", __func__,
267                         handle);
268
269                 mutex_handle->recursion = 0;
270                 mutex_handle->tid = 0;
271                 
272                 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
273         }
274
275         thr_ret = _wapi_handle_unlock_handle (handle);
276         g_assert (thr_ret == 0);
277 }
278
279 static void namedmutex_abandon (gpointer handle, pid_t pid, pthread_t tid)
280 {
281         struct _WapiHandle_namedmutex *mutex_handle;
282         gboolean ok;
283         int thr_ret;
284         
285         ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDMUTEX,
286                                   (gpointer *)&mutex_handle);
287         if (ok == FALSE) {
288                 g_warning ("%s: error looking up named mutex handle %p",
289                            __func__, handle);
290                 return;
291         }
292
293         thr_ret = _wapi_handle_lock_handle (handle);
294         g_assert (thr_ret == 0);
295         
296         if (pthread_equal (mutex_handle->tid, tid)) {
297                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Mutex handle %p abandoned!", __func__,
298                         handle);
299
300                 mutex_handle->recursion = 0;
301                 mutex_handle->tid = 0;
302                 
303                 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
304         }
305
306         thr_ret = _wapi_handle_unlock_handle (handle);
307         g_assert (thr_ret == 0);
308 }
309
310 /* When a thread exits, any mutexes it still holds need to be
311  * signalled.  This function must not be called with the shared handle
312  * lock held, as namedmutex_abandon () will try to acquire it
313  */
314 void _wapi_mutex_abandon (gpointer data, pid_t pid, pthread_t tid)
315 {
316         WapiHandleType type = _wapi_handle_type (data);
317
318         if (type == WAPI_HANDLE_MUTEX) {
319                 mutex_abandon (data, pid, tid);
320         } else if (type == WAPI_HANDLE_NAMEDMUTEX) {
321                 namedmutex_abandon (data, pid, tid);
322         } else {
323                 g_assert_not_reached ();
324         }
325 }
326
327 static gpointer mutex_create (WapiSecurityAttributes *security G_GNUC_UNUSED,
328                               gboolean owned)
329 {
330         struct _WapiHandle_mutex mutex_handle = {0};
331         gpointer handle;
332         int thr_ret;
333         
334         /* Need to blow away any old errors here, because code tests
335          * for ERROR_ALREADY_EXISTS on success (!) to see if a mutex
336          * was freshly created
337          */
338         SetLastError (ERROR_SUCCESS);
339         
340         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Creating unnamed mutex", __func__);
341         
342         handle = _wapi_handle_new (WAPI_HANDLE_MUTEX, &mutex_handle);
343         if (handle == _WAPI_HANDLE_INVALID) {
344                 g_warning ("%s: error creating mutex handle", __func__);
345                 SetLastError (ERROR_GEN_FAILURE);
346                 return(NULL);
347         }
348
349         thr_ret = _wapi_handle_lock_handle (handle);
350         g_assert (thr_ret == 0);
351         
352         if(owned==TRUE) {
353                 mutex_own (handle);
354         } else {
355                 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
356         }
357         
358         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning mutex handle %p", __func__, handle);
359
360         thr_ret = _wapi_handle_unlock_handle (handle);
361         g_assert (thr_ret == 0);
362         
363         return(handle);
364 }
365
366 static gpointer namedmutex_create (WapiSecurityAttributes *security G_GNUC_UNUSED, gboolean owned,
367                         const gunichar2 *name)
368 {
369         struct _WapiHandle_namedmutex namedmutex_handle = {{{0}}, 0};
370         gpointer handle;
371         gchar *utf8_name;
372         int thr_ret;
373
374         /* w32 seems to guarantee that opening named objects can't
375          * race each other
376          */
377         thr_ret = _wapi_namespace_lock ();
378         g_assert (thr_ret == 0);
379
380         /* Need to blow away any old errors here, because code tests
381          * for ERROR_ALREADY_EXISTS on success (!) to see if a mutex
382          * was freshly created
383          */
384         SetLastError (ERROR_SUCCESS);
385         
386         utf8_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
387         
388         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Creating named mutex [%s]", __func__, utf8_name);
389         
390         handle = _wapi_search_handle_namespace (WAPI_HANDLE_NAMEDMUTEX,
391                                                 utf8_name);
392         if (handle == _WAPI_HANDLE_INVALID) {
393                 /* The name has already been used for a different
394                  * object.
395                  */
396                 SetLastError (ERROR_INVALID_HANDLE);
397                 goto cleanup;
398         } else if (handle) {
399                 /* Not an error, but this is how the caller is
400                  * informed that the mutex wasn't freshly created
401                  */
402                 SetLastError (ERROR_ALREADY_EXISTS);
403         } else {
404                 /* A new named mutex, so create both the private and
405                  * shared parts
406                  */
407         
408                 strncpy (&namedmutex_handle.sharedns.name [0], utf8_name, MAX_PATH);
409                 namedmutex_handle.sharedns.name [MAX_PATH] = '\0';
410
411                 handle = _wapi_handle_new (WAPI_HANDLE_NAMEDMUTEX,
412                                            &namedmutex_handle);
413         
414                 if (handle == _WAPI_HANDLE_INVALID) {
415                         g_warning ("%s: error creating mutex handle", __func__);
416                         SetLastError (ERROR_GEN_FAILURE);
417                         goto cleanup;
418                 }
419
420                 /* Set the initial state, as this is a completely new
421                  * handle
422                  */
423                 thr_ret = _wapi_handle_lock_handle (handle);
424                 g_assert (thr_ret == 0);
425         
426                 if (owned == TRUE) {
427                         namedmutex_own (handle);
428                 } else {
429                         _wapi_handle_set_signal_state (handle, TRUE, FALSE);
430                 }
431
432                 thr_ret = _wapi_handle_unlock_handle (handle);
433                 g_assert (thr_ret == 0);
434         }
435         
436         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning mutex handle %p", __func__, handle);
437
438 cleanup:
439         g_free (utf8_name);
440
441         _wapi_namespace_unlock (NULL);
442         
443         return handle;
444 }
445
446 /**
447  * CreateMutex:
448  * @security: Ignored for now.
449  * @owned: If %TRUE, the mutex is created with the calling thread
450  * already owning the mutex.
451  * @name:Pointer to a string specifying the name of this mutex, or
452  * %NULL.
453  *
454  * Creates a new mutex handle.  A mutex is signalled when no thread
455  * owns it.  A thread acquires ownership of the mutex by waiting for
456  * it with WaitForSingleObject() or WaitForMultipleObjects().  A
457  * thread relinquishes ownership with ReleaseMutex().
458  *
459  * A thread that owns a mutex can specify the same mutex in repeated
460  * wait function calls without blocking.  The thread must call
461  * ReleaseMutex() an equal number of times to release the mutex.
462  *
463  * Return value: A new handle, or %NULL on error.
464  */
465 gpointer CreateMutex(WapiSecurityAttributes *security G_GNUC_UNUSED, gboolean owned,
466                         const gunichar2 *name)
467 {
468         mono_once (&mutex_ops_once, mutex_ops_init);
469
470         if (name == NULL) {
471                 return(mutex_create (security, owned));
472         } else {
473                 return(namedmutex_create (security, owned, name));
474         }
475 }
476
477 static gboolean mutex_release (gpointer handle)
478 {
479         struct _WapiHandle_mutex *mutex_handle;
480         gboolean ok;
481         pthread_t tid = pthread_self ();
482         int thr_ret;
483         gboolean ret = FALSE;
484         
485         ok = _wapi_lookup_handle (handle, WAPI_HANDLE_MUTEX,
486                                   (gpointer *)&mutex_handle);
487         if (ok == FALSE) {
488                 g_warning ("%s: error looking up mutex handle %p", __func__,
489                            handle);
490                 return(FALSE);
491         }
492
493         thr_ret = _wapi_handle_lock_handle (handle);
494         g_assert (thr_ret == 0);
495         
496         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Releasing mutex handle %p", __func__, handle);
497
498         if (!pthread_equal (mutex_handle->tid, tid)) {
499                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: We don't own mutex handle %p (owned by %ld, me %ld)", __func__,
500                         handle, mutex_handle->tid, tid);
501
502                 goto cleanup;
503         }
504         ret = TRUE;
505         
506         /* OK, we own this mutex */
507         mutex_handle->recursion--;
508         
509         if(mutex_handle->recursion==0) {
510                 _wapi_thread_disown_mutex (handle);
511
512                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Unlocking mutex handle %p", __func__, handle);
513
514                 mutex_handle->tid=0;
515                 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
516         }
517
518 cleanup:
519         thr_ret = _wapi_handle_unlock_handle (handle);
520         g_assert (thr_ret == 0);
521         
522         return(ret);
523 }
524
525 static gboolean namedmutex_release (gpointer handle)
526 {
527         struct _WapiHandle_namedmutex *mutex_handle;
528         gboolean ok;
529         pthread_t tid = pthread_self ();
530         int thr_ret;
531         gboolean ret = FALSE;
532         
533         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDMUTEX,
534                                 (gpointer *)&mutex_handle);
535         if(ok==FALSE) {
536                 g_warning ("%s: error looking up named mutex handle %p",
537                            __func__, handle);
538                 return(FALSE);
539         }
540
541         thr_ret = _wapi_handle_lock_handle (handle);
542         g_assert (thr_ret == 0);
543         
544         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Releasing mutex handle %p", __func__, handle);
545
546         if (!pthread_equal (mutex_handle->tid, tid)) {
547                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: We don't own mutex handle %p (owned by %ld, me %ld)", __func__,
548                         handle, mutex_handle->tid, tid);
549
550                 goto cleanup;
551         }
552         ret = TRUE;
553         
554         /* OK, we own this mutex */
555         mutex_handle->recursion--;
556         
557         if(mutex_handle->recursion==0) {
558                 _wapi_thread_disown_mutex (handle);
559
560                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Unlocking mutex handle %p", __func__, handle);
561
562                 mutex_handle->tid=0;
563                 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
564         }
565
566 cleanup:
567         thr_ret = _wapi_handle_unlock_handle (handle);
568         g_assert (thr_ret == 0);
569         
570         return(ret);
571 }
572
573 /**
574  * ReleaseMutex:
575  * @handle: The mutex handle.
576  *
577  * Releases ownership if the mutex handle @handle.
578  *
579  * Return value: %TRUE on success, %FALSE otherwise.  This function
580  * fails if the calling thread does not own the mutex @handle.
581  */
582 gboolean ReleaseMutex(gpointer handle)
583 {
584         WapiHandleType type;
585
586         if (handle == NULL) {
587                 SetLastError (ERROR_INVALID_HANDLE);
588                 return(FALSE);
589         }
590         
591         type = _wapi_handle_type (handle);
592         
593         if (mutex_ops[type].release == NULL) {
594                 SetLastError (ERROR_INVALID_HANDLE);
595                 return(FALSE);
596         }
597         
598         return(mutex_ops[type].release (handle));
599 }
600
601 gpointer OpenMutex (guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, const gunichar2 *name)
602 {
603         gpointer handle;
604         gchar *utf8_name;
605         int thr_ret;
606
607         mono_once (&mutex_ops_once, mutex_ops_init);
608
609         /* w32 seems to guarantee that opening named objects can't
610          * race each other
611          */
612         thr_ret = _wapi_namespace_lock ();
613         g_assert (thr_ret == 0);
614
615         utf8_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
616         
617         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Opening named mutex [%s]", __func__, utf8_name);
618         
619         handle = _wapi_search_handle_namespace (WAPI_HANDLE_NAMEDMUTEX,
620                                                 utf8_name);
621         if (handle == _WAPI_HANDLE_INVALID) {
622                 /* The name has already been used for a different
623                  * object.
624                  */
625                 SetLastError (ERROR_INVALID_HANDLE);
626                 goto cleanup;
627         } else if (!handle) {
628                 /* This name doesn't exist */
629                 SetLastError (ERROR_FILE_NOT_FOUND);    /* yes, really */
630                 goto cleanup;
631         }
632
633         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning named mutex handle %p", __func__, handle);
634
635 cleanup:
636         g_free (utf8_name);
637
638         _wapi_namespace_unlock (NULL);
639         
640         return handle;
641 }