Improve the reliability and error reporting of the TPL Dataflow test suite.
[mono-project.git] / mono / io-layer / mutexes.c
blob7ef9c43e24b7df29ba52e572aceb9acf1fa0e07f
1 /*
2 * mutexes.c: Mutex handles
4 * Author:
5 * Dick Porter (dick@ximian.com)
7 * (C) 2002-2006 Ximian, Inc.
8 */
10 #include <config.h>
11 #include <glib.h>
12 #include <pthread.h>
13 #include <string.h>
14 #include <unistd.h>
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/mutex-private.h>
21 #include <mono/utils/mono-mutex.h>
23 #if 0
24 #define DEBUG(...) g_message(__VA_ARGS__)
25 #else
26 #define DEBUG(...)
27 #endif
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 = {
39 NULL, /* close */
40 mutex_signal, /* signal */
41 mutex_own, /* own */
42 mutex_is_owned, /* is_owned */
43 NULL, /* special_wait */
44 NULL /* prewait */
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,
53 mut->recursion);
54 #else
55 g_print ("own: %5d:%5ld, count: %5u", mut->pid, mut->tid,
56 mut->recursion);
57 #endif
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 */
69 static gboolean mutex_release (gpointer handle);
70 static gboolean namedmutex_release (gpointer handle);
72 static struct
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},
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 |
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);
104 static void mutex_signal(gpointer handle)
106 ReleaseMutex(handle);
109 static gboolean mutex_own (gpointer handle)
111 struct _WapiHandle_mutex *mutex_handle;
112 gboolean ok;
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);
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,
134 mutex_handle->tid);
136 return(TRUE);
139 static gboolean mutex_is_owned (gpointer handle)
141 struct _WapiHandle_mutex *mutex_handle;
142 gboolean ok;
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);
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 ());
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);
164 return(FALSE);
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;
177 gboolean ok;
179 DEBUG ("%s: owning named mutex handle %p", __func__, handle);
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);
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);
201 return(TRUE);
204 static gboolean namedmutex_is_owned (gpointer handle)
206 struct _WapiHandle_namedmutex *namedmutex_handle;
207 gboolean ok;
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);
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 ());
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);
229 return(FALSE);
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
240 * clean up.
242 struct _WapiHandle_namedmutex *namedmutex_handle;
243 gboolean ok;
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;
253 DEBUG ("%s: Checking ownership of named mutex handle %p", __func__,
254 handle);
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;
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 ();
282 } else {
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;
293 gboolean ok;
294 int thr_ret;
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;
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);
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;
328 gboolean ok;
329 int thr_ret;
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;
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);
368 } else {
369 g_assert_not_reached ();
373 static gpointer mutex_create (WapiSecurityAttributes *security G_GNUC_UNUSED,
374 gboolean owned)
376 struct _WapiHandle_mutex mutex_handle = {0};
377 gpointer handle;
378 int thr_ret;
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);
392 return(NULL);
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);
400 if(owned==TRUE) {
401 mutex_own (handle);
402 } else {
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);
412 return(handle);
415 static gpointer namedmutex_create (WapiSecurityAttributes *security G_GNUC_UNUSED, gboolean owned,
416 const gunichar2 *name)
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;
426 /* w32 seems to guarantee that opening named objects can't
427 * race each other
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,
443 utf8_name);
444 if (offset == -1) {
445 /* The name has already been used for a different
446 * object.
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
454 SetLastError (ERROR_ALREADY_EXISTS);
456 /* Fall through to create the mutex handle. */
458 if (offset == 0) {
459 /* A new named mutex, so create both the private and
460 * shared parts
463 if (strlen (utf8_name) < MAX_PATH) {
464 namelen = strlen (utf8_name);
465 } else {
466 namelen = MAX_PATH;
469 memcpy (&namedmutex_handle.sharedns.name, utf8_name, namelen);
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
477 handle = _wapi_handle_new_from_offset (WAPI_HANDLE_NAMEDMUTEX,
478 offset, TRUE);
481 if (handle == _WAPI_HANDLE_INVALID) {
482 g_warning ("%s: error creating mutex handle", __func__);
483 SetLastError (ERROR_GEN_FAILURE);
484 goto cleanup;
486 ret = handle;
488 if (offset == 0) {
489 /* Set the initial state, as this is a completely new
490 * handle
492 thr_ret = _wapi_handle_lock_shared_handles ();
493 g_assert (thr_ret == 0);
495 if (owned == TRUE) {
496 namedmutex_own (handle);
497 } else {
498 _wapi_shared_handle_set_signal_state (handle, TRUE);
501 _wapi_handle_unlock_shared_handles ();
504 DEBUG ("%s: returning mutex handle %p", __func__, handle);
506 cleanup:
507 g_free (utf8_name);
509 _wapi_namespace_unlock (NULL);
511 return(ret);
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.
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);
538 if (name == NULL) {
539 return(mutex_create (security, owned));
540 } else {
541 return(namedmutex_create (security, owned, name));
545 static gboolean mutex_release (gpointer handle)
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;
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);
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);
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);
573 goto cleanup;
575 ret = TRUE;
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);
585 mutex_handle->pid=0;
586 mutex_handle->tid=0;
587 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
590 cleanup:
591 thr_ret = _wapi_handle_unlock_handle (handle);
592 g_assert (thr_ret == 0);
593 pthread_cleanup_pop (0);
595 return(ret);
598 static gboolean namedmutex_release (gpointer handle)
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;
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);
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);
624 goto cleanup;
626 ret = TRUE;
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);
636 mutex_handle->pid=0;
637 mutex_handle->tid=0;
638 _wapi_shared_handle_set_signal_state (handle, TRUE);
641 cleanup:
642 _wapi_handle_unlock_shared_handles ();
644 return(ret);
648 * ReleaseMutex:
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)
658 WapiHandleType type;
660 if (handle == NULL) {
661 SetLastError (ERROR_INVALID_HANDLE);
662 return(FALSE);
665 type = _wapi_handle_type (handle);
667 if (mutex_ops[type].release == NULL) {
668 SetLastError (ERROR_INVALID_HANDLE);
669 return(FALSE);
672 return(mutex_ops[type].release (handle));
675 gpointer OpenMutex (guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, const gunichar2 *name)
677 gpointer handle;
678 gchar *utf8_name;
679 int thr_ret;
680 gpointer ret = NULL;
681 gint32 offset;
683 mono_once (&mutex_ops_once, mutex_ops_init);
685 /* w32 seems to guarantee that opening named objects can't
686 * race each other
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,
696 utf8_name);
697 if (offset == -1) {
698 /* The name has already been used for a different
699 * object.
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;
709 /* A new reference to an existing named mutex, so just create
710 * the private part
712 handle = _wapi_handle_new_from_offset (WAPI_HANDLE_NAMEDMUTEX, offset,
713 TRUE);
715 if (handle == _WAPI_HANDLE_INVALID) {
716 g_warning ("%s: error opening named mutex handle", __func__);
717 SetLastError (ERROR_GEN_FAILURE);
718 goto cleanup;
720 ret = handle;
722 DEBUG ("%s: returning named mutex handle %p", __func__, handle);
724 cleanup:
725 g_free (utf8_name);
727 _wapi_namespace_unlock (NULL);
729 return(ret);