[w32handle] Unify WaitHandle.Wait{One,Any,All} icalls (#5051)
authorLudovic Henry <ludovic@xamarin.com>
Sat, 17 Jun 2017 01:01:51 +0000 (21:01 -0400)
committerGitHub <noreply@github.com>
Sat, 17 Jun 2017 01:01:51 +0000 (21:01 -0400)
mcs/class/Mono.Debugger.Soft/Test/dtest.cs
mcs/class/corlib/System.Threading/WaitHandle.cs
mono/metadata/icall-def.h
mono/metadata/threads-types.h
mono/metadata/threads.c

index 8d22ac808b2282d92cd8c3787030eb0ba147f14b..7a16e5dcb83b1927bff434a6abb6604646d2845e 100644 (file)
@@ -4145,7 +4145,7 @@ public class DebuggerTests
 
                frames = thread.GetFrames ();
                Assert.AreEqual (8, frames.Length, "#7");
-               Assert.AreEqual ("WaitOne_internal", frames [0].Method.Name, "#8.0");
+               Assert.AreEqual ("Wait_internal", frames [0].Method.Name, "#8.0");
                Assert.AreEqual ("WaitOneNative", frames [1].Method.Name, "#8.1");
                Assert.AreEqual ("InternalWaitOne", frames [2].Method.Name, "#8.2");
                Assert.AreEqual ("WaitOne", frames [3].Method.Name, "#8.3");
index dd91330355ed355081c3778ece51e449cb73c7ef..0e16f046e8012a7fa5f1cbbb30a84877519e56b8 100644 (file)
@@ -49,6 +49,9 @@ namespace System.Threading
 
                static int WaitMultiple(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext, bool WaitAll)
                {
+                       if (waitHandles.Length > MaxWaitHandles)
+                               return WAIT_FAILED;
+
                        int release_last = -1;
 
                        try {
@@ -58,8 +61,7 @@ namespace System.Threading
 #endif
 
                                for (int i = 0; i < waitHandles.Length; ++i) {
-                                       try {
-                                       } finally {
+                                       try {} finally {
                                                /* we have to put it in a finally block, to avoid having a ThreadAbortException
                                                 * between the return from DangerousAddRef and the assignement to release_last */
                                                bool release = false;
@@ -68,10 +70,14 @@ namespace System.Threading
                                        }
                                }
 
-                               if (WaitAll)
-                                       return WaitAll_internal (waitHandles, millisecondsTimeout);
-                               else
-                                       return WaitAny_internal (waitHandles, millisecondsTimeout);
+                               unsafe {
+                                       IntPtr* handles = stackalloc IntPtr[waitHandles.Length];
+
+                                       for (int i = 0; i < waitHandles.Length; ++i)
+                                               handles[i] = waitHandles[i].SafeWaitHandle.DangerousGetHandle ();
+
+                                       return Wait_internal(handles, waitHandles.Length, WaitAll, millisecondsTimeout);
+                               }
                        } finally {
                                for (int i = release_last; i >= 0; --i) {
                                        waitHandles [i].SafeWaitHandle.DangerousRelease ();
@@ -84,12 +90,6 @@ namespace System.Threading
                        }
                }
 
-               [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               private static extern int WaitAll_internal(WaitHandle[] handles, int ms);
-
-               [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               private static extern int WaitAny_internal(WaitHandle[] handles, int ms);
-
                static int WaitOneNative (SafeHandle waitableSafeHandle, uint millisecondsTimeout, bool hasThreadAffinity, bool exitContext)
                {
                        bool release = false;
@@ -101,7 +101,10 @@ namespace System.Threading
 
                                waitableSafeHandle.DangerousAddRef (ref release);
 
-                               return WaitOne_internal (waitableSafeHandle.DangerousGetHandle (), (int) millisecondsTimeout);
+                               unsafe {
+                                       IntPtr handle = waitableSafeHandle.DangerousGetHandle();
+                                       return Wait_internal(&handle, 1, false, (int)millisecondsTimeout);
+                               }
                        } finally {
                                if (release)
                                        waitableSafeHandle.DangerousRelease ();
@@ -114,7 +117,7 @@ namespace System.Threading
                }
 
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               static extern int WaitOne_internal(IntPtr handle, int ms);
+               unsafe static extern int Wait_internal(IntPtr* handles, int numHandles, bool waitAll, int ms);
 
                static int SignalAndWaitOne (SafeWaitHandle waitHandleToSignal,SafeWaitHandle waitHandleToWaitOn, int millisecondsTimeout, bool hasThreadAffinity,  bool exitContext)
                {
index a77e1a7c00ed6589fb4456c37da2838fd4595154..64c806a05f60c23ec7f7c0b57d66c89abdbddd07 100644 (file)
@@ -1032,10 +1032,8 @@ ICALL(VOLATILE_25, "Write(uintptr&,uintptr)", ves_icall_System_Threading_Volatil
 ICALL(VOLATILE_26, "Write(ulong&,ulong)", ves_icall_System_Threading_Volatile_Write8)
 
 ICALL_TYPE(WAITH, "System.Threading.WaitHandle", WAITH_1)
-ICALL(WAITH_1, "SignalAndWait_Internal", ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal)
-ICALL(WAITH_2, "WaitAll_internal", ves_icall_System_Threading_WaitHandle_WaitAll_internal)
-ICALL(WAITH_3, "WaitAny_internal", ves_icall_System_Threading_WaitHandle_WaitAny_internal)
-ICALL(WAITH_4, "WaitOne_internal", ves_icall_System_Threading_WaitHandle_WaitOne_internal)
+HANDLES(ICALL(WAITH_1, "SignalAndWait_Internal", ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal))
+HANDLES(ICALL(WAITH_2, "Wait_internal", ves_icall_System_Threading_WaitHandle_Wait_internal))
 
 ICALL_TYPE(TYPE, "System.Type", TYPE_1)
 HANDLES(ICALL(TYPE_1, "internal_from_handle", ves_icall_System_Type_internal_from_handle))
index 59d4856629bbd526b4a902e9e290c6422cbb99c1..257266e21b6fe5130f3d7e2ac07acbe67bf7d1a2 100644 (file)
@@ -89,10 +89,8 @@ MonoObject* ves_icall_System_Threading_Thread_GetCachedCurrentUICulture (MonoInt
 void ves_icall_System_Threading_Thread_SetCachedCurrentUICulture (MonoThread *this_obj, MonoObject *culture);
 MonoThread *ves_icall_System_Threading_Thread_GetCurrentThread (void);
 
-gint32 ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms);
-gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms);
-gint32 ves_icall_System_Threading_WaitHandle_WaitOne_internal(gpointer handle, gint32 ms);
-gint32 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (gpointer toSignal, gpointer toWait, gint32 ms);
+gint32 ves_icall_System_Threading_WaitHandle_Wait_internal(gpointer *handles, gint32 numhandles, MonoBoolean waitall, gint32 ms, MonoError *error);
+gint32 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (gpointer toSignal, gpointer toWait, gint32 ms, MonoError *error);
 
 MonoArray* ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray *arr);
 MonoArray* ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr);
index 60848191ddc3a64032d48c9d9f7dab5444f2411c..da85ec6e9a0036e32e1f3828e0111b6f0520b78b 100644 (file)
@@ -1858,28 +1858,40 @@ map_native_wait_result_to_managed (MonoW32HandleWaitRet val, gsize numobjects)
        }
 }
 
-static MonoW32HandleWaitRet
-mono_wait_uninterrupted (MonoInternalThread *thread, guint32 numhandles, gpointer *handles, gboolean waitall, gint32 ms, MonoError *error)
+gint32
+ves_icall_System_Threading_WaitHandle_Wait_internal (gpointer *handles, gint32 numhandles, MonoBoolean waitall, gint32 timeout, MonoError *error)
 {
-       MonoException *exc;
        MonoW32HandleWaitRet ret;
+       MonoInternalThread *thread;
+       MonoException *exc;
        gint64 start;
-       gint32 diff_ms;
-       gint32 wait = ms;
+       guint32 timeoutLeft;
 
-       error_init (error);
+       /* Do this WaitSleepJoin check before creating objects */
+       if (mono_thread_current_check_pending_interrupt ())
+               return map_native_wait_result_to_managed (MONO_W32HANDLE_WAIT_RET_FAILED, 0);
 
-       start = (ms == -1) ? 0 : mono_100ns_ticks ();
-       do {
+       thread = mono_thread_internal_current ();
+
+       mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
+
+       if (timeout == -1)
+               timeout = MONO_INFINITE_WAIT;
+       if (timeout != MONO_INFINITE_WAIT)
+               start = mono_msec_ticks ();
+
+       timeoutLeft = timeout;
+
+       for (;;) {
                MONO_ENTER_GC_SAFE;
 #ifdef HOST_WIN32
                if (numhandles != 1)
-                       ret = mono_w32handle_convert_wait_ret (WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, TRUE), numhandles);
+                       ret = mono_w32handle_convert_wait_ret (WaitForMultipleObjectsEx (numhandles, handles, waitall, timeoutLeft, TRUE), numhandles);
                else
-                       ret = mono_w32handle_convert_wait_ret (WaitForSingleObjectEx (handles [0], ms, TRUE), 1);
+                       ret = mono_w32handle_convert_wait_ret (WaitForSingleObjectEx (handles [0], timeoutLeft, TRUE), 1);
 #else
                /* mono_w32handle_wait_multiple optimizes the case for numhandles == 1 */
-               ret = mono_w32handle_wait_multiple (handles, numhandles, waitall, wait, TRUE);
+               ret = mono_w32handle_wait_multiple (handles, numhandles, waitall, timeoutLeft, TRUE);
 #endif /* HOST_WIN32 */
                MONO_EXIT_GC_SAFE;
 
@@ -1892,128 +1904,26 @@ mono_wait_uninterrupted (MonoInternalThread *thread, guint32 numhandles, gpointe
                        break;
                }
 
-               if (ms == -1)
-                       continue;
-
-               /* Re-calculate ms according to the time passed */
-               diff_ms = (gint32)((mono_100ns_ticks () - start) / 10000);
-               if (diff_ms >= ms) {
-                       ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT;
-                       break;
-               }
-               wait = ms - diff_ms;
-       } while (TRUE);
-       
-       return ret;
-}
-
-gint32 ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms)
-{
-       MonoError error;
-       HANDLE *handles;
-       guint32 numhandles;
-       MonoW32HandleWaitRet ret;
-       guint32 i;
-       MonoObject *waitHandle;
-       MonoInternalThread *thread = mono_thread_internal_current ();
-
-       /* Do this WaitSleepJoin check before creating objects */
-       if (mono_thread_current_check_pending_interrupt ())
-               return map_native_wait_result_to_managed (MONO_W32HANDLE_WAIT_RET_FAILED, 0);
-
-       /* We fail in managed if the array has more than 64 elements */
-       numhandles = (guint32)mono_array_length(mono_handles);
-       handles = g_new0(HANDLE, numhandles);
-
-       for(i = 0; i < numhandles; i++) {       
-               waitHandle = mono_array_get(mono_handles, MonoObject*, i);
-               handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
-       }
-       
-       if(ms== -1) {
-               ms=MONO_INFINITE_WAIT;
-       }
-
-       mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
-
-       ret = mono_wait_uninterrupted (thread, numhandles, handles, TRUE, ms, &error);
-
-       mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
-
-       g_free(handles);
-
-       mono_error_set_pending_exception (&error);
-
-       return map_native_wait_result_to_managed (ret, numhandles);
-}
-
-gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms)
-{
-       MonoError error;
-       HANDLE handles [MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
-       uintptr_t numhandles;
-       MonoW32HandleWaitRet ret;
-       guint32 i;
-       MonoObject *waitHandle;
-       MonoInternalThread *thread = mono_thread_internal_current ();
-
-       /* Do this WaitSleepJoin check before creating objects */
-       if (mono_thread_current_check_pending_interrupt ())
-               return map_native_wait_result_to_managed (MONO_W32HANDLE_WAIT_RET_FAILED, 0);
+               if (timeout != MONO_INFINITE_WAIT) {
+                       gint64 elapsed;
 
-       numhandles = mono_array_length(mono_handles);
-       if (numhandles > MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS)
-               return map_native_wait_result_to_managed (MONO_W32HANDLE_WAIT_RET_FAILED, 0);
+                       elapsed = mono_msec_ticks () - start;
+                       if (elapsed >= timeout) {
+                               ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT;
+                               break;
+                       }
 
-       for(i = 0; i < numhandles; i++) {       
-               waitHandle = mono_array_get(mono_handles, MonoObject*, i);
-               handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
-       }
-       
-       if(ms== -1) {
-               ms=MONO_INFINITE_WAIT;
+                       timeoutLeft = timeout - elapsed;
+               }
        }
 
-       mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
-
-       ret = mono_wait_uninterrupted (thread, numhandles, handles, FALSE, ms, &error);
-
        mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
 
-       THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, mono_native_thread_id_get (), ret));
-
-       mono_error_set_pending_exception (&error);
-
        return map_native_wait_result_to_managed (ret, numhandles);
 }
 
-gint32 ves_icall_System_Threading_WaitHandle_WaitOne_internal(HANDLE handle, gint32 ms)
-{
-       MonoError error;
-       MonoW32HandleWaitRet ret;
-       MonoInternalThread *thread = mono_thread_internal_current ();
-
-       THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for %p, %d ms", __func__, mono_native_thread_id_get (), handle, ms));
-       
-       if(ms== -1) {
-               ms=MONO_INFINITE_WAIT;
-       }
-       
-       if (mono_thread_current_check_pending_interrupt ())
-               return map_native_wait_result_to_managed (MONO_W32HANDLE_WAIT_RET_FAILED, 0);
-
-       mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
-       
-       ret = mono_wait_uninterrupted (thread, 1, &handle, FALSE, ms, &error);
-       
-       mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
-
-       mono_error_set_pending_exception (&error);
-       return map_native_wait_result_to_managed (ret, 1);
-}
-
 gint32
-ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms)
+ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (gpointer toSignal, gpointer toWait, gint32 ms, MonoError *error)
 {
        MonoW32HandleWaitRet ret;
        MonoInternalThread *thread = mono_thread_internal_current ();