Merge pull request #5567 from kumpera/fix_59334
authorRodrigo Kumpera <kumpera@users.noreply.github.com>
Thu, 28 Sep 2017 20:50:07 +0000 (16:50 -0400)
committerGitHub <noreply@github.com>
Thu, 28 Sep 2017 20:50:07 +0000 (16:50 -0400)
[runtime] Handle RuntimeWrappedException and dynamic methods. Fixes #59334

41 files changed:
mcs/class/Mono.Posix/Mono.Unix/UnixMarshal.cs
mcs/class/Mono.Posix/Test/Mono.Unix/UnixMarshalTest.cs
mcs/class/corlib/Test/System.IO/FileTest.cs
mcs/class/corlib/Test/System/TypeTest.cs
mcs/tools/mkbundle/mkbundle.cs
mono/metadata/class.c
mono/metadata/class.h
mono/metadata/gc.c
mono/metadata/monitor.c
mono/metadata/object-offsets.h
mono/metadata/sgen-mono.c
mono/metadata/threadpool.c
mono/metadata/threads-types.h
mono/metadata/threads.c
mono/metadata/w32handle.c
mono/metadata/w32process-unix.c
mono/metadata/w32socket-win32.c
mono/mini/aot-compiler.c
mono/mini/cpu-arm64.md
mono/mini/method-to-ir.c
mono/mini/mini-amd64.c
mono/mini/mini-amd64.h
mono/mini/mini-arm.c
mono/mini/mini-arm64.c
mono/mini/mini-arm64.h
mono/mini/mini-runtime.c
mono/mini/mini.h
mono/profiler/log.c
mono/tests/Makefile.am
mono/tests/bug-59281.cs [new file with mode: 0644]
mono/tests/runtime-invoke.cs
mono/utils/Makefile.am
mono/utils/mono-os-semaphore.h
mono/utils/mono-os-wait-win32.c [new file with mode: 0644]
mono/utils/mono-os-wait.h [new file with mode: 0644]
mono/utils/mono-threads-windows.c
mono/utils/mono-threads.h
mono/utils/os-event-win32.c
mono/utils/unlocked.h
msvc/libmonoutils.vcxproj
msvc/libmonoutils.vcxproj.filters

