From 4a8ae92a2535aa59915c6872e63111f57abebe9b Mon Sep 17 00:00:00 2001 From: Koundinya Veluri Date: Tue, 27 Sep 2016 13:14:24 -0700 Subject: [PATCH] Expose some members of the Thread class - Added RuntimeThread class that Thread derives from. An instance of RuntimeThread will be used by the Thread class in CoreFX to forward thread functionality to the runtime. - Some functionality in the RuntimeThread could potentially be moved to CoreFX. In particular, some of thread creation and apartment state handling could probably be moved with some minimal help from the runtime. Leaving that refactoring for later. - A few things are left unimplemented (for instance, apartment state handling doesn't work currently). That functionality will be enabled in a future change. Part of dotnet/corefxdotnet/coreclr#11632, dotnet/corefxdotnet/coreclr#11638, dotnet/corefxdotnet/coreclr#11635 Commit migrated from https://github.com/dotnet/coreclr/commit/007d910f7e97c277bcc0681298384bb79ed32d81 --- src/coreclr/src/mscorlib/model.xml | 37 +++++++++++++++ .../src/mscorlib/mscorlib.shared.sources.props | 2 + src/coreclr/src/mscorlib/ref/mscorlib.cs | 40 ++++++++++++++++- .../Internal/Runtime/Augments/IRuntimeThread.cs | 26 +++++++++++ .../Runtime/Augments/RuntimeThreadAugments.cs | 22 +++++++++ .../src/System/Threading/ExecutionContext.cs | 2 +- .../src/mscorlib/src/System/Threading/Thread.cs | 52 +++++++++++++++++++--- .../src/mscorlib/src/System/_LocalDataStoreMgr.cs | 22 +++++---- 8 files changed, 187 insertions(+), 16 deletions(-) create mode 100644 src/coreclr/src/mscorlib/src/Internal/Runtime/Augments/IRuntimeThread.cs create mode 100644 src/coreclr/src/mscorlib/src/Internal/Runtime/Augments/RuntimeThreadAugments.cs diff --git a/src/coreclr/src/mscorlib/model.xml b/src/coreclr/src/mscorlib/model.xml index 54915fe..91030ee 100644 --- a/src/coreclr/src/mscorlib/model.xml +++ b/src/coreclr/src/mscorlib/model.xml @@ -3560,6 +3560,8 @@ + + @@ -7828,6 +7830,12 @@ + + + + + + @@ -7993,6 +8001,27 @@ + + + + + + + + + + + + + + + + + + + + + @@ -8017,6 +8046,14 @@ + + + + + + + + diff --git a/src/coreclr/src/mscorlib/mscorlib.shared.sources.props b/src/coreclr/src/mscorlib/mscorlib.shared.sources.props index 066e670..18efb07 100644 --- a/src/coreclr/src/mscorlib/mscorlib.shared.sources.props +++ b/src/coreclr/src/mscorlib/mscorlib.shared.sources.props @@ -458,6 +458,8 @@ + + diff --git a/src/coreclr/src/mscorlib/ref/mscorlib.cs b/src/coreclr/src/mscorlib/ref/mscorlib.cs index 1231d89..e3b0f02 100644 --- a/src/coreclr/src/mscorlib/ref/mscorlib.cs +++ b/src/coreclr/src/mscorlib/ref/mscorlib.cs @@ -15,6 +15,29 @@ namespace Internal.Runtime.Augments public static void FailFast(string message, System.Exception error) { } public static string[] GetCommandLineArgs() { throw null; } } + public partial interface IRuntimeThread + { + System.Threading.ExecutionContext ExecutionContext { get; } + System.Threading.ApartmentState GetApartmentState(); + void Interrupt(); + bool IsAlive { get; } + bool IsBackground { get; set; } + bool IsThreadPoolThread { get; } + int ManagedThreadId { get; } + string Name { get; set; } + System.Threading.ThreadPriority Priority { get; set; } + System.Threading.ThreadState ThreadState { get; } + bool TrySetApartmentState(System.Threading.ApartmentState state); + } + public static partial class RuntimeThreadAugments + { + public static Internal.Runtime.Augments.IRuntimeThread Create(System.Threading.ThreadStart start) { throw null; } + public static Internal.Runtime.Augments.IRuntimeThread Create(System.Threading.ThreadStart start, int maxStackSize) { throw null; } + public static Internal.Runtime.Augments.IRuntimeThread Create(System.Threading.ParameterizedThreadStart start) { throw null; } + public static Internal.Runtime.Augments.IRuntimeThread Create(System.Threading.ParameterizedThreadStart start, int maxStackSize) { throw null; } + public static Internal.Runtime.Augments.IRuntimeThread CurrentThread { get { throw null; } } + public static void SpinWait(int iterations) { throw null; } + } } namespace Microsoft.Win32.SafeHandles { @@ -2483,7 +2506,8 @@ namespace System [System.Runtime.InteropServices.ComVisibleAttribute(true)] public sealed partial class LocalDataStoreSlot { - internal LocalDataStoreSlot() { } + internal LocalDataStoreSlot(object mgr, int slot, long cookie) { } + internal object Manager { get { throw null; } } ~LocalDataStoreSlot() { } } [System.Runtime.InteropServices.ComVisibleAttribute(true)] @@ -12836,6 +12860,12 @@ namespace System.Threading public System.Threading.Mutex Mutex { get { throw null; } } public int MutexIndex { get { throw null; } } } + public enum ApartmentState + { + MTA = 1, + STA = 0, + Unknown = 2, + } public sealed partial class AsyncLocal { public AsyncLocal() { } @@ -13336,6 +13366,14 @@ namespace System.Threading [System.Security.Permissions.SecurityPermissionAttribute(System.Security.Permissions.SecurityAction.Demand, ControlThread=true)] public static bool SetMinThreads(int workerThreads, int completionPortThreads) { throw null; } } + public enum ThreadPriority + { + AboveNormal = 3, + BelowNormal = 1, + Highest = 4, + Lowest = 0, + Normal = 2, + } [System.Runtime.InteropServices.ComVisibleAttribute(true)] public delegate void ThreadStart(); public sealed partial class ThreadStartException : System.SystemException diff --git a/src/coreclr/src/mscorlib/src/Internal/Runtime/Augments/IRuntimeThread.cs b/src/coreclr/src/mscorlib/src/Internal/Runtime/Augments/IRuntimeThread.cs new file mode 100644 index 0000000..a724341 --- /dev/null +++ b/src/coreclr/src/mscorlib/src/Internal/Runtime/Augments/IRuntimeThread.cs @@ -0,0 +1,26 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Threading; + +namespace Internal.Runtime.Augments +{ + public interface IRuntimeThread + { + ExecutionContext ExecutionContext { get; } + bool IsAlive { get; } + bool IsBackground { get; set; } + bool IsThreadPoolThread { get; } + int ManagedThreadId { get; } + string Name { get; set; } + ThreadPriority Priority { get; set; } + ThreadState ThreadState { get; } + + ApartmentState GetApartmentState(); + bool TrySetApartmentState(ApartmentState state); + + void Interrupt(); + } +} diff --git a/src/coreclr/src/mscorlib/src/Internal/Runtime/Augments/RuntimeThreadAugments.cs b/src/coreclr/src/mscorlib/src/Internal/Runtime/Augments/RuntimeThreadAugments.cs new file mode 100644 index 0000000..3a71a14 --- /dev/null +++ b/src/coreclr/src/mscorlib/src/Internal/Runtime/Augments/RuntimeThreadAugments.cs @@ -0,0 +1,22 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Threading; + +namespace Internal.Runtime.Augments +{ + /// For internal use only. Exposes runtime functionality to the Thread implementation in corefx. + public static class RuntimeThreadAugments + { + public static IRuntimeThread CurrentThread => Thread.CurrentThread; + + public static IRuntimeThread Create(ThreadStart start) => new Thread(start); + public static IRuntimeThread Create(ThreadStart start, int maxStackSize) => new Thread(start, maxStackSize); + public static IRuntimeThread Create(ParameterizedThreadStart start) => new Thread(start); + public static IRuntimeThread Create(ParameterizedThreadStart start, int maxStackSize) + => new Thread(start, maxStackSize); + public static void SpinWait(int iterations) => Thread.SpinWait(iterations); + } +} diff --git a/src/coreclr/src/mscorlib/src/System/Threading/ExecutionContext.cs b/src/coreclr/src/mscorlib/src/System/Threading/ExecutionContext.cs index 0440368..9a98133 100644 --- a/src/coreclr/src/mscorlib/src/System/Threading/ExecutionContext.cs +++ b/src/coreclr/src/mscorlib/src/System/Threading/ExecutionContext.cs @@ -65,7 +65,7 @@ namespace System.Threading public sealed class ExecutionContext : IDisposable { - private static readonly ExecutionContext Default = new ExecutionContext(); + internal static readonly ExecutionContext Default = new ExecutionContext(); private readonly Dictionary m_localValues; private readonly IAsyncLocal[] m_localChangeNotifications; diff --git a/src/coreclr/src/mscorlib/src/System/Threading/Thread.cs b/src/coreclr/src/mscorlib/src/System/Threading/Thread.cs index e62cfae..f35c45c 100644 --- a/src/coreclr/src/mscorlib/src/System/Threading/Thread.cs +++ b/src/coreclr/src/mscorlib/src/System/Threading/Thread.cs @@ -12,6 +12,8 @@ ** =============================================================================*/ +using Internal.Runtime.Augments; + namespace System.Threading { using System.Threading; using System.Runtime; @@ -122,7 +124,7 @@ namespace System.Threading { [ClassInterface(ClassInterfaceType.None)] [ComDefaultInterface(typeof(_Thread))] [System.Runtime.InteropServices.ComVisible(true)] - public sealed class Thread : CriticalFinalizerObject, _Thread + public sealed class Thread : CriticalFinalizerObject, _Thread, IRuntimeThread { /*========================================================================= ** Data accessed from managed code that needs to be defined in @@ -356,10 +358,21 @@ namespace System.Threading { #if FEATURE_CORECLR - internal ExecutionContext ExecutionContext + public ExecutionContext ExecutionContext { - get { return m_ExecutionContext; } - set { m_ExecutionContext = value; } + get + { + if (this == CurrentThread && m_ExecutionContext == null) + { + m_ExecutionContext = ExecutionContext.Default; + } + return m_ExecutionContext; + } + internal set + { + Contract.Assert(this == CurrentThread); + m_ExecutionContext = value; + } } internal SynchronizationContext SynchronizationContext @@ -539,7 +552,22 @@ namespace System.Threading { [MethodImplAttribute(MethodImplOptions.InternalCall)] private extern void AbortInternal(); -#if !FEATURE_CORECLR +#if FEATURE_CORECLR + /*========================================================================= + ** Interrupts a thread that is inside a Wait(), Sleep() or Join(). If that + ** thread is not currently blocked in that manner, it will be interrupted + ** when it next begins to block. + =========================================================================*/ + [System.Security.SecuritySafeCritical] // auto-generated +#pragma warning disable 618 // obsolete types: SecurityPermissionAttribute, SecurityAction + [SecurityPermission(SecurityAction.Demand, ControlThread = true)] +#pragma warning restore 618 // obsolete types: SecurityPermissionAttribute, SecurityAction + public void Interrupt() + { + // TODO: implement + throw new NotImplementedException(); + } +#else // !FEATURE_CORECLR /*========================================================================= ** Resets a thread abort. ** Should be called by trusted code only @@ -608,7 +636,7 @@ namespace System.Threading { [System.Security.SecurityCritical] // auto-generated [MethodImplAttribute(MethodImplOptions.InternalCall)] private extern void InterruptInternal(); -#endif +#endif // FEATURE_CORECLR /*========================================================================= ** Returns the priority of the thread. @@ -888,20 +916,32 @@ namespace System.Threading { SetApartmentStateNative((int)value, true); } } +#endif // FEATURE_COMINTEROP_APARTMENT_SUPPORT [System.Security.SecuritySafeCritical] // auto-generated public ApartmentState GetApartmentState() { +#if FEATURE_COMINTEROP_APARTMENT_SUPPORT return (ApartmentState)GetApartmentStateNative(); +#else // !FEATURE_COMINTEROP_APARTMENT_SUPPORT + Contract.Assert(false); // the Thread class in CoreFX should have handled this case + return ApartmentState.MTA; +#endif // FEATURE_COMINTEROP_APARTMENT_SUPPORT } [System.Security.SecuritySafeCritical] // auto-generated [HostProtection(Synchronization=true, SelfAffectingThreading=true)] public bool TrySetApartmentState(ApartmentState state) { +#if FEATURE_COMINTEROP_APARTMENT_SUPPORT return SetApartmentStateHelper(state, false); +#else // !FEATURE_COMINTEROP_APARTMENT_SUPPORT + Contract.Assert(false); // the Thread class in CoreFX should have handled this case + return false; +#endif // FEATURE_COMINTEROP_APARTMENT_SUPPORT } +#if FEATURE_COMINTEROP_APARTMENT_SUPPORT [System.Security.SecuritySafeCritical] // auto-generated [HostProtection(Synchronization=true, SelfAffectingThreading=true)] public void SetApartmentState(ApartmentState state) diff --git a/src/coreclr/src/mscorlib/src/System/_LocalDataStoreMgr.cs b/src/coreclr/src/mscorlib/src/System/_LocalDataStoreMgr.cs index 6154138..3e3bece 100644 --- a/src/coreclr/src/mscorlib/src/System/_LocalDataStoreMgr.cs +++ b/src/coreclr/src/mscorlib/src/System/_LocalDataStoreMgr.cs @@ -26,12 +26,12 @@ namespace System { [System.Runtime.InteropServices.ComVisible(true)] public sealed class LocalDataStoreSlot { - private LocalDataStoreMgr m_mgr; + private object m_mgr; private int m_slot; private long m_cookie; // Construct the object to encapsulate the slot. - internal LocalDataStoreSlot(LocalDataStoreMgr mgr, int slot, long cookie) + internal LocalDataStoreSlot(object mgr, int slot, long cookie) { m_mgr = mgr; m_slot = slot; @@ -39,7 +39,7 @@ namespace System { } // Accessors for the two fields of this class. - internal LocalDataStoreMgr Manager + internal object Manager { get { @@ -58,22 +58,28 @@ namespace System { get { return m_cookie; - } + } } // Release the slot reserved by this object when this object goes away. ~LocalDataStoreSlot() { - LocalDataStoreMgr mgr = m_mgr; + object mgr = m_mgr; if (mgr == null) return; + LocalDataStoreMgr localDataStoreMgr = mgr as LocalDataStoreMgr; + if (localDataStoreMgr == null) + { + return; + } + int slot = m_slot; - // Mark the slot as free. - m_slot = -1; + // Mark the slot as free. + m_slot = -1; - mgr.FreeDataSlot(slot, m_cookie); + localDataStoreMgr.FreeDataSlot(slot, m_cookie); } } -- 2.7.4