1801 lines
77 KiB
C#
1801 lines
77 KiB
C#
// ==++==
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//
|
|
// ==--==
|
|
//
|
|
// <OWNER>[....]</OWNER>
|
|
/*=============================================================================
|
|
**
|
|
** Class: Thread
|
|
**
|
|
**
|
|
** Purpose: Class for creating and managing a thread.
|
|
**
|
|
**
|
|
=============================================================================*/
|
|
|
|
namespace System.Threading {
|
|
using System.Threading;
|
|
using System.Runtime;
|
|
using System.Runtime.InteropServices;
|
|
#if FEATURE_REMOTING
|
|
using System.Runtime.Remoting.Contexts;
|
|
#endif
|
|
using System.Runtime.Remoting.Messaging;
|
|
using System;
|
|
using System.Diagnostics;
|
|
using System.Security.Permissions;
|
|
using System.Security.Principal;
|
|
using System.Globalization;
|
|
using System.Collections.Generic;
|
|
using System.Runtime.Serialization;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Runtime.ConstrainedExecution;
|
|
using System.Security;
|
|
using System.Runtime.Versioning;
|
|
using System.Diagnostics.Contracts;
|
|
|
|
internal delegate Object InternalCrossContextDelegate(Object[] args);
|
|
|
|
internal class ThreadHelper
|
|
{
|
|
[System.Security.SecuritySafeCritical]
|
|
static ThreadHelper() {}
|
|
|
|
Delegate _start;
|
|
Object _startArg = null;
|
|
ExecutionContext _executionContext = null;
|
|
internal ThreadHelper(Delegate start)
|
|
{
|
|
_start = start;
|
|
}
|
|
|
|
internal void SetExecutionContextHelper(ExecutionContext ec)
|
|
{
|
|
_executionContext = ec;
|
|
}
|
|
|
|
[System.Security.SecurityCritical]
|
|
static internal ContextCallback _ccb = new ContextCallback(ThreadStart_Context);
|
|
|
|
[System.Security.SecurityCritical]
|
|
static private void ThreadStart_Context(Object state)
|
|
{
|
|
ThreadHelper t = (ThreadHelper)state;
|
|
if (t._start is ThreadStart)
|
|
{
|
|
((ThreadStart)t._start)();
|
|
}
|
|
else
|
|
{
|
|
((ParameterizedThreadStart)t._start)(t._startArg);
|
|
}
|
|
}
|
|
|
|
// call back helper
|
|
#if FEATURE_CORECLR
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
#else
|
|
[System.Security.SecurityCritical]
|
|
#endif
|
|
internal void ThreadStart(object obj)
|
|
{
|
|
_startArg = obj;
|
|
if (_executionContext != null)
|
|
{
|
|
ExecutionContext.Run(_executionContext, _ccb, (Object)this);
|
|
}
|
|
else
|
|
{
|
|
((ParameterizedThreadStart)_start)(obj);
|
|
}
|
|
}
|
|
|
|
// call back helper
|
|
#if FEATURE_CORECLR
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
#else
|
|
[System.Security.SecurityCritical]
|
|
#endif
|
|
internal void ThreadStart()
|
|
{
|
|
if (_executionContext != null)
|
|
{
|
|
ExecutionContext.Run(_executionContext, _ccb, (Object)this);
|
|
}
|
|
else
|
|
{
|
|
((ThreadStart)_start)();
|
|
}
|
|
}
|
|
}
|
|
#if !MONO
|
|
internal struct ThreadHandle
|
|
{
|
|
private IntPtr m_ptr;
|
|
|
|
internal ThreadHandle(IntPtr pThread)
|
|
{
|
|
m_ptr = pThread;
|
|
}
|
|
}
|
|
#endif
|
|
// deliberately not [serializable]
|
|
[ClassInterface(ClassInterfaceType.None)]
|
|
[ComDefaultInterface(typeof(_Thread))]
|
|
[System.Runtime.InteropServices.ComVisible(true)]
|
|
public sealed partial class Thread : CriticalFinalizerObject
|
|
#if !MOBILE
|
|
, _Thread
|
|
#endif
|
|
{
|
|
#if !MONO
|
|
/*=========================================================================
|
|
** Data accessed from managed code that needs to be defined in
|
|
** ThreadBaseObject to maintain alignment between the two classes.
|
|
** DON'T CHANGE THESE UNLESS YOU MODIFY ThreadBaseObject in vm\object.h
|
|
=========================================================================*/
|
|
#if FEATURE_REMOTING
|
|
private Context m_Context;
|
|
#endif
|
|
private ExecutionContext m_ExecutionContext; // this call context follows the logical thread
|
|
|
|
private String m_Name;
|
|
private Delegate m_Delegate; // Delegate
|
|
|
|
#if FEATURE_LEAK_CULTURE_INFO
|
|
private CultureInfo m_CurrentCulture;
|
|
private CultureInfo m_CurrentUICulture;
|
|
#endif
|
|
private Object m_ThreadStartArg;
|
|
|
|
/*=========================================================================
|
|
** The base implementation of Thread is all native. The following fields
|
|
** should never be used in the C# code. They are here to define the proper
|
|
** space so the thread object may be allocated. DON'T CHANGE THESE UNLESS
|
|
** YOU MODIFY ThreadBaseObject in vm\object.h
|
|
=========================================================================*/
|
|
#pragma warning disable 169
|
|
#pragma warning disable 414 // These fields are not used from managed.
|
|
// IntPtrs need to be together, and before ints, because IntPtrs are 64-bit
|
|
// fields on 64-bit platforms, where they will be sorted together.
|
|
|
|
private IntPtr DONT_USE_InternalThread; // Pointer
|
|
private int m_Priority; // INT32
|
|
private int m_ManagedThreadId; // INT32
|
|
|
|
#pragma warning restore 414
|
|
#pragma warning restore 169
|
|
|
|
private bool m_ExecutionContextBelongsToOuterScope;
|
|
#if DEBUG
|
|
private bool m_ForbidExecutionContextMutation;
|
|
#endif
|
|
#endif
|
|
/*=========================================================================
|
|
** This manager is responsible for storing the global data that is
|
|
** shared amongst all the thread local stores.
|
|
=========================================================================*/
|
|
static private LocalDataStoreMgr s_LocalDataStoreMgr;
|
|
|
|
/*=========================================================================
|
|
** Thread-local data store
|
|
=========================================================================*/
|
|
[ThreadStatic]
|
|
static private LocalDataStoreHolder s_LocalDataStore;
|
|
|
|
// Do not move! Order of above fields needs to be preserved for alignment
|
|
// with native code
|
|
// See code:#threadCultureInfo
|
|
#if !FEATURE_LEAK_CULTURE_INFO
|
|
[ThreadStatic]
|
|
private static CultureInfo m_CurrentCulture;
|
|
[ThreadStatic]
|
|
private static CultureInfo m_CurrentUICulture;
|
|
#endif
|
|
|
|
#if FEATURE_CORECLR
|
|
// Adding an empty default ctor for annotation purposes
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
internal Thread(){}
|
|
#endif // FEATURE_CORECLR
|
|
|
|
/*=========================================================================
|
|
** Creates a new Thread object which will begin execution at
|
|
** start.ThreadStart on a new thread when the Start method is called.
|
|
**
|
|
** Exceptions: ArgumentNullException if start == null.
|
|
=========================================================================*/
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
public Thread(ThreadStart start) {
|
|
if (start == null) {
|
|
throw new ArgumentNullException("start");
|
|
}
|
|
Contract.EndContractBlock();
|
|
SetStartHelper((Delegate)start,0); //0 will setup Thread with default stackSize
|
|
}
|
|
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
public Thread(ThreadStart start, int maxStackSize) {
|
|
if (start == null) {
|
|
throw new ArgumentNullException("start");
|
|
}
|
|
if (0 > maxStackSize)
|
|
throw new ArgumentOutOfRangeException("maxStackSize",Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
|
|
Contract.EndContractBlock();
|
|
SetStartHelper((Delegate)start, maxStackSize);
|
|
}
|
|
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
public Thread(ParameterizedThreadStart start) {
|
|
if (start == null) {
|
|
throw new ArgumentNullException("start");
|
|
}
|
|
Contract.EndContractBlock();
|
|
SetStartHelper((Delegate)start, 0);
|
|
}
|
|
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
public Thread(ParameterizedThreadStart start, int maxStackSize) {
|
|
if (start == null) {
|
|
throw new ArgumentNullException("start");
|
|
}
|
|
if (0 > maxStackSize)
|
|
throw new ArgumentOutOfRangeException("maxStackSize",Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
|
|
Contract.EndContractBlock();
|
|
SetStartHelper((Delegate)start, maxStackSize);
|
|
}
|
|
#if !MONO
|
|
[ComVisible(false)]
|
|
public override int GetHashCode()
|
|
{
|
|
return m_ManagedThreadId;
|
|
}
|
|
|
|
extern public int ManagedThreadId
|
|
{
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
get;
|
|
}
|
|
|
|
// Returns handle for interop with EE. The handle is guaranteed to be non-null.
|
|
internal unsafe ThreadHandle GetNativeHandle()
|
|
{
|
|
IntPtr thread = DONT_USE_InternalThread;
|
|
|
|
// This should never happen under normal circumstances. m_assembly is always assigned before it is handed out to the user.
|
|
// There are ways how to create an unitialized objects through remoting, etc. Avoid AVing in the EE by throwing a nice
|
|
// exception here.
|
|
if (thread.IsNull())
|
|
throw new ArgumentException(null, Environment.GetResourceString("Argument_InvalidHandle"));
|
|
|
|
return new ThreadHandle(thread);
|
|
}
|
|
#endif
|
|
|
|
/*=========================================================================
|
|
** Spawns off a new thread which will begin executing at the ThreadStart
|
|
** method on the IThreadable interface passed in the constructor. Once the
|
|
** thread is dead, it cannot be restarted with another call to Start.
|
|
**
|
|
** Exceptions: ThreadStateException if the thread has already been started.
|
|
=========================================================================*/
|
|
[HostProtection(Synchronization=true,ExternalThreading=true)]
|
|
[MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
|
|
public void Start()
|
|
{
|
|
StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
|
|
Start(ref stackMark);
|
|
}
|
|
|
|
[HostProtection(Synchronization=true,ExternalThreading=true)]
|
|
[MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
|
|
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
|
|
if(m_Delegate is ThreadStart)
|
|
{
|
|
//We expect the thread to be setup with a ParameterizedThreadStart
|
|
// if this constructor is called.
|
|
//If we got here then that wasn't the case
|
|
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ThreadWrongThreadStart"));
|
|
}
|
|
m_ThreadStartArg = parameter;
|
|
StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
|
|
Start(ref stackMark);
|
|
}
|
|
|
|
[System.Security.SecuritySafeCritical]
|
|
private void Start(ref StackCrawlMark stackMark)
|
|
{
|
|
#if FEATURE_COMINTEROP_APARTMENT_SUPPORT
|
|
// Eagerly initialize the COM Apartment state of the thread if we're allowed to.
|
|
StartupSetApartmentStateInternal();
|
|
#endif // FEATURE_COMINTEROP_APARTMENT_SUPPORT
|
|
|
|
// Attach current thread's security principal object to the new
|
|
// thread. Be careful not to bind the current thread to a principal
|
|
// if it's not already bound.
|
|
if (m_Delegate != null)
|
|
{
|
|
// If we reach here with a null delegate, something is broken. But we'll let the StartInternal method take care of
|
|
// reporting an error. Just make sure we dont try to dereference a null delegate.
|
|
ThreadHelper t = (ThreadHelper)(m_Delegate.Target);
|
|
ExecutionContext ec = ExecutionContext.Capture(
|
|
ref stackMark,
|
|
ExecutionContext.CaptureOptions.IgnoreSyncCtx);
|
|
t.SetExecutionContextHelper(ec);
|
|
}
|
|
#if FEATURE_ROLE_BASED_SECURITY
|
|
IPrincipal principal = (IPrincipal)CallContext.Principal;
|
|
#else
|
|
IPrincipal principal = null;
|
|
#endif
|
|
StartInternal(principal, ref stackMark);
|
|
}
|
|
|
|
|
|
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
|
|
internal ExecutionContext.Reader GetExecutionContextReader()
|
|
{
|
|
return new ExecutionContext.Reader(m_ExecutionContext);
|
|
}
|
|
|
|
internal bool ExecutionContextBelongsToCurrentScope
|
|
{
|
|
get { return !m_ExecutionContextBelongsToOuterScope; }
|
|
set { m_ExecutionContextBelongsToOuterScope = !value; }
|
|
}
|
|
|
|
#if !MONO && DEBUG
|
|
internal bool ForbidExecutionContextMutation
|
|
{
|
|
set { m_ForbidExecutionContextMutation = value; }
|
|
}
|
|
#endif
|
|
|
|
// note: please don't access this directly from mscorlib. Use GetMutableExecutionContext or GetExecutionContextReader instead.
|
|
public ExecutionContext ExecutionContext
|
|
{
|
|
[SecuritySafeCritical]
|
|
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
|
|
get
|
|
{
|
|
ExecutionContext result;
|
|
if (this == Thread.CurrentThread)
|
|
result = GetMutableExecutionContext();
|
|
else
|
|
result = m_ExecutionContext;
|
|
|
|
return result;
|
|
}
|
|
}
|
|
|
|
[SecurityCritical]
|
|
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
|
|
internal ExecutionContext GetMutableExecutionContext()
|
|
{
|
|
Contract.Assert(Thread.CurrentThread == this);
|
|
#if !MONO && DEBUG
|
|
Contract.Assert(!m_ForbidExecutionContextMutation);
|
|
#endif
|
|
if (m_ExecutionContext == null)
|
|
{
|
|
m_ExecutionContext = new ExecutionContext();
|
|
}
|
|
else if (!ExecutionContextBelongsToCurrentScope)
|
|
{
|
|
ExecutionContext copy = m_ExecutionContext.CreateMutableCopy();
|
|
m_ExecutionContext = copy;
|
|
}
|
|
|
|
ExecutionContextBelongsToCurrentScope = true;
|
|
return m_ExecutionContext;
|
|
}
|
|
|
|
[SecurityCritical]
|
|
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
|
|
internal void SetExecutionContext(ExecutionContext value, bool belongsToCurrentScope)
|
|
{
|
|
m_ExecutionContext = value;
|
|
ExecutionContextBelongsToCurrentScope = belongsToCurrentScope;
|
|
}
|
|
|
|
[SecurityCritical]
|
|
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
|
|
internal void SetExecutionContext(ExecutionContext.Reader value, bool belongsToCurrentScope)
|
|
{
|
|
m_ExecutionContext = value.DangerousGetRawExecutionContext();
|
|
ExecutionContextBelongsToCurrentScope = belongsToCurrentScope;
|
|
}
|
|
#if !MONO
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
private extern void StartInternal(IPrincipal principal, ref StackCrawlMark stackMark);
|
|
#endif
|
|
#if FEATURE_COMPRESSEDSTACK || MONO
|
|
/// <internalonly/>
|
|
[System.Security.SecurityCritical] // auto-generated_required
|
|
[DynamicSecurityMethodAttribute()]
|
|
[Obsolete("Thread.SetCompressedStack is no longer supported. Please use the System.Threading.CompressedStack class")]
|
|
public void SetCompressedStack( CompressedStack stack )
|
|
{
|
|
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ThreadAPIsNotSupported"));
|
|
}
|
|
#if !MONO
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall), ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
|
|
internal extern IntPtr SetAppDomainStack( SafeCompressedStackHandle csHandle);
|
|
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall), ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
|
|
internal extern void RestoreAppDomainStack( IntPtr appDomainStack);
|
|
#endif
|
|
|
|
/// <internalonly/>
|
|
[System.Security.SecurityCritical] // auto-generated_required
|
|
[Obsolete("Thread.GetCompressedStack is no longer supported. Please use the System.Threading.CompressedStack class")]
|
|
public CompressedStack GetCompressedStack()
|
|
{
|
|
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ThreadAPIsNotSupported"));
|
|
}
|
|
#endif // #if FEATURE_COMPRESSEDSTACK
|
|
#if !MONO
|
|
|
|
// Helper method to get a logical thread ID for StringBuilder (for
|
|
// correctness) and for FileStream's async code path (for perf, to
|
|
// avoid creating a Thread instance).
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
#if !FEATURE_CORECLR
|
|
[System.Runtime.ForceTokenStabilization]
|
|
#endif //!FEATURE_CORECLR
|
|
internal extern static IntPtr InternalGetCurrentThread();
|
|
|
|
/*=========================================================================
|
|
** Raises a ThreadAbortException in the thread, which usually
|
|
** results in the thread's death. The ThreadAbortException is a special
|
|
** exception that is not catchable. The finally clauses of all try
|
|
** statements will be executed before the thread dies. This includes the
|
|
** finally that a thread might be executing at the moment the Abort is raised.
|
|
** The thread is not stopped immediately--you must Join on the
|
|
** thread to guarantee it has stopped.
|
|
** It is possible for a thread to do an unbounded amount of computation in
|
|
** the finally's and thus indefinitely delay the threads death.
|
|
** If Abort() is called on a thread that has not been started, the thread
|
|
** will abort when Start() is called.
|
|
** If Abort is called twice on the same thread, a DuplicateThreadAbort
|
|
** exception is thrown.
|
|
=========================================================================*/
|
|
|
|
#if !FEATURE_CORECLR
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
[SecurityPermissionAttribute(SecurityAction.Demand, ControlThread=true)]
|
|
public void Abort(Object stateInfo)
|
|
{
|
|
// If two aborts come at the same time, it is possible that the state info
|
|
// gets set by one, and the actual abort gets delivered by another. But this
|
|
// is not distinguishable by an application.
|
|
// The accessor helper will only set the value if it isn't already set,
|
|
// and that particular bit of native code can test much faster than this
|
|
// code could, because testing might cause a cross-appdomain marshalling.
|
|
AbortReason = stateInfo;
|
|
|
|
// Note: we demand ControlThread permission, then call AbortInternal directly
|
|
// rather than delegating to the Abort() function below. We do this to ensure
|
|
// that only callers with ControlThread are allowed to change the AbortReason
|
|
// of the thread. We call AbortInternal directly to avoid demanding the same
|
|
// permission twice.
|
|
AbortInternal();
|
|
}
|
|
#endif
|
|
|
|
#if FEATURE_CORECLR
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
#else
|
|
[System.Security.SecuritySafeCritical]
|
|
#endif
|
|
#pragma warning disable 618
|
|
[SecurityPermissionAttribute(SecurityAction.Demand, ControlThread = true)]
|
|
#pragma warning restore 618
|
|
public void Abort()
|
|
{
|
|
#if FEATURE_LEGACYNETCF
|
|
if(CompatibilitySwitches.IsAppEarlierThanWindowsPhone8)
|
|
{
|
|
System.Reflection.Assembly callingAssembly = System.Reflection.Assembly.GetCallingAssembly();
|
|
if(callingAssembly != null && !callingAssembly.IsProfileAssembly)
|
|
{
|
|
string caller = new StackFrame(1).GetMethod().FullName;
|
|
string callee = System.Reflection.MethodBase.GetCurrentMethod().FullName;
|
|
throw new MethodAccessException(String.Format(
|
|
CultureInfo.CurrentCulture,
|
|
Environment.GetResourceString("Arg_MethodAccessException_WithCaller"),
|
|
caller,
|
|
callee));
|
|
}
|
|
}
|
|
#endif // FEATURE_LEGACYNETCF
|
|
AbortInternal();
|
|
}
|
|
|
|
// Internal helper (since we can't place security demands on
|
|
// ecalls/fcalls).
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
private extern void AbortInternal();
|
|
#endif
|
|
#if !FEATURE_CORECLR || MONO
|
|
/*=========================================================================
|
|
** Resets a thread abort.
|
|
** Should be called by trusted code only
|
|
=========================================================================*/
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
[SecurityPermissionAttribute(SecurityAction.Demand, ControlThread=true)]
|
|
public static void ResetAbort()
|
|
{
|
|
Thread thread = Thread.CurrentThread;
|
|
if ((thread.ThreadState & ThreadState.AbortRequested) == 0)
|
|
throw new ThreadStateException(Environment.GetResourceString("ThreadState_NoAbortRequested"));
|
|
thread.ResetAbortNative();
|
|
thread.ClearAbortReason();
|
|
}
|
|
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
private extern void ResetAbortNative();
|
|
|
|
/*=========================================================================
|
|
** Suspends the thread. If the thread is already suspended, this call has
|
|
** no effect.
|
|
**
|
|
** Exceptions: ThreadStateException if the thread has not been started or
|
|
** it is dead.
|
|
=========================================================================*/
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
[Obsolete("Thread.Suspend has been deprecated. Please use other classes in System.Threading, such as Monitor, Mutex, Event, and Semaphore, to synchronize Threads or protect resources. http://go.microsoft.com/fwlink/?linkid=14202", false)][SecurityPermission(SecurityAction.Demand, ControlThread=true)]
|
|
[SecurityPermission(SecurityAction.Demand, ControlThread=true)]
|
|
public void Suspend() { SuspendInternal(); }
|
|
|
|
// Internal helper (since we can't place security demands on
|
|
// ecalls/fcalls).
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
private extern void SuspendInternal();
|
|
|
|
/*=========================================================================
|
|
** Resumes a thread that has been suspended.
|
|
**
|
|
** Exceptions: ThreadStateException if the thread has not been started or
|
|
** it is dead or it isn't in the suspended state.
|
|
=========================================================================*/
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
[Obsolete("Thread.Resume has been deprecated. Please use other classes in System.Threading, such as Monitor, Mutex, Event, and Semaphore, to synchronize Threads or protect resources. http://go.microsoft.com/fwlink/?linkid=14202", false)]
|
|
[SecurityPermission(SecurityAction.Demand, ControlThread=true)]
|
|
public void Resume() { ResumeInternal(); }
|
|
|
|
// Internal helper (since we can't place security demands on
|
|
// ecalls/fcalls).
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
private extern void ResumeInternal();
|
|
|
|
/*=========================================================================
|
|
** 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
|
|
[SecurityPermission(SecurityAction.Demand, ControlThread=true)]
|
|
public void Interrupt() { InterruptInternal(); }
|
|
|
|
// Internal helper (since we can't place security demands on
|
|
// ecalls/fcalls).
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
private extern void InterruptInternal();
|
|
#endif
|
|
|
|
/*=========================================================================
|
|
** Returns the priority of the thread.
|
|
**
|
|
** Exceptions: ThreadStateException if the thread is dead.
|
|
=========================================================================*/
|
|
|
|
public ThreadPriority Priority {
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
get { return (ThreadPriority)GetPriorityNative(); }
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
[HostProtection(SelfAffectingThreading=true)]
|
|
set { SetPriorityNative((int)value); }
|
|
}
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
private extern int GetPriorityNative();
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
private extern void SetPriorityNative(int priority);
|
|
#if !MONO
|
|
/*=========================================================================
|
|
** Returns true if the thread has been started and is not dead.
|
|
=========================================================================*/
|
|
public extern bool IsAlive {
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
|
get;
|
|
}
|
|
|
|
/*=========================================================================
|
|
** Returns true if the thread is a threadpool thread.
|
|
=========================================================================*/
|
|
public extern bool IsThreadPoolThread {
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
|
get;
|
|
}
|
|
#endif
|
|
/*=========================================================================
|
|
** 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 < 0.
|
|
** ThreadInterruptedException if the thread is interrupted while waiting.
|
|
** ThreadStateException if the thread has not been started yet.
|
|
=========================================================================*/
|
|
[System.Security.SecurityCritical]
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
private extern bool JoinInternal(int millisecondsTimeout);
|
|
|
|
[System.Security.SecuritySafeCritical]
|
|
[HostProtection(Synchronization=true, ExternalThreading=true)]
|
|
public void Join()
|
|
{
|
|
JoinInternal(Timeout.Infinite);
|
|
}
|
|
|
|
[System.Security.SecuritySafeCritical]
|
|
[HostProtection(Synchronization=true, ExternalThreading=true)]
|
|
public bool Join(int millisecondsTimeout)
|
|
{
|
|
#if MONO
|
|
if (millisecondsTimeout < Timeout.Infinite)
|
|
throw new ArgumentOutOfRangeException("millisecondsTimeout", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
|
|
#endif
|
|
return JoinInternal(millisecondsTimeout);
|
|
}
|
|
|
|
[HostProtection(Synchronization=true, ExternalThreading=true)]
|
|
public bool Join(TimeSpan timeout)
|
|
{
|
|
long tm = (long)timeout.TotalMilliseconds;
|
|
if (tm < -1 || tm > (long) Int32.MaxValue)
|
|
throw new ArgumentOutOfRangeException("timeout", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
|
|
|
|
return Join((int)tm);
|
|
}
|
|
|
|
/*=========================================================================
|
|
** Suspends the current thread for timeout milliseconds. If timeout == 0,
|
|
** forces the thread to give up the remainer of its timeslice. If timeout
|
|
** == Timeout.Infinite, no timeout will occur.
|
|
**
|
|
** Exceptions: ArgumentException if timeout < 0.
|
|
** ThreadInterruptedException if the thread is interrupted while sleeping.
|
|
=========================================================================*/
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
private static extern void SleepInternal(int millisecondsTimeout);
|
|
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
public static void Sleep(int millisecondsTimeout)
|
|
{
|
|
#if MONO
|
|
if (millisecondsTimeout < Timeout.Infinite)
|
|
throw new ArgumentOutOfRangeException("millisecondsTimeout", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
|
|
#endif
|
|
SleepInternal(millisecondsTimeout);
|
|
#if !MONO
|
|
// Ensure we don't return to app code when the pause is underway
|
|
if(AppDomainPauseManager.IsPaused)
|
|
AppDomainPauseManager.ResumeEvent.WaitOneWithoutFAS();
|
|
#endif
|
|
}
|
|
|
|
public static void Sleep(TimeSpan timeout)
|
|
{
|
|
long tm = (long)timeout.TotalMilliseconds;
|
|
if (tm < -1 || tm > (long) Int32.MaxValue)
|
|
throw new ArgumentOutOfRangeException("timeout", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
|
|
Sleep((int)tm);
|
|
}
|
|
|
|
#if !MONO
|
|
/* wait for a length of time proportial to 'iterations'. Each iteration is should
|
|
only take a few machine instructions. Calling this API is preferable to coding
|
|
a explict busy loop because the hardware can be informed that it is busy waiting. */
|
|
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall),
|
|
HostProtection(Synchronization=true,ExternalThreading=true),
|
|
ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success),
|
|
ResourceExposure(ResourceScope.None)]
|
|
private static extern void SpinWaitInternal(int iterations);
|
|
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
[HostProtection(Synchronization=true,ExternalThreading=true),
|
|
ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
|
|
public static void SpinWait(int iterations)
|
|
{
|
|
SpinWaitInternal(iterations);
|
|
}
|
|
#endif
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall),
|
|
HostProtection(Synchronization = true, ExternalThreading = true),
|
|
ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success),
|
|
ResourceExposure(ResourceScope.None)]
|
|
private static extern bool YieldInternal();
|
|
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
[HostProtection(Synchronization = true, ExternalThreading = true),
|
|
ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
|
|
public static bool Yield()
|
|
{
|
|
return YieldInternal();
|
|
}
|
|
|
|
#if !MONO
|
|
public static Thread CurrentThread {
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
|
|
#if !FEATURE_CORECLR
|
|
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
|
|
#endif
|
|
get {
|
|
Contract.Ensures(Contract.Result<Thread>() != null);
|
|
return GetCurrentThreadNative();
|
|
}
|
|
}
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall), ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
|
|
private static extern Thread GetCurrentThreadNative();
|
|
#endif
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
private void SetStartHelper(Delegate start, int maxStackSize)
|
|
{
|
|
#if MONO
|
|
maxStackSize = GetProcessDefaultStackSize(maxStackSize);
|
|
#else
|
|
#if FEATURE_CORECLR
|
|
// We only support default stacks in CoreCLR
|
|
Contract.Assert(maxStackSize == 0);
|
|
#else
|
|
// Only fully-trusted code is allowed to create "large" stacks. Partial-trust falls back to
|
|
// the default stack size.
|
|
ulong defaultStackSize = GetProcessDefaultStackSize();
|
|
|
|
if ((ulong)(uint)maxStackSize > defaultStackSize)
|
|
{
|
|
try
|
|
{
|
|
SecurityPermission.Demand(PermissionType.FullTrust);
|
|
}
|
|
catch (SecurityException)
|
|
{
|
|
maxStackSize = (int)Math.Min(defaultStackSize, (ulong)(uint)int.MaxValue);
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
ThreadHelper threadStartCallBack = new ThreadHelper(start);
|
|
if(start is ThreadStart)
|
|
{
|
|
SetStart(new ThreadStart(threadStartCallBack.ThreadStart), maxStackSize);
|
|
}
|
|
else
|
|
{
|
|
SetStart(new ParameterizedThreadStart(threadStartCallBack.ThreadStart), maxStackSize);
|
|
}
|
|
}
|
|
#if !MONO
|
|
[SecurityCritical]
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
|
|
[SuppressUnmanagedCodeSecurity]
|
|
private static extern ulong GetProcessDefaultStackSize();
|
|
|
|
/*=========================================================================
|
|
** PRIVATE Sets the IThreadable interface for the thread. Assumes that
|
|
** start != null.
|
|
=========================================================================*/
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
private extern void SetStart(Delegate start, int maxStackSize);
|
|
|
|
/*=========================================================================
|
|
** Clean up the thread when it goes away.
|
|
=========================================================================*/
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
|
|
~Thread()
|
|
{
|
|
// Delegate to the unmanaged portion.
|
|
InternalFinalize();
|
|
}
|
|
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
private extern void InternalFinalize();
|
|
|
|
#if FEATURE_COMINTEROP
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
public extern void DisableComObjectEagerCleanup();
|
|
#endif //FEATURE_COMINTEROP
|
|
|
|
/*=========================================================================
|
|
** 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 {
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
get { return IsBackgroundNative(); }
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
[HostProtection(SelfAffectingThreading=true)]
|
|
set { SetBackgroundNative(value); }
|
|
}
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
private extern bool IsBackgroundNative();
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
private extern void SetBackgroundNative(bool isBackground);
|
|
|
|
|
|
/*=========================================================================
|
|
** Return the thread state as a consistent set of bits. This is more
|
|
** general then IsAlive or IsBackground.
|
|
=========================================================================*/
|
|
public ThreadState ThreadState {
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
get { return (ThreadState)GetThreadStateNative(); }
|
|
}
|
|
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
private extern int GetThreadStateNative();
|
|
|
|
#if FEATURE_COMINTEROP_APARTMENT_SUPPORT
|
|
/*=========================================================================
|
|
** An unstarted thread can be marked to indicate that it will host a
|
|
** single-threaded or multi-threaded apartment.
|
|
**
|
|
** Exceptions: ArgumentException if state is not a valid apartment state
|
|
** (ApartmentSTA or ApartmentMTA).
|
|
=========================================================================*/
|
|
[Obsolete("The ApartmentState property has been deprecated. Use GetApartmentState, SetApartmentState or TrySetApartmentState instead.", false)]
|
|
public ApartmentState ApartmentState
|
|
{
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
get
|
|
{
|
|
return (ApartmentState)GetApartmentStateNative();
|
|
}
|
|
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
[HostProtection(Synchronization=true, SelfAffectingThreading=true)]
|
|
set
|
|
{
|
|
SetApartmentStateNative((int)value, true);
|
|
}
|
|
}
|
|
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
public ApartmentState GetApartmentState()
|
|
{
|
|
return (ApartmentState)GetApartmentStateNative();
|
|
}
|
|
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
[HostProtection(Synchronization=true, SelfAffectingThreading=true)]
|
|
public bool TrySetApartmentState(ApartmentState state)
|
|
{
|
|
return SetApartmentStateHelper(state, false);
|
|
}
|
|
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
[HostProtection(Synchronization=true, SelfAffectingThreading=true)]
|
|
public void SetApartmentState(ApartmentState state)
|
|
{
|
|
bool result = SetApartmentStateHelper(state, true);
|
|
if (!result)
|
|
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ApartmentStateSwitchFailed"));
|
|
}
|
|
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
private 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;
|
|
}
|
|
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
private extern int GetApartmentStateNative();
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
private extern int SetApartmentStateNative(int state, bool fireMDAOnMismatch);
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
private extern void StartupSetApartmentStateInternal();
|
|
#endif // FEATURE_COMINTEROP_APARTMENT_SUPPORT
|
|
#endif
|
|
/*=========================================================================
|
|
** Allocates an un-named data slot. The slot is allocated on ALL the
|
|
** threads.
|
|
=========================================================================*/
|
|
[HostProtection(SharedState=true, ExternalThreading=true)]
|
|
public static LocalDataStoreSlot AllocateDataSlot()
|
|
{
|
|
return LocalDataStoreManager.AllocateDataSlot();
|
|
}
|
|
|
|
/*=========================================================================
|
|
** Allocates a named data slot. The slot is allocated on ALL the
|
|
** threads. Named data slots are "public" and can be manipulated by
|
|
** anyone.
|
|
=========================================================================*/
|
|
[HostProtection(SharedState=true, ExternalThreading=true)]
|
|
public static LocalDataStoreSlot AllocateNamedDataSlot(String name)
|
|
{
|
|
return LocalDataStoreManager.AllocateNamedDataSlot(name);
|
|
}
|
|
|
|
/*=========================================================================
|
|
** Looks up a named data slot. If the name has not been used, a new slot is
|
|
** allocated. Named data slots are "public" and can be manipulated by
|
|
** anyone.
|
|
=========================================================================*/
|
|
[HostProtection(SharedState=true, ExternalThreading=true)]
|
|
public static LocalDataStoreSlot GetNamedDataSlot(String name)
|
|
{
|
|
return LocalDataStoreManager.GetNamedDataSlot(name);
|
|
}
|
|
|
|
/*=========================================================================
|
|
** Frees a named data slot. The slot is allocated on ALL the
|
|
** threads. Named data slots are "public" and can be manipulated by
|
|
** anyone.
|
|
=========================================================================*/
|
|
[HostProtection(SharedState=true, ExternalThreading=true)]
|
|
public static void FreeNamedDataSlot(String name)
|
|
{
|
|
LocalDataStoreManager.FreeNamedDataSlot(name);
|
|
}
|
|
|
|
/*=========================================================================
|
|
** Retrieves the value from the specified slot on the current thread, for that thread's current domain.
|
|
=========================================================================*/
|
|
[HostProtection(SharedState=true, ExternalThreading=true)]
|
|
[ResourceExposure(ResourceScope.AppDomain)]
|
|
public static Object GetData(LocalDataStoreSlot slot)
|
|
{
|
|
LocalDataStoreHolder dls = s_LocalDataStore;
|
|
if (dls == null)
|
|
{
|
|
// Make sure to validate the slot even if we take the quick path
|
|
LocalDataStoreManager.ValidateSlot(slot);
|
|
return null;
|
|
}
|
|
|
|
return dls.Store.GetData(slot);
|
|
}
|
|
|
|
/*=========================================================================
|
|
** Sets the data in the specified slot on the currently running thread, for that thread's current domain.
|
|
=========================================================================*/
|
|
[HostProtection(SharedState=true, ExternalThreading=true)]
|
|
[ResourceExposure(ResourceScope.AppDomain)]
|
|
public static void SetData(LocalDataStoreSlot slot, Object data)
|
|
{
|
|
LocalDataStoreHolder dls = s_LocalDataStore;
|
|
|
|
// Create new DLS if one hasn't been created for this domain for this thread
|
|
if (dls == null) {
|
|
dls = LocalDataStoreManager.CreateLocalDataStore();
|
|
s_LocalDataStore = dls;
|
|
}
|
|
|
|
dls.Store.SetData(slot, data);
|
|
}
|
|
#if !MONO
|
|
|
|
// #threadCultureInfo
|
|
//
|
|
// Background:
|
|
// In the desktop runtime, we allow a thread's cultures to travel with the thread
|
|
// across AppDomain boundaries. Furthermore we update the native thread with the
|
|
// culture of the managed thread. Because of security concerns and potential SxS
|
|
// effects, in Silverlight we are making the changes listed below.
|
|
//
|
|
// Silverlight Changes:
|
|
// - thread instance member cultures (CurrentCulture and CurrentUICulture)
|
|
// confined within AppDomains
|
|
// - changes to these properties don't affect the underlying native thread
|
|
//
|
|
// Ifdef:
|
|
// FEATURE_LEAK_CULTURE_INFO : CultureInfos can leak across AppDomains, not
|
|
// enabled in Silverlight
|
|
//
|
|
// Implementation notes:
|
|
// In Silverlight, culture members thread static (per Thread, per AppDomain).
|
|
//
|
|
// Quirks:
|
|
// An interesting side-effect of isolating cultures within an AppDomain is that we
|
|
// now need to special case resource lookup for mscorlib, which transitions to the
|
|
// default domain to lookup resources. See Environment.cs for more details.
|
|
//
|
|
#if FEATURE_LEAK_CULTURE_INFO
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
static extern private bool nativeGetSafeCulture(Thread t, int appDomainId, bool isUI, ref CultureInfo safeCulture);
|
|
#endif // FEATURE_LEAK_CULTURE_INFO
|
|
|
|
// As the culture can be customized object then we cannot hold any
|
|
// reference to it before we check if it is safe because the app domain
|
|
// owning this customized culture may get unloaded while executing this
|
|
// code. To achieve that we have to do the check using nativeGetSafeCulture
|
|
// as the thread cannot get interrupted during the FCALL.
|
|
// If the culture is safe (not customized or created in current app domain)
|
|
// then the FCALL will return a reference to that culture otherwise the
|
|
// FCALL will return failure. In case of failure we'll return the default culture.
|
|
// If the app domain owning a customized culture that is set to teh thread and this
|
|
// app domain get unloaded there is a code to clean up the culture from the thread
|
|
// using the code in AppDomain::ReleaseDomainStores.
|
|
|
|
public CultureInfo CurrentUICulture {
|
|
get {
|
|
Contract.Ensures(Contract.Result<CultureInfo>() != null);
|
|
#if FEATURE_APPX
|
|
if(AppDomain.IsAppXModel()) {
|
|
return CultureInfo.GetCultureInfoForUserPreferredLanguageInAppX() ?? GetCurrentUICultureNoAppX();
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
return GetCurrentUICultureNoAppX();
|
|
}
|
|
}
|
|
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
[HostProtection(ExternalThreading=true)]
|
|
set {
|
|
if (value == null) {
|
|
throw new ArgumentNullException("value");
|
|
}
|
|
Contract.EndContractBlock();
|
|
|
|
//If they're trying to use a Culture with a name that we can't use in resource lookup,
|
|
//don't even let them set it on the thread.
|
|
CultureInfo.VerifyCultureName(value, true);
|
|
|
|
// If you add more pre-conditions to this method, check to see if you also need to
|
|
// add them to CultureInfo.DefaultThreadCurrentUICulture.set.
|
|
|
|
#if FEATURE_LEAK_CULTURE_INFO
|
|
if (nativeSetThreadUILocale(value.SortName) == false)
|
|
{
|
|
throw new ArgumentException(Environment.GetResourceString("Argument_InvalidResourceCultureName", value.Name));
|
|
}
|
|
value.StartCrossDomainTracking();
|
|
#else
|
|
if (m_CurrentUICulture == null && m_CurrentCulture == null)
|
|
nativeInitCultureAccessors();
|
|
#endif
|
|
|
|
#if FEATURE_LEGACYNETCF
|
|
if (CompatibilitySwitches.IsAppEarlierThanWindowsPhone8)
|
|
{
|
|
//
|
|
// NetCF had a bug where Thread.Current{UI}Culture would set the culture for every thread in the process.
|
|
// This was because they stored the value in a regular static field (NetCF has no support for ThreadStatic fields).
|
|
// Some apps depend on the broken behavior. We will emulate this behavior by redirecting setters to
|
|
// DefaultThreadCurrentUICulture. (Note that this property did not existed in NetCF and so it is fine to piggy back
|
|
// on it for the quirk.)
|
|
//
|
|
CultureInfo.SetCurrentUICultureQuirk(value);
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
m_CurrentUICulture = value;
|
|
}
|
|
}
|
|
|
|
#if FEATURE_LEAK_CULTURE_INFO
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
#endif
|
|
internal CultureInfo GetCurrentUICultureNoAppX() {
|
|
|
|
Contract.Ensures(Contract.Result<CultureInfo>() != null);
|
|
|
|
// Fetch a local copy of m_CurrentUICulture to
|
|
// avoid ----s that malicious user can introduce
|
|
if (m_CurrentUICulture == null) {
|
|
CultureInfo appDomainDefaultUICulture = CultureInfo.DefaultThreadCurrentUICulture;
|
|
return (appDomainDefaultUICulture != null ? appDomainDefaultUICulture : CultureInfo.UserDefaultUICulture);
|
|
}
|
|
|
|
#if FEATURE_LEAK_CULTURE_INFO
|
|
CultureInfo culture = null;
|
|
|
|
if (!nativeGetSafeCulture(this, GetDomainID(), true, ref culture) || culture == null) {
|
|
return CultureInfo.UserDefaultUICulture;
|
|
}
|
|
|
|
return culture;
|
|
#else
|
|
return m_CurrentUICulture;
|
|
#endif
|
|
}
|
|
|
|
// This returns the exposed context for a given context ID.
|
|
#if FEATURE_LEAK_CULTURE_INFO
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
static extern private bool nativeSetThreadUILocale(String locale);
|
|
#endif
|
|
|
|
// As the culture can be customized object then we cannot hold any
|
|
// reference to it before we check if it is safe because the app domain
|
|
// owning this customized culture may get unloaded while executing this
|
|
// code. To achieve that we have to do the check using nativeGetSafeCulture
|
|
// as the thread cannot get interrupted during the FCALL.
|
|
// If the culture is safe (not customized or created in current app domain)
|
|
// then the FCALL will return a reference to that culture otherwise the
|
|
// FCALL will return failure. In case of failure we'll return the default culture.
|
|
// If the app domain owning a customized culture that is set to teh thread and this
|
|
// app domain get unloaded there is a code to clean up the culture from the thread
|
|
// using the code in AppDomain::ReleaseDomainStores.
|
|
|
|
public CultureInfo CurrentCulture {
|
|
get {
|
|
Contract.Ensures(Contract.Result<CultureInfo>() != null);
|
|
|
|
#if FEATURE_APPX
|
|
if(AppDomain.IsAppXModel()) {
|
|
return CultureInfo.GetCultureInfoForUserPreferredLanguageInAppX() ?? GetCurrentCultureNoAppX();
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
return GetCurrentCultureNoAppX();
|
|
}
|
|
}
|
|
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
#if FEATURE_LEAK_CULTURE_INFO
|
|
[SecurityPermission(SecurityAction.Demand, ControlThread = true)]
|
|
#endif
|
|
set {
|
|
if (null==value) {
|
|
throw new ArgumentNullException("value");
|
|
}
|
|
Contract.EndContractBlock();
|
|
|
|
// If you add more pre-conditions to this method, check to see if you also need to
|
|
// add them to CultureInfo.DefaultThreadCurrentCulture.set.
|
|
|
|
#if FEATURE_LEAK_CULTURE_INFO
|
|
//If we can't set the nativeThreadLocale, we'll just let it stay
|
|
//at whatever value it had before. This allows people who use
|
|
//just managed code not to be limited by the underlying OS.
|
|
CultureInfo.nativeSetThreadLocale(value.SortName);
|
|
value.StartCrossDomainTracking();
|
|
#else
|
|
if (m_CurrentCulture == null && m_CurrentUICulture == null)
|
|
nativeInitCultureAccessors();
|
|
#endif
|
|
|
|
#if FEATURE_LEGACYNETCF
|
|
if (CompatibilitySwitches.IsAppEarlierThanWindowsPhone8)
|
|
{
|
|
// See comment in CurrentUICulture setter
|
|
CultureInfo.SetCurrentCultureQuirk(value);
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
m_CurrentCulture = value;
|
|
}
|
|
}
|
|
|
|
#if FEATURE_LEAK_CULTURE_INFO
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
#endif
|
|
private CultureInfo GetCurrentCultureNoAppX() {
|
|
|
|
Contract.Ensures(Contract.Result<CultureInfo>() != null);
|
|
|
|
// Fetch a local copy of m_CurrentCulture to
|
|
// avoid ----s that malicious user can introduce
|
|
if (m_CurrentCulture == null) {
|
|
CultureInfo appDomainDefaultCulture = CultureInfo.DefaultThreadCurrentCulture;
|
|
return (appDomainDefaultCulture != null ? appDomainDefaultCulture : CultureInfo.UserDefaultCulture);
|
|
}
|
|
|
|
#if FEATURE_LEAK_CULTURE_INFO
|
|
CultureInfo culture = null;
|
|
|
|
if (!nativeGetSafeCulture(this, GetDomainID(), false, ref culture) || culture == null) {
|
|
return CultureInfo.UserDefaultCulture;
|
|
}
|
|
|
|
return culture;
|
|
#else
|
|
return m_CurrentCulture;
|
|
#endif
|
|
|
|
}
|
|
|
|
#if! FEATURE_LEAK_CULTURE_INFO
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
|
|
[SuppressUnmanagedCodeSecurity]
|
|
private static extern void nativeInitCultureAccessors();
|
|
#endif
|
|
|
|
/*=============================================================*/
|
|
|
|
/*======================================================================
|
|
** Current thread context is stored in a slot in the thread local store
|
|
** CurrentContext gets the Context from the slot.
|
|
======================================================================*/
|
|
#if FEATURE_REMOTING
|
|
public static Context CurrentContext
|
|
{
|
|
[System.Security.SecurityCritical] // auto-generated_required
|
|
get
|
|
{
|
|
return CurrentThread.GetCurrentContextInternal();
|
|
}
|
|
}
|
|
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
internal Context GetCurrentContextInternal()
|
|
{
|
|
if (m_Context == null)
|
|
{
|
|
m_Context = Context.DefaultContext;
|
|
}
|
|
return m_Context;
|
|
}
|
|
#endif
|
|
|
|
|
|
#if FEATURE_IMPERSONATION
|
|
// Get and set thread's current principal (for role based security).
|
|
public static IPrincipal CurrentPrincipal
|
|
{
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
get
|
|
{
|
|
lock (CurrentThread)
|
|
{
|
|
IPrincipal principal = (IPrincipal)
|
|
CallContext.Principal;
|
|
if (principal == null)
|
|
{
|
|
principal = GetDomain().GetThreadPrincipal();
|
|
CallContext.Principal = principal;
|
|
}
|
|
return principal;
|
|
}
|
|
}
|
|
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
[SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)]
|
|
#if !FEATURE_CORECLR
|
|
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
|
|
#endif
|
|
set
|
|
{
|
|
CallContext.Principal = value;
|
|
}
|
|
}
|
|
#endif // FEATURE_IMPERSONATION
|
|
|
|
// Private routine called from unmanaged code to set an initial
|
|
// principal for a newly created thread.
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
private void SetPrincipalInternal(IPrincipal principal)
|
|
{
|
|
GetMutableExecutionContext().LogicalCallContext.SecurityData.Principal = principal;
|
|
}
|
|
|
|
#if FEATURE_REMOTING
|
|
|
|
// This returns the exposed context for a given context ID.
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
internal static extern Context GetContextInternal(IntPtr id);
|
|
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
internal extern Object InternalCrossContextCallback(Context ctx, IntPtr ctxID, Int32 appDomainID, InternalCrossContextDelegate ftnToCall, Object[] args);
|
|
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
internal Object InternalCrossContextCallback(Context ctx, InternalCrossContextDelegate ftnToCall, Object[] args)
|
|
{
|
|
return InternalCrossContextCallback(ctx, ctx.InternalContextID, 0, ftnToCall, args);
|
|
}
|
|
|
|
// CompleteCrossContextCallback is called by the EE after transitioning to the requested context
|
|
private static Object CompleteCrossContextCallback(InternalCrossContextDelegate ftnToCall, Object[] args)
|
|
{
|
|
return ftnToCall(args);
|
|
}
|
|
#endif // FEATURE_REMOTING
|
|
|
|
/*======================================================================
|
|
** Returns the current domain in which current thread is running.
|
|
======================================================================*/
|
|
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
private static extern AppDomain GetDomainInternal();
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
private static extern AppDomain GetFastDomainInternal();
|
|
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
public static AppDomain GetDomain()
|
|
{
|
|
Contract.Ensures(Contract.Result<AppDomain>() != null);
|
|
|
|
|
|
AppDomain ad;
|
|
ad = GetFastDomainInternal();
|
|
if (ad == null)
|
|
ad = GetDomainInternal();
|
|
|
|
#if FEATURE_REMOTING
|
|
Contract.Assert(CurrentThread.m_Context == null || CurrentThread.m_Context.AppDomain == ad, "AppDomains on the managed & unmanaged threads should match");
|
|
#endif
|
|
return ad;
|
|
}
|
|
|
|
|
|
/*
|
|
* This returns a unique id to identify an appdomain.
|
|
*/
|
|
public static int GetDomainID()
|
|
{
|
|
return GetDomain().GetId();
|
|
}
|
|
|
|
|
|
// Retrieves the name of the thread.
|
|
//
|
|
public String Name {
|
|
get {
|
|
return m_Name;
|
|
|
|
}
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
[HostProtection(ExternalThreading=true)]
|
|
set {
|
|
lock(this) {
|
|
if (m_Name != null)
|
|
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_WriteOnce"));
|
|
m_Name = value;
|
|
|
|
InformThreadNameChange(GetNativeHandle(), value, (value != null) ? value.Length : 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
|
|
[SuppressUnmanagedCodeSecurity]
|
|
private static extern void InformThreadNameChange(ThreadHandle t, String name, int len);
|
|
|
|
internal Object AbortReason {
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
get {
|
|
object result = null;
|
|
try
|
|
{
|
|
result = GetAbortReason();
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ExceptionStateCrossAppDomain"), e);
|
|
}
|
|
return result;
|
|
}
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
set { SetAbortReason(value); }
|
|
}
|
|
|
|
/*
|
|
* This marks the beginning of a critical code region.
|
|
*/
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
[HostProtection(Synchronization=true, ExternalThreading=true)]
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
|
|
public static extern void BeginCriticalRegion();
|
|
|
|
/*
|
|
* This marks the end of a critical code region.
|
|
*/
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
[HostProtection(Synchronization=true, ExternalThreading=true)]
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
|
|
public static extern void EndCriticalRegion();
|
|
|
|
/*
|
|
* This marks the beginning of a code region that requires thread affinity.
|
|
*/
|
|
[System.Security.SecurityCritical] // auto-generated_required
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
|
|
public static extern void BeginThreadAffinity();
|
|
|
|
/*
|
|
* This marks the end of a code region that requires thread affinity.
|
|
*/
|
|
[System.Security.SecurityCritical] // auto-generated_required
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
|
|
public static extern void EndThreadAffinity();
|
|
|
|
/*=========================================================================
|
|
** Volatile Read & Write and MemoryBarrier methods.
|
|
** Provides the ability to read and write values ensuring that the values
|
|
** are read/written each time they are accessed.
|
|
=========================================================================*/
|
|
|
|
[MethodImplAttribute(MethodImplOptions.NoInlining)] // disable optimizations
|
|
public static byte VolatileRead(ref byte address)
|
|
{
|
|
byte ret = address;
|
|
MemoryBarrier(); // Call MemoryBarrier to ensure the proper semantic in a portable way.
|
|
return ret;
|
|
}
|
|
|
|
[MethodImplAttribute(MethodImplOptions.NoInlining)] // disable optimizations
|
|
public static short VolatileRead(ref short address)
|
|
{
|
|
short ret = address;
|
|
MemoryBarrier(); // Call MemoryBarrier to ensure the proper semantic in a portable way.
|
|
return ret;
|
|
}
|
|
|
|
[MethodImplAttribute(MethodImplOptions.NoInlining)] // disable optimizations
|
|
public static int VolatileRead(ref int address)
|
|
{
|
|
int ret = address;
|
|
MemoryBarrier(); // Call MemoryBarrier to ensure the proper semantic in a portable way.
|
|
return ret;
|
|
}
|
|
|
|
[MethodImplAttribute(MethodImplOptions.NoInlining)] // disable optimizations
|
|
public static long VolatileRead(ref long address)
|
|
{
|
|
long ret = address;
|
|
MemoryBarrier(); // Call MemoryBarrier to ensure the proper semantic in a portable way.
|
|
return ret;
|
|
}
|
|
|
|
[CLSCompliant(false)]
|
|
[MethodImplAttribute(MethodImplOptions.NoInlining)] // disable optimizations
|
|
public static sbyte VolatileRead(ref sbyte address)
|
|
{
|
|
sbyte ret = address;
|
|
MemoryBarrier(); // Call MemoryBarrier to ensure the proper semantic in a portable way.
|
|
return ret;
|
|
}
|
|
|
|
[CLSCompliant(false)]
|
|
[MethodImplAttribute(MethodImplOptions.NoInlining)] // disable optimizations
|
|
public static ushort VolatileRead(ref ushort address)
|
|
{
|
|
ushort ret = address;
|
|
MemoryBarrier(); // Call MemoryBarrier to ensure the proper semantic in a portable way.
|
|
return ret;
|
|
}
|
|
|
|
[CLSCompliant(false)]
|
|
[MethodImplAttribute(MethodImplOptions.NoInlining)] // disable optimizations
|
|
public static uint VolatileRead(ref uint address)
|
|
{
|
|
uint ret = address;
|
|
MemoryBarrier(); // Call MemoryBarrier to ensure the proper semantic in a portable way.
|
|
return ret;
|
|
}
|
|
|
|
[MethodImplAttribute(MethodImplOptions.NoInlining)] // disable optimizations
|
|
public static IntPtr VolatileRead(ref IntPtr address)
|
|
{
|
|
IntPtr ret = address;
|
|
MemoryBarrier(); // Call MemoryBarrier to ensure the proper semantic in a portable way.
|
|
return ret;
|
|
}
|
|
|
|
[CLSCompliant(false)]
|
|
[MethodImplAttribute(MethodImplOptions.NoInlining)] // disable optimizations
|
|
public static UIntPtr VolatileRead(ref UIntPtr address)
|
|
{
|
|
UIntPtr ret = address;
|
|
MemoryBarrier(); // Call MemoryBarrier to ensure the proper semantic in a portable way.
|
|
return ret;
|
|
}
|
|
|
|
[CLSCompliant(false)]
|
|
[MethodImplAttribute(MethodImplOptions.NoInlining)] // disable optimizations
|
|
public static ulong VolatileRead(ref ulong address)
|
|
{
|
|
ulong ret = address;
|
|
MemoryBarrier(); // Call MemoryBarrier to ensure the proper semantic in a portable way.
|
|
return ret;
|
|
}
|
|
|
|
[MethodImplAttribute(MethodImplOptions.NoInlining)] // disable optimizations
|
|
public static float VolatileRead(ref float address)
|
|
{
|
|
float ret = address;
|
|
MemoryBarrier(); // Call MemoryBarrier to ensure the proper semantic in a portable way.
|
|
return ret;
|
|
}
|
|
|
|
[MethodImplAttribute(MethodImplOptions.NoInlining)] // disable optimizations
|
|
public static double VolatileRead(ref double address)
|
|
{
|
|
double ret = address;
|
|
MemoryBarrier(); // Call MemoryBarrier to ensure the proper semantic in a portable way.
|
|
return ret;
|
|
}
|
|
|
|
[MethodImplAttribute(MethodImplOptions.NoInlining)] // disable optimizations
|
|
public static Object VolatileRead(ref Object address)
|
|
{
|
|
Object ret = address;
|
|
MemoryBarrier(); // Call MemoryBarrier to ensure the proper semantic in a portable way.
|
|
return ret;
|
|
}
|
|
|
|
[MethodImplAttribute(MethodImplOptions.NoInlining)] // disable optimizations
|
|
public static void VolatileWrite(ref byte address, byte value)
|
|
{
|
|
MemoryBarrier(); // Call MemoryBarrier to ensure the proper semantic in a portable way.
|
|
address = value;
|
|
}
|
|
|
|
[MethodImplAttribute(MethodImplOptions.NoInlining)] // disable optimizations
|
|
public static void VolatileWrite(ref short address, short value)
|
|
{
|
|
MemoryBarrier(); // Call MemoryBarrier to ensure the proper semantic in a portable way.
|
|
address = value;
|
|
}
|
|
|
|
[MethodImplAttribute(MethodImplOptions.NoInlining)] // disable optimizations
|
|
public static void VolatileWrite(ref int address, int value)
|
|
{
|
|
MemoryBarrier(); // Call MemoryBarrier to ensure the proper semantic in a portable way.
|
|
address = value;
|
|
}
|
|
|
|
[MethodImplAttribute(MethodImplOptions.NoInlining)] // disable optimizations
|
|
public static void VolatileWrite(ref long address, long value)
|
|
{
|
|
MemoryBarrier(); // Call MemoryBarrier to ensure the proper semantic in a portable way.
|
|
address = value;
|
|
}
|
|
|
|
[CLSCompliant(false)]
|
|
[MethodImplAttribute(MethodImplOptions.NoInlining)] // disable optimizations
|
|
public static void VolatileWrite(ref sbyte address, sbyte value)
|
|
{
|
|
MemoryBarrier(); // Call MemoryBarrier to ensure the proper semantic in a portable way.
|
|
address = value;
|
|
}
|
|
|
|
[CLSCompliant(false)]
|
|
[MethodImplAttribute(MethodImplOptions.NoInlining)] // disable optimizations
|
|
public static void VolatileWrite(ref ushort address, ushort value)
|
|
{
|
|
MemoryBarrier(); // Call MemoryBarrier to ensure the proper semantic in a portable way.
|
|
address = value;
|
|
}
|
|
|
|
[CLSCompliant(false)]
|
|
[MethodImplAttribute(MethodImplOptions.NoInlining)] // disable optimizations
|
|
public static void VolatileWrite(ref uint address, uint value)
|
|
{
|
|
MemoryBarrier(); // Call MemoryBarrier to ensure the proper semantic in a portable way.
|
|
address = value;
|
|
}
|
|
|
|
[MethodImplAttribute(MethodImplOptions.NoInlining)] // disable optimizations
|
|
public static void VolatileWrite(ref IntPtr address, IntPtr value)
|
|
{
|
|
MemoryBarrier(); // Call MemoryBarrier to ensure the proper semantic in a portable way.
|
|
address = value;
|
|
}
|
|
|
|
[CLSCompliant(false)]
|
|
[MethodImplAttribute(MethodImplOptions.NoInlining)] // disable optimizations
|
|
public static void VolatileWrite(ref UIntPtr address, UIntPtr value)
|
|
{
|
|
MemoryBarrier(); // Call MemoryBarrier to ensure the proper semantic in a portable way.
|
|
address = value;
|
|
}
|
|
|
|
[CLSCompliant(false)]
|
|
[MethodImplAttribute(MethodImplOptions.NoInlining)] // disable optimizations
|
|
public static void VolatileWrite(ref ulong address, ulong value)
|
|
{
|
|
MemoryBarrier(); // Call MemoryBarrier to ensure the proper semantic in a portable way.
|
|
address = value;
|
|
}
|
|
|
|
[MethodImplAttribute(MethodImplOptions.NoInlining)] // disable optimizations
|
|
public static void VolatileWrite(ref float address, float value)
|
|
{
|
|
MemoryBarrier(); // Call MemoryBarrier to ensure the proper semantic in a portable way.
|
|
address = value;
|
|
}
|
|
|
|
[MethodImplAttribute(MethodImplOptions.NoInlining)] // disable optimizations
|
|
public static void VolatileWrite(ref double address, double value)
|
|
{
|
|
MemoryBarrier(); // Call MemoryBarrier to ensure the proper semantic in a portable way.
|
|
address = value;
|
|
}
|
|
|
|
[MethodImplAttribute(MethodImplOptions.NoInlining)] // disable optimizations
|
|
public static void VolatileWrite(ref Object address, Object value)
|
|
{
|
|
MemoryBarrier(); // Call MemoryBarrier to ensure the proper semantic in a portable way.
|
|
address = value;
|
|
}
|
|
#endif
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
public static extern void MemoryBarrier();
|
|
|
|
private static LocalDataStoreMgr LocalDataStoreManager
|
|
{
|
|
get
|
|
{
|
|
if (s_LocalDataStoreMgr == null)
|
|
{
|
|
Interlocked.CompareExchange(ref s_LocalDataStoreMgr, new LocalDataStoreMgr(), null);
|
|
}
|
|
|
|
return s_LocalDataStoreMgr;
|
|
}
|
|
}
|
|
#if !MOBILE
|
|
void _Thread.GetTypeInfoCount(out uint pcTInfo)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
void _Thread.GetTypeInfo(uint iTInfo, uint lcid, IntPtr ppTInfo)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
void _Thread.GetIDsOfNames([In] ref Guid riid, IntPtr rgszNames, uint cNames, uint lcid, IntPtr rgDispId)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
void _Thread.Invoke(uint dispIdMember, [In] ref Guid riid, uint lcid, short wFlags, IntPtr pDispParams, IntPtr pVarResult, IntPtr pExcepInfo, IntPtr puArgErr)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
#endif
|
|
#if !MONO
|
|
// Helper function to set the AbortReason for a thread abort.
|
|
// Checks that they're not alredy set, and then atomically updates
|
|
// the reason info (object + ADID).
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
internal extern void SetAbortReason(Object o);
|
|
|
|
// Helper function to retrieve the AbortReason from a thread
|
|
// abort. Will perform cross-AppDomain marshalling if the object
|
|
// lives in a different AppDomain from the requester.
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
internal extern Object GetAbortReason();
|
|
|
|
// Helper function to clear the AbortReason. Takes care of
|
|
// AppDomain related cleanup if required.
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
internal extern void ClearAbortReason();
|
|
#endif
|
|
|
|
} // 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
|
|
// stack crawl will both prevent inlining of the calle and pass an ESP point to stack crawl to
|
|
// Declaring these in EH clauses is illegal; they must declared in the main method body
|
|
[Serializable]
|
|
internal enum StackCrawlMark
|
|
{
|
|
LookForMe = 0,
|
|
LookForMyCaller = 1,
|
|
LookForMyCallersCaller = 2,
|
|
LookForThread = 3
|
|
}
|
|
|
|
}
|