[Mono.Runtime.Tests] Exclude simd tests
[mono-project.git] / mono / metadata / w32mutex-unix.c
blob29bc860d68ab68e1bb6eb9ff5cca114e849b3f77
1 /**
2 * \file
3 * Runtime support for managed Mutex on Unix
5 * Author:
6 * Ludovic Henry (luhenry@microsoft.com)
8 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
9 */
11 #include "w32mutex.h"
13 #include <pthread.h>
15 #include "w32error.h"
16 #include "w32handle-namespace.h"
17 #include "mono/metadata/object-internals.h"
18 #include "mono/utils/mono-logger-internals.h"
19 #include "mono/utils/mono-threads.h"
20 #include "mono/metadata/w32handle.h"
21 #include "icall-decl.h"
23 #define MAX_PATH 260
25 typedef struct {
26 MonoNativeThreadId tid;
27 guint32 recursion;
28 gboolean abandoned;
29 } MonoW32HandleMutex;
31 struct MonoW32HandleNamedMutex {
32 MonoW32HandleMutex m;
33 MonoW32HandleNamespace sharedns;
36 static gpointer
37 mono_w32mutex_open (const char* utf8_name, gint32 rights G_GNUC_UNUSED, gint32 *win32error);
39 static void
40 thread_own_mutex (MonoInternalThreadHandle internal, gpointer handle, MonoW32Handle *handle_data)
42 /* if we are not on the current thread, there is a
43 * race condition when allocating internal->owned_mutexes */
44 g_assert (mono_thread_internal_is_current_handle (internal));
46 if (!MONO_HANDLE_GETVAL (internal, owned_mutexes))
47 MONO_HANDLE_SETVAL(internal, owned_mutexes, GPtrArray*, g_ptr_array_new ());
49 g_ptr_array_add (MONO_HANDLE_GETVAL (internal, owned_mutexes), mono_w32handle_duplicate (handle_data));
52 static void
53 thread_disown_mutex (MonoInternalThreadHandle internal, gpointer handle)
55 gboolean removed;
57 g_assert (mono_thread_internal_is_current_handle (internal));
59 g_assert (MONO_HANDLE_GETVAL (internal, owned_mutexes));
60 removed = g_ptr_array_remove (MONO_HANDLE_GETVAL (internal, owned_mutexes), handle);
61 g_assert (removed);
63 mono_w32handle_close (handle);
66 static void
67 mutex_handle_signal (MonoW32Handle *handle_data)
69 HANDLE_FUNCTION_ENTER ();
71 MonoW32HandleMutex *mutex_handle;
72 pthread_t tid;
74 mutex_handle = (MonoW32HandleMutex*) handle_data->specific;
76 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: signalling %s handle %p, tid: %p recursion: %d",
77 __func__, mono_w32handle_get_typename (handle_data->type), handle_data, (gpointer) mutex_handle->tid, mutex_handle->recursion);
79 tid = pthread_self ();
81 if (mutex_handle->abandoned) {
82 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: %s handle %p is abandoned",
83 __func__, mono_w32handle_get_typename (handle_data->type), handle_data);
84 } else if (!pthread_equal (mutex_handle->tid, tid)) {
85 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: we don't own %s handle %p (owned by %ld, me %ld)",
86 __func__, mono_w32handle_get_typename (handle_data->type), handle_data, (long)mutex_handle->tid, (long)tid);
87 } else {
88 /* OK, we own this mutex */
89 mutex_handle->recursion--;
91 if (mutex_handle->recursion == 0) {
92 thread_disown_mutex (mono_thread_internal_current_handle (), handle_data);
94 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: unlocking %s handle %p, tid: %p recusion : %d",
95 __func__, mono_w32handle_get_typename (handle_data->type), handle_data, (gpointer) mutex_handle->tid, mutex_handle->recursion);
97 mutex_handle->tid = 0;
98 mono_w32handle_set_signal_state (handle_data, TRUE, FALSE);
102 HANDLE_FUNCTION_RETURN ();
105 static gboolean
106 mutex_handle_own (MonoW32Handle *handle_data, gboolean *abandoned)
108 HANDLE_FUNCTION_ENTER ();
110 MonoW32HandleMutex *mutex_handle;
112 *abandoned = FALSE;
114 mutex_handle = (MonoW32HandleMutex*) handle_data->specific;
116 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: owning %s handle %p, before: [tid: %p, recursion: %d], after: [tid: %p, recursion: %d], abandoned: %s",
117 __func__, mono_w32handle_get_typename (handle_data->type), handle_data, (gpointer) mutex_handle->tid, mutex_handle->recursion, (gpointer) pthread_self (), mutex_handle->recursion + 1, mutex_handle->abandoned ? "true" : "false");
119 if (mutex_handle->recursion != 0) {
120 g_assert (pthread_equal (pthread_self (), mutex_handle->tid));
121 mutex_handle->recursion++;
122 } else {
123 mutex_handle->tid = pthread_self ();
124 mutex_handle->recursion = 1;
126 thread_own_mutex (mono_thread_internal_current_handle (), handle_data, handle_data);
129 if (mutex_handle->abandoned) {
130 mutex_handle->abandoned = FALSE;
131 *abandoned = TRUE;
134 mono_w32handle_set_signal_state (handle_data, FALSE, FALSE);
136 HANDLE_FUNCTION_RETURN_VAL (TRUE);
139 static gboolean
140 mutex_handle_is_owned (MonoW32Handle *handle_data)
142 MonoW32HandleMutex *mutex_handle;
144 mutex_handle = (MonoW32HandleMutex*) handle_data->specific;
146 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: testing ownership %s handle %p",
147 __func__, mono_w32handle_get_typename (handle_data->type), handle_data);
149 if (mutex_handle->recursion > 0 && pthread_equal (mutex_handle->tid, pthread_self ())) {
150 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: %s handle %p owned by %p",
151 __func__, mono_w32handle_get_typename (handle_data->type), handle_data, (gpointer) pthread_self ());
152 return TRUE;
153 } else {
154 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: %s handle %p not owned by %p, tid: %p recursion: %d",
155 __func__, mono_w32handle_get_typename (handle_data->type), handle_data, (gpointer) pthread_self (), (gpointer) mutex_handle->tid, mutex_handle->recursion);
156 return FALSE;
160 static void mutex_handle_prewait (MonoW32Handle *handle_data)
162 /* If the mutex is not currently owned, do nothing and let the
163 * usual wait carry on. If it is owned, check that the owner
164 * is still alive; if it isn't we override the previous owner
165 * and assume that process exited abnormally and failed to
166 * clean up.
168 MonoW32HandleMutex *mutex_handle;
170 mutex_handle = (MonoW32HandleMutex*) handle_data->specific;
172 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: pre-waiting %s handle %p, owned? %s",
173 __func__, mono_w32handle_get_typename (handle_data->type), handle_data, mutex_handle->recursion != 0 ? "true" : "false");
176 static void mutex_details (MonoW32Handle *handle_data)
178 MonoW32HandleMutex *mut = (MonoW32HandleMutex *)handle_data->specific;
180 #ifdef PTHREAD_POINTER_ID
181 g_print ("own: %5p, count: %5u", mut->tid, mut->recursion);
182 #else
183 g_print ("own: %5ld, count: %5u", mut->tid, mut->recursion);
184 #endif
187 static void namedmutex_details (MonoW32Handle *handle_data)
189 MonoW32HandleNamedMutex *namedmut = (MonoW32HandleNamedMutex *)handle_data->specific;
191 #ifdef PTHREAD_POINTER_ID
192 g_print ("own: %5p, count: %5u, name: \"%s\"",
193 namedmut->m.tid, namedmut->m.recursion, namedmut->sharedns.name);
194 #else
195 g_print ("own: %5ld, count: %5u, name: \"%s\"",
196 namedmut->m.tid, namedmut->m.recursion, namedmut->sharedns.name);
197 #endif
200 static const gchar* mutex_typename (void)
202 return "Mutex";
205 static gsize mutex_typesize (void)
207 return sizeof (MonoW32HandleMutex);
210 static const gchar* namedmutex_typename (void)
212 return "N.Mutex";
215 static gsize namedmutex_typesize (void)
217 return sizeof (MonoW32HandleNamedMutex);
220 void
221 mono_w32mutex_init (void)
223 static const MonoW32HandleOps mutex_ops = {
224 NULL, /* close */
225 mutex_handle_signal, /* signal */
226 mutex_handle_own, /* own */
227 mutex_handle_is_owned, /* is_owned */
228 NULL, /* special_wait */
229 mutex_handle_prewait, /* prewait */
230 mutex_details, /* details */
231 mutex_typename, /* typename */
232 mutex_typesize, /* typesize */
235 static const MonoW32HandleOps namedmutex_ops = {
236 NULL, /* close */
237 mutex_handle_signal, /* signal */
238 mutex_handle_own, /* own */
239 mutex_handle_is_owned, /* is_owned */
240 NULL, /* special_wait */
241 mutex_handle_prewait, /* prewait */
242 namedmutex_details, /* details */
243 namedmutex_typename, /* typename */
244 namedmutex_typesize, /* typesize */
247 mono_w32handle_register_ops (MONO_W32TYPE_MUTEX, &mutex_ops);
248 mono_w32handle_register_ops (MONO_W32TYPE_NAMEDMUTEX, &namedmutex_ops);
250 mono_w32handle_register_capabilities (MONO_W32TYPE_MUTEX,
251 (MonoW32HandleCapability)(MONO_W32HANDLE_CAP_WAIT | MONO_W32HANDLE_CAP_SIGNAL | MONO_W32HANDLE_CAP_OWN));
252 mono_w32handle_register_capabilities (MONO_W32TYPE_NAMEDMUTEX,
253 (MonoW32HandleCapability)(MONO_W32HANDLE_CAP_WAIT | MONO_W32HANDLE_CAP_SIGNAL | MONO_W32HANDLE_CAP_OWN));
256 static gpointer mutex_handle_create (MonoW32HandleMutex *mutex_handle, MonoW32Type type, gboolean owned)
258 MonoW32Handle *handle_data;
259 gpointer handle;
260 gboolean abandoned;
262 mutex_handle->tid = 0;
263 mutex_handle->recursion = 0;
264 mutex_handle->abandoned = FALSE;
266 handle = mono_w32handle_new (type, mutex_handle);
267 if (handle == INVALID_HANDLE_VALUE) {
268 g_warning ("%s: error creating %s handle",
269 __func__, mono_w32handle_get_typename (type));
270 mono_w32error_set_last (ERROR_GEN_FAILURE);
271 return NULL;
274 if (!mono_w32handle_lookup_and_ref (handle, &handle_data))
275 g_error ("%s: unkown handle %p", __func__, handle);
277 if (handle_data->type != type)
278 g_error ("%s: unknown mutex handle %p", __func__, handle);
280 mono_w32handle_lock (handle_data);
282 if (owned)
283 mutex_handle_own (handle_data, &abandoned);
284 else
285 mono_w32handle_set_signal_state (handle_data, TRUE, FALSE);
287 mono_w32handle_unlock (handle_data);
289 /* Balance mono_w32handle_lookup_and_ref */
290 mono_w32handle_unref (handle_data);
292 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: created %s handle %p",
293 __func__, mono_w32handle_get_typename (type), handle);
295 return handle;
298 static gpointer mutex_create (gboolean owned)
300 MonoW32HandleMutex mutex_handle;
301 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: creating %s handle",
302 __func__, mono_w32handle_get_typename (MONO_W32TYPE_MUTEX));
303 return mutex_handle_create (&mutex_handle, MONO_W32TYPE_MUTEX, owned);
306 static gpointer
307 namedmutex_create (gboolean owned, const char *utf8_name, gsize utf8_len)
309 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: creating %s handle",
310 __func__, mono_w32handle_get_typename (MONO_W32TYPE_NAMEDMUTEX));
312 // Opening named objects does not race.
313 mono_w32handle_namespace_lock ();
315 gpointer handle = mono_w32handle_namespace_search_handle (MONO_W32TYPE_NAMEDMUTEX, utf8_name);
317 if (handle == INVALID_HANDLE_VALUE) {
318 /* The name has already been used for a different object. */
319 handle = NULL;
320 mono_w32error_set_last (ERROR_INVALID_HANDLE);
321 } else if (handle) {
322 /* Not an error, but this is how the caller is informed that the mutex wasn't freshly created */
323 mono_w32error_set_last (ERROR_ALREADY_EXISTS);
325 /* mono_w32handle_namespace_search_handle already adds a ref to the handle */
326 } else {
327 /* A new named mutex */
328 MonoW32HandleNamedMutex namedmutex_handle;
330 // FIXME Silent truncation.
332 size_t len = utf8_len < MAX_PATH ? utf8_len : MAX_PATH;
333 memcpy (&namedmutex_handle.sharedns.name [0], utf8_name, len);
334 namedmutex_handle.sharedns.name [len] = '\0';
336 handle = mutex_handle_create ((MonoW32HandleMutex*) &namedmutex_handle, MONO_W32TYPE_NAMEDMUTEX, owned);
339 mono_w32handle_namespace_unlock ();
341 return handle;
344 gpointer
345 ves_icall_System_Threading_Mutex_CreateMutex_icall (MonoBoolean owned, const gunichar2 *name,
346 gint32 name_length, MonoBoolean *created, MonoError *error)
348 gpointer mutex;
350 *created = TRUE;
352 /* Need to blow away any old errors here, because code tests
353 * for ERROR_ALREADY_EXISTS on success (!) to see if a mutex
354 * was freshly created */
355 mono_w32error_set_last (ERROR_SUCCESS);
357 if (!name) {
358 mutex = mutex_create (owned);
359 } else {
360 gsize utf8_name_length = 0;
361 char *utf8_name = mono_utf16_to_utf8len (name, name_length, &utf8_name_length, error);
362 return_val_if_nok (error, NULL);
364 mutex = namedmutex_create (owned, utf8_name, utf8_name_length);
366 if (mono_w32error_get_last () == ERROR_ALREADY_EXISTS)
367 *created = FALSE;
368 g_free (utf8_name);
371 return mutex;
374 MonoBoolean
375 ves_icall_System_Threading_Mutex_ReleaseMutex_internal (gpointer handle)
377 MonoW32Handle *handle_data;
378 MonoW32HandleMutex *mutex_handle;
379 pthread_t tid;
380 gboolean ret;
382 if (!mono_w32handle_lookup_and_ref (handle, &handle_data)) {
383 g_warning ("%s: unkown handle %p", __func__, handle);
384 mono_w32error_set_last (ERROR_INVALID_HANDLE);
385 return FALSE;
388 if (handle_data->type != MONO_W32TYPE_MUTEX && handle_data->type != MONO_W32TYPE_NAMEDMUTEX) {
389 g_warning ("%s: unknown mutex handle %p", __func__, handle);
390 mono_w32error_set_last (ERROR_INVALID_HANDLE);
391 mono_w32handle_unref (handle_data);
392 return FALSE;
395 mutex_handle = (MonoW32HandleMutex*) handle_data->specific;
397 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: releasing %s handle %p, tid: %p recursion: %d",
398 __func__, mono_w32handle_get_typename (handle_data->type), handle, (gpointer) mutex_handle->tid, mutex_handle->recursion);
400 mono_w32handle_lock (handle_data);
402 tid = pthread_self ();
404 if (mutex_handle->abandoned) {
405 // The Win32 ReleaseMutex() function returns TRUE for abandoned mutexes
406 ret = TRUE;
407 } else if (!pthread_equal (mutex_handle->tid, tid)) {
408 ret = FALSE;
410 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: we don't own %s handle %p (owned by %ld, me %ld)",
411 __func__, mono_w32handle_get_typename (handle_data->type), handle, (long)mutex_handle->tid, (long)tid);
412 } else {
413 ret = TRUE;
415 /* OK, we own this mutex */
416 mutex_handle->recursion--;
418 if (mutex_handle->recursion == 0) {
419 thread_disown_mutex (mono_thread_internal_current_handle (), handle);
421 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: unlocking %s handle %p, tid: %p recusion : %d",
422 __func__, mono_w32handle_get_typename (handle_data->type), handle, (gpointer) mutex_handle->tid, mutex_handle->recursion);
424 mutex_handle->tid = 0;
425 mono_w32handle_set_signal_state (handle_data, TRUE, FALSE);
429 mono_w32handle_unlock (handle_data);
430 mono_w32handle_unref (handle_data);
432 return ret;
435 gpointer
436 ves_icall_System_Threading_Mutex_OpenMutex_icall (const gunichar2 *name, gint32 name_length, gint32 rights G_GNUC_UNUSED, gint32 *win32error, MonoError *error)
438 *win32error = ERROR_SUCCESS;
439 char *utf8_name = mono_utf16_to_utf8 (name, name_length, error);
440 return_val_if_nok (error, NULL);
441 gpointer handle = mono_w32mutex_open (utf8_name, rights, win32error);
442 g_free (utf8_name);
443 return handle;
446 gpointer
447 mono_w32mutex_open (const char* utf8_name, gint32 rights G_GNUC_UNUSED, gint32 *win32error)
449 *win32error = ERROR_SUCCESS;
451 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: Opening named mutex [%s]",
452 __func__, utf8_name);
454 // Opening named objects does not race.
455 mono_w32handle_namespace_lock ();
457 gpointer handle = mono_w32handle_namespace_search_handle (MONO_W32TYPE_NAMEDMUTEX, utf8_name);
459 mono_w32handle_namespace_unlock ();
461 if (handle == INVALID_HANDLE_VALUE) {
462 /* The name has already been used for a different object. */
463 *win32error = ERROR_INVALID_HANDLE;
464 return handle;
465 } else if (!handle) {
466 /* This name doesn't exist */
467 *win32error = ERROR_FILE_NOT_FOUND;
468 return handle;
471 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: returning named mutex handle %p",
472 __func__, handle);
474 return handle;
477 void
478 mono_w32mutex_abandon (MonoInternalThread *internal_raw)
480 HANDLE_FUNCTION_ENTER ()
482 MONO_HANDLE_DCL (MonoInternalThread, internal);
484 g_assert (mono_thread_internal_is_current_handle (internal));
486 if (!MONO_HANDLE_GETVAL (internal, owned_mutexes))
487 goto exit;
489 while (MONO_HANDLE_GETVAL (internal, owned_mutexes)->len) {
490 MonoW32Handle *handle_data;
491 MonoW32HandleMutex *mutex_handle;
492 MonoNativeThreadId tid;
493 gpointer handle;
495 handle = g_ptr_array_index (MONO_HANDLE_GETVAL (internal, owned_mutexes), 0);
497 if (!mono_w32handle_lookup_and_ref (handle, &handle_data))
498 g_error ("%s: unkown handle %p", __func__, handle);
500 if (handle_data->type != MONO_W32TYPE_MUTEX && handle_data->type != MONO_W32TYPE_NAMEDMUTEX)
501 g_error ("%s: unkown mutex handle %p", __func__, handle);
503 mutex_handle = (MonoW32HandleMutex*) handle_data->specific;
505 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: abandoning %s handle %p",
506 __func__, mono_w32handle_get_typename (handle_data->type), handle);
508 tid = MONO_UINT_TO_NATIVE_THREAD_ID (MONO_HANDLE_GETVAL (internal, tid));
510 if (!pthread_equal (mutex_handle->tid, tid))
511 g_error ("%s: trying to release mutex %p acquired by thread %p from thread %p",
512 __func__, handle, (gpointer) mutex_handle->tid, (gpointer) tid);
514 mono_w32handle_lock (handle_data);
516 mutex_handle->recursion = 0;
517 mutex_handle->tid = 0;
518 mutex_handle->abandoned = TRUE;
520 mono_w32handle_set_signal_state (handle_data, TRUE, FALSE);
522 thread_disown_mutex (internal, handle);
524 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: abandoned %s handle %p",
525 __func__, mono_w32handle_get_typename (handle_data->type), handle);
527 mono_w32handle_unlock (handle_data);
528 mono_w32handle_unref (handle_data);
531 g_ptr_array_free (MONO_HANDLE_GETVAL (internal, owned_mutexes), TRUE);
532 MONO_HANDLE_SETVAL(internal, owned_mutexes, GPtrArray*, NULL);
534 exit:
535 HANDLE_FUNCTION_RETURN ();
538 MonoW32HandleNamespace*
539 mono_w32mutex_get_namespace (MonoW32HandleNamedMutex *mutex)
541 return &mutex->sharedns;