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/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>
24 static void mutex_signal(gpointer handle);
25 static gboolean mutex_own (gpointer handle);
26 static gboolean mutex_is_owned (gpointer handle);
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);
33 struct _WapiHandleOps _wapi_mutex_ops = {
35 mutex_signal, /* signal */
37 mutex_is_owned, /* is_owned */
38 NULL, /* special_wait */
42 void _wapi_mutex_details (gpointer handle_info)
44 struct _WapiHandle_mutex *mut = (struct _WapiHandle_mutex *)handle_info;
46 #ifdef PTHREAD_POINTER_ID
47 g_print ("own: %5p, count: %5u", mut->tid, mut->recursion);
49 g_print ("own: %5ld, count: %5u", mut->tid, mut->recursion);
53 struct _WapiHandleOps _wapi_namedmutex_ops = {
55 namedmutex_signal, /* signal */
56 namedmutex_own, /* own */
57 namedmutex_is_owned, /* is_owned */
58 NULL, /* special_wait */
59 namedmutex_prewait /* prewait */
62 static gboolean mutex_release (gpointer handle);
63 static gboolean namedmutex_release (gpointer handle);
67 gboolean (*release)(gpointer handle);
68 } mutex_ops[WAPI_HANDLE_COUNT] = {
83 static mono_once_t mutex_ops_once=MONO_ONCE_INIT;
85 static void mutex_ops_init (void)
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));
93 static void mutex_signal(gpointer handle)
98 static gboolean mutex_own (gpointer handle)
100 struct _WapiHandle_mutex *mutex_handle;
103 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_MUTEX,
104 (gpointer *)&mutex_handle);
106 g_warning ("%s: error looking up mutex handle %p", __func__,
111 _wapi_thread_own_mutex (handle);
113 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: owning mutex handle %p", __func__, handle);
115 _wapi_handle_set_signal_state (handle, FALSE, FALSE);
117 mutex_handle->tid = pthread_self ();
118 mutex_handle->recursion++;
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);
126 static gboolean mutex_is_owned (gpointer handle)
128 struct _WapiHandle_mutex *mutex_handle;
131 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_MUTEX,
132 (gpointer *)&mutex_handle);
134 g_warning ("%s: error looking up mutex handle %p", __func__,
139 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: testing ownership mutex handle %p", __func__, handle);
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 ());
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);
154 static void namedmutex_signal (gpointer handle)
156 ReleaseMutex(handle);
159 /* NB, always called with the shared handle lock held */
160 static gboolean namedmutex_own (gpointer handle)
162 struct _WapiHandle_namedmutex *namedmutex_handle;
165 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: owning named mutex handle %p", __func__, handle);
167 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDMUTEX,
168 (gpointer *)&namedmutex_handle);
170 g_warning ("%s: error looking up named mutex handle %p",
175 _wapi_thread_own_mutex (handle);
177 namedmutex_handle->tid = pthread_self ();
178 namedmutex_handle->recursion++;
180 _wapi_handle_set_signal_state (handle, FALSE, FALSE);
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);
188 static gboolean namedmutex_is_owned (gpointer handle)
190 struct _WapiHandle_namedmutex *namedmutex_handle;
193 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDMUTEX,
194 (gpointer *)&namedmutex_handle);
196 g_warning ("%s: error looking up mutex handle %p", __func__,
201 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: testing ownership mutex handle %p", __func__, handle);
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 ());
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);
216 /* The shared state is not locked when prewait methods are called */
217 static void namedmutex_prewait (gpointer handle)
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
225 struct _WapiHandle_namedmutex *namedmutex_handle;
228 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDMUTEX,
229 (gpointer *)&namedmutex_handle);
231 g_warning ("%s: error looking up named mutex handle %p",
236 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Checking ownership of named mutex handle %p", __func__,
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__,
243 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Named mutex handle %p owned by this process", __func__,
248 static void mutex_abandon (gpointer handle, pid_t pid, pthread_t tid)
250 struct _WapiHandle_mutex *mutex_handle;
254 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_MUTEX,
255 (gpointer *)&mutex_handle);
257 g_warning ("%s: error looking up mutex handle %p", __func__,
262 thr_ret = _wapi_handle_lock_handle (handle);
263 g_assert (thr_ret == 0);
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__,
269 mutex_handle->recursion = 0;
270 mutex_handle->tid = 0;
272 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
275 thr_ret = _wapi_handle_unlock_handle (handle);
276 g_assert (thr_ret == 0);
279 static void namedmutex_abandon (gpointer handle, pid_t pid, pthread_t tid)
281 struct _WapiHandle_namedmutex *mutex_handle;
285 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDMUTEX,
286 (gpointer *)&mutex_handle);
288 g_warning ("%s: error looking up named mutex handle %p",
293 thr_ret = _wapi_handle_lock_handle (handle);
294 g_assert (thr_ret == 0);
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__,
300 mutex_handle->recursion = 0;
301 mutex_handle->tid = 0;
303 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
306 thr_ret = _wapi_handle_unlock_handle (handle);
307 g_assert (thr_ret == 0);
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
314 void _wapi_mutex_abandon (gpointer data, pid_t pid, pthread_t tid)
316 WapiHandleType type = _wapi_handle_type (data);
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);
323 g_assert_not_reached ();
327 static gpointer mutex_create (WapiSecurityAttributes *security G_GNUC_UNUSED,
330 struct _WapiHandle_mutex mutex_handle = {0};
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
338 SetLastError (ERROR_SUCCESS);
340 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Creating unnamed mutex", __func__);
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);
349 thr_ret = _wapi_handle_lock_handle (handle);
350 g_assert (thr_ret == 0);
355 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
358 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning mutex handle %p", __func__, handle);
360 thr_ret = _wapi_handle_unlock_handle (handle);
361 g_assert (thr_ret == 0);
366 static gpointer namedmutex_create (WapiSecurityAttributes *security G_GNUC_UNUSED, gboolean owned,
367 const gunichar2 *name)
369 struct _WapiHandle_namedmutex namedmutex_handle = {{{0}}, 0};
374 /* w32 seems to guarantee that opening named objects can't
377 thr_ret = _wapi_namespace_lock ();
378 g_assert (thr_ret == 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 utf8_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
388 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Creating named mutex [%s]", __func__, utf8_name);
390 handle = _wapi_search_handle_namespace (WAPI_HANDLE_NAMEDMUTEX,
392 if (handle == _WAPI_HANDLE_INVALID) {
393 /* The name has already been used for a different
396 SetLastError (ERROR_INVALID_HANDLE);
399 /* Not an error, but this is how the caller is
400 * informed that the mutex wasn't freshly created
402 SetLastError (ERROR_ALREADY_EXISTS);
404 /* A new named mutex, so create both the private and
408 strncpy (&namedmutex_handle.sharedns.name [0], utf8_name, MAX_PATH);
409 namedmutex_handle.sharedns.name [MAX_PATH] = '\0';
411 handle = _wapi_handle_new (WAPI_HANDLE_NAMEDMUTEX,
414 if (handle == _WAPI_HANDLE_INVALID) {
415 g_warning ("%s: error creating mutex handle", __func__);
416 SetLastError (ERROR_GEN_FAILURE);
420 /* Set the initial state, as this is a completely new
423 thr_ret = _wapi_handle_lock_handle (handle);
424 g_assert (thr_ret == 0);
427 namedmutex_own (handle);
429 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
432 thr_ret = _wapi_handle_unlock_handle (handle);
433 g_assert (thr_ret == 0);
436 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning mutex handle %p", __func__, handle);
441 _wapi_namespace_unlock (NULL);
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
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().
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.
463 * Return value: A new handle, or %NULL on error.
465 gpointer CreateMutex(WapiSecurityAttributes *security G_GNUC_UNUSED, gboolean owned,
466 const gunichar2 *name)
468 mono_once (&mutex_ops_once, mutex_ops_init);
471 return(mutex_create (security, owned));
473 return(namedmutex_create (security, owned, name));
477 static gboolean mutex_release (gpointer handle)
479 struct _WapiHandle_mutex *mutex_handle;
481 pthread_t tid = pthread_self ();
483 gboolean ret = FALSE;
485 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_MUTEX,
486 (gpointer *)&mutex_handle);
488 g_warning ("%s: error looking up mutex handle %p", __func__,
493 thr_ret = _wapi_handle_lock_handle (handle);
494 g_assert (thr_ret == 0);
496 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Releasing mutex handle %p", __func__, handle);
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);
506 /* OK, we own this mutex */
507 mutex_handle->recursion--;
509 if(mutex_handle->recursion==0) {
510 _wapi_thread_disown_mutex (handle);
512 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Unlocking mutex handle %p", __func__, handle);
515 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
519 thr_ret = _wapi_handle_unlock_handle (handle);
520 g_assert (thr_ret == 0);
525 static gboolean namedmutex_release (gpointer handle)
527 struct _WapiHandle_namedmutex *mutex_handle;
529 pthread_t tid = pthread_self ();
531 gboolean ret = FALSE;
533 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDMUTEX,
534 (gpointer *)&mutex_handle);
536 g_warning ("%s: error looking up named mutex handle %p",
541 thr_ret = _wapi_handle_lock_handle (handle);
542 g_assert (thr_ret == 0);
544 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Releasing mutex handle %p", __func__, handle);
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);
554 /* OK, we own this mutex */
555 mutex_handle->recursion--;
557 if(mutex_handle->recursion==0) {
558 _wapi_thread_disown_mutex (handle);
560 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Unlocking mutex handle %p", __func__, handle);
563 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
567 thr_ret = _wapi_handle_unlock_handle (handle);
568 g_assert (thr_ret == 0);
575 * @handle: The mutex handle.
577 * Releases ownership if the mutex handle @handle.
579 * Return value: %TRUE on success, %FALSE otherwise. This function
580 * fails if the calling thread does not own the mutex @handle.
582 gboolean ReleaseMutex(gpointer handle)
586 if (handle == NULL) {
587 SetLastError (ERROR_INVALID_HANDLE);
591 type = _wapi_handle_type (handle);
593 if (mutex_ops[type].release == NULL) {
594 SetLastError (ERROR_INVALID_HANDLE);
598 return(mutex_ops[type].release (handle));
601 gpointer OpenMutex (guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, const gunichar2 *name)
607 mono_once (&mutex_ops_once, mutex_ops_init);
609 /* w32 seems to guarantee that opening named objects can't
612 thr_ret = _wapi_namespace_lock ();
613 g_assert (thr_ret == 0);
615 utf8_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
617 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Opening named mutex [%s]", __func__, utf8_name);
619 handle = _wapi_search_handle_namespace (WAPI_HANDLE_NAMEDMUTEX,
621 if (handle == _WAPI_HANDLE_INVALID) {
622 /* The name has already been used for a different
625 SetLastError (ERROR_INVALID_HANDLE);
627 } else if (!handle) {
628 /* This name doesn't exist */
629 SetLastError (ERROR_FILE_NOT_FOUND); /* yes, really */
633 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning named mutex handle %p", __func__, handle);
638 _wapi_namespace_unlock (NULL);