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);
27 static void mutex_prewait (gpointer handle);
28 static void mutex_details (gpointer data);
29 static const gchar* mutex_typename (void);
30 static gsize mutex_typesize (void);
32 static void namedmutex_signal (gpointer handle);
33 static gboolean namedmutex_own (gpointer handle);
34 static gboolean namedmutex_is_owned (gpointer handle);
35 static void namedmutex_prewait (gpointer handle);
36 static void namedmutex_details (gpointer data);
37 static const gchar* namedmutex_typename (void);
38 static gsize namedmutex_typesize (void);
40 WapiHandleOps _wapi_mutex_ops = {
42 mutex_signal, /* signal */
44 mutex_is_owned, /* is_owned */
45 NULL, /* special_wait */
46 mutex_prewait, /* prewait */
47 mutex_details, /* details */
48 mutex_typename, /* typename */
49 mutex_typesize, /* typesize */
52 WapiHandleOps _wapi_namedmutex_ops = {
54 namedmutex_signal, /* signal */
55 namedmutex_own, /* own */
56 namedmutex_is_owned, /* is_owned */
57 NULL, /* special_wait */
58 namedmutex_prewait, /* prewait */
59 namedmutex_details, /* details */
60 namedmutex_typename, /* typename */
61 namedmutex_typesize, /* typesize */
64 static mono_once_t mutex_ops_once=MONO_ONCE_INIT;
66 static void mutex_ops_init (void)
68 _wapi_handle_register_capabilities (WAPI_HANDLE_MUTEX,
69 (WapiHandleCapability)(WAPI_HANDLE_CAP_WAIT | WAPI_HANDLE_CAP_SIGNAL | WAPI_HANDLE_CAP_OWN));
70 _wapi_handle_register_capabilities (WAPI_HANDLE_NAMEDMUTEX,
71 (WapiHandleCapability)(WAPI_HANDLE_CAP_WAIT | WAPI_HANDLE_CAP_SIGNAL | WAPI_HANDLE_CAP_OWN));
74 static const char* mutex_handle_type_to_string (WapiHandleType type)
77 case WAPI_HANDLE_MUTEX: return "mutex";
78 case WAPI_HANDLE_NAMEDMUTEX: return "named mutex";
80 g_assert_not_reached ();
85 mutex_handle_own (gpointer handle, WapiHandleType type)
87 struct _WapiHandle_mutex *mutex_handle;
89 if (!_wapi_lookup_handle (handle, type, (gpointer *)&mutex_handle)) {
90 g_warning ("%s: error looking up %s handle %p", __func__, mutex_handle_type_to_string (type), handle);
94 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: owning %s handle %p, tid %p, recursion %u",
95 __func__, mutex_handle_type_to_string (type), handle, (gpointer) mutex_handle->tid, mutex_handle->recursion);
97 _wapi_thread_own_mutex (handle);
99 mutex_handle->tid = pthread_self ();
100 mutex_handle->recursion++;
102 _wapi_handle_set_signal_state (handle, FALSE, FALSE);
108 mutex_handle_is_owned (gpointer handle, WapiHandleType type)
110 struct _WapiHandle_mutex *mutex_handle;
112 if (!_wapi_lookup_handle (handle, type, (gpointer *)&mutex_handle)) {
113 g_warning ("%s: error looking up %s handle %p", __func__, mutex_handle_type_to_string (type), handle);
117 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: testing ownership %s handle %p",
118 __func__, mutex_handle_type_to_string (type), handle);
120 if (mutex_handle->recursion > 0 && pthread_equal (mutex_handle->tid, pthread_self ())) {
121 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: %s handle %p owned by %p",
122 __func__, mutex_handle_type_to_string (type), handle, (gpointer) pthread_self ());
125 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: %s handle %p not owned by %p, but locked %d times by %p",
126 __func__, mutex_handle_type_to_string (type), handle, (gpointer) pthread_self (), mutex_handle->recursion, (gpointer) mutex_handle->tid);
131 static void mutex_signal(gpointer handle)
133 ReleaseMutex(handle);
136 static gboolean mutex_own (gpointer handle)
138 return mutex_handle_own (handle, WAPI_HANDLE_MUTEX);
141 static gboolean mutex_is_owned (gpointer handle)
144 return mutex_handle_is_owned (handle, WAPI_HANDLE_MUTEX);
147 static void namedmutex_signal (gpointer handle)
149 ReleaseMutex(handle);
152 /* NB, always called with the shared handle lock held */
153 static gboolean namedmutex_own (gpointer handle)
155 return mutex_handle_own (handle, WAPI_HANDLE_NAMEDMUTEX);
158 static gboolean namedmutex_is_owned (gpointer handle)
160 return mutex_handle_is_owned (handle, WAPI_HANDLE_NAMEDMUTEX);
163 static void mutex_handle_prewait (gpointer handle, WapiHandleType type)
165 /* If the mutex is not currently owned, do nothing and let the
166 * usual wait carry on. If it is owned, check that the owner
167 * is still alive; if it isn't we override the previous owner
168 * and assume that process exited abnormally and failed to
171 struct _WapiHandle_mutex *mutex_handle;
173 if (!_wapi_lookup_handle (handle, type, (gpointer *)&mutex_handle)) {
174 g_warning ("%s: error looking up %s handle %p",
175 __func__, mutex_handle_type_to_string (type), handle);
179 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: pre-waiting %s handle %p, owned? %s",
180 __func__, mutex_handle_type_to_string (type), handle, mutex_handle->recursion != 0 ? "true" : "false");
183 /* The shared state is not locked when prewait methods are called */
184 static void mutex_prewait (gpointer handle)
186 mutex_handle_prewait (handle, WAPI_HANDLE_MUTEX);
189 /* The shared state is not locked when prewait methods are called */
190 static void namedmutex_prewait (gpointer handle)
192 mutex_handle_prewait (handle, WAPI_HANDLE_NAMEDMUTEX);
195 static void mutex_details (gpointer data)
197 struct _WapiHandle_mutex *mut = (struct _WapiHandle_mutex *)data;
199 #ifdef PTHREAD_POINTER_ID
200 g_print ("own: %5p, count: %5u", mut->tid, mut->recursion);
202 g_print ("own: %5ld, count: %5u", mut->tid, mut->recursion);
206 static void namedmutex_details (gpointer data)
208 struct _WapiHandle_namedmutex *namedmut = (struct _WapiHandle_namedmutex *)data;
210 #ifdef PTHREAD_POINTER_ID
211 g_print ("own: %5p, count: %5u, name: \"%s\"",
212 namedmut->m.tid, namedmut->m.recursion, namedmut->sharedns.name);
214 g_print ("own: %5ld, count: %5u, name: \"%s\"",
215 namedmut->m.tid, namedmut->m.recursion, namedmut->sharedns.name);
219 static const gchar* mutex_typename (void)
224 static gsize mutex_typesize (void)
226 return sizeof (struct _WapiHandle_mutex);
229 static const gchar* namedmutex_typename (void)
234 static gsize namedmutex_typesize (void)
236 return sizeof (struct _WapiHandle_namedmutex);
239 /* When a thread exits, any mutexes it still holds need to be signalled. */
240 void _wapi_mutex_abandon (gpointer handle, pid_t pid, pthread_t tid)
243 struct _WapiHandle_mutex *mutex_handle;
246 switch (type = _wapi_handle_type (handle)) {
247 case WAPI_HANDLE_MUTEX:
248 case WAPI_HANDLE_NAMEDMUTEX:
251 g_assert_not_reached ();
254 if (!_wapi_lookup_handle (handle, type, (gpointer *)&mutex_handle)) {
255 g_warning ("%s: error looking up %s handle %p",
256 __func__, mutex_handle_type_to_string (type), handle);
260 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: abandon %s handle %p",
261 __func__, mutex_handle_type_to_string (type), handle);
263 thr_ret = _wapi_handle_lock_handle (handle);
264 g_assert (thr_ret == 0);
266 if (pthread_equal (mutex_handle->tid, tid)) {
267 mutex_handle->recursion = 0;
268 mutex_handle->tid = 0;
270 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
272 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: abandoned %s handle %p",
273 __func__, mutex_handle_type_to_string (type), handle);
276 thr_ret = _wapi_handle_unlock_handle (handle);
277 g_assert (thr_ret == 0);
280 static gpointer mutex_handle_create (struct _WapiHandle_mutex *mutex_handle, WapiHandleType type, gboolean owned)
285 mutex_handle->tid = 0;
286 mutex_handle->recursion = 0;
288 handle = _wapi_handle_new (type, mutex_handle);
289 if (handle == _WAPI_HANDLE_INVALID) {
290 g_warning ("%s: error creating %s handle",
291 __func__, mutex_handle_type_to_string (type));
292 SetLastError (ERROR_GEN_FAILURE);
296 thr_ret = _wapi_handle_lock_handle (handle);
297 g_assert (thr_ret == 0);
300 mutex_handle_own (handle, type);
302 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
304 thr_ret = _wapi_handle_unlock_handle (handle);
305 g_assert (thr_ret == 0);
307 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: created %s handle %p",
308 __func__, mutex_handle_type_to_string (type), handle);
313 static gpointer mutex_create (gboolean owned)
315 struct _WapiHandle_mutex mutex_handle;
316 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: creating %s handle",
317 __func__, mutex_handle_type_to_string (WAPI_HANDLE_MUTEX));
318 return mutex_handle_create (&mutex_handle, WAPI_HANDLE_MUTEX, owned);
321 static gpointer namedmutex_create (gboolean owned, const gunichar2 *name)
327 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: creating %s handle",
328 __func__, mutex_handle_type_to_string (WAPI_HANDLE_NAMEDMUTEX));
330 /* w32 seems to guarantee that opening named objects can't race each other */
331 thr_ret = _wapi_namespace_lock ();
332 g_assert (thr_ret == 0);
334 utf8_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
336 handle = _wapi_search_handle_namespace (WAPI_HANDLE_NAMEDMUTEX, utf8_name);
337 if (handle == _WAPI_HANDLE_INVALID) {
338 /* The name has already been used for a different object. */
340 SetLastError (ERROR_INVALID_HANDLE);
342 /* Not an error, but this is how the caller is informed that the mutex wasn't freshly created */
343 SetLastError (ERROR_ALREADY_EXISTS);
345 /* this is used as creating a new handle */
346 _wapi_handle_ref (handle);
348 /* A new named mutex */
349 struct _WapiHandle_namedmutex namedmutex_handle;
351 strncpy (&namedmutex_handle.sharedns.name [0], utf8_name, MAX_PATH);
352 namedmutex_handle.sharedns.name [MAX_PATH] = '\0';
354 handle = mutex_handle_create ((struct _WapiHandle_mutex*) &namedmutex_handle, WAPI_HANDLE_NAMEDMUTEX, owned);
359 thr_ret = _wapi_namespace_unlock (NULL);
360 g_assert (thr_ret == 0);
367 * @security: Ignored for now.
368 * @owned: If %TRUE, the mutex is created with the calling thread
369 * already owning the mutex.
370 * @name:Pointer to a string specifying the name of this mutex, or
373 * Creates a new mutex handle. A mutex is signalled when no thread
374 * owns it. A thread acquires ownership of the mutex by waiting for
375 * it with WaitForSingleObject() or WaitForMultipleObjects(). A
376 * thread relinquishes ownership with ReleaseMutex().
378 * A thread that owns a mutex can specify the same mutex in repeated
379 * wait function calls without blocking. The thread must call
380 * ReleaseMutex() an equal number of times to release the mutex.
382 * Return value: A new handle, or %NULL on error.
384 gpointer CreateMutex(WapiSecurityAttributes *security G_GNUC_UNUSED, gboolean owned, const gunichar2 *name)
386 mono_once (&mutex_ops_once, mutex_ops_init);
388 /* Need to blow away any old errors here, because code tests
389 * for ERROR_ALREADY_EXISTS on success (!) to see if a mutex
390 * was freshly created */
391 SetLastError (ERROR_SUCCESS);
393 return name ? namedmutex_create (owned, name) : mutex_create (owned);
398 * @handle: The mutex handle.
400 * Releases ownership if the mutex handle @handle.
402 * Return value: %TRUE on success, %FALSE otherwise. This function
403 * fails if the calling thread does not own the mutex @handle.
405 gboolean ReleaseMutex(gpointer handle)
408 struct _WapiHandle_mutex *mutex_handle;
413 if (handle == NULL) {
414 SetLastError (ERROR_INVALID_HANDLE);
418 switch (type = _wapi_handle_type (handle)) {
419 case WAPI_HANDLE_MUTEX:
420 case WAPI_HANDLE_NAMEDMUTEX:
423 SetLastError (ERROR_INVALID_HANDLE);
427 if (!_wapi_lookup_handle (handle, type, (gpointer *)&mutex_handle)) {
428 g_warning ("%s: error looking up %s handle %p",
429 __func__, mutex_handle_type_to_string (type), handle);
433 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: releasing %s handle %p",
434 __func__, mutex_handle_type_to_string (type), handle);
436 thr_ret = _wapi_handle_lock_handle (handle);
437 g_assert (thr_ret == 0);
439 tid = pthread_self ();
441 if (!pthread_equal (mutex_handle->tid, tid)) {
444 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: we don't own %s handle %p (owned by %ld, me %ld)",
445 __func__, mutex_handle_type_to_string (type), handle, mutex_handle->tid, tid);
449 /* OK, we own this mutex */
450 mutex_handle->recursion--;
452 if (mutex_handle->recursion == 0) {
453 _wapi_thread_disown_mutex (handle);
455 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unlocking %s handle %p",
456 __func__, mutex_handle_type_to_string (type), handle);
458 mutex_handle->tid = 0;
459 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
463 thr_ret = _wapi_handle_unlock_handle (handle);
464 g_assert (thr_ret == 0);
469 gpointer OpenMutex (guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, const gunichar2 *name)
475 mono_once (&mutex_ops_once, mutex_ops_init);
477 /* w32 seems to guarantee that opening named objects can't
480 thr_ret = _wapi_namespace_lock ();
481 g_assert (thr_ret == 0);
483 utf8_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
485 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Opening named mutex [%s]", __func__, utf8_name);
487 handle = _wapi_search_handle_namespace (WAPI_HANDLE_NAMEDMUTEX,
489 if (handle == _WAPI_HANDLE_INVALID) {
490 /* The name has already been used for a different
493 SetLastError (ERROR_INVALID_HANDLE);
495 } else if (!handle) {
496 /* This name doesn't exist */
497 SetLastError (ERROR_FILE_NOT_FOUND); /* yes, really */
501 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning named mutex handle %p", __func__, handle);
506 _wapi_namespace_unlock (NULL);