**
=============================================================================*/
-#pragma warning disable 0420
-
-/*
- * Below you'll notice two sets of APIs that are separated by the
- * use of 'Unsafe' in their names. The unsafe versions are called
- * that because they do not propagate the calling stack onto the
- * worker thread. This allows code to lose the calling stack and
- * thereby elevate its security privileges. Note that this operation
- * is much akin to the combined ability to control security policy
- * and control security evidence. With these privileges, a person
- * can gain the right to load assemblies that are fully trusted which
- * then assert full trust and can call any code they want regardless
- * of the previous stack information.
- */
+using System.Security;
+using System.Security.Permissions;
+using System;
+using Microsoft.Win32;
+using System.Runtime.CompilerServices;
+using System.Runtime.ConstrainedExecution;
+using System.Runtime.InteropServices;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Diagnostics.Contracts;
+using System.Diagnostics.CodeAnalysis;
+using System.Diagnostics.Tracing;
namespace System.Threading
{
- using System.Security;
- using System.Security.Permissions;
- using System;
- using Microsoft.Win32;
- using System.Runtime.CompilerServices;
- using System.Runtime.ConstrainedExecution;
- using System.Runtime.InteropServices;
- using System.Collections.Concurrent;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.Diagnostics.Contracts;
- using System.Diagnostics.CodeAnalysis;
- using System.Diagnostics.Tracing;
-
internal static class ThreadPoolGlobals
{
//Per-appDomain quantum (in ms) for which the thread keeps processing
internal sealed class ThreadPoolWorkQueue
{
// Simple sparsely populated array to allow lock-free reading.
- internal class SparseArray<T> where T : class
+ internal sealed class SparseArray<T> where T : class
{
private volatile T[] m_array;
m_array = new T[initialSize];
}
- internal T[] Current
- {
- get { return m_array; }
- }
+ internal T[] Current => m_array;
internal int Add(T e)
{
continue;
T[] newArray = new T[array.Length * 2];
- Array.Copy(array, newArray, i + 1);
+ Array.Copy(array, 0, newArray, 0, i + 1);
newArray[i + 1] = e;
m_array = newArray;
return i + 1;
}
}
- internal class WorkStealingQueue
+ internal sealed class WorkStealingQueue
{
private const int INITIAL_SIZE = 32;
internal volatile IThreadPoolWorkItem[] m_array = new IThreadPoolWorkItem[INITIAL_SIZE];
private volatile int m_headIndex = START_INDEX;
private volatile int m_tailIndex = START_INDEX;
- private SpinLock m_foreignLock = new SpinLock(false);
+ private SpinLock m_foreignLock = new SpinLock(enableThreadOwnerTracking:false);
public void LocalPush(IThreadPoolWorkItem obj)
{
finally
{
if (lockTaken)
- m_foreignLock.Exit(true);
+ m_foreignLock.Exit(useMemoryBarrier:true);
}
}
if (count >= m_mask)
{
// We're full; expand the queue by doubling its size.
- IThreadPoolWorkItem[] newArray = new IThreadPoolWorkItem[m_array.Length << 1];
+ var newArray = new IThreadPoolWorkItem[m_array.Length << 1];
for (int i = 0; i < m_array.Length; i++)
newArray[i] = m_array[(i + head) & m_mask];
finally
{
if (lockTaken)
- m_foreignLock.Exit(false);
+ m_foreignLock.Exit(useMemoryBarrier:false);
}
}
}
finally
{
if (lockTaken)
- m_foreignLock.Exit(false);
+ m_foreignLock.Exit(useMemoryBarrier:false);
}
}
}
finally
{
if (lockTaken)
- m_foreignLock.Exit(false);
+ m_foreignLock.Exit(useMemoryBarrier:false);
}
}
}
finally
{
if (taken)
- m_foreignLock.Exit(false);
+ m_foreignLock.Exit(useMemoryBarrier:false);
}
missedSteal = true;
loggingEnabled = FrameworkEventSource.Log.IsEnabled(EventLevel.Verbose, FrameworkEventSource.Keywords.ThreadPool|FrameworkEventSource.Keywords.ThreadTransfer);
}
- public ThreadPoolWorkQueueThreadLocals EnsureCurrentThreadHasQueue()
- {
- if (null == ThreadPoolWorkQueueThreadLocals.threadLocals)
- ThreadPoolWorkQueueThreadLocals.threadLocals = new ThreadPoolWorkQueueThreadLocals(this);
- return ThreadPoolWorkQueueThreadLocals.threadLocals;
- }
+ public ThreadPoolWorkQueueThreadLocals EnsureCurrentThreadHasQueue() =>
+ ThreadPoolWorkQueueThreadLocals.threadLocals ??
+ (ThreadPoolWorkQueueThreadLocals.threadLocals = new ThreadPoolWorkQueueThreadLocals(this));
internal void EnsureThreadRequested()
{
public void Enqueue(IThreadPoolWorkItem callback, bool forceGlobal)
{
+ if (loggingEnabled)
+ System.Diagnostics.Tracing.FrameworkEventSource.Log.ThreadPoolEnqueueWorkObject(callback);
+
ThreadPoolWorkQueueThreadLocals tl = null;
if (!forceGlobal)
tl = ThreadPoolWorkQueueThreadLocals.threadLocals;
-
- if (loggingEnabled)
- System.Diagnostics.Tracing.FrameworkEventSource.Log.ThreadPoolEnqueueWorkObject(callback);
if (null != tl)
{
return callback;
}
- static internal bool Dispatch()
+ internal static bool Dispatch()
{
var workQueue = ThreadPoolGlobals.workQueue;
//
try { }
finally
{
- ThreadPool.ReportThreadStatus(true);
+ ThreadPool.ReportThreadStatus(isWorking:true);
reportedStatus = true;
}
workItem.ExecuteWorkItem();
finally
{
if (reportedStatus)
- ThreadPool.ReportThreadStatus(false);
+ ThreadPool.ReportThreadStatus(isWorking:false);
}
}
else
// it was executed or not (in debug builds only). Task uses this to communicate the ThreadAbortException to anyone
// who waits for the task to complete.
//
- if (workItem != null)
- workItem.MarkAborted(tae);
+ workItem?.MarkAborted(tae);
//
// In this case, the VM is going to request another thread on our behalf. No need to do it twice.
}
// we can never reach this point, but the C# compiler doesn't know that, because it doesn't know the ThreadAbortException will be reraised above.
- Debug.Assert(false);
+ Debug.Fail("Should never reach this point");
return true;
}
}
try { }
finally
{
- IThreadPoolWorkItem cb = null;
+ IThreadPoolWorkItem cb;
if (workStealingQueue.LocalPop(out cb))
{
Debug.Assert(null != cb);
- workQueue.Enqueue(cb, true);
+ workQueue.Enqueue(cb, forceGlobal:true);
}
else
{
internal sealed class RegisteredWaitHandleSafe : CriticalFinalizerObject
{
- private static IntPtr InvalidHandle
- {
- get
- {
- return Win32Native.INVALID_HANDLE_VALUE;
- }
- }
- private IntPtr registeredWaitHandle;
+ private static IntPtr InvalidHandle => Win32Native.INVALID_HANDLE_VALUE;
+ private IntPtr registeredWaitHandle = InvalidHandle;
private WaitHandle m_internalWaitObject;
private bool bReleaseNeeded = false;
private volatile int m_lock = 0;
- internal RegisteredWaitHandleSafe()
- {
- registeredWaitHandle = InvalidHandle;
- }
-
- internal IntPtr GetHandle()
- {
- return registeredWaitHandle;
- }
+ internal IntPtr GetHandle() => registeredWaitHandle;
internal void SetHandle(IntPtr handle)
{
return result;
}
- private bool ValidHandle()
- {
- return (registeredWaitHandle != InvalidHandle && registeredWaitHandle != IntPtr.Zero);
- }
+ private bool ValidHandle() =>
+ registeredWaitHandle != InvalidHandle && registeredWaitHandle != IntPtr.Zero;
~RegisteredWaitHandleSafe()
{
private static extern bool UnregisterWaitNative(IntPtr handle, SafeHandle waitObject);
}
-[System.Runtime.InteropServices.ComVisible(true)]
+ [System.Runtime.InteropServices.ComVisible(true)]
public sealed class RegisteredWaitHandle : MarshalByRefObject {
- private RegisteredWaitHandleSafe internalRegisteredWait;
+ private readonly RegisteredWaitHandleSafe internalRegisteredWait;
internal RegisteredWaitHandle()
{
internalRegisteredWait.SetWaitObject(waitObject);
}
-
-[System.Runtime.InteropServices.ComVisible(true)]
+ [System.Runtime.InteropServices.ComVisible(true)]
// This is the only public method on this class
public bool Unregister(
WaitHandle waitObject // object to be notified when all callbacks to delegates have completed
//
internal static class _ThreadPoolWaitCallback
{
- static internal bool PerformWaitCallback()
- {
- return ThreadPoolWorkQueue.Dispatch();
- }
+ internal static bool PerformWaitCallback() => ThreadPoolWorkQueue.Dispatch();
}
//
internal sealed class QueueUserWorkItemCallback : IThreadPoolWorkItem
{
private WaitCallback callback;
- private ExecutionContext context;
- private Object state;
+ private readonly ExecutionContext context;
+ private readonly Object state;
#if DEBUG
volatile int executed;
void IThreadPoolWorkItem.ExecuteWorkItem()
{
#if DEBUG
- MarkExecuted(false);
+ MarkExecuted(aborted:false);
#endif
// call directly if it is an unsafe call OR EC flow is suppressed
if (context == null)
}
else
{
- ExecutionContext.Run(context, ccb, this, true);
+ ExecutionContext.Run(context, ccb, this, preserveSyncCtx:true);
}
}
#if DEBUG
// this workitem didn't execute because we got a ThreadAbortException prior to the call to ExecuteWorkItem.
// This counts as being executed for our purposes.
- MarkExecuted(true);
+ MarkExecuted(aborted:true);
#endif
}
- static internal ContextCallback ccb = new ContextCallback(WaitCallback_Context);
+ internal static readonly ContextCallback ccb = new ContextCallback(WaitCallback_Context);
- static private void WaitCallback_Context(Object state)
+ private static void WaitCallback_Context(Object state)
{
QueueUserWorkItemCallback obj = (QueueUserWorkItemCallback)state;
- WaitCallback wc = obj.callback as WaitCallback;
+ WaitCallback wc = obj.callback;
Debug.Assert(null != wc);
wc(obj.state);
}
internal sealed class QueueUserWorkItemCallbackDefaultContext : IThreadPoolWorkItem
{
private WaitCallback callback;
- private Object state;
+ private readonly Object state;
#if DEBUG
private volatile int executed;
void IThreadPoolWorkItem.ExecuteWorkItem()
{
#if DEBUG
- MarkExecuted(false);
+ MarkExecuted(aborted:false);
#endif
- ExecutionContext.Run(ExecutionContext.PreAllocatedDefault, ccb, this, true);
+ ExecutionContext.Run(ExecutionContext.PreAllocatedDefault, ccb, this, preserveSyncCtx:true);
}
void IThreadPoolWorkItem.MarkAborted(ThreadAbortException tae)
#if DEBUG
// this workitem didn't execute because we got a ThreadAbortException prior to the call to ExecuteWorkItem.
// This counts as being executed for our purposes.
- MarkExecuted(true);
+ MarkExecuted(aborted:true);
#endif
}
- static internal ContextCallback ccb = new ContextCallback(WaitCallback_Context);
+ internal static readonly ContextCallback ccb = new ContextCallback(WaitCallback_Context);
- static private void WaitCallback_Context(Object state)
+ private static void WaitCallback_Context(Object state)
{
QueueUserWorkItemCallbackDefaultContext obj = (QueueUserWorkItemCallbackDefaultContext)state;
- WaitCallback wc = obj.callback as WaitCallback;
+ WaitCallback wc = obj.callback;
Debug.Assert(null != wc);
obj.callback = null;
wc(obj.state);
WaitOrTimerCallback _waitOrTimerCallback;
ExecutionContext _executionContext;
Object _state;
- static private ContextCallback _ccbt = new ContextCallback(WaitOrTimerCallback_Context_t);
- static private ContextCallback _ccbf = new ContextCallback(WaitOrTimerCallback_Context_f);
+ private static readonly ContextCallback _ccbt = new ContextCallback(WaitOrTimerCallback_Context_t);
+ private static readonly ContextCallback _ccbf = new ContextCallback(WaitOrTimerCallback_Context_f);
internal _ThreadPoolWaitOrTimerCallback(WaitOrTimerCallback waitOrTimerCallback, Object state, bool compressStack, ref StackCrawlMark stackMark)
{
}
}
- static private void WaitOrTimerCallback_Context_t(Object state)
- {
- WaitOrTimerCallback_Context(state, true);
- }
+ private static void WaitOrTimerCallback_Context_t(Object state) =>
+ WaitOrTimerCallback_Context(state, timedOut:true);
- static private void WaitOrTimerCallback_Context_f(Object state)
- {
- WaitOrTimerCallback_Context(state, false);
- }
+ private static void WaitOrTimerCallback_Context_f(Object state) =>
+ WaitOrTimerCallback_Context(state, timedOut:false);
- static private void WaitOrTimerCallback_Context(Object state, bool timedOut)
+ private static void WaitOrTimerCallback_Context(Object state, bool timedOut)
{
_ThreadPoolWaitOrTimerCallback helper = (_ThreadPoolWaitOrTimerCallback)state;
helper._waitOrTimerCallback(helper._state, timedOut);
}
// call back helper
- static internal void PerformWaitOrTimerCallback(Object state, bool timedOut)
+ internal static void PerformWaitOrTimerCallback(Object state, bool timedOut)
{
_ThreadPoolWaitOrTimerCallback helper = (_ThreadPoolWaitOrTimerCallback)state;
Debug.Assert(helper != null, "Null state passed to PerformWaitOrTimerCallback!");
{
using (ExecutionContext executionContext = helper._executionContext.CreateCopy())
{
- if (timedOut)
- ExecutionContext.Run(executionContext, _ccbt, helper, true);
- else
- ExecutionContext.Run(executionContext, _ccbf, helper, true);
+ ExecutionContext.Run(executionContext, timedOut ? _ccbt : _ccbf, helper, preserveSyncCtx:true);
}
}
}
public static class ThreadPool
{
-
public static bool SetMaxThreads(int workerThreads, int completionPortThreads)
{
return SetMaxThreadsNative(workerThreads, completionPortThreads);
//ThreadPool has per-appdomain managed queue of work-items. The VM is
//responsible for just scheduling threads into appdomains. After that
//work-items are dispatched from the managed queue.
- private static bool QueueUserWorkItemHelper(WaitCallback callBack, Object state, ref StackCrawlMark stackMark, bool compressStack )
+ private static bool QueueUserWorkItemHelper(WaitCallback callBack, Object state, ref StackCrawlMark stackMark, bool compressStack)
{
- bool success = true;
-
- if (callBack != null)
+ if (callBack == null)
{
- //The thread pool maintains a per-appdomain managed work queue.
- //New thread pool entries are added in the managed queue.
- //The VM is responsible for the actual growing/shrinking of
- //threads.
-
- EnsureVMInitialized();
+ throw new ArgumentNullException(nameof(WaitCallback));
+ }
- //
- // If we are able to create the workitem, we need to get it in the queue without being interrupted
- // by a ThreadAbortException.
- //
- try { }
- finally
- {
- ExecutionContext context = compressStack && !ExecutionContext.IsFlowSuppressed() ?
- ExecutionContext.Capture(ref stackMark, ExecutionContext.CaptureOptions.IgnoreSyncCtx | ExecutionContext.CaptureOptions.OptimizeDefaultCase) :
- null;
+ //The thread pool maintains a per-appdomain managed work queue.
+ //New thread pool entries are added in the managed queue.
+ //The VM is responsible for the actual growing/shrinking of
+ //threads.
- IThreadPoolWorkItem tpcallBack = context == ExecutionContext.PreAllocatedDefault ?
- new QueueUserWorkItemCallbackDefaultContext(callBack, state) :
- (IThreadPoolWorkItem)new QueueUserWorkItemCallback(callBack, state, context);
+ EnsureVMInitialized();
- ThreadPoolGlobals.workQueue.Enqueue(tpcallBack, true);
- success = true;
- }
- }
- else
+ //
+ // If we are able to create the workitem, we need to get it in the queue without being interrupted
+ // by a ThreadAbortException.
+ //
+ try { }
+ finally
{
- throw new ArgumentNullException(nameof(WaitCallback));
+ ExecutionContext context = compressStack && !ExecutionContext.IsFlowSuppressed() ?
+ ExecutionContext.Capture(ref stackMark, ExecutionContext.CaptureOptions.IgnoreSyncCtx | ExecutionContext.CaptureOptions.OptimizeDefaultCase) :
+ null;
+
+ IThreadPoolWorkItem tpcallBack = context == ExecutionContext.PreAllocatedDefault ?
+ new QueueUserWorkItemCallbackDefaultContext(callBack, state) :
+ (IThreadPoolWorkItem)new QueueUserWorkItemCallback(callBack, state, context);
+
+ ThreadPoolGlobals.workQueue.Enqueue(tpcallBack, forceGlobal:true);
}
- return success;
+ return true;
}
internal static void UnsafeQueueCustomWorkItem(IThreadPoolWorkItem workItem, bool forceGlobal)
internal static bool TryPopCustomWorkItem(IThreadPoolWorkItem workItem)
{
Debug.Assert(null != workItem);
- if (!ThreadPoolGlobals.vmTpInitialized)
- return false; //Not initialized, so there's no way this workitem was ever queued.
- return ThreadPoolGlobals.workQueue.LocalFindAndPop(workItem);
+ return
+ ThreadPoolGlobals.vmTpInitialized && // if not initialized, so there's no way this workitem was ever queued.
+ ThreadPoolGlobals.workQueue.LocalFindAndPop(workItem);
}
// Get all workitems. Called by TaskScheduler in its debugger hooks.
// This is the method the debugger will actually call, if it ends up calling
// into ThreadPool directly. Tests can use this to simulate a debugger, as well.
- internal static object[] GetQueuedWorkItemsForDebugger()
- {
- return ToObjectArray(GetQueuedWorkItems());
- }
+ internal static object[] GetQueuedWorkItemsForDebugger() =>
+ ToObjectArray(GetQueuedWorkItems());
- internal static object[] GetGloballyQueuedWorkItemsForDebugger()
- {
- return ToObjectArray(GetGloballyQueuedWorkItems());
- }
+ internal static object[] GetGloballyQueuedWorkItemsForDebugger() =>
+ ToObjectArray(GetGloballyQueuedWorkItems());
- internal static object[] GetLocallyQueuedWorkItemsForDebugger()
- {
- return ToObjectArray(GetLocallyQueuedWorkItems());
- }
+ internal static object[] GetLocallyQueuedWorkItemsForDebugger() =>
+ ToObjectArray(GetLocallyQueuedWorkItems());
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
[SuppressUnmanagedCodeSecurity]
unsafe private static extern bool PostQueuedCompletionStatus(NativeOverlapped* overlapped);
[CLSCompliant(false)]
- unsafe public static bool UnsafeQueueNativeOverlapped(NativeOverlapped* overlapped)
- {
- return PostQueuedCompletionStatus(overlapped);
- }
+ unsafe public static bool UnsafeQueueNativeOverlapped(NativeOverlapped* overlapped) =>
+ PostQueuedCompletionStatus(overlapped);
private static void EnsureVMInitialized()
{
[Obsolete("ThreadPool.BindHandle(IntPtr) has been deprecated. Please use ThreadPool.BindHandle(SafeHandle) instead.", false)]
- public static bool BindHandle(
- IntPtr osHandle
- )
+ public static bool BindHandle(IntPtr osHandle)
{
return BindIOCompletionCallbackNative(osHandle);
}