Move Thread to shared CoreLib (#22744)
authorFilip Navara <filip.navara@gmail.com>
Wed, 27 Feb 2019 06:48:33 +0000 (07:48 +0100)
committerJan Kotas <jkotas@microsoft.com>
Wed, 27 Feb 2019 06:48:33 +0000 (22:48 -0800)
* Move Thread to shared CoreLib

* Remove all local variables from Thread in shared code

* Remove duplicate checks

* Port back CoreRT changes needed for shared code

* Fix missing culture initialization in ThreadStart()

* Adjust for shared WaitHandle

40 files changed:
src/System.Private.CoreLib/Resources/Strings.resx
src/System.Private.CoreLib/System.Private.CoreLib.csproj
src/System.Private.CoreLib/shared/Internal/Runtime/Augments/RuntimeThread.cs [new file with mode: 0644]
src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems
src/System.Private.CoreLib/shared/System/AppDomain.cs
src/System.Private.CoreLib/shared/System/AppDomainSetup.cs
src/System.Private.CoreLib/shared/System/Buffers/TlsOverPerCoreLockedStacksArrayPool.cs
src/System.Private.CoreLib/shared/System/CannotUnloadAppDomainException.cs
src/System.Private.CoreLib/shared/System/Collections/ArrayList.cs
src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventSource.cs
src/System.Private.CoreLib/shared/System/Environment.Unix.cs
src/System.Private.CoreLib/shared/System/Environment.WinRT.cs
src/System.Private.CoreLib/shared/System/LocalDataStoreSlot.cs
src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncMethodBuilder.cs
src/System.Private.CoreLib/shared/System/Security/IPermission.cs
src/System.Private.CoreLib/shared/System/Security/ISecurityEncodable.cs
src/System.Private.CoreLib/shared/System/Security/IStackWalk.cs
src/System.Private.CoreLib/shared/System/Security/PermissionSet.cs
src/System.Private.CoreLib/shared/System/Security/Permissions/PermissionState.cs
src/System.Private.CoreLib/shared/System/Security/Principal/IIdentity.cs
src/System.Private.CoreLib/shared/System/Security/Principal/PrincipalPolicy.cs
src/System.Private.CoreLib/shared/System/Security/SecurityElement.cs
src/System.Private.CoreLib/shared/System/Threading/ExecutionContext.cs
src/System.Private.CoreLib/shared/System/Threading/ReaderWriterLockSlim.cs
src/System.Private.CoreLib/shared/System/Threading/SemaphoreSlim.cs
src/System.Private.CoreLib/shared/System/Threading/SpinWait.cs
src/System.Private.CoreLib/shared/System/Threading/SynchronizationContext.cs
src/System.Private.CoreLib/shared/System/Threading/Tasks/ConcurrentExclusiveSchedulerPair.cs
src/System.Private.CoreLib/shared/System/Threading/Tasks/Task.cs
src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskContinuation.cs
src/System.Private.CoreLib/shared/System/Threading/Tasks/ThreadPoolTaskScheduler.cs
src/System.Private.CoreLib/shared/System/Threading/Thread.Unix.cs
src/System.Private.CoreLib/shared/System/Threading/Thread.Windows.cs
src/System.Private.CoreLib/shared/System/Threading/Thread.cs
src/System.Private.CoreLib/shared/System/Threading/ThreadPool.cs
src/System.Private.CoreLib/shared/System/Threading/Timer.cs
src/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeThread.cs [deleted file]
src/System.Private.CoreLib/src/System/Threading/Thread.CoreCLR.cs [moved from src/System.Private.CoreLib/src/System/Threading/Thread.cs with 51% similarity]
src/vm/ecalllist.h
tests/src/baseservices/threading/coverage/OSThreadId/OSThreadId.cs

index f769f6c..155cb43 100644 (file)
   <data name="AppDomain_AppBaseNotSet" xml:space="preserve">
     <value>The ApplicationBase must be set before retrieving this property.</value>
   </data>
+  <data name="AppDomain_Name" xml:space="preserve">
+    <value>Name:</value>
+  </data>
+  <data name="AppDomain_NoContextPolicies" xml:space="preserve">
+    <value>There are no context policies.</value>
+  </data>
+  <data name="AppDomain_Policy_PrincipalTwice" xml:space="preserve">
+    <value>Default principal object cannot be set twice.</value>
+  </data>
   <data name="AmbiguousImplementationException_NullMessage" xml:space="preserve">
     <value>Ambiguous implementation found.</value>
   </data>
   <data name="Arg_CannotMixComparisonInfrastructure" xml:space="preserve">
     <value>The usage of IKeyComparer and IHashCodeProvider/IComparer interfaces cannot be mixed; use one or the other.</value>
   </data>
+  <data name="Arg_CannotUnloadAppDomainException" xml:space="preserve">
+    <value>Attempt to unload the AppDomain failed.</value>
+  </data>
   <data name="Arg_CATypeResolutionFailed" xml:space="preserve">
     <value>Failed to resolve type from string "{0}" which was embedded in custom attribute blob.</value>
   </data>
   <data name="Arg_MustBeType" xml:space="preserve">
     <value>Type must be a type provided by the runtime.</value>
   </data>
+  <data name="Arg_MustBeTrue" xml:space="preserve">
+    <value>Argument must be true.</value>
+  </data>
   <data name="Arg_MustBeUInt16" xml:space="preserve">
     <value>Object must be of type UInt16.</value>
   </data>
   <data name="Argument_ArraysInvalid" xml:space="preserve">
     <value>Array or pointer types are not valid.</value>
   </data>
+  <data name="Argument_AttributeNamesMustBeUnique" xml:space="preserve">
+    <value>Attribute names must be unique.</value>
+  </data>
   <data name="Argument_BadAttributeOnInterfaceMethod" xml:space="preserve">
     <value>Interface method must be abstract and virtual.</value>
   </data>
   <data name="Argument_InvalidDigitSubstitution" xml:space="preserve">
     <value>The DigitSubstitution property must be of a valid member of the DigitShapes enumeration. Valid entries include Context, NativeNational or None.</value>
   </data>
+  <data name="Argument_InvalidElementName" xml:space="preserve">
+    <value>Invalid element name '{0}'.</value>
+  </data>
+  <data name="Argument_InvalidElementTag" xml:space="preserve">
+    <value>Invalid element tag '{0}'.</value>
+  </data>
+  <data name="Argument_InvalidElementText" xml:space="preserve">
+    <value>Invalid element text '{0}'.</value>
+  </data>
+  <data name="Argument_InvalidElementValue" xml:space="preserve">
+    <value>Invalid element value '{0}'.</value>
+  </data>
   <data name="Argument_InvalidEnum" xml:space="preserve">
     <value>The Enum type should contain one and only one instance field.</value>
   </data>
   <data name="ArgumentNull_Buffer" xml:space="preserve">
     <value>Buffer cannot be null.</value>
   </data>
+  <data name="ArgumentNull_Child" xml:space="preserve">
+    <value>Cannot have a null child.</value>
+  </data>
   <data name="ArgumentNull_Collection" xml:space="preserve">
     <value>Collection cannot be null.</value>
   </data>
   <data name="InvalidOperation_TypeNotCreated" xml:space="preserve">
     <value>Type has not been created.</value>
   </data>
+  <data name="InvalidOperation_UnderlyingArrayListChanged" xml:space="preserve">
+    <value>This range in the underlying list is invalid. A possible cause is that elements were removed.</value>
+  </data>
   <data name="InvalidOperation_UnknownEnumType" xml:space="preserve">
     <value>Unknown enum type.</value>
   </data>
   <data name="NotSupported_PIAInAppxProcess" xml:space="preserve">
     <value>A Primary Interop Assembly is not supported in AppX.</value>
   </data>
+  <data name="NotSupported_RangeCollection" xml:space="preserve">
+    <value>The specified operation is not supported on Ranges.</value>
+  </data>
   <data name="NotSupported_Reading" xml:space="preserve">
     <value>Accessor does not support reading.</value>
   </data>
   <data name="PlatformNotSupported_IExpando" xml:space="preserve">
     <value>Marshalling an IDispatchEx to an IReflect or IExpando is not supported on this platform.</value>
   </data>
+  <data name="PlatformNotSupported_AppDomains" xml:space="preserve">
+    <value>Secondary AppDomains are not supported on this platform.</value>
+  </data>
+  <data name="PlatformNotSupported_CAS" xml:space="preserve">
+    <value>Code Access Security is not supported on this platform.</value>
+  </data>
+  <data name="PlatformNotSupported_AppDomain_ResMon" xml:space="preserve">
+    <value>AppDomain resource monitoring is not supported on this platform.</value>
+  </data>
+  <data name="PlatformNotSupported_Principal" xml:space="preserve">
+    <value>Windows Principal functionality is not supported on this platform.</value>
+  </data>
+  <data name="PlatformNotSupported_ThreadAbort" xml:space="preserve">
+    <value>Thread abort is not supported on this platform.</value>
+  </data>
+  <data name="PlatformNotSupported_ThreadSuspend" xml:space="preserve">
+    <value>Thread suspend is not supported on this platform.</value>
+  </data>
   <data name="Policy_CannotLoadSemiTrustAssembliesDuringInit" xml:space="preserve">
     <value>All assemblies loaded as part of AppDomain initialization must be fully trusted.</value>
   </data>
   <data name="TaskT_TransitionToFinal_AlreadyCompleted" xml:space="preserve">
     <value>An attempt was made to transition a task to a final state when it had already completed.</value>
   </data>
+  <data name="Thread_ApartmentState_ChangeFailed" xml:space="preserve">
+    <value>Failed to set the specified COM apartment state.</value>
+  </data>
+  <data name="Thread_GetSetCompressedStack_NotSupported" xml:space="preserve">
+    <value>Use CompressedStack.(Capture/Run) instead.</value>
+  </data>
+  <data name="Thread_Operation_RequiresCurrentThread" xml:space="preserve">
+    <value>This operation must be performed on the same thread as that represented by the Thread instance.</value>
+  </data>
   <data name="Threading_AbandonedMutexException" xml:space="preserve">
     <value>The wait completed due to an abandoned mutex.</value>
   </data>
index 595ed87..55bf8b4 100644 (file)
   <!-- Sources -->
   <ItemGroup>
     <Compile Include="$(BclSourcesRoot)\Internal\Console.cs" />
-    <Compile Include="$(BclSourcesRoot)\Internal\Runtime\Augments\RuntimeThread.cs" />
     <Compile Include="$(BclSourcesRoot)\Microsoft\Win32\UnsafeNativeMethods.cs" />
     <Compile Include="$(BclSourcesRoot)\System\__Canon.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Activator.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Threading\Monitor.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Threading\Overlapped.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Threading\SynchronizationContext.CoreCLR.cs" />
-    <Compile Include="$(BclSourcesRoot)\System\Threading\Thread.cs" />
+    <Compile Include="$(BclSourcesRoot)\System\Threading\Thread.CoreCLR.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Threading\ThreadPool.CoreCLR.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Threading\Timer.CoreCLR.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Threading\WaitHandle.CoreCLR.cs" />
diff --git a/src/System.Private.CoreLib/shared/Internal/Runtime/Augments/RuntimeThread.cs b/src/System.Private.CoreLib/shared/Internal/Runtime/Augments/RuntimeThread.cs
new file mode 100644 (file)
index 0000000..5e811c0
--- /dev/null
@@ -0,0 +1,56 @@
+// 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.Diagnostics;
+using System.Runtime.CompilerServices;
+using System.Runtime.ConstrainedExecution;
+using System.Runtime.InteropServices;
+using System.Security;
+using System.Threading;
+
+namespace Internal.Runtime.Augments
+{
+    public class RuntimeThread : CriticalFinalizerObject
+    {
+        private Thread _thread;
+        [ThreadStatic]
+        private static RuntimeThread t_currentThread;
+
+        private RuntimeThread(Thread thread)
+        {
+            _thread = thread;
+        }
+
+        public static RuntimeThread Create(ThreadStart start) => new RuntimeThread(new Thread(start));
+        public static RuntimeThread Create(ThreadStart start, int maxStackSize) => new RuntimeThread(new Thread(start, maxStackSize));
+        public static RuntimeThread Create(ParameterizedThreadStart start) => new RuntimeThread(new Thread(start));
+        public static RuntimeThread Create(ParameterizedThreadStart start, int maxStackSize) => new RuntimeThread(new Thread(start, maxStackSize));
+
+        public static RuntimeThread CurrentThread => t_currentThread ?? (t_currentThread = new RuntimeThread(Thread.CurrentThread));
+
+        public bool IsAlive => _thread.IsAlive;
+        public bool IsBackground { get => _thread.IsBackground; set => _thread.IsBackground = value; }
+        public bool IsThreadPoolThread => _thread.IsThreadPoolThread;
+        public int ManagedThreadId => _thread.ManagedThreadId;
+        public string Name { get => _thread.Name; set => _thread.Name = value; }
+        public ThreadPriority Priority { get => _thread.Priority; set => _thread.Priority = value; }
+        public ThreadState ThreadState => _thread.ThreadState;
+
+        public ApartmentState GetApartmentState() => _thread.GetApartmentState();
+        public bool TrySetApartmentState(ApartmentState state) => _thread.TrySetApartmentState(state);
+        public void DisableComObjectEagerCleanup() => _thread.DisableComObjectEagerCleanup();
+        public void Interrupt() => _thread.Interrupt();
+        public void Join() => _thread.Join();
+        public bool Join(int millisecondsTimeout) => _thread.Join(millisecondsTimeout);
+
+        public static void Sleep(int millisecondsTimeout) => Thread.Sleep(millisecondsTimeout);
+        public static int GetCurrentProcessorId() => Thread.GetCurrentProcessorId();
+        public static void SpinWait(int iterations) => Thread.SpinWait(iterations);
+        public static bool Yield() => Thread.Yield();
+
+        public void Start() => _thread.Start();
+        public void Start(object parameter) => _thread.Start(parameter);
+    }
+}
index 0389fb6..77b9589 100644 (file)
@@ -21,6 +21,7 @@
   <ItemGroup>
     <Compile Include="$(MSBuildThisFileDirectory)Internal\IO\File.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Internal\Padding.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)Internal\Runtime\Augments\RuntimeThread.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Internal\Runtime\CompilerServices\Unsafe.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Internal\Threading\Tasks\AsyncCausalitySupport.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\SafeHandles\CriticalHandleMinusOneIsInvalid.cs" />
@@ -31,6 +32,8 @@
     <Compile Include="$(MSBuildThisFileDirectory)System\Action.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\AccessViolationException.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\AppContext.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\AppDomain.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\AppDomainSetup.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\ApplicationException.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\AggregateException.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\ArgumentException.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Buffers\Text\Utf8Parser\Utf8Parser.TimeSpanSplitter.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Byte.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\ByReference.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\CannotUnloadAppDomainException.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Char.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\CharEnumerator.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\CLSCompliantAttribute.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Collections\ArrayList.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Collections\Comparer.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Collections\Concurrent\ConcurrentQueue.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Collections\Concurrent\ConcurrentQueueSegment.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Lazy.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\LocalAppContextSwitches.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\LocalAppContextSwitches.Common.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\LocalDataStoreSlot.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Marvin.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Marvin.OrdinalIgnoreCase.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Math.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\SByte.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Security\AllowPartiallyTrustedCallersAttribute.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Security\CryptographicException.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Security\IPermission.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Security\ISecurityEncodable.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Security\IStackWalk.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Security\PartialTrustVisibilityLevel.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Security\PermissionSet.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Security\Permissions\PermissionState.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Security\Principal\IIdentity.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Security\Principal\IPrincipal.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Security\Principal\PrincipalPolicy.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Security\SecureString.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Security\SecurityCriticalAttribute.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Security\SecurityCriticalScope.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Security\SecurityElement.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Security\SecurityException.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Security\SecurityRulesAttribute.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Security\SecurityRuleSet.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Threading\CancellationToken.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Threading\CancellationTokenRegistration.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Threading\CancellationTokenSource.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Threading\CompressedStack.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Threading\DeferredDisposableLifetime.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Threading\EventResetMode.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Threading\EventWaitHandle.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Threading\SpinWait.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Threading\SynchronizationContext.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Threading\SynchronizationLockException.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Threading\Thread.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Threading\ThreadLocal.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Threading\Volatile.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Threading\Tasks\AsyncCausalityTracerConstants.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\MemoryFailPoint.Windows.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\Marshal.Windows.cs" Condition="'$(TargetsCoreRT)' != 'true'" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Security\SecureString.Windows.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Threading\Thread.Windows.cs" />
   </ItemGroup>
   <ItemGroup Condition="'$(FeatureAsyncCausalityTracer)' != 'true'">
     <Compile Include="$(MSBuildThisFileDirectory)System\Threading\Tasks\AsyncCausalityTracer.Noop.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\MemoryFailPoint.Unix.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\Marshal.Unix.cs" Condition="'$(TargetsCoreRT)' != 'true'" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Security\SecureString.Unix.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Threading\Thread.Unix.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\TimeZoneInfo.Unix.cs" />
   </ItemGroup>
   <ItemGroup Condition="$(TargetsUnix) or '$(EnableWinRT)'=='true'">
index 93f6a2b..fe3706b 100644 (file)
@@ -16,6 +16,9 @@ using System.Threading;
 
 namespace System
 {
+#if PROJECTN
+    [Internal.Runtime.CompilerServices.RelocatedType("System.Runtime.Extensions")]
+#endif
     public sealed partial class AppDomain : MarshalByRefObject
     {
         private static readonly AppDomain s_domain = new AppDomain();
@@ -85,7 +88,7 @@ namespace System
             }
             if (assemblyName.Length == 0 || assemblyName[0] == '\0')
             {
-                throw new ArgumentException(SR.ZeroLengthString);
+                throw new ArgumentException(SR.Argument_StringZeroLength, nameof(assemblyName));
             }
 
             return assemblyName;
@@ -120,7 +123,7 @@ namespace System
             MethodInfo entry = assembly.EntryPoint;
             if (entry == null)
             {
-                throw new MissingMethodException(SR.EntryPointNotFound + assembly.FullName);
+                throw new MissingMethodException(SR.Arg_EntryPointNotFoundException);
             }
 
             object result = entry.Invoke(
@@ -165,7 +168,7 @@ namespace System
             {
                 throw new ArgumentNullException(nameof(domain));
             }
-            throw new CannotUnloadAppDomainException(SR.NotSupported_Platform);
+            throw new CannotUnloadAppDomainException(SR.Arg_PlatformNotSupported);
         }
 
         public Assembly Load(byte[] rawAssembly) => Assembly.Load(rawAssembly);
index 2b8e71e..c278e72 100644 (file)
@@ -4,6 +4,9 @@
 
 namespace System
 {
+#if PROJECTN
+    [Internal.Runtime.CompilerServices.RelocatedType("System.Runtime.Extensions")]
+#endif
     public sealed class AppDomainSetup
     {
         internal AppDomainSetup() { }
index 3b65ccb..1a933a5 100644 (file)
@@ -6,7 +6,6 @@ using System;
 using System.Collections.Generic;
 using System.Runtime.CompilerServices;
 using System.Threading;
-using Internal.Runtime.Augments;
 using Internal.Runtime.CompilerServices;
 
 namespace System.Buffers
@@ -346,7 +345,7 @@ namespace System.Buffers
                 // Try to push on to the associated stack first.  If that fails,
                 // round-robin through the other stacks.
                 LockedStack[] stacks = _perCoreStacks;
-                int index = RuntimeThread.GetCurrentProcessorId() % stacks.Length;
+                int index = Thread.GetCurrentProcessorId() % stacks.Length;
                 for (int i = 0; i < stacks.Length; i++)
                 {
                     if (stacks[index].TryPush(array)) return;
@@ -362,7 +361,7 @@ namespace System.Buffers
                 // round-robin through the other stacks.
                 T[] arr;
                 LockedStack[] stacks = _perCoreStacks;
-                int index = RuntimeThread.GetCurrentProcessorId() % stacks.Length;
+                int index = Thread.GetCurrentProcessorId() % stacks.Length;
                 for (int i = 0; i < stacks.Length; i++)
                 {
                     if ((arr = stacks[index].TryPop()) != null) return arr;
index f8dce02..9a4fb14 100644 (file)
@@ -8,6 +8,9 @@ namespace System
 {
     [Serializable]
     [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
+#if PROJECTN
+    [Internal.Runtime.CompilerServices.RelocatedType("System.Runtime.Extensions")]
+#endif
     public class CannotUnloadAppDomainException : SystemException
     {
         internal const int COR_E_CANNOTUNLOADAPPDOMAIN = unchecked((int)0x80131015); // corresponds to __HResults.COR_E_CANNOTUNLOADAPPDOMAIN in corelib
index 124df2b..d2ccc23 100644 (file)
@@ -28,6 +28,9 @@ namespace System.Collections
     [DebuggerDisplay("Count = {Count}")]
     [Serializable]
     [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
+#if PROJECTN
+    [Internal.Runtime.CompilerServices.RelocatedType("System.Runtime.Extensions")]
+#endif
     public class ArrayList : IList, ICloneable
     {
         private object[] _items; // Do not rename (binary serialization)
@@ -449,7 +452,7 @@ namespace System.Collections
         public virtual void Insert(int index, object value)
         {
             // Note that insertions at the end are legal.
-            if (index < 0 || index > _size) throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_ArrayListInsert);
+            if (index < 0 || index > _size) throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_Index);
 
             if (_size == _items.Length) EnsureCapacity(_size + 1);
             if (index < _size)
index 47cc8f7..0a1eb78 100644 (file)
@@ -182,7 +182,6 @@ using System.Security.Permissions;
 using System.Text;
 using System.Threading;
 using Microsoft.Win32;
-using Internal.Runtime.Augments;
 
 #if ES_BUILD_STANDALONE
 using EventDescriptor = Microsoft.Diagnostics.Tracing.EventDescriptor;
@@ -2803,11 +2802,7 @@ namespace System.Diagnostics.Tracing
                     // 5 chunks, so only the largest manifests will hit the pause.
                     if ((envelope.ChunkNumber % 5) == 0)
                     {
-#if ES_BUILD_STANDALONE
                         Thread.Sleep(15);
-#else
-                        RuntimeThread.Sleep(15);
-#endif
                     }
                 }
             }
@@ -4685,7 +4680,7 @@ namespace System.Diagnostics.Tracing
             {
                 if (!m_osThreadId.HasValue)
                 {
-                    m_osThreadId = (long)RuntimeThread.CurrentOSThreadId;
+                    m_osThreadId = (long)Thread.CurrentOSThreadId;
                 }
 
                 return m_osThreadId.Value;
index 65a0260..00b5029 100644 (file)
@@ -2,7 +2,6 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
-using Internal.Runtime.Augments;
 using System.Collections;
 using System.Collections.Generic;
 using System.Diagnostics;
index a8e3dbc..3d86829 100644 (file)
@@ -3,7 +3,6 @@
 // See the LICENSE file in the project root for more information.
 
 using System.IO;
-using Internal.Runtime.Augments;
 
 namespace System
 {
index dae59bc..ae9a741 100644 (file)
@@ -6,6 +6,9 @@ using System.Threading;
 
 namespace System
 {
+#if PROJECTN
+    [Internal.Runtime.CompilerServices.RelocatedType("System.Threading.Thread")]
+#endif
     public sealed class LocalDataStoreSlot
     {
         internal LocalDataStoreSlot(ThreadLocal<object> data)
index aef62e8..6f38bdb 100644 (file)
@@ -19,10 +19,6 @@ using System.Threading.Tasks;
 using System.Text;
 using Internal.Runtime.CompilerServices;
 
-#if CORERT
-using Thread = Internal.Runtime.Augments.RuntimeThread;
-#endif
-
 namespace System.Runtime.CompilerServices
 {
     /// <summary>
index a882c0f..cfdf1eb 100644 (file)
@@ -4,6 +4,9 @@
 
 namespace System.Security
 {
+#if PROJECTN
+    [Internal.Runtime.CompilerServices.RelocatedType("System.Runtime.Extensions")]
+#endif
     public partial interface IPermission : ISecurityEncodable
     {
         IPermission Copy();
index 844bb04..62cdb3f 100644 (file)
@@ -4,6 +4,9 @@
 
 namespace System.Security
 {
+#if PROJECTN
+    [Internal.Runtime.CompilerServices.RelocatedType("System.Runtime.Extensions")]
+#endif
     public partial interface ISecurityEncodable
     {
         void FromXml(SecurityElement e);
index f8d472e..9e6986a 100644 (file)
@@ -4,6 +4,9 @@
 
 namespace System.Security
 {
+#if PROJECTN
+    [Internal.Runtime.CompilerServices.RelocatedType("System.Runtime.Extensions")]
+#endif
     public partial interface IStackWalk
     {
         void Assert();
index 5c07248..9de469d 100644 (file)
@@ -8,6 +8,9 @@ using System.Runtime.Serialization;
 
 namespace System.Security
 {
+#if PROJECTN
+    [Internal.Runtime.CompilerServices.RelocatedType("System.Runtime.Extensions")]
+#endif
     public partial class PermissionSet : ICollection, IEnumerable, IDeserializationCallback, ISecurityEncodable, IStackWalk
     {
         public PermissionSet(PermissionState state) { }
index aace3dc..3ce1e70 100644 (file)
@@ -4,6 +4,9 @@
 
 namespace System.Security.Permissions
 {
+#if PROJECTN
+    [Internal.Runtime.CompilerServices.RelocatedType("System.Runtime.Extensions")]
+#endif
     public enum PermissionState
     {
         None = 0,
index a25a976..177f2b8 100644 (file)
@@ -10,6 +10,9 @@ using System;
 
 namespace System.Security.Principal
 {
+#if PROJECTN
+    [Internal.Runtime.CompilerServices.RelocatedType("System.Security.Principal")]
+#endif
     public interface IIdentity
     {
         // Access to the name string
index 53a8ba7..3884b10 100644 (file)
@@ -9,6 +9,9 @@
 
 namespace System.Security.Principal
 {
+#if PROJECTN
+    [Internal.Runtime.CompilerServices.RelocatedType("System.Security.Principal")]
+#endif
     public enum PrincipalPolicy 
     {
         // Note: it's important that the default policy has the value 0.
index 7af11e9..9b0b37f 100644 (file)
@@ -10,6 +10,9 @@ using System.Text;
 
 namespace System.Security
 {
+#if PROJECTN
+    [Internal.Runtime.CompilerServices.RelocatedType("System.Runtime.Extensions")]
+#endif
     internal interface ISecurityElementFactory
     {
         SecurityElement CreateSecurityElement();
@@ -21,6 +24,9 @@ namespace System.Security
         string Attribute(string attributeName);
     }
 
+#if PROJECTN
+    [Internal.Runtime.CompilerServices.RelocatedType("System.Runtime.Extensions")]
+#endif
     public sealed class SecurityElement : ISecurityElementFactory
     {
         internal string _tag;
index 348bb2d..2529997 100644 (file)
@@ -16,8 +16,6 @@ using System.Runtime.CompilerServices;
 using System.Runtime.ExceptionServices;
 using System.Runtime.Serialization;
 
-using Thread = Internal.Runtime.Augments.RuntimeThread;
-
 namespace System.Threading
 {
     public delegate void ContextCallback(object state);
index 9424fbd..9776871 100644 (file)
@@ -2,7 +2,6 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
-using Internal.Runtime.Augments;
 using System.Diagnostics; // for TraceInformation
 using System.Runtime.CompilerServices;
 
@@ -1241,11 +1240,11 @@ namespace System.Threading
             //Exponential back-off
             if ((spinCount < 5) && (ProcessorCount > 1))
             {
-                RuntimeThread.SpinWait(LockSpinCycles * spinCount);
+                Thread.SpinWait(LockSpinCycles * spinCount);
             }
             else
             {
-                RuntimeThread.Sleep(0);
+                Thread.Sleep(0);
             }
 
             // Don't want to Sleep(1) in this spin wait:
@@ -1592,15 +1591,15 @@ namespace System.Threading
                 {
                     if (spinIndex < LockSpinCount && processorCount > 1)
                     {
-                        RuntimeThread.SpinWait(LockSpinCycles * (spinIndex + 1)); // Wait a few dozen instructions to let another processor release lock.
+                        Thread.SpinWait(LockSpinCycles * (spinIndex + 1)); // Wait a few dozen instructions to let another processor release lock.
                     }
                     else if (spinIndex < (LockSpinCount + LockSleep0Count))
                     {
-                        RuntimeThread.Sleep(0);   // Give up my quantum.
+                        Thread.Sleep(0);   // Give up my quantum.
                     }
                     else
                     {
-                        RuntimeThread.Sleep(1);   // Give up my quantum.
+                        Thread.Sleep(1);   // Give up my quantum.
                     }
 
                     if (!IsEnterDeprioritized(reason))
index d726353..c7dacef 100644 (file)
@@ -5,8 +5,6 @@
 using System.Diagnostics;
 using System.Threading.Tasks;
 
-using Thread = Internal.Runtime.Augments.RuntimeThread;
-
 namespace System.Threading
 {
     /// <summary>
index 01e71d1..88b4b41 100644 (file)
@@ -9,7 +9,6 @@
 // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 
 using System.Diagnostics;
-using Internal.Runtime.Augments;
 
 namespace System.Threading
 {
@@ -195,18 +194,18 @@ namespace System.Threading
 
                 if (_count >= sleep1Threshold && sleep1Threshold >= 0)
                 {
-                    RuntimeThread.Sleep(1);
+                    Thread.Sleep(1);
                 }
                 else
                 {
                     int yieldsSoFar = _count >= YieldThreshold ? (_count - YieldThreshold) / 2 : _count;
                     if ((yieldsSoFar % Sleep0EveryHowManyYields) == (Sleep0EveryHowManyYields - 1))
                     {
-                        RuntimeThread.Sleep(0);
+                        Thread.Sleep(0);
                     }
                     else
                     {
-                        RuntimeThread.Yield();
+                        Thread.Yield();
                     }
                 }
             }
@@ -228,15 +227,15 @@ namespace System.Threading
                 // allow other useful work to run. Long YieldProcessor() loops can help to reduce contention, but Sleep(1) is
                 // usually better for that.
                 //
-                // RuntimeThread.OptimalMaxSpinWaitsPerSpinIteration:
+                // Thread.OptimalMaxSpinWaitsPerSpinIteration:
                 //   - See Thread::InitializeYieldProcessorNormalized(), which describes and calculates this value.
                 //
-                int n = RuntimeThread.OptimalMaxSpinWaitsPerSpinIteration;
+                int n = Thread.OptimalMaxSpinWaitsPerSpinIteration;
                 if (_count <= 30 && (1 << _count) < n)
                 {
                     n = 1 << _count;
                 }
-                RuntimeThread.SpinWait(n);
+                Thread.SpinWait(n);
             }
 
             // Finally, increment our spin counter.
index 33e025d..6f8bddf 100644 (file)
@@ -2,8 +2,6 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
-using Thread = Internal.Runtime.Augments.RuntimeThread;
-
 namespace System.Threading
 {
     public partial class SynchronizationContext
index e207a74..df7c934 100644 (file)
@@ -18,8 +18,6 @@ using System.Collections.Generic;
 using System.Diagnostics;
 using System.Diagnostics.CodeAnalysis;
 
-using Thread = Internal.Runtime.Augments.RuntimeThread;
-
 namespace System.Threading.Tasks
 {
     /// <summary>
index 5ad074c..a4c9619 100644 (file)
@@ -16,13 +16,8 @@ using System.Diagnostics;
 using System.Diagnostics.Tracing;
 using System.Runtime.CompilerServices;
 using System.Runtime.ExceptionServices;
-using Internal.Runtime.Augments;
 using Internal.Runtime.CompilerServices;
 
-#if CORERT
-using Thread = Internal.Runtime.Augments.RuntimeThread;
-#endif
-
 namespace System.Threading.Tasks
 {
     /// <summary>
index 034d19d..63ae2bd 100644 (file)
@@ -7,10 +7,6 @@ using System.Diagnostics;
 using System.Runtime.ExceptionServices;
 using System.Runtime.CompilerServices;
 
-#if CORERT
-using Thread = Internal.Runtime.Augments.RuntimeThread;
-#endif
-
 namespace System.Threading.Tasks
 {
     // Task type used to implement: Task ContinueWith(Action<Task,...>)
index 339a9d8..9ab28ef 100644 (file)
@@ -17,8 +17,6 @@ using System.Diagnostics;
 using System.Collections.Generic;
 using System.Text;
 
-using Internal.Runtime.Augments;
-
 namespace System.Threading.Tasks
 {
     /// <summary>
@@ -47,7 +45,7 @@ namespace System.Threading.Tasks
             if ((options & TaskCreationOptions.LongRunning) != 0)
             {
                 // Run LongRunning tasks on their own dedicated thread.
-                RuntimeThread thread = RuntimeThread.Create(s_longRunningThreadWork);
+                Thread thread = new Thread(s_longRunningThreadWork);
                 thread.IsBackground = true; // Keep this thread from blocking process shutdown
                 thread.Start(task);
             }
index 252969e..902fcf2 100644 (file)
@@ -8,10 +8,6 @@ namespace System.Threading
 {
     public sealed partial class Thread
     {
-        public ApartmentState GetApartmentState() => ApartmentState.Unknown;
-        private static Exception GetApartmentStateChangeFailedException() => new PlatformNotSupportedException(SR.PlatformNotSupported_COMInterop);
-        private bool TrySetApartmentStateUnchecked(ApartmentState state) => state == GetApartmentState();
-
-        public void DisableComObjectEagerCleanup() { }
+        private static Exception GetApartmentStateChangeFailedException() => new PlatformNotSupportedException(SR.PlatformNotSupported_ComInterop);
     }
 }
index 6738158..44e5f38 100644 (file)
@@ -8,11 +8,7 @@ namespace System.Threading
 {
     public sealed partial class Thread
     {
-        public ApartmentState GetApartmentState() => _runtimeThread.GetApartmentState();
         private static Exception GetApartmentStateChangeFailedException() =>
             new InvalidOperationException(SR.Thread_ApartmentState_ChangeFailed);
-        private bool TrySetApartmentStateUnchecked(ApartmentState state) => _runtimeThread.TrySetApartmentState(state);
-
-        public void DisableComObjectEagerCleanup() => _runtimeThread.DisableComObjectEagerCleanup();
     }
 }
index e9e654a..0705daa 100644 (file)
@@ -2,7 +2,6 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
-using Internal.Runtime.Augments;
 using System.Collections.Generic;
 using System.Diagnostics;
 using System.Globalization;
@@ -11,36 +10,26 @@ using System.Security.Principal;
 
 namespace System.Threading
 {
+#if PROJECTN
+    [Internal.Runtime.CompilerServices.RelocatedType("System.Threading.Thread")]
+#endif
     public sealed partial class Thread : CriticalFinalizerObject
     {
-        [ThreadStatic]
-        private static Thread t_currentThread;
         private static AsyncLocal<IPrincipal> s_asyncLocalPrincipal;
 
-        private readonly RuntimeThread _runtimeThread;
-        private Delegate _start;
-        private CultureInfo _startCulture;
-        private CultureInfo _startUICulture;
-
-        private Thread(RuntimeThread runtimeThread)
-        {
-            Debug.Assert(runtimeThread != null);
-            _runtimeThread = runtimeThread;
-        }
-
         public Thread(ThreadStart start)
+            : this()
         {
             if (start == null)
             {
                 throw new ArgumentNullException(nameof(start));
             }
 
-            _runtimeThread = RuntimeThread.Create(ThreadMain_ThreadStart);
-            Debug.Assert(_runtimeThread != null);
-            _start = start;
+            Create(start);
         }
 
         public Thread(ThreadStart start, int maxStackSize)
+            : this()
         {
             if (start == null)
             {
@@ -48,27 +37,25 @@ namespace System.Threading
             }
             if (maxStackSize < 0)
             {
-                throw new ArgumentOutOfRangeException(nameof(maxStackSize), SR.ArgumentOutOfRange_NeedNonnegativeNumber);
+                throw new ArgumentOutOfRangeException(nameof(maxStackSize), SR.ArgumentOutOfRange_NeedNonNegNum);
             }
 
-            _runtimeThread = RuntimeThread.Create(ThreadMain_ThreadStart, maxStackSize);
-            Debug.Assert(_runtimeThread != null);
-            _start = start;
+            Create(start, maxStackSize);
         }
 
         public Thread(ParameterizedThreadStart start)
+            : this()
         {
             if (start == null)
             {
                 throw new ArgumentNullException(nameof(start));
             }
 
-            _runtimeThread = RuntimeThread.Create(ThreadMain_ParameterizedThreadStart);
-            Debug.Assert(_runtimeThread != null);
-            _start = start;
+            Create(start);
         }
 
         public Thread(ParameterizedThreadStart start, int maxStackSize)
+            : this()
         {
             if (start == null)
             {
@@ -76,57 +63,10 @@ namespace System.Threading
             }
             if (maxStackSize < 0)
             {
-                throw new ArgumentOutOfRangeException(nameof(maxStackSize), SR.ArgumentOutOfRange_NeedNonnegativeNumber);
-            }
-
-            _runtimeThread = RuntimeThread.Create(ThreadMain_ParameterizedThreadStart, maxStackSize);
-            Debug.Assert(_runtimeThread != null);
-            _start = start;
-        }
-
-        private Delegate InitializeNewThread()
-        {
-            t_currentThread = this;
-
-            Delegate start = _start;
-            _start = null;
-
-            if (_startCulture != null)
-            {
-                CultureInfo.CurrentCulture = _startCulture;
-                _startCulture = null;
+                throw new ArgumentOutOfRangeException(nameof(maxStackSize), SR.ArgumentOutOfRange_NeedNonNegNum);
             }
 
-            if (_startUICulture != null)
-            {
-                CultureInfo.CurrentUICulture = _startUICulture;
-                _startUICulture = null;
-            }
-
-            return start;
-        }
-
-        private void ThreadMain_ThreadStart()
-        {
-            ((ThreadStart)InitializeNewThread())();
-        }
-
-        private void ThreadMain_ParameterizedThreadStart(object parameter)
-        {
-            ((ParameterizedThreadStart)InitializeNewThread())(parameter);
-        }
-
-        public static Thread CurrentThread
-        {
-            get
-            {
-                Thread currentThread = t_currentThread;
-                if (currentThread == null)
-                {
-                    t_currentThread = currentThread = new Thread(RuntimeThread.CurrentThread);
-                }
-                return currentThread;
-            }
+            Create(start, maxStackSize);
         }
 
         private void RequireCurrentThread()
@@ -137,17 +77,17 @@ namespace System.Threading
             }
         }
 
-        private void SetCultureOnUnstartedThread(CultureInfo value, ref CultureInfo culture)
+        private void SetCultureOnUnstartedThread(CultureInfo value, bool uiCulture)
         {
             if (value == null)
             {
                 throw new ArgumentNullException(nameof(value));
             }
-            if ((_runtimeThread.ThreadState & ThreadState.Unstarted) == 0)
+            if ((ThreadState & ThreadState.Unstarted) == 0)
             {
                 throw new InvalidOperationException(SR.Thread_Operation_RequiresCurrentThread);
             }
-            culture = value;
+            SetCultureOnUnstartedThreadNoCheck(value, uiCulture);
         }
 
         public CultureInfo CurrentCulture
@@ -161,7 +101,7 @@ namespace System.Threading
             {
                 if (this != CurrentThread)
                 {
-                    SetCultureOnUnstartedThread(value, ref _startCulture);
+                    SetCultureOnUnstartedThread(value, uiCulture: false);
                     return;
                 }
                 CultureInfo.CurrentCulture = value;
@@ -179,7 +119,7 @@ namespace System.Threading
             {
                 if (this != CurrentThread)
                 {
-                    SetCultureOnUnstartedThread(value, ref _startUICulture);
+                    SetCultureOnUnstartedThread(value, uiCulture: true);
                     return;
                 }
                 CultureInfo.CurrentUICulture = value;
@@ -210,15 +150,6 @@ namespace System.Threading
             }
         }
 
-        public ExecutionContext ExecutionContext => ExecutionContext.Capture();
-        public bool IsAlive => _runtimeThread.IsAlive;
-        public bool IsBackground { get { return _runtimeThread.IsBackground; } set { _runtimeThread.IsBackground = value; } }
-        public bool IsThreadPoolThread => _runtimeThread.IsThreadPoolThread;
-        public int ManagedThreadId => _runtimeThread.ManagedThreadId;
-        public string Name { get { return _runtimeThread.Name; } set { _runtimeThread.Name = value; } }
-        public ThreadPriority Priority { get { return _runtimeThread.Priority; } set { _runtimeThread.Priority = value; } }
-        public ThreadState ThreadState => _runtimeThread.ThreadState;
-
         public void Abort()
         {
             throw new PlatformNotSupportedException(SR.PlatformNotSupported_ThreadAbort);
@@ -297,16 +228,6 @@ namespace System.Threading
             return TrySetApartmentStateUnchecked(state);
         }
 
-        private static int ToTimeoutMilliseconds(TimeSpan timeout)
-        {
-            var timeoutMilliseconds = (long)timeout.TotalMilliseconds;
-            if (timeoutMilliseconds < -1 || timeoutMilliseconds > int.MaxValue)
-            {
-                throw new ArgumentOutOfRangeException(nameof(timeout), SR.ArgumentOutOfRange_TimeoutMilliseconds);
-            }
-            return (int)timeoutMilliseconds;
-        }
-
         [Obsolete("Thread.GetCompressedStack is no longer supported. Please use the System.Threading.CompressedStack class")]
         public CompressedStack GetCompressedStack()
         {
@@ -319,21 +240,13 @@ namespace System.Threading
             throw new InvalidOperationException(SR.Thread_GetSetCompressedStack_NotSupported);
         }
 
-        public static int GetCurrentProcessorId() => RuntimeThread.GetCurrentProcessorId();
         public static AppDomain GetDomain() => AppDomain.CurrentDomain;
-        public static int GetDomainID() => GetDomain().Id;
+        public static int GetDomainID() => 1;
         public override int GetHashCode() => ManagedThreadId;
-        public void Interrupt() => _runtimeThread.Interrupt();
-        public void Join() => _runtimeThread.Join();
-        public bool Join(int millisecondsTimeout) => _runtimeThread.Join(millisecondsTimeout);
-        public bool Join(TimeSpan timeout) => Join(ToTimeoutMilliseconds(timeout));
+        public void Join() => Join(-1);
+        public bool Join(TimeSpan timeout) => Join(WaitHandle.ToTimeoutMilliseconds(timeout));
         public static void MemoryBarrier() => Interlocked.MemoryBarrier();
-        public static void Sleep(int millisecondsTimeout) => RuntimeThread.Sleep(millisecondsTimeout);
-        public static void Sleep(TimeSpan timeout) => Sleep(ToTimeoutMilliseconds(timeout));
-        public static void SpinWait(int iterations) => RuntimeThread.SpinWait(iterations);
-        public static bool Yield() => RuntimeThread.Yield();
-        public void Start() => _runtimeThread.Start();
-        public void Start(object parameter) => _runtimeThread.Start(parameter);
+        public static void Sleep(TimeSpan timeout) => Sleep(WaitHandle.ToTimeoutMilliseconds(timeout));
 
         public static byte VolatileRead(ref byte address) => Volatile.Read(ref address);
         public static double VolatileRead(ref double address) => Volatile.Read(ref address);
index ffcab54..017a8e7 100644 (file)
@@ -22,8 +22,6 @@ using System.Runtime.InteropServices;
 using System.Threading.Tasks;
 using Internal.Runtime.CompilerServices;
 
-using Thread = Internal.Runtime.Augments.RuntimeThread;
-
 namespace System.Threading
 {
     internal static class ThreadPoolGlobals
index 3dfb5d9..180bcb5 100644 (file)
@@ -2,13 +2,10 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
-using Internal.Runtime.Augments;
 using System.Diagnostics;
 using System.Diagnostics.Tracing;
 using System.Threading.Tasks;
 
-using Thread = Internal.Runtime.Augments.RuntimeThread;
-
 namespace System.Threading
 {
     public delegate void TimerCallback(object state);
@@ -446,7 +443,7 @@ namespace System.Threading
             {
                 _executionContext = ExecutionContext.Capture();
             }
-            _associatedTimerQueue = TimerQueue.Instances[RuntimeThread.GetCurrentProcessorId() % TimerQueue.Instances.Length];
+            _associatedTimerQueue = TimerQueue.Instances[Thread.GetCurrentProcessorId() % TimerQueue.Instances.Length];
 
             // After the following statement, the timer may fire.  No more manipulation of timer state outside of
             // the lock is permitted beyond this point!
diff --git a/src/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeThread.cs b/src/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeThread.cs
deleted file mode 100644 (file)
index 89e6396..0000000
+++ /dev/null
@@ -1,287 +0,0 @@
-// 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.Diagnostics;
-using System.Runtime.CompilerServices;
-using System.Runtime.ConstrainedExecution;
-using System.Runtime.InteropServices;
-using System.Security;
-using System.Threading;
-
-namespace Internal.Runtime.Augments
-{
-    public class RuntimeThread : CriticalFinalizerObject
-    {
-        private static int s_optimalMaxSpinWaitsPerSpinIteration;
-
-        internal RuntimeThread() { }
-
-        public static RuntimeThread Create(ThreadStart start) => new Thread(start);
-        public static RuntimeThread Create(ThreadStart start, int maxStackSize) => new Thread(start, maxStackSize);
-        public static RuntimeThread Create(ParameterizedThreadStart start) => new Thread(start);
-        public static RuntimeThread Create(ParameterizedThreadStart start, int maxStackSize) => new Thread(start, maxStackSize);
-
-        private Thread AsThread()
-        {
-            Debug.Assert(this is Thread);
-            return (Thread)this;
-        }
-
-        public static RuntimeThread CurrentThread => Thread.CurrentThread;
-
-        /*=========================================================================
-        ** Returns true if the thread has been started and is not dead.
-        =========================================================================*/
-        public extern bool IsAlive
-        {
-            [MethodImpl(MethodImplOptions.InternalCall)]
-            get;
-        }
-
-        /*=========================================================================
-        ** Return whether or not this thread is a background thread.  Background
-        ** threads do not affect when the Execution Engine shuts down.
-        **
-        ** Exceptions: ThreadStateException if the thread is dead.
-        =========================================================================*/
-        public bool IsBackground
-        {
-            get { return IsBackgroundNative(); }
-            set { SetBackgroundNative(value); }
-        }
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private extern bool IsBackgroundNative();
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private extern void SetBackgroundNative(bool isBackground);
-
-        /*=========================================================================
-        ** Returns true if the thread is a threadpool thread.
-        =========================================================================*/
-        public extern bool IsThreadPoolThread
-        {
-            [MethodImpl(MethodImplOptions.InternalCall)]
-            get;
-        }
-
-        public int ManagedThreadId => AsThread().ManagedThreadId;
-        public string Name { get { return AsThread().Name; } set { AsThread().Name = value; } }
-
-        /*=========================================================================
-        ** Returns the priority of the thread.
-        **
-        ** Exceptions: ThreadStateException if the thread is dead.
-        =========================================================================*/
-        public ThreadPriority Priority
-        {
-            get { return (ThreadPriority)GetPriorityNative(); }
-            set { SetPriorityNative((int)value); }
-        }
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private extern int GetPriorityNative();
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private extern void SetPriorityNative(int priority);
-
-        /*=========================================================================
-        ** Returns the operating system identifier for the current thread.
-        =========================================================================*/
-        internal static ulong CurrentOSThreadId
-        {
-            get
-            {
-                return GetCurrentOSThreadId();
-            }
-        }
-        [DllImport(JitHelpers.QCall)]
-        private static extern ulong GetCurrentOSThreadId();
-
-        /*=========================================================================
-        ** Return the thread state as a consistent set of bits.  This is more
-        ** general then IsAlive or IsBackground.
-        =========================================================================*/
-        public ThreadState ThreadState
-        {
-            get { return (ThreadState)GetThreadStateNative(); }
-        }
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private extern int GetThreadStateNative();
-
-        public ApartmentState GetApartmentState()
-        {
-#if FEATURE_COMINTEROP_APARTMENT_SUPPORT
-            return (ApartmentState)GetApartmentStateNative();
-#else // !FEATURE_COMINTEROP_APARTMENT_SUPPORT
-            Debug.Assert(false); // the Thread class in CoreFX should have handled this case
-            return ApartmentState.MTA;
-#endif // FEATURE_COMINTEROP_APARTMENT_SUPPORT
-        }
-
-        /*=========================================================================
-        ** An unstarted thread can be marked to indicate that it will host a
-        ** single-threaded or multi-threaded apartment.
-        =========================================================================*/
-        public bool TrySetApartmentState(ApartmentState state)
-        {
-#if FEATURE_COMINTEROP_APARTMENT_SUPPORT
-            return SetApartmentStateHelper(state, false);
-#else // !FEATURE_COMINTEROP_APARTMENT_SUPPORT
-            Debug.Assert(false); // the Thread class in CoreFX should have handled this case
-            return false;
-#endif // FEATURE_COMINTEROP_APARTMENT_SUPPORT
-        }
-
-#if FEATURE_COMINTEROP_APARTMENT_SUPPORT
-        internal bool SetApartmentStateHelper(ApartmentState state, bool fireMDAOnMismatch)
-        {
-            ApartmentState retState = (ApartmentState)SetApartmentStateNative((int)state, fireMDAOnMismatch);
-
-            // Special case where we pass in Unknown and get back MTA.
-            //  Once we CoUninitialize the thread, the OS will still
-            //  report the thread as implicitly in the MTA if any
-            //  other thread in the process is CoInitialized.
-            if ((state == System.Threading.ApartmentState.Unknown) && (retState == System.Threading.ApartmentState.MTA))
-                return true;
-
-            if (retState != state)
-                return false;
-
-            return true;
-        }
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        internal extern int GetApartmentStateNative();
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        internal extern int SetApartmentStateNative(int state, bool fireMDAOnMismatch);
-#endif // FEATURE_COMINTEROP_APARTMENT_SUPPORT
-
-#if FEATURE_COMINTEROP
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        public extern void DisableComObjectEagerCleanup();
-#else // !FEATURE_COMINTEROP
-        public void DisableComObjectEagerCleanup()
-        {
-            Debug.Assert(false); // the Thread class in CoreFX should have handled this case
-        }
-#endif // FEATURE_COMINTEROP
-
-        /*=========================================================================
-        ** 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.
-        =========================================================================*/
-        public void Interrupt() => InterruptInternal();
-
-        // Internal helper (since we can't place security demands on
-        // ecalls/fcalls).
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private extern void InterruptInternal();
-
-        /*=========================================================================
-        ** Waits for the thread to die or for timeout milliseconds to elapse.
-        ** Returns true if the thread died, or false if the wait timed out. If
-        ** Timeout.Infinite is given as the parameter, no timeout will occur.
-        **
-        ** Exceptions: ArgumentException if timeout < -1 (Timeout.Infinite).
-        **             ThreadInterruptedException if the thread is interrupted while waiting.
-        **             ThreadStateException if the thread has not been started yet.
-        =========================================================================*/
-        public void Join() => JoinInternal(Timeout.Infinite);
-
-        public bool Join(int millisecondsTimeout) => JoinInternal(millisecondsTimeout);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private extern bool JoinInternal(int millisecondsTimeout);
-
-        public static void Sleep(int millisecondsTimeout) => Thread.Sleep(millisecondsTimeout);
-
-        [DllImport(JitHelpers.QCall)]
-        private static extern int GetOptimalMaxSpinWaitsPerSpinIterationInternal();
-
-        /// <summary>
-        /// Max value to be passed into <see cref="SpinWait(int)"/> for optimal delaying. This value is normalized to be
-        /// appropriate for the processor.
-        /// </summary>
-        internal static int OptimalMaxSpinWaitsPerSpinIteration
-        {
-            get
-            {
-                if (s_optimalMaxSpinWaitsPerSpinIteration != 0)
-                {
-                    return s_optimalMaxSpinWaitsPerSpinIteration;
-                }
-
-                // This is done lazily because the first call to the function below in the process triggers a measurement that
-                // takes a nontrivial amount of time if the measurement has not already been done in the backgorund.
-                // See Thread::InitializeYieldProcessorNormalized(), which describes and calculates this value.
-                s_optimalMaxSpinWaitsPerSpinIteration = GetOptimalMaxSpinWaitsPerSpinIterationInternal();
-                Debug.Assert(s_optimalMaxSpinWaitsPerSpinIteration > 0);
-                return s_optimalMaxSpinWaitsPerSpinIteration;
-            }
-        }
-
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        private static extern int GetCurrentProcessorNumber();
-
-        // The upper bits of t_currentProcessorIdCache are the currentProcessorId. The lower bits of
-        // the t_currentProcessorIdCache are counting down to get it periodically refreshed.
-        // TODO: Consider flushing the currentProcessorIdCache on Wait operations or similar 
-        // actions that are likely to result in changing the executing core
-        [ThreadStatic]
-        private static int t_currentProcessorIdCache;
-
-        private const int ProcessorIdCacheShift = 16;
-        private const int ProcessorIdCacheCountDownMask = (1 << ProcessorIdCacheShift) - 1;
-        private const int ProcessorIdRefreshRate = 5000;
-
-        private static int RefreshCurrentProcessorId()
-        {
-            int currentProcessorId = GetCurrentProcessorNumber();
-
-            // On Unix, GetCurrentProcessorNumber() is implemented in terms of sched_getcpu, which
-            // doesn't exist on all platforms.  On those it doesn't exist on, GetCurrentProcessorNumber()
-            // returns -1.  As a fallback in that case and to spread the threads across the buckets
-            // by default, we use the current managed thread ID as a proxy.
-            if (currentProcessorId < 0) currentProcessorId = Environment.CurrentManagedThreadId;
-
-            // Add offset to make it clear that it is not guaranteed to be 0-based processor number
-            currentProcessorId += 100;
-
-            Debug.Assert(ProcessorIdRefreshRate <= ProcessorIdCacheCountDownMask);
-
-            // Mask with int.MaxValue to ensure the execution Id is not negative
-            t_currentProcessorIdCache = ((currentProcessorId << ProcessorIdCacheShift) & int.MaxValue) | ProcessorIdRefreshRate;
-
-            return currentProcessorId;
-        }
-
-        // Cached processor id used as a hint for which per-core stack to access. It is periodically
-        // refreshed to trail the actual thread core affinity.
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static int GetCurrentProcessorId()
-        {
-            int currentProcessorIdCache = t_currentProcessorIdCache--;
-            if ((currentProcessorIdCache & ProcessorIdCacheCountDownMask) == 0)
-                return RefreshCurrentProcessorId();
-            return (currentProcessorIdCache >> ProcessorIdCacheShift);
-        }
-
-        public static void SpinWait(int iterations) => Thread.SpinWait(iterations);
-        public static bool Yield() => Thread.Yield();
-
-        public void Start() => AsThread().Start();
-        public void Start(object parameter) => AsThread().Start(parameter);
-
-        public void ResetThreadPoolThread()
-        {
-            // Currently implemented in unmanaged method Thread::InternalReset and
-            // called internally from the ThreadPool in NotifyWorkItemComplete.
-        }
-    }
-}
@@ -2,35 +2,26 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
-//
-/*=============================================================================
-**
-**
-**
-** Purpose: Class for creating and managing a thread.
-**
-**
-=============================================================================*/
-
-using Internal.Runtime.Augments;
+using System;
+using System.Diagnostics;
+using System.Globalization;
+using System.Runtime.CompilerServices;
+using System.Runtime.ConstrainedExecution;
+using System.Runtime.InteropServices;
 
 namespace System.Threading
 {
-    using System.Runtime.InteropServices;
-    using System;
-    using System.Globalization;
-    using System.Runtime.CompilerServices;
-    using System.Runtime.ConstrainedExecution;
-    using System.Diagnostics;
-
     internal class ThreadHelper
     {
         private Delegate _start;
+        internal CultureInfo _startCulture;
+        internal CultureInfo _startUICulture;
         private object _startArg = null;
         private ExecutionContext _executionContext = null;
+
         internal ThreadHelper(Delegate start)
         {
-            _start = start;
+            _start = start; 
         }
 
         internal void SetExecutionContextHelper(ExecutionContext ec)
@@ -53,10 +44,28 @@ namespace System.Threading
             }
         }
 
+        private void InitializeCulture()
+        {
+            if (_startCulture != null)
+            {
+                CultureInfo.CurrentCulture = _startCulture;
+                _startCulture = null;
+            }
+
+            if (_startUICulture != null)
+            {
+                CultureInfo.CurrentUICulture = _startUICulture;
+                _startUICulture = null;
+            }
+        }
+
         // call back helper
         internal void ThreadStart(object obj)
         {
             _startArg = obj;
+
+            InitializeCulture();
+
             ExecutionContext context = _executionContext;
             if (context != null)
             {
@@ -71,6 +80,8 @@ namespace System.Threading
         // call back helper
         internal void ThreadStart()
         {
+            InitializeCulture();
+
             ExecutionContext context = _executionContext;
             if (context != null)
             {
@@ -93,7 +104,7 @@ namespace System.Threading
         }
     }
 
-    internal sealed class Thread : RuntimeThread
+    public sealed partial class Thread
     {
         /*=========================================================================
         ** Data accessed from managed code that needs to be defined in
@@ -143,51 +154,27 @@ namespace System.Threading
         **
         ** Exceptions: ArgumentNullException if start == null.
         =========================================================================*/
-        public Thread(ThreadStart start)
+        private void Create(ThreadStart start)
         {
-            if (start == null)
-            {
-                throw new ArgumentNullException(nameof(start));
-            }
             SetStartHelper((Delegate)start, 0);  //0 will setup Thread with default stackSize
         }
 
-        internal Thread(ThreadStart start, int maxStackSize)
+        private void Create(ThreadStart start, int maxStackSize)
         {
-            if (start == null)
-            {
-                throw new ArgumentNullException(nameof(start));
-            }
-            if (0 > maxStackSize)
-                throw new ArgumentOutOfRangeException(nameof(maxStackSize), SR.ArgumentOutOfRange_NeedNonNegNum);
             SetStartHelper((Delegate)start, maxStackSize);
         }
-        public Thread(ParameterizedThreadStart start)
+
+        private void Create(ParameterizedThreadStart start)
         {
-            if (start == null)
-            {
-                throw new ArgumentNullException(nameof(start));
-            }
             SetStartHelper((Delegate)start, 0);
         }
 
-        internal Thread(ParameterizedThreadStart start, int maxStackSize)
+        private void Create(ParameterizedThreadStart start, int maxStackSize)
         {
-            if (start == null)
-            {
-                throw new ArgumentNullException(nameof(start));
-            }
-            if (0 > maxStackSize)
-                throw new ArgumentOutOfRangeException(nameof(maxStackSize), SR.ArgumentOutOfRange_NeedNonNegNum);
             SetStartHelper((Delegate)start, maxStackSize);
         }
 
-        public override int GetHashCode()
-        {
-            return _managedThreadId;
-        }
-
-        public extern new int ManagedThreadId
+        public extern int ManagedThreadId
         {
             [MethodImplAttribute(MethodImplOptions.InternalCall)]
             get;
@@ -215,7 +202,7 @@ namespace System.Threading
         **
         ** Exceptions: ThreadStateException if the thread has already been started.
         =========================================================================*/
-        public new void Start(object parameter)
+        public void Start(object parameter)
         {
             //In the case of a null delegate (second call to start on same thread)
             //    StartInternal method will take care of the error reporting
@@ -230,7 +217,7 @@ namespace System.Threading
             Start();
         }
 
-        public new void Start()
+        public void Start()
         {
 #if FEATURE_COMINTEROP_APARTMENT_SUPPORT
             // Eagerly initialize the COM Apartment state of the thread if we're allowed to.
@@ -252,6 +239,21 @@ namespace System.Threading
             StartInternal();
         }
 
+        private void SetCultureOnUnstartedThreadNoCheck(CultureInfo value, bool uiCulture)
+        {
+            Debug.Assert(m_Delegate != null);
+
+            ThreadHelper t = (ThreadHelper)(m_Delegate.Target);
+            if (uiCulture)
+            {
+                t._startUICulture = value;
+            }
+            else
+            {
+                t._startCulture = value;
+            }
+        }
+
         internal ExecutionContext ExecutionContext
         {
             get { return m_ExecutionContext; }
@@ -285,20 +287,11 @@ namespace System.Threading
         [MethodImplAttribute(MethodImplOptions.InternalCall)]
         private static extern void SleepInternal(int millisecondsTimeout);
 
-        public static new void Sleep(int millisecondsTimeout)
+        public static void Sleep(int millisecondsTimeout)
         {
             SleepInternal(millisecondsTimeout);
         }
 
-        public static void Sleep(TimeSpan timeout)
-        {
-            long tm = (long)timeout.TotalMilliseconds;
-            if (tm < -1 || tm > (long)int.MaxValue)
-                throw new ArgumentOutOfRangeException(nameof(timeout), SR.ArgumentOutOfRange_NeedNonNegOrNegative1);
-            Sleep((int)tm);
-        }
-
-
         /* wait for a length of time proportional to 'iterations'.  Each iteration is should
            only take a few machine instructions.  Calling this API is preferable to coding
            a explicit busy loop because the hardware can be informed that it is busy waiting. */
@@ -306,7 +299,7 @@ namespace System.Threading
         [MethodImplAttribute(MethodImplOptions.InternalCall)]
         private static extern void SpinWaitInternal(int iterations);
 
-        public static new void SpinWait(int iterations)
+        public static void SpinWait(int iterations)
         {
             SpinWaitInternal(iterations);
         }
@@ -314,12 +307,12 @@ namespace System.Threading
         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
         private static extern bool YieldInternal();
 
-        internal static new bool Yield()
+        public static bool Yield()
         {
             return YieldInternal();
         }
 
-        public static new Thread CurrentThread => t_currentThread ?? InitializeCurrentThread();
+        public static Thread CurrentThread => t_currentThread ?? InitializeCurrentThread();
 
         [MethodImpl(MethodImplOptions.NoInlining)]
         private static Thread InitializeCurrentThread()
@@ -369,18 +362,9 @@ namespace System.Threading
         private extern void StartupSetApartmentStateInternal();
 #endif // FEATURE_COMINTEROP_APARTMENT_SUPPORT
 
-        /*
-         *  This returns a unique id to identify an appdomain.
-         */
-        internal static int GetDomainID()
-        {
-            return 1;
-        }
-
-
         // Retrieves the name of the thread.
         //
-        public new string Name
+        public string Name
         {
             get
             {
@@ -402,6 +386,242 @@ namespace System.Threading
         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
         private static extern void InformThreadNameChange(ThreadHandle t, string name, int len);
 
+        /*=========================================================================
+        ** Returns true if the thread has been started and is not dead.
+        =========================================================================*/
+        public extern bool IsAlive
+        {
+            [MethodImpl(MethodImplOptions.InternalCall)]
+            get;
+        }
+
+        /*=========================================================================
+        ** Return whether or not this thread is a background thread.  Background
+        ** threads do not affect when the Execution Engine shuts down.
+        **
+        ** Exceptions: ThreadStateException if the thread is dead.
+        =========================================================================*/
+        public bool IsBackground
+        {
+            get { return IsBackgroundNative(); }
+            set { SetBackgroundNative(value); }
+        }
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private extern bool IsBackgroundNative();
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private extern void SetBackgroundNative(bool isBackground);
+
+        /*=========================================================================
+        ** Returns true if the thread is a threadpool thread.
+        =========================================================================*/
+        public extern bool IsThreadPoolThread
+        {
+            [MethodImpl(MethodImplOptions.InternalCall)]
+            get;
+        }
+
+        /*=========================================================================
+        ** Returns the priority of the thread.
+        **
+        ** Exceptions: ThreadStateException if the thread is dead.
+        =========================================================================*/
+        public ThreadPriority Priority
+        {
+            get { return (ThreadPriority)GetPriorityNative(); }
+            set { SetPriorityNative((int)value); }
+        }
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private extern int GetPriorityNative();
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private extern void SetPriorityNative(int priority);
+
+        /*=========================================================================
+        ** Returns the operating system identifier for the current thread.
+        =========================================================================*/
+        internal static ulong CurrentOSThreadId
+        {
+            get
+            {
+                return GetCurrentOSThreadId();
+            }
+        }
+
+        [DllImport(JitHelpers.QCall)]
+        private static extern ulong GetCurrentOSThreadId();
+
+        /*=========================================================================
+        ** Return the thread state as a consistent set of bits.  This is more
+        ** general then IsAlive or IsBackground.
+        =========================================================================*/
+        public ThreadState ThreadState
+        {
+            get { return (ThreadState)GetThreadStateNative(); }
+        }
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private extern int GetThreadStateNative();
+
+        public ApartmentState GetApartmentState()
+        {
+#if FEATURE_COMINTEROP_APARTMENT_SUPPORT
+            return (ApartmentState)GetApartmentStateNative();
+#else // !FEATURE_COMINTEROP_APARTMENT_SUPPORT
+            Debug.Assert(false); // the Thread class in CoreFX should have handled this case
+            return ApartmentState.MTA;
+#endif // FEATURE_COMINTEROP_APARTMENT_SUPPORT
+        }
+
+        /*=========================================================================
+        ** An unstarted thread can be marked to indicate that it will host a
+        ** single-threaded or multi-threaded apartment.
+        =========================================================================*/
+        public bool TrySetApartmentStateUnchecked(ApartmentState state)
+        {
+#if FEATURE_COMINTEROP_APARTMENT_SUPPORT
+            return SetApartmentStateHelper(state, false);
+#else // !FEATURE_COMINTEROP_APARTMENT_SUPPORT
+            Debug.Assert(false); // the Thread class in CoreFX should have handled this case
+            return false;
+#endif // FEATURE_COMINTEROP_APARTMENT_SUPPORT
+        }
+
+#if FEATURE_COMINTEROP_APARTMENT_SUPPORT
+        internal bool SetApartmentStateHelper(ApartmentState state, bool fireMDAOnMismatch)
+        {
+            ApartmentState retState = (ApartmentState)SetApartmentStateNative((int)state, fireMDAOnMismatch);
+
+            // Special case where we pass in Unknown and get back MTA.
+            //  Once we CoUninitialize the thread, the OS will still
+            //  report the thread as implicitly in the MTA if any
+            //  other thread in the process is CoInitialized.
+            if ((state == System.Threading.ApartmentState.Unknown) && (retState == System.Threading.ApartmentState.MTA))
+                return true;
+
+            if (retState != state)
+                return false;
+
+            return true;
+        }
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal extern int GetApartmentStateNative();
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal extern int SetApartmentStateNative(int state, bool fireMDAOnMismatch);
+#endif // FEATURE_COMINTEROP_APARTMENT_SUPPORT
+
+#if FEATURE_COMINTEROP
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public extern void DisableComObjectEagerCleanup();
+#else // !FEATURE_COMINTEROP
+        public void DisableComObjectEagerCleanup()
+        {
+        }
+#endif // FEATURE_COMINTEROP
+
+        /// <summary>
+        /// 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.
+        /// </summary>
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public extern void Interrupt();
+
+        /// <summary>
+        /// Waits for the thread to die or for timeout milliseconds to elapse.
+        /// </summary>
+        /// <returns>
+        /// Returns true if the thread died, or false if the wait timed out. If
+        /// -1 is given as the parameter, no timeout will occur.
+        /// </returns>
+        /// <exception cref="ArgumentException">if timeout &lt; -1 (Timeout.Infinite)</exception>
+        /// <exception cref="ThreadInterruptedException">if the thread is interrupted while waiting</exception>
+        /// <exception cref="ThreadStateException">if the thread has not been started yet</exception>
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public extern bool Join(int millisecondsTimeout);
+
+        private static int s_optimalMaxSpinWaitsPerSpinIteration;
+
+        [DllImport(JitHelpers.QCall)]
+        private static extern int GetOptimalMaxSpinWaitsPerSpinIterationInternal();
+
+        /// <summary>
+        /// Max value to be passed into <see cref="SpinWait(int)"/> for optimal delaying. This value is normalized to be
+        /// appropriate for the processor.
+        /// </summary>
+        internal static int OptimalMaxSpinWaitsPerSpinIteration
+        {
+            get
+            {
+                if (s_optimalMaxSpinWaitsPerSpinIteration != 0)
+                {
+                    return s_optimalMaxSpinWaitsPerSpinIteration;
+                }
+
+                // This is done lazily because the first call to the function below in the process triggers a measurement that
+                // takes a nontrivial amount of time if the measurement has not already been done in the backgorund.
+                // See Thread::InitializeYieldProcessorNormalized(), which describes and calculates this value.
+                s_optimalMaxSpinWaitsPerSpinIteration = GetOptimalMaxSpinWaitsPerSpinIterationInternal();
+                Debug.Assert(s_optimalMaxSpinWaitsPerSpinIteration > 0);
+                return s_optimalMaxSpinWaitsPerSpinIteration;
+            }
+        }
+
+        [MethodImplAttribute(MethodImplOptions.InternalCall)]
+        private static extern int GetCurrentProcessorNumber();
+
+        // The upper bits of t_currentProcessorIdCache are the currentProcessorId. The lower bits of
+        // the t_currentProcessorIdCache are counting down to get it periodically refreshed.
+        // TODO: Consider flushing the currentProcessorIdCache on Wait operations or similar 
+        // actions that are likely to result in changing the executing core
+        [ThreadStatic]
+        private static int t_currentProcessorIdCache;
+
+        private const int ProcessorIdCacheShift = 16;
+        private const int ProcessorIdCacheCountDownMask = (1 << ProcessorIdCacheShift) - 1;
+        private const int ProcessorIdRefreshRate = 5000;
+
+        private static int RefreshCurrentProcessorId()
+        {
+            int currentProcessorId = GetCurrentProcessorNumber();
+
+            // On Unix, GetCurrentProcessorNumber() is implemented in terms of sched_getcpu, which
+            // doesn't exist on all platforms.  On those it doesn't exist on, GetCurrentProcessorNumber()
+            // returns -1.  As a fallback in that case and to spread the threads across the buckets
+            // by default, we use the current managed thread ID as a proxy.
+            if (currentProcessorId < 0) currentProcessorId = Environment.CurrentManagedThreadId;
+
+            // Add offset to make it clear that it is not guaranteed to be 0-based processor number
+            currentProcessorId += 100;
+
+            Debug.Assert(ProcessorIdRefreshRate <= ProcessorIdCacheCountDownMask);
+
+            // Mask with int.MaxValue to ensure the execution Id is not negative
+            t_currentProcessorIdCache = ((currentProcessorId << ProcessorIdCacheShift) & int.MaxValue) | ProcessorIdRefreshRate;
+
+            return currentProcessorId;
+        }
+
+        // Cached processor id used as a hint for which per-core stack to access. It is periodically
+        // refreshed to trail the actual thread core affinity.
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static int GetCurrentProcessorId()
+        {
+            int currentProcessorIdCache = t_currentProcessorIdCache--;
+            if ((currentProcessorIdCache & ProcessorIdCacheCountDownMask) == 0)
+                return RefreshCurrentProcessorId();
+            return (currentProcessorIdCache >> ProcessorIdCacheShift);
+        }
+
+        internal void ResetThreadPoolThread()
+        {
+            // Currently implemented in unmanaged method Thread::InternalReset and
+            // called internally from the ThreadPool in NotifyWorkItemComplete.
+        }
     } // End of class Thread
 
     // declaring a local var of this enum type and passing it by ref into a function that needs to do a
index 30492d1..43049a3 100644 (file)
@@ -620,7 +620,22 @@ FCFuncStart(gMathFFuncs)
     FCIntrinsic("Tanh", COMSingle::Tanh, CORINFO_INTRINSIC_Tanh)
 FCFuncEnd()
 
-FCFuncStart(gRuntimeThreadFuncs)
+FCFuncStart(gThreadFuncs)
+    FCDynamic("InternalGetCurrentThread", CORINFO_INTRINSIC_Illegal, ECall::InternalGetCurrentThread)
+    FCFuncElement("StartInternal", ThreadNative::Start)
+#undef Sleep
+    FCFuncElement("SleepInternal", ThreadNative::Sleep)
+#define Sleep(a) Dont_Use_Sleep(a)
+    FCFuncElement("SetStart", ThreadNative::SetStart)
+    QCFuncElement("InformThreadNameChange", ThreadNative::InformThreadNameChange)
+    FCFuncElement("SpinWaitInternal", ThreadNative::SpinWait)
+    QCFuncElement("YieldInternal", ThreadNative::YieldThread)
+    FCIntrinsic("GetCurrentThreadNative", ThreadNative::GetCurrentThread, CORINFO_INTRINSIC_GetCurrentManagedThread)
+    FCIntrinsic("get_ManagedThreadId", ThreadNative::GetManagedThreadId, CORINFO_INTRINSIC_GetManagedThreadId)
+    FCFuncElement("InternalFinalize", ThreadNative::Finalize)
+#ifdef FEATURE_COMINTEROP_APARTMENT_SUPPORT
+    FCFuncElement("StartupSetApartmentStateInternal", ThreadNative::StartupSetApartmentState)
+#endif // FEATURE_COMINTEROP_APARTMENT_SUPPORT
     FCFuncElement("get_IsAlive", ThreadNative::IsAlive)
     FCFuncElement("IsBackgroundNative", ThreadNative::IsBackground)
     FCFuncElement("SetBackgroundNative", ThreadNative::SetBackground)
@@ -636,30 +651,12 @@ FCFuncStart(gRuntimeThreadFuncs)
 #ifdef FEATURE_COMINTEROP
     FCFuncElement("DisableComObjectEagerCleanup", ThreadNative::DisableComObjectEagerCleanup)
 #endif // FEATURE_COMINTEROP
-    FCFuncElement("InterruptInternal", ThreadNative::Interrupt)
-    FCFuncElement("JoinInternal", ThreadNative::Join)
+    FCFuncElement("Interrupt", ThreadNative::Interrupt)
+    FCFuncElement("Join", ThreadNative::Join)
     QCFuncElement("GetOptimalMaxSpinWaitsPerSpinIterationInternal", ThreadNative::GetOptimalMaxSpinWaitsPerSpinIteration)
     FCFuncElement("GetCurrentProcessorNumber", ThreadNative::GetCurrentProcessorNumber)
 FCFuncEnd()
 
-FCFuncStart(gThreadFuncs)
-    FCDynamic("InternalGetCurrentThread", CORINFO_INTRINSIC_Illegal, ECall::InternalGetCurrentThread)
-    FCFuncElement("StartInternal", ThreadNative::Start)
-#undef Sleep
-    FCFuncElement("SleepInternal", ThreadNative::Sleep)
-#define Sleep(a) Dont_Use_Sleep(a)
-    FCFuncElement("SetStart", ThreadNative::SetStart)
-    QCFuncElement("InformThreadNameChange", ThreadNative::InformThreadNameChange)
-    FCFuncElement("SpinWaitInternal", ThreadNative::SpinWait)
-    QCFuncElement("YieldInternal", ThreadNative::YieldThread)
-    FCIntrinsic("GetCurrentThreadNative", ThreadNative::GetCurrentThread, CORINFO_INTRINSIC_GetCurrentManagedThread)
-    FCIntrinsic("get_ManagedThreadId", ThreadNative::GetManagedThreadId, CORINFO_INTRINSIC_GetManagedThreadId)
-    FCFuncElement("InternalFinalize", ThreadNative::Finalize)
-#ifdef FEATURE_COMINTEROP_APARTMENT_SUPPORT
-    FCFuncElement("StartupSetApartmentStateInternal", ThreadNative::StartupSetApartmentState)
-#endif // FEATURE_COMINTEROP_APARTMENT_SUPPORT
-FCFuncEnd()
-
 FCFuncStart(gThreadPoolFuncs)
     FCFuncElement("PostQueuedCompletionStatus", ThreadPoolNative::CorPostQueuedCompletionStatus)
     FCFuncElement("GetAvailableThreadsNative", ThreadPoolNative::CorGetAvailableThreads)
@@ -1269,7 +1266,6 @@ FCClassElement("RuntimeHelpers", "System.Runtime.CompilerServices", gRuntimeHelp
 FCClassElement("RuntimeImports", "System.Runtime", gRuntimeImportsFuncs)
 FCClassElement("RuntimeMethodHandle", "System", gRuntimeMethodHandle)
 FCClassElement("RuntimeModule", "System.Reflection", gCOMModuleFuncs)
-FCClassElement("RuntimeThread", "Internal.Runtime.Augments", gRuntimeThreadFuncs)
 FCClassElement("RuntimeType", "System", gSystem_RuntimeType)
 FCClassElement("RuntimeTypeHandle", "System", gCOMTypeHandleFuncs)
 FCClassElement("SafeTypeNameParserHandle", "System", gSafeTypeNameParserHandle)
index 85895a7..af9a055 100644 (file)
@@ -15,7 +15,7 @@ namespace Threading.Tests
         public static int Main(string[] args)
         {
             // The property to be tested is internal.
-            Type runtimeThreadType = typeof(object).Assembly.GetType("Internal.Runtime.Augments.RuntimeThread");
+            Type runtimeThreadType = typeof(object).Assembly.GetType("System.Threading.Thread");
             Assert(runtimeThreadType != null);
             PropertyInfo osThreadIdProperty = runtimeThreadType.GetProperty("CurrentOSThreadId", BindingFlags.NonPublic | BindingFlags.Static);
             Assert(osThreadIdProperty != null);