Merge pull request #5714 from alexischr/update_bockbuild
[mono.git] / mono / metadata / w32mutex-unix.c
index 37e8e5c462d19ef2c0d5297f7ba593adce3562d7..ab2ef003ddf9db938f2479bb5612d9657666b993 100644 (file)
@@ -1,5 +1,6 @@
-/*
- * w32mutex-unix.c: Runtime support for managed Mutex on Unix
+/**
+ * \file
+ * Runtime support for managed Mutex on Unix
  *
  * Author:
  *     Ludovic Henry (luhenry@microsoft.com)
 
 #include <pthread.h>
 
+#include "w32error.h"
 #include "w32handle-namespace.h"
-#include "mono/io-layer/io-layer.h"
 #include "mono/metadata/object-internals.h"
 #include "mono/utils/mono-logger-internals.h"
 #include "mono/utils/mono-threads.h"
 #include "mono/metadata/w32handle.h"
 
+#define MAX_PATH 260
+
 typedef struct {
        MonoNativeThreadId tid;
        guint32 recursion;
@@ -29,11 +32,12 @@ struct MonoW32HandleNamedMutex {
        MonoW32HandleNamespace sharedns;
 };
 
+gpointer
+mono_w32mutex_open (const gchar* utf8_name, gint32 right G_GNUC_UNUSED, gint32 *error);
+
 static void
 thread_own_mutex (MonoInternalThread *internal, gpointer handle)
 {
-       mono_w32handle_ref (handle);
-
        /* if we are not on the current thread, there is a
         * race condition when allocating internal->owned_mutexes */
        g_assert (mono_thread_internal_is_current (internal));
@@ -41,7 +45,7 @@ thread_own_mutex (MonoInternalThread *internal, gpointer handle)
        if (!internal->owned_mutexes)
                internal->owned_mutexes = g_ptr_array_new ();
 
-       g_ptr_array_add (internal->owned_mutexes, handle);
+       g_ptr_array_add (internal->owned_mutexes, mono_w32handle_duplicate (handle));
 }
 
 static void
@@ -55,23 +59,55 @@ thread_disown_mutex (MonoInternalThread *internal, gpointer handle)
        removed = g_ptr_array_remove (internal->owned_mutexes, handle);
        g_assert (removed);
 
-       mono_w32handle_unref (handle);
+       mono_w32handle_close (handle);
+}
+
+static void
+mutex_handle_signal (gpointer handle, MonoW32HandleType type, MonoW32HandleMutex *mutex_handle)
+{
+       pthread_t tid;
+
+       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: signalling %s handle %p, tid: %p recursion: %d",
+               __func__, mono_w32handle_get_typename (type), handle, (gpointer) mutex_handle->tid, mutex_handle->recursion);
+
+       tid = pthread_self ();
+
+       if (mutex_handle->abandoned) {
+               mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: %s handle %p is abandoned",
+                       __func__, mono_w32handle_get_typename (type), handle);
+       } else if (!pthread_equal (mutex_handle->tid, tid)) {
+               mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: we don't own %s handle %p (owned by %ld, me %ld)",
+                       __func__, mono_w32handle_get_typename (type), handle, (long)mutex_handle->tid, (long)tid);
+       } else {
+               /* OK, we own this mutex */
+               mutex_handle->recursion--;
+
+               if (mutex_handle->recursion == 0) {
+                       thread_disown_mutex (mono_thread_internal_current (), handle);
+
+                       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unlocking %s handle %p, tid: %p recusion : %d",
+                               __func__, mono_w32handle_get_typename (type), handle, (gpointer) mutex_handle->tid, mutex_handle->recursion);
+
+                       mutex_handle->tid = 0;
+                       mono_w32handle_set_signal_state (handle, TRUE, FALSE);
+               }
+       }
 }
 
 static gboolean
