2 * mutexes.c: Mutex handles
5 * Dick Porter (dick@ximian.com)
7 * (C) 2002 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>
25 static void mutex_signal(gpointer handle);
26 static gboolean mutex_own (gpointer handle);
27 static gboolean mutex_is_owned (gpointer handle);
29 static void namedmutex_signal (gpointer handle);
30 static gboolean namedmutex_own (gpointer handle);
31 static gboolean namedmutex_is_owned (gpointer handle);
33 struct _WapiHandleOps _wapi_mutex_ops = {
35 mutex_signal, /* signal */
37 mutex_is_owned, /* is_owned */
40 void _wapi_mutex_details (gpointer handle_info)
42 struct _WapiHandle_mutex *mut = (struct _WapiHandle_mutex *)handle_info;
44 #ifdef PTHREAD_POINTER_ID
45 g_print ("own: %5d:%5p, count: %5u", mut->pid, mut->tid,
48 g_print ("own: %5d:%5ld, count: %5u", mut->pid, mut->tid,
53 struct _WapiHandleOps _wapi_namedmutex_ops = {
55 namedmutex_signal, /* signal */
56 namedmutex_own, /* own */
57 namedmutex_is_owned, /* is_owned */
60 static gboolean mutex_release (gpointer handle);
61 static gboolean namedmutex_release (gpointer handle);
65 gboolean (*release)(gpointer handle);
66 } mutex_ops[WAPI_HANDLE_COUNT] = {
81 static mono_once_t mutex_ops_once=MONO_ONCE_INIT;
83 static void mutex_ops_init (void)
85 _wapi_handle_register_capabilities (WAPI_HANDLE_MUTEX,
86 WAPI_HANDLE_CAP_WAIT |
87 WAPI_HANDLE_CAP_SIGNAL |
89 _wapi_handle_register_capabilities (WAPI_HANDLE_NAMEDMUTEX,
90 WAPI_HANDLE_CAP_WAIT |
91 WAPI_HANDLE_CAP_SIGNAL |
95 static void mutex_signal(gpointer handle)
100 static gboolean mutex_own (gpointer handle)
102 struct _WapiHandle_mutex *mutex_handle;
105 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_MUTEX,
106 (gpointer *)&mutex_handle);
108 g_warning ("%s: error looking up mutex handle %p", __func__,
113 _wapi_thread_own_mutex (pthread_self (), handle);
116 g_message("%s: owning mutex handle %p", __func__, handle);
119 _wapi_handle_set_signal_state (handle, FALSE, FALSE);
121 mutex_handle->pid = getpid ();
122 mutex_handle->tid = pthread_self ();
123 mutex_handle->recursion++;
126 g_message ("%s: mutex handle %p locked %d times by %d:%ld", __func__,
127 handle, mutex_handle->recursion, mutex_handle->pid,
134 static gboolean mutex_is_owned (gpointer handle)
136 struct _WapiHandle_mutex *mutex_handle;
139 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_MUTEX,
140 (gpointer *)&mutex_handle);
142 g_warning ("%s: error looking up mutex handle %p", __func__,
148 g_message("%s: testing ownership mutex handle %p", __func__, handle);
151 if (mutex_handle->recursion > 0 &&
152 mutex_handle->pid == getpid () &&
153 mutex_handle->tid == pthread_self ()) {
155 g_message ("%s: mutex handle %p owned by %d:%ld", __func__,
156 handle, getpid (), pthread_self ());
162 g_message ("%s: mutex handle %p not owned by %d:%ld, but locked %d times by %d:%ld", __func__, handle, getpid (), pthread_self (), mutex_handle->recursion, mutex_handle->pid, mutex_handle->tid);
169 static void namedmutex_signal (gpointer handle)
171 ReleaseMutex(handle);
174 static gboolean namedmutex_own (gpointer handle)
176 struct _WapiHandleShared shared_handle;
177 struct _WapiHandle_namedmutex *namedmutex_handle;
181 g_message ("%s: owning named mutex handle %p", __func__, handle);
184 ok = _wapi_copy_handle (handle, WAPI_HANDLE_NAMEDMUTEX,
187 g_warning ("%s: error looking up named mutex handle %p",
192 _wapi_thread_own_mutex (pthread_self (), handle);
194 namedmutex_handle = &shared_handle.u.namedmutex;
196 namedmutex_handle->pid = getpid ();
197 namedmutex_handle->tid = pthread_self ();
198 namedmutex_handle->recursion++;
200 ok = _wapi_replace_handle (handle, WAPI_HANDLE_NAMEDMUTEX,
203 SetLastError (ERROR_OUTOFMEMORY);
207 _wapi_shared_handle_set_signal_state (handle, FALSE);
210 g_message ("%s: mutex handle %p locked %d times by %d:%ld", __func__,
211 handle, namedmutex_handle->recursion,
212 namedmutex_handle->pid, namedmutex_handle->tid);
218 static gboolean namedmutex_is_owned (gpointer handle)
220 struct _WapiHandle_namedmutex *namedmutex_handle;
223 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDMUTEX,
224 (gpointer *)&namedmutex_handle);
226 g_warning ("%s: error looking up mutex handle %p", __func__,
232 g_message ("%s: testing ownership mutex handle %p", __func__, handle);
235 if (namedmutex_handle->recursion > 0 &&
236 namedmutex_handle->pid == getpid () &&
237 namedmutex_handle->tid == pthread_self ()) {
239 g_message ("%s: mutex handle %p owned by %d:%ld", __func__,
240 handle, getpid (), pthread_self ());
246 g_message ("%s: mutex handle %p not owned by %d:%ld, but locked %d times by %d:%ld", __func__, handle, getpid (), pthread_self (), namedmutex_handle->recursion, namedmutex_handle->pid, namedmutex_handle->tid);
253 static void mutex_abandon (gpointer handle, pid_t pid, pthread_t tid)
255 struct _WapiHandle_mutex *mutex_handle;
259 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_MUTEX,
260 (gpointer *)&mutex_handle);
262 g_warning ("%s: error looking up mutex handle %p", __func__,
267 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
269 thr_ret = _wapi_handle_lock_handle (handle);
270 g_assert (thr_ret == 0);
272 if (mutex_handle->pid == pid &&
273 mutex_handle->tid == tid) {
275 g_message ("%s: Mutex handle %p abandoned!", __func__, handle);
278 mutex_handle->recursion = 0;
279 mutex_handle->pid = 0;
280 mutex_handle->tid = 0;
282 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
285 thr_ret = _wapi_handle_unlock_handle (handle);
286 g_assert (thr_ret == 0);
287 pthread_cleanup_pop (0);
290 static void namedmutex_abandon (gpointer handle, pid_t pid, pthread_t tid)
292 struct _WapiHandle_namedmutex *mutex_handle;
296 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDMUTEX,
297 (gpointer *)&mutex_handle);
299 g_warning ("%s: error looking up named mutex handle %p",
304 thr_ret = _wapi_handle_lock_shared_handles ();
305 g_assert (thr_ret == 0);
307 if (mutex_handle->pid == pid &&
308 mutex_handle->tid == tid) {
310 g_message ("%s: Mutex handle %p abandoned!", __func__, handle);
313 mutex_handle->recursion = 0;
314 mutex_handle->pid = 0;
315 mutex_handle->tid = 0;
317 _wapi_shared_handle_set_signal_state (handle, TRUE);
320 _wapi_handle_unlock_shared_handles ();
323 /* When a thread exits, any mutexes it still holds need to be signalled */
324 void _wapi_mutex_abandon (gpointer data, pid_t pid, pthread_t tid)
326 WapiHandleType type = _wapi_handle_type (data);
328 if (type == WAPI_HANDLE_MUTEX) {
329 mutex_abandon (data, pid, tid);
330 } else if (type == WAPI_HANDLE_NAMEDMUTEX) {
331 namedmutex_abandon (data, pid, tid);
333 g_assert_not_reached ();
337 static gpointer mutex_create (WapiSecurityAttributes *security G_GNUC_UNUSED,
340 struct _WapiHandle_mutex mutex_handle = {0};
344 /* Need to blow away any old errors here, because code tests
345 * for ERROR_ALREADY_EXISTS on success (!) to see if a mutex
346 * was freshly created
348 SetLastError (ERROR_SUCCESS);
351 g_message ("%s: Creating unnamed mutex", __func__);
354 handle = _wapi_handle_new (WAPI_HANDLE_MUTEX, &mutex_handle);
355 if (handle == _WAPI_HANDLE_INVALID) {
356 g_warning ("%s: error creating mutex handle", __func__);
357 SetLastError (ERROR_GEN_FAILURE);
361 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
363 thr_ret = _wapi_handle_lock_handle (handle);
364 g_assert (thr_ret == 0);
369 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
373 g_message ("%s: returning mutex handle %p", __func__, handle);
376 thr_ret = _wapi_handle_unlock_handle (handle);
377 g_assert (thr_ret == 0);
378 pthread_cleanup_pop (0);
383 static gpointer namedmutex_create (WapiSecurityAttributes *security G_GNUC_UNUSED, gboolean owned,
384 const gunichar2 *name)
386 struct _WapiHandle_namedmutex namedmutex_handle = {{{0}}, 0};
394 /* w32 seems to guarantee that opening named mutexes can't
397 pthread_cleanup_push ((void(*)(void *))_wapi_namespace_unlock, NULL);
398 thr_ret = _wapi_namespace_lock ();
399 g_assert (thr_ret == 0);
401 /* Need to blow away any old errors here, because code tests
402 * for ERROR_ALREADY_EXISTS on success (!) to see if a mutex
403 * was freshly created
405 SetLastError (ERROR_SUCCESS);
407 utf8_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
410 g_message ("%s: Creating named mutex [%s]", __func__, utf8_name);
413 offset = _wapi_search_handle_namespace (WAPI_HANDLE_NAMEDMUTEX,
416 /* The name has already been used for a different
419 SetLastError (ERROR_INVALID_HANDLE);
421 } else if (offset != 0) {
422 /* Not an error, but this is how the caller is
423 * informed that the mutex wasn't freshly created
425 SetLastError (ERROR_ALREADY_EXISTS);
427 /* Fall through to create the mutex handle. */
429 if (strlen (utf8_name) < MAX_PATH) {
430 namelen = strlen (utf8_name);
435 memcpy (&namedmutex_handle.sharedns.name, utf8_name, namelen);
438 /* A new named mutex, so create both the private and
441 handle = _wapi_handle_new (WAPI_HANDLE_NAMEDMUTEX,
444 /* A new reference to an existing named mutex, so just
445 * create the private part
447 handle = _wapi_handle_new_from_offset (WAPI_HANDLE_NAMEDMUTEX,
451 if (handle == _WAPI_HANDLE_INVALID) {
452 g_warning ("%s: error creating mutex handle", __func__);
453 SetLastError (ERROR_GEN_FAILURE);
459 /* Set the initial state, as this is a completely new
462 thr_ret = _wapi_handle_lock_shared_handles ();
463 g_assert (thr_ret == 0);
466 namedmutex_own (handle);
468 _wapi_shared_handle_set_signal_state (handle, TRUE);
471 _wapi_handle_unlock_shared_handles ();
475 g_message ("%s: returning mutex handle %p", __func__, handle);
480 /* Releases the timestamp */
481 pthread_cleanup_pop (1);
488 * @security: Ignored for now.
489 * @owned: If %TRUE, the mutex is created with the calling thread
490 * already owning the mutex.
491 * @name:Pointer to a string specifying the name of this mutex, or
494 * Creates a new mutex handle. A mutex is signalled when no thread
495 * owns it. A thread acquires ownership of the mutex by waiting for
496 * it with WaitForSingleObject() or WaitForMultipleObjects(). A
497 * thread relinquishes ownership with ReleaseMutex().
499 * A thread that owns a mutex can specify the same mutex in repeated
500 * wait function calls without blocking. The thread must call
501 * ReleaseMutex() an equal number of times to release the mutex.
503 * Return value: A new handle, or %NULL on error.
505 gpointer CreateMutex(WapiSecurityAttributes *security G_GNUC_UNUSED, gboolean owned,
506 const gunichar2 *name)
508 mono_once (&mutex_ops_once, mutex_ops_init);
511 return(mutex_create (security, owned));
513 return(namedmutex_create (security, owned, name));
517 static gboolean mutex_release (gpointer handle)
519 struct _WapiHandle_mutex *mutex_handle;
521 pthread_t tid=pthread_self();
524 gboolean ret = FALSE;
526 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_MUTEX,
527 (gpointer *)&mutex_handle);
529 g_warning ("%s: error looking up mutex handle %p", __func__,
534 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
536 thr_ret = _wapi_handle_lock_handle (handle);
537 g_assert (thr_ret == 0);
540 g_message("%s: Releasing mutex handle %p", __func__, handle);
543 if(mutex_handle->tid!=tid || mutex_handle->pid!=pid) {
545 g_message("%s: We don't own mutex handle %p (owned by %d:%ld, me %d:%ld)", __func__, handle, mutex_handle->pid, mutex_handle->tid, pid, tid);
552 /* OK, we own this mutex */
553 mutex_handle->recursion--;
555 if(mutex_handle->recursion==0) {
556 _wapi_thread_disown_mutex (tid, handle);
559 g_message("%s: Unlocking mutex handle %p", __func__, handle);
564 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
568 thr_ret = _wapi_handle_unlock_handle (handle);
569 g_assert (thr_ret == 0);
570 pthread_cleanup_pop (0);
575 static gboolean namedmutex_release (gpointer handle)
577 struct _WapiHandle_namedmutex *mutex_handle;
579 pthread_t tid=pthread_self();
582 gboolean ret = FALSE;
584 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDMUTEX,
585 (gpointer *)&mutex_handle);
587 g_warning ("%s: error looking up named mutex handle %p",
592 thr_ret = _wapi_handle_lock_shared_handles ();
593 g_assert (thr_ret == 0);
596 g_message("%s: Releasing mutex handle %p", __func__, handle);
599 if(mutex_handle->tid!=tid || mutex_handle->pid!=pid) {
601 g_message("%s: We don't own mutex handle %p (owned by %d:%ld, me %d:%ld)", __func__, handle, mutex_handle->pid, mutex_handle->tid, pid, tid);
608 /* OK, we own this mutex */
609 mutex_handle->recursion--;
611 if(mutex_handle->recursion==0) {
612 _wapi_thread_disown_mutex (tid, handle);
615 g_message("%s: Unlocking mutex handle %p", __func__, handle);
620 _wapi_shared_handle_set_signal_state (handle, TRUE);
624 _wapi_handle_unlock_shared_handles ();
631 * @handle: The mutex handle.
633 * Releases ownership if the mutex handle @handle.
635 * Return value: %TRUE on success, %FALSE otherwise. This function
636 * fails if the calling thread does not own the mutex @handle.
638 gboolean ReleaseMutex(gpointer handle)
642 if (handle == NULL) {
643 SetLastError (ERROR_INVALID_HANDLE);
647 type = _wapi_handle_type (handle);
649 if (mutex_ops[type].release == NULL) {
650 SetLastError (ERROR_INVALID_HANDLE);
654 return(mutex_ops[type].release (handle));