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