-mutex_handle_own (gpointer handle, MonoW32HandleType type, guint32 *statuscode)
+mutex_handle_own (gpointer handle, MonoW32HandleType type, gboolean *abandoned)
 {
        MonoW32HandleMutex *mutex_handle;
 
-       *statuscode = WAIT_OBJECT_0;
+       *abandoned = FALSE;
 
        if (!mono_w32handle_lookup (handle, type, (gpointer *)&mutex_handle)) {
-               g_warning ("%s: error looking up %s handle %p", __func__, mono_w32handle_ops_typename (type), handle);
+               g_warning ("%s: error looking up %s handle %p", __func__, mono_w32handle_get_typename (type), handle);
                return FALSE;
        }
 
        mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: owning %s handle %p, before: [tid: %p, recursion: %d], after: [tid: %p, recursion: %d], abandoned: %s",
-               __func__, mono_w32handle_ops_typename (type), handle, (gpointer) mutex_handle->tid, mutex_handle->recursion, (gpointer) pthread_self (), mutex_handle->recursion + 1, mutex_handle->abandoned ? "true" : "false");
+               __func__, mono_w32handle_get_typename (type), handle, (gpointer) mutex_handle->tid, mutex_handle->recursion, (gpointer) pthread_self (), mutex_handle->recursion + 1, mutex_handle->abandoned ? "true" : "false");
 
        if (mutex_handle->recursion != 0) {
                g_assert (pthread_equal (pthread_self (), mutex_handle->tid));
@@ -85,7 +121,7 @@ mutex_handle_own (gpointer handle, MonoW32HandleType type, guint32 *statuscode)
 
        if (mutex_handle->abandoned) {
                mutex_handle->abandoned = FALSE;
-               *statuscode = WAIT_ABANDONED_0;
+               *abandoned = TRUE;
        }
 
        mono_w32handle_set_signal_state (handle, FALSE, FALSE);
@@ -99,49 +135,48 @@ mutex_handle_is_owned (gpointer handle, MonoW32HandleType type)
        MonoW32HandleMutex *mutex_handle;
 
        if (!mono_w32handle_lookup (handle, type, (gpointer *)&mutex_handle)) {
-               g_warning ("%s: error looking up %s handle %p", __func__, mono_w32handle_ops_typename (type), handle);
+               g_warning ("%s: error looking up %s handle %p", __func__, mono_w32handle_get_typename (type), handle);
                return FALSE;
        }
 
        mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: testing ownership %s handle %p",
-               __func__, mono_w32handle_ops_typename (type), handle);
+               __func__, mono_w32handle_get_typename (type), handle);
 
        if (mutex_handle->recursion > 0 && pthread_equal (mutex_handle->tid, pthread_self ())) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: %s handle %p owned by %p",
-                       __func__, mono_w32handle_ops_typename (type), handle, (gpointer) pthread_self ());
+                       __func__, mono_w32handle_get_typename (type), handle, (gpointer) pthread_self ());
                return TRUE;
        } else {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: %s handle %p not owned by %p, tid: %p recursion: %d",
-                       __func__, mono_w32handle_ops_typename (type), handle, (gpointer) pthread_self (), (gpointer) mutex_handle->tid, mutex_handle->recursion);
+                       __func__, mono_w32handle_get_typename (type), handle, (gpointer) pthread_self (), (gpointer) mutex_handle->tid, mutex_handle->recursion);
                return FALSE;
        }
 }
 
-static void mutex_signal(gpointer handle)
+static void mutex_signal(gpointer handle, gpointer handle_specific)
 {
-       ves_icall_System_Threading_Mutex_ReleaseMutex_internal (handle);
+       mutex_handle_signal (handle, MONO_W32HANDLE_MUTEX, (MonoW32HandleMutex*) handle_specific);
 }
 
-static gboolean mutex_own (gpointer handle, guint32 *statuscode)
+static gboolean mutex_own (gpointer handle, gboolean *abandoned)
 {
-       return mutex_handle_own (handle, MONO_W32HANDLE_MUTEX, statuscode);
+       return mutex_handle_own (handle, MONO_W32HANDLE_MUTEX, abandoned);
 }
 
 static gboolean mutex_is_owned (gpointer handle)
 {
-       
        return mutex_handle_is_owned (handle, MONO_W32HANDLE_MUTEX);
 }
 
-static void namedmutex_signal (gpointer handle)
+static void namedmutex_signal (gpointer handle, gpointer handle_specific)
 {
-       ves_icall_System_Threading_Mutex_ReleaseMutex_internal (handle);
+       mutex_handle_signal (handle, MONO_W32HANDLE_NAMEDMUTEX, (MonoW32HandleMutex*) handle_specific);
 }
 
 /* NB, always called with the shared handle lock held */
-static gboolean namedmutex_own (gpointer handle, guint32 *statuscode)
+static gboolean namedmutex_own (gpointer handle, gboolean *abandoned)
 {
-       return mutex_handle_own (handle, MONO_W32HANDLE_NAMEDMUTEX, statuscode);
+       return mutex_handle_own (handle, MONO_W32HANDLE_NAMEDMUTEX, abandoned);
 }
 
 static gboolean namedmutex_is_owned (gpointer handle)