index 0b01eb19ad40fc1592cd78c2ed3aa74f6a1c6a7e..7d39fd4c43ffad92bcf2f284a542482b63f0c4eb 100644 (file)
@@ -309,6 +309,9 @@ namespace Mono.Unix {
 
                public static IntPtr StringToHeap (string s, Encoding encoding)
                {
+                       if (s == null)
+                               return IntPtr.Zero;
+
                        return StringToHeap (s, 0, s.Length, encoding);
                }
 
index 8ae50b98c977fa9af5531e7dbae9227c8d8586cd..9b0ce35d9614123b25bf97468dbdb3a68be03bfd 100644 (file)
@@ -40,6 +40,13 @@ namespace MonoTests.Mono.Unix {
                }
 #endif
 
+               [Test]
+               public void BXC10074 ()
+               {
+                       var result = UnixMarshal.StringToHeap (null, Encoding.ASCII);
+                       Assert.AreEqual (IntPtr.Zero, result, "This used to crash due to a NullReferenceException");
+               }
+
                [Test]
                public void TestStringToHeap ()
                {
index 4528027b24e9bc730bcb914ef0f2573189f1cc90..7e01ce544d7240a073f1ca6fbc32d2cf3cb54c71 100644 (file)
@@ -2709,8 +2709,10 @@ namespace MonoTests.System.IO
                        File.Delete (path2);
 
                        try {
-                               symlink (path1, path2);
-                               symlink (path2, path1);
+                               if (symlink (path1, path2) != 0)
+                                       Assert.Fail ("symlink #1 failed with errno={0}", Marshal.GetLastWin32Error ());
+                               if (symlink (path2, path1) != 0)
+                                       Assert.Fail ("symlink #2 failed with errno={0}", Marshal.GetLastWin32Error ());
 
                                Assert.IsTrue (File.Exists (path1), "File.Exists must return true for path1 symlink loop");
                                Assert.IsTrue (File.Exists (path2), "File.Exists must return true for path2 symlink loop");
index d03e4c21f2af694ee1ea2bf45fa97fad43341c19..72c2cb41923870747b317d5a06907fe1da14446c 100644 (file)
@@ -296,6 +296,14 @@ namespace MonoTests.System
                {
                }
 
+               private void GenericMethod2<A, B, C, D> ()
+                       where C : Duper
+                       where A : B, IFace
+                       where B : C
+                       where D : Baz<object>
+               {
+               }
+
                public class Nested
                {
 
@@ -369,6 +377,54 @@ namespace MonoTests.System
                        // Tests for parameters with generic constraints
                        mi = typeof (TypeTest).GetMethod ("GenericMethod", BindingFlags.Instance|BindingFlags.NonPublic);
                        Assert.IsTrue (typeof (IFace).IsAssignableFrom (mi.GetParameters ()[1].ParameterType));
+
+                       // Transitivity of IsAssignableFrom for type parameters
+                       mi = typeof (TypeTest).GetMethod ("GenericMethod2", BindingFlags.Instance|BindingFlags.NonPublic);
+                       var gparams = mi.GetGenericArguments ();
+                       // B : Duper since B : C and C : Duper
+                       Assert.IsTrue (typeof (Duper).IsAssignableFrom (gparams[1]), "#36");
+                       // A : Duper since A : B and B : Duper
+                       Assert.IsTrue (typeof (Duper).IsAssignableFrom (gparams[0]), "#37a");
+                       // A : IFace since A : IFace
+                       Assert.IsTrue (typeof (IFace).IsAssignableFrom (gparams[0]), "#37b");
+                       // B : Super since B : Duper and Duper : Super
+                       Assert.IsTrue (typeof (Super).IsAssignableFrom (gparams[1]), "#38");
+                       // A : Super since A : B and B : Super
+                       Assert.IsTrue (typeof (Super).IsAssignableFrom (gparams[0]), "#39");
+                       // D : IBar<object> since D : Baz<object> and Baz<object> : IBar<object>
+                       Assert.IsTrue (typeof (IBar<object>).IsAssignableFrom (gparams [3]), "#40");
+                       // A not assignable from B since A : B
+                       Assert.IsFalse (gparams[0].IsAssignableFrom (gparams [1]), "#41");
+                       Assert.IsFalse (gparams[0].IsAssignableFrom (gparams [2]), "#42");
+
+                       // A is not assignable from Array and Delegate and vice versa
+                       Assert.IsFalse (gparams[0].IsAssignableFrom (typeof (Array)), "#43");
+                       Assert.IsFalse (gparams[0].IsAssignableFrom (typeof (Delegate)), "#44");
+                       Assert.IsFalse (typeof (Array).IsAssignableFrom (gparams[0]), "#45");
+                       Assert.IsFalse (typeof (Delegate).IsAssignableFrom (gparams[0]), "#46");
+
+               }
+
+               [Test]
+               public void GenericParameterBaseType ()
+               {
+                       var mi = typeof (TypeTest).GetMethod ("GenericMethod2", BindingFlags.Instance|BindingFlags.NonPublic);
+                       var gparams = mi.GetGenericArguments ();
+
+                       // From the .NET documentation: BaseType property of a
+                       // gparam is "object" if its only constraints are other
+                       // gparams or interfaces, otherwise if it has a class
+                       // constraint that class is the BaseType.
+
+                       // A : B where B is a gparam, and A : IFace which is an
+                       // interface, so A.BaseType is object
+                       Assert.AreEqual (typeof (object), gparams[0].BaseType, "#1");
+                       // B : C where C is a gparam, so B.BaseType is object
+                       Assert.AreEqual (typeof (object), gparams[1].BaseType, "#2");
+                       // C : Duper where Duper is a class, so A.BaseType is Duper
+                       Assert.AreEqual (typeof (Duper), gparams[2].BaseType, "#3");
+                       // D : Baz<object>
+                       Assert.AreEqual (typeof (Baz<object>), gparams[3].BaseType, "#4");
                }
 
                [Test]
@@ -3619,6 +3675,38 @@ namespace MonoTests.System
                        public int field;
                }
 
+               [Test]
+               public void IsAssignableFromGenericArgumentsWithConstraints ()
+               {
+                       // Regression test for #58809
+
+                       // Generic Parameters of a gtd should have their
+                       // constraints respected even when those constraints
+                       // are other generic parameters themselves.
+
+                       var ps = typeof (GenericWithParamConstraints<,,>).GetGenericArguments ();
+
+                       var a = ps[0];
+                       var b = ps[1];
+                       var c = ps[2];
+
+                       // Foo<C>
+                       var fooOfC = typeof (Foo<>).MakeGenericType (c);
+
+                       // constraint B : Foo <C>
+                       Assert.IsTrue (fooOfC.IsAssignableFrom (b), "#1");
+
+                       // constraint A : B
+                       Assert.IsTrue (b.IsAssignableFrom (a), "#2");
+
+                       // A : Foo<C> since A : B and B : Foo<C>
+                       Assert.IsTrue (fooOfC.IsAssignableFrom (a), "#3");
+               }
+
+               class GenericWithParamConstraints<A, B, C> where B : Foo<C> where A : B
+               {
+               }
+
                [Test] // Bug #612780
                public void CannotMakeDerivedTypesFromTypedByRef ()
                {
index 8680e0bbf8160f8f502a3705956eb7ebc06b88cb..d4ef1cbb5520e4f8c493fdcce14d61e2b21730f1 100755 (executable)
@@ -1009,6 +1009,7 @@ void          mono_register_config_for_assembly (const char* assembly_name, cons
                        else
                        {
                                string zlib = (compress ? "-lz" : "");
+                               string objc = (style == "osx" ? "-framework CoreFoundation -lobjc" : "");
                                string debugging = "-g";
                                string cc = GetEnv("CC", "cc");
                                string cmd = null;
@@ -1022,16 +1023,16 @@ void          mono_register_config_for_assembly (const char* assembly_name, cons
                                                smonolib = "`pkg-config --variable=libdir mono-2`/libmono-2.0.a ";
                                        else
                                                smonolib = "-Wl,-Bstatic -lmono-2.0 -Wl,-Bdynamic ";
-                                       cmd = String.Format("{4} -o '{2}' -Wall `pkg-config --cflags mono-2` {0} {3} " +
+                                       cmd = String.Format("{4} -o '{2}' -Wall {5} `pkg-config --cflags mono-2` {0} {3} " +
                                                "`pkg-config --libs-only-L mono-2` " + smonolib +
                                                "`pkg-config --libs-only-l mono-2 | sed -e \"s/\\-lmono-2.0 //\"` {1}",
-                                               temp_c, temp_o, output, zlib, cc);
+                                               temp_c, temp_o, output, zlib, cc, objc);
                                }
                                else
                                {
 
-                                       cmd = String.Format("{4} " + debugging + " -o '{2}' -Wall {0} `pkg-config --cflags --libs mono-2` {3} {1}",
-                                               temp_c, temp_o, output, zlib, cc);
+                                       cmd = String.Format("{4} " + debugging + " -o '{2}' -Wall {5} {0} `pkg-config --cflags --libs mono-2` {3} {1}",
+                                               temp_c, temp_o, output, zlib, cc, objc);
                                }
                                Execute (cmd);
                        }
index f00d436281a5d0d1a05075f56870a49d37183875..e1539de106cd4bb92eaa32c27f30e5795facc6cd 100644 (file)
@@ -2926,6 +2926,10 @@ collect_implemented_interfaces_aux (MonoClass *klass, GPtrArray **res, GHashTabl
                        *ifaces = g_hash_table_new (NULL, NULL);
                if (g_hash_table_lookup (*ifaces, ic))
                        continue;
+               /* A gparam is not an implemented interface for the purposes of
+                * mono_class_get_implemented_interfaces */
+               if (mono_class_is_gparam (ic))
+                       continue;
                g_ptr_array_add (*res, ic);
                g_hash_table_insert (*ifaces, ic, ic);
                mono_class_init (ic);
@@ -3316,7 +3320,9 @@ setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite)
                for (i = 0; i < k->interface_count; i++) {
                        ic = k->interfaces [i];
 
-                       mono_class_init (ic);
+                       /* A gparam does not have any interface_id set. */
+                       if (! mono_class_is_gparam (ic))
+                               mono_class_init (ic);
 
                        if (max_iid < ic->interface_id)
                                max_iid = ic->interface_id;
@@ -8220,22 +8226,31 @@ mono_class_is_assignable_from (MonoClass *klass, MonoClass *oklass)
                return mono_gparam_is_assignable_from (klass, oklass);
        }
 
-       if (MONO_CLASS_IS_INTERFACE (klass)) {
-               if ((oklass->byval_arg.type == MONO_TYPE_VAR) || (oklass->byval_arg.type == MONO_TYPE_MVAR)) {
-                       MonoGenericParam *gparam = oklass->byval_arg.data.generic_param;
-                       MonoClass **constraints = mono_generic_container_get_param_info (gparam->owner, gparam->num)->constraints;
-                       int i;
+       /* This can happen if oklass is a tyvar that has a constraint which is another tyvar which in turn
+        * has a constraint which is a class type:
+        *
+        *  class Foo { }
+        *  class G<T1, T2> where T1 : T2 where T2 : Foo { }
+        *
+        * In this case, Foo is assignable from T1.
+        */
+       if ((oklass->byval_arg.type == MONO_TYPE_VAR) || (oklass->byval_arg.type == MONO_TYPE_MVAR)) {
+               MonoGenericParam *gparam = oklass->byval_arg.data.generic_param;
+               MonoClass **constraints = mono_generic_container_get_param_info (gparam->owner, gparam->num)->constraints;
+               int i;
 
-                       if (constraints) {
-                               for (i = 0; constraints [i]; ++i) {
-                                       if (mono_class_is_assignable_from (klass, constraints [i]))
-                                               return TRUE;
-                               }
+               if (constraints) {
+                       for (i = 0; constraints [i]; ++i) {
+                               if (mono_class_is_assignable_from (klass, constraints [i]))
+                                       return TRUE;
                        }
-
-                       return FALSE;
                }
 
+               return mono_class_has_parent (oklass, klass);
+       }
+
+       if (MONO_CLASS_IS_INTERFACE (klass)) {
+
                /* interface_offsets might not be set for dynamic classes */
                if (mono_class_get_ref_info_handle (oklass) && !oklass->interface_bitmap) {
                        /* 
index f79cd9bff99e928cd3b8c9834b69311126c43fcd..565dac59e4f215b0ac4c2dd7a5abf35b10b62195 100644 (file)
@@ -45,6 +45,7 @@ mono_class_from_typeref    (MonoImage *image, uint32_t type_token);
 MONO_API MonoClass *
 mono_class_from_typeref_checked (MonoImage *image, uint32_t type_token, MonoError *error);
 
+MONO_RT_EXTERNAL_ONLY
 MONO_API MonoClass *
 mono_class_from_generic_parameter (MonoGenericParam *param, MonoImage *image, mono_bool is_mvar);
 
index 80605dba2d0d7f4aff7090ebf2e60aefb53704a0..4cda6ddb320b7b922fc56033c80a6b3594322aed 100644 (file)
@@ -45,6 +45,7 @@
 #include <mono/utils/hazard-pointer.h>
 #include <mono/utils/w32api.h>
 #include <mono/utils/unlocked.h>
+#include <mono/utils/mono-os-wait.h>
 
 #ifndef HOST_WIN32
 #include <pthread.h>
@@ -598,7 +599,7 @@ ves_icall_System_GC_WaitForPendingFinalizers (void)
        mono_gc_finalize_notify ();
        /* g_print ("Waiting for pending finalizers....\n"); */
        MONO_ENTER_GC_SAFE;
-       WaitForSingleObjectEx (pending_done_event, INFINITE, TRUE);
+       mono_win32_wait_for_single_object_ex (pending_done_event, INFINITE, TRUE);
        MONO_EXIT_GC_SAFE;
        /* g_print ("Done pending....\n"); */
 #else
@@ -996,7 +997,7 @@ mono_gc_cleanup (void)
                                        ret = guarded_wait (gc_thread->handle, MONO_INFINITE_WAIT, FALSE);
                                        g_assert (ret == MONO_THREAD_INFO_WAIT_RET_SUCCESS_0);
 
-                                       mono_threads_add_joinable_thread (GUINT_TO_POINTER (gc_thread->tid));
+                                       mono_threads_add_joinable_thread ((gpointer)(MONO_UINT_TO_NATIVE_THREAD_ID (gc_thread->tid)));
                                        break;
                                }
 
@@ -1021,7 +1022,7 @@ mono_gc_cleanup (void)
 
                                        g_assert (ret == MONO_THREAD_INFO_WAIT_RET_SUCCESS_0);
 
-                                       mono_threads_add_joinable_thread (GUINT_TO_POINTER (gc_thread->tid));
+                                       mono_threads_add_joinable_thread ((gpointer)(MONO_UINT_TO_NATIVE_THREAD_ID (gc_thread->tid)));
                                        break;
                                }
 
index c371f0f3c476c0e6756c97460e5c37e9cd3e1bc5..d3b51abfc80247f536fdb2410f28edf528411200 100644 (file)
@@ -32,6 +32,7 @@
 #include <mono/utils/mono-time.h>
 #include <mono/utils/atomic.h>
 #include <mono/utils/w32api.h>
+#include <mono/utils/mono-os-wait.h>
 
 /*
  * Pull the list of opcodes
@@ -1387,7 +1388,7 @@ ves_icall_System_Threading_Monitor_Monitor_wait (MonoObject *obj, guint32 ms)
         */
        MONO_ENTER_GC_SAFE;
 #ifdef HOST_WIN32
-       ret = mono_w32handle_convert_wait_ret (WaitForSingleObjectEx (event, ms, TRUE), 1);
+       ret = mono_w32handle_convert_wait_ret (mono_win32_wait_for_single_object_ex (event, ms, TRUE), 1);
 #else
        ret = mono_w32handle_wait_one (event, ms, TRUE);
 #endif /* HOST_WIN32 */
@@ -1416,7 +1417,7 @@ ves_icall_System_Threading_Monitor_Monitor_wait (MonoObject *obj, guint32 ms)
                 */
                MONO_ENTER_GC_SAFE;
 #ifdef HOST_WIN32
-               ret = mono_w32handle_convert_wait_ret (WaitForSingleObjectEx (event, 0, FALSE), 1);
+               ret = mono_w32handle_convert_wait_ret (mono_win32_wait_for_single_object_ex (event, 0, FALSE), 1);
 #else
                ret = mono_w32handle_wait_one (event, 0, FALSE);
 #endif /* HOST_WIN32 */
index 233f9528ed90ca0a34cdf5377989320fe0dc61c7..8968bf737f5b1a9219671cdf4d0473e92777e330 100644 (file)
@@ -232,6 +232,7 @@ DECL_OFFSET(MonoLMF, pc)
 DECL_OFFSET(MonoLMF, gregs)
 DECL_OFFSET(DynCallArgs, regs)
 DECL_OFFSET(DynCallArgs, fpregs)
+DECL_OFFSET(DynCallArgs, n_stackargs)
 DECL_OFFSET(DynCallArgs, n_fpargs)
 DECL_OFFSET(DynCallArgs, n_fpret)
 #endif
index ac977c0e5902e4133b05074a7edab4b20680a20a..33d1e52dd8d54de2bb03247eb072253093d70f88 100644 (file)
@@ -2261,8 +2261,7 @@ sgen_client_thread_detach_with_lock (SgenThreadInfo *p)
 
        tid = mono_thread_info_get_tid (p);
 
-       if (p->client_info.info.runtime_thread)
-               mono_threads_add_joinable_thread ((gpointer)tid);
+       mono_threads_add_joinable_runtime_thread (&p->client_info.info);
 
        if (mono_gc_get_gc_callbacks ()->thread_detach_func) {
                mono_gc_get_gc_callbacks ()->thread_detach_func (p->client_info.runtime_data);
index 1c8c1f401a8fb0a49c3f0cdb8b9f1abeeedeeda4..a1424beaebaea483723c7cda7050bed4182730f6 100644 (file)
@@ -46,6 +46,7 @@
 #include <mono/utils/mono-threads.h>
 #include <mono/utils/mono-time.h>
 #include <mono/utils/refcount.h>
+#include <mono/utils/mono-os-wait.h>
 
 typedef struct {
        MonoDomain *domain;
@@ -495,7 +496,7 @@ mono_threadpool_end_invoke (MonoAsyncResult *ares, MonoArray **out_args, MonoObj
                mono_monitor_exit ((MonoObject*) ares);
                MONO_ENTER_GC_SAFE;
 #ifdef HOST_WIN32
-               WaitForSingleObjectEx (wait_event, INFINITE, TRUE);
+               mono_win32_wait_for_single_object_ex (wait_event, INFINITE, TRUE);
 #else
                mono_w32handle_wait_one (wait_event, MONO_INFINITE_WAIT, TRUE);
 #endif
index 013046d0ee808d6cd1bfcd4cd0894d628faeed1e..2feb0ba4f8488713a117dd3a8156fb28de455e03 100644 (file)
@@ -242,6 +242,7 @@ gboolean
 mono_thread_create_checked (MonoDomain *domain, gpointer func, gpointer arg, MonoError *error);
 
 /* Can't include utils/mono-threads.h because of the THREAD_INFO_TYPE wizardry */
+void mono_threads_add_joinable_runtime_thread (gpointer thread_info);
 void mono_threads_add_joinable_thread (gpointer tid);
 void mono_threads_join_threads (void);
 void mono_thread_join (gpointer tid);
index 52dc0c0c23001fa962b2fe7e74dd8afe53a5de48..43c8a61d9ab8159f75591149aa572c470dc52227 100644 (file)
@@ -54,6 +54,7 @@
 #include <mono/metadata/abi-details.h>
 #include <mono/metadata/w32error.h>
 #include <mono/utils/w32api.h>
+#include <mono/utils/mono-os-wait.h>
 
 #ifdef HAVE_SIGNAL_H
 #include <signal.h>
@@ -61,6 +62,9 @@
 
 #if defined(HOST_WIN32)
 #include <objbase.h>
+
+extern gboolean
+mono_native_thread_join_handle (HANDLE thread_handle, gboolean close_handle);
 #endif
 
 #if defined(HOST_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64)
@@ -757,6 +761,15 @@ mono_thread_detach_internal (MonoInternalThread *thread)
        thread->abort_exc = NULL;
        thread->current_appcontext = NULL;
 
+       /*
+       * Prevent race condition between execution of this method and runtime shutdown.
+       * Adding runtime thread to the joinable threads list will make sure runtime shutdown
+       * won't complete until added runtime thread have exited. Owner of threads attached to the
+       * runtime but not identified as runtime threads needs to make sure thread detach calls won't
+       * race with runtime shutdown.
+       */
+       mono_threads_add_joinable_runtime_thread (thread->thread_info);
+
        /*
         * thread->synch_cs can be NULL if this was called after
         * ves_icall_System_Threading_InternalThread_Thread_free_internal.
@@ -1020,7 +1033,7 @@ static guint32 WINAPI start_wrapper_internal(StartInfo *start_info, gsize *stack
 
        mono_thread_detach_internal (internal);
 
-       return(0);
+       return 0;
 }
 
 static gsize WINAPI
@@ -1114,7 +1127,7 @@ create_thread (MonoThread *thread, MonoInternalThread *internal, MonoObject *sta
        else
                stack_set_size = 0;
 
-       if (!mono_thread_platform_create_thread (start_wrapper, start_info, &stack_set_size, &tid)) {
+       if (!mono_thread_platform_create_thread ((MonoThreadStart)start_wrapper, start_info, &stack_set_size, &tid)) {
                /* The thread couldn't be created, so set an exception */
                mono_threads_lock ();
                mono_g_hash_table_remove (threads_starting_up, thread);
@@ -1588,6 +1601,8 @@ ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj
 void 
 mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean permanent, gboolean reset, MonoError *error)
 {
+       MonoNativeThreadId tid = 0;
+
        LOCK_THREAD (this_obj);
 
        error_init (error);
@@ -1614,14 +1629,16 @@ mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, g
        else
                this_obj->name = NULL;
 
-       
+       if (!(this_obj->state & ThreadState_Stopped))
+               tid = thread_get_tid (this_obj);
+
        UNLOCK_THREAD (this_obj);
 
-       if (this_obj->name && this_obj->tid) {
+       if (this_obj->name && tid) {
                char *tname = mono_string_to_utf8_checked (name, error);
                return_if_nok (error);
-               MONO_PROFILER_RAISE (thread_name, (this_obj->tid, tname));
-               mono_native_thread_set_name (thread_get_tid (this_obj), tname);
+               MONO_PROFILER_RAISE (thread_name, ((uintptr_t)tid, tname));
+               mono_native_thread_set_name (tid, tname);
                mono_free (tname);
        }
 }
@@ -1817,8 +1834,6 @@ ves_icall_System_Threading_Thread_Join_internal (MonoThread *this_obj, int ms)
                return FALSE;
        }
 
-       MonoNativeThreadId tid = thread_get_tid (thread);
-
        UNLOCK_THREAD (thread);
 
        if (ms == -1)
@@ -1836,16 +1851,9 @@ ves_icall_System_Threading_Thread_Join_internal (MonoThread *this_obj, int ms)
        if (ret == MONO_THREAD_INFO_WAIT_RET_SUCCESS_0) {
                THREAD_DEBUG (g_message ("%s: join successful", __func__));
 
-#ifdef HOST_WIN32
-               /* TODO: Do this on Unix platforms as well. See PR #5454 for context.  */
                /* Wait for the thread to really exit */
-               MONO_ENTER_GC_SAFE;
-               /* This shouldn't block */
-               mono_threads_join_lock ();
-               mono_native_thread_join (tid);
-               mono_threads_join_unlock ();
-               MONO_EXIT_GC_SAFE;
-#endif
+               MonoNativeThreadId tid = thread_get_tid (thread);
+               mono_thread_join (tid);
 
                return TRUE;
        }
@@ -1904,9 +1912,9 @@ ves_icall_System_Threading_WaitHandle_Wait_internal (gpointer *handles, gint32 n
                MONO_ENTER_GC_SAFE;
 #ifdef HOST_WIN32
                if (numhandles != 1)
-                       ret = mono_w32handle_convert_wait_ret (WaitForMultipleObjectsEx (numhandles, handles, waitall, timeoutLeft, TRUE), numhandles);
+                       ret = mono_w32handle_convert_wait_ret (mono_win32_wait_for_multiple_objects_ex(numhandles, handles, waitall, timeoutLeft, TRUE), numhandles);
                else
-                       ret = mono_w32handle_convert_wait_ret (WaitForSingleObjectEx (handles [0], timeoutLeft, TRUE), 1);
+                       ret = mono_w32handle_convert_wait_ret (mono_win32_wait_for_single_object_ex (handles [0], timeoutLeft, TRUE), 1);
 #else
                /* mono_w32handle_wait_multiple optimizes the case for numhandles == 1 */
                ret = mono_w32handle_wait_multiple (handles, numhandles, waitall, timeoutLeft, TRUE);
@@ -1956,7 +1964,7 @@ ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (gpointer toSignal,
        
        MONO_ENTER_GC_SAFE;
 #ifdef HOST_WIN32
-       ret = mono_w32handle_convert_wait_ret (SignalObjectAndWait (toSignal, toWait, ms, TRUE), 1);
+       ret = mono_w32handle_convert_wait_ret (mono_win32_signal_object_and_wait (toSignal, toWait, ms, TRUE), 1);
 #else
        ret = mono_w32handle_signal_and_wait (toSignal, toWait, ms, TRUE);
 #endif
@@ -3005,7 +3013,7 @@ thread_detach (MonoThreadInfo *info)
 static void
 thread_detach_with_lock (MonoThreadInfo *info)
 {
-       return mono_gc_thread_detach_with_lock (info);
+       mono_gc_thread_detach_with_lock (info);
 }
 
 static gboolean
@@ -4455,8 +4463,9 @@ mono_thread_execute_interruption (void)
 
        /* this will consume pending APC calls */
 #ifdef HOST_WIN32
-       WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
+       mono_win32_wait_for_single_object_ex (GetCurrentThread (), 0, TRUE);
 #endif
+
        /* Clear the interrupted flag of the thread so it can wait again */
        mono_thread_info_clear_self_interrupt ();
 
@@ -4524,9 +4533,8 @@ mono_thread_request_interruption (gboolean running_managed)
 
                /* this will awake the thread if it is in WaitForSingleObject 
                   or similar */
-               /* Our implementation of this function ignores the func argument */
 #ifdef HOST_WIN32
-               QueueUserAPC ((PAPCFUNC)dummy_apc, thread->native_handle, (ULONG_PTR)NULL);
+               mono_win32_interrupt_wait (thread->thread_info, thread->native_handle, (DWORD)thread->tid);
 #else
                mono_thread_info_self_interrupt ();
 #endif
@@ -5002,6 +5010,78 @@ mono_thread_is_foreign (MonoThread *thread)
        return info->runtime_thread == FALSE;
 }
 
+#ifndef HOST_WIN32
+static void
+threads_native_thread_join_lock (gpointer tid, gpointer value)
+{
+       pthread_t thread = (pthread_t)tid;
+       if (thread != pthread_self ()) {
+               MONO_ENTER_GC_SAFE;
+               /* This shouldn't block */
+               mono_threads_join_lock ();
+               mono_native_thread_join (thread);
+               mono_threads_join_unlock ();
+               MONO_EXIT_GC_SAFE;
+       }
+}
+static void
+threads_native_thread_join_nolock (gpointer tid, gpointer value)
+{
+       pthread_t thread = (pthread_t)tid;
+       MONO_ENTER_GC_SAFE;
+       mono_native_thread_join (thread);
+       MONO_EXIT_GC_SAFE;
+}
+
+static void
+threads_add_joinable_thread_nolock (gpointer tid)
+{
+       g_hash_table_insert (joinable_threads, tid, tid);
+}
+#else
+static void
+threads_native_thread_join_lock (gpointer tid, gpointer value)
+{
+       MonoNativeThreadId thread_id = (MonoNativeThreadId)(guint64)tid;
+       HANDLE thread_handle = (HANDLE)value;
+       if (thread_id != GetCurrentThreadId () && thread_handle != NULL && thread_handle != INVALID_HANDLE_VALUE) {
+               MONO_ENTER_GC_SAFE;
+               /* This shouldn't block */
+               mono_threads_join_lock ();
+               mono_native_thread_join_handle (thread_handle, TRUE);
+               mono_threads_join_unlock ();
+               MONO_EXIT_GC_SAFE;
+       }
+}
+
+static void
+threads_native_thread_join_nolock (gpointer tid, gpointer value)
+{
+       HANDLE thread_handle = (HANDLE)value;
+       MONO_ENTER_GC_SAFE;
+       mono_native_thread_join_handle (thread_handle, TRUE);
+       MONO_EXIT_GC_SAFE;
+}
+
+static void
+threads_add_joinable_thread_nolock (gpointer tid)
+{
+       g_hash_table_insert (joinable_threads, tid, (gpointer)OpenThread (SYNCHRONIZE, TRUE, (MonoNativeThreadId)(guint64)tid));
+}
+#endif
+
+void
+mono_threads_add_joinable_runtime_thread (gpointer thread_info)
+{
+       g_assert (thread_info);
+       MonoThreadInfo *mono_thread_info = (MonoThreadInfo*)thread_info;
+
+       if (mono_thread_info->runtime_thread) {
+               if (InterlockedCompareExchange (&mono_thread_info->thread_pending_native_join, TRUE, FALSE) == FALSE)
+                       mono_threads_add_joinable_thread ((gpointer)(MONO_UINT_TO_NATIVE_THREAD_ID (mono_thread_info_get_tid (mono_thread_info))));
+       }
+}
+
 /*
  * mono_add_joinable_thread:
  *
@@ -5011,21 +5091,24 @@ mono_thread_is_foreign (MonoThread *thread)
 void
 mono_threads_add_joinable_thread (gpointer tid)
 {
-#ifndef HOST_WIN32
        /*
         * We cannot detach from threads because it causes problems like
         * 2fd16f60/r114307. So we collect them and join them when
-        * we have time (in he finalizer thread).
+        * we have time (in the finalizer thread).
         */
        joinable_threads_lock ();
        if (!joinable_threads)
                joinable_threads = g_hash_table_new (NULL, NULL);
-       g_hash_table_insert (joinable_threads, tid, tid);
-       UnlockedIncrement (&joinable_thread_count);
+
+       gpointer orig_key;
+       gpointer value;
+       if (!g_hash_table_lookup_extended (joinable_threads, tid, &orig_key, &value)) {
+               threads_add_joinable_thread_nolock (tid);
+               UnlockedIncrement (&joinable_thread_count);
+       }
        joinable_threads_unlock ();
 
        mono_gc_finalize_notify ();
-#endif
 }
 
 /*
@@ -5037,11 +5120,9 @@ mono_threads_add_joinable_thread (gpointer tid)
 void
 mono_threads_join_threads (void)
 {
-#ifndef HOST_WIN32
        GHashTableIter iter;
        gpointer key;
-       gpointer tid;
-       pthread_t thread;
+       gpointer value;
        gboolean found;
 
        /* Fastpath */
@@ -5053,27 +5134,17 @@ mono_threads_join_threads (void)
                found = FALSE;
                if (g_hash_table_size (joinable_threads)) {
                        g_hash_table_iter_init (&iter, joinable_threads);
-                       g_hash_table_iter_next (&iter, &key, (void**)&tid);
-                       thread = (pthread_t)tid;
+                       g_hash_table_iter_next (&iter, &key, (void**)&value);
                        g_hash_table_remove (joinable_threads, key);
                        UnlockedDecrement (&joinable_thread_count);
                        found = TRUE;
                }
                joinable_threads_unlock ();
-               if (found) {
-                       if (thread != pthread_self ()) {
-                               MONO_ENTER_GC_SAFE;
-                               /* This shouldn't block */
-                               mono_threads_join_lock ();
-                               mono_native_thread_join (thread);
-                               mono_threads_join_unlock ();
-                               MONO_EXIT_GC_SAFE;
-                       }
-               } else {
+               if (found)
+                       threads_native_thread_join_lock (key, value);
+               else
                        break;
-               }
        }
-#endif
 }
 
 /*
@@ -5085,26 +5156,25 @@ mono_threads_join_threads (void)
 void
 mono_thread_join (gpointer tid)
 {
-#ifndef HOST_WIN32
-       pthread_t thread;
        gboolean found = FALSE;
+       gpointer orig_key;
+       gpointer value;
 
        joinable_threads_lock ();
        if (!joinable_threads)
                joinable_threads = g_hash_table_new (NULL, NULL);
-       if (g_hash_table_lookup (joinable_threads, tid)) {
+
+       if (g_hash_table_lookup_extended (joinable_threads, tid, &orig_key, &value)) {
                g_hash_table_remove (joinable_threads, tid);
                UnlockedDecrement (&joinable_thread_count);
                found = TRUE;
        }
        joinable_threads_unlock ();
+
        if (!found)
                return;
-       thread = (pthread_t)tid;
-       MONO_ENTER_GC_SAFE;
-       mono_native_thread_join (thread);
-       MONO_EXIT_GC_SAFE;
-#endif
+
+       threads_native_thread_join_nolock (tid, value);
 }
 
 void
index 98d4ace6d62593b62e3b0e1be6ace694f8333ff6..654b215538d800de195db57afeca5ccaaa9176e9 100644 (file)
@@ -1218,8 +1218,13 @@ mono_w32handle_wait_multiple (gpointer *handles, gsize nhandles, gboolean waital
                signalled = (waitall && count == nhandles) || (!waitall && count > 0);
 
                if (signalled) {
-                       for (i = 0; i < nhandles; i++)
-                               own_if_signalled (handles [i], &abandoned [i]);
+                       for (i = 0; i < nhandles; i++) {
+                               if (own_if_signalled (handles [i], &abandoned [i]) && !waitall) {
+                                       /* if we are calling WaitHandle.WaitAny, .NET only owns the first one; it matters for Mutex which
+                                        * throw AbandonedMutexException in case we owned it but didn't release it */
+                                       break;
+                               }
+                       }
                }
 
                mono_w32handle_unlock_handles (handles, nhandles);
index 8a55844b6e08884068d95bb62ce3a0037eed9578..f71dc34bdb758365d5b4d928476d27255c164a97 100644 (file)
@@ -2580,8 +2580,8 @@ ves_icall_Microsoft_Win32_NativeMethods_GetProcessTimes (gpointer handle, gint64
                        &start_ticks, &user_ticks, &kernel_ticks);
 
                ticks_to_processtime (start_ticks, creation_processtime);
-               ticks_to_processtime (user_ticks, kernel_processtime);
-               ticks_to_processtime (kernel_ticks, user_processtime);
+               ticks_to_processtime (kernel_ticks, kernel_processtime);
+               ticks_to_processtime (user_ticks, user_processtime);
                return TRUE;
        }
 
index 4f7cc8cdcf555f28ffbf37a6a7c6807192bdeaf6..076500687baeea45d32e1f247532c8a83b43e684 100644 (file)
@@ -23,6 +23,7 @@
 #include "w32socket-internals.h"
 
 #include "utils/w32api.h"
+#include "utils/mono-os-wait.h"
 
 #define LOGDEBUG(...)  
 
@@ -76,10 +77,10 @@ static gboolean alertable_socket_wait (SOCKET sock, int event_bit)
        WSAEVENT event = WSACreateEvent ();
        if (event != WSA_INVALID_EVENT) {
                if (WSAEventSelect (sock, event, (1 << event_bit) | FD_CLOSE) != SOCKET_ERROR) {
-                       LOGDEBUG (g_message ("%06d - Calling WSAWaitForMultipleEvents () on socket %d", GetCurrentThreadId (), sock));
-                       DWORD ret = WSAWaitForMultipleEvents (1, &event, TRUE, timeout, TRUE);
+                       LOGDEBUG (g_message ("%06d - Calling mono_win32_wsa_wait_for_multiple_events () on socket %d", GetCurrentThreadId (), sock));
+                       DWORD ret = mono_win32_wsa_wait_for_multiple_events (1, &event, TRUE, timeout, TRUE);
                        if (ret == WSA_WAIT_IO_COMPLETION) {
-                               LOGDEBUG (g_message ("%06d - WSAWaitForMultipleEvents () returned WSA_WAIT_IO_COMPLETION for socket %d", GetCurrentThreadId (), sock));
+                               LOGDEBUG (g_message ("%06d - mono_win32_wsa_wait_for_multiple_events () returned WSA_WAIT_IO_COMPLETION for socket %d", GetCurrentThreadId (), sock));
                                error = WSAEINTR;
                        } else if (ret == WSA_WAIT_TIMEOUT) {
                                error = WSAETIMEDOUT;
@@ -229,9 +230,9 @@ BOOL mono_w32socket_transmit_file (SOCKET hSocket, gpointer hFile, TRANSMIT_FILE
                        if (error == WSA_IO_PENDING) {
                                error = 0;
                                // NOTE: .NET's Socket.SendFile() doesn't honor the Socket's SendTimeout so we shouldn't either
-                               DWORD ret = WaitForSingleObjectEx (overlapped.hEvent, INFINITE, TRUE);
+                               DWORD ret = mono_win32_wait_for_single_object_ex (overlapped.hEvent, INFINITE, TRUE);
                                if (ret == WAIT_IO_COMPLETION) {
-                                       LOGDEBUG (g_message ("%06d - WaitForSingleObjectEx () returned WSA_WAIT_IO_COMPLETION for socket %d", GetCurrentThreadId (), hSocket));
+                                       LOGDEBUG (g_message ("%06d - mono_win32_wait_for_single_object_ex () returned WSA_WAIT_IO_COMPLETION for socket %d", GetCurrentThreadId (), hSocket));
                                        error = WSAEINTR;
                                } else if (ret == WAIT_TIMEOUT) {
                                        error = WSAETIMEDOUT;
index 125110303adc583d0bf57c0457bfd357e021114b..6b91543a56b6bbfd9e7f6a4c32f6bdb29911f289 100644 (file)
@@ -2897,7 +2897,7 @@ encode_klass_ref_inner (MonoAotCompile *acfg, MonoClass *klass, guint8 *buf, gui
                if (par->gshared_constraint) {
                        MonoGSharedGenericParam *gpar = (MonoGSharedGenericParam*)par;
                        encode_type (acfg, par->gshared_constraint, p, &p);
-                       encode_klass_ref (acfg, mono_class_from_generic_parameter (gpar->parent, NULL, klass->byval_arg.type == MONO_TYPE_MVAR), p, &p);
+                       encode_klass_ref (acfg, mono_class_from_generic_parameter_internal (gpar->parent), p, &p);
                } else {
                        encode_value (klass->byval_arg.type, p, &p);
                        encode_value (mono_type_get_generic_param_num (&klass->byval_arg), p, &p);
index 230a975dbe348bc43711c24276613744530c5e0f..8b1cf4118cc32f1f5a222e71fa92832c1523fec7 100644 (file)
@@ -360,7 +360,7 @@ long_conv_to_ovf_i4_2: dest:i src1:i src2:i len:36
 vcall2: len:40 clob:c
 vcall2_reg: src1:i len:40 clob:c
 vcall2_membase: src1:b len:40 clob:c
-dyn_call: src1:i src2:i len:192 clob:c
+dyn_call: src1:i src2:i len:216 clob:c
 
 # This is different from the original JIT opcodes
 float_beq: len:32
index 442ec3c0a5c9005eab5da957140d8c8851189215..3ac76cdfd8da9c4ea1327993de1364edac13c075 100644 (file)
@@ -11838,7 +11838,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
                                }
 
-                               /* Has to use a call inst since it local regalloc expects it */
+                               /* Has to use a call inst since local regalloc expects it */
                                MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
                                ins = (MonoInst*)call;
                                sp -= 2;
@@ -11847,6 +11847,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                MONO_ADD_INS (cfg->cbb, ins);
 
                                cfg->param_area = MAX (cfg->param_area, cfg->backend->dyn_call_param_area);
+                               /* OP_DYN_CALL might need to allocate a dynamically sized param area */
+                               cfg->flags |= MONO_CFG_HAS_ALLOCA;
 
                                ip += 2;
                                inline_costs += 10 * num_calls++;
index 949f8946ddd1c73cf2a3d56a303448eff7115656..43d0e17babbd6c4d5fa6509eac2eb389aade1999 100644 (file)
@@ -2374,6 +2374,7 @@ mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
 typedef struct {
        MonoMethodSignature *sig;
        CallInfo *cinfo;
+       int nstack_args;
 } ArchDynCallInfo;
 
 static gboolean
@@ -2400,10 +2401,7 @@ dyn_call_supported (MonoMethodSignature *sig, CallInfo *cinfo)
                case ArgInFloatSSEReg:
                case ArgInDoubleSSEReg:
                case ArgValuetypeInReg:
-                       break;
                case ArgOnStack:
-                       if (!(ainfo->offset + (ainfo->arg_size / 8) <= DYN_CALL_STACK_ARGS))
-                               return FALSE;
                        break;
                default:
                        return FALSE;
@@ -2426,6 +2424,7 @@ mono_arch_dyn_call_prepare (MonoMethodSignature *sig)
 {
        ArchDynCallInfo *info;
        CallInfo *cinfo;
+       int i;
 
        cinfo = get_call_info (NULL, sig);
 
@@ -2438,6 +2437,21 @@ mono_arch_dyn_call_prepare (MonoMethodSignature *sig)
        // FIXME: Preprocess the info to speed up get_dyn_call_args ().
        info->sig = sig;
        info->cinfo = cinfo;
+       info->nstack_args = 0;
+
+       for (i = 0; i < cinfo->nargs; ++i) {
+               ArgInfo *ainfo = &cinfo->args [i];
+               switch (ainfo->storage) {
+               case ArgOnStack:
+                       info->nstack_args = MAX (info->nstack_args, ainfo->offset + (ainfo->arg_size / 8));
+                       break;
+               default:
+                       break;
+               }
+       }
+       /* Align to 16 bytes */
+       if (info->nstack_args & 1)
+               info->nstack_args ++;
        
        return (MonoDynCallInfo*)info;
 }
@@ -2456,6 +2470,15 @@ mono_arch_dyn_call_free (MonoDynCallInfo *info)
        g_free (ainfo);
 }
 
+int
+mono_arch_dyn_call_get_buf_size (MonoDynCallInfo *info)
+{
+       ArchDynCallInfo *ainfo = (ArchDynCallInfo*)info;
+
+       /* Extend the 'regs' field dynamically */
+       return sizeof (DynCallArgs) + (ainfo->nstack_args * sizeof (mgreg_t));
+}
+
 #define PTR_TO_GREG(ptr) (mgreg_t)(ptr)
 #define GREG_TO_PTR(greg) (gpointer)(greg)
 
@@ -2474,7 +2497,7 @@ mono_arch_dyn_call_free (MonoDynCallInfo *info)
  * libffi.
  */
 void
-mono_arch_start_dyn_call (MonoDynCallInfo *info, gpointer **args, guint8 *ret, guint8 *buf, int buf_len)
+mono_arch_start_dyn_call (MonoDynCallInfo *info, gpointer **args, guint8 *ret, guint8 *buf)
 {
        ArchDynCallInfo *dinfo = (ArchDynCallInfo*)info;
        DynCallArgs *p = (DynCallArgs*)buf;
@@ -2491,10 +2514,9 @@ mono_arch_start_dyn_call (MonoDynCallInfo *info, gpointer **args, guint8 *ret, g
                param_reg_to_index_inited = 1;
        }
 
-       g_assert (buf_len >= sizeof (DynCallArgs));
-
        p->res = 0;
        p->ret = ret;
+       p->nstack_args = dinfo->nstack_args;
 
        arg_index = 0;
        greg = 0;
@@ -4649,9 +4671,10 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        code = emit_move_return_value (cfg, ins, code);
                        break;
                case OP_DYN_CALL: {
-                       int i;
+                       int i, limit_reg, index_reg, src_reg, dst_reg;
                        MonoInst *var = cfg->dyn_call_var;
                        guint8 *label;
+                       guint8 *buf [16];
 
                        g_assert (var->opcode == OP_REGOFFSET);
 
@@ -4672,15 +4695,38 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                                amd64_sse_movsd_reg_membase (code, i, AMD64_R11, MONO_STRUCT_OFFSET (DynCallArgs, fregs) + (i * sizeof (double)));
                        amd64_patch (label, code);
 
+                       /* Allocate param area */
+                       /* This doesn't need to be freed since OP_DYN_CALL is never called in a loop */
+                       amd64_mov_reg_membase (code, AMD64_RAX, AMD64_R11, MONO_STRUCT_OFFSET (DynCallArgs, nstack_args), 8);
+                       amd64_shift_reg_imm (code, X86_SHL, AMD64_RAX, 3);
+                       amd64_alu_reg_reg (code, X86_SUB, AMD64_RSP, AMD64_RAX);
                        /* Set stack args */
-                       for (i = 0; i < DYN_CALL_STACK_ARGS; ++i) {
-                               amd64_mov_reg_membase (code, AMD64_RAX, AMD64_R11, MONO_STRUCT_OFFSET (DynCallArgs, regs) + ((PARAM_REGS + i) * sizeof(mgreg_t)), sizeof(mgreg_t));
-                               amd64_mov_membase_reg (code, AMD64_RSP, i * sizeof (mgreg_t), AMD64_RAX, sizeof (mgreg_t));
-                       }
+                       /* rax/rcx/rdx/r8/r9 is scratch */
+                       limit_reg = AMD64_RAX;
+                       index_reg = AMD64_RCX;
+                       src_reg = AMD64_R8;
+                       dst_reg = AMD64_R9;
+                       amd64_mov_reg_membase (code, limit_reg, AMD64_R11, MONO_STRUCT_OFFSET (DynCallArgs, nstack_args), 8);
+                       amd64_mov_reg_imm (code, index_reg, 0);
+                       amd64_lea_membase (code, src_reg, AMD64_R11, MONO_STRUCT_OFFSET (DynCallArgs, regs) + ((PARAM_REGS) * sizeof(mgreg_t)));
+                       amd64_mov_reg_reg (code, dst_reg, AMD64_RSP, 8);
+                       buf [0] = code;
+                       x86_jump8 (code, 0);
+                       buf [1] = code;
+                       amd64_mov_reg_membase (code, AMD64_RDX, src_reg, 0, 8);
+                       amd64_mov_membase_reg (code, dst_reg, 0, AMD64_RDX, 8);
+                       amd64_alu_reg_imm (code, X86_ADD, index_reg, 1);
+                       amd64_alu_reg_imm (code, X86_ADD, src_reg, 8);
+                       amd64_alu_reg_imm (code, X86_ADD, dst_reg, 8);
+                       amd64_patch (buf [0], code);
+                       amd64_alu_reg_reg (code, X86_CMP, index_reg, limit_reg);
+                       buf [2] = code;
+                       x86_branch8 (code, X86_CC_LT, 0, FALSE);
+                       amd64_patch (buf [2], buf [1]);
 
                        /* Set argument registers */
                        for (i = 0; i < PARAM_REGS; ++i)
-                               amd64_mov_reg_membase (code, param_regs [i], AMD64_R11, i * sizeof(mgreg_t), sizeof(mgreg_t));
+                               amd64_mov_reg_membase (code, param_regs [i], AMD64_R11, MONO_STRUCT_OFFSET (DynCallArgs, regs) + (i * sizeof(mgreg_t)), sizeof(mgreg_t));
                        
                        /* Make the call */
                        amd64_call_reg (code, AMD64_R10);
index f09f285a17bb26b132a9e30ff6710db8b37ad020..ba8466dfebeaa1d47b59d994c7b2995cb48e3929 100644 (file)
@@ -270,15 +270,15 @@ typedef struct {
        gpointer bp_addrs [MONO_ZERO_LEN_ARRAY];
 } SeqPointInfo;
 
-#define DYN_CALL_STACK_ARGS 6
-
 typedef struct {
-       mgreg_t regs [PARAM_REGS + DYN_CALL_STACK_ARGS];
        mgreg_t res;
        guint8 *ret;
        double fregs [8];
        mgreg_t has_fp;
+       mgreg_t nstack_args;
        guint8 buffer [256];
+       /* This should come last as the structure is dynamically extended */
+       mgreg_t regs [PARAM_REGS];
 } DynCallArgs;
 
 typedef enum {
@@ -429,7 +429,7 @@ typedef struct {
 
 #define MONO_ARCH_GSHARED_SUPPORTED 1
 #define MONO_ARCH_DYN_CALL_SUPPORTED 1
-#define MONO_ARCH_DYN_CALL_PARAM_AREA (DYN_CALL_STACK_ARGS * 8)
+#define MONO_ARCH_DYN_CALL_PARAM_AREA 0
 
 #define MONO_ARCH_LLVM_SUPPORTED 1
 #define MONO_ARCH_HAVE_CARD_TABLE_WBARRIER 1
index 1e56345f03d271d03e69ab814e3cfef87f2f2243..44626141830fe9f5ff2c42f28ae54de1c668f0ee 100644 (file)
@@ -2753,16 +2753,20 @@ mono_arch_dyn_call_free (MonoDynCallInfo *info)
        g_free (ainfo);
 }
 
+int
+mono_arch_dyn_call_get_buf_size (MonoDynCallInfo *info)
+{
+       return sizeof (DynCallArgs);
+}
+
 void
-mono_arch_start_dyn_call (MonoDynCallInfo *info, gpointer **args, guint8 *ret, guint8 *buf, int buf_len)
+mono_arch_start_dyn_call (MonoDynCallInfo *info, gpointer **args, guint8 *ret, guint8 *buf)
 {
        ArchDynCallInfo *dinfo = (ArchDynCallInfo*)info;
        DynCallArgs *p = (DynCallArgs*)buf;
        int arg_index, greg, i, j, pindex;
        MonoMethodSignature *sig = dinfo->sig;
 
-       g_assert (buf_len >= sizeof (DynCallArgs));
-
        p->res = 0;
        p->ret = ret;
        p->has_fpregs = 0;
index 9edb57aa9ef87da6594dea1b82e87867f7ee5dfe..6192f26b9cf042e653ad287c859bb881aafebca0 100644 (file)
@@ -1381,9 +1381,6 @@ dyn_call_supported (CallInfo *cinfo, MonoMethodSignature *sig)
 {
        int i;
 
-       if (sig->hasthis + sig->param_count > PARAM_REGS + DYN_CALL_STACK_ARGS)
-               return FALSE;
-
        // FIXME: Add more cases
        switch (cinfo->ret.storage) {
        case ArgNone:
@@ -1412,10 +1409,7 @@ dyn_call_supported (CallInfo *cinfo, MonoMethodSignature *sig)
                case ArgInFRegR4:
                case ArgHFA:
                case ArgVtypeByRef:
-                       break;
                case ArgOnStack:
-                       if (ainfo->offset >= DYN_CALL_STACK_ARGS * sizeof (mgreg_t))
-                               return FALSE;
                        break;
                default:
                        return FALSE;
@@ -1473,6 +1467,15 @@ mono_arch_dyn_call_free (MonoDynCallInfo *info)
        g_free (ainfo);
 }
 
+int
+mono_arch_dyn_call_get_buf_size (MonoDynCallInfo *info)
+{
+       ArchDynCallInfo *ainfo = (ArchDynCallInfo*)info;
+
+       g_assert (ainfo->cinfo->stack_usage % MONO_ARCH_FRAME_ALIGNMENT == 0);
+       return sizeof (DynCallArgs) + ainfo->cinfo->stack_usage;
+}
+
 static double
 bitcast_r4_to_r8 (float f)
 {
@@ -1490,7 +1493,7 @@ bitcast_r8_to_r4 (double f)
 }
 
 void
-mono_arch_start_dyn_call (MonoDynCallInfo *info, gpointer **args, guint8 *ret, guint8 *buf, int buf_len)
+mono_arch_start_dyn_call (MonoDynCallInfo *info, gpointer **args, guint8 *ret, guint8 *buf)
 {
        ArchDynCallInfo *dinfo = (ArchDynCallInfo*)info;
        DynCallArgs *p = (DynCallArgs*)buf;
@@ -1499,12 +1502,11 @@ mono_arch_start_dyn_call (MonoDynCallInfo *info, gpointer **args, guint8 *ret, g
        CallInfo *cinfo = dinfo->cinfo;
        int buffer_offset = 0;
 
-       g_assert (buf_len >= sizeof (DynCallArgs));
-
        p->res = 0;
        p->ret = ret;
        p->n_fpargs = dinfo->n_fpargs;
        p->n_fpret = dinfo->n_fpret;
+       p->n_stackargs = cinfo->stack_usage / sizeof (mgreg_t);
 
        arg_index = 0;
        greg = 0;
@@ -4175,14 +4177,35 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                                code = emit_ldrfpx (code, ARMREG_D0 + i, ARMREG_LR, MONO_STRUCT_OFFSET (DynCallArgs, fpregs) + (i * 8));
                        arm_patch_rel (labels [0], code, MONO_R_ARM64_BCC);
 
+                       /* Allocate callee area */
+                       code = emit_ldrx (code, ARMREG_R0, ARMREG_LR, MONO_STRUCT_OFFSET (DynCallArgs, n_stackargs));
+                       arm_lslw (code, ARMREG_R0, ARMREG_R0, 3);
+                       arm_movspx (code, ARMREG_R1, ARMREG_SP);
+                       arm_subx (code, ARMREG_R1, ARMREG_R1, ARMREG_R0);
+                       arm_movspx (code, ARMREG_SP, ARMREG_R1);
+
                        /* Set stack args */
-                       for (i = 0; i < DYN_CALL_STACK_ARGS; ++i) {
-                               code = emit_ldrx (code, ARMREG_R0, ARMREG_LR, MONO_STRUCT_OFFSET (DynCallArgs, regs) + ((PARAM_REGS + 1 + i) * sizeof (mgreg_t)));
-                               code = emit_strx (code, ARMREG_R0, ARMREG_SP, i * sizeof (mgreg_t));
-                       }
+                       /* R1 = limit */
+                       code = emit_ldrx (code, ARMREG_R1, ARMREG_LR, MONO_STRUCT_OFFSET (DynCallArgs, n_stackargs));
+                       /* R2 = pointer into 'regs' */
+                       code = emit_imm (code, ARMREG_R2, MONO_STRUCT_OFFSET (DynCallArgs, regs) + ((PARAM_REGS + 1) * sizeof (mgreg_t)));
+                       arm_addx (code, ARMREG_R2, ARMREG_LR, ARMREG_R2);
+                       /* R3 = pointer to stack */
+                       arm_movspx (code, ARMREG_R3, ARMREG_SP);
+                       labels [0] = code;
+                       arm_b (code, code);
+                       labels [1] = code;
+                       code = emit_ldrx (code, ARMREG_R5, ARMREG_R2, 0);
+                       code = emit_strx (code, ARMREG_R5, ARMREG_R3, 0);
+                       code = emit_addx_imm (code, ARMREG_R2, ARMREG_R2, sizeof (mgreg_t));
+                       code = emit_addx_imm (code, ARMREG_R3, ARMREG_R3, sizeof (mgreg_t));
+                       code = emit_subx_imm (code, ARMREG_R1, ARMREG_R1, 1);
+                       arm_patch_rel (labels [0], code, MONO_R_ARM64_B);
+                       arm_cmpw (code, ARMREG_R1, ARMREG_RZR);
+                       arm_bcc (code, ARMCOND_GT, labels [1]);
 
                        /* Set argument registers + r8 */
-                       code = mono_arm_emit_load_regarray (code, 0x1ff, ARMREG_LR, 0);
+                       code = mono_arm_emit_load_regarray (code, 0x1ff, ARMREG_LR, MONO_STRUCT_OFFSET (DynCallArgs, regs));
 
                        /* Make the call */
                        arm_blrx (code, ARMREG_IP1);
index 6268a1064de9266f034eaa7b72f1a3b34a722560..d14301ace80d56e480a728f919b7d198351d05af 100644 (file)
@@ -89,16 +89,15 @@ typedef struct {
 #define PARAM_REGS 8
 #define FP_PARAM_REGS 8
 
-#define DYN_CALL_STACK_ARGS 6
-
 typedef struct {
-       /* The +1 is for r8 */
-       mgreg_t regs [PARAM_REGS + 1 + DYN_CALL_STACK_ARGS];
        mgreg_t res, res2;
        guint8 *ret;
        double fpregs [FP_PARAM_REGS];
-       int n_fpargs, n_fpret;
+       int n_fpargs, n_fpret, n_stackargs;
        guint8 buffer [256];
+       /* This should come last as the structure is dynamically extended */
+       /* The +1 is for r8 */
+       mgreg_t regs [PARAM_REGS + 1];
 } DynCallArgs;
 
 typedef struct {
@@ -141,7 +140,7 @@ typedef struct {
 #define MONO_ARCH_HAVE_EXCEPTIONS_INIT 1
 #define MONO_ARCH_HAVE_GET_TRAMPOLINES 1
 #define MONO_ARCH_DYN_CALL_SUPPORTED 1
-#define MONO_ARCH_DYN_CALL_PARAM_AREA (DYN_CALL_STACK_ARGS * 8)
+#define MONO_ARCH_DYN_CALL_PARAM_AREA 0
 #define MONO_ARCH_SOFT_DEBUG_SUPPORTED 1
 #define MONO_ARCH_GSHAREDVT_SUPPORTED 1
 #define MONO_ARCH_HAVE_SETUP_RESUME_FROM_SIGNAL_HANDLER_CTX 1
index 90d695ae2d63a1028762ac33317db4a9c4f1c541..b433a360d97e7a1cd83f9a9d7989b97105d05fb7 100644 (file)
@@ -2431,8 +2431,11 @@ create_runtime_invoke_info (MonoDomain *domain, MonoMethod *method, gpointer com
                if (mono_class_is_contextbound (method->klass) || !info->compiled_method)
                        supported = FALSE;
 
-               if (supported)
+               if (supported) {
                        info->dyn_call_info = mono_arch_dyn_call_prepare (sig);
+                       if (debug_options.dyn_runtime_invoke)
+                               g_assert (info->dyn_call_info);
+               }
        }
 #endif
 
@@ -2734,8 +2737,8 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
                MonoMethodSignature *sig = mono_method_signature (method);
                gpointer *args;
                static RuntimeInvokeDynamicFunction dyn_runtime_invoke;
-               int i, pindex;
-               guint8 buf [512];
+               int i, pindex, buf_size;
+               guint8 *buf;
                guint8 retval [256];
 
                if (!dyn_runtime_invoke) {
@@ -2764,7 +2767,11 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
 
                //printf ("M: %s\n", mono_method_full_name (method, TRUE));
 
-               mono_arch_start_dyn_call (info->dyn_call_info, (gpointer**)args, retval, buf, sizeof (buf));
+               buf_size = mono_arch_dyn_call_get_buf_size (info->dyn_call_info);
+               buf = g_alloca (buf_size);
+               g_assert (buf);
+
+               mono_arch_start_dyn_call (info->dyn_call_info, (gpointer**)args, retval, buf);
 
                dyn_runtime_invoke (buf, exc, info->compiled_method);
                mono_arch_finish_dyn_call (info->dyn_call_info, buf);
index cf53f940c755bb716b308f42b504dc3a01687000..539125b2f387005ca812adf5d3d01d7c70e42f37 100644 (file)
@@ -2783,7 +2783,8 @@ void      mono_arch_emit_outarg_vt              (MonoCompile *cfg, MonoInst *ins
 void      mono_arch_emit_setret                 (MonoCompile *cfg, MonoMethod *method, MonoInst *val);
 MonoDynCallInfo *mono_arch_dyn_call_prepare     (MonoMethodSignature *sig);
 void      mono_arch_dyn_call_free               (MonoDynCallInfo *info);
-void      mono_arch_start_dyn_call              (MonoDynCallInfo *info, gpointer **args, guint8 *ret, guint8 *buf, int buf_len);
+int       mono_arch_dyn_call_get_buf_size       (MonoDynCallInfo *info);
+void      mono_arch_start_dyn_call              (MonoDynCallInfo *info, gpointer **args, guint8 *ret, guint8 *buf);
 void      mono_arch_finish_dyn_call             (MonoDynCallInfo *info, guint8 *buf);
 MonoInst *mono_arch_emit_inst_for_method        (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args);
 void      mono_arch_decompose_opts              (MonoCompile *cfg, MonoInst *ins);
index 274e1a50fa6fa8a32fd6a2e186d3722e3295574d..f3dbc56cbad61ad5382d149c07877bdd0359877b 100644 (file)
@@ -1142,7 +1142,7 @@ sync_point_mark (MonoProfilerSyncPointType type)
 
        ENTER_LOG (&sync_points_ctr, logbuffer,
                EVENT_SIZE /* event */ +
-               LEB128_SIZE /* type */
+               BYTE_SIZE /* type */
        );
 
        emit_event (logbuffer, TYPE_META | TYPE_SYNC_POINT);
@@ -1905,7 +1905,8 @@ clause_exc (MonoProfiler *prof, MonoMethod *method, uint32_t clause_num, MonoExc
                EVENT_SIZE /* event */ +
                BYTE_SIZE /* clause type */ +
                LEB128_SIZE /* clause num */ +
-               LEB128_SIZE /* method */
+               LEB128_SIZE /* method */ +
+               LEB128_SIZE /* exc */
        );
 
        emit_event (logbuffer, TYPE_EXCEPTION | TYPE_CLAUSE);
@@ -2268,7 +2269,7 @@ dump_ubin (const char *filename, uintptr_t load_addr, uint64_t offset, uintptr_t
                LEB128_SIZE /* load address */ +
                LEB128_SIZE /* offset */ +
                LEB128_SIZE /* size */ +
-               nlen /* file name */
+               len /* file name */
        );
 
        emit_event (logbuffer, TYPE_SAMPLE | TYPE_SAMPLE_UBIN);
@@ -2671,6 +2672,12 @@ counters_sample (uint64_t timestamp)
        ;
 
        for (agent = log_profiler.counters; agent; agent = agent->next) {
+               /*
+                * FIXME: This calculation is incorrect for string counters since
+                * mono_counter_get_size () just returns 0 in that case. We should
+                * address this if we ever actually add any string counters to Mono.
+                */
+
                size +=
                        LEB128_SIZE /* index */ +
                        BYTE_SIZE /* type */ +
index 729b663f91ba9cfb66dbdee3e980641d7a843803..77f06635dde8017a61e1b2cdf018e915e63a44d7 100755 (executable)
@@ -519,7 +519,8 @@ TESTS_CS_SRC=               \
        imt_big_iface_test.cs \
        bug-58782-plain-throw.cs \
        bug-58782-capture-and-throw.cs \
-       recursive-struct-arrays.cs
+       recursive-struct-arrays.cs \
+       bug-59281.cs
 
 if AMD64
 TESTS_CS_SRC += async-exc-compilation.cs finally_guard.cs finally_block_ending_in_dead_bb.cs
diff --git a/mono/tests/bug-59281.cs b/mono/tests/bug-59281.cs
new file mode 100644 (file)
index 0000000..94250c2
--- /dev/null
@@ -0,0 +1,51 @@
+using System;
+using System.Threading;
+
+class Driver
+{
+
+       static readonly Mutex[] mutexes = new Mutex[2];
+
+       public static void Main(string[] args)
+       {
+               for (int i = 0; i < mutexes.Length; i++) {
+                       mutexes [i] = new Mutex();
+               }
+
+               Thread thread1 = new Thread(() => {
+                       for (int i = 0; i < 1; i++) {
+                               int idx = -1;
+                               try {
+                                       idx = WaitHandle.WaitAny (mutexes);
+                                       Console.WriteLine($"Thread 1 iter: {i} with mutex: {idx}");
+                               } finally {
+                                       if (idx != -1)
+                                               mutexes [idx].ReleaseMutex();
+                               }
+                       }
+
+                       Console.WriteLine("Thread 1 ended");
+               });
+
+               thread1.Start();
+               thread1.Join();
+
+               Thread thread2 = new Thread(() => {
+                       for (int i = 0; i < 1000; i++) {
+                               int idx = -1;
+                               try {
+                                       idx = WaitHandle.WaitAny (mutexes);
+                                       Console.WriteLine($"Thread 2 iter: {i} with mutex: {idx}");
+                               } finally {
+                                       if (idx != -1)
+                                               mutexes [idx].ReleaseMutex();
+                               }
+                       }
+
+                       Console.WriteLine("Thread 2 ended");
+               });
+
+               thread2.Start();
+               thread2.Join();
+       }
+}
\ No newline at end of file
index 23fec490693ff134df0462fe9125fc60160bbd86..2c34478f83d63d1931908c51f24d1384fbc2f1db 100644 (file)
@@ -29,6 +29,11 @@ enum Enum2
        D
 }
 
+struct AStruct {
+       public int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10;
+       public int a11, a12, a13, a14, a15, a16, a17, a18, a19, a20;
+}
+
 class Tests
 {
        public static Enum1 return_enum1 () {
@@ -47,6 +52,10 @@ class Tests
                return UInt64.MaxValue - 5;
        }
 
+       public static object return_t<T> (T t) {
+               return (object)t;
+       }
+
        static int Main (string[] args)
        {
                return TestDriver.RunTests (typeof (Tests), args);
@@ -279,4 +288,19 @@ class Tests
         else
             return 1;
     }
+
+       public static int test_0_large_arg ()
+       {
+               var arg = new AStruct ();
+               arg.a1 = 1;
+               arg.a2 = 2;
+               arg.a3 = 3;
+               arg.a20 = 20;
+               var res = typeof (Tests).GetMethod ("return_t").MakeGenericMethod (new Type [] { typeof (AStruct) }).Invoke (null, new object [] { arg });
+               var arg2 = (AStruct)res;
+               if (arg2.a20 == 20)
+                       return 0;
+               else
+                       return 1;
+       }
 }
index 118ab953d0e8bcc172995e3e797a268899737113..119d7c94c2cce1c8e2427211a53467708fc0eeb4 100644 (file)
@@ -13,7 +13,8 @@ endif
 
 if HOST_WIN32
 win32_sources = \
-       os-event-win32.c
+       os-event-win32.c \
+       mono-os-wait-win32.c
 
 platform_sources = $(win32_sources)
 else
@@ -61,6 +62,7 @@ monoutils_sources = \
        mono-mmap-windows-internals.h   \
        mono-os-mutex.h         \
        mono-os-mutex.c         \
+       mono-os-wait.h \
        mono-coop-mutex.h               \
        mono-once.h             \
        mono-lazy-init.h                \
index f766529201e3426bf1349b2f3020ad39d9a54932..0f8984ef9d9d2ef19f7a371feeb0726799351f0f 100644 (file)
@@ -31,8 +31,7 @@
 #elif !defined(HOST_WIN32) && defined(HAVE_SEMAPHORE_H)
 #include <semaphore.h>
 #else
-#include <winsock2.h>
-#include <windows.h>
+#include <mono/utils/mono-os-wait.h>
 #endif
 
 #define MONO_HAS_SEMAPHORES 1
@@ -318,9 +317,9 @@ mono_os_sem_timedwait (MonoSemType *sem, guint32 timeout_ms, MonoSemFlags flags)
        BOOL res;
 
 retry:
-       res = WaitForSingleObjectEx (*sem, timeout_ms, flags & MONO_SEM_FLAGS_ALERTABLE);
+       res = mono_win32_wait_for_single_object_ex (*sem, timeout_ms, flags & MONO_SEM_FLAGS_ALERTABLE);
        if (G_UNLIKELY (res != WAIT_OBJECT_0 && res != WAIT_IO_COMPLETION && res != WAIT_TIMEOUT))
-               g_error ("%s: WaitForSingleObjectEx failed with error %d", __func__, GetLastError ());
+               g_error ("%s: mono_win32_wait_for_single_object_ex failed with error %d", __func__, GetLastError ());
 
        if (res == WAIT_IO_COMPLETION && !(flags & MONO_SEM_FLAGS_ALERTABLE))
                goto retry;
diff --git a/mono/utils/mono-os-wait-win32.c b/mono/utils/mono-os-wait-win32.c
new file mode 100644 (file)
index 0000000..a302d97
--- /dev/null
@@ -0,0 +1,217 @@
+/**
+* \file
+* Win32 OS wait wrappers and interrupt/abort APC handling.
+*
+* Author:
+*   Johan Lorensson (lateralusx.github@gmail.com)
+*
+* Licensed under the MIT license. See LICENSE file in the project root for full license information.
+*/
+
+#include <mono/utils/mono-os-wait.h>
+#include <mono/utils/mono-threads.h>
+#include <mono/utils/mono-threads-debug.h>
+
+enum ThreadWaitInfo {
+       THREAD_WAIT_INFO_CLEARED = 0,
+       THREAD_WAIT_INFO_ALERTABLE_WAIT_SLOT = 1 << 0,
+       THREAD_WAIT_INFO_PENDING_INTERRUPT_APC_SLOT = 1 << 1,
+       THREAD_WAIT_INFO_PENDING_ABORT_APC_SLOT = 1 << 2
+};
+
+static inline void
+request_interrupt (gpointer thread_info, HANDLE native_thread_handle, gint32 pending_apc_slot, PAPCFUNC apc_callback, DWORD tid)
+{
+       /*
+       * On Windows platforms, an async interrupt/abort request queues an APC
+       * that needs to be processed by target thread before it can return from an
+       * alertable OS wait call and complete the mono interrupt/abort request.
+       * Uncontrolled queuing of APC's could flood the APC queue preventing the target thread
+       * to return from its alertable OS wait call, blocking the interrupt/abort requests to complete
+       * This check makes sure that only one APC per type gets queued, preventing potential flooding
+       * of the APC queue. NOTE, this code will execute regardless if targeted thread is currently in
+       * an alertable wait or not. This is done to prevent races between interrupt/abort requests and
+       * alertable wait calls. Threads already in an alertable wait should handle WAIT_IO_COMPLETION
+       * return scenarios and restart the alertable wait operation if needed or take other actions
+       * (like service the interrupt/abort request).
+       */
+       MonoThreadInfo *info = (MonoThreadInfo *)thread_info;
+       gint32 old_wait_info, new_wait_info;
+
+       do {
+               old_wait_info = InterlockedRead (&info->thread_wait_info);
+               if (old_wait_info & pending_apc_slot)
+                       return;
+
+               new_wait_info = old_wait_info | pending_apc_slot;
+       } while (InterlockedCompareExchange (&info->thread_wait_info, new_wait_info, old_wait_info) != old_wait_info);
+
+       THREADS_INTERRUPT_DEBUG ("%06d - Interrupting/Aborting syscall in thread %06d", GetCurrentThreadId (), tid);
+       QueueUserAPC (apc_callback, native_thread_handle, (ULONG_PTR)NULL);
+}
+
+static void CALLBACK
+interrupt_apc (ULONG_PTR param)
+{
+       THREADS_INTERRUPT_DEBUG ("%06d - interrupt_apc () called", GetCurrentThreadId ());
+}
+
+void
+mono_win32_interrupt_wait (PVOID thread_info, HANDLE native_thread_handle, DWORD tid)
+{
+       request_interrupt (thread_info, native_thread_handle, THREAD_WAIT_INFO_PENDING_INTERRUPT_APC_SLOT, interrupt_apc, tid);
+}
+
+static void CALLBACK
+abort_apc (ULONG_PTR param)
+{
+       THREADS_INTERRUPT_DEBUG ("%06d - abort_apc () called", GetCurrentThreadId ());
+}
+
+void
+mono_win32_abort_wait (PVOID thread_info, HANDLE native_thread_handle, DWORD tid)
+{
+       request_interrupt (thread_info, native_thread_handle, THREAD_WAIT_INFO_PENDING_ABORT_APC_SLOT, abort_apc, tid);
+}
+
+static inline void
+enter_alertable_wait (MonoThreadInfo *info)
+{
+       // Clear any previous flags. Set alertable wait flag.
+       InterlockedExchange (&info->thread_wait_info, THREAD_WAIT_INFO_ALERTABLE_WAIT_SLOT);
+}
+
+static inline void
+leave_alertable_wait (MonoThreadInfo *info)
+{
+       // Clear any previous flags. Thread is exiting alertable wait state, and info around pending interrupt/abort APC's
+       // can now be discarded as well, thread is out of wait operation and can proceed it's execution.
+       InterlockedExchange (&info->thread_wait_info, THREAD_WAIT_INFO_CLEARED);
+}
+
+DWORD
+mono_win32_sleep_ex (DWORD timeout, BOOL alertable)
+{
+       DWORD result = WAIT_FAILED;
+       MonoThreadInfo *info = mono_thread_info_current_unchecked ();
+
+       if (alertable && info) {
+               enter_alertable_wait (info);
+       }
+
+       result = SleepEx (timeout, alertable);
+
+       // NOTE, leave_alertable_wait should not affect GetLastError but
+       // if changed, GetLastError needs to be preserved and reset before returning.
+       if (alertable && info) {
+               leave_alertable_wait (info);
+       }
+
+       return result;
+}
+
+DWORD
+mono_win32_wait_for_single_object_ex (HANDLE handle, DWORD timeout, BOOL alertable)
+{
+       DWORD result = WAIT_FAILED;
+       MonoThreadInfo *info = mono_thread_info_current_unchecked ();
+
+       if (alertable && info) {
+               enter_alertable_wait (info);
+       }
+
+       result = WaitForSingleObjectEx (handle, timeout, alertable);
+
+       // NOTE, leave_alertable_wait should not affect GetLastError but
+       // if changed, GetLastError needs to be preserved and reset before returning.
+       if (alertable && info) {
+               leave_alertable_wait (info);
+       }
+
+       return result;
+}
+
+DWORD
+mono_win32_wait_for_multiple_objects_ex (DWORD count, CONST HANDLE *handles, BOOL waitAll, DWORD timeout, BOOL alertable)
+{
+       DWORD result = WAIT_FAILED;
+       MonoThreadInfo *info = mono_thread_info_current_unchecked ();
+
+       if (alertable && info) {
+               enter_alertable_wait (info);
+       }
+
+       result = WaitForMultipleObjectsEx (count, handles, waitAll, timeout, alertable);
+
+       // NOTE, leave_alertable_wait should not affect GetLastError but
+       // if changed, GetLastError needs to be preserved and reset before returning.
+       if (alertable && info) {
+               leave_alertable_wait (info);
+       }
+
+       return result;
+}
+
+DWORD
+mono_win32_signal_object_and_wait (HANDLE toSignal, HANDLE toWait, DWORD timeout, BOOL alertable)
+{
+       DWORD result = WAIT_FAILED;
+       MonoThreadInfo *info = mono_thread_info_current_unchecked ();
+
+       if (alertable && info) {
+               enter_alertable_wait (info);
+       }
+
+       result = SignalObjectAndWait (toSignal, toWait, timeout, alertable);
+
+       // NOTE, leave_alertable_wait should not affect GetLastError but
+       // if changed, GetLastError needs to be preserved and reset before returning.
+       if (alertable && info) {
+               leave_alertable_wait (info);
+       }
+
+       return result;
+}
+
+DWORD
+mono_win32_msg_wait_for_multiple_objects_ex (DWORD count, CONST HANDLE *handles, DWORD timeout, DWORD wakeMask, DWORD flags)
+{
+       DWORD result = WAIT_FAILED;
+       MonoThreadInfo *info = mono_thread_info_current_unchecked ();
+       BOOL alertable = flags & MWMO_ALERTABLE;
+
+       if (alertable && info) {
+               enter_alertable_wait (info);
+       }
+
+       result = MsgWaitForMultipleObjectsEx (count, handles, timeout, wakeMask, flags);
+
+       // NOTE, leave_alertable_wait should not affect GetLastError but
+       // if changed, GetLastError needs to be preserved and reset before returning.
+       if (alertable && info) {
+               leave_alertable_wait (info);
+       }
+
+       return result;
+}
+
+DWORD
+mono_win32_wsa_wait_for_multiple_events (DWORD count, const WSAEVENT FAR *handles, BOOL waitAll, DWORD timeout, BOOL alertable)
+{
+       DWORD result = WAIT_FAILED;
+       MonoThreadInfo *info = mono_thread_info_current_unchecked ();
+
+       if (alertable && info) {
+               enter_alertable_wait (info);
+       }
+
+       result = WSAWaitForMultipleEvents (count, handles, waitAll, timeout, alertable);
+
+       // NOTE, leave_alertable_wait should not affect GetLastError but
+       // if changed, GetLastError needs to be preserved and reset before returning.
+       if (alertable && info) {
+               leave_alertable_wait (info);
+       }
+
+       return result;
+}
diff --git a/mono/utils/mono-os-wait.h b/mono/utils/mono-os-wait.h
new file mode 100644 (file)
index 0000000..566ed97
--- /dev/null
@@ -0,0 +1,40 @@
+/**
+* \file
+*/
+
+#ifndef _MONO_UTILS_OS_WAIT_H_
+#define _MONO_UTILS_OS_WAIT_H_
+
+#include <config.h>
+#ifdef HOST_WIN32
+
+#include <winsock2.h>
+#include <windows.h>
+
+DWORD
+mono_win32_sleep_ex (DWORD timeout, BOOL alertable);
+
+DWORD
+mono_win32_wait_for_single_object_ex (HANDLE handle, DWORD timeout, BOOL alertable);
+
+DWORD
+mono_win32_wait_for_multiple_objects_ex (DWORD count, CONST HANDLE *handles, BOOL waitAll, DWORD timeout, BOOL alertable);
+
+DWORD
+mono_win32_signal_object_and_wait (HANDLE toSignal, HANDLE toWait, DWORD timeout, BOOL alertable);
+
+DWORD
+mono_win32_msg_wait_for_multiple_objects_ex (DWORD count, CONST HANDLE *handles, DWORD timeout, DWORD wakeMask, DWORD flags);
+
+DWORD
+mono_win32_wsa_wait_for_multiple_events (DWORD count, const WSAEVENT FAR *handles, BOOL waitAll, DWORD timeout, BOOL alertable);
+
+void
+mono_win32_interrupt_wait (PVOID thread_info, HANDLE native_thread_handle, DWORD tid);
+
+void
+mono_win32_abort_wait (PVOID thread_info, HANDLE native_thread_handle, DWORD tid);
+
+#endif
+
+#endif /* _MONO_UTILS_OS_WAIT_H_ */
index 9ef565ddf9107934b6c77054a3ecc44f5ad2dcb2..563d210e8ed5cfe9ef657e7aba24d77d0f0429cf 100644 (file)
 
 #include <mono/utils/mono-compiler.h>
 #include <mono/utils/mono-threads-debug.h>
+#include <mono/utils/mono-os-wait.h>
 #include <limits.h>
 
-
 void
 mono_threads_suspend_init (void)
 {
 }
 
-static void CALLBACK
-interrupt_apc (ULONG_PTR param)
-{
-}
-
 gboolean
 mono_threads_suspend_begin_async_suspend (MonoThreadInfo *info, gboolean interrupt_kernel)
 {
@@ -57,9 +52,8 @@ mono_threads_suspend_begin_async_suspend (MonoThreadInfo *info, gboolean interru
        info->suspend_can_continue = mono_threads_get_runtime_callbacks ()->thread_state_init_from_handle (&info->thread_saved_state [ASYNC_SUSPEND_STATE_INDEX], info);
        THREADS_SUSPEND_DEBUG ("thread state %p -> %d\n", (void*)id, res);
        if (info->suspend_can_continue) {
-               //FIXME do we need to QueueUserAPC on this case?
                if (interrupt_kernel)
-                       QueueUserAPC ((PAPCFUNC)interrupt_apc, handle, (ULONG_PTR)NULL);
+                       mono_win32_interrupt_wait (info, handle, id);
        } else {
                THREADS_SUSPEND_DEBUG ("FAILSAFE RESUME/2 %p -> %d\n", (void*)info->native_handle, 0);
        }
@@ -74,11 +68,7 @@ mono_threads_suspend_check_suspend_result (MonoThreadInfo *info)
        return info->suspend_can_continue;
 }
 
-static void CALLBACK
-abort_apc (ULONG_PTR param)
-{
-       THREADS_INTERRUPT_DEBUG ("%06d - abort_apc () called", GetCurrentThreadId ());
-}
+
 
 void
 mono_threads_suspend_abort_syscall (MonoThreadInfo *info)
@@ -89,8 +79,7 @@ mono_threads_suspend_abort_syscall (MonoThreadInfo *info)
        handle = OpenThread (THREAD_ALL_ACCESS, FALSE, id);
        g_assert (handle);
 
-       THREADS_INTERRUPT_DEBUG ("%06d - Aborting syscall in thread %06d", GetCurrentThreadId (), id);
-       QueueUserAPC ((PAPCFUNC)abort_apc, handle, (ULONG_PTR)NULL);
+       mono_win32_abort_wait (info, handle, id);
 
        CloseHandle (handle);
 }
@@ -229,19 +218,26 @@ mono_native_thread_create (MonoNativeThreadId *tid, gpointer func, gpointer arg)
        return CreateThread (NULL, 0, (func), (arg), 0, (tid)) != NULL;
 }
 
+gboolean
+mono_native_thread_join_handle (HANDLE thread_handle, gboolean close_handle)
+{
+       DWORD res = WaitForSingleObject (thread_handle, INFINITE);
+
+       if (close_handle)
+               CloseHandle (thread_handle);
+
+       return res != WAIT_FAILED;
+}
+
 gboolean
 mono_native_thread_join (MonoNativeThreadId tid)
 {
        HANDLE handle;
 
-       if (!(handle = OpenThread (THREAD_ALL_ACCESS, TRUE, tid)))
+       if (!(handle = OpenThread (SYNCHRONIZE, TRUE, tid)))
                return FALSE;
 
-       DWORD res = WaitForSingleObject (handle, INFINITE);
-
-       CloseHandle (handle);
-
-       return res != WAIT_FAILED;
+       return mono_native_thread_join_handle (handle, TRUE);
 }
 
 #if HAVE_DECL___READFSDWORD==0
index b95784fa6fd9ebeb5d69a5f94eba78e658ad4809..9a67fb863316e44896f975ef4d8f4e9c5e333367 100644 (file)
@@ -230,6 +230,13 @@ typedef struct {
         * handled a sampling signal before sending another one.
         */
        gint32 profiler_signal_ack;
+
+       gint32 thread_pending_native_join;
+
+#ifdef USE_WINDOWS_BACKEND
+       gint32 thread_wait_info;
+#endif
+
 } MonoThreadInfo;
 
 typedef struct {
index b63ec21a28f1a424f21ac6f1a8525a17395041ba..095669a0e4aebea91650beee4833ef795d97c8ca 100644 (file)
@@ -14,6 +14,7 @@
 #include <winbase.h>
 
 #include "atomic.h"
+#include "mono-os-wait.h"
 
 void
 mono_os_event_init (MonoOSEvent *event, gboolean initial)
@@ -72,7 +73,7 @@ mono_os_event_wait_one (MonoOSEvent *event, guint32 timeout, gboolean alertable)
        g_assert (event);
        g_assert (event->handle);
 
-       res = WaitForSingleObjectEx (event->handle, timeout, alertable);
+       res = mono_win32_wait_for_single_object_ex (event->handle, timeout, alertable);
        if (res == WAIT_OBJECT_0)
                return MONO_OS_EVENT_WAIT_RET_SUCCESS_0;
        else if (res == WAIT_IO_COMPLETION)
@@ -80,7 +81,7 @@ mono_os_event_wait_one (MonoOSEvent *event, guint32 timeout, gboolean alertable)
        else if (res == WAIT_TIMEOUT)
                return MONO_OS_EVENT_WAIT_RET_TIMEOUT;
        else if (res == WAIT_FAILED)
-               g_error ("%s: WaitForSingleObjectEx failed with error %d", __func__, GetLastError ());
+               g_error ("%s: mono_thread_win32_wait_one_handle failed with error %d", __func__, GetLastError ());
        else
                g_error ("%s: unknown res value %d", __func__, res);
 }
@@ -105,7 +106,7 @@ mono_os_event_wait_multiple (MonoOSEvent **events, gsize nevents, gboolean waita
                handles [i] = events [i]->handle;
        }
 
-       res = WaitForMultipleObjectsEx (nevents, handles, waitall, timeout, alertable);
+       res = mono_win32_wait_for_multiple_objects_ex ((DWORD)nevents, handles, waitall, timeout, alertable);
        if (res >= WAIT_OBJECT_0 && res < WAIT_OBJECT_0 + MONO_OS_EVENT_WAIT_MAXIMUM_OBJECTS)
                return MONO_OS_EVENT_WAIT_RET_SUCCESS_0 + (res - WAIT_OBJECT_0);
        else if (res == WAIT_IO_COMPLETION)
@@ -113,7 +114,7 @@ mono_os_event_wait_multiple (MonoOSEvent **events, gsize nevents, gboolean waita
        else if (res == WAIT_TIMEOUT)
                return MONO_OS_EVENT_WAIT_RET_TIMEOUT;
        else if (res == WAIT_FAILED)
-               g_error ("%s: WaitForSingleObjectEx failed with error %d", __func__, GetLastError ());
+               g_error ("%s: mono_thread_win32_wait_multiple_handle failed with error %d", __func__, GetLastError ());
        else
                g_error ("%s: unknown res value %d", __func__, res);
 }
index 406b686cfeb850c2e064353c12ca696342f335cb..8a1e98bb2ee7068e6246e130b186c16abcca09d3 100644 (file)
@@ -20,6 +20,8 @@
 
 #if MONO_HAS_CLANG_THREAD_SANITIZER
 #define MONO_UNLOCKED_ATTRS MONO_NO_SANITIZE_THREAD MONO_NEVER_INLINE static
+#elif defined(_MSC_VER)
+#define MONO_UNLOCKED_ATTRS MONO_ALWAYS_INLINE static
 #else
 #define MONO_UNLOCKED_ATTRS MONO_ALWAYS_INLINE static inline
 #endif
index 350a54654e475e39aa163f1c125cbaff0c19b47b..beba4278b8e64cf515143a124e9b3f5b39c13b94 100644 (file)
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>\r
+<?xml version="1.0" encoding="utf-8"?>\r
 <Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
   <ItemGroup Label="ProjectConfigurations">\r
     <ProjectConfiguration Include="Debug|Win32">\r
@@ -68,6 +68,7 @@
     <ClCompile Include="..\mono\utils\mono-mmap-windows.c" />\r
     <ClCompile Include="..\mono\utils\mono-mmap.c" />\r
     <ClCompile Include="..\mono\utils\mono-networkinterfaces.c" />\r
+    <ClCompile Include="..\mono\utils\mono-os-wait-win32.c" />\r
     <ClCompile Include="..\mono\utils\mono-proclib-windows.c" />\r
     <ClCompile Include="..\mono\utils\mono-rand-windows.c" />\r
     <ClCompile Include="..\mono\utils\mono-rand.c" />\r
     <ClInclude Include="..\mono\utils\mono-once.h" />\r
     <ClInclude Include="..\mono\utils\mono-os-mutex.h" />\r
     <ClInclude Include="..\mono\utils\mono-os-semaphore.h" />\r
+    <ClInclude Include="..\mono\utils\mono-os-wait.h" />\r
     <ClInclude Include="..\mono\utils\mono-path.h" />\r
     <ClInclude Include="..\mono\utils\mono-poll.h" />\r
     <ClInclude Include="..\mono\utils\mono-proclib-windows-internals.h" />\r
     <ClInclude Include="..\mono\utils\strenc.h" />\r
     <ClInclude Include="..\mono\utils\valgrind.h" />\r
     <ClInclude Include="..\mono\utils\atomic.h" />\r
-    <ClInclude Include="..\mono\utils\unlocked.h" />
+    <ClInclude Include="..\mono\utils\unlocked.h" />\r
     <ClInclude Include="..\mono\utils\mono-hwcap.h" />\r
     <ClInclude Include="..\mono\utils\mono-hwcap-x86.h" />\r
     <ClInclude Include="..\mono\utils\bsearch.h" />\r
index a8b85cafce86e1c03fcf45ec014d136d12f7a423..e4b82690a1821a115451b8f47e75ab4f9aecaa44 100644 (file)
     <ClCompile Include="..\mono\utils\mono-os-mutex.c">\r
       <Filter>Source Files</Filter>\r
     </ClCompile>\r
+    <ClCompile Include="..\mono\utils\mono-os-wait-win32.c">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
   </ItemGroup>\r
   <ItemGroup>\r
     <ClInclude Include="..\mono\utils\atomic.h">\r
     <ClInclude Include="..\mono\utils\os-event.h">\r
       <Filter>Header Files</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="..\mono\utils\unlocked.h">
-      <Filter>Header Files</Filter>
-    </ClInclude>
+    <ClInclude Include="..\mono\utils\unlocked.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\mono\utils\mono-os-wait.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
   </ItemGroup>\r
   <ItemGroup>\r
     <Filter Include="Header Files">\r