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/mutex-private.h>
19 #include <mono/io-layer/io-trace.h>
20 #include <mono/utils/mono-once.h>
21 #include <mono/utils/mono-logger-internals.h>
22 #include <mono/utils/w32handle.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 static MonoW32HandleOps _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 static MonoW32HandleOps _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 */
65 _wapi_mutex_init (void)
67 mono_w32handle_register_ops (MONO_W32HANDLE_MUTEX, &_wapi_mutex_ops);
68 mono_w32handle_register_ops (MONO_W32HANDLE_NAMEDMUTEX, &_wapi_namedmutex_ops);
70 mono_w32handle_register_capabilities (MONO_W32HANDLE_MUTEX,
71 (MonoW32HandleCapability)(MONO_W32HANDLE_CAP_WAIT | MONO_W32HANDLE_CAP_SIGNAL | MONO_W32HANDLE_CAP_OWN));
72 mono_w32handle_register_capabilities (MONO_W32HANDLE_NAMEDMUTEX,
73 (MonoW32HandleCapability)(MONO_W32HANDLE_CAP_WAIT | MONO_W32HANDLE_CAP_SIGNAL | MONO_W32HANDLE_CAP_OWN));
76 static const char* mutex_handle_type_to_string (MonoW32HandleType type)
79 case MONO_W32HANDLE_MUTEX: return "mutex";
80 case MONO_W32HANDLE_NAMEDMUTEX: return "named mutex";
82 g_assert_not_reached ();
87 mutex_handle_own (gpointer handle, MonoW32HandleType type)
89 struct _WapiHandle_mutex *mutex_handle;
91 if (!mono_w32handle_lookup (handle, type, (gpointer *)&mutex_handle)) {
92 g_warning ("%s: error looking up %s handle %p", __func__, mutex_handle_type_to_string (type), handle);
96 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: owning %s handle %p, tid %p, recursion %u",
97 __func__, mutex_handle_type_to_string (type), handle, (gpointer) mutex_handle->tid, mutex_handle->recursion);
99 mono_thread_info_own_mutex (mono_thread_info_current (), handle);
101 mutex_handle->tid = pthread_self ();
102 mutex_handle->recursion++;
104 mono_w32handle_set_signal_state (handle, FALSE, FALSE);
110 mutex_handle_is_owned (gpointer handle, MonoW32HandleType type)
112 struct _WapiHandle_mutex *mutex_handle;
114 if (!mono_w32handle_lookup (handle, type, (gpointer *)&mutex_handle)) {
115 g_warning ("%s: error looking up %s handle %p", __func__, mutex_handle_type_to_string (type), handle);
119 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: testing ownership %s handle %p",
120 __func__, mutex_handle_type_to_string (type), handle);
122 if (mutex_handle->recursion > 0 && pthread_equal (mutex_handle->tid, pthread_self ())) {
123 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: %s handle %p owned by %p",
124 __func__, mutex_handle_type_to_string (type), handle, (gpointer) pthread_self ());
127 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: %s handle %p not owned by %p, but locked %d times by %p",
128 __func__, mutex_handle_type_to_string (type), handle, (gpointer) pthread_self (), mutex_handle->recursion, (gpointer) mutex_handle->tid);
133 static void mutex_signal(gpointer handle)
135 ReleaseMutex(handle);
138 static gboolean mutex_own (gpointer handle)
140 return mutex_handle_own (handle, MONO_W32HANDLE_MUTEX);
143 static gboolean mutex_is_owned (gpointer handle)
146 return mutex_handle_is_owned (handle, MONO_W32HANDLE_MUTEX);
149 static void namedmutex_signal (gpointer handle)
151 ReleaseMutex(handle);
154 /* NB, always called with the shared handle lock held */
155 static gboolean namedmutex_own (gpointer handle)
157 return mutex_handle_own (handle, MONO_W32HANDLE_NAMEDMUTEX);
160 static gboolean namedmutex_is_owned (gpointer handle)
162 return mutex_handle_is_owned (handle, MONO_W32HANDLE_NAMEDMUTEX);
165 static void mutex_handle_prewait (gpointer handle, MonoW32HandleType type)
167 /* If the mutex is not currently owned, do nothing and let the
168 * usual wait carry on. If it is owned, check that the owner
169 * is still alive; if it isn't we override the previous owner
170 * and assume that process exited abnormally and failed to
173 struct _WapiHandle_mutex *mutex_handle;
175 if (!mono_w32handle_lookup (handle, type, (gpointer *)&mutex_handle)) {
176 g_warning ("%s: error looking up %s handle %p",
177 __func__, mutex_handle_type_to_string (type), handle);
181 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: pre-waiting %s handle %p, owned? %s",
182 __func__, mutex_handle_type_to_string (type), handle, mutex_handle->recursion != 0 ? "true" : "false");
185 /* The shared state is not locked when prewait methods are called */
186 static void mutex_prewait (gpointer handle)
188 mutex_handle_prewait (handle, MONO_W32HANDLE_MUTEX);
191 /* The shared state is not locked when prewait methods are called */
192 static void namedmutex_prewait (gpointer handle)
194 mutex_handle_prewait (handle, MONO_W32HANDLE_NAMEDMUTEX);
197 static void mutex_details (gpointer data)
199 struct _WapiHandle_mutex *mut = (struct _WapiHandle_mutex *)data;
201 #ifdef PTHREAD_POINTER_ID
202 g_print ("own: %5p, count: %5u", mut->tid, mut->recursion);
204 g_print ("own: %5ld, count: %5u", mut->tid, mut->recursion);
208 static void namedmutex_details (gpointer data)
210 struct _WapiHandle_namedmutex *namedmut = (struct _WapiHandle_namedmutex *)data;
212 #ifdef PTHREAD_POINTER_ID
213 g_print ("own: %5p, count: %5u, name: \"%s\"",
214 namedmut->m.tid, namedmut->m.recursion, namedmut->sharedns.name);
216 g_print ("own: %5ld, count: %5u, name: \"%s\"",
217 namedmut->m.tid, namedmut->m.recursion, namedmut->sharedns.name);
221 static const gchar* mutex_typename (void)
226 static gsize mutex_typesize (void)
228 return sizeof (struct _WapiHandle_mutex);
231 static const gchar* namedmutex_typename (void)
236 static gsize namedmutex_typesize (void)
238 return sizeof (struct _WapiHandle_namedmutex);
241 /* When a thread exits, any mutexes it still holds need to be signalled. */
242 void wapi_mutex_abandon (gpointer handle, pid_t pid, pthread_t tid)
244 MonoW32HandleType type;
245 struct _WapiHandle_mutex *mutex_handle;
248 switch (type = mono_w32handle_get_type (handle)) {
249 case MONO_W32HANDLE_MUTEX:
250 case MONO_W32HANDLE_NAMEDMUTEX:
253 g_assert_not_reached ();
256 if (!mono_w32handle_lookup (handle, type, (gpointer *)&mutex_handle)) {
257 g_warning ("%s: error looking up %s handle %p",
258 __func__, mutex_handle_type_to_string (type), handle);
262 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: abandon %s handle %p",
263 __func__, mutex_handle_type_to_string (type), handle);
265 thr_ret = mono_w32handle_lock_handle (handle);
266 g_assert (thr_ret == 0);
268 if (pthread_equal (mutex_handle->tid, tid)) {
269 mutex_handle->recursion = 0;
270 mutex_handle->tid = 0;
272 mono_w32handle_set_signal_state (handle, TRUE, FALSE);
274 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: abandoned %s handle %p",
275 __func__, mutex_handle_type_to_string (type), handle);
278 thr_ret = mono_w32handle_unlock_handle (handle);
279 g_assert (thr_ret == 0);
282 static gpointer mutex_handle_create (struct _WapiHandle_mutex *mutex_handle, MonoW32HandleType type, gboolean owned)
287 mutex_handle->tid = 0;
288 mutex_handle->recursion = 0;
290 handle = mono_w32handle_new (type, mutex_handle);
291 if (handle == INVALID_HANDLE_VALUE) {
292 g_warning ("%s: error creating %s handle",
293 __func__, mutex_handle_type_to_string (type));
294 SetLastError (ERROR_GEN_FAILURE);
298 thr_ret = mono_w32handle_lock_handle (handle);
299 g_assert (thr_ret == 0);
302 mutex_handle_own (handle, type);
304 mono_w32handle_set_signal_state (handle, TRUE, FALSE);
306 thr_ret = mono_w32handle_unlock_handle (handle);
307 g_assert (thr_ret == 0);
309 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: created %s handle %p",
310 __func__, mutex_handle_type_to_string (type), handle);
315 static gpointer mutex_create (gboolean owned)
317 struct _WapiHandle_mutex mutex_handle;
318 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: creating %s handle",
319 __func__, mutex_handle_type_to_string (MONO_W32HANDLE_MUTEX));
320 return mutex_handle_create (&mutex_handle, MONO_W32HANDLE_MUTEX, owned);
323 static gpointer namedmutex_create (gboolean owned, const gunichar2 *name)
329 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: creating %s handle",
330 __func__, mutex_handle_type_to_string (MONO_W32HANDLE_NAMEDMUTEX));
332 /* w32 seems to guarantee that opening named objects can't race each other */
333 thr_ret = _wapi_namespace_lock ();
334 g_assert (thr_ret == 0);
336 utf8_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
338 handle = _wapi_search_handle_namespace (MONO_W32HANDLE_NAMEDMUTEX, utf8_name);
339 if (handle == INVALID_HANDLE_VALUE) {
340 /* The name has already been used for a different object. */
342 SetLastError (ERROR_INVALID_HANDLE);
344 /* Not an error, but this is how the caller is informed that the mutex wasn't freshly created */
345 SetLastError (ERROR_ALREADY_EXISTS);
347 /* this is used as creating a new handle */
348 mono_w32handle_ref (handle);
350 /* A new named mutex */
351 struct _WapiHandle_namedmutex namedmutex_handle;
353 strncpy (&namedmutex_handle.sharedns.name [0], utf8_name, MAX_PATH);
354 namedmutex_handle.sharedns.name [MAX_PATH] = '\0';
356 handle = mutex_handle_create ((struct _WapiHandle_mutex*) &namedmutex_handle, MONO_W32HANDLE_NAMEDMUTEX, owned);
361 thr_ret = _wapi_namespace_unlock (NULL);
362 g_assert (thr_ret == 0);
369 * @security: Ignored for now.
370 * @owned: If %TRUE, the mutex is created with the calling thread
371 * already owning the mutex.
372 * @name:Pointer to a string specifying the name of this mutex, or
375 * Creates a new mutex handle. A mutex is signalled when no thread
376 * owns it. A thread acquires ownership of the mutex by waiting for
377 * it with WaitForSingleObject() or WaitForMultipleObjects(). A
378 * thread relinquishes ownership with ReleaseMutex().
380 * A thread that owns a mutex can specify the same mutex in repeated
381 * wait function calls without blocking. The thread must call
382 * ReleaseMutex() an equal number of times to release the mutex.
384 * Return value: A new handle, or %NULL on error.
386 gpointer CreateMutex(WapiSecurityAttributes *security G_GNUC_UNUSED, gboolean owned, const gunichar2 *name)
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)
407 MonoW32HandleType type;
408 struct _WapiHandle_mutex *mutex_handle;
413 if (handle == NULL) {
414 SetLastError (ERROR_INVALID_HANDLE);
418 switch (type = mono_w32handle_get_type (handle)) {
419 case MONO_W32HANDLE_MUTEX:
420 case MONO_W32HANDLE_NAMEDMUTEX:
423 SetLastError (ERROR_INVALID_HANDLE);
427 if (!mono_w32handle_lookup (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 = mono_w32handle_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 mono_thread_info_disown_mutex (mono_thread_info_current (), 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 mono_w32handle_set_signal_state (handle, TRUE, FALSE);
463 thr_ret = mono_w32handle_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 /* w32 seems to guarantee that opening named objects can't
478 thr_ret = _wapi_namespace_lock ();
479 g_assert (thr_ret == 0);
481 utf8_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
483 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Opening named mutex [%s]", __func__, utf8_name);
485 handle = _wapi_search_handle_namespace (MONO_W32HANDLE_NAMEDMUTEX,
487 if (handle == INVALID_HANDLE_VALUE) {
488 /* The name has already been used for a different
491 SetLastError (ERROR_INVALID_HANDLE);
493 } else if (!handle) {
494 /* This name doesn't exist */
495 SetLastError (ERROR_FILE_NOT_FOUND); /* yes, really */
499 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning named mutex handle %p", __func__, handle);
504 _wapi_namespace_unlock (NULL);