@@ -161,12 +196,12 @@ static void mutex_handle_prewait (gpointer handle, MonoW32HandleType type)
 
        if (!mono_w32handle_lookup (handle, type, (gpointer *)&mutex_handle)) {
                g_warning ("%s: error looking up %s handle %p",
-                       __func__, mono_w32handle_ops_typename (type), handle);
+                       __func__, mono_w32handle_get_typename (type), handle);
                return;
        }
 
        mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: pre-waiting %s handle %p, owned? %s",
-               __func__, mono_w32handle_ops_typename (type), handle, mutex_handle->recursion != 0 ? "true" : "false");
+               __func__, mono_w32handle_get_typename (type), handle, mutex_handle->recursion != 0 ? "true" : "false");
 }
 
 /* The shared state is not locked when prewait methods are called */
@@ -264,8 +299,7 @@ mono_w32mutex_init (void)
 static gpointer mutex_handle_create (MonoW32HandleMutex *mutex_handle, MonoW32HandleType type, gboolean owned)
 {
        gpointer handle;
-       int thr_ret;
-       guint32 statuscode;
+       gboolean abandoned;
 
        mutex_handle->tid = 0;
        mutex_handle->recursion = 0;
@@ -274,24 +308,22 @@ static gpointer mutex_handle_create (MonoW32HandleMutex *mutex_handle, MonoW32Ha
        handle = mono_w32handle_new (type, mutex_handle);
        if (handle == INVALID_HANDLE_VALUE) {
                g_warning ("%s: error creating %s handle",
-                       __func__, mono_w32handle_ops_typename (type));
-               SetLastError (ERROR_GEN_FAILURE);
+                       __func__, mono_w32handle_get_typename (type));
+               mono_w32error_set_last (ERROR_GEN_FAILURE);
                return NULL;
        }
 
-       thr_ret = mono_w32handle_lock_handle (handle);
-       g_assert (thr_ret == 0);
+       mono_w32handle_lock_handle (handle);
 
        if (owned)
-               mutex_handle_own (handle, type, &statuscode);
+               mutex_handle_own (handle, type, &abandoned);
        else
                mono_w32handle_set_signal_state (handle, TRUE, FALSE);
 
-       thr_ret = mono_w32handle_unlock_handle (handle);
-       g_assert (thr_ret == 0);
+       mono_w32handle_unlock_handle (handle);
 
        mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: created %s handle %p",
-               __func__, mono_w32handle_ops_typename (type), handle);
+               __func__, mono_w32handle_get_typename (type), handle);
 
        return handle;
 }
@@ -300,69 +332,72 @@ static gpointer mutex_create (gboolean owned)
 {
        MonoW32HandleMutex mutex_handle;
        mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: creating %s handle",
-               __func__, mono_w32handle_ops_typename (MONO_W32HANDLE_MUTEX));
+               __func__, mono_w32handle_get_typename (MONO_W32HANDLE_MUTEX));
        return mutex_handle_create (&mutex_handle, MONO_W32HANDLE_MUTEX, owned);
 }
 
-static gpointer namedmutex_create (gboolean owned, const gunichar2 *name)
+static gpointer namedmutex_create (gboolean owned, const gchar *utf8_name)
 {
        gpointer handle;
-       gchar *utf8_name;
 
        mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: creating %s handle",
-               __func__, mono_w32handle_ops_typename (MONO_W32HANDLE_NAMEDMUTEX));
+               __func__, mono_w32handle_get_typename (MONO_W32HANDLE_NAMEDMUTEX));
 
        /* w32 seems to guarantee that opening named objects can't race each other */
        mono_w32handle_namespace_lock ();
 
