Expose some members of the Thread class
authorKoundinya Veluri <kouvel@microsoft.com>
Tue, 27 Sep 2016 20:14:24 +0000 (13:14 -0700)
committerKoundinya Veluri <kouvel@microsoft.com>
Wed, 12 Oct 2016 18:44:43 +0000 (11:44 -0700)
- 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
src/coreclr/src/mscorlib/mscorlib.shared.sources.props
src/coreclr/src/mscorlib/ref/mscorlib.cs
src/coreclr/src/mscorlib/src/Internal/Runtime/Augments/IRuntimeThread.cs [new file with mode: 0644]
src/coreclr/src/mscorlib/src/Internal/Runtime/Augments/RuntimeThreadAugments.cs [new file with mode: 0644]
src/coreclr/src/mscorlib/src/System/Threading/ExecutionContext.cs
src/coreclr/src/mscorlib/src/System/Threading/Thread.cs
src/coreclr/src/mscorlib/src/System/_LocalDataStoreMgr.cs

index 54915fe..91030ee 100644 (file)
       <Member MemberType="Property" Name="Value" />
     </Type>
     <Type Name="System.LocalDataStoreSlot">
+      <Member Status="ImplRoot" Name="#ctor(System.Object,System.Int32,System.Int64)" />
+      <Member Status="ImplRoot" Name="get_Manager" />
       <Member Status="ImplRoot" Name="Finalize" />
     </Type>
     <Type Name="System.MarshalByRefObject">
       <Member MemberType="Property" Name="Mutex" />
       <Member MemberType="Property" Name="MutexIndex" />
     </Type>
+    <Type Name="System.Threading.ApartmentState">
+      <Member MemberType="Field" Name="MTA" />
+      <Member MemberType="Field" Name="STA" />
+      <Member MemberType="Field" Name="Unknown" />
+      <Member MemberType="Field" Name="value__" />
+    </Type>
     <Type Name="System.Threading.AutoResetEvent">
       <Member Name="#ctor(System.Boolean)" />
     </Type>
       <Member Status="ImplRoot" MemberType="Field" Name="m_Priority" />
       <Member Status="ImplRoot" MemberType="Field" Name="m_ThreadStartArg" />
     </Type>
+    <Type Name="Internal.Runtime.Augments.IRuntimeThread">
+      <Member Name="GetApartmentState" />
+      <Member MemberType="Property" Name="ExecutionContext" />
+      <Member Name="Interrupt" />
+      <Member MemberType="Property" Name="IsAlive" />
+      <Member MemberType="Property" Name="IsBackground" />
+      <Member MemberType="Property" Name="IsThreadPoolThread" />
+      <Member MemberType="Property" Name="ManagedThreadId" />
+      <Member MemberType="Property" Name="Name" />
+      <Member MemberType="Property" Name="Priority" />
+      <Member MemberType="Property" Name="ThreadState" />
+      <Member Name="TrySetApartmentState(System.Threading.ApartmentState)" />
+    </Type>
+    <Type Name="Internal.Runtime.Augments.RuntimeThreadAugments">
+      <Member Name="Create(System.Threading.ThreadStart)" />
+      <Member Name="Create(System.Threading.ThreadStart,System.Int32)" />
+      <Member Name="Create(System.Threading.ParameterizedThreadStart)" />
+      <Member Name="Create(System.Threading.ParameterizedThreadStart,System.Int32)" />
+      <Member MemberType="Property" Name="CurrentThread" />
+      <Member Name="SpinWait(System.Int32)" />
+    </Type>
     <Type Name="System.Threading.ThreadAbortException">
       <Member Status="ImplRoot" Name="#ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)" />
     </Type>
       <Member Status="ImplRoot" Name="GetLocallyQueuedWorkItemsForDebugger"/>
       <Member Status="ImplRoot" Name="NotifyWorkItemProgress"/>
     </Type>
+    <Type Name="System.Threading.ThreadPriority">
+      <Member MemberType="Field" Name="AboveNormal" />
+      <Member MemberType="Field" Name="BelowNormal" />
+      <Member MemberType="Field" Name="Highest" />
+      <Member MemberType="Field" Name="Lowest" />
+      <Member MemberType="Field" Name="Normal" />
+      <Member MemberType="Field" Name="value__" />
+    </Type>
     <Type Status="ImplRoot"  Name="System.Threading.StackCrawlMark">
       <Member MemberType="Field" Name="LookForMe" />
       <Member MemberType="Field" Name="LookForMyCaller" />
index 066e670..18efb07 100644 (file)
   </ItemGroup>
   <ItemGroup>
     <InternalSources Condition="'$(FeatureCoreclr)' == 'true'" Include="$(BclSourcesRoot)\Internal\Runtime\Augments\EnvironmentAugments.cs" />
+    <InternalSources Condition="'$(FeatureCoreclr)' == 'true'" Include="$(BclSourcesRoot)\Internal\Runtime\Augments\IRuntimeThread.cs" />
+    <InternalSources Condition="'$(FeatureCoreclr)' == 'true'" Include="$(BclSourcesRoot)\Internal\Runtime\Augments\RuntimeThreadAugments.cs" />
   </ItemGroup>
   <ItemGroup>
     <ReflectionSources Include="$(BclSourcesRoot)\System\Reflection\__Filters.cs" />
index 1231d89..e3b0f02 100644 (file)
@@ -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<T>
     {
         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 (file)
index 0000000..a724341
--- /dev/null
@@ -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 (file)
index 0000000..3a71a14
--- /dev/null
@@ -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
+{
+    /// <summary>For internal use only.  Exposes runtime functionality to the Thread implementation in corefx.</summary>
+    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);
+    }
+}
index 0440368..9a98133 100644 (file)
@@ -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<IAsyncLocal, object> m_localValues;
         private readonly IAsyncLocal[] m_localChangeNotifications;
index e62cfae..f35c45c 100644 (file)
@@ -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)
index 6154138..3e3bece 100644 (file)
@@ -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);
         }
     }