2 * mutexes.c: Mutex handles
5 * Dick Porter (dick@ximian.com)
7 * (C) 2002-2006 Ximian, Inc.
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>
24 #define DEBUG(...) g_message(__VA_ARGS__)
29 static void mutex_signal(gpointer handle
);
30 static gboolean
mutex_own (gpointer handle
);
31 static gboolean
mutex_is_owned (gpointer handle
);
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
);
38 struct _WapiHandleOps _wapi_mutex_ops
= {
40 mutex_signal
, /* signal */
42 mutex_is_owned
, /* is_owned */
43 NULL
, /* special_wait */
47 void _wapi_mutex_details (gpointer handle_info
)
49 struct _WapiHandle_mutex
*mut
= (struct _WapiHandle_mutex
*)handle_info
;
51 #ifdef PTHREAD_POINTER_ID
52 g_print ("own: %5d:%5p, count: %5u", mut
->pid
, mut
->tid
,
55 g_print ("own: %5d:%5ld, count: %5u", mut
->pid
, mut
->tid
,
60 struct _WapiHandleOps _wapi_namedmutex_ops
= {
62 namedmutex_signal
, /* signal */
63 namedmutex_own
, /* own */
64 namedmutex_is_owned
, /* is_owned */
65 NULL
, /* special_wait */
66 namedmutex_prewait
/* prewait */
69 static gboolean
mutex_release (gpointer handle
);
70 static gboolean
namedmutex_release (gpointer handle
);
74 gboolean (*release
)(gpointer handle
);
75 } mutex_ops
[WAPI_HANDLE_COUNT
] = {
90 static mono_once_t mutex_ops_once
=MONO_ONCE_INIT
;
92 static void mutex_ops_init (void)
94 _wapi_handle_register_capabilities (WAPI_HANDLE_MUTEX
,
95 WAPI_HANDLE_CAP_WAIT
|
96 WAPI_HANDLE_CAP_SIGNAL
|
98 _wapi_handle_register_capabilities (WAPI_HANDLE_NAMEDMUTEX
,
99 WAPI_HANDLE_CAP_WAIT
|
100 WAPI_HANDLE_CAP_SIGNAL
|
101 WAPI_HANDLE_CAP_OWN
);
104 static void mutex_signal(gpointer handle
)
106 ReleaseMutex(handle
);
109 static gboolean
mutex_own (gpointer handle
)
111 struct _WapiHandle_mutex
*mutex_handle
;
114 ok
= _wapi_lookup_handle (handle
, WAPI_HANDLE_MUTEX
,
115 (gpointer
*)&mutex_handle
);
117 g_warning ("%s: error looking up mutex handle %p", __func__
,
122 _wapi_thread_own_mutex (handle
);
124 DEBUG("%s: owning mutex handle %p", __func__
, handle
);
126 _wapi_handle_set_signal_state (handle
, FALSE
, FALSE
);
128 mutex_handle
->pid
= _wapi_getpid ();
129 mutex_handle
->tid
= pthread_self ();
130 mutex_handle
->recursion
++;
132 DEBUG ("%s: mutex handle %p locked %d times by %d:%ld", __func__
,
133 handle
, mutex_handle
->recursion
, mutex_handle
->pid
,
139 static gboolean
mutex_is_owned (gpointer handle
)
141 struct _WapiHandle_mutex
*mutex_handle
;
144 ok
=_wapi_lookup_handle (handle
, WAPI_HANDLE_MUTEX
,
145 (gpointer
*)&mutex_handle
);
147 g_warning ("%s: error looking up mutex handle %p", __func__
,
152 DEBUG("%s: testing ownership mutex handle %p", __func__
, handle
);
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 ());
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
);
168 static void namedmutex_signal (gpointer handle
)
170 ReleaseMutex(handle
);
173 /* NB, always called with the shared handle lock held */
174 static gboolean
namedmutex_own (gpointer handle
)
176 struct _WapiHandle_namedmutex
*namedmutex_handle
;
179 DEBUG ("%s: owning named mutex handle %p", __func__
, handle
);
181 ok
= _wapi_lookup_handle (handle
, WAPI_HANDLE_NAMEDMUTEX
,
182 (gpointer
*)&namedmutex_handle
);
184 g_warning ("%s: error looking up named mutex handle %p",
189 _wapi_thread_own_mutex (handle
);
191 namedmutex_handle
->pid
= _wapi_getpid ();
192 namedmutex_handle
->tid
= pthread_self ();
193 namedmutex_handle
->recursion
++;
195 _wapi_shared_handle_set_signal_state (handle
, FALSE
);
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
);
204 static gboolean
namedmutex_is_owned (gpointer handle
)
206 struct _WapiHandle_namedmutex
*namedmutex_handle
;
209 ok
= _wapi_lookup_handle (handle
, WAPI_HANDLE_NAMEDMUTEX
,
210 (gpointer
*)&namedmutex_handle
);
212 g_warning ("%s: error looking up mutex handle %p", __func__
,
217 DEBUG ("%s: testing ownership mutex handle %p", __func__
, handle
);
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 ());
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
);
233 /* The shared state is not locked when prewait methods are called */
234 static void namedmutex_prewait (gpointer handle
)
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
242 struct _WapiHandle_namedmutex
*namedmutex_handle
;
245 ok
= _wapi_lookup_handle (handle
, WAPI_HANDLE_NAMEDMUTEX
,
246 (gpointer
*)&namedmutex_handle
);
248 g_warning ("%s: error looking up named mutex handle %p",
253 DEBUG ("%s: Checking ownership of named mutex handle %p", __func__
,
256 if (namedmutex_handle
->recursion
== 0) {
257 DEBUG ("%s: Named mutex handle %p not owned", __func__
,
259 } else if (namedmutex_handle
->pid
== _wapi_getpid ()) {
260 DEBUG ("%s: Named mutex handle %p owned by this process",
264 gpointer proc_handle
;
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
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);
276 namedmutex_handle
->pid
= 0;
277 namedmutex_handle
->tid
= 0;
278 namedmutex_handle
->recursion
= 0;
280 _wapi_shared_handle_set_signal_state (handle
, TRUE
);
281 _wapi_handle_unlock_shared_handles ();
283 DEBUG ("%s: Found active pid %d for named mutex handle %p", __func__
, namedmutex_handle
->pid
, handle
);
285 if (proc_handle
!= NULL
)
286 CloseProcess (proc_handle
);
290 static void mutex_abandon (gpointer handle
, pid_t pid
, pthread_t tid
)
292 struct _WapiHandle_mutex
*mutex_handle
;
296 ok
= _wapi_lookup_handle (handle
, WAPI_HANDLE_MUTEX
,
297 (gpointer
*)&mutex_handle
);
299 g_warning ("%s: error looking up mutex handle %p", __func__
,
304 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle
,
306 thr_ret
= _wapi_handle_lock_handle (handle
);
307 g_assert (thr_ret
== 0);
309 if (mutex_handle
->pid
== pid
&&
310 pthread_equal (mutex_handle
->tid
, tid
)) {
311 DEBUG ("%s: Mutex handle %p abandoned!", __func__
, handle
);
313 mutex_handle
->recursion
= 0;
314 mutex_handle
->pid
= 0;
315 mutex_handle
->tid
= 0;
317 _wapi_handle_set_signal_state (handle
, TRUE
, FALSE
);
320 thr_ret
= _wapi_handle_unlock_handle (handle
);
321 g_assert (thr_ret
== 0);
322 pthread_cleanup_pop (0);
325 static void namedmutex_abandon (gpointer handle
, pid_t pid
, pthread_t tid
)
327 struct _WapiHandle_namedmutex
*mutex_handle
;
331 ok
= _wapi_lookup_handle (handle
, WAPI_HANDLE_NAMEDMUTEX
,
332 (gpointer
*)&mutex_handle
);
334 g_warning ("%s: error looking up named mutex handle %p",
339 thr_ret
= _wapi_handle_lock_shared_handles ();
340 g_assert (thr_ret
== 0);
342 if (mutex_handle
->pid
== pid
&&
343 pthread_equal (mutex_handle
->tid
, tid
)) {
344 DEBUG ("%s: Mutex handle %p abandoned!", __func__
, handle
);
346 mutex_handle
->recursion
= 0;
347 mutex_handle
->pid
= 0;
348 mutex_handle
->tid
= 0;
350 _wapi_shared_handle_set_signal_state (handle
, TRUE
);
353 _wapi_handle_unlock_shared_handles ();
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
360 void _wapi_mutex_abandon (gpointer data
, pid_t pid
, pthread_t tid
)
362 WapiHandleType type
= _wapi_handle_type (data
);
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
);
369 g_assert_not_reached ();
373 static gpointer
mutex_create (WapiSecurityAttributes
*security G_GNUC_UNUSED
,
376 struct _WapiHandle_mutex mutex_handle
= {0};
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
384 SetLastError (ERROR_SUCCESS
);
386 DEBUG ("%s: Creating unnamed mutex", __func__
);
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
);
395 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle
,
397 thr_ret
= _wapi_handle_lock_handle (handle
);
398 g_assert (thr_ret
== 0);
403 _wapi_handle_set_signal_state (handle
, TRUE
, FALSE
);
406 DEBUG ("%s: returning mutex handle %p", __func__
, handle
);
408 thr_ret
= _wapi_handle_unlock_handle (handle
);
409 g_assert (thr_ret
== 0);
410 pthread_cleanup_pop (0);
415 static gpointer
namedmutex_create (WapiSecurityAttributes
*security G_GNUC_UNUSED
, gboolean owned
,
416 const gunichar2
*name
)
418 struct _WapiHandle_namedmutex namedmutex_handle
= {{{0}}, 0};
426 /* w32 seems to guarantee that opening named objects can't
429 thr_ret
= _wapi_namespace_lock ();
430 g_assert (thr_ret
== 0);
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
436 SetLastError (ERROR_SUCCESS
);
438 utf8_name
= g_utf16_to_utf8 (name
, -1, NULL
, NULL
, NULL
);
440 DEBUG ("%s: Creating named mutex [%s]", __func__
, utf8_name
);
442 offset
= _wapi_search_handle_namespace (WAPI_HANDLE_NAMEDMUTEX
,
445 /* The name has already been used for a different
448 SetLastError (ERROR_INVALID_HANDLE
);
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
454 SetLastError (ERROR_ALREADY_EXISTS
);
456 /* Fall through to create the mutex handle. */
459 /* A new named mutex, so create both the private and
463 if (strlen (utf8_name
) < MAX_PATH
) {
464 namelen
= strlen (utf8_name
);
469 memcpy (&namedmutex_handle
.sharedns
.name
, utf8_name
, namelen
);
471 handle
= _wapi_handle_new (WAPI_HANDLE_NAMEDMUTEX
,
474 /* A new reference to an existing named mutex, so just
475 * create the private part
477 handle
= _wapi_handle_new_from_offset (WAPI_HANDLE_NAMEDMUTEX
,
481 if (handle
== _WAPI_HANDLE_INVALID
) {
482 g_warning ("%s: error creating mutex handle", __func__
);
483 SetLastError (ERROR_GEN_FAILURE
);
489 /* Set the initial state, as this is a completely new
492 thr_ret
= _wapi_handle_lock_shared_handles ();
493 g_assert (thr_ret
== 0);
496 namedmutex_own (handle
);
498 _wapi_shared_handle_set_signal_state (handle
, TRUE
);
501 _wapi_handle_unlock_shared_handles ();
504 DEBUG ("%s: returning mutex handle %p", __func__
, handle
);
509 _wapi_namespace_unlock (NULL
);
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
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().
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.
531 * Return value: A new handle, or %NULL on error.
533 gpointer
CreateMutex(WapiSecurityAttributes
*security G_GNUC_UNUSED
, gboolean owned
,
534 const gunichar2
*name
)
536 mono_once (&mutex_ops_once
, mutex_ops_init
);
539 return(mutex_create (security
, owned
));
541 return(namedmutex_create (security
, owned
, name
));
545 static gboolean
mutex_release (gpointer handle
)
547 struct _WapiHandle_mutex
*mutex_handle
;
549 pthread_t tid
= pthread_self ();
550 pid_t pid
= _wapi_getpid ();
552 gboolean ret
= FALSE
;
554 ok
= _wapi_lookup_handle (handle
, WAPI_HANDLE_MUTEX
,
555 (gpointer
*)&mutex_handle
);
557 g_warning ("%s: error looking up mutex handle %p", __func__
,
562 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle
,
564 thr_ret
= _wapi_handle_lock_handle (handle
);
565 g_assert (thr_ret
== 0);
567 DEBUG("%s: Releasing mutex handle %p", __func__
, handle
);
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
);
577 /* OK, we own this mutex */
578 mutex_handle
->recursion
--;
580 if(mutex_handle
->recursion
==0) {
581 _wapi_thread_disown_mutex (handle
);
583 DEBUG("%s: Unlocking mutex handle %p", __func__
, handle
);
587 _wapi_handle_set_signal_state (handle
, TRUE
, FALSE
);
591 thr_ret
= _wapi_handle_unlock_handle (handle
);
592 g_assert (thr_ret
== 0);
593 pthread_cleanup_pop (0);
598 static gboolean
namedmutex_release (gpointer handle
)
600 struct _WapiHandle_namedmutex
*mutex_handle
;
602 pthread_t tid
= pthread_self ();
603 pid_t pid
= _wapi_getpid ();
605 gboolean ret
= FALSE
;
607 ok
=_wapi_lookup_handle (handle
, WAPI_HANDLE_NAMEDMUTEX
,
608 (gpointer
*)&mutex_handle
);
610 g_warning ("%s: error looking up named mutex handle %p",
615 thr_ret
= _wapi_handle_lock_shared_handles ();
616 g_assert (thr_ret
== 0);
618 DEBUG("%s: Releasing mutex handle %p", __func__
, handle
);
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
);
628 /* OK, we own this mutex */
629 mutex_handle
->recursion
--;
631 if(mutex_handle
->recursion
==0) {
632 _wapi_thread_disown_mutex (handle
);
634 DEBUG("%s: Unlocking mutex handle %p", __func__
, handle
);
638 _wapi_shared_handle_set_signal_state (handle
, TRUE
);
642 _wapi_handle_unlock_shared_handles ();
649 * @handle: The mutex handle.
651 * Releases ownership if the mutex handle @handle.
653 * Return value: %TRUE on success, %FALSE otherwise. This function
654 * fails if the calling thread does not own the mutex @handle.
656 gboolean
ReleaseMutex(gpointer handle
)
660 if (handle
== NULL
) {
661 SetLastError (ERROR_INVALID_HANDLE
);
665 type
= _wapi_handle_type (handle
);
667 if (mutex_ops
[type
].release
== NULL
) {
668 SetLastError (ERROR_INVALID_HANDLE
);
672 return(mutex_ops
[type
].release (handle
));
675 gpointer
OpenMutex (guint32 access G_GNUC_UNUSED
, gboolean inherit G_GNUC_UNUSED
, const gunichar2
*name
)
683 mono_once (&mutex_ops_once
, mutex_ops_init
);
685 /* w32 seems to guarantee that opening named objects can't
688 thr_ret
= _wapi_namespace_lock ();
689 g_assert (thr_ret
== 0);
691 utf8_name
= g_utf16_to_utf8 (name
, -1, NULL
, NULL
, NULL
);
693 DEBUG ("%s: Opening named mutex [%s]", __func__
, utf8_name
);
695 offset
= _wapi_search_handle_namespace (WAPI_HANDLE_NAMEDMUTEX
,
698 /* The name has already been used for a different
701 SetLastError (ERROR_INVALID_HANDLE
);
703 } else if (offset
== 0) {
704 /* This name doesn't exist */
705 SetLastError (ERROR_FILE_NOT_FOUND
); /* yes, really */
709 /* A new reference to an existing named mutex, so just create
712 handle
= _wapi_handle_new_from_offset (WAPI_HANDLE_NAMEDMUTEX
, offset
,
715 if (handle
== _WAPI_HANDLE_INVALID
) {
716 g_warning ("%s: error opening named mutex handle", __func__
);
717 SetLastError (ERROR_GEN_FAILURE
);
722 DEBUG ("%s: returning named mutex handle %p", __func__
, handle
);
727 _wapi_namespace_unlock (NULL
);