-       utf8_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
+       glong utf8_len = strlen (utf8_name);
 
        handle = mono_w32handle_namespace_search_handle (MONO_W32HANDLE_NAMEDMUTEX, utf8_name);
        if (handle == INVALID_HANDLE_VALUE) {
                /* The name has already been used for a different object. */
                handle = NULL;
-               SetLastError (ERROR_INVALID_HANDLE);
+               mono_w32error_set_last (ERROR_INVALID_HANDLE);
        } else if (handle) {
                /* Not an error, but this is how the caller is informed that the mutex wasn't freshly created */
-               SetLastError (ERROR_ALREADY_EXISTS);
+               mono_w32error_set_last (ERROR_ALREADY_EXISTS);
 
                /* mono_w32handle_namespace_search_handle already adds a ref to the handle */
        } else {
                /* A new named mutex */
                MonoW32HandleNamedMutex namedmutex_handle;
 
-               strncpy (&namedmutex_handle.sharedns.name [0], utf8_name, MAX_PATH);
-               namedmutex_handle.sharedns.name [MAX_PATH] = '\0';
+               size_t len = utf8_len < MAX_PATH ? utf8_len : MAX_PATH;
+               memcpy (&namedmutex_handle.sharedns.name [0], utf8_name, len);
+               namedmutex_handle.sharedns.name [len] = '\0';
 
                handle = mutex_handle_create ((MonoW32HandleMutex*) &namedmutex_handle, MONO_W32HANDLE_NAMEDMUTEX, owned);
        }
 
-       g_free (utf8_name);
-
        mono_w32handle_namespace_unlock ();
 
        return handle;
 }
 
 gpointer
-ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned, MonoString *name, MonoBoolean *created)
+ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned, MonoStringHandle name, MonoBoolean *created, MonoError *error)
 {
        gpointer mutex;
 
+       error_init (error);
        *created = TRUE;
 
        /* Need to blow away any old errors here, because code tests
         * for ERROR_ALREADY_EXISTS on success (!) to see if a mutex
         * was freshly created */
-       SetLastError (ERROR_SUCCESS);
+       mono_w32error_set_last (ERROR_SUCCESS);
 
-       if (!name) {
+       if (MONO_HANDLE_IS_NULL (name)) {
                mutex = mutex_create (owned);
        } else {
-               mutex = namedmutex_create (owned, mono_string_chars (name));
+               gchar *utf8_name = mono_string_handle_to_utf8 (name, error);
+               return_val_if_nok (error, NULL);
 
-               if (GetLastError () == ERROR_ALREADY_EXISTS)
+               mutex = namedmutex_create (owned, utf8_name);
+
+               if (mono_w32error_get_last () == ERROR_ALREADY_EXISTS)
                        *created = FALSE;
+               g_free (utf8_name);
        }
 
        return mutex;
@@ -374,11 +409,10 @@ ves_icall_System_Threading_Mutex_ReleaseMutex_internal (gpointer handle)
        MonoW32HandleType type;
        MonoW32HandleMutex *mutex_handle;
        pthread_t tid;
-       int thr_ret;
        gboolean ret;
 
        if (handle == NULL) {
-               SetLastError (ERROR_INVALID_HANDLE);
+               mono_w32error_set_last (ERROR_INVALID_HANDLE);
                return FALSE;
        }
 
@@ -387,21 +421,20 @@ ves_icall_System_Threading_Mutex_ReleaseMutex_internal (gpointer handle)
        case MONO_W32HANDLE_NAMEDMUTEX:
                break;
        default:
-               SetLastError (ERROR_INVALID_HANDLE);
+               mono_w32error_set_last (ERROR_INVALID_HANDLE);
                return FALSE;
        }
 
        if (!mono_w32handle_lookup (handle, type, (gpointer *)&mutex_handle)) {
                g_warning ("%s: error looking up %s handle %p",
-                       __func__, mono_w32handle_ops_typename (type), handle);
+                       __func__, mono_w32handle_get_typename (type), handle);
                return FALSE;
        }
 
        mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: releasing %s handle %p, tid: %p recursion: %d",
-               __func__, mono_w32handle_ops_typename (type), handle, (gpointer) mutex_handle->tid, mutex_handle->recursion);
+               __func__, mono_w32handle_get_typename (type), handle, (gpointer) mutex_handle->tid, mutex_handle->recursion);
 
-       thr_ret = mono_w32handle_lock_handle (handle);
-       g_assert (thr_ret == 0);
+       mono_w32handle_lock_handle (handle);
 
        tid = pthread_self ();
 
