From 6fc58f529b10f664c71bb301ed9d3524ed4e4f87 Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Fri, 16 Jun 2017 21:01:51 -0400 Subject: [PATCH] [w32handle] Unify WaitHandle.Wait{One,Any,All} icalls (#5051) --- mcs/class/Mono.Debugger.Soft/Test/dtest.cs | 2 +- .../corlib/System.Threading/WaitHandle.cs | 31 ++-- mono/metadata/icall-def.h | 6 +- mono/metadata/threads-types.h | 6 +- mono/metadata/threads.c | 156 ++++-------------- 5 files changed, 55 insertions(+), 146 deletions(-) diff --git a/mcs/class/Mono.Debugger.Soft/Test/dtest.cs b/mcs/class/Mono.Debugger.Soft/Test/dtest.cs index 8d22ac808b2..7a16e5dcb83 100644 --- a/mcs/class/Mono.Debugger.Soft/Test/dtest.cs +++ b/mcs/class/Mono.Debugger.Soft/Test/dtest.cs @@ -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"); diff --git a/mcs/class/corlib/System.Threading/WaitHandle.cs b/mcs/class/corlib/System.Threading/WaitHandle.cs index dd91330355e..0e16f046e80 100644 --- a/mcs/class/corlib/System.Threading/WaitHandle.cs +++ b/mcs/class/corlib/System.Threading/WaitHandle.cs @@ -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) { diff --git a/mono/metadata/icall-def.h b/mono/metadata/icall-def.h index a77e1a7c00e..64c806a05f6 100644 --- a/mono/metadata/icall-def.h +++ b/mono/metadata/icall-def.h @@ -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)) diff --git a/mono/metadata/threads-types.h b/mono/metadata/threads-types.h index 59d4856629b..257266e21b6 100644 --- a/mono/metadata/threads-types.h +++ b/mono/metadata/threads-types.h @@ -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); diff --git a/mono/metadata/threads.c b/mono/metadata/threads.c index 60848191ddc..da85ec6e9a0 100644 --- a/mono/metadata/threads.c +++ b/mono/metadata/threads.c @@ -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 (); -- 2.25.1