@@ -412,7 +445,7 @@ ves_icall_System_Threading_Mutex_ReleaseMutex_internal (gpointer handle)
                ret = FALSE;
 
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: we don't own %s handle %p (owned by %ld, me %ld)",
-                           __func__, mono_w32handle_ops_typename (type), handle, (long)mutex_handle->tid, (long)tid);
+                           __func__, mono_w32handle_get_typename (type), handle, (long)mutex_handle->tid, (long)tid);
        } else {
                ret = TRUE;
 
@@ -423,32 +456,39 @@ ves_icall_System_Threading_Mutex_ReleaseMutex_internal (gpointer handle)
                        thread_disown_mutex (mono_thread_internal_current (), handle);
 
                        mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unlocking %s handle %p, tid: %p recusion : %d",
-                               __func__, mono_w32handle_ops_typename (type), handle, (gpointer) mutex_handle->tid, mutex_handle->recursion);
+                               __func__, mono_w32handle_get_typename (type), handle, (gpointer) mutex_handle->tid, mutex_handle->recursion);
 
                        mutex_handle->tid = 0;
                        mono_w32handle_set_signal_state (handle, TRUE, FALSE);
                }
        }
 
-       thr_ret = mono_w32handle_unlock_handle (handle);
-       g_assert (thr_ret == 0);
+       mono_w32handle_unlock_handle (handle);
 
        return ret;
 }
 
 gpointer
-ves_icall_System_Threading_Mutex_OpenMutex_internal (MonoString *name, gint32 rights G_GNUC_UNUSED, gint32 *error)
+ves_icall_System_Threading_Mutex_OpenMutex_internal (MonoStringHandle name, gint32 rights G_GNUC_UNUSED, gint32 *err, MonoError *error)
+{
+       error_init (error);
+       gchar *utf8_name = mono_string_handle_to_utf8 (name, error);
+       return_val_if_nok (error, NULL);
+       gpointer handle = mono_w32mutex_open (utf8_name, rights, err);
+       g_free (utf8_name);
+       return handle;
+}
+
+gpointer
+mono_w32mutex_open (const gchar* utf8_name, gint32 right G_GNUC_UNUSED, gint32 *error)
 {
        gpointer handle;
-       gchar *utf8_name;
 
        *error = ERROR_SUCCESS;
 
        /* w32 seems to guarantee that opening named objects can't race each other */
        mono_w32handle_namespace_lock ();
 
-       utf8_name = g_utf16_to_utf8 (mono_string_chars (name), -1, NULL, NULL, NULL);
-
        mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Opening named mutex [%s]",
                __func__, utf8_name);
 
@@ -467,8 +507,6 @@ ves_icall_System_Threading_Mutex_OpenMutex_internal (MonoString *name, gint32 ri
                __func__, handle);
 
 cleanup:
-       g_free (utf8_name);
-
        mono_w32handle_namespace_unlock ();
 
        return handle;
@@ -492,7 +530,6 @@ mono_w32mutex_abandon (void)
                MonoW32HandleMutex *mutex_handle;
                MonoNativeThreadId tid;
                gpointer handle;
-               int thr_ret;
 
                handle = g_ptr_array_index (internal->owned_mutexes, 0);
 
@@ -506,11 +543,11 @@ mono_w32mutex_abandon (void)
 
                if (!mono_w32handle_lookup (handle, type, (gpointer *)&mutex_handle)) {
                        g_error ("%s: error looking up %s handle %p",
-                               __func__, mono_w32handle_ops_typename (type), handle);
+                               __func__, mono_w32handle_get_typename (type), handle);
                }
 
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: abandoning %s handle %p",
-                       __func__, mono_w32handle_ops_typename (type), handle);
+                       __func__, mono_w32handle_get_typename (type), handle);
 
                tid = MONO_UINT_TO_NATIVE_THREAD_ID (internal->tid);
 
@@ -518,8 +555,7 @@ mono_w32mutex_abandon (void)
                        g_error ("%s: trying to release mutex %p acquired by thread %p from thread %p",
                                __func__, handle, (gpointer) mutex_handle->tid, (gpointer) tid);
 
-               thr_ret = mono_w32handle_lock_handle (handle);
-               g_assert (thr_ret == 0);
+               mono_w32handle_lock_handle (handle);
 
                mutex_handle->recursion = 0;
                mutex_handle->tid = 0;
@@ -530,10 +566,9 @@ mono_w32mutex_abandon (void)
                thread_disown_mutex (internal, handle);
 
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: abandoned %s handle %p",
-                       __func__, mono_w32handle_ops_typename (type), handle);
+                       __func__, mono_w32handle_get_typename (type), handle);
 
-               thr_ret = mono_w32handle_unlock_handle (handle);
-               g_assert (thr_ret == 0);
+               mono_w32handle_unlock_handle (handle);
        }
 
        g_ptr_array_free (internal->owned_mutexes, TRUE);