summaryrefslogtreecommitdiff
path: root/src/mscorlib/src/System/Threading
diff options
context:
space:
mode:
Diffstat (limited to 'src/mscorlib/src/System/Threading')
-rw-r--r--src/mscorlib/src/System/Threading/ApartmentState.cs1
-rw-r--r--src/mscorlib/src/System/Threading/AsyncLocal.cs2
-rw-r--r--src/mscorlib/src/System/Threading/AutoResetEvent.cs2
-rw-r--r--src/mscorlib/src/System/Threading/CancellationToken.cs8
-rw-r--r--src/mscorlib/src/System/Threading/CancellationTokenRegistration.cs1
-rw-r--r--src/mscorlib/src/System/Threading/CancellationTokenSource.cs102
-rw-r--r--src/mscorlib/src/System/Threading/CountdownEvent.cs2
-rw-r--r--src/mscorlib/src/System/Threading/EventWaitHandle.cs14
-rw-r--r--src/mscorlib/src/System/Threading/ExecutionContext.cs62
-rw-r--r--src/mscorlib/src/System/Threading/IObjectHandle.cs31
-rw-r--r--src/mscorlib/src/System/Threading/Interlocked.cs20
-rw-r--r--src/mscorlib/src/System/Threading/LazyInitializer.cs1
-rw-r--r--src/mscorlib/src/System/Threading/LockCookie.cs57
-rw-r--r--src/mscorlib/src/System/Threading/LockRecursionException.cs1
-rw-r--r--src/mscorlib/src/System/Threading/ManualResetEvent.cs2
-rw-r--r--src/mscorlib/src/System/Threading/ManualResetEventSlim.cs2
-rw-r--r--src/mscorlib/src/System/Threading/Monitor.cs3
-rw-r--r--src/mscorlib/src/System/Threading/Mutex.cs52
-rw-r--r--src/mscorlib/src/System/Threading/Overlapped.cs54
-rw-r--r--src/mscorlib/src/System/Threading/ParameterizedThreadStart.cs1
-rw-r--r--src/mscorlib/src/System/Threading/ReaderWriterLock.cs276
-rw-r--r--src/mscorlib/src/System/Threading/SemaphoreSlim.cs6
-rw-r--r--src/mscorlib/src/System/Threading/SpinLock.cs82
-rw-r--r--src/mscorlib/src/System/Threading/SpinWait.cs1
-rw-r--r--src/mscorlib/src/System/Threading/SynchronizationContext.cs23
-rw-r--r--src/mscorlib/src/System/Threading/SynchronizationLockException.cs1
-rw-r--r--src/mscorlib/src/System/Threading/Tasks/BeginEndAwaitableAdapter.cs157
-rw-r--r--src/mscorlib/src/System/Threading/Tasks/ConcurrentExclusiveSchedulerPair.cs1
-rw-r--r--src/mscorlib/src/System/Threading/Tasks/FutureFactory.cs145
-rw-r--r--src/mscorlib/src/System/Threading/Tasks/IAsyncCausalityTracerStatics.cs14
-rw-r--r--src/mscorlib/src/System/Threading/Tasks/Parallel.cs3593
-rw-r--r--src/mscorlib/src/System/Threading/Tasks/ParallelLoopState.cs641
-rw-r--r--src/mscorlib/src/System/Threading/Tasks/ParallelRangeManager.cs279
-rw-r--r--src/mscorlib/src/System/Threading/Tasks/ProducerConsumerQueues.cs171
-rw-r--r--src/mscorlib/src/System/Threading/Tasks/TPLETWProvider.cs214
-rw-r--r--src/mscorlib/src/System/Threading/Tasks/Task.cs716
-rw-r--r--src/mscorlib/src/System/Threading/Tasks/TaskCompletionSource.cs17
-rw-r--r--src/mscorlib/src/System/Threading/Tasks/TaskContinuation.cs54
-rw-r--r--src/mscorlib/src/System/Threading/Tasks/TaskExceptionHolder.cs17
-rw-r--r--src/mscorlib/src/System/Threading/Tasks/TaskFactory.cs259
-rw-r--r--src/mscorlib/src/System/Threading/Tasks/TaskScheduler.cs1
-rw-r--r--src/mscorlib/src/System/Threading/Tasks/future.cs171
-rw-r--r--src/mscorlib/src/System/Threading/Thread.cs542
-rw-r--r--src/mscorlib/src/System/Threading/ThreadAbortException.cs6
-rw-r--r--src/mscorlib/src/System/Threading/ThreadInterruptedException.cs1
-rw-r--r--src/mscorlib/src/System/Threading/ThreadLocal.cs1
-rw-r--r--src/mscorlib/src/System/Threading/ThreadPool.cs960
-rw-r--r--src/mscorlib/src/System/Threading/ThreadPriority.cs1
-rw-r--r--src/mscorlib/src/System/Threading/ThreadStart.cs2
-rw-r--r--src/mscorlib/src/System/Threading/ThreadState.cs1
-rw-r--r--src/mscorlib/src/System/Threading/ThreadStateException.cs1
-rw-r--r--src/mscorlib/src/System/Threading/Timeout.cs2
-rw-r--r--src/mscorlib/src/System/Threading/Timer.cs147
-rw-r--r--src/mscorlib/src/System/Threading/Volatile.cs32
-rw-r--r--src/mscorlib/src/System/Threading/WaitHandle.cs13
55 files changed, 752 insertions, 8214 deletions
diff --git a/src/mscorlib/src/System/Threading/ApartmentState.cs b/src/mscorlib/src/System/Threading/ApartmentState.cs
index 844f85e..1edf0af 100644
--- a/src/mscorlib/src/System/Threading/ApartmentState.cs
+++ b/src/mscorlib/src/System/Threading/ApartmentState.cs
@@ -15,7 +15,6 @@
namespace System.Threading {
[Serializable]
-[System.Runtime.InteropServices.ComVisible(true)]
public enum ApartmentState
{
/*=========================================================================
diff --git a/src/mscorlib/src/System/Threading/AsyncLocal.cs b/src/mscorlib/src/System/Threading/AsyncLocal.cs
index 6ed1545..8c4319b 100644
--- a/src/mscorlib/src/System/Threading/AsyncLocal.cs
+++ b/src/mscorlib/src/System/Threading/AsyncLocal.cs
@@ -127,8 +127,6 @@ namespace System.Threading
{
public static IAsyncLocalValueMap Empty { get; } = new EmptyAsyncLocalValueMap();
- public static IAsyncLocalValueMap Create(IAsyncLocal key, object value) => new OneElementAsyncLocalValueMap(key, value);
-
// Instance without any key/value pairs. Used as a singleton/
private sealed class EmptyAsyncLocalValueMap : IAsyncLocalValueMap
{
diff --git a/src/mscorlib/src/System/Threading/AutoResetEvent.cs b/src/mscorlib/src/System/Threading/AutoResetEvent.cs
index 78a6fa1..fc6b230 100644
--- a/src/mscorlib/src/System/Threading/AutoResetEvent.cs
+++ b/src/mscorlib/src/System/Threading/AutoResetEvent.cs
@@ -14,10 +14,8 @@
namespace System.Threading {
using System;
- using System.Security.Permissions;
using System.Runtime.InteropServices;
- [System.Runtime.InteropServices.ComVisible(true)]
public sealed class AutoResetEvent : EventWaitHandle
{
public AutoResetEvent(bool initialState) : base(initialState,EventResetMode.AutoReset){ }
diff --git a/src/mscorlib/src/System/Threading/CancellationToken.cs b/src/mscorlib/src/System/Threading/CancellationToken.cs
index 5b78f20..b68ba4c 100644
--- a/src/mscorlib/src/System/Threading/CancellationToken.cs
+++ b/src/mscorlib/src/System/Threading/CancellationToken.cs
@@ -9,7 +9,6 @@
using System;
using System.Runtime.InteropServices;
-using System.Security.Permissions;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.Runtime;
@@ -38,7 +37,6 @@ namespace System.Threading
/// All members of this struct are thread-safe and may be used concurrently from multiple threads.
/// </para>
/// </remarks>
- [ComVisible(false)]
[DebuggerDisplay("IsCancellationRequested = {IsCancellationRequested}")]
public struct CancellationToken
{
@@ -317,11 +315,8 @@ namespace System.Threading
}
// the real work..
- [MethodImpl(MethodImplOptions.NoInlining)]
private CancellationTokenRegistration Register(Action<Object> callback, Object state, bool useSynchronizationContext, bool useExecutionContext)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
-
if (callback == null)
throw new ArgumentNullException(nameof(callback));
@@ -341,8 +336,7 @@ namespace System.Threading
if (useSynchronizationContext)
capturedSyncContext = SynchronizationContext.Current;
if (useExecutionContext)
- capturedExecutionContext = ExecutionContext.Capture(
- ref stackMark, ExecutionContext.CaptureOptions.OptimizeDefaultCase); // ideally we'd also use IgnoreSyncCtx, but that could break compat
+ capturedExecutionContext = ExecutionContext.Capture();
}
// Register the callback with the source.
diff --git a/src/mscorlib/src/System/Threading/CancellationTokenRegistration.cs b/src/mscorlib/src/System/Threading/CancellationTokenRegistration.cs
index ac27fe3..89e98fa 100644
--- a/src/mscorlib/src/System/Threading/CancellationTokenRegistration.cs
+++ b/src/mscorlib/src/System/Threading/CancellationTokenRegistration.cs
@@ -6,7 +6,6 @@
////////////////////////////////////////////////////////////////////////////////
using System.Diagnostics.Contracts;
-using System.Security.Permissions;
using System.Runtime.CompilerServices;
namespace System.Threading
diff --git a/src/mscorlib/src/System/Threading/CancellationTokenSource.cs b/src/mscorlib/src/System/Threading/CancellationTokenSource.cs
index fe9e0de..1e70d6f 100644
--- a/src/mscorlib/src/System/Threading/CancellationTokenSource.cs
+++ b/src/mscorlib/src/System/Threading/CancellationTokenSource.cs
@@ -10,7 +10,6 @@ using System;
using System.Security;
using System.Collections.Generic;
using System.Runtime.InteropServices;
-using System.Security.Permissions;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.Runtime;
@@ -35,7 +34,6 @@ namespace System.Threading
/// concurrently from multiple threads.
/// </para>
/// </remarks>
- [ComVisible(false)]
public class CancellationTokenSource : IDisposable
{
@@ -864,12 +862,19 @@ namespace System.Threading
/// <param name="token2">The second <see cref="T:System.Threading.CancellationToken">CancellationToken</see> to observe.</param>
/// <returns>A <see cref="T:System.Threading.CancellationTokenSource">CancellationTokenSource</see> that is linked
/// to the source tokens.</returns>
- public static CancellationTokenSource CreateLinkedTokenSource(CancellationToken token1, CancellationToken token2)
- {
- return token1.CanBeCanceled || token2.CanBeCanceled ?
- new LinkedCancellationTokenSource(token1, token2) :
- new CancellationTokenSource();
- }
+ public static CancellationTokenSource CreateLinkedTokenSource(CancellationToken token1, CancellationToken token2) =>
+ !token1.CanBeCanceled ? CreateLinkedTokenSource(token2) :
+ token2.CanBeCanceled ? new Linked2CancellationTokenSource(token1, token2) :
+ (CancellationTokenSource)new Linked1CancellationTokenSource(token1);
+
+ /// <summary>
+ /// Creates a <see cref="CancellationTokenSource"/> that will be in the canceled state
+ /// when any of the source tokens are in the canceled state.
+ /// </summary>
+ /// <param name="token">The first <see cref="T:System.Threading.CancellationToken">CancellationToken</see> to observe.</param>
+ /// <returns>A <see cref="CancellationTokenSource"/> that is linked to the source tokens.</returns>
+ internal static CancellationTokenSource CreateLinkedTokenSource(CancellationToken token) =>
+ token.CanBeCanceled ? new Linked1CancellationTokenSource(token) : new CancellationTokenSource();
/// <summary>
/// Creates a <see cref="T:System.Threading.CancellationTokenSource">CancellationTokenSource</see> that will be in the canceled state
@@ -884,14 +889,19 @@ namespace System.Threading
if (tokens == null)
throw new ArgumentNullException(nameof(tokens));
- if (tokens.Length == 0)
- throw new ArgumentException(Environment.GetResourceString("CancellationToken_CreateLinkedToken_TokensIsEmpty"));
-
- // a defensive copy is not required as the array has value-items that have only a single IntPtr field,
- // hence each item cannot be null itself, and reads of the payloads cannot be torn.
- Contract.EndContractBlock();
-
- return new LinkedCancellationTokenSource(tokens);
+ switch (tokens.Length)
+ {
+ case 0:
+ throw new ArgumentException(Environment.GetResourceString("CancellationToken_CreateLinkedToken_TokensIsEmpty"));
+ case 1:
+ return CreateLinkedTokenSource(tokens[0]);
+ case 2:
+ return CreateLinkedTokenSource(tokens[0], tokens[1]);
+ default:
+ // a defensive copy is not required as the array has value-items that have only a single reference field,
+ // hence each item cannot be null itself, and reads of the payloads cannot be torn.
+ return new LinkedNCancellationTokenSource(tokens);
+ }
}
@@ -907,35 +917,50 @@ namespace System.Threading
}
}
- private sealed class LinkedCancellationTokenSource : CancellationTokenSource
+ private sealed class Linked1CancellationTokenSource : CancellationTokenSource
{
- private static readonly Action<object> s_linkedTokenCancelDelegate =
- s => ((CancellationTokenSource)s).NotifyCancellation(throwOnFirstException: false); // skip ThrowIfDisposed() check in Cancel()
- private CancellationTokenRegistration[] m_linkingRegistrations;
+ private readonly CancellationTokenRegistration _reg1;
- internal LinkedCancellationTokenSource(CancellationToken token1, CancellationToken token2)
+ internal Linked1CancellationTokenSource(CancellationToken token1)
{
- bool token2CanBeCanceled = token2.CanBeCanceled;
+ _reg1 = token1.InternalRegisterWithoutEC(LinkedNCancellationTokenSource.s_linkedTokenCancelDelegate, this);
+ }
- if (token1.CanBeCanceled)
- {
- m_linkingRegistrations = new CancellationTokenRegistration[token2CanBeCanceled ? 2 : 1]; // there will be at least 1 and at most 2 linkings
- m_linkingRegistrations[0] = token1.InternalRegisterWithoutEC(s_linkedTokenCancelDelegate, this);
- }
+ protected override void Dispose(bool disposing)
+ {
+ if (!disposing || m_disposed) return;
+ _reg1.Dispose();
+ base.Dispose(disposing);
+ }
+ }
- if (token2CanBeCanceled)
- {
- int index = 1;
- if (m_linkingRegistrations == null)
- {
- m_linkingRegistrations = new CancellationTokenRegistration[1]; // this will be the only linking
- index = 0;
- }
- m_linkingRegistrations[index] = token2.InternalRegisterWithoutEC(s_linkedTokenCancelDelegate, this);
- }
+ private sealed class Linked2CancellationTokenSource : CancellationTokenSource
+ {
+ private readonly CancellationTokenRegistration _reg1;
+ private readonly CancellationTokenRegistration _reg2;
+
+ internal Linked2CancellationTokenSource(CancellationToken token1, CancellationToken token2)
+ {
+ _reg1 = token1.InternalRegisterWithoutEC(LinkedNCancellationTokenSource.s_linkedTokenCancelDelegate, this);
+ _reg2 = token2.InternalRegisterWithoutEC(LinkedNCancellationTokenSource.s_linkedTokenCancelDelegate, this);
}
- internal LinkedCancellationTokenSource(params CancellationToken[] tokens)
+ protected override void Dispose(bool disposing)
+ {
+ if (!disposing || m_disposed) return;
+ _reg1.Dispose();
+ _reg2.Dispose();
+ base.Dispose(disposing);
+ }
+ }
+
+ private sealed class LinkedNCancellationTokenSource : CancellationTokenSource
+ {
+ internal static readonly Action<object> s_linkedTokenCancelDelegate =
+ s => ((CancellationTokenSource)s).NotifyCancellation(throwOnFirstException: false); // skip ThrowIfDisposed() check in Cancel()
+ private CancellationTokenRegistration[] m_linkingRegistrations;
+
+ internal LinkedNCancellationTokenSource(params CancellationToken[] tokens)
{
m_linkingRegistrations = new CancellationTokenRegistration[tokens.Length];
@@ -968,7 +993,6 @@ namespace System.Threading
base.Dispose(disposing);
}
-
}
}
diff --git a/src/mscorlib/src/System/Threading/CountdownEvent.cs b/src/mscorlib/src/System/Threading/CountdownEvent.cs
index d86a2cc..af055e3 100644
--- a/src/mscorlib/src/System/Threading/CountdownEvent.cs
+++ b/src/mscorlib/src/System/Threading/CountdownEvent.cs
@@ -11,7 +11,6 @@
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
using System;
-using System.Security.Permissions;
using System.Runtime.InteropServices;
using System.Threading;
using System.Diagnostics;
@@ -30,7 +29,6 @@ namespace System.Threading
/// completed, and Reset, which should only be used when no other threads are
/// accessing the event.
/// </remarks>
- [ComVisible(false)]
[DebuggerDisplay("Initial Count={InitialCount}, Current Count={CurrentCount}")]
public class CountdownEvent : IDisposable
{
diff --git a/src/mscorlib/src/System/Threading/EventWaitHandle.cs b/src/mscorlib/src/System/Threading/EventWaitHandle.cs
index 4b1611c..0268948 100644
--- a/src/mscorlib/src/System/Threading/EventWaitHandle.cs
+++ b/src/mscorlib/src/System/Threading/EventWaitHandle.cs
@@ -15,10 +15,10 @@
namespace System.Security.AccessControl
{
- public class EventWaitHandleSecurity
+ internal class EventWaitHandleSecurity
{
}
- public enum EventWaitHandleRights
+ internal enum EventWaitHandleRights
{
}
}
@@ -28,7 +28,6 @@ namespace System.Threading
using System;
using System.Threading;
using System.Runtime.CompilerServices;
- using System.Security.Permissions;
using System.IO;
using Microsoft.Win32;
using Microsoft.Win32.SafeHandles;
@@ -89,7 +88,7 @@ namespace System.Threading
{
}
- public unsafe EventWaitHandle(bool initialState, EventResetMode mode, string name, out bool createdNew, EventWaitHandleSecurity eventSecurity)
+ internal unsafe EventWaitHandle(bool initialState, EventResetMode mode, string name, out bool createdNew, EventWaitHandleSecurity eventSecurity)
{
if(name != null)
{
@@ -146,7 +145,7 @@ namespace System.Threading
return OpenExisting(name, (EventWaitHandleRights)0);
}
- public static EventWaitHandle OpenExisting(string name, EventWaitHandleRights rights)
+ internal static EventWaitHandle OpenExisting(string name, EventWaitHandleRights rights)
{
EventWaitHandle result;
switch (OpenExistingWorker(name, rights, out result))
@@ -171,11 +170,6 @@ namespace System.Threading
return OpenExistingWorker(name, (EventWaitHandleRights)0, out result) == OpenExistingResult.Success;
}
- public static bool TryOpenExisting(string name, EventWaitHandleRights rights, out EventWaitHandle result)
- {
- return OpenExistingWorker(name, rights, out result) == OpenExistingResult.Success;
- }
-
private static OpenExistingResult OpenExistingWorker(string name, EventWaitHandleRights rights, out EventWaitHandle result)
{
#if PLATFORM_UNIX
diff --git a/src/mscorlib/src/System/Threading/ExecutionContext.cs b/src/mscorlib/src/System/Threading/ExecutionContext.cs
index 5ea9942..47a55a3 100644
--- a/src/mscorlib/src/System/Threading/ExecutionContext.cs
+++ b/src/mscorlib/src/System/Threading/ExecutionContext.cs
@@ -19,7 +19,6 @@ namespace System.Threading
using System.Reflection;
using System.Runtime.ExceptionServices;
using System.Runtime.Serialization;
- using System.Security.Permissions;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
using System.Runtime.ConstrainedExecution;
@@ -27,7 +26,6 @@ namespace System.Threading
using System.Diagnostics.Contracts;
using System.Diagnostics.CodeAnalysis;
- [System.Runtime.InteropServices.ComVisible(true)]
public delegate void ContextCallback(Object state);
internal struct ExecutionContextSwitcher
@@ -55,7 +53,7 @@ namespace System.Threading
[Serializable]
public sealed class ExecutionContext : IDisposable, ISerializable
{
- private static readonly ExecutionContext Default = new ExecutionContext();
+ internal static readonly ExecutionContext Default = new ExecutionContext();
private readonly IAsyncLocalValueMap m_localValues;
private readonly IAsyncLocal[] m_localChangeNotifications;
@@ -93,16 +91,10 @@ namespace System.Threading
public static ExecutionContext Capture()
{
ExecutionContext executionContext = Thread.CurrentThread.ExecutionContext;
- if (executionContext == null)
- {
- return Default;
- }
- if (executionContext.m_isFlowSuppressed)
- {
- // Prevent ExecutionContext.Run on a suppressed-flow context for desktop framework compatibility
- return null;
- }
- return executionContext;
+ return
+ executionContext == null ? Default :
+ executionContext.m_isFlowSuppressed ? null :
+ executionContext;
}
private ExecutionContext ShallowClone(bool isFlowSuppressed)
@@ -301,38 +293,6 @@ namespace System.Threading
}
}
- #region Wrappers for CLR compat, to avoid ifdefs all over the BCL
-
- [Flags]
- internal enum CaptureOptions
- {
- None = 0x00,
- IgnoreSyncCtx = 0x01,
- OptimizeDefaultCase = 0x02,
- }
-
- internal static ExecutionContext Capture(ref StackCrawlMark stackMark, CaptureOptions captureOptions)
- {
- return Capture();
- }
-
- [FriendAccessAllowed]
- internal static ExecutionContext FastCapture()
- {
- return Capture();
- }
-
- [FriendAccessAllowed]
- internal static void Run(ExecutionContext executionContext, ContextCallback callback, Object state, bool preserveSyncCtx)
- {
- Run(executionContext, callback, state);
- }
-
- internal bool IsDefaultFTContext(bool ignoreSyncCtx)
- {
- return this == Default;
- }
-
public ExecutionContext CreateCopy()
{
return this; // since CoreCLR's ExecutionContext is immutable, we don't need to create copies.
@@ -342,18 +302,6 @@ namespace System.Threading
{
// For CLR compat only
}
-
- internal static ExecutionContext PreAllocatedDefault
- {
- get { return ExecutionContext.Default; }
- }
-
- internal bool IsPreAllocatedDefault
- {
- get { return this == ExecutionContext.Default; }
- }
-
- #endregion
}
public struct AsyncFlowControl : IDisposable
diff --git a/src/mscorlib/src/System/Threading/IObjectHandle.cs b/src/mscorlib/src/System/Threading/IObjectHandle.cs
deleted file mode 100644
index 464f06e..0000000
--- a/src/mscorlib/src/System/Threading/IObjectHandle.cs
+++ /dev/null
@@ -1,31 +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.
-
-/*============================================================
-**
-**
-**
-** IObjectHandle defines the interface for unwrapping objects.
-** Objects that are marshal by value object can be returned through
-** an indirection allowing the caller to control when the
-** object is loaded into their domain. The caller can unwrap
-** the object from the indirection through this interface.
-**
-**
-===========================================================*/
-namespace System.Runtime.Remoting {
-
- using System;
- using System.Runtime.InteropServices;
-
- [ InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown),
- GuidAttribute("C460E2B4-E199-412a-8456-84DC3E4838C3") ]
- [System.Runtime.InteropServices.ComVisible(true)]
- public interface IObjectHandle {
- // Unwrap the object. Implementers of this interface
- // typically have an indirect referece to another object.
- Object Unwrap();
- }
-}
-
diff --git a/src/mscorlib/src/System/Threading/Interlocked.cs b/src/mscorlib/src/System/Threading/Interlocked.cs
index 8a0b527..131d51a 100644
--- a/src/mscorlib/src/System/Threading/Interlocked.cs
+++ b/src/mscorlib/src/System/Threading/Interlocked.cs
@@ -6,7 +6,6 @@
namespace System.Threading
{
using System;
- using System.Security.Permissions;
using System.Runtime.CompilerServices;
using System.Runtime.ConstrainedExecution;
using System.Runtime.Versioning;
@@ -25,13 +24,11 @@ namespace System.Threading
* long
*****************************/
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
public static int Increment(ref int location)
{
return Add(ref location, 1);
}
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
public static long Increment(ref long location)
{
return Add(ref location, 1);
@@ -43,7 +40,6 @@ namespace System.Threading
* long
*****************************/
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
public static int Decrement(ref int location)
{
return Add(ref location, -1);
@@ -65,7 +61,6 @@ namespace System.Threading
*****************************/
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
public static extern int Exchange(ref int location1, int value);
[MethodImplAttribute(MethodImplOptions.InternalCall)]
@@ -78,15 +73,11 @@ namespace System.Threading
public static extern double Exchange(ref double location1, double value);
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
public static extern Object Exchange(ref Object location1, Object value);
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
public static extern IntPtr Exchange(ref IntPtr location1, IntPtr value);
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
- [System.Runtime.InteropServices.ComVisible(false)]
public static T Exchange<T>(ref T location1, T value) where T : class
{
_Exchange(__makeref(location1), __makeref(value));
@@ -98,7 +89,6 @@ namespace System.Threading
}
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
private static extern void _Exchange(TypedReference location1, TypedReference value);
/******************************
@@ -112,7 +102,6 @@ namespace System.Threading
*****************************/
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
public static extern int CompareExchange(ref int location1, int value, int comparand);
[MethodImplAttribute(MethodImplOptions.InternalCall)]
@@ -125,11 +114,9 @@ namespace System.Threading
public static extern double CompareExchange(ref double location1, double value, double comparand);
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
public static extern Object CompareExchange(ref Object location1, Object value, Object comparand);
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
public static extern IntPtr CompareExchange(ref IntPtr location1, IntPtr value, IntPtr comparand);
/*****************************************************************
@@ -156,8 +143,6 @@ namespace System.Threading
* for details.
*****************************************************************/
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
- [System.Runtime.InteropServices.ComVisible(false)]
public static T CompareExchange<T>(ref T location1, T value, T comparand) where T : class
{
// _CompareExchange() passes back the value read from location1 via local named 'value'
@@ -166,12 +151,10 @@ namespace System.Threading
}
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
private static extern void _CompareExchange(TypedReference location1, TypedReference value, Object comparand);
// BCL-internal overload that returns success via a ref bool param, useful for reliable spin locks.
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
internal static extern int CompareExchange(ref int location1, int value, int comparand, ref bool succeeded);
/******************************
@@ -181,19 +164,16 @@ namespace System.Threading
*****************************/
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
internal static extern int ExchangeAdd(ref int location1, int value);
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern long ExchangeAdd(ref long location1, long value);
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
public static int Add(ref int location1, int value)
{
return ExchangeAdd(ref location1, value) + value;
}
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
public static long Add(ref long location1, long value)
{
return ExchangeAdd(ref location1, value) + value;
diff --git a/src/mscorlib/src/System/Threading/LazyInitializer.cs b/src/mscorlib/src/System/Threading/LazyInitializer.cs
index 238cc89..af32673 100644
--- a/src/mscorlib/src/System/Threading/LazyInitializer.cs
+++ b/src/mscorlib/src/System/Threading/LazyInitializer.cs
@@ -11,7 +11,6 @@
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-using System.Security.Permissions;
using System.Diagnostics;
using System.Diagnostics.Contracts;
namespace System.Threading
diff --git a/src/mscorlib/src/System/Threading/LockCookie.cs b/src/mscorlib/src/System/Threading/LockCookie.cs
deleted file mode 100644
index c1fbfd8..0000000
--- a/src/mscorlib/src/System/Threading/LockCookie.cs
+++ /dev/null
@@ -1,57 +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.
-
-//
-/*============================================================
-**
-**
-**
-** Purpose: Defines the lock that implements
-** single-writer/multiple-reader semantics
-**
-**
-===========================================================*/
-
-namespace System.Threading {
-
- using System;
- [System.Runtime.InteropServices.ComVisible(true)]
- public struct LockCookie
- {
- private int _dwFlags;
- private int _dwWriterSeqNum;
- private int _wReaderAndWriterLevel;
- private int _dwThreadID;
-
- public override int GetHashCode()
- {
- return _dwFlags + _dwWriterSeqNum + _wReaderAndWriterLevel + _dwThreadID;
- }
-
- public override bool Equals(Object obj)
- {
- if (obj is LockCookie)
- return Equals((LockCookie)obj);
- else
- return false;
- }
-
- public bool Equals(LockCookie obj)
- {
- return obj._dwFlags == _dwFlags && obj._dwWriterSeqNum == _dwWriterSeqNum &&
- obj._wReaderAndWriterLevel == _wReaderAndWriterLevel && obj._dwThreadID == _dwThreadID;
- }
-
- public static bool operator ==(LockCookie a, LockCookie b)
- {
- return a.Equals(b);
- }
-
- public static bool operator !=(LockCookie a, LockCookie b)
- {
- return !(a == b);
- }
- }
-}
-
diff --git a/src/mscorlib/src/System/Threading/LockRecursionException.cs b/src/mscorlib/src/System/Threading/LockRecursionException.cs
index ab95e70..40f04b0 100644
--- a/src/mscorlib/src/System/Threading/LockRecursionException.cs
+++ b/src/mscorlib/src/System/Threading/LockRecursionException.cs
@@ -19,7 +19,6 @@ namespace System.Threading
using System.Runtime.CompilerServices;
[Serializable]
- [System.Security.Permissions.HostProtection(MayLeakOnAbort = true)]
public class LockRecursionException : System.Exception
{
public LockRecursionException() { }
diff --git a/src/mscorlib/src/System/Threading/ManualResetEvent.cs b/src/mscorlib/src/System/Threading/ManualResetEvent.cs
index 0004156..a8e012f 100644
--- a/src/mscorlib/src/System/Threading/ManualResetEvent.cs
+++ b/src/mscorlib/src/System/Threading/ManualResetEvent.cs
@@ -14,10 +14,8 @@
namespace System.Threading {
using System;
- using System.Security.Permissions;
using System.Runtime.InteropServices;
-[System.Runtime.InteropServices.ComVisible(true)]
public sealed class ManualResetEvent : EventWaitHandle
{
public ManualResetEvent(bool initialState) : base(initialState,EventResetMode.ManualReset){}
diff --git a/src/mscorlib/src/System/Threading/ManualResetEventSlim.cs b/src/mscorlib/src/System/Threading/ManualResetEventSlim.cs
index 509af5b..2d57b41 100644
--- a/src/mscorlib/src/System/Threading/ManualResetEventSlim.cs
+++ b/src/mscorlib/src/System/Threading/ManualResetEventSlim.cs
@@ -13,7 +13,6 @@
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
using System;
-using System.Security.Permissions;
using System.Threading;
using System.Runtime.InteropServices;
using System.Diagnostics;
@@ -45,7 +44,6 @@ namespace System.Threading
/// completed, and Reset, which should only be used when no other threads are
/// accessing the event.
/// </remarks>
- [ComVisible(false)]
[DebuggerDisplay("Set = {IsSet}")]
public class ManualResetEventSlim : IDisposable
{
diff --git a/src/mscorlib/src/System/Threading/Monitor.cs b/src/mscorlib/src/System/Threading/Monitor.cs
index 94dec13..fdbc384 100644
--- a/src/mscorlib/src/System/Threading/Monitor.cs
+++ b/src/mscorlib/src/System/Threading/Monitor.cs
@@ -17,7 +17,6 @@
namespace System.Threading {
using System;
- using System.Security.Permissions;
using System.Runtime;
using System.Runtime.Remoting;
using System.Threading;
@@ -27,7 +26,6 @@ namespace System.Threading {
using System.Diagnostics;
using System.Diagnostics.Contracts;
- [System.Runtime.InteropServices.ComVisible(true)]
public static class Monitor
{
/*=========================================================================
@@ -76,7 +74,6 @@ namespace System.Threading {
** own the lock.
=========================================================================*/
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
public static extern void Exit(Object obj);
/*=========================================================================
diff --git a/src/mscorlib/src/System/Threading/Mutex.cs b/src/mscorlib/src/System/Threading/Mutex.cs
index 506abb7..dcb8213 100644
--- a/src/mscorlib/src/System/Threading/Mutex.cs
+++ b/src/mscorlib/src/System/Threading/Mutex.cs
@@ -16,7 +16,6 @@ namespace System.Threading
using System;
using System.Threading;
using System.Runtime.CompilerServices;
- using System.Security.Permissions;
using System.IO;
using Microsoft.Win32;
using Microsoft.Win32.SafeHandles;
@@ -27,23 +26,20 @@ namespace System.Threading
using System.Diagnostics;
using System.Diagnostics.Contracts;
- [ComVisible(true)]
public sealed class Mutex : WaitHandle
{
static bool dummyBool;
- public class MutexSecurity
+ internal class MutexSecurity
{
}
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
public Mutex(bool initiallyOwned, String name, out bool createdNew)
: this(initiallyOwned, name, out createdNew, (MutexSecurity)null)
{
}
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
- public unsafe Mutex(bool initiallyOwned, String name, out bool createdNew, MutexSecurity mutexSecurity)
+ internal unsafe Mutex(bool initiallyOwned, String name, out bool createdNew, MutexSecurity mutexSecurity)
{
if (name == string.Empty)
{
@@ -62,26 +58,6 @@ namespace System.Threading
CreateMutexWithGuaranteedCleanup(initiallyOwned, name, out createdNew, secAttrs);
}
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
- internal Mutex(bool initiallyOwned, String name, out bool createdNew, Win32Native.SECURITY_ATTRIBUTES secAttrs)
- {
- if (name == string.Empty)
- {
- // Empty name is treated as an unnamed mutex. Set to null, and we will check for null from now on.
- name = null;
- }
-#if !PLATFORM_UNIX
- if (name != null && System.IO.Path.MaxPath < name.Length)
- {
- throw new ArgumentException(Environment.GetResourceString("Argument_WaitHandleNameTooLong", Path.MaxPath), nameof(name));
- }
-#endif
- Contract.EndContractBlock();
-
- CreateMutexWithGuaranteedCleanup(initiallyOwned, name, out createdNew, secAttrs);
- }
-
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
internal void CreateMutexWithGuaranteedCleanup(bool initiallyOwned, String name, out bool createdNew, Win32Native.SECURITY_ATTRIBUTES secAttrs)
{
RuntimeHelpers.CleanupCode cleanupCode = new RuntimeHelpers.CleanupCode(MutexCleanupCode);
@@ -104,7 +80,6 @@ namespace System.Threading
Win32Native.SECURITY_ATTRIBUTES m_secAttrs;
Mutex m_mutex;
- [PrePrepareMethod]
internal MutexTryCodeHelper(bool initiallyOwned,MutexCleanupInfo cleanupInfo, String name, Win32Native.SECURITY_ATTRIBUTES secAttrs, Mutex mutex)
{
Debug.Assert(name == null || name.Length != 0);
@@ -116,7 +91,6 @@ namespace System.Threading
m_mutex = mutex;
}
- [PrePrepareMethod]
internal void MutexTryCode(object userData)
{
SafeWaitHandle mutexHandle = null;
@@ -153,7 +127,7 @@ namespace System.Threading
#if PLATFORM_UNIX
case Win32Native.ERROR_FILENAME_EXCED_RANGE:
// On Unix, length validation is done by CoreCLR's PAL after converting to utf-8
- throw new ArgumentException(Environment.GetResourceString("Argument_WaitHandleNameTooLong", PathInternal.MaxComponentLength), "name");
+ throw new ArgumentException(Environment.GetResourceString("Argument_WaitHandleNameTooLong", Interop.Sys.MaxName), "name");
#endif
case Win32Native.ERROR_INVALID_HANDLE:
@@ -170,7 +144,6 @@ namespace System.Threading
}
}
- [PrePrepareMethod]
private void MutexCleanupCode(Object userData, bool exceptionThrown)
{
MutexCleanupInfo cleanupInfo = (MutexCleanupInfo) userData;
@@ -198,21 +171,17 @@ namespace System.Threading
}
}
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
public Mutex(bool initiallyOwned, String name) : this(initiallyOwned, name, out dummyBool) {
}
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
public Mutex(bool initiallyOwned) : this(initiallyOwned, null, out dummyBool)
{
}
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
public Mutex() : this(false, null, out dummyBool)
{
}
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
private Mutex(SafeWaitHandle handle)
{
SetHandleInternal(handle);
@@ -224,11 +193,11 @@ namespace System.Threading
return OpenExisting(name, (MutexRights) 0);
}
- public enum MutexRights
+ internal enum MutexRights
{
}
- public static Mutex OpenExisting(string name, MutexRights rights)
+ internal static Mutex OpenExisting(string name, MutexRights rights)
{
Mutex result;
switch (OpenExistingWorker(name, rights, out result))
@@ -253,11 +222,6 @@ namespace System.Threading
return OpenExistingWorker(name, (MutexRights)0, out result) == OpenExistingResult.Success;
}
- public static bool TryOpenExisting(string name, MutexRights rights, out Mutex result)
- {
- return OpenExistingWorker(name, rights, out result) == OpenExistingResult.Success;
- }
-
private static OpenExistingResult OpenExistingWorker(string name, MutexRights rights, out Mutex result)
{
if (name == null)
@@ -294,7 +258,7 @@ namespace System.Threading
if (name != null && errorCode == Win32Native.ERROR_FILENAME_EXCED_RANGE)
{
// On Unix, length validation is done by CoreCLR's PAL after converting to utf-8
- throw new ArgumentException(Environment.GetResourceString("Argument_WaitHandleNameTooLong", PathInternal.MaxComponentLength), nameof(name));
+ throw new ArgumentException(Environment.GetResourceString("Argument_WaitHandleNameTooLong", Interop.Sys.MaxName), nameof(name));
}
#endif
@@ -316,7 +280,6 @@ namespace System.Threading
// Note: To call ReleaseMutex, you must have an ACL granting you
// MUTEX_MODIFY_STATE rights (0x0001). The other interesting value
// in a Mutex's ACL is MUTEX_ALL_ACCESS (0x1F0001).
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
public void ReleaseMutex()
{
if (Win32Native.ReleaseMutex(safeWaitHandle))
@@ -324,11 +287,10 @@ namespace System.Threading
}
else
{
- throw new Exception(Environment.GetResourceString("Arg_SynchronizationLockException"));
+ throw new ApplicationException(Environment.GetResourceString("Arg_SynchronizationLockException"));
}
}
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
static int CreateMutexHandle(bool initiallyOwned, String name, Win32Native.SECURITY_ATTRIBUTES securityAttribute, out SafeWaitHandle mutexHandle)
{
int errorCode;
diff --git a/src/mscorlib/src/System/Threading/Overlapped.cs b/src/mscorlib/src/System/Threading/Overlapped.cs
index 2b192c7..d3caff5 100644
--- a/src/mscorlib/src/System/Threading/Overlapped.cs
+++ b/src/mscorlib/src/System/Threading/Overlapped.cs
@@ -31,7 +31,6 @@ namespace System.Threading
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
- using System.Security.Permissions;
using System.Runtime.ConstrainedExecution;
using System.Diagnostics;
using System.Diagnostics.Contracts;
@@ -44,7 +43,6 @@ namespace System.Threading
// The first five matches OVERLAPPED structure.
// The remaining are reserved at the end
[System.Runtime.InteropServices.StructLayout(LayoutKind.Sequential)]
- [System.Runtime.InteropServices.ComVisible(true)]
public struct NativeOverlapped
{
public IntPtr InternalLow;
@@ -71,13 +69,11 @@ namespace System.Threading
{
}
- internal _IOCompletionCallback(IOCompletionCallback ioCompletionCallback, ref StackCrawlMark stackMark)
+ internal _IOCompletionCallback(IOCompletionCallback ioCompletionCallback)
{
_ioCompletionCallback = ioCompletionCallback;
// clone the exection context
- _executionContext = ExecutionContext.Capture(
- ref stackMark,
- ExecutionContext.CaptureOptions.IgnoreSyncCtx | ExecutionContext.CaptureOptions.OptimizeDefaultCase);
+ _executionContext = ExecutionContext.Capture();
}
// Context callback: same sig for SendOrPostCallback and ContextCallback
static internal ContextCallback _ccb = new ContextCallback(IOCompletionCallback_Context);
@@ -103,26 +99,23 @@ namespace System.Threading
overlapped = OverlappedData.GetOverlappedFromNative(pOVERLAP).m_overlapped;
helper = overlapped.iocbHelper;
- if (helper == null || helper._executionContext == null || helper._executionContext.IsDefaultFTContext(true))
- {
- // We got here because of UnsafePack (or) Pack with EC flow supressed
- IOCompletionCallback callback = overlapped.UserCallback;
- callback( errorCode, numBytes, pOVERLAP);
- }
- else
- {
- // We got here because of Pack
- helper._errorCode = errorCode;
- helper._numBytes = numBytes;
- helper._pOVERLAP = pOVERLAP;
- using (ExecutionContext executionContext = helper._executionContext.CreateCopy())
- ExecutionContext.Run(executionContext, _ccb, helper, true);
- }
-
- //Quickly check the VM again, to see if a packet has arrived.
-
+ if (helper == null || helper._executionContext == null || helper._executionContext == ExecutionContext.Default)
+ {
+ // We got here because of UnsafePack (or) Pack with EC flow supressed
+ IOCompletionCallback callback = overlapped.UserCallback;
+ callback( errorCode, numBytes, pOVERLAP);
+ }
+ else
+ {
+ // We got here because of Pack
+ helper._errorCode = errorCode;
+ helper._numBytes = numBytes;
+ helper._pOVERLAP = pOVERLAP;
+ ExecutionContext.Run(helper._executionContext, _ccb, helper);
+ }
+
+ //Quickly check the VM again, to see if a packet has arrived.
OverlappedData.CheckVMForIOPacket(out pOVERLAP, out errorCode, out numBytes);
-
} while (pOVERLAP != null);
}
@@ -174,17 +167,15 @@ namespace System.Threading
m_nativeOverlapped.InternalHigh = (IntPtr)0;
}
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
unsafe internal NativeOverlapped* Pack(IOCompletionCallback iocb, Object userData)
{
if (!m_pinSelf.IsNull()) {
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_Overlapped_Pack"));
}
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
if (iocb != null)
{
- m_iocbHelper = new _IOCompletionCallback(iocb, ref stackMark);
+ m_iocbHelper = new _IOCompletionCallback(iocb);
m_iocb = iocb;
}
else
@@ -229,7 +220,6 @@ namespace System.Threading
return AllocateNativeOverlapped();
}
- [ComVisible(false)]
internal IntPtr UserHandle
{
get { return m_nativeOverlapped.EventHandle; }
@@ -255,7 +245,6 @@ namespace System.Threading
#region class Overlapped
/// <internalonly/>
- [System.Runtime.InteropServices.ComVisible(true)]
public class Overlapped
{
private OverlappedData m_overlappedData;
@@ -307,7 +296,6 @@ namespace System.Threading
set { m_overlappedData.UserHandle = new IntPtr(value); }
}
- [ComVisible(false)]
public IntPtr EventHandleIntPtr
{
get { return m_overlappedData.UserHandle; }
@@ -336,7 +324,7 @@ namespace System.Threading
return Pack (iocb, null);
}
- [CLSCompliant(false),ComVisible(false)]
+ [CLSCompliant(false)]
unsafe public NativeOverlapped* Pack(IOCompletionCallback iocb, Object userData)
{
return m_overlappedData.Pack(iocb, userData);
@@ -349,7 +337,7 @@ namespace System.Threading
return UnsafePack (iocb, null);
}
- [CLSCompliant(false), ComVisible(false)]
+ [CLSCompliant(false)]
unsafe public NativeOverlapped* UnsafePack(IOCompletionCallback iocb, Object userData)
{
return m_overlappedData.UnsafePack(iocb, userData);
diff --git a/src/mscorlib/src/System/Threading/ParameterizedThreadStart.cs b/src/mscorlib/src/System/Threading/ParameterizedThreadStart.cs
index 45d24fe..32b6315 100644
--- a/src/mscorlib/src/System/Threading/ParameterizedThreadStart.cs
+++ b/src/mscorlib/src/System/Threading/ParameterizedThreadStart.cs
@@ -15,7 +15,6 @@
namespace System.Threading {
- using System.Security.Permissions;
using System.Threading;
using System.Runtime.InteropServices;
diff --git a/src/mscorlib/src/System/Threading/ReaderWriterLock.cs b/src/mscorlib/src/System/Threading/ReaderWriterLock.cs
deleted file mode 100644
index e35ac76..0000000
--- a/src/mscorlib/src/System/Threading/ReaderWriterLock.cs
+++ /dev/null
@@ -1,276 +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.
-
-//
-/*============================================================
-**
-**
-**
-** Purpose: Defines the lock that implements
-** single-writer/multiple-reader semantics
-**
-**
-===========================================================*/
-
-#if FEATURE_RWLOCK
-namespace System.Threading {
- using System.Threading;
- using System.Security.Permissions;
- using System.Runtime.Remoting;
- using System;
- using System.Runtime.CompilerServices;
- using System.Runtime.InteropServices;
- using System.Runtime.ConstrainedExecution;
- using System.Runtime.Versioning;
- using System.Diagnostics.Contracts;
-
- [ComVisible(true)]
- public sealed class ReaderWriterLock: CriticalFinalizerObject
- {
- /*
- * Constructor
- */
- public ReaderWriterLock()
- {
- PrivateInitialize();
- }
-
- /*
- * Destructor
- */
- ~ReaderWriterLock()
- {
- PrivateDestruct();
- }
-
- /*
- * Property that returns TRUE if the reader lock is held
- * by the current thread
- */
- public bool IsReaderLockHeld {
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
- get {
- return(PrivateGetIsReaderLockHeld());
- }
- }
-
- /*
- * Property that returns TRUE if the writer lock is held
- * by the current thread
- */
- public bool IsWriterLockHeld {
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
- get {
- return(PrivateGetIsWriterLockHeld());
- }
- }
-
- /*
- * Property that returns the current writer sequence number.
- * The caller should be a reader or writer for getting
- * meaningful results
- */
- public int WriterSeqNum {
- get {
- return(PrivateGetWriterSeqNum());
- }
- }
-
- /*
- * Acquires reader lock. The thread will block if a different
- * thread has writer lock.
- */
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- private extern void AcquireReaderLockInternal(int millisecondsTimeout);
-
- public void AcquireReaderLock(int millisecondsTimeout)
- {
- AcquireReaderLockInternal(millisecondsTimeout);
- }
-
-
- public void AcquireReaderLock(TimeSpan timeout)
- {
- long tm = (long)timeout.TotalMilliseconds;
- if (tm < -1 || tm > (long) Int32.MaxValue)
- throw new ArgumentOutOfRangeException(nameof(timeout), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
- AcquireReaderLockInternal((int)tm);
- }
-
- /*
- * Acquires writer lock. The thread will block if a different
- * thread has reader lock. It will dead lock if this thread
- * has reader lock. Use UpgardeToWriterLock when you are not
- * sure if the thread has reader lock
- */
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- private extern void AcquireWriterLockInternal(int millisecondsTimeout);
-
- public void AcquireWriterLock(int millisecondsTimeout)
- {
- AcquireWriterLockInternal(millisecondsTimeout);
- }
-
- public void AcquireWriterLock(TimeSpan timeout)
- {
- long tm = (long)timeout.TotalMilliseconds;
- if (tm < -1 || tm > (long) Int32.MaxValue)
- throw new ArgumentOutOfRangeException(nameof(timeout), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
- AcquireWriterLockInternal((int)tm);
- }
-
-
- /*
- * Releases reader lock.
- */
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
- private extern void ReleaseReaderLockInternal();
-
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
- public void ReleaseReaderLock()
- {
- ReleaseReaderLockInternal();
- }
-
- /*
- * Releases writer lock.
- */
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
- private extern void ReleaseWriterLockInternal();
-
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
- public void ReleaseWriterLock()
- {
- ReleaseWriterLockInternal();
- }
-
- /*
- * Upgardes the thread to a writer. If the thread has is a
- * reader, it is possible that the reader lock was
- * released before writer lock was acquired.
- */
- public LockCookie UpgradeToWriterLock(int millisecondsTimeout)
- {
- LockCookie result = new LockCookie ();
- FCallUpgradeToWriterLock (ref result, millisecondsTimeout);
- return result;
- }
-
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- private extern void FCallUpgradeToWriterLock(ref LockCookie result, int millisecondsTimeout);
-
- public LockCookie UpgradeToWriterLock(TimeSpan timeout)
- {
- long tm = (long)timeout.TotalMilliseconds;
- if (tm < -1 || tm > (long) Int32.MaxValue)
- throw new ArgumentOutOfRangeException(nameof(timeout), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
- return UpgradeToWriterLock((int)tm);
- }
-
- /*
- * Restores the lock status of the thread to the one it was
- * in when it called UpgradeToWriterLock.
- */
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- private extern void DowngradeFromWriterLockInternal(ref LockCookie lockCookie);
-
- public void DowngradeFromWriterLock(ref LockCookie lockCookie)
- {
- DowngradeFromWriterLockInternal(ref lockCookie);
- }
-
- /*
- * Releases the lock irrespective of the number of times the thread
- * acquired the lock
- */
- public LockCookie ReleaseLock()
- {
- LockCookie result = new LockCookie ();
- FCallReleaseLock (ref result);
- return result;
- }
-
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- private extern void FCallReleaseLock(ref LockCookie result);
-
- /*
- * Restores the lock status of the thread to the one it was
- * in when it called ReleaseLock.
- */
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- private extern void RestoreLockInternal(ref LockCookie lockCookie);
-
- public void RestoreLock(ref LockCookie lockCookie)
- {
- RestoreLockInternal(ref lockCookie);
- }
-
- /*
- * Internal helper that returns TRUE if the reader lock is held
- * by the current thread
- */
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
- private extern bool PrivateGetIsReaderLockHeld();
-
- /*
- * Internal helper that returns TRUE if the writer lock is held
- * by the current thread
- */
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
- private extern bool PrivateGetIsWriterLockHeld();
-
- /*
- * Internal helper that returns the current writer sequence
- * number. The caller should be a reader or writer for getting
- * meaningful results
- */
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- private extern int PrivateGetWriterSeqNum();
-
- /*
- * Returns true if there were intermediate writes since the
- * sequence number was obtained. The caller should be
- * a reader or writer for getting meaningful results
- */
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- public extern bool AnyWritersSince(int seqNum);
-
- // Initialize state kept inside the lock
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- private extern void PrivateInitialize();
-
- // Destruct resource associated with the lock
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- private extern void PrivateDestruct();
-
- // State
-#pragma warning disable 169
-#pragma warning disable 414 // These fields are not used from managed.
- private IntPtr _hWriterEvent;
- private IntPtr _hReaderEvent;
- private IntPtr _hObjectHandle;
- private int _dwState = 0;
- private int _dwULockID = 0;
- private int _dwLLockID = 0;
- private int _dwWriterID = 0;
- private int _dwWriterSeqNum = 0;
- private short _wWriterLevel;
-#if RWLOCK_STATISTICS
- // WARNING: You must explicitly #define RWLOCK_STATISTICS when you
- // build in both the VM and BCL directories if you want this.
- private int _dwReaderEntryCount = 0;
- private int _dwReaderContentionCount = 0;
- private int _dwWriterEntryCount = 0;
- private int _dwWriterContentionCount = 0;
- private int _dwEventsReleasedCount = 0;
-#endif // RWLOCK_STATISTICS
-#pragma warning restore 414
-#pragma warning restore 169
- }
-}
-#endif //FEATURE_RWLOCK
diff --git a/src/mscorlib/src/System/Threading/SemaphoreSlim.cs b/src/mscorlib/src/System/Threading/SemaphoreSlim.cs
index 92d760d..c3b43d9 100644
--- a/src/mscorlib/src/System/Threading/SemaphoreSlim.cs
+++ b/src/mscorlib/src/System/Threading/SemaphoreSlim.cs
@@ -16,7 +16,6 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Security;
-using System.Security.Permissions;
using System.Runtime.InteropServices;
using System.Diagnostics.Contracts;
using System.Threading.Tasks;
@@ -39,7 +38,6 @@ namespace System.Threading
/// completed.
/// </para>
/// </remarks>
- [ComVisible(false)]
[DebuggerDisplay("Current Count = {m_currentCount}")]
public class SemaphoreSlim : IDisposable
{
@@ -315,7 +313,7 @@ namespace System.Threading
if (millisecondsTimeout < -1)
{
throw new ArgumentOutOfRangeException(
- "totalMilliSeconds", millisecondsTimeout, GetResourceString("SemaphoreSlim_Wait_TimeoutWrong"));
+ nameof(millisecondsTimeout), millisecondsTimeout, GetResourceString("SemaphoreSlim_Wait_TimeoutWrong"));
}
cancellationToken.ThrowIfCancellationRequested();
@@ -609,7 +607,7 @@ namespace System.Threading
if (millisecondsTimeout < -1)
{
throw new ArgumentOutOfRangeException(
- "totalMilliSeconds", millisecondsTimeout, GetResourceString("SemaphoreSlim_Wait_TimeoutWrong"));
+ nameof(millisecondsTimeout), millisecondsTimeout, GetResourceString("SemaphoreSlim_Wait_TimeoutWrong"));
}
// Bail early for cancellation
diff --git a/src/mscorlib/src/System/Threading/SpinLock.cs b/src/mscorlib/src/System/Threading/SpinLock.cs
index 1d90890..eee73ce 100644
--- a/src/mscorlib/src/System/Threading/SpinLock.cs
+++ b/src/mscorlib/src/System/Threading/SpinLock.cs
@@ -9,19 +9,14 @@
// repeatedly checking until the lock becomes available. As the thread remains active performing a non-useful task,
// the use of such a lock is a kind of busy waiting and consumes CPU resources without performing real work.
//
-//
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-using System;
-using System.Security.Permissions;
+
+using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
-using System.Runtime.ConstrainedExecution;
-using System.Diagnostics;
-using System.Diagnostics.Contracts;
namespace System.Threading
{
-
/// <summary>
/// Provides a mutual exclusion lock primitive where a thread trying to acquire the lock waits in a loop
/// repeatedly checking until the lock becomes available.
@@ -54,7 +49,6 @@ namespace System.Threading
/// concurrently.
/// </para>
/// </remarks>
- [ComVisible(false)]
[DebuggerTypeProxy(typeof(SystemThreading_SpinLockDebugView))]
[DebuggerDisplay("IsHeld = {IsHeld}")]
public struct SpinLock
@@ -106,6 +100,14 @@ namespace System.Threading
// The waiters count is calculated by m_owner & WAITERS_MASK 01111....110
private static int MAXIMUM_WAITERS = WAITERS_MASK;
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private int CompareExchange(ref int location, int value, int comparand, ref bool success)
+ {
+ int result = Interlocked.CompareExchange(ref location, value, comparand);
+ success = (result == comparand);
+ return result;
+ }
+
/// <summary>
/// Initializes a new instance of the <see cref="T:System.Threading.SpinLock"/>
/// structure with the option to track thread IDs to improve debugging.
@@ -158,9 +160,8 @@ namespace System.Threading
int observedOwner = m_owner;
if (lockTaken || //invalid parameter
(observedOwner & ID_DISABLED_AND_ANONYMOUS_OWNED) != LOCK_ID_DISABLE_MASK || //thread tracking is enabled or the lock is already acquired
- Interlocked.CompareExchange(ref m_owner, observedOwner | LOCK_ANONYMOUS_OWNED, observedOwner, ref lockTaken) != observedOwner) //acquiring the lock failed
+ CompareExchange(ref m_owner, observedOwner | LOCK_ANONYMOUS_OWNED, observedOwner, ref lockTaken) != observedOwner) //acquiring the lock failed
ContinueTryEnter(Timeout.Infinite, ref lockTaken); // Then try the slow path if any of the above conditions is met
-
}
/// <summary>
@@ -183,7 +184,22 @@ namespace System.Threading
/// </exception>
public void TryEnter(ref bool lockTaken)
{
- TryEnter(0, ref lockTaken);
+ int observedOwner = m_owner;
+ if (((observedOwner & LOCK_ID_DISABLE_MASK) == 0) | lockTaken)
+ {
+ // Thread tracking enabled or invalid arg. Take slow path.
+ ContinueTryEnter(0, ref lockTaken);
+ }
+ else if ((observedOwner & LOCK_ANONYMOUS_OWNED) != 0)
+ {
+ // Lock already held by someone
+ lockTaken = false;
+ }
+ else
+ {
+ // Lock wasn't held; try to acquire it.
+ CompareExchange(ref m_owner, observedOwner | LOCK_ANONYMOUS_OWNED, observedOwner, ref lockTaken);
+ }
}
/// <summary>
@@ -219,7 +235,7 @@ namespace System.Threading
if (totalMilliseconds < -1 || totalMilliseconds > int.MaxValue)
{
throw new System.ArgumentOutOfRangeException(
- nameof(timeout), timeout, Environment.GetResourceString("SpinLock_TryEnter_ArgumentOutOfRange"));
+ nameof(timeout), timeout, SR.SpinLock_TryEnter_ArgumentOutOfRange);
}
// Call reliable enter with the int-based timeout milliseconds
@@ -254,7 +270,7 @@ namespace System.Threading
if (millisecondsTimeout < -1 || //invalid parameter
lockTaken || //invalid parameter
(observedOwner & ID_DISABLED_AND_ANONYMOUS_OWNED) != LOCK_ID_DISABLE_MASK || //thread tracking is enabled or the lock is already acquired
- Interlocked.CompareExchange(ref m_owner, observedOwner | LOCK_ANONYMOUS_OWNED, observedOwner, ref lockTaken) != observedOwner) // acquiring the lock failed
+ CompareExchange(ref m_owner, observedOwner | LOCK_ANONYMOUS_OWNED, observedOwner, ref lockTaken) != observedOwner) // acquiring the lock failed
ContinueTryEnter(millisecondsTimeout, ref lockTaken); // The call the slow pth
}
@@ -271,13 +287,13 @@ namespace System.Threading
if (lockTaken)
{
lockTaken = false;
- throw new System.ArgumentException(Environment.GetResourceString("SpinLock_TryReliableEnter_ArgumentException"));
+ throw new System.ArgumentException(SR.SpinLock_TryReliableEnter_ArgumentException);
}
if (millisecondsTimeout < -1)
{
throw new ArgumentOutOfRangeException(
- nameof(millisecondsTimeout), millisecondsTimeout, Environment.GetResourceString("SpinLock_TryEnter_ArgumentOutOfRange"));
+ nameof(millisecondsTimeout), millisecondsTimeout, SR.SpinLock_TryEnter_ArgumentOutOfRange);
}
uint startTime = 0;
@@ -311,7 +327,7 @@ namespace System.Threading
observedOwner = m_owner;
if ((observedOwner & LOCK_ANONYMOUS_OWNED) == LOCK_UNOWNED)
{
- if (Interlocked.CompareExchange(ref m_owner, observedOwner | 1, observedOwner, ref lockTaken) == observedOwner)
+ if (CompareExchange(ref m_owner, observedOwner | 1, observedOwner, ref lockTaken) == observedOwner)
{
// Aquired lock
return;
@@ -331,7 +347,7 @@ namespace System.Threading
else //failed to acquire the lock,then try to update the waiters. If the waiters count reached the maximum, jsut break the loop to avoid overflow
{
if ((observedOwner & WAITERS_MASK) != MAXIMUM_WAITERS)
- turn = (Interlocked.Add(ref m_owner, 2) & WAITERS_MASK) >> 1 ;
+ turn = (Interlocked.Add(ref m_owner, 2) & WAITERS_MASK) >> 1;
}
//***Step 2. Spinning
@@ -353,7 +369,7 @@ namespace System.Threading
: (observedOwner - 2) | 1; // otherwise decrement the waiters and set the lock bit
Debug.Assert((newOwner & WAITERS_MASK) >= 0);
- if (Interlocked.CompareExchange(ref m_owner, newOwner, observedOwner, ref lockTaken) == observedOwner)
+ if (CompareExchange(ref m_owner, newOwner, observedOwner, ref lockTaken) == observedOwner)
{
return;
}
@@ -381,7 +397,7 @@ namespace System.Threading
: (observedOwner - 2) | 1; // otherwise decrement the waiters and set the lock bit
Debug.Assert((newOwner & WAITERS_MASK) >= 0);
- if (Interlocked.CompareExchange(ref m_owner, newOwner, observedOwner, ref lockTaken) == observedOwner)
+ if (CompareExchange(ref m_owner, newOwner, observedOwner, ref lockTaken) == observedOwner)
{
return;
}
@@ -431,7 +447,6 @@ namespace System.Threading
}
spinner.SpinOnce();
}
-
}
/// <summary>
@@ -444,11 +459,11 @@ namespace System.Threading
int lockUnowned = 0;
// We are using thread IDs to mark ownership. Snap the thread ID and check for recursion.
// We also must or the ID enablement bit, to ensure we propagate when we CAS it in.
- int m_newOwner = Thread.CurrentThread.ManagedThreadId;
+ int m_newOwner = Environment.CurrentManagedThreadId;
if (m_owner == m_newOwner)
{
// We don't allow lock recursion.
- throw new LockRecursionException(Environment.GetResourceString("SpinLock_TryEnter_LockRecursionException"));
+ throw new LockRecursionException(SR.SpinLock_TryEnter_LockRecursionException);
}
@@ -457,7 +472,6 @@ namespace System.Threading
// Loop until the lock has been successfully acquired or, if specified, the timeout expires.
do
{
-
// We failed to get the lock, either from the fast route or the last iteration
// and the timeout hasn't expired; spin once and try again.
spinner.SpinOnce();
@@ -466,7 +480,7 @@ namespace System.Threading
if (m_owner == lockUnowned)
{
- if (Interlocked.CompareExchange(ref m_owner, m_newOwner, lockUnowned, ref lockTaken) == lockUnowned)
+ if (CompareExchange(ref m_owner, m_newOwner, lockUnowned, ref lockTaken) == lockUnowned)
{
return;
}
@@ -491,7 +505,6 @@ namespace System.Threading
/// <exception cref="SynchronizationLockException">
/// Thread ownership tracking is enabled, and the current thread is not the owner of this lock.
/// </exception>
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
public void Exit()
{
//This is the fast path for the thread tracking is disabled, otherwise go to the slow path
@@ -517,15 +530,14 @@ namespace System.Threading
/// <exception cref="SynchronizationLockException">
/// Thread ownership tracking is enabled, and the current thread is not the owner of this lock.
/// </exception>
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
public void Exit(bool useMemoryBarrier)
{
// This is the fast path for the thread tracking is diabled and not to use memory barrier, otherwise go to the slow path
// The reason not to add else statement if the usememorybarrier is that it will add more barnching in the code and will prevent
- // method inlining, so this is optimized for useMemoryBarrier=false and Exit() overload optimized for useMemoryBarrier=true
- if ((m_owner & LOCK_ID_DISABLE_MASK) != 0 && !useMemoryBarrier)
+ // method inlining, so this is optimized for useMemoryBarrier=false and Exit() overload optimized for useMemoryBarrier=true.
+ int tmpOwner = m_owner;
+ if ((tmpOwner & LOCK_ID_DISABLE_MASK) != 0 & !useMemoryBarrier)
{
- int tmpOwner = m_owner;
m_owner = tmpOwner & (~LOCK_ANONYMOUS_OWNED);
}
else
@@ -545,7 +557,7 @@ namespace System.Threading
if (threadTrackingEnabled && !IsHeldByCurrentThread)
{
throw new System.Threading.SynchronizationLockException(
- Environment.GetResourceString("SpinLock_Exit_SynchronizationLockException"));
+ SR.SpinLock_Exit_SynchronizationLockException);
}
if (useMemoryBarrier)
@@ -554,7 +566,6 @@ namespace System.Threading
Interlocked.Exchange(ref m_owner, LOCK_UNOWNED);
else
Interlocked.Decrement(ref m_owner);
-
}
else
{
@@ -565,9 +576,7 @@ namespace System.Threading
int tmpOwner = m_owner;
m_owner = tmpOwner & (~LOCK_ANONYMOUS_OWNED);
}
-
}
-
}
/// <summary>
@@ -575,7 +584,6 @@ namespace System.Threading
/// </summary>
public bool IsHeld
{
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
get
{
if (IsThreadOwnerTrackingEnabled)
@@ -601,21 +609,19 @@ namespace System.Threading
/// </exception>
public bool IsHeldByCurrentThread
{
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
get
{
if (!IsThreadOwnerTrackingEnabled)
{
- throw new InvalidOperationException(Environment.GetResourceString("SpinLock_IsHeldByCurrentThread"));
+ throw new InvalidOperationException(SR.SpinLock_IsHeldByCurrentThread);
}
- return ((m_owner & (~LOCK_ID_DISABLE_MASK)) == Thread.CurrentThread.ManagedThreadId);
+ return ((m_owner & (~LOCK_ID_DISABLE_MASK)) == Environment.CurrentManagedThreadId);
}
}
/// <summary>Gets whether thread ownership tracking is enabled for this instance.</summary>
public bool IsThreadOwnerTrackingEnabled
{
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
get { return (m_owner & LOCK_ID_DISABLE_MASK) == 0; }
}
diff --git a/src/mscorlib/src/System/Threading/SpinWait.cs b/src/mscorlib/src/System/Threading/SpinWait.cs
index 1b31407..8431f65 100644
--- a/src/mscorlib/src/System/Threading/SpinWait.cs
+++ b/src/mscorlib/src/System/Threading/SpinWait.cs
@@ -12,7 +12,6 @@
using System;
using System.Runtime.ConstrainedExecution;
-using System.Security.Permissions;
using System.Threading;
using System.Diagnostics;
using System.Diagnostics.Contracts;
diff --git a/src/mscorlib/src/System/Threading/SynchronizationContext.cs b/src/mscorlib/src/System/Threading/SynchronizationContext.cs
index 5531597..f4b3c79 100644
--- a/src/mscorlib/src/System/Threading/SynchronizationContext.cs
+++ b/src/mscorlib/src/System/Threading/SynchronizationContext.cs
@@ -13,12 +13,9 @@
namespace System.Threading
{
using Microsoft.Win32.SafeHandles;
- using System.Security.Permissions;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
-#if FEATURE_CORRUPTING_EXCEPTIONS
using System.Runtime.ExceptionServices;
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
using System.Runtime;
using System.Runtime.Versioning;
using System.Runtime.ConstrainedExecution;
@@ -29,14 +26,12 @@ namespace System.Threading
using System.Diagnostics.CodeAnalysis;
-#if FEATURE_SYNCHRONIZATIONCONTEXT_WAIT
[Flags]
enum SynchronizationContextProperties
{
None = 0,
RequireWaitNotification = 0x1
};
-#endif
#if FEATURE_COMINTEROP && FEATURE_APPX
//
@@ -52,15 +47,12 @@ namespace System.Threading
public class SynchronizationContext
{
-#if FEATURE_SYNCHRONIZATIONCONTEXT_WAIT
SynchronizationContextProperties _props = SynchronizationContextProperties.None;
-#endif
public SynchronizationContext()
{
}
-#if FEATURE_SYNCHRONIZATIONCONTEXT_WAIT
// helper delegate to statically bind to Wait method
private delegate int WaitDelegate(IntPtr[] waitHandles, bool waitAll, int millisecondsTimeout);
@@ -109,7 +101,6 @@ namespace System.Threading
{
return ((_props & SynchronizationContextProperties.RequireWaitNotification) != 0);
}
-#endif
public virtual void Send(SendOrPostCallback d, Object state)
@@ -137,10 +128,8 @@ namespace System.Threading
{
}
-#if FEATURE_SYNCHRONIZATIONCONTEXT_WAIT
// Method called when the CLR does a wait operation
[CLSCompliant(false)]
- [PrePrepareMethod]
public virtual int Wait(IntPtr[] waitHandles, bool waitAll, int millisecondsTimeout)
{
return WaitHelper(waitHandles, waitAll, millisecondsTimeout);
@@ -148,8 +137,6 @@ namespace System.Threading
// Method that can be called by Wait overrides
[CLSCompliant(false)]
- [PrePrepareMethod]
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
protected static int WaitHelper(IntPtr[] waitHandles, bool waitAll, int millisecondsTimeout)
{
if (waitHandles == null)
@@ -164,22 +151,14 @@ namespace System.Threading
// Static helper to which the above method can delegate to in order to get the default
// COM behavior.
[CLSCompliant(false)]
- [PrePrepareMethod]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
private static extern int WaitHelperNative(IntPtr[] waitHandles, bool waitAll, int millisecondsTimeout);
-#endif
public static void SetSynchronizationContext(SynchronizationContext syncContext)
{
Thread.CurrentThread.SynchronizationContext = syncContext;
}
- public static void SetThreadStaticContext(SynchronizationContext syncContext)
- {
- Thread.CurrentThread.SynchronizationContext = syncContext;
- }
-
public static SynchronizationContext Current
{
get
@@ -260,11 +239,9 @@ namespace System.Threading
return new SynchronizationContext();
}
-#if FEATURE_SYNCHRONIZATIONCONTEXT_WAIT
private static int InvokeWaitMethodHelper(SynchronizationContext syncContext, IntPtr[] waitHandles, bool waitAll, int millisecondsTimeout)
{
return syncContext.Wait(waitHandles, waitAll, millisecondsTimeout);
}
-#endif
}
}
diff --git a/src/mscorlib/src/System/Threading/SynchronizationLockException.cs b/src/mscorlib/src/System/Threading/SynchronizationLockException.cs
index 0610a60..de42c1f 100644
--- a/src/mscorlib/src/System/Threading/SynchronizationLockException.cs
+++ b/src/mscorlib/src/System/Threading/SynchronizationLockException.cs
@@ -17,7 +17,6 @@ namespace System.Threading {
using System;
using System.Runtime.Serialization;
- [System.Runtime.InteropServices.ComVisible(true)]
[Serializable]
public class SynchronizationLockException : SystemException {
public SynchronizationLockException()
diff --git a/src/mscorlib/src/System/Threading/Tasks/BeginEndAwaitableAdapter.cs b/src/mscorlib/src/System/Threading/Tasks/BeginEndAwaitableAdapter.cs
deleted file mode 100644
index 71eb787..0000000
--- a/src/mscorlib/src/System/Threading/Tasks/BeginEndAwaitableAdapter.cs
+++ /dev/null
@@ -1,157 +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.Diagnostics.Contracts;
-using System.IO;
-using System.Runtime.CompilerServices;
-using System.Security;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace System.Threading.Tasks {
-
-/// <summary>
-/// Provides an adapter to make Begin/End pairs awaitable.
-/// In general, Task.Factory.FromAsync should be used for this purpose.
-/// However, for cases where absolute minimal overhead is required, this type
-/// may be used to making APM pairs awaitable while minimizing overhead.
-/// (APM = Asynchronous Programming Model or the Begin/End pattern.)
-/// </summary>
-/// <remarks>
-/// This instance may be reused repeatedly. However, it must only be used
-/// by a single APM invocation at a time. It's state will automatically be reset
-/// when the await completes.
-/// </remarks>
-/// <example>
-/// Usage sample:
-/// <code>
-/// static async Task CopyStreamAsync(Stream source, Stream dest) {
-///
-/// BeginEndAwaitableAdapter adapter = new BeginEndAwaitableAdapter();
-/// Byte[] buffer = new Byte[0x1000];
-///
-/// while (true) {
-///
-/// source.BeginRead(buffer, 0, buffer.Length, BeginEndAwaitableAdapter.Callback, adapter);
-/// Int32 numRead = source.EndRead(await adapter);
-/// if (numRead == 0)
-/// break;
-///
-/// dest.BeginWrite(buffer, 0, numRead, BeginEndAwaitableAdapter.Callback, adapter);
-/// dest.EndWrite(await adapter);
-/// }
-/// }
-/// </code>
-/// </example>
-internal sealed class BeginEndAwaitableAdapter : ICriticalNotifyCompletion {
-
- /// <summary>A sentinel marker used to communicate between OnCompleted and the APM callback
- /// that the callback has already run, and thus OnCompleted needs to execute the callback.</summary>
- private readonly static Action CALLBACK_RAN = () => { };
-
- /// <summary>The IAsyncResult for the APM operation.</summary>
- private IAsyncResult _asyncResult;
-
- /// <summary>The continuation delegate provided to the awaiter.</summary>
- private Action _continuation;
-
-
- /// <summary>A callback to be passed as the AsyncCallback to an APM pair.
- /// It expects that an BeginEndAwaitableAdapter instance was supplied to the APM Begin method as the object state.</summary>
- public readonly static AsyncCallback Callback = (asyncResult) => {
-
- Debug.Assert(asyncResult != null);
- Debug.Assert(asyncResult.IsCompleted);
- Debug.Assert(asyncResult.AsyncState is BeginEndAwaitableAdapter);
-
- // Get the adapter object supplied as the "object state" to the Begin method
- BeginEndAwaitableAdapter adapter = (BeginEndAwaitableAdapter) asyncResult.AsyncState;
-
- // Store the IAsyncResult into it so that it's available to the awaiter
- adapter._asyncResult = asyncResult;
-
- // If the _continuation has already been set to the actual continuation by OnCompleted, then invoke the continuation.
- // Set _continuation to the CALLBACK_RAN sentinel so that IsCompleted returns true and OnCompleted sees the sentinel
- // and knows to invoke the callback.
- // Due to some known incorrect implementations of IAsyncResult in the Framework where CompletedSynchronously is lazily
- // set to true if it is first invoked after IsCompleted is true, we cannot rely here on CompletedSynchronously for
- // synchronization between the caller and the callback, and thus do not use CompletedSynchronously at all.
- Action continuation = Interlocked.Exchange(ref adapter._continuation, CALLBACK_RAN);
- if (continuation != null) {
-
- Debug.Assert(continuation != CALLBACK_RAN);
- continuation();
- }
- };
-
-
- /// <summary>Gets an awaiter.</summary>
- /// <returns>Returns itself as the awaiter.</returns>
- public BeginEndAwaitableAdapter GetAwaiter() {
-
- return this;
- }
-
-
- /// <summary>Gets whether the awaited APM operation completed.</summary>
- public bool IsCompleted {
- get {
-
- // We are completed if the callback was called and it set the continuation to the CALLBACK_RAN sentinel.
- // If the operation completes asynchronously, there's still a chance we'll see CALLBACK_RAN here, in which
- // case we're still good to keep running synchronously.
- return (_continuation == CALLBACK_RAN);
- }
- }
-
- /// <summary>Schedules the continuation to run when the operation completes.</summary>
- /// <param name="continuation">The continuation.</param>
- public void UnsafeOnCompleted(Action continuation) {
-
- Debug.Assert(continuation != null);
- OnCompleted(continuation);
- }
-
-
- /// <summary>Schedules the continuation to run when the operation completes.</summary>
- /// <param name="continuation">The continuation.</param>
- public void OnCompleted(Action continuation) {
-
- Debug.Assert(continuation != null);
-
- // If the continuation field is null, then set it to be the target continuation
- // so that when the operation completes, it'll invoke the continuation. If it's non-null,
- // it was already set to the CALLBACK_RAN-sentinel by the Callback, in which case we hit a very rare race condition
- // where the operation didn't complete synchronously but completed asynchronously between our
- // calls to IsCompleted and OnCompleted... in that case, just schedule a task to run the continuation.
- if (_continuation == CALLBACK_RAN
- || Interlocked.CompareExchange(ref _continuation, continuation, null) == CALLBACK_RAN) {
-
- Task.Run(continuation); // must run async at this point, or else we'd risk stack diving
- }
- }
-
-
- /// <summary>Gets the IAsyncResult for the APM operation after the operation completes, and then resets the adapter.</summary>
- /// <returns>The IAsyncResult for the operation.</returns>
- public IAsyncResult GetResult() {
-
- Debug.Assert(_asyncResult != null && _asyncResult.IsCompleted);
-
- // Get the IAsyncResult
- IAsyncResult result = _asyncResult;
-
- // Reset the adapter
- _asyncResult = null;
- _continuation = null;
-
- // Return the result
- return result;
- }
-
-} // class BeginEndAwaitableAdapter
-
-} // namespace
diff --git a/src/mscorlib/src/System/Threading/Tasks/ConcurrentExclusiveSchedulerPair.cs b/src/mscorlib/src/System/Threading/Tasks/ConcurrentExclusiveSchedulerPair.cs
index c7a96b0..a87406a 100644
--- a/src/mscorlib/src/System/Threading/Tasks/ConcurrentExclusiveSchedulerPair.cs
+++ b/src/mscorlib/src/System/Threading/Tasks/ConcurrentExclusiveSchedulerPair.cs
@@ -20,7 +20,6 @@ using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Contracts;
using System.Security;
-using System.Security.Permissions;
namespace System.Threading.Tasks
{
diff --git a/src/mscorlib/src/System/Threading/Tasks/FutureFactory.cs b/src/mscorlib/src/System/Threading/Tasks/FutureFactory.cs
index c98e219..137afa1 100644
--- a/src/mscorlib/src/System/Threading/Tasks/FutureFactory.cs
+++ b/src/mscorlib/src/System/Threading/Tasks/FutureFactory.cs
@@ -12,7 +12,6 @@
using System;
using System.Security;
-using System.Security.Permissions;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Diagnostics;
@@ -277,13 +276,11 @@ namespace System.Threading.Tasks
/// However, unless creation and scheduling must be separated, StartNew is the recommended approach
/// for both simplicity and performance.
/// </remarks>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> StartNew(Func<TResult> function)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
Task currTask = Task.InternalCurrent;
return Task<TResult>.StartNew(currTask, function, m_defaultCancellationToken,
- m_defaultCreationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask), ref stackMark);
+ m_defaultCreationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask));
}
/// <summary>
@@ -306,13 +303,11 @@ namespace System.Threading.Tasks
/// However, unless creation and scheduling must be separated, StartNew is the recommended approach
/// for both simplicity and performance.
/// </remarks>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> StartNew(Func<TResult> function, CancellationToken cancellationToken)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
Task currTask = Task.InternalCurrent;
return Task<TResult>.StartNew(currTask, function, cancellationToken,
- m_defaultCreationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask), ref stackMark);
+ m_defaultCreationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask));
}
/// <summary>
@@ -337,13 +332,11 @@ namespace System.Threading.Tasks
/// However, unless creation and scheduling must be separated, StartNew is the recommended approach
/// for both simplicity and performance.
/// </remarks>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> StartNew(Func<TResult> function, TaskCreationOptions creationOptions)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
Task currTask = Task.InternalCurrent;
return Task<TResult>.StartNew(currTask, function, m_defaultCancellationToken,
- creationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask), ref stackMark);
+ creationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask));
}
/// <summary>
@@ -379,13 +372,11 @@ namespace System.Threading.Tasks
/// However, unless creation and scheduling must be separated, StartNew is the recommended approach
/// for both simplicity and performance.
/// </remarks>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> StartNew(Func<TResult> function, CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskScheduler scheduler)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
return Task<TResult>.StartNew(
Task.InternalCurrentIfAttached(creationOptions), function, cancellationToken,
- creationOptions, InternalTaskOptions.None, scheduler, ref stackMark);
+ creationOptions, InternalTaskOptions.None, scheduler);
}
/// <summary>
@@ -406,13 +397,11 @@ namespace System.Threading.Tasks
/// However, unless creation and scheduling must be separated, StartNew is the recommended approach
/// for both simplicity and performance.
/// </remarks>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> StartNew(Func<Object, TResult> function, Object state)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
Task currTask = Task.InternalCurrent;
return Task<TResult>.StartNew(currTask, function, state, m_defaultCancellationToken,
- m_defaultCreationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask), ref stackMark);
+ m_defaultCreationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask));
}
/// <summary>
@@ -437,13 +426,11 @@ namespace System.Threading.Tasks
/// However, unless creation and scheduling must be separated, StartNew is the recommended approach
/// for both simplicity and performance.
/// </remarks>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> StartNew(Func<Object, TResult> function, Object state, CancellationToken cancellationToken)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
Task currTask = Task.InternalCurrent;
return Task<TResult>.StartNew(currTask, function, state, cancellationToken,
- m_defaultCreationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask), ref stackMark);
+ m_defaultCreationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask));
}
/// <summary>
@@ -470,13 +457,11 @@ namespace System.Threading.Tasks
/// However, unless creation and scheduling must be separated, StartNew is the recommended approach
/// for both simplicity and performance.
/// </remarks>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> StartNew(Func<Object, TResult> function, Object state, TaskCreationOptions creationOptions)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
Task currTask = Task.InternalCurrent;
return Task<TResult>.StartNew(currTask, function, state, m_defaultCancellationToken,
- creationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask), ref stackMark);
+ creationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask));
}
/// <summary>
@@ -514,12 +499,10 @@ namespace System.Threading.Tasks
/// However, unless creation and scheduling must be separated, StartNew is the recommended approach
/// for both simplicity and performance.
/// </remarks>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> StartNew(Func<Object, TResult> function, Object state, CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskScheduler scheduler)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
return Task<TResult>.StartNew(Task.InternalCurrentIfAttached(creationOptions), function, state, cancellationToken,
- creationOptions, InternalTaskOptions.None, scheduler, ref stackMark);
+ creationOptions, InternalTaskOptions.None, scheduler);
}
//
@@ -604,11 +587,9 @@ namespace System.Threading.Tasks
/// <paramref name="endMethod"/> argument is null.</exception>
/// <returns>A <see cref="T:System.Threading.Tasks.Task{TResult}">Task</see> that represents the
/// asynchronous operation.</returns>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> FromAsync(IAsyncResult asyncResult, Func<IAsyncResult, TResult> endMethod)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return FromAsyncImpl(asyncResult, endMethod, null, m_defaultCreationOptions, DefaultScheduler, ref stackMark);
+ return FromAsyncImpl(asyncResult, endMethod, null, m_defaultCreationOptions, DefaultScheduler);
}
/// <summary>
@@ -630,14 +611,12 @@ namespace System.Threading.Tasks
/// value.</exception>
/// <returns>A <see cref="T:System.Threading.Tasks.Task{TResult}">Task</see> that represents the
/// asynchronous operation.</returns>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> FromAsync(
IAsyncResult asyncResult,
Func<IAsyncResult, TResult> endMethod,
TaskCreationOptions creationOptions)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return FromAsyncImpl(asyncResult, endMethod, null, creationOptions, DefaultScheduler, ref stackMark);
+ return FromAsyncImpl(asyncResult, endMethod, null, creationOptions, DefaultScheduler);
}
@@ -665,27 +644,23 @@ namespace System.Threading.Tasks
/// value.</exception>
/// <returns>A <see cref="T:System.Threading.Tasks.Task{TResult}">Task</see> that represents the
/// asynchronous operation.</returns>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> FromAsync(
IAsyncResult asyncResult,
Func<IAsyncResult, TResult> endMethod,
TaskCreationOptions creationOptions,
TaskScheduler scheduler)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return FromAsyncImpl(asyncResult, endMethod, null, creationOptions, scheduler, ref stackMark);
+ return FromAsyncImpl(asyncResult, endMethod, null, creationOptions, scheduler);
}
- // internal overload that supports StackCrawlMark
- // We also need this logic broken out into a static method so that the similar TaskFactory.FromAsync()
+ // We need this logic broken out into a static method so that the similar TaskFactory.FromAsync()
// method can access the logic w/o declaring a TaskFactory<TResult> instance.
internal static Task<TResult> FromAsyncImpl(
IAsyncResult asyncResult,
Func<IAsyncResult, TResult> endFunction,
Action<IAsyncResult> endAction,
TaskCreationOptions creationOptions,
- TaskScheduler scheduler,
- ref StackCrawlMark stackMark)
+ TaskScheduler scheduler)
{
if (asyncResult == null)
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.asyncResult);
@@ -714,12 +689,12 @@ namespace System.Threading.Tasks
// Just specify this task as detached. No matter what happens, we want endMethod
// to be called -- even if the parent is canceled. So we don't want to flow
// RespectParentCancellation.
- Task t = new Task(delegate
+ Task t = new Task(new Action<object>(delegate
{
FromAsyncCoreLogic(asyncResult, endFunction, endAction, promise, requiresSynchronization:true);
- },
+ }),
(object)null, null,
- default(CancellationToken), TaskCreationOptions.None, InternalTaskOptions.None, null, ref stackMark);
+ default(CancellationToken), TaskCreationOptions.None, InternalTaskOptions.None, null);
if (AsyncCausalityTracer.LoggingOn)
AsyncCausalityTracer.TraceOperationCreation(CausalityTraceLevel.Verbose, t.Id, "TaskFactory.FromAsync Callback", 0);
@@ -1428,14 +1403,12 @@ namespace System.Threading.Tasks
/// <paramref name="tasks"/> array contains a null value.</exception>
/// <exception cref="T:System.ArgumentException">The exception that is thrown when the
/// <paramref name="tasks"/> array is empty.</exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWhenAll(Task[] tasks, Func<Task[], TResult> continuationFunction)
{
if (continuationFunction == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.continuationFunction);
Contract.EndContractBlock();
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWhenAllImpl(tasks, continuationFunction, null, m_defaultContinuationOptions, m_defaultCancellationToken, DefaultScheduler, ref stackMark);
+ return ContinueWhenAllImpl(tasks, continuationFunction, null, m_defaultContinuationOptions, m_defaultCancellationToken, DefaultScheduler);
}
/// <summary>
@@ -1459,14 +1432,12 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
/// has already been disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWhenAll(Task[] tasks, Func<Task[], TResult> continuationFunction, CancellationToken cancellationToken)
{
if (continuationFunction == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.continuationFunction);
Contract.EndContractBlock();
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWhenAllImpl(tasks, continuationFunction, null, m_defaultContinuationOptions, cancellationToken, DefaultScheduler, ref stackMark);
+ return ContinueWhenAllImpl(tasks, continuationFunction, null, m_defaultContinuationOptions, cancellationToken, DefaultScheduler);
}
/// <summary>
@@ -1496,14 +1467,12 @@ namespace System.Threading.Tasks
/// which constrain for which <see cref="System.Threading.Tasks.TaskStatus">TaskStatus</see> states a continuation
/// will be executed, are illegal with ContinueWhenAll.
/// </remarks>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWhenAll(Task[] tasks, Func<Task[], TResult> continuationFunction, TaskContinuationOptions continuationOptions)
{
if (continuationFunction == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.continuationFunction);
Contract.EndContractBlock();
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWhenAllImpl(tasks, continuationFunction, null, continuationOptions, m_defaultCancellationToken, DefaultScheduler, ref stackMark);
+ return ContinueWhenAllImpl(tasks, continuationFunction, null, continuationOptions, m_defaultCancellationToken, DefaultScheduler);
}
/// <summary>
@@ -1543,15 +1512,13 @@ namespace System.Threading.Tasks
/// which constrain for which <see cref="System.Threading.Tasks.TaskStatus">TaskStatus</see> states a continuation
/// will be executed, are illegal with ContinueWhenAll.
/// </remarks>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWhenAll(Task[] tasks, Func<Task[], TResult> continuationFunction,
CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
{
if (continuationFunction == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.continuationFunction);
Contract.EndContractBlock();
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWhenAllImpl(tasks, continuationFunction, null, continuationOptions, cancellationToken, scheduler, ref stackMark);
+ return ContinueWhenAllImpl(tasks, continuationFunction, null, continuationOptions, cancellationToken, scheduler);
}
/// <summary>
@@ -1571,14 +1538,12 @@ namespace System.Threading.Tasks
/// <paramref name="tasks"/> array contains a null value.</exception>
/// <exception cref="T:System.ArgumentException">The exception that is thrown when the
/// <paramref name="tasks"/> array is empty.</exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWhenAll<TAntecedentResult>(Task<TAntecedentResult>[] tasks, Func<Task<TAntecedentResult>[], TResult> continuationFunction)
{
if (continuationFunction == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.continuationFunction);
Contract.EndContractBlock();
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWhenAllImpl<TAntecedentResult>(tasks, continuationFunction, null, m_defaultContinuationOptions, m_defaultCancellationToken, DefaultScheduler, ref stackMark);
+ return ContinueWhenAllImpl<TAntecedentResult>(tasks, continuationFunction, null, m_defaultContinuationOptions, m_defaultCancellationToken, DefaultScheduler);
}
/// <summary>
@@ -1603,15 +1568,13 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
/// has already been disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWhenAll<TAntecedentResult>(Task<TAntecedentResult>[] tasks, Func<Task<TAntecedentResult>[], TResult> continuationFunction,
CancellationToken cancellationToken)
{
if (continuationFunction == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.continuationFunction);
Contract.EndContractBlock();
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWhenAllImpl<TAntecedentResult>(tasks, continuationFunction, null, m_defaultContinuationOptions, cancellationToken, DefaultScheduler, ref stackMark);
+ return ContinueWhenAllImpl<TAntecedentResult>(tasks, continuationFunction, null, m_defaultContinuationOptions, cancellationToken, DefaultScheduler);
}
/// <summary>
@@ -1642,15 +1605,13 @@ namespace System.Threading.Tasks
/// which constrain for which <see cref="System.Threading.Tasks.TaskStatus">TaskStatus</see> states a continuation
/// will be executed, are illegal with ContinueWhenAll.
/// </remarks>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWhenAll<TAntecedentResult>(Task<TAntecedentResult>[] tasks, Func<Task<TAntecedentResult>[], TResult> continuationFunction,
TaskContinuationOptions continuationOptions)
{
if (continuationFunction == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.continuationFunction);
Contract.EndContractBlock();
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWhenAllImpl<TAntecedentResult>(tasks, continuationFunction, null, continuationOptions, m_defaultCancellationToken, DefaultScheduler, ref stackMark);
+ return ContinueWhenAllImpl<TAntecedentResult>(tasks, continuationFunction, null, continuationOptions, m_defaultCancellationToken, DefaultScheduler);
}
/// <summary>
@@ -1691,15 +1652,13 @@ namespace System.Threading.Tasks
/// which constrain for which <see cref="System.Threading.Tasks.TaskStatus">TaskStatus</see> states a continuation
/// will be executed, are illegal with ContinueWhenAll.
/// </remarks>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWhenAll<TAntecedentResult>(Task<TAntecedentResult>[] tasks, Func<Task<TAntecedentResult>[], TResult> continuationFunction,
CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
{
if (continuationFunction == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.continuationFunction);
Contract.EndContractBlock();
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWhenAllImpl<TAntecedentResult>(tasks, continuationFunction, null, continuationOptions, cancellationToken, scheduler, ref stackMark);
+ return ContinueWhenAllImpl<TAntecedentResult>(tasks, continuationFunction, null, continuationOptions, cancellationToken, scheduler);
}
@@ -1707,7 +1666,7 @@ namespace System.Threading.Tasks
// Note: if you make any changes to this method, please do the same to the non-generic version too.
internal static Task<TResult> ContinueWhenAllImpl<TAntecedentResult>(Task<TAntecedentResult>[] tasks,
Func<Task<TAntecedentResult>[], TResult> continuationFunction, Action<Task<TAntecedentResult>[]> continuationAction,
- TaskContinuationOptions continuationOptions, CancellationToken cancellationToken, TaskScheduler scheduler, ref StackCrawlMark stackMark)
+ TaskContinuationOptions continuationOptions, CancellationToken cancellationToken, TaskScheduler scheduler)
{
// check arguments
TaskFactory.CheckMultiTaskContinuationOptions(continuationOptions);
@@ -1737,7 +1696,7 @@ namespace System.Threading.Tasks
return starter.ContinueWith<TResult>(
// use a cached delegate
GenericDelegateCache<TAntecedentResult, TResult>.CWAllFuncDelegate,
- continuationFunction, scheduler, cancellationToken, continuationOptions, ref stackMark);
+ continuationFunction, scheduler, cancellationToken, continuationOptions);
}
else
{
@@ -1746,7 +1705,7 @@ namespace System.Threading.Tasks
return starter.ContinueWith<TResult>(
// use a cached delegate
GenericDelegateCache<TAntecedentResult, TResult>.CWAllActionDelegate,
- continuationAction, scheduler, cancellationToken, continuationOptions, ref stackMark);
+ continuationAction, scheduler, cancellationToken, continuationOptions);
}
}
@@ -1754,7 +1713,7 @@ namespace System.Threading.Tasks
// Note: if you make any changes to this method, please do the same to the generic version too.
internal static Task<TResult> ContinueWhenAllImpl(Task[] tasks,
Func<Task[], TResult> continuationFunction, Action<Task[]> continuationAction,
- TaskContinuationOptions continuationOptions, CancellationToken cancellationToken, TaskScheduler scheduler, ref StackCrawlMark stackMark)
+ TaskContinuationOptions continuationOptions, CancellationToken cancellationToken, TaskScheduler scheduler)
{
// check arguments
TaskFactory.CheckMultiTaskContinuationOptions(continuationOptions);
@@ -1790,7 +1749,7 @@ namespace System.Threading.Tasks
completedTasks.NotifyDebuggerOfWaitCompletionIfNecessary();
return ((Func<Task[], TResult>)state)(completedTasks.Result);
},
- continuationFunction, scheduler, cancellationToken, continuationOptions, ref stackMark);
+ continuationFunction, scheduler, cancellationToken, continuationOptions);
}
else
{
@@ -1804,7 +1763,7 @@ namespace System.Threading.Tasks
completedTasks.NotifyDebuggerOfWaitCompletionIfNecessary();
((Action<Task[]>)state)(completedTasks.Result); return default(TResult);
},
- continuationAction, scheduler, cancellationToken, continuationOptions, ref stackMark);
+ continuationAction, scheduler, cancellationToken, continuationOptions);
}
}
@@ -1828,14 +1787,12 @@ namespace System.Threading.Tasks
/// <paramref name="tasks"/> array contains a null value.</exception>
/// <exception cref="T:System.ArgumentException">The exception that is thrown when the
/// <paramref name="tasks"/> array is empty.</exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWhenAny(Task[] tasks, Func<Task, TResult> continuationFunction)
{
if (continuationFunction == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.continuationFunction);
Contract.EndContractBlock();
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWhenAnyImpl(tasks, continuationFunction, null, m_defaultContinuationOptions, m_defaultCancellationToken, DefaultScheduler, ref stackMark);
+ return ContinueWhenAnyImpl(tasks, continuationFunction, null, m_defaultContinuationOptions, m_defaultCancellationToken, DefaultScheduler);
}
/// <summary>
@@ -1859,14 +1816,12 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
/// has already been disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWhenAny(Task[] tasks, Func<Task, TResult> continuationFunction, CancellationToken cancellationToken)
{
if (continuationFunction == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.continuationFunction);
Contract.EndContractBlock();
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWhenAnyImpl(tasks, continuationFunction, null, m_defaultContinuationOptions, cancellationToken, DefaultScheduler, ref stackMark);
+ return ContinueWhenAnyImpl(tasks, continuationFunction, null, m_defaultContinuationOptions, cancellationToken, DefaultScheduler);
}
/// <summary>
@@ -1896,14 +1851,12 @@ namespace System.Threading.Tasks
/// which constrain for which <see cref="System.Threading.Tasks.TaskStatus">TaskStatus</see> states a continuation
/// will be executed, are illegal with ContinueWhenAny.
/// </remarks>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWhenAny(Task[] tasks, Func<Task, TResult> continuationFunction, TaskContinuationOptions continuationOptions)
{
if (continuationFunction == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.continuationFunction);
Contract.EndContractBlock();
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWhenAnyImpl(tasks, continuationFunction, null, continuationOptions, m_defaultCancellationToken, DefaultScheduler, ref stackMark);
+ return ContinueWhenAnyImpl(tasks, continuationFunction, null, continuationOptions, m_defaultCancellationToken, DefaultScheduler);
}
/// <summary>
@@ -1943,15 +1896,13 @@ namespace System.Threading.Tasks
/// which constrain for which <see cref="System.Threading.Tasks.TaskStatus">TaskStatus</see> states a continuation
/// will be executed, are illegal with ContinueWhenAny.
/// </remarks>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWhenAny(Task[] tasks, Func<Task, TResult> continuationFunction,
CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
{
if (continuationFunction == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.continuationFunction);
Contract.EndContractBlock();
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWhenAnyImpl(tasks, continuationFunction, null, continuationOptions, cancellationToken, scheduler, ref stackMark);
+ return ContinueWhenAnyImpl(tasks, continuationFunction, null, continuationOptions, cancellationToken, scheduler);
}
/// <summary>
@@ -1971,14 +1922,12 @@ namespace System.Threading.Tasks
/// <paramref name="tasks"/> array contains a null value.</exception>
/// <exception cref="T:System.ArgumentException">The exception that is thrown when the
/// <paramref name="tasks"/> array is empty.</exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWhenAny<TAntecedentResult>(Task<TAntecedentResult>[] tasks, Func<Task<TAntecedentResult>, TResult> continuationFunction)
{
if (continuationFunction == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.continuationFunction);
Contract.EndContractBlock();
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWhenAnyImpl<TAntecedentResult>(tasks, continuationFunction, null, m_defaultContinuationOptions, m_defaultCancellationToken, DefaultScheduler, ref stackMark);
+ return ContinueWhenAnyImpl<TAntecedentResult>(tasks, continuationFunction, null, m_defaultContinuationOptions, m_defaultCancellationToken, DefaultScheduler);
}
/// <summary>
@@ -2003,15 +1952,13 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
/// has already been disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWhenAny<TAntecedentResult>(Task<TAntecedentResult>[] tasks, Func<Task<TAntecedentResult>, TResult> continuationFunction,
CancellationToken cancellationToken)
{
if (continuationFunction == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.continuationFunction);
Contract.EndContractBlock();
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWhenAnyImpl<TAntecedentResult>(tasks, continuationFunction, null, m_defaultContinuationOptions, cancellationToken, DefaultScheduler, ref stackMark);
+ return ContinueWhenAnyImpl<TAntecedentResult>(tasks, continuationFunction, null, m_defaultContinuationOptions, cancellationToken, DefaultScheduler);
}
/// <summary>
@@ -2042,15 +1989,13 @@ namespace System.Threading.Tasks
/// which constrain for which <see cref="System.Threading.Tasks.TaskStatus">TaskStatus</see> states a continuation
/// will be executed, are illegal with ContinueWhenAny.
/// </remarks>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWhenAny<TAntecedentResult>(Task<TAntecedentResult>[] tasks, Func<Task<TAntecedentResult>, TResult> continuationFunction,
TaskContinuationOptions continuationOptions)
{
if (continuationFunction == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.continuationFunction);
Contract.EndContractBlock();
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWhenAnyImpl<TAntecedentResult>(tasks, continuationFunction, null, continuationOptions, m_defaultCancellationToken, DefaultScheduler, ref stackMark);
+ return ContinueWhenAnyImpl<TAntecedentResult>(tasks, continuationFunction, null, continuationOptions, m_defaultCancellationToken, DefaultScheduler);
}
/// <summary>
@@ -2091,22 +2036,20 @@ namespace System.Threading.Tasks
/// which constrain for which <see cref="System.Threading.Tasks.TaskStatus">TaskStatus</see> states a continuation
/// will be executed, are illegal with ContinueWhenAny.
/// </remarks>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWhenAny<TAntecedentResult>(Task<TAntecedentResult>[] tasks, Func<Task<TAntecedentResult>, TResult> continuationFunction,
CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
{
if (continuationFunction == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.continuationFunction);
Contract.EndContractBlock();
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWhenAnyImpl<TAntecedentResult>(tasks, continuationFunction, null, continuationOptions, cancellationToken, scheduler, ref stackMark);
+ return ContinueWhenAnyImpl<TAntecedentResult>(tasks, continuationFunction, null, continuationOptions, cancellationToken, scheduler);
}
// Core implementation of ContinueWhenAny, non-generic version
// Note: if you make any changes to this method, be sure to do the same to the generic version
internal static Task<TResult> ContinueWhenAnyImpl(Task[] tasks,
Func<Task, TResult> continuationFunction, Action<Task> continuationAction,
- TaskContinuationOptions continuationOptions, CancellationToken cancellationToken, TaskScheduler scheduler, ref StackCrawlMark stackMark)
+ TaskContinuationOptions continuationOptions, CancellationToken cancellationToken, TaskScheduler scheduler)
{
// check arguments
TaskFactory.CheckMultiTaskContinuationOptions(continuationOptions);
@@ -2136,7 +2079,7 @@ namespace System.Threading.Tasks
//the following delegate avoids closure capture as much as possible
//completedTask.Result is the winning task; state == continuationAction
(completedTask, state) => { return ((Func<Task, TResult>)state)(completedTask.Result); },
- continuationFunction, scheduler, cancellationToken, continuationOptions, ref stackMark);
+ continuationFunction, scheduler, cancellationToken, continuationOptions);
}
else
{
@@ -2145,7 +2088,7 @@ namespace System.Threading.Tasks
//the following delegate avoids closure capture as much as possible
//completedTask.Result is the winning task; state == continuationAction
(completedTask, state) => { ((Action<Task>)state)(completedTask.Result); return default(TResult); },
- continuationAction, scheduler, cancellationToken, continuationOptions, ref stackMark);
+ continuationAction, scheduler, cancellationToken, continuationOptions);
}
}
@@ -2154,7 +2097,7 @@ namespace System.Threading.Tasks
// Note: if you make any changes to this method, be sure to do the same to the non-generic version
internal static Task<TResult> ContinueWhenAnyImpl<TAntecedentResult>(Task<TAntecedentResult>[] tasks,
Func<Task<TAntecedentResult>, TResult> continuationFunction, Action<Task<TAntecedentResult>> continuationAction,
- TaskContinuationOptions continuationOptions, CancellationToken cancellationToken, TaskScheduler scheduler, ref StackCrawlMark stackMark)
+ TaskContinuationOptions continuationOptions, CancellationToken cancellationToken, TaskScheduler scheduler)
{
// check arguments
TaskFactory.CheckMultiTaskContinuationOptions(continuationOptions);
@@ -2182,7 +2125,7 @@ namespace System.Threading.Tasks
return starter.ContinueWith<TResult>(
// Use a cached delegate
GenericDelegateCache<TAntecedentResult, TResult>.CWAnyFuncDelegate,
- continuationFunction, scheduler, cancellationToken, continuationOptions, ref stackMark);
+ continuationFunction, scheduler, cancellationToken, continuationOptions);
}
else
{
@@ -2190,7 +2133,7 @@ namespace System.Threading.Tasks
return starter.ContinueWith<TResult>(
// Use a cached delegate
GenericDelegateCache<TAntecedentResult,TResult>.CWAnyActionDelegate,
- continuationAction, scheduler, cancellationToken, continuationOptions, ref stackMark);
+ continuationAction, scheduler, cancellationToken, continuationOptions);
}
}
}
diff --git a/src/mscorlib/src/System/Threading/Tasks/IAsyncCausalityTracerStatics.cs b/src/mscorlib/src/System/Threading/Tasks/IAsyncCausalityTracerStatics.cs
index b8155d0..32efd77 100644
--- a/src/mscorlib/src/System/Threading/Tasks/IAsyncCausalityTracerStatics.cs
+++ b/src/mscorlib/src/System/Threading/Tasks/IAsyncCausalityTracerStatics.cs
@@ -19,16 +19,16 @@ namespace Windows.Foundation.Diagnostics
[Guid("50850B26-267E-451B-A890-AB6A370245EE")]
[WindowsRuntimeImport]
internal interface IAsyncCausalityTracerStatics
- {
- void TraceOperationCreation(CausalityTraceLevel traceLevel, CausalitySource source, Guid platformId, ulong operationId, string operationName, ulong relatedContext);
- void TraceOperationCompletion(CausalityTraceLevel traceLevel, CausalitySource source, Guid platformId, ulong operationId, AsyncCausalityStatus status);
- void TraceOperationRelation(CausalityTraceLevel traceLevel, CausalitySource source, Guid platformId, ulong operationId, CausalityRelation relation);
- void TraceSynchronousWorkStart(CausalityTraceLevel traceLevel, CausalitySource source, Guid platformId, ulong operationId, CausalitySynchronousWork work);
- void TraceSynchronousWorkCompletion(CausalityTraceLevel traceLevel, CausalitySource source, CausalitySynchronousWork work);
+ {
+ void TraceOperationCreation(CausalityTraceLevel traceLevel, CausalitySource source, Guid platformId, ulong operationId, string operationName, ulong relatedContext);
+ void TraceOperationCompletion(CausalityTraceLevel traceLevel, CausalitySource source, Guid platformId, ulong operationId, AsyncCausalityStatus status);
+ void TraceOperationRelation(CausalityTraceLevel traceLevel, CausalitySource source, Guid platformId, ulong operationId, CausalityRelation relation);
+ void TraceSynchronousWorkStart(CausalityTraceLevel traceLevel, CausalitySource source, Guid platformId, ulong operationId, CausalitySynchronousWork work);
+ void TraceSynchronousWorkCompletion(CausalityTraceLevel traceLevel, CausalitySource source, CausalitySynchronousWork work);
//These next 2 functions could've been represented as an event except that the EventRegistrationToken wasn't being propagated to WinRT
EventRegistrationToken add_TracingStatusChanged(System.EventHandler<TracingStatusChangedEventArgs> eventHandler);
void remove_TracingStatusChanged(EventRegistrationToken token);
- }
+ }
[ComImport]
[Guid("410B7711-FF3B-477F-9C9A-D2EFDA302DC3")]
diff --git a/src/mscorlib/src/System/Threading/Tasks/Parallel.cs b/src/mscorlib/src/System/Threading/Tasks/Parallel.cs
deleted file mode 100644
index 7808943..0000000
--- a/src/mscorlib/src/System/Threading/Tasks/Parallel.cs
+++ /dev/null
@@ -1,3593 +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.
-
-// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
-//
-//
-//
-// A helper class that contains parallel versions of various looping constructs. This
-// internally uses the task parallel library, but takes care to expose very little
-// evidence of this infrastructure being used.
-//
-// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-
-using System;
-using System.Diagnostics;
-using System.Collections;
-using System.Collections.Generic;
-using System.Collections.Concurrent;
-using System.Security.Permissions;
-using System.Threading;
-using System.Threading.Tasks;
-using System.Diagnostics.Contracts;
-
-
-namespace System.Threading.Tasks
-{
- /// <summary>
- /// Stores options that configure the operation of methods on the
- /// <see cref="T:System.Threading.Tasks.Parallel">Parallel</see> class.
- /// </summary>
- /// <remarks>
- /// By default, methods on the Parallel class attempt to utilize all available processors, are non-cancelable, and target
- /// the default TaskScheduler (TaskScheduler.Default). <see cref="ParallelOptions"/> enables
- /// overriding these defaults.
- /// </remarks>
- public class ParallelOptions
- {
- private TaskScheduler m_scheduler;
- private int m_maxDegreeOfParallelism;
- private CancellationToken m_cancellationToken;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="ParallelOptions"/> class.
- /// </summary>
- /// <remarks>
- /// This constructor initializes the instance with default values. <see cref="MaxDegreeOfParallelism"/>
- /// is initialized to -1, signifying that there is no upper bound set on how much parallelism should
- /// be employed. <see cref="CancellationToken"/> is initialized to a non-cancelable token,
- /// and <see cref="TaskScheduler"/> is initialized to the default scheduler (TaskScheduler.Default).
- /// All of these defaults may be overwritten using the property set accessors on the instance.
- /// </remarks>
- public ParallelOptions()
- {
- m_scheduler = TaskScheduler.Default;
- m_maxDegreeOfParallelism = -1;
- m_cancellationToken = CancellationToken.None;
- }
-
- /// <summary>
- /// Gets or sets the <see cref="T:System.Threading.Tasks.TaskScheduler">TaskScheduler</see>
- /// associated with this <see cref="ParallelOptions"/> instance. Setting this property to null
- /// indicates that the current scheduler should be used.
- /// </summary>
- public TaskScheduler TaskScheduler
- {
- get { return m_scheduler; }
- set { m_scheduler = value; }
- }
-
- // Convenience property used by TPL logic
- internal TaskScheduler EffectiveTaskScheduler
- {
- get
- {
- if (m_scheduler == null) return TaskScheduler.Current;
- else return m_scheduler;
- }
- }
-
- /// <summary>
- /// Gets or sets the maximum degree of parallelism enabled by this ParallelOptions instance.
- /// </summary>
- /// <remarks>
- /// The <see cref="MaxDegreeOfParallelism"/> limits the number of concurrent operations run by <see
- /// cref="T:System.Threading.Tasks.Parallel">Parallel</see> method calls that are passed this
- /// ParallelOptions instance to the set value, if it is positive. If <see
- /// cref="MaxDegreeOfParallelism"/> is -1, then there is no limit placed on the number of concurrently
- /// running operations.
- /// </remarks>
- /// <exception cref="T:System.ArgumentOutOfRangeException">
- /// The exception that is thrown when this <see cref="MaxDegreeOfParallelism"/> is set to 0 or some
- /// value less than -1.
- /// </exception>
- public int MaxDegreeOfParallelism
- {
- get { return m_maxDegreeOfParallelism; }
- set
- {
- if ((value == 0) || (value < -1))
- throw new ArgumentOutOfRangeException(nameof(MaxDegreeOfParallelism));
- m_maxDegreeOfParallelism = value;
- }
- }
-
- /// <summary>
- /// Gets or sets the <see cref="T:System.Threading.CancellationToken">CancellationToken</see>
- /// associated with this <see cref="ParallelOptions"/> instance.
- /// </summary>
- /// <remarks>
- /// Providing a <see cref="T:System.Threading.CancellationToken">CancellationToken</see>
- /// to a <see cref="T:System.Threading.Tasks.Parallel">Parallel</see> method enables the operation to be
- /// exited early. Code external to the operation may cancel the token, and if the operation observes the
- /// token being set, it may exit early by throwing an
- /// <see cref="T:System.OperationCanceledException"/>.
- /// </remarks>
- public CancellationToken CancellationToken
- {
- get { return m_cancellationToken; }
- set { m_cancellationToken = value; }
- }
-
- internal int EffectiveMaxConcurrencyLevel
- {
- get
- {
- int rval = MaxDegreeOfParallelism;
- int schedulerMax = EffectiveTaskScheduler.MaximumConcurrencyLevel;
- if ((schedulerMax > 0) && (schedulerMax != Int32.MaxValue))
- {
- rval = (rval == -1) ? schedulerMax : Math.Min(schedulerMax, rval);
- }
- return rval;
- }
- }
- }
-
- /// <summary>
- /// Provides support for parallel loops and regions.
- /// </summary>
- /// <remarks>
- /// The <see cref="T:System.Threading.Tasks.Parallel"/> class provides library-based data parallel replacements
- /// for common operations such as for loops, for each loops, and execution of a set of statements.
- /// </remarks>
- public static class Parallel
- {
- // static counter for generating unique Fork/Join Context IDs to be used in ETW events
- internal static int s_forkJoinContextID;
-
- // We use a stride for loops to amortize the frequency of interlocked operations.
- internal const int DEFAULT_LOOP_STRIDE = 16;
-
- // Static variable to hold default parallel options
- internal static ParallelOptions s_defaultParallelOptions = new ParallelOptions();
-
- /// <summary>
- /// Executes each of the provided actions, possibly in parallel.
- /// </summary>
- /// <param name="actions">An array of <see cref="T:System.Action">Actions</see> to execute.</param>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the
- /// <paramref name="actions"/> argument is null.</exception>
- /// <exception cref="T:System.ArgumentException">The exception that is thrown when the
- /// <paramref name="actions"/> array contains a null element.</exception>
- /// <exception cref="T:System.AggregateException">The exception that is thrown when any
- /// action in the <paramref name="actions"/> array throws an exception.</exception>
- /// <remarks>
- /// This method can be used to execute a set of operations, potentially in parallel.
- /// No guarantees are made about the order in which the operations execute or whether
- /// they execute in parallel. This method does not return until each of the
- /// provided operations has completed, regardless of whether completion
- /// occurs due to normal or exceptional termination.
- /// </remarks>
- public static void Invoke(params Action[] actions)
- {
- Invoke(s_defaultParallelOptions, actions);
- }
-
- /// <summary>
- /// Executes each of the provided actions, possibly in parallel.
- /// </summary>
- /// <param name="parallelOptions">A <see cref="T:System.Threading.Tasks.ParallelOptions">ParallelOptions</see>
- /// instance that configures the behavior of this operation.</param>
- /// <param name="actions">An array of <see cref="T:System.Action">Actions</see> to execute.</param>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the
- /// <paramref name="actions"/> argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the
- /// <paramref name="parallelOptions"/> argument is null.</exception>
- /// <exception cref="T:System.ArgumentException">The exception that is thrown when the
- /// <paramref name="actions"/> array contains a null element.</exception>
- /// <exception cref="T:System.OperationCanceledException">The exception that is thrown when
- /// the <see cref="T:System.Threading.CancellationToken">CancellationToken</see> in the
- /// <paramref name="parallelOptions"/> is set.</exception>
- /// <exception cref="T:System.AggregateException">The exception that is thrown when any
- /// action in the <paramref name="actions"/> array throws an exception.</exception>
- /// <exception cref="T:System.ObjectDisposedException">The exception that is thrown when the
- /// the <see cref="T:System.Threading.CancellationTokenSource">CancellationTokenSource</see> associated with the
- /// the <see cref="T:System.Threading.CancellationToken">CancellationToken</see> in the
- /// <paramref name="parallelOptions"/> has been disposed.</exception>
- /// <remarks>
- /// This method can be used to execute a set of operations, potentially in parallel.
- /// No guarantees are made about the order in which the operations execute or whether
- /// the they execute in parallel. This method does not return until each of the
- /// provided operations has completed, regardless of whether completion
- /// occurs due to normal or exceptional termination.
- /// </remarks>
- public static void Invoke(ParallelOptions parallelOptions, params Action[] actions)
- {
- if (actions == null)
- {
- throw new ArgumentNullException(nameof(actions));
- }
- if (parallelOptions == null)
- {
- throw new ArgumentNullException(nameof(parallelOptions));
- }
-
- // Throw an ODE if we're passed a disposed CancellationToken.
- if (parallelOptions.CancellationToken.CanBeCanceled
- && AppContextSwitches.ThrowExceptionIfDisposedCancellationTokenSource)
- {
- parallelOptions.CancellationToken.ThrowIfSourceDisposed();
- }
- // Quit early if we're already canceled -- avoid a bunch of work.
- if (parallelOptions.CancellationToken.IsCancellationRequested)
- throw new OperationCanceledException(parallelOptions.CancellationToken);
-
- // We must validate that the actions array contains no null elements, and also
- // make a defensive copy of the actions array.
- Action[] actionsCopy = new Action[actions.Length];
- for (int i = 0; i < actionsCopy.Length; i++)
- {
- actionsCopy[i] = actions[i];
- if (actionsCopy[i] == null)
- {
- throw new ArgumentException(Environment.GetResourceString("Parallel_Invoke_ActionNull"));
- }
- }
-
- // ETW event for Parallel Invoke Begin
- int forkJoinContextID = 0;
- Task callerTask = null;
- if (TplEtwProvider.Log.IsEnabled())
- {
- forkJoinContextID = Interlocked.Increment(ref s_forkJoinContextID);
- callerTask = Task.InternalCurrent;
- TplEtwProvider.Log.ParallelInvokeBegin((callerTask != null ? callerTask.m_taskScheduler.Id : TaskScheduler.Current.Id), (callerTask != null ? callerTask.Id : 0),
- forkJoinContextID, TplEtwProvider.ForkJoinOperationType.ParallelInvoke,
- actionsCopy.Length);
- }
-
-#if DEBUG
- actions = null; // Ensure we don't accidentally use this below.
-#endif
-
- // If we have no work to do, we are done.
- if (actionsCopy.Length < 1) return;
-
- // In the algorithm below, if the number of actions is greater than this, we automatically
- // use Parallel.For() to handle the actions, rather than the Task-per-Action strategy.
- const int SMALL_ACTIONCOUNT_LIMIT = 10;
-
- try
- {
- // If we've gotten this far, it's time to process the actions.
- if ((actionsCopy.Length > SMALL_ACTIONCOUNT_LIMIT) ||
- (parallelOptions.MaxDegreeOfParallelism != -1 && parallelOptions.MaxDegreeOfParallelism < actionsCopy.Length))
- {
- // Used to hold any exceptions encountered during action processing
- ConcurrentQueue<Exception> exceptionQ = null; // will be lazily initialized if necessary
-
- // This is more efficient for a large number of actions, or for enforcing MaxDegreeOfParallelism.
- try
- {
- // Launch a self-replicating task to handle the execution of all actions.
- // The use of a self-replicating task allows us to use as many cores
- // as are available, and no more. The exception to this rule is
- // that, in the case of a blocked action, the ThreadPool may inject
- // extra threads, which means extra tasks can run.
- int actionIndex = 0;
- ParallelForReplicatingTask rootTask = new ParallelForReplicatingTask(parallelOptions, delegate
- {
- // Each for-task will pull an action at a time from the list
- int myIndex = Interlocked.Increment(ref actionIndex); // = index to use + 1
- while (myIndex <= actionsCopy.Length)
- {
- // Catch and store any exceptions. If we don't catch them, the self-replicating
- // task will exit, and that may cause other SR-tasks to exit.
- // And (absent cancellation) we want all actions to execute.
- try
- {
- actionsCopy[myIndex - 1]();
- }
- catch (Exception e)
- {
- LazyInitializer.EnsureInitialized<ConcurrentQueue<Exception>>(ref exceptionQ, () => { return new ConcurrentQueue<Exception>(); });
- exceptionQ.Enqueue(e);
- }
-
- // Check for cancellation. If it is encountered, then exit the delegate.
- if (parallelOptions.CancellationToken.IsCancellationRequested)
- throw new OperationCanceledException(parallelOptions.CancellationToken);
-
- // You're still in the game. Grab your next action index.
- myIndex = Interlocked.Increment(ref actionIndex);
- }
- }, TaskCreationOptions.None, InternalTaskOptions.SelfReplicating);
-
- rootTask.RunSynchronously(parallelOptions.EffectiveTaskScheduler);
- rootTask.Wait();
- }
- catch (Exception e)
- {
- LazyInitializer.EnsureInitialized<ConcurrentQueue<Exception>>(ref exceptionQ, () => { return new ConcurrentQueue<Exception>(); });
-
- // Since we're consuming all action exceptions, there are very few reasons that
- // we would see an exception here. Two that come to mind:
- // (1) An OCE thrown by one or more actions (AggregateException thrown)
- // (2) An exception thrown from the ParallelForReplicatingTask constructor
- // (regular exception thrown).
- // We'll need to cover them both.
- AggregateException ae = e as AggregateException;
- if (ae != null)
- {
- // Strip off outer container of an AggregateException, because downstream
- // logic needs OCEs to be at the top level.
- foreach (Exception exc in ae.InnerExceptions) exceptionQ.Enqueue(exc);
- }
- else
- {
- exceptionQ.Enqueue(e);
- }
- }
-
- // If we have encountered any exceptions, then throw.
- if ((exceptionQ != null) && (exceptionQ.Count > 0))
- {
- ThrowIfReducableToSingleOCE(exceptionQ, parallelOptions.CancellationToken);
- throw new AggregateException(exceptionQ);
- }
- }
- else
- {
- // This is more efficient for a small number of actions and no DOP support
-
- // Initialize our array of tasks, one per action.
- Task[] tasks = new Task[actionsCopy.Length];
-
- // One more check before we begin...
- if (parallelOptions.CancellationToken.IsCancellationRequested)
- throw new OperationCanceledException(parallelOptions.CancellationToken);
-
- // Launch all actions as tasks
- for (int i = 1; i < tasks.Length; i++)
- {
- tasks[i] = Task.Factory.StartNew(actionsCopy[i], parallelOptions.CancellationToken, TaskCreationOptions.None,
- InternalTaskOptions.None, parallelOptions.EffectiveTaskScheduler);
- }
-
- // Optimization: Use current thread to run something before we block waiting for all tasks.
- tasks[0] = new Task(actionsCopy[0]);
- tasks[0].RunSynchronously(parallelOptions.EffectiveTaskScheduler);
-
- // Now wait for the tasks to complete. This will not unblock until all of
- // them complete, and it will throw an exception if one or more of them also
- // threw an exception. We let such exceptions go completely unhandled.
- try
- {
- if (tasks.Length <= 4)
- {
- // for 4 or less tasks, the sequential waitall version is faster
- Task.FastWaitAll(tasks);
- }
- else
- {
- // otherwise we revert to the regular WaitAll which delegates the multiple wait to the cooperative event.
- Task.WaitAll(tasks);
- }
- }
- catch (AggregateException aggExp)
- {
- // see if we can combine it into a single OCE. If not propagate the original exception
- ThrowIfReducableToSingleOCE(aggExp.InnerExceptions, parallelOptions.CancellationToken);
- throw;
- }
- finally
- {
- for (int i = 0; i < tasks.Length; i++)
- {
- if (tasks[i].IsCompleted) tasks[i].Dispose();
- }
- }
- }
- }
- finally
- {
- // ETW event for Parallel Invoke End
- if (TplEtwProvider.Log.IsEnabled())
- {
- TplEtwProvider.Log.ParallelInvokeEnd((callerTask != null ? callerTask.m_taskScheduler.Id : TaskScheduler.Current.Id), (callerTask != null ? callerTask.Id : 0),
- forkJoinContextID);
- }
- }
- }
-
- /// <summary>
- /// Executes a for loop in which iterations may run in parallel.
- /// </summary>
- /// <param name="fromInclusive">The start index, inclusive.</param>
- /// <param name="toExclusive">The end index, exclusive.</param>
- /// <param name="body">The delegate that is invoked once per iteration.</param>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="body"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.AggregateException">The exception that is thrown to contain an exception
- /// thrown from one of the specified delegates.</exception>
- /// <returns>A <see cref="T:System.Threading.Tasks.ParallelLoopResult">ParallelLoopResult</see> structure
- /// that contains information on what portion of the loop completed.</returns>
- /// <remarks>
- /// The <paramref name="body"/> delegate is invoked once for each value in the iteration range:
- /// [fromInclusive, toExclusive). It is provided with the iteration count (an Int32) as a parameter.
- /// </remarks>
- public static ParallelLoopResult For(int fromInclusive, int toExclusive, Action<int> body)
- {
- if (body == null)
- {
- throw new ArgumentNullException(nameof(body));
- }
-
- return ForWorker<object>(
- fromInclusive, toExclusive,
- s_defaultParallelOptions,
- body, null, null, null, null);
- }
-
- /// <summary>
- /// Executes a for loop in which iterations may run in parallel.
- /// </summary>
- /// <param name="fromInclusive">The start index, inclusive.</param>
- /// <param name="toExclusive">The end index, exclusive.</param>
- /// <param name="body">The delegate that is invoked once per iteration.</param>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="body"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.AggregateException">The exception that is thrown to contain an exception
- /// thrown from one of the specified delegates.</exception>
- /// <returns>A <see cref="T:System.Threading.Tasks.ParallelLoopResult">ParallelLoopResult</see> structure
- /// that contains information on what portion of the loop completed.</returns>
- /// <remarks>
- /// The <paramref name="body"/> delegate is invoked once for each value in the iteration range:
- /// [fromInclusive, toExclusive). It is provided with the iteration count (an Int64) as a parameter.
- /// </remarks>
- public static ParallelLoopResult For(long fromInclusive, long toExclusive, Action<long> body)
- {
- if (body == null)
- {
- throw new ArgumentNullException(nameof(body));
- }
-
- return ForWorker64<object>(
- fromInclusive, toExclusive, s_defaultParallelOptions,
- body, null, null, null, null);
- }
-
- /// <summary>
- /// Executes a for loop in which iterations may run in parallel.
- /// </summary>
- /// <param name="fromInclusive">The start index, inclusive.</param>
- /// <param name="toExclusive">The end index, exclusive.</param>
- /// <param name="parallelOptions">A <see cref="T:System.Threading.Tasks.ParallelOptions">ParallelOptions</see>
- /// instance that configures the behavior of this operation.</param>
- /// <param name="body">The delegate that is invoked once per iteration.</param>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="body"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the
- /// <paramref name="parallelOptions"/> argument is null.</exception>
- /// <exception cref="T:System.OperationCanceledException">The exception that is thrown when the
- /// <see cref="T:System.Threading.CancellationToken">CancellationToken</see> in the <paramref name="parallelOptions"/>
- /// argument is set.</exception>
- /// <exception cref="T:System.AggregateException">The exception that is thrown to contain an exception
- /// thrown from one of the specified delegates.</exception>
- /// <exception cref="T:System.ObjectDisposedException">The exception that is thrown when the
- /// the <see cref="T:System.Threading.CancellationTokenSource">CancellationTokenSource</see> associated with the
- /// the <see cref="T:System.Threading.CancellationToken">CancellationToken</see> in the
- /// <paramref name="parallelOptions"/> has been disposed.</exception>
- /// <returns>A <see cref="T:System.Threading.Tasks.ParallelLoopResult">ParallelLoopResult</see> structure
- /// that contains information on what portion of the loop completed.</returns>
- /// <remarks>
- /// The <paramref name="body"/> delegate is invoked once for each value in the iteration range:
- /// [fromInclusive, toExclusive). It is provided with the iteration count (an Int32) as a parameter.
- /// </remarks>
- public static ParallelLoopResult For(int fromInclusive, int toExclusive, ParallelOptions parallelOptions, Action<int> body)
- {
- if (body == null)
- {
- throw new ArgumentNullException(nameof(body));
- }
- if (parallelOptions == null)
- {
- throw new ArgumentNullException(nameof(parallelOptions));
- }
-
- return ForWorker<object>(
- fromInclusive, toExclusive, parallelOptions,
- body, null, null, null, null);
- }
-
- /// <summary>
- /// Executes a for loop in which iterations may run in parallel.
- /// </summary>
- /// <param name="fromInclusive">The start index, inclusive.</param>
- /// <param name="toExclusive">The end index, exclusive.</param>
- /// <param name="parallelOptions">A <see cref="T:System.Threading.Tasks.ParallelOptions">ParallelOptions</see>
- /// instance that configures the behavior of this operation.</param>
- /// <param name="body">The delegate that is invoked once per iteration.</param>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="body"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the
- /// <paramref name="parallelOptions"/> argument is null.</exception>
- /// <exception cref="T:System.OperationCanceledException">The exception that is thrown when the
- /// <see cref="T:System.Threading.CancellationToken">CancellationToken</see> in the <paramref name="parallelOptions"/>
- /// argument is set.</exception>
- /// <exception cref="T:System.AggregateException">The exception that is thrown to contain an exception
- /// thrown from one of the specified delegates.</exception>
- /// <exception cref="T:System.ObjectDisposedException">The exception that is thrown when the
- /// the <see cref="T:System.Threading.CancellationTokenSource">CancellationTokenSource</see> associated with the
- /// the <see cref="T:System.Threading.CancellationToken">CancellationToken</see> in the
- /// <paramref name="parallelOptions"/> has been disposed.</exception>
- /// <returns>A <see cref="T:System.Threading.Tasks.ParallelLoopResult">ParallelLoopResult</see> structure
- /// that contains information on what portion of the loop completed.</returns>
- /// <remarks>
- /// The <paramref name="body"/> delegate is invoked once for each value in the iteration range:
- /// [fromInclusive, toExclusive). It is provided with the iteration count (an Int64) as a parameter.
- /// </remarks>
- public static ParallelLoopResult For(long fromInclusive, long toExclusive, ParallelOptions parallelOptions, Action<long> body)
- {
- if (body == null)
- {
- throw new ArgumentNullException(nameof(body));
- }
- if (parallelOptions == null)
- {
- throw new ArgumentNullException(nameof(parallelOptions));
- }
-
- return ForWorker64<object>(
- fromInclusive, toExclusive, parallelOptions,
- body, null, null, null, null);
- }
-
- /// <summary>
- /// Executes a for loop in which iterations may run in parallel.
- /// </summary>
- /// <param name="fromInclusive">The start index, inclusive.</param>
- /// <param name="toExclusive">The end index, exclusive.</param>
- /// <param name="body">The delegate that is invoked once per iteration.</param>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="body"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.AggregateException">The exception that is thrown to contain an exception
- /// thrown from one of the specified delegates.</exception>
- /// <returns>A <see cref="T:System.Threading.Tasks.ParallelLoopResult">ParallelLoopResult</see> structure
- /// that contains information on what portion of the loop completed.</returns>
- /// <remarks>
- /// <para>
- /// The <paramref name="body"/> delegate is invoked once for each value in the iteration range:
- /// [fromInclusive, toExclusive). It is provided with the following parameters: the iteration count (an Int32),
- /// and a <see cref="System.Threading.Tasks.ParallelLoopState">ParallelLoopState</see> instance that may be
- /// used to break out of the loop prematurely.
- /// </para>
- /// <para>
- /// Calling <see cref="System.Threading.Tasks.ParallelLoopState.Break()">ParallelLoopState.Break()</see>
- /// informs the For operation that iterations after the current one need not
- /// execute. However, all iterations before the current one will still need to be executed if they have not already.
- /// Therefore, calling Break is similar to using a break operation within a
- /// conventional for loop in a language like C#, but it is not a perfect substitute: for example, there is no guarantee that iterations
- /// after the current one will definitely not execute.
- /// </para>
- /// <para>
- /// If executing all iterations before the current one is not necessary,
- /// <see cref="System.Threading.Tasks.ParallelLoopState.Stop()">ParallelLoopState.Stop()</see>
- /// should be preferred to using Break. Calling Stop informs the For loop that it may abandon all remaining
- /// iterations, regardless of whether they're for interations above or below the current,
- /// since all required work has already been completed. As with Break, however, there are no guarantees regarding
- /// which other iterations will not execute.
- /// </para>
- /// <para>
- /// When a loop is ended prematurely, the <see cref="T:ParallelLoopState"/> that's returned will contain
- /// relevant information about the loop's completion.
- /// </para>
- /// </remarks>
- public static ParallelLoopResult For(int fromInclusive, int toExclusive, Action<int, ParallelLoopState> body)
- {
- if (body == null)
- {
- throw new ArgumentNullException(nameof(body));
- }
-
- return ForWorker<object>(
- fromInclusive, toExclusive, s_defaultParallelOptions,
- null, body, null, null, null);
- }
-
- /// <summary>
- /// Executes a for loop in which iterations may run in parallel.
- /// </summary>
- /// <param name="fromInclusive">The start index, inclusive.</param>
- /// <param name="toExclusive">The end index, exclusive.</param>
- /// <param name="body">The delegate that is invoked once per iteration.</param>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="body"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.AggregateException">The exception that is thrown to contain an exception
- /// thrown from one of the specified delegates.</exception>
- /// <returns>A <see cref="T:System.Threading.Tasks.ParallelLoopResult">ParallelLoopResult</see> structure
- /// that contains information on what portion of the loop completed.</returns>
- /// <remarks>
- /// The <paramref name="body"/> delegate is invoked once for each value in the iteration range:
- /// [fromInclusive, toExclusive). It is provided with the following parameters: the iteration count (an Int64),
- /// and a <see cref="System.Threading.Tasks.ParallelLoopState">ParallelLoopState</see> instance that may be
- /// used to break out of the loop prematurely.
- /// </remarks>
- public static ParallelLoopResult For(long fromInclusive, long toExclusive, Action<long, ParallelLoopState> body)
- {
- if (body == null)
- {
- throw new ArgumentNullException(nameof(body));
- }
-
- return ForWorker64<object>(
- fromInclusive, toExclusive, s_defaultParallelOptions,
- null, body, null, null, null);
- }
-
- /// <summary>
- /// Executes a for loop in which iterations may run in parallel.
- /// </summary>
- /// <param name="fromInclusive">The start index, inclusive.</param>
- /// <param name="toExclusive">The end index, exclusive.</param>
- /// <param name="parallelOptions">A <see cref="T:System.Threading.Tasks.ParallelOptions">ParallelOptions</see>
- /// instance that configures the behavior of this operation.</param>
- /// <param name="body">The delegate that is invoked once per iteration.</param>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="body"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the
- /// <paramref name="parallelOptions"/> argument is null.</exception>
- /// <exception cref="T:System.OperationCanceledException">The exception that is thrown when the
- /// <see cref="T:System.Threading.CancellationToken">CancellationToken</see> in the <paramref name="parallelOptions"/>
- /// argument is set.</exception>
- /// <exception cref="T:System.AggregateException">The exception that is thrown to contain an exception
- /// thrown from one of the specified delegates.</exception>
- /// <exception cref="T:System.ObjectDisposedException">The exception that is thrown when the
- /// the <see cref="T:System.Threading.CancellationTokenSource">CancellationTokenSource</see> associated with the
- /// the <see cref="T:System.Threading.CancellationToken">CancellationToken</see> in the
- /// <paramref name="parallelOptions"/> has been disposed.</exception>
- /// <returns>A <see cref="T:System.Threading.Tasks.ParallelLoopResult">ParallelLoopResult</see> structure
- /// that contains information on what portion of the loop completed.</returns>
- /// <remarks>
- /// The <paramref name="body"/> delegate is invoked once for each value in the iteration range:
- /// [fromInclusive, toExclusive). It is provided with the following parameters: the iteration count (an Int32),
- /// and a <see cref="System.Threading.Tasks.ParallelLoopState">ParallelLoopState</see> instance that may be
- /// used to break out of the loop prematurely.
- /// </remarks>
- public static ParallelLoopResult For(int fromInclusive, int toExclusive, ParallelOptions parallelOptions, Action<int, ParallelLoopState> body)
- {
- if (body == null)
- {
- throw new ArgumentNullException(nameof(body));
- }
- if (parallelOptions == null)
- {
- throw new ArgumentNullException(nameof(parallelOptions));
- }
-
- return ForWorker<object>(
- fromInclusive, toExclusive, parallelOptions,
- null, body, null, null, null);
- }
-
- /// <summary>
- /// Executes a for loop in which iterations may run in parallel.
- /// </summary>
- /// <param name="fromInclusive">The start index, inclusive.</param>
- /// <param name="toExclusive">The end index, exclusive.</param>
- /// <param name="parallelOptions">A <see cref="T:System.Threading.Tasks.ParallelOptions">ParallelOptions</see>
- /// instance that configures the behavior of this operation.</param>
- /// <param name="body">The delegate that is invoked once per iteration.</param>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="body"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the
- /// <paramref name="parallelOptions"/> argument is null.</exception>
- /// <exception cref="T:System.OperationCanceledException">The exception that is thrown when the
- /// <see cref="T:System.Threading.CancellationToken">CancellationToken</see> in the <paramref name="parallelOptions"/>
- /// argument is set.</exception>
- /// <exception cref="T:System.AggregateException">The exception that is thrown to contain an exception
- /// thrown from one of the specified delegates.</exception>
- /// <exception cref="T:System.ObjectDisposedException">The exception that is thrown when the
- /// the <see cref="T:System.Threading.CancellationTokenSource">CancellationTokenSource</see> associated with the
- /// the <see cref="T:System.Threading.CancellationToken">CancellationToken</see> in the
- /// <paramref name="parallelOptions"/> has been disposed.</exception>
- /// <returns>A <see cref="T:System.Threading.Tasks.ParallelLoopResult">ParallelLoopResult</see> structure
- /// that contains information on what portion of the loop completed.</returns>
- /// <remarks>
- /// The <paramref name="body"/> delegate is invoked once for each value in the iteration range:
- /// [fromInclusive, toExclusive). It is provided with the following parameters: the iteration count (an Int64),
- /// and a <see cref="System.Threading.Tasks.ParallelLoopState">ParallelLoopState</see> instance that may be
- /// used to break out of the loop prematurely.
- /// </remarks>
- public static ParallelLoopResult For(long fromInclusive, long toExclusive, ParallelOptions parallelOptions,
- Action<long, ParallelLoopState> body)
- {
- if (body == null)
- {
- throw new ArgumentNullException(nameof(body));
- }
- if (parallelOptions == null)
- {
- throw new ArgumentNullException(nameof(parallelOptions));
- }
-
- return ForWorker64<object>(
- fromInclusive, toExclusive, parallelOptions,
- null, body, null, null, null);
- }
-
- /// <summary>
- /// Executes a for loop in which iterations may run in parallel.
- /// </summary>
- /// <typeparam name="TLocal">The type of the thread-local data.</typeparam>
- /// <param name="fromInclusive">The start index, inclusive.</param>
- /// <param name="toExclusive">The end index, exclusive.</param>
- /// <param name="localInit">The function delegate that returns the initial state of the local data
- /// for each thread.</param>
- /// <param name="body">The delegate that is invoked once per iteration.</param>
- /// <param name="localFinally">The delegate that performs a final action on the local state of each
- /// thread.</param>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="body"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the
- /// <paramref name="localInit"/> argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the
- /// <paramref name="localFinally"/> argument is null.</exception>
- /// <exception cref="T:System.AggregateException">The exception that is thrown to contain an exception
- /// thrown from one of the specified delegates.</exception>
- /// <returns>A <see cref="T:System.Threading.Tasks.ParallelLoopResult">ParallelLoopResult</see> structure
- /// that contains information on what portion of the loop completed.</returns>
- /// <remarks>
- /// <para>
- /// The <paramref name="body"/> delegate is invoked once for each value in the iteration range:
- /// [fromInclusive, toExclusive). It is provided with the following parameters: the iteration count (an Int32),
- /// a <see cref="System.Threading.Tasks.ParallelLoopState">ParallelLoopState</see> instance that may be
- /// used to break out of the loop prematurely, and some local state that may be shared amongst iterations
- /// that execute on the same thread.
- /// </para>
- /// <para>
- /// The <paramref name="localInit"/> delegate is invoked once for each thread that participates in the loop's
- /// execution and returns the initial local state for each of those threads. These initial states are passed to the first
- /// <paramref name="body"/> invocations on each thread. Then, every subsequent body invocation returns a possibly
- /// modified state value that is passed to the next body invocation. Finally, the last body invocation on each thread returns a state value
- /// that is passed to the <paramref name="localFinally"/> delegate. The localFinally delegate is invoked once per thread to perform a final
- /// action on each thread's local state.
- /// </para>
- /// </remarks>
- public static ParallelLoopResult For<TLocal>(
- int fromInclusive, int toExclusive,
- Func<TLocal> localInit,
- Func<int, ParallelLoopState, TLocal, TLocal> body,
- Action<TLocal> localFinally)
- {
- if (body == null)
- {
- throw new ArgumentNullException(nameof(body));
- }
- if (localInit == null)
- {
- throw new ArgumentNullException(nameof(localInit));
- }
- if (localFinally == null)
- {
- throw new ArgumentNullException(nameof(localFinally));
- }
-
- return ForWorker(
- fromInclusive, toExclusive, s_defaultParallelOptions,
- null, null, body, localInit, localFinally);
- }
-
- /// <summary>
- /// Executes a for loop in which iterations may run in parallel. Supports 64-bit indices.
- /// </summary>
- /// <typeparam name="TLocal">The type of the thread-local data.</typeparam>
- /// <param name="fromInclusive">The start index, inclusive.</param>
- /// <param name="toExclusive">The end index, exclusive.</param>
- /// <param name="localInit">The function delegate that returns the initial state of the local data
- /// for each thread.</param>
- /// <param name="body">The delegate that is invoked once per iteration.</param>
- /// <param name="localFinally">The delegate that performs a final action on the local state of each
- /// thread.</param>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="body"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the
- /// <paramref name="localInit"/> argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the
- /// <paramref name="localFinally"/> argument is null.</exception>
- /// <exception cref="T:System.AggregateException">The exception that is thrown to contain an exception
- /// thrown from one of the specified delegates.</exception>
- /// <returns>A <see cref="T:System.Threading.Tasks.ParallelLoopResult">ParallelLoopResult</see> structure
- /// that contains information on what portion of the loop completed.</returns>
- /// <remarks>
- /// <para>
- /// The <paramref name="body"/> delegate is invoked once for each value in the iteration range:
- /// [fromInclusive, toExclusive). It is provided with the following parameters: the iteration count (an Int64),
- /// a <see cref="System.Threading.Tasks.ParallelLoopState">ParallelLoopState</see> instance that may be
- /// used to break out of the loop prematurely, and some local state that may be shared amongst iterations
- /// that execute on the same thread.
- /// </para>
- /// <para>
- /// The <paramref name="localInit"/> delegate is invoked once for each thread that participates in the loop's
- /// execution and returns the initial local state for each of those threads. These initial states are passed to the first
- /// <paramref name="body"/> invocations on each thread. Then, every subsequent body invocation returns a possibly
- /// modified state value that is passed to the next body invocation. Finally, the last body invocation on each thread returns a state value
- /// that is passed to the <paramref name="localFinally"/> delegate. The localFinally delegate is invoked once per thread to perform a final
- /// action on each thread's local state.
- /// </para>
- /// </remarks>
- public static ParallelLoopResult For<TLocal>(
- long fromInclusive, long toExclusive,
- Func<TLocal> localInit,
- Func<long, ParallelLoopState, TLocal, TLocal> body,
- Action<TLocal> localFinally)
- {
- if (body == null)
- {
- throw new ArgumentNullException(nameof(body));
- }
- if (localInit == null)
- {
- throw new ArgumentNullException(nameof(localInit));
- }
- if (localFinally == null)
- {
- throw new ArgumentNullException(nameof(localFinally));
- }
-
- return ForWorker64(
- fromInclusive, toExclusive, s_defaultParallelOptions,
- null, null, body, localInit, localFinally);
- }
-
- /// <summary>
- /// Executes a for loop in which iterations may run in parallel.
- /// </summary>
- /// <typeparam name="TLocal">The type of the thread-local data.</typeparam>
- /// <param name="fromInclusive">The start index, inclusive.</param>
- /// <param name="toExclusive">The end index, exclusive.</param>
- /// <param name="parallelOptions">A <see cref="T:System.Threading.Tasks.ParallelOptions">ParallelOptions</see>
- /// instance that configures the behavior of this operation.</param>
- /// <param name="localInit">The function delegate that returns the initial state of the local data
- /// for each thread.</param>
- /// <param name="body">The delegate that is invoked once per iteration.</param>
- /// <param name="localFinally">The delegate that performs a final action on the local state of each
- /// thread.</param>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="body"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the
- /// <paramref name="localInit"/> argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the
- /// <paramref name="localFinally"/> argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the
- /// <paramref name="parallelOptions"/> argument is null.</exception>
- /// <exception cref="T:System.OperationCanceledException">The exception that is thrown when the
- /// <see cref="T:System.Threading.CancellationToken">CancellationToken</see> in the <paramref name="parallelOptions"/>
- /// argument is set.</exception>
- /// <exception cref="T:System.AggregateException">The exception that is thrown to contain an exception
- /// thrown from one of the specified delegates.</exception>
- /// <exception cref="T:System.ObjectDisposedException">The exception that is thrown when the
- /// the <see cref="T:System.Threading.CancellationTokenSource">CancellationTokenSource</see> associated with the
- /// the <see cref="T:System.Threading.CancellationToken">CancellationToken</see> in the
- /// <paramref name="parallelOptions"/> has been disposed.</exception>
- /// <returns>A <see cref="T:System.Threading.Tasks.ParallelLoopResult">ParallelLoopResult</see> structure
- /// that contains information on what portion of the loop completed.</returns>
- /// <remarks>
- /// <para>
- /// The <paramref name="body"/> delegate is invoked once for each value in the iteration range:
- /// [fromInclusive, toExclusive). It is provided with the following parameters: the iteration count (an Int32),
- /// a <see cref="System.Threading.Tasks.ParallelLoopState">ParallelLoopState</see> instance that may be
- /// used to break out of the loop prematurely, and some local state that may be shared amongst iterations
- /// that execute on the same thread.
- /// </para>
- /// <para>
- /// The <paramref name="localInit"/> delegate is invoked once for each thread that participates in the loop's
- /// execution and returns the initial local state for each of those threads. These initial states are passed to the first
- /// <paramref name="body"/> invocations on each thread. Then, every subsequent body invocation returns a possibly
- /// modified state value that is passed to the next body invocation. Finally, the last body invocation on each thread returns a state value
- /// that is passed to the <paramref name="localFinally"/> delegate. The localFinally delegate is invoked once per thread to perform a final
- /// action on each thread's local state.
- /// </para>
- /// </remarks>
- public static ParallelLoopResult For<TLocal>(
- int fromInclusive, int toExclusive, ParallelOptions parallelOptions,
- Func<TLocal> localInit,
- Func<int, ParallelLoopState, TLocal, TLocal> body,
- Action<TLocal> localFinally)
- {
- if (body == null)
- {
- throw new ArgumentNullException(nameof(body));
- }
- if (localInit == null)
- {
- throw new ArgumentNullException(nameof(localInit));
- }
- if (localFinally == null)
- {
- throw new ArgumentNullException(nameof(localFinally));
- }
- if (parallelOptions == null)
- {
- throw new ArgumentNullException(nameof(parallelOptions));
- }
-
- return ForWorker(
- fromInclusive, toExclusive, parallelOptions,
- null, null, body, localInit, localFinally);
- }
-
- /// <summary>
- /// Executes a for loop in which iterations may run in parallel.
- /// </summary>
- /// <typeparam name="TLocal">The type of the thread-local data.</typeparam>
- /// <param name="fromInclusive">The start index, inclusive.</param>
- /// <param name="toExclusive">The end index, exclusive.</param>
- /// <param name="parallelOptions">A <see cref="T:System.Threading.Tasks.ParallelOptions">ParallelOptions</see>
- /// instance that configures the behavior of this operation.</param>
- /// <param name="localInit">The function delegate that returns the initial state of the local data
- /// for each thread.</param>
- /// <param name="body">The delegate that is invoked once per iteration.</param>
- /// <param name="localFinally">The delegate that performs a final action on the local state of each
- /// thread.</param>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="body"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the
- /// <paramref name="localInit"/> argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the
- /// <paramref name="localFinally"/> argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the
- /// <paramref name="parallelOptions"/> argument is null.</exception>
- /// <exception cref="T:System.OperationCanceledException">The exception that is thrown when the
- /// <see cref="T:System.Threading.CancellationToken">CancellationToken</see> in the <paramref name="parallelOptions"/>
- /// argument is set.</exception>
- /// <exception cref="T:System.AggregateException">The exception that is thrown to contain an exception
- /// thrown from one of the specified delegates.</exception>
- /// <exception cref="T:System.ObjectDisposedException">The exception that is thrown when the
- /// the <see cref="T:System.Threading.CancellationTokenSource">CancellationTokenSource</see> associated with the
- /// the <see cref="T:System.Threading.CancellationToken">CancellationToken</see> in the
- /// <paramref name="parallelOptions"/> has been disposed.</exception>
- /// <returns>A <see cref="T:System.Threading.Tasks.ParallelLoopResult">ParallelLoopResult</see> structure
- /// that contains information on what portion of the loop completed.</returns>
- /// <remarks>
- /// <para>
- /// The <paramref name="body"/> delegate is invoked once for each value in the iteration range:
- /// [fromInclusive, toExclusive). It is provided with the following parameters: the iteration count (an Int64),
- /// a <see cref="System.Threading.Tasks.ParallelLoopState">ParallelLoopState</see> instance that may be
- /// used to break out of the loop prematurely, and some local state that may be shared amongst iterations
- /// that execute on the same thread.
- /// </para>
- /// <para>
- /// The <paramref name="localInit"/> delegate is invoked once for each thread that participates in the loop's
- /// execution and returns the initial local state for each of those threads. These initial states are passed to the first
- /// <paramref name="body"/> invocations on each thread. Then, every subsequent body invocation returns a possibly
- /// modified state value that is passed to the next body invocation. Finally, the last body invocation on each thread returns a state value
- /// that is passed to the <paramref name="localFinally"/> delegate. The localFinally delegate is invoked once per thread to perform a final
- /// action on each thread's local state.
- /// </para>
- /// </remarks>
- public static ParallelLoopResult For<TLocal>(
- long fromInclusive, long toExclusive, ParallelOptions parallelOptions,
- Func<TLocal> localInit,
- Func<long, ParallelLoopState, TLocal, TLocal> body,
- Action<TLocal> localFinally)
- {
- if (body == null)
- {
- throw new ArgumentNullException(nameof(body));
- }
- if (localInit == null)
- {
- throw new ArgumentNullException(nameof(localInit));
- }
- if (localFinally == null)
- {
- throw new ArgumentNullException(nameof(localFinally));
- }
- if (parallelOptions == null)
- {
- throw new ArgumentNullException(nameof(parallelOptions));
- }
-
-
- return ForWorker64(
- fromInclusive, toExclusive, parallelOptions,
- null, null, body, localInit, localFinally);
- }
-
-
-
-
-
-
-
- /// <summary>
- /// Performs the major work of the parallel for loop. It assumes that argument validation has already
- /// been performed by the caller. This function's whole purpose in life is to enable as much reuse of
- /// common implementation details for the various For overloads we offer. Without it, we'd end up
- /// with lots of duplicate code. It handles: (1) simple for loops, (2) for loops that depend on
- /// ParallelState, and (3) for loops with thread local data.
- ///
- /// </summary>
- /// <typeparam name="TLocal">The type of the local data.</typeparam>
- /// <param name="fromInclusive">The loop's start index, inclusive.</param>
- /// <param name="toExclusive">The loop's end index, exclusive.</param>
- /// <param name="parallelOptions">A ParallelOptions instance.</param>
- /// <param name="body">The simple loop body.</param>
- /// <param name="bodyWithState">The loop body for ParallelState overloads.</param>
- /// <param name="bodyWithLocal">The loop body for thread local state overloads.</param>
- /// <param name="localInit">A selector function that returns new thread local state.</param>
- /// <param name="localFinally">A cleanup function to destroy thread local state.</param>
- /// <remarks>Only one of the body arguments may be supplied (i.e. they are exclusive).</remarks>
- /// <returns>A <see cref="T:System.Threading.Tasks.ParallelLoopResult"/> structure.</returns>
- private static ParallelLoopResult ForWorker<TLocal>(
- int fromInclusive, int toExclusive,
- ParallelOptions parallelOptions,
- Action<int> body,
- Action<int, ParallelLoopState> bodyWithState,
- Func<int, ParallelLoopState, TLocal, TLocal> bodyWithLocal,
- Func<TLocal> localInit, Action<TLocal> localFinally)
- {
- Debug.Assert(((body == null ? 0 : 1) + (bodyWithState == null ? 0 : 1) + (bodyWithLocal == null ? 0 : 1)) == 1,
- "expected exactly one body function to be supplied");
- Debug.Assert(bodyWithLocal != null || (localInit == null && localFinally == null),
- "thread local functions should only be supplied for loops w/ thread local bodies");
-
- // Instantiate our result. Specifics will be filled in later.
- ParallelLoopResult result = new ParallelLoopResult();
-
- // We just return immediately if 'to' is smaller (or equal to) 'from'.
- if (toExclusive <= fromInclusive)
- {
- result.m_completed = true;
- return result;
- }
-
- // For all loops we need a shared flag even though we don't have a body with state,
- // because the shared flag contains the exceptional bool, which triggers other workers
- // to exit their loops if one worker catches an exception
- ParallelLoopStateFlags32 sharedPStateFlags = new ParallelLoopStateFlags32();
-
- TaskCreationOptions creationOptions = TaskCreationOptions.None;
- InternalTaskOptions internalOptions = InternalTaskOptions.SelfReplicating;
-
- // Before getting started, do a quick peek to see if we have been canceled already
- if (parallelOptions.CancellationToken.IsCancellationRequested)
- {
- throw new OperationCanceledException(parallelOptions.CancellationToken);
- }
-
- // initialize ranges with passed in loop arguments and expected number of workers
- int numExpectedWorkers = (parallelOptions.EffectiveMaxConcurrencyLevel == -1) ?
- PlatformHelper.ProcessorCount :
- parallelOptions.EffectiveMaxConcurrencyLevel;
- RangeManager rangeManager = new RangeManager(fromInclusive, toExclusive, 1, numExpectedWorkers);
-
- // Keep track of any cancellations
- OperationCanceledException oce = null;
-
- CancellationTokenRegistration ctr = new CancellationTokenRegistration();
-
- // if cancellation is enabled, we need to register a callback to stop the loop when it gets signaled
- if (parallelOptions.CancellationToken.CanBeCanceled)
- {
- ctr = parallelOptions.CancellationToken.InternalRegisterWithoutEC((o) =>
- {
- // Cause processing to stop
- sharedPStateFlags.Cancel();
- // Record our cancellation
- oce = new OperationCanceledException(parallelOptions.CancellationToken);
- }, null);
- }
-
- // ETW event for Parallel For begin
- int forkJoinContextID = 0;
- Task callingTask = null;
- if (TplEtwProvider.Log.IsEnabled())
- {
- forkJoinContextID = Interlocked.Increment(ref s_forkJoinContextID);
- callingTask = Task.InternalCurrent;
- TplEtwProvider.Log.ParallelLoopBegin((callingTask != null ? callingTask.m_taskScheduler.Id : TaskScheduler.Current.Id), (callingTask != null ? callingTask.Id : 0),
- forkJoinContextID, TplEtwProvider.ForkJoinOperationType.ParallelFor,
- fromInclusive, toExclusive);
- }
-
- ParallelForReplicatingTask rootTask = null;
-
- try
- {
- // this needs to be in try-block because it can throw in BuggyScheduler.MaxConcurrencyLevel
- rootTask = new ParallelForReplicatingTask(
- parallelOptions,
- delegate
- {
- //
- // first thing we do upon enterying the task is to register as a new "RangeWorker" with the
- // shared RangeManager instance.
- //
- // If this call returns a RangeWorker struct which wraps the state needed by this task
- //
- // We need to call FindNewWork32() on it to see whether there's a chunk available.
- //
-
-
- // Cache some information about the current task
- Task currentWorkerTask = Task.InternalCurrent;
- bool bIsRootTask = (currentWorkerTask == rootTask);
-
- RangeWorker currentWorker = new RangeWorker();
- Object savedStateFromPreviousReplica = currentWorkerTask.SavedStateFromPreviousReplica;
-
- if (savedStateFromPreviousReplica is RangeWorker)
- currentWorker = (RangeWorker)savedStateFromPreviousReplica;
- else
- currentWorker = rangeManager.RegisterNewWorker();
-
-
-
- // These are the local index values to be used in the sequential loop.
- // Their values filled in by FindNewWork32
- int nFromInclusiveLocal;
- int nToExclusiveLocal;
-
- if (currentWorker.FindNewWork32(out nFromInclusiveLocal, out nToExclusiveLocal) == false ||
- sharedPStateFlags.ShouldExitLoop(nFromInclusiveLocal) == true)
- {
- return; // no need to run
- }
-
- // ETW event for ParallelFor Worker Fork
- if (TplEtwProvider.Log.IsEnabled())
- {
- TplEtwProvider.Log.ParallelFork((currentWorkerTask != null ? currentWorkerTask.m_taskScheduler.Id : TaskScheduler.Current.Id), (currentWorkerTask != null ? currentWorkerTask.Id : 0),
- forkJoinContextID);
- }
-
- TLocal localValue = default(TLocal);
- bool bLocalValueInitialized = false; // Tracks whether localInit ran without exceptions, so that we can skip localFinally if it wasn't
-
- try
- {
- // Create a new state object that references the shared "stopped" and "exceptional" flags
- // If needed, it will contain a new instance of thread-local state by invoking the selector.
- ParallelLoopState32 state = null;
-
- if (bodyWithState != null)
- {
- Debug.Assert(sharedPStateFlags != null);
- state = new ParallelLoopState32(sharedPStateFlags);
- }
- else if (bodyWithLocal != null)
- {
- Debug.Assert(sharedPStateFlags != null);
- state = new ParallelLoopState32(sharedPStateFlags);
- if (localInit != null)
- {
- localValue = localInit();
- bLocalValueInitialized = true;
- }
- }
-
- // initialize a loop timer which will help us decide whether we should exit early
- LoopTimer loopTimer = new LoopTimer(rootTask.ActiveChildCount);
-
- // Now perform the loop itself.
- do
- {
- if (body != null)
- {
- for (int j = nFromInclusiveLocal;
- j < nToExclusiveLocal && (sharedPStateFlags.LoopStateFlags == ParallelLoopStateFlags.PLS_NONE // fast path check as SEL() doesn't inline
- || !sharedPStateFlags.ShouldExitLoop()); // the no-arg version is used since we have no state
- j += 1)
- {
-
- body(j);
- }
- }
- else if (bodyWithState != null)
- {
- for (int j = nFromInclusiveLocal;
- j < nToExclusiveLocal && (sharedPStateFlags.LoopStateFlags == ParallelLoopStateFlags.PLS_NONE // fast path check as SEL() doesn't inline
- || !sharedPStateFlags.ShouldExitLoop(j));
- j += 1)
- {
-
- state.CurrentIteration = j;
- bodyWithState(j, state);
- }
- }
- else
- {
- for (int j = nFromInclusiveLocal;
- j < nToExclusiveLocal && (sharedPStateFlags.LoopStateFlags == ParallelLoopStateFlags.PLS_NONE // fast path check as SEL() doesn't inline
- || !sharedPStateFlags.ShouldExitLoop(j));
- j += 1)
- {
- state.CurrentIteration = j;
- localValue = bodyWithLocal(j, state, localValue);
- }
- }
-
- // Cooperative multitasking workaround for AppDomain fairness.
- // Check if allowed loop time is exceeded, if so save current state and return. The self replicating task logic
- // will detect this, and queue up a replacement task. Note that we don't do this on the root task.
- if (!bIsRootTask && loopTimer.LimitExceeded())
- {
- currentWorkerTask.SavedStateForNextReplica = (object)currentWorker;
- break;
- }
-
- }
- // Exit if we can't find new work, or if the loop was stoppped.
- while (currentWorker.FindNewWork32(out nFromInclusiveLocal, out nToExclusiveLocal) &&
- ((sharedPStateFlags.LoopStateFlags == ParallelLoopStateFlags.PLS_NONE) ||
- !sharedPStateFlags.ShouldExitLoop(nFromInclusiveLocal)));
- }
- catch
- {
- // if we catch an exception in a worker, we signal the other workers to exit the loop, and we rethrow
- sharedPStateFlags.SetExceptional();
- throw;
- }
- finally
- {
- // If a cleanup function was specified, call it. Otherwise, if the type is
- // IDisposable, we will invoke Dispose on behalf of the user.
- if (localFinally != null && bLocalValueInitialized)
- {
- localFinally(localValue);
- }
-
- // ETW event for ParallelFor Worker Join
- if (TplEtwProvider.Log.IsEnabled())
- {
- TplEtwProvider.Log.ParallelJoin((currentWorkerTask != null ? currentWorkerTask.m_taskScheduler.Id : TaskScheduler.Current.Id), (currentWorkerTask != null ? currentWorkerTask.Id : 0),
- forkJoinContextID);
- }
- }
- },
- creationOptions, internalOptions);
-
- rootTask.RunSynchronously(parallelOptions.EffectiveTaskScheduler); // might throw TSE
- rootTask.Wait();
-
- // If we made a cancellation registration, we need to clean it up now before observing the OCE
- // Otherwise we could be caught in the middle of a callback, and observe PLS_STOPPED, but oce = null
- if (parallelOptions.CancellationToken.CanBeCanceled)
- {
- ctr.Dispose();
- }
-
- // If we got through that with no exceptions, and we were canceled, then
- // throw our cancellation exception
- if (oce != null) throw oce;
- }
- catch (AggregateException aggExp)
- {
- // if we made a cancellation registration, and rootTask.Wait threw, we need to clean it up here
- if (parallelOptions.CancellationToken.CanBeCanceled)
- {
- ctr.Dispose();
- }
-
- // see if we can combine it into a single OCE. If not propagate the original exception
- ThrowIfReducableToSingleOCE(aggExp.InnerExceptions, parallelOptions.CancellationToken);
- throw;
- }
- catch (TaskSchedulerException)
- {
- // if we made a cancellation registration, and rootTask.RunSynchronously threw, we need to clean it up here
- if (parallelOptions.CancellationToken.CanBeCanceled)
- {
- ctr.Dispose();
- }
- throw;
- }
- finally
- {
- int sb_status = sharedPStateFlags.LoopStateFlags;
- result.m_completed = (sb_status == ParallelLoopStateFlags.PLS_NONE);
- if ((sb_status & ParallelLoopStateFlags.PLS_BROKEN) != 0)
- {
- result.m_lowestBreakIteration = sharedPStateFlags.LowestBreakIteration;
- }
-
- if ((rootTask != null) && rootTask.IsCompleted) rootTask.Dispose();
-
- // ETW event for Parallel For End
- if (TplEtwProvider.Log.IsEnabled())
- {
- int nTotalIterations = 0;
-
- // calculate how many iterations we ran in total
- if (sb_status == ParallelLoopStateFlags.PLS_NONE)
- nTotalIterations = toExclusive - fromInclusive;
- else if ((sb_status & ParallelLoopStateFlags.PLS_BROKEN) != 0)
- nTotalIterations = sharedPStateFlags.LowestBreakIteration - fromInclusive;
- else
- nTotalIterations = -1; //PLS_STOPPED! We can't determine this if we were stopped..
-
- TplEtwProvider.Log.ParallelLoopEnd((callingTask != null ? callingTask.m_taskScheduler.Id : TaskScheduler.Current.Id), (callingTask != null ? callingTask.Id : 0),
- forkJoinContextID, nTotalIterations);
- }
- }
-
- return result;
- }
-
- /// <summary>
- /// Performs the major work of the 64-bit parallel for loop. It assumes that argument validation has already
- /// been performed by the caller. This function's whole purpose in life is to enable as much reuse of
- /// common implementation details for the various For overloads we offer. Without it, we'd end up
- /// with lots of duplicate code. It handles: (1) simple for loops, (2) for loops that depend on
- /// ParallelState, and (3) for loops with thread local data.
- ///
- /// </summary>
- /// <typeparam name="TLocal">The type of the local data.</typeparam>
- /// <param name="fromInclusive">The loop's start index, inclusive.</param>
- /// <param name="toExclusive">The loop's end index, exclusive.</param>
- /// <param name="parallelOptions">A ParallelOptions instance.</param>
- /// <param name="body">The simple loop body.</param>
- /// <param name="bodyWithState">The loop body for ParallelState overloads.</param>
- /// <param name="bodyWithLocal">The loop body for thread local state overloads.</param>
- /// <param name="localInit">A selector function that returns new thread local state.</param>
- /// <param name="localFinally">A cleanup function to destroy thread local state.</param>
- /// <remarks>Only one of the body arguments may be supplied (i.e. they are exclusive).</remarks>
- /// <returns>A <see cref="T:System.Threading.Tasks.ParallelLoopResult"/> structure.</returns>
- private static ParallelLoopResult ForWorker64<TLocal>(
- long fromInclusive, long toExclusive,
- ParallelOptions parallelOptions,
- Action<long> body,
- Action<long, ParallelLoopState> bodyWithState,
- Func<long, ParallelLoopState, TLocal, TLocal> bodyWithLocal,
- Func<TLocal> localInit, Action<TLocal> localFinally)
- {
- Debug.Assert(((body == null ? 0 : 1) + (bodyWithState == null ? 0 : 1) + (bodyWithLocal == null ? 0 : 1)) == 1,
- "expected exactly one body function to be supplied");
- Debug.Assert(bodyWithLocal != null || (localInit == null && localFinally == null),
- "thread local functions should only be supplied for loops w/ thread local bodies");
-
- // Instantiate our result. Specifics will be filled in later.
- ParallelLoopResult result = new ParallelLoopResult();
-
- // We just return immediately if 'to' is smaller (or equal to) 'from'.
- if (toExclusive <= fromInclusive)
- {
- result.m_completed = true;
- return result;
- }
-
- // For all loops we need a shared flag even though we don't have a body with state,
- // because the shared flag contains the exceptional bool, which triggers other workers
- // to exit their loops if one worker catches an exception
- ParallelLoopStateFlags64 sharedPStateFlags = new ParallelLoopStateFlags64();
-
- TaskCreationOptions creationOptions = TaskCreationOptions.None;
- InternalTaskOptions internalOptions = InternalTaskOptions.SelfReplicating;
-
- // Before getting started, do a quick peek to see if we have been canceled already
- if (parallelOptions.CancellationToken.IsCancellationRequested)
- {
- throw new OperationCanceledException(parallelOptions.CancellationToken);
- }
-
- // initialize ranges with passed in loop arguments and expected number of workers
- int numExpectedWorkers = (parallelOptions.EffectiveMaxConcurrencyLevel == -1) ?
- PlatformHelper.ProcessorCount :
- parallelOptions.EffectiveMaxConcurrencyLevel;
- RangeManager rangeManager = new RangeManager(fromInclusive, toExclusive, 1, numExpectedWorkers);
-
- // Keep track of any cancellations
- OperationCanceledException oce = null;
-
- CancellationTokenRegistration ctr = new CancellationTokenRegistration();
-
- // if cancellation is enabled, we need to register a callback to stop the loop when it gets signaled
- if (parallelOptions.CancellationToken.CanBeCanceled)
- {
- ctr = parallelOptions.CancellationToken.InternalRegisterWithoutEC((o) =>
- {
- // Cause processing to stop
- sharedPStateFlags.Cancel();
- // Record our cancellation
- oce = new OperationCanceledException(parallelOptions.CancellationToken);
- }, null);
- }
-
- // ETW event for Parallel For begin
- Task callerTask = null;
- int forkJoinContextID = 0;
- if (TplEtwProvider.Log.IsEnabled())
- {
- forkJoinContextID = Interlocked.Increment(ref s_forkJoinContextID);
- callerTask = Task.InternalCurrent;
- TplEtwProvider.Log.ParallelLoopBegin((callerTask != null ? callerTask.m_taskScheduler.Id : TaskScheduler.Current.Id), (callerTask != null ? callerTask.Id : 0),
- forkJoinContextID, TplEtwProvider.ForkJoinOperationType.ParallelFor,
- fromInclusive, toExclusive);
- }
-
- ParallelForReplicatingTask rootTask = null;
-
- try
- {
- // this needs to be in try-block because it can throw in BuggyScheduler.MaxConcurrencyLevel
- rootTask = new ParallelForReplicatingTask(
- parallelOptions,
- delegate
- {
- //
- // first thing we do upon enterying the task is to register as a new "RangeWorker" with the
- // shared RangeManager instance.
- //
- // If this call returns a RangeWorker struct which wraps the state needed by this task
- //
- // We need to call FindNewWork() on it to see whether there's a chunk available.
- //
-
- // Cache some information about the current task
- Task currentWorkerTask = Task.InternalCurrent;
- bool bIsRootTask = (currentWorkerTask == rootTask);
-
- RangeWorker currentWorker = new RangeWorker();
- Object savedStateFromPreviousReplica = currentWorkerTask.SavedStateFromPreviousReplica;
-
- if (savedStateFromPreviousReplica is RangeWorker)
- currentWorker = (RangeWorker)savedStateFromPreviousReplica;
- else
- currentWorker = rangeManager.RegisterNewWorker();
-
-
- // These are the local index values to be used in the sequential loop.
- // Their values filled in by FindNewWork
- long nFromInclusiveLocal;
- long nToExclusiveLocal;
-
- if (currentWorker.FindNewWork(out nFromInclusiveLocal, out nToExclusiveLocal) == false ||
- sharedPStateFlags.ShouldExitLoop(nFromInclusiveLocal) == true)
- {
- return; // no need to run
- }
-
- // ETW event for ParallelFor Worker Fork
- if (TplEtwProvider.Log.IsEnabled())
- {
- TplEtwProvider.Log.ParallelFork((currentWorkerTask != null ? currentWorkerTask.m_taskScheduler.Id : TaskScheduler.Current.Id), (currentWorkerTask != null ? currentWorkerTask.Id : 0),
- forkJoinContextID);
- }
-
- TLocal localValue = default(TLocal);
- bool bLocalValueInitialized = false; // Tracks whether localInit ran without exceptions, so that we can skip localFinally if it wasn't
-
- try
- {
-
- // Create a new state object that references the shared "stopped" and "exceptional" flags
- // If needed, it will contain a new instance of thread-local state by invoking the selector.
- ParallelLoopState64 state = null;
-
- if (bodyWithState != null)
- {
- Debug.Assert(sharedPStateFlags != null);
- state = new ParallelLoopState64(sharedPStateFlags);
- }
- else if (bodyWithLocal != null)
- {
- Debug.Assert(sharedPStateFlags != null);
- state = new ParallelLoopState64(sharedPStateFlags);
-
- // If a thread-local selector was supplied, invoke it. Otherwise, use the default.
- if (localInit != null)
- {
- localValue = localInit();
- bLocalValueInitialized = true;
- }
- }
-
- // initialize a loop timer which will help us decide whether we should exit early
- LoopTimer loopTimer = new LoopTimer(rootTask.ActiveChildCount);
-
- // Now perform the loop itself.
- do
- {
- if (body != null)
- {
- for (long j = nFromInclusiveLocal;
- j < nToExclusiveLocal && (sharedPStateFlags.LoopStateFlags == ParallelLoopStateFlags.PLS_NONE // fast path check as SEL() doesn't inline
- || !sharedPStateFlags.ShouldExitLoop()); // the no-arg version is used since we have no state
- j += 1)
- {
- body(j);
- }
- }
- else if (bodyWithState != null)
- {
- for (long j = nFromInclusiveLocal;
- j < nToExclusiveLocal && (sharedPStateFlags.LoopStateFlags == ParallelLoopStateFlags.PLS_NONE // fast path check as SEL() doesn't inline
- || !sharedPStateFlags.ShouldExitLoop(j));
- j += 1)
- {
- state.CurrentIteration = j;
- bodyWithState(j, state);
- }
- }
- else
- {
- for (long j = nFromInclusiveLocal;
- j < nToExclusiveLocal && (sharedPStateFlags.LoopStateFlags == ParallelLoopStateFlags.PLS_NONE // fast path check as SEL() doesn't inline
- || !sharedPStateFlags.ShouldExitLoop(j));
- j += 1)
- {
- state.CurrentIteration = j;
- localValue = bodyWithLocal(j, state, localValue);
- }
- }
-
- // Cooperative multitasking workaround for AppDomain fairness.
- // Check if allowed loop time is exceeded, if so save current state and return. The self replicating task logic
- // will detect this, and queue up a replacement task. Note that we don't do this on the root task.
- if (!bIsRootTask && loopTimer.LimitExceeded())
- {
- currentWorkerTask.SavedStateForNextReplica = (object)currentWorker;
- break;
- }
- }
- // Exit if we can't find new work, or if the loop was stoppped.
- while (currentWorker.FindNewWork(out nFromInclusiveLocal, out nToExclusiveLocal) &&
- ((sharedPStateFlags.LoopStateFlags == ParallelLoopStateFlags.PLS_NONE) ||
- !sharedPStateFlags.ShouldExitLoop(nFromInclusiveLocal)));
- }
- catch
- {
- // if we catch an exception in a worker, we signal the other workers to exit the loop, and we rethrow
- sharedPStateFlags.SetExceptional();
- throw;
- }
- finally
- {
- // If a cleanup function was specified, call it. Otherwise, if the type is
- // IDisposable, we will invoke Dispose on behalf of the user.
- if (localFinally != null && bLocalValueInitialized)
- {
- localFinally(localValue);
- }
-
- // ETW event for ParallelFor Worker Join
- if (TplEtwProvider.Log.IsEnabled())
- {
- TplEtwProvider.Log.ParallelJoin((currentWorkerTask != null ? currentWorkerTask.m_taskScheduler.Id : TaskScheduler.Current.Id), (currentWorkerTask != null ? currentWorkerTask.Id : 0),
- forkJoinContextID);
- }
- }
- },
- creationOptions, internalOptions);
-
- rootTask.RunSynchronously(parallelOptions.EffectiveTaskScheduler); // might throw TSE
- rootTask.Wait();
-
- // If we made a cancellation registration, we need to clean it up now before observing the OCE
- // Otherwise we could be caught in the middle of a callback, and observe PLS_STOPPED, but oce = null
- if (parallelOptions.CancellationToken.CanBeCanceled)
- {
- ctr.Dispose();
- }
-
- // If we got through that with no exceptions, and we were canceled, then
- // throw our cancellation exception
- if (oce != null) throw oce;
- }
- catch (AggregateException aggExp)
- {
- // if we made a cancellation registration, and rootTask.Wait threw, we need to clean it up here
- if (parallelOptions.CancellationToken.CanBeCanceled)
- {
- ctr.Dispose();
- }
-
- // see if we can combine it into a single OCE. If not propagate the original exception
- ThrowIfReducableToSingleOCE(aggExp.InnerExceptions, parallelOptions.CancellationToken);
- throw;
- }
- catch (TaskSchedulerException)
- {
- // if we made a cancellation registration, and rootTask.RunSynchronously threw, we need to clean it up here
- if (parallelOptions.CancellationToken.CanBeCanceled)
- {
- ctr.Dispose();
- }
- throw;
- }
- finally
- {
- int sb_status = sharedPStateFlags.LoopStateFlags;
- result.m_completed = (sb_status == ParallelLoopStateFlags.PLS_NONE);
- if ((sb_status & ParallelLoopStateFlags.PLS_BROKEN) != 0)
- {
- result.m_lowestBreakIteration = sharedPStateFlags.LowestBreakIteration;
- }
-
- if ((rootTask != null) && rootTask.IsCompleted) rootTask.Dispose();
-
- // ETW event for Parallel For End
- if (TplEtwProvider.Log.IsEnabled())
- {
- long nTotalIterations = 0;
-
- // calculate how many iterations we ran in total
- if (sb_status == ParallelLoopStateFlags.PLS_NONE)
- nTotalIterations = toExclusive - fromInclusive;
- else if ((sb_status & ParallelLoopStateFlags.PLS_BROKEN) != 0)
- nTotalIterations = sharedPStateFlags.LowestBreakIteration - fromInclusive;
- else
- nTotalIterations = -1; //PLS_STOPPED! We can't determine this if we were stopped..
-
- TplEtwProvider.Log.ParallelLoopEnd((callerTask != null ? callerTask.m_taskScheduler.Id : TaskScheduler.Current.Id), (callerTask != null ? callerTask.Id : 0),
- forkJoinContextID, nTotalIterations);
- }
- }
-
- return result;
- }
-
-
- /// <summary>
- /// Executes a for each operation on an <see cref="T:System.Collections.IEnumerable{TSource}"/>
- /// in which iterations may run in parallel.
- /// </summary>
- /// <typeparam name="TSource">The type of the data in the source.</typeparam>
- /// <param name="source">An enumerable data source.</param>
- /// <param name="body">The delegate that is invoked once per iteration.</param>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="source"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="body"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.AggregateException">The exception that is thrown to contain an exception
- /// thrown from one of the specified delegates.</exception>
- /// <returns>A <see cref="T:System.Threading.Tasks.ParallelLoopResult">ParallelLoopResult</see> structure
- /// that contains information on what portion of the loop completed.</returns>
- /// <remarks>
- /// The <paramref name="body"/> delegate is invoked once for each element in the <paramref name="source"/>
- /// enumerable. It is provided with the current element as a parameter.
- /// </remarks>
- public static ParallelLoopResult ForEach<TSource>(IEnumerable<TSource> source, Action<TSource> body)
- {
- if (source == null)
- {
- throw new ArgumentNullException(nameof(source));
- }
- if (body == null)
- {
- throw new ArgumentNullException(nameof(body));
- }
-
- return ForEachWorker<TSource, object>(
- source, s_defaultParallelOptions, body, null, null, null, null, null, null);
- }
-
- /// <summary>
- /// Executes a for each operation on an <see cref="T:System.Collections.IEnumerable{TSource}"/>
- /// in which iterations may run in parallel.
- /// </summary>
- /// <typeparam name="TSource">The type of the data in the source.</typeparam>
- /// <param name="source">An enumerable data source.</param>
- /// <param name="parallelOptions">A <see cref="T:System.Threading.Tasks.ParallelOptions">ParallelOptions</see>
- /// instance that configures the behavior of this operation.</param>
- /// <param name="body">The delegate that is invoked once per iteration.</param>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="source"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the
- /// <paramref name="parallelOptions"/> argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="body"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.OperationCanceledException">The exception that is thrown when the
- /// <see cref="T:System.Threading.CancellationToken">CancellationToken</see> in the <paramref name="parallelOptions"/>
- /// argument is set</exception>
- /// <exception cref="T:System.AggregateException">The exception that is thrown to contain an exception
- /// thrown from one of the specified delegates.</exception>
- /// <exception cref="T:System.ObjectDisposedException">The exception that is thrown when the
- /// the <see cref="T:System.Threading.CancellationTokenSource">CancellationTokenSource</see> associated with the
- /// the <see cref="T:System.Threading.CancellationToken">CancellationToken</see> in the
- /// <paramref name="parallelOptions"/> has been disposed.</exception>
- /// <returns>A <see cref="T:System.Threading.Tasks.ParallelLoopResult">ParallelLoopResult</see> structure
- /// that contains information on what portion of the loop completed.</returns>
- /// <remarks>
- /// The <paramref name="body"/> delegate is invoked once for each element in the <paramref name="source"/>
- /// enumerable. It is provided with the current element as a parameter.
- /// </remarks>
- public static ParallelLoopResult ForEach<TSource>(IEnumerable<TSource> source, ParallelOptions parallelOptions, Action<TSource> body)
- {
- if (source == null)
- {
- throw new ArgumentNullException(nameof(source));
- }
- if (body == null)
- {
- throw new ArgumentNullException(nameof(body));
- }
- if (parallelOptions == null)
- {
- throw new ArgumentNullException(nameof(parallelOptions));
- }
-
- return ForEachWorker<TSource, object>(
- source, parallelOptions, body, null, null, null, null, null, null);
- }
-
- /// <summary>
- /// Executes a for each operation on an <see cref="T:System.Collections.IEnumerable{TSource}"/>
- /// in which iterations may run in parallel.
- /// </summary>
- /// <typeparam name="TSource">The type of the data in the source.</typeparam>
- /// <param name="source">An enumerable data source.</param>
- /// <param name="body">The delegate that is invoked once per iteration.</param>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="source"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="body"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.AggregateException">The exception that is thrown to contain an exception
- /// thrown from one of the specified delegates.</exception>
- /// <returns>A <see cref="T:System.Threading.Tasks.ParallelLoopResult">ParallelLoopResult</see> structure
- /// that contains information on what portion of the loop completed.</returns>
- /// <remarks>
- /// The <paramref name="body"/> delegate is invoked once for each element in the <paramref name="source"/>
- /// enumerable. It is provided with the following parameters: the current element,
- /// and a <see cref="System.Threading.Tasks.ParallelLoopState">ParallelLoopState</see> instance that may be
- /// used to break out of the loop prematurely.
- /// </remarks>
- public static ParallelLoopResult ForEach<TSource>(IEnumerable<TSource> source, Action<TSource, ParallelLoopState> body)
- {
- if (source == null)
- {
- throw new ArgumentNullException(nameof(source));
- }
- if (body == null)
- {
- throw new ArgumentNullException(nameof(body));
- }
-
- return ForEachWorker<TSource, object>(
- source, s_defaultParallelOptions, null, body, null, null, null, null, null);
- }
-
- /// <summary>
- /// Executes a for each operation on an <see cref="T:System.Collections.IEnumerable{TSource}"/>
- /// in which iterations may run in parallel.
- /// </summary>
- /// <typeparam name="TSource">The type of the data in the source.</typeparam>
- /// <param name="source">An enumerable data source.</param>
- /// <param name="parallelOptions">A <see cref="T:System.Threading.Tasks.ParallelOptions">ParallelOptions</see>
- /// instance that configures the behavior of this operation.</param>
- /// <param name="body">The delegate that is invoked once per iteration.</param>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="source"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the
- /// <paramref name="parallelOptions"/> argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="body"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.OperationCanceledException">The exception that is thrown when the
- /// <see cref="T:System.Threading.CancellationToken">CancellationToken</see> in the <paramref name="parallelOptions"/>
- /// argument is set</exception>
- /// <exception cref="T:System.AggregateException">The exception that is thrown to contain an exception
- /// thrown from one of the specified delegates.</exception>
- /// <exception cref="T:System.ObjectDisposedException">The exception that is thrown when the
- /// the <see cref="T:System.Threading.CancellationTokenSource">CancellationTokenSource</see> associated with the
- /// the <see cref="T:System.Threading.CancellationToken">CancellationToken</see> in the
- /// <paramref name="parallelOptions"/> has been disposed.</exception>
- /// <returns>A <see cref="T:System.Threading.Tasks.ParallelLoopResult">ParallelLoopResult</see> structure
- /// that contains information on what portion of the loop completed.</returns>
- /// <remarks>
- /// The <paramref name="body"/> delegate is invoked once for each element in the <paramref name="source"/>
- /// enumerable. It is provided with the following parameters: the current element,
- /// and a <see cref="System.Threading.Tasks.ParallelLoopState">ParallelLoopState</see> instance that may be
- /// used to break out of the loop prematurely.
- /// </remarks>
- public static ParallelLoopResult ForEach<TSource>(IEnumerable<TSource> source, ParallelOptions parallelOptions, Action<TSource, ParallelLoopState> body)
- {
- if (source == null)
- {
- throw new ArgumentNullException(nameof(source));
- }
- if (body == null)
- {
- throw new ArgumentNullException(nameof(body));
- }
- if (parallelOptions == null)
- {
- throw new ArgumentNullException(nameof(parallelOptions));
- }
-
- return ForEachWorker<TSource, object>(
- source, parallelOptions, null, body, null, null, null, null, null);
- }
-
- /// <summary>
- /// Executes a for each operation on an <see cref="T:System.Collections.IEnumerable{TSource}"/>
- /// in which iterations may run in parallel.
- /// </summary>
- /// <typeparam name="TSource">The type of the data in the source.</typeparam>
- /// <param name="source">An enumerable data source.</param>
- /// <param name="body">The delegate that is invoked once per iteration.</param>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="source"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="body"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.AggregateException">The exception that is thrown to contain an exception
- /// thrown from one of the specified delegates.</exception>
- /// <returns>A <see cref="T:System.Threading.Tasks.ParallelLoopResult">ParallelLoopResult</see> structure
- /// that contains information on what portion of the loop completed.</returns>
- /// <remarks>
- /// The <paramref name="body"/> delegate is invoked once for each element in the <paramref name="source"/>
- /// enumerable. It is provided with the following parameters: the current element,
- /// a <see cref="System.Threading.Tasks.ParallelLoopState">ParallelLoopState</see> instance that may be
- /// used to break out of the loop prematurely, and the current element's index (an Int64).
- /// </remarks>
- public static ParallelLoopResult ForEach<TSource>(IEnumerable<TSource> source, Action<TSource, ParallelLoopState, long> body)
- {
- if (source == null)
- {
- throw new ArgumentNullException(nameof(source));
- }
- if (body == null)
- {
- throw new ArgumentNullException(nameof(body));
- }
-
- return ForEachWorker<TSource, object>(
- source, s_defaultParallelOptions, null, null, body, null, null, null, null);
- }
-
- /// <summary>
- /// Executes a for each operation on an <see cref="T:System.Collections.IEnumerable{TSource}"/>
- /// in which iterations may run in parallel.
- /// </summary>
- /// <typeparam name="TSource">The type of the data in the source.</typeparam>
- /// <param name="source">An enumerable data source.</param>
- /// <param name="parallelOptions">A <see cref="T:System.Threading.Tasks.ParallelOptions">ParallelOptions</see>
- /// instance that configures the behavior of this operation.</param>
- /// <param name="body">The delegate that is invoked once per iteration.</param>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="source"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the
- /// <paramref name="parallelOptions"/> argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="body"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.OperationCanceledException">The exception that is thrown when the
- /// <see cref="T:System.Threading.CancellationToken">CancellationToken</see> in the <paramref name="parallelOptions"/>
- /// argument is set</exception>
- /// <exception cref="T:System.AggregateException">The exception that is thrown to contain an exception
- /// thrown from one of the specified delegates.</exception>
- /// <exception cref="T:System.ObjectDisposedException">The exception that is thrown when the
- /// the <see cref="T:System.Threading.CancellationTokenSource">CancellationTokenSource</see> associated with the
- /// the <see cref="T:System.Threading.CancellationToken">CancellationToken</see> in the
- /// <paramref name="parallelOptions"/> has been disposed.</exception>
- /// <returns>A <see cref="T:System.Threading.Tasks.ParallelLoopResult">ParallelLoopResult</see> structure
- /// that contains information on what portion of the loop completed.</returns>
- /// <remarks>
- /// The <paramref name="body"/> delegate is invoked once for each element in the <paramref name="source"/>
- /// enumerable. It is provided with the following parameters: the current element,
- /// a <see cref="System.Threading.Tasks.ParallelLoopState">ParallelLoopState</see> instance that may be
- /// used to break out of the loop prematurely, and the current element's index (an Int64).
- /// </remarks>
- public static ParallelLoopResult ForEach<TSource>(IEnumerable<TSource> source, ParallelOptions parallelOptions, Action<TSource, ParallelLoopState, long> body)
- {
- if (source == null)
- {
- throw new ArgumentNullException(nameof(source));
- }
- if (body == null)
- {
- throw new ArgumentNullException(nameof(body));
- }
- if (parallelOptions == null)
- {
- throw new ArgumentNullException(nameof(parallelOptions));
- }
-
- return ForEachWorker<TSource, object>(
- source, parallelOptions, null, null, body, null, null, null, null);
- }
-
- /// <summary>
- /// Executes a for each operation on an <see cref="T:System.Collections.IEnumerable{TSource}"/>
- /// in which iterations may run in parallel.
- /// </summary>
- /// <typeparam name="TSource">The type of the data in the source.</typeparam>
- /// <typeparam name="TLocal">The type of the thread-local data.</typeparam>
- /// <param name="source">An enumerable data source.</param>
- /// <param name="localInit">The function delegate that returns the initial state of the local data
- /// for each thread.</param>
- /// <param name="body">The delegate that is invoked once per iteration.</param>
- /// <param name="localFinally">The delegate that performs a final action on the local state of each
- /// thread.</param>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="source"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="body"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the
- /// <paramref name="localInit"/> argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the
- /// <paramref name="localFinally"/> argument is null.</exception>
- /// <exception cref="T:System.AggregateException">The exception that is thrown to contain an exception
- /// thrown from one of the specified delegates.</exception>
- /// <returns>A <see cref="T:System.Threading.Tasks.ParallelLoopResult">ParallelLoopResult</see> structure
- /// that contains information on what portion of the loop completed.</returns>
- /// <remarks>
- /// <para>
- /// The <paramref name="body"/> delegate is invoked once for each element in the <paramref name="source"/>
- /// enumerable. It is provided with the following parameters: the current element,
- /// a <see cref="System.Threading.Tasks.ParallelLoopState">ParallelLoopState</see> instance that may be
- /// used to break out of the loop prematurely, and some local state that may be shared amongst iterations
- /// that execute on the same thread.
- /// </para>
- /// <para>
- /// The <paramref name="localInit"/> delegate is invoked once for each thread that participates in the loop's
- /// execution and returns the initial local state for each of those threads. These initial states are passed to the first
- /// <paramref name="body"/> invocations on each thread. Then, every subsequent body invocation returns a possibly
- /// modified state value that is passed to the next body invocation. Finally, the last body invocation on each thread returns a state value
- /// that is passed to the <paramref name="localFinally"/> delegate. The localFinally delegate is invoked once per thread to perform a final
- /// action on each thread's local state.
- /// </para>
- /// </remarks>
- public static ParallelLoopResult ForEach<TSource, TLocal>(IEnumerable<TSource> source, Func<TLocal> localInit,
- Func<TSource, ParallelLoopState, TLocal, TLocal> body, Action<TLocal> localFinally)
- {
- if (source == null)
- {
- throw new ArgumentNullException(nameof(source));
- }
- if (body == null)
- {
- throw new ArgumentNullException(nameof(body));
- }
- if (localInit == null)
- {
- throw new ArgumentNullException(nameof(localInit));
- }
- if (localFinally == null)
- {
- throw new ArgumentNullException(nameof(localFinally));
- }
-
- return ForEachWorker<TSource, TLocal>(
- source, s_defaultParallelOptions, null, null, null, body, null, localInit, localFinally);
- }
-
- /// <summary>
- /// Executes a for each operation on an <see cref="T:System.Collections.IEnumerable{TSource}"/>
- /// in which iterations may run in parallel.
- /// </summary>
- /// <typeparam name="TSource">The type of the data in the source.</typeparam>
- /// <typeparam name="TLocal">The type of the thread-local data.</typeparam>
- /// <param name="source">An enumerable data source.</param>
- /// <param name="parallelOptions">A <see cref="T:System.Threading.Tasks.ParallelOptions">ParallelOptions</see>
- /// instance that configures the behavior of this operation.</param>
- /// <param name="localInit">The function delegate that returns the initial state of the local data
- /// for each thread.</param>
- /// <param name="body">The delegate that is invoked once per iteration.</param>
- /// <param name="localFinally">The delegate that performs a final action on the local state of each
- /// thread.</param>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="source"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the
- /// <paramref name="parallelOptions"/> argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="body"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the
- /// <paramref name="localInit"/> argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the
- /// <paramref name="localFinally"/> argument is null.</exception>
- /// <exception cref="T:System.OperationCanceledException">The exception that is thrown when the
- /// <see cref="T:System.Threading.CancellationToken">CancellationToken</see> in the <paramref name="parallelOptions"/>
- /// argument is set</exception>
- /// <exception cref="T:System.AggregateException">The exception that is thrown to contain an exception
- /// thrown from one of the specified delegates.</exception>
- /// <exception cref="T:System.ObjectDisposedException">The exception that is thrown when the
- /// the <see cref="T:System.Threading.CancellationTokenSource">CancellationTokenSource</see> associated with the
- /// the <see cref="T:System.Threading.CancellationToken">CancellationToken</see> in the
- /// <paramref name="parallelOptions"/> has been disposed.</exception>
- /// <returns>A <see cref="T:System.Threading.Tasks.ParallelLoopResult">ParallelLoopResult</see> structure
- /// that contains information on what portion of the loop completed.</returns>
- /// <remarks>
- /// <para>
- /// The <paramref name="body"/> delegate is invoked once for each element in the <paramref name="source"/>
- /// enumerable. It is provided with the following parameters: the current element,
- /// a <see cref="System.Threading.Tasks.ParallelLoopState">ParallelLoopState</see> instance that may be
- /// used to break out of the loop prematurely, and some local state that may be shared amongst iterations
- /// that execute on the same thread.
- /// </para>
- /// <para>
- /// The <paramref name="localInit"/> delegate is invoked once for each thread that participates in the loop's
- /// execution and returns the initial local state for each of those threads. These initial states are passed to the first
- /// <paramref name="body"/> invocations on each thread. Then, every subsequent body invocation returns a possibly
- /// modified state value that is passed to the next body invocation. Finally, the last body invocation on each thread returns a state value
- /// that is passed to the <paramref name="localFinally"/> delegate. The localFinally delegate is invoked once per thread to perform a final
- /// action on each thread's local state.
- /// </para>
- /// </remarks>
- public static ParallelLoopResult ForEach<TSource, TLocal>(IEnumerable<TSource> source,
- ParallelOptions parallelOptions, Func<TLocal> localInit,
- Func<TSource, ParallelLoopState, TLocal, TLocal> body, Action<TLocal> localFinally)
- {
- if (source == null)
- {
- throw new ArgumentNullException(nameof(source));
- }
- if (body == null)
- {
- throw new ArgumentNullException(nameof(body));
- }
- if (localInit == null)
- {
- throw new ArgumentNullException(nameof(localInit));
- }
- if (localFinally == null)
- {
- throw new ArgumentNullException(nameof(localFinally));
- }
- if (parallelOptions == null)
- {
- throw new ArgumentNullException(nameof(parallelOptions));
- }
-
- return ForEachWorker<TSource, TLocal>(
- source, parallelOptions, null, null, null, body, null, localInit, localFinally);
- }
-
- /// <summary>
- /// Executes a for each operation on an <see cref="T:System.Collections.IEnumerable{TSource}"/>
- /// in which iterations may run in parallel.
- /// </summary>
- /// <typeparam name="TSource">The type of the data in the source.</typeparam>
- /// <typeparam name="TLocal">The type of the thread-local data.</typeparam>
- /// <param name="source">An enumerable data source.</param>
- /// <param name="localInit">The function delegate that returns the initial state of the local data
- /// for each thread.</param>
- /// <param name="body">The delegate that is invoked once per iteration.</param>
- /// <param name="localFinally">The delegate that performs a final action on the local state of each
- /// thread.</param>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="source"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="body"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the
- /// <paramref name="localInit"/> argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the
- /// <paramref name="localFinally"/> argument is null.</exception>
- /// <exception cref="T:System.AggregateException">The exception that is thrown to contain an exception
- /// thrown from one of the specified delegates.</exception>
- /// <returns>A <see cref="T:System.Threading.Tasks.ParallelLoopResult">ParallelLoopResult</see> structure
- /// that contains information on what portion of the loop completed.</returns>
- /// <remarks>
- /// <para>
- /// The <paramref name="body"/> delegate is invoked once for each element in the <paramref name="source"/>
- /// enumerable. It is provided with the following parameters: the current element,
- /// a <see cref="System.Threading.Tasks.ParallelLoopState">ParallelLoopState</see> instance that may be
- /// used to break out of the loop prematurely, the current element's index (an Int64), and some local
- /// state that may be shared amongst iterations that execute on the same thread.
- /// </para>
- /// <para>
- /// The <paramref name="localInit"/> delegate is invoked once for each thread that participates in the loop's
- /// execution and returns the initial local state for each of those threads. These initial states are passed to the first
- /// <paramref name="body"/> invocations on each thread. Then, every subsequent body invocation returns a possibly
- /// modified state value that is passed to the next body invocation. Finally, the last body invocation on each thread returns a state value
- /// that is passed to the <paramref name="localFinally"/> delegate. The localFinally delegate is invoked once per thread to perform a final
- /// action on each thread's local state.
- /// </para>
- /// </remarks>
- public static ParallelLoopResult ForEach<TSource, TLocal>(IEnumerable<TSource> source, Func<TLocal> localInit,
- Func<TSource, ParallelLoopState, long, TLocal, TLocal> body, Action<TLocal> localFinally)
- {
- if (source == null)
- {
- throw new ArgumentNullException(nameof(source));
- }
- if (body == null)
- {
- throw new ArgumentNullException(nameof(body));
- }
- if (localInit == null)
- {
- throw new ArgumentNullException(nameof(localInit));
- }
- if (localFinally == null)
- {
- throw new ArgumentNullException(nameof(localFinally));
- }
-
- return ForEachWorker<TSource, TLocal>(
- source, s_defaultParallelOptions, null, null, null, null, body, localInit, localFinally);
- }
-
- /// <summary>
- /// Executes a for each operation on an <see cref="T:System.Collections.IEnumerable{TSource}"/>
- /// in which iterations may run in parallel.
- /// </summary>
- /// <typeparam name="TSource">The type of the data in the source.</typeparam>
- /// <typeparam name="TLocal">The type of the thread-local data.</typeparam>
- /// <param name="source">An enumerable data source.</param>
- /// <param name="parallelOptions">A <see cref="T:System.Threading.Tasks.ParallelOptions">ParallelOptions</see>
- /// instance that configures the behavior of this operation.</param>
- /// <param name="localInit">The function delegate that returns the initial state of the local data
- /// for each thread.</param>
- /// <param name="body">The delegate that is invoked once per iteration.</param>
- /// <param name="localFinally">The delegate that performs a final action on the local state of each
- /// thread.</param>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="source"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the
- /// <paramref name="parallelOptions"/> argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="body"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the
- /// <paramref name="localInit"/> argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the
- /// <paramref name="localFinally"/> argument is null.</exception>
- /// <exception cref="T:System.OperationCanceledException">The exception that is thrown when the
- /// <see cref="T:System.Threading.CancellationToken">CancellationToken</see> in the <paramref name="parallelOptions"/>
- /// argument is set</exception>
- /// <exception cref="T:System.AggregateException">The exception that is thrown to contain an exception
- /// thrown from one of the specified delegates.</exception>
- /// <exception cref="T:System.ObjectDisposedException">The exception that is thrown when the
- /// the <see cref="T:System.Threading.CancellationTokenSource">CancellationTokenSource</see> associated with the
- /// the <see cref="T:System.Threading.CancellationToken">CancellationToken</see> in the
- /// <paramref name="parallelOptions"/> has been disposed.</exception>
- /// <returns>A <see cref="T:System.Threading.Tasks.ParallelLoopResult">ParallelLoopResult</see> structure
- /// that contains information on what portion of the loop completed.</returns>
- /// <remarks>
- /// <para>
- /// The <paramref name="body"/> delegate is invoked once for each element in the <paramref name="source"/>
- /// enumerable. It is provided with the following parameters: the current element,
- /// a <see cref="System.Threading.Tasks.ParallelLoopState">ParallelLoopState</see> instance that may be
- /// used to break out of the loop prematurely, the current element's index (an Int64), and some local
- /// state that may be shared amongst iterations that execute on the same thread.
- /// </para>
- /// <para>
- /// The <paramref name="localInit"/> delegate is invoked once for each thread that participates in the loop's
- /// execution and returns the initial local state for each of those threads. These initial states are passed to the first
- /// <paramref name="body"/> invocations on each thread. Then, every subsequent body invocation returns a possibly
- /// modified state value that is passed to the next body invocation. Finally, the last body invocation on each thread returns a state value
- /// that is passed to the <paramref name="localFinally"/> delegate. The localFinally delegate is invoked once per thread to perform a final
- /// action on each thread's local state.
- /// </para>
- /// </remarks>
- public static ParallelLoopResult ForEach<TSource, TLocal>(IEnumerable<TSource> source, ParallelOptions parallelOptions, Func<TLocal> localInit,
- Func<TSource, ParallelLoopState, long, TLocal, TLocal> body, Action<TLocal> localFinally)
- {
- if (source == null)
- {
- throw new ArgumentNullException(nameof(source));
- }
- if (body == null)
- {
- throw new ArgumentNullException(nameof(body));
- }
- if (localInit == null)
- {
- throw new ArgumentNullException(nameof(localInit));
- }
- if (localFinally == null)
- {
- throw new ArgumentNullException(nameof(localFinally));
- }
- if (parallelOptions == null)
- {
- throw new ArgumentNullException(nameof(parallelOptions));
- }
-
- return ForEachWorker<TSource, TLocal>(
- source, parallelOptions, null, null, null, null, body, localInit, localFinally);
- }
-
-
- /// <summary>
- /// Performs the major work of the parallel foreach loop. It assumes that argument validation has
- /// already been performed by the caller. This function's whole purpose in life is to enable as much
- /// reuse of common implementation details for the various For overloads we offer. Without it, we'd
- /// end up with lots of duplicate code. It handles: (1) simple foreach loops, (2) foreach loops that
- /// depend on ParallelState, and (3) foreach loops that access indices, (4) foreach loops with thread
- /// local data, and any necessary permutations thereof.
- ///
- /// </summary>
- /// <typeparam name="TSource">The type of the source data.</typeparam>
- /// <typeparam name="TLocal">The type of the local data.</typeparam>
- /// <param name="source">An enumerable data source.</param>
- /// <param name="parallelOptions">ParallelOptions instance to use with this ForEach-loop</param>
- /// <param name="body">The simple loop body.</param>
- /// <param name="bodyWithState">The loop body for ParallelState overloads.</param>
- /// <param name="bodyWithStateAndIndex">The loop body for ParallelState/indexed overloads.</param>
- /// <param name="bodyWithStateAndLocal">The loop body for ParallelState/thread local state overloads.</param>
- /// <param name="bodyWithEverything">The loop body for ParallelState/indexed/thread local state overloads.</param>
- /// <param name="localInit">A selector function that returns new thread local state.</param>
- /// <param name="localFinally">A cleanup function to destroy thread local state.</param>
- /// <remarks>Only one of the bodyXX arguments may be supplied (i.e. they are exclusive).</remarks>
- /// <returns>A <see cref="T:System.Threading.Tasks.ParallelLoopResult"/> structure.</returns>
- private static ParallelLoopResult ForEachWorker<TSource, TLocal>(
- IEnumerable<TSource> source,
- ParallelOptions parallelOptions,
- Action<TSource> body,
- Action<TSource, ParallelLoopState> bodyWithState,
- Action<TSource, ParallelLoopState, long> bodyWithStateAndIndex,
- Func<TSource, ParallelLoopState, TLocal, TLocal> bodyWithStateAndLocal,
- Func<TSource, ParallelLoopState, long, TLocal, TLocal> bodyWithEverything,
- Func<TLocal> localInit, Action<TLocal> localFinally)
- {
- Debug.Assert(((body == null ? 0 : 1) + (bodyWithState == null ? 0 : 1) +
- (bodyWithStateAndIndex == null ? 0 : 1) + (bodyWithStateAndLocal == null ? 0 : 1) + (bodyWithEverything == null ? 0 : 1)) == 1,
- "expected exactly one body function to be supplied");
- Debug.Assert((bodyWithStateAndLocal != null) || (bodyWithEverything != null) || (localInit == null && localFinally == null),
- "thread local functions should only be supplied for loops w/ thread local bodies");
-
- // Before getting started, do a quick peek to see if we have been canceled already
- if (parallelOptions.CancellationToken.IsCancellationRequested)
- {
- throw new OperationCanceledException(parallelOptions.CancellationToken);
- }
-
- // If it's an array, we can use a fast-path that uses ldelems in the IL.
- TSource[] sourceAsArray = source as TSource[];
- if (sourceAsArray != null)
- {
- return ForEachWorker<TSource, TLocal>(
- sourceAsArray, parallelOptions, body, bodyWithState, bodyWithStateAndIndex, bodyWithStateAndLocal,
- bodyWithEverything, localInit, localFinally);
- }
-
- // If we can index into the list, we can use a faster code-path that doesn't result in
- // contention for the single, shared enumerator object.
- IList<TSource> sourceAsList = source as IList<TSource>;
- if (sourceAsList != null)
- {
- return ForEachWorker<TSource, TLocal>(
- sourceAsList, parallelOptions, body, bodyWithState, bodyWithStateAndIndex, bodyWithStateAndLocal,
- bodyWithEverything, localInit, localFinally);
- }
-
- // This is an honest-to-goodness IEnumerable. Wrap it in a Partitioner and defer to our
- // ForEach(Partitioner) logic.
- return PartitionerForEachWorker<TSource, TLocal>(Partitioner.Create(source), parallelOptions, body, bodyWithState,
- bodyWithStateAndIndex, bodyWithStateAndLocal, bodyWithEverything, localInit, localFinally);
-
- }
-
- /// <summary>
- /// A fast path for the more general ForEachWorker method above. This uses ldelem instructions to
- /// access the individual elements of the array, which will be faster.
- /// </summary>
- /// <typeparam name="TSource">The type of the source data.</typeparam>
- /// <typeparam name="TLocal">The type of the local data.</typeparam>
- /// <param name="array">An array data source.</param>
- /// <param name="parallelOptions">The options to use for execution.</param>
- /// <param name="body">The simple loop body.</param>
- /// <param name="bodyWithState">The loop body for ParallelState overloads.</param>
- /// <param name="bodyWithStateAndIndex">The loop body for indexed/ParallelLoopState overloads.</param>
- /// <param name="bodyWithStateAndLocal">The loop body for local/ParallelLoopState overloads.</param>
- /// <param name="bodyWithEverything">The loop body for the most generic overload.</param>
- /// <param name="localInit">A selector function that returns new thread local state.</param>
- /// <param name="localFinally">A cleanup function to destroy thread local state.</param>
- /// <returns>A <see cref="T:System.Threading.Tasks.ParallelLoopResult"/> structure.</returns>
- private static ParallelLoopResult ForEachWorker<TSource, TLocal>(
- TSource[] array,
- ParallelOptions parallelOptions,
- Action<TSource> body,
- Action<TSource, ParallelLoopState> bodyWithState,
- Action<TSource, ParallelLoopState, long> bodyWithStateAndIndex,
- Func<TSource, ParallelLoopState, TLocal, TLocal> bodyWithStateAndLocal,
- Func<TSource, ParallelLoopState, long, TLocal, TLocal> bodyWithEverything,
- Func<TLocal> localInit, Action<TLocal> localFinally)
- {
- Debug.Assert(array != null);
- Debug.Assert(parallelOptions != null, "ForEachWorker(array): parallelOptions is null");
-
- int from = array.GetLowerBound(0);
- int to = array.GetUpperBound(0) + 1;
-
- if (body != null)
- {
- return ForWorker<object>(
- from, to, parallelOptions, (i) => body(array[i]), null, null, null, null);
- }
- else if (bodyWithState != null)
- {
- return ForWorker<object>(
- from, to, parallelOptions, null, (i, state) => bodyWithState(array[i], state), null, null, null);
- }
- else if (bodyWithStateAndIndex != null)
- {
- return ForWorker<object>(
- from, to, parallelOptions, null, (i, state) => bodyWithStateAndIndex(array[i], state, i), null, null, null);
- }
- else if (bodyWithStateAndLocal != null)
- {
- return ForWorker<TLocal>(
- from, to, parallelOptions, null, null, (i, state, local) => bodyWithStateAndLocal(array[i], state, local), localInit, localFinally);
- }
- else
- {
- return ForWorker<TLocal>(
- from, to, parallelOptions, null, null, (i, state, local) => bodyWithEverything(array[i], state, i, local), localInit, localFinally);
- }
- }
-
- /// <summary>
- /// A fast path for the more general ForEachWorker method above. This uses IList&lt;T&gt;'s indexer
- /// capabilities to access the individual elements of the list rather than an enumerator.
- /// </summary>
- /// <typeparam name="TSource">The type of the source data.</typeparam>
- /// <typeparam name="TLocal">The type of the local data.</typeparam>
- /// <param name="list">A list data source.</param>
- /// <param name="parallelOptions">The options to use for execution.</param>
- /// <param name="body">The simple loop body.</param>
- /// <param name="bodyWithState">The loop body for ParallelState overloads.</param>
- /// <param name="bodyWithStateAndIndex">The loop body for indexed/ParallelLoopState overloads.</param>
- /// <param name="bodyWithStateAndLocal">The loop body for local/ParallelLoopState overloads.</param>
- /// <param name="bodyWithEverything">The loop body for the most generic overload.</param>
- /// <param name="localInit">A selector function that returns new thread local state.</param>
- /// <param name="localFinally">A cleanup function to destroy thread local state.</param>
- /// <returns>A <see cref="T:System.Threading.Tasks.ParallelLoopResult"/> structure.</returns>
- private static ParallelLoopResult ForEachWorker<TSource, TLocal>(
- IList<TSource> list,
- ParallelOptions parallelOptions,
- Action<TSource> body,
- Action<TSource, ParallelLoopState> bodyWithState,
- Action<TSource, ParallelLoopState, long> bodyWithStateAndIndex,
- Func<TSource, ParallelLoopState, TLocal, TLocal> bodyWithStateAndLocal,
- Func<TSource, ParallelLoopState, long, TLocal, TLocal> bodyWithEverything,
- Func<TLocal> localInit, Action<TLocal> localFinally)
- {
- Debug.Assert(list != null);
- Debug.Assert(parallelOptions != null, "ForEachWorker(list): parallelOptions is null");
-
- if (body != null)
- {
- return ForWorker<object>(
- 0, list.Count, parallelOptions, (i) => body(list[i]), null, null, null, null);
- }
- else if (bodyWithState != null)
- {
- return ForWorker<object>(
- 0, list.Count, parallelOptions, null, (i, state) => bodyWithState(list[i], state), null, null, null);
- }
- else if (bodyWithStateAndIndex != null)
- {
- return ForWorker<object>(
- 0, list.Count, parallelOptions, null, (i, state) => bodyWithStateAndIndex(list[i], state, i), null, null, null);
- }
- else if (bodyWithStateAndLocal != null)
- {
- return ForWorker<TLocal>(
- 0, list.Count, parallelOptions, null, null, (i, state, local) => bodyWithStateAndLocal(list[i], state, local), localInit, localFinally);
- }
- else
- {
- return ForWorker<TLocal>(
- 0, list.Count, parallelOptions, null, null, (i, state, local) => bodyWithEverything(list[i], state, i, local), localInit, localFinally);
- }
- }
-
-
-
- /// <summary>
- /// Executes a for each operation on a <see cref="T:System.Collections.Concurrent.Partitioner{TSource}">
- /// Partitioner</see> in which iterations may run in parallel.
- /// </summary>
- /// <typeparam name="TSource">The type of the elements in <paramref name="source"/>.</typeparam>
- /// <param name="source">The Partitioner that contains the original data source.</param>
- /// <param name="body">The delegate that is invoked once per iteration.</param>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="source"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="body"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when the
- /// SupportsDynamicPartitions property in the <paramref name="source"/> Partitioner returns
- /// false.</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when any
- /// methods in the <paramref name="source"/> Partitioner return null.</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when the
- /// GetPartitions() method in the <paramref name="source"/> Partitioner does not return
- /// the correct number of partitions.</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when the
- /// GetPartitions() method in the <paramref name="source"/> Partitioner returns an IList
- /// with at least one null value.</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when the
- /// GetDynamicPartitions() method in the <paramref name="source"/> Partitioner returns an
- /// IEnumerable whose GetEnumerator() method returns null.</exception>
- /// <exception cref="T:System.AggregateException">The exception that is thrown to contain an exception
- /// thrown from one of the specified delegates.</exception>
- /// <returns>A <see cref="T:System.Threading.Tasks.ParallelLoopResult">ParallelLoopResult</see> structure
- /// that contains information on what portion of the loop completed.</returns>
- /// <remarks>
- /// <para>
- /// The <see cref="T:System.Collections.Concurrent.Partitioner{TSource}">Partitioner</see> is used to retrieve
- /// the elements to be processed, in place of the original data source. If the current element's
- /// index is desired, the source must be an <see cref="T:System.Collections.Concurrent.OrderablePartitioner">
- /// OrderablePartitioner</see>.
- /// </para>
- /// <para>
- /// The <paramref name="body"/> delegate is invoked once for each element in the <paramref name="source"/>
- /// Partitioner. It is provided with the current element as a parameter.
- /// </para>
- /// </remarks>
- public static ParallelLoopResult ForEach<TSource>(
- Partitioner<TSource> source,
- Action<TSource> body)
- {
- if (source == null)
- {
- throw new ArgumentNullException(nameof(source));
- }
- if (body == null)
- {
- throw new ArgumentNullException(nameof(body));
- }
-
- return PartitionerForEachWorker<TSource, object>(source, s_defaultParallelOptions, body, null, null, null, null, null, null);
- }
-
- /// <summary>
- /// Executes a for each operation on a <see cref="T:System.Collections.Concurrent.Partitioner{TSource}">
- /// Partitioner</see> in which iterations may run in parallel.
- /// </summary>
- /// <typeparam name="TSource">The type of the elements in <paramref name="source"/>.</typeparam>
- /// <param name="source">The Partitioner that contains the original data source.</param>
- /// <param name="body">The delegate that is invoked once per iteration.</param>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="source"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="body"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when the
- /// SupportsDynamicPartitions property in the <paramref name="source"/> Partitioner returns
- /// false.</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when any
- /// methods in the <paramref name="source"/> Partitioner return null.</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when the
- /// GetPartitions() method in the <paramref name="source"/> Partitioner does not return
- /// the correct number of partitions.</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when the
- /// GetPartitions() method in the <paramref name="source"/> Partitioner returns an IList
- /// with at least one null value.</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when the
- /// GetDynamicPartitions() method in the <paramref name="source"/> Partitioner returns an
- /// IEnumerable whose GetEnumerator() method returns null.</exception>
- /// <exception cref="T:System.AggregateException">The exception that is thrown to contain an exception
- /// thrown from one of the specified delegates.</exception>
- /// <returns>A <see cref="T:System.Threading.Tasks.ParallelLoopResult">ParallelLoopResult</see> structure
- /// that contains information on what portion of the loop completed.</returns>
- /// <remarks>
- /// <para>
- /// The <see cref="T:System.Collections.Concurrent.Partitioner{TSource}">Partitioner</see> is used to retrieve
- /// the elements to be processed, in place of the original data source. If the current element's
- /// index is desired, the source must be an <see cref="T:System.Collections.Concurrent.OrderablePartitioner">
- /// OrderablePartitioner</see>.
- /// </para>
- /// <para>
- /// The <paramref name="body"/> delegate is invoked once for each element in the <paramref name="source"/>
- /// Partitioner. It is provided with the following parameters: the current element,
- /// and a <see cref="System.Threading.Tasks.ParallelLoopState">ParallelLoopState</see> instance that may be
- /// used to break out of the loop prematurely.
- /// </para>
- /// </remarks>
- public static ParallelLoopResult ForEach<TSource>(
- Partitioner<TSource> source,
- Action<TSource, ParallelLoopState> body)
- {
- if (source == null)
- {
- throw new ArgumentNullException(nameof(source));
- }
- if (body == null)
- {
- throw new ArgumentNullException(nameof(body));
- }
-
- return PartitionerForEachWorker<TSource, object>(source, s_defaultParallelOptions, null, body, null, null, null, null, null);
- }
-
- /// <summary>
- /// Executes a for each operation on a <see cref="T:System.Collections.Concurrent.OrderablePartitioner{TSource}">
- /// OrderablePartitioner</see> in which iterations may run in parallel.
- /// </summary>
- /// <typeparam name="TSource">The type of the elements in <paramref name="source"/>.</typeparam>
- /// <param name="source">The OrderablePartitioner that contains the original data source.</param>
- /// <param name="body">The delegate that is invoked once per iteration.</param>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="source"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="body"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when the
- /// SupportsDynamicPartitions property in the <paramref name="source"/> OrderablePartitioner returns
- /// false.</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when the
- /// KeysNormalized property in the <paramref name="source"/> OrderablePartitioner returns
- /// false.</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when any
- /// methods in the <paramref name="source"/> OrderablePartitioner return null.</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when the
- /// GetPartitions() or GetOrderablePartitions() methods in the <paramref name="source"/>
- /// OrderablePartitioner do not return the correct number of partitions.</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when the
- /// GetPartitions() or GetOrderablePartitions() methods in the <paramref name="source"/>
- /// OrderablePartitioner return an IList with at least one null value.</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when the
- /// GetDynamicPartitions() or GetDynamicOrderablePartitions() methods in the <paramref name="source"/>
- /// OrderablePartitioner return an IEnumerable whose GetEnumerator() method returns null.</exception>
- /// <exception cref="T:System.AggregateException">The exception that is thrown to contain an exception
- /// thrown from one of the specified delegates.</exception>
- /// <returns>A <see cref="T:System.Threading.Tasks.ParallelLoopResult">ParallelLoopResult</see> structure
- /// that contains information on what portion of the loop completed.</returns>
- /// <remarks>
- /// <para>
- /// The <see cref="T:System.Collections.Concurrent.Partitioner{TSource}">Partitioner</see> is used to retrieve
- /// the elements to be processed, in place of the original data source. If the current element's
- /// index is desired, the source must be an <see cref="T:System.Collections.Concurrent.OrderablePartitioner">
- /// OrderablePartitioner</see>.
- /// </para>
- /// <para>
- /// The <paramref name="body"/> delegate is invoked once for each element in the <paramref name="source"/>
- /// Partitioner. It is provided with the following parameters: the current element,
- /// a <see cref="System.Threading.Tasks.ParallelLoopState">ParallelLoopState</see> instance that may be
- /// used to break out of the loop prematurely, and the current element's index (an Int64).
- /// </para>
- /// </remarks>
- public static ParallelLoopResult ForEach<TSource>(
- OrderablePartitioner<TSource> source,
- Action<TSource, ParallelLoopState, long> body)
- {
- if (source == null)
- {
- throw new ArgumentNullException(nameof(source));
- }
- if (body == null)
- {
- throw new ArgumentNullException(nameof(body));
- }
-
- if (!source.KeysNormalized)
- {
- throw new InvalidOperationException(Environment.GetResourceString("Parallel_ForEach_OrderedPartitionerKeysNotNormalized"));
- }
-
- return PartitionerForEachWorker<TSource, object>(source, s_defaultParallelOptions, null, null, body, null, null, null, null);
- }
-
- /// <summary>
- /// Executes a for each operation on a <see cref="T:System.Collections.Concurrent.Partitioner{TSource}">
- /// Partitioner</see> in which iterations may run in parallel.
- /// </summary>
- /// <typeparam name="TSource">The type of the elements in <paramref name="source"/>.</typeparam>
- /// <typeparam name="TLocal">The type of the thread-local data.</typeparam>
- /// <param name="source">The Partitioner that contains the original data source.</param>
- /// <param name="localInit">The function delegate that returns the initial state of the local data
- /// for each thread.</param>
- /// <param name="body">The delegate that is invoked once per iteration.</param>
- /// <param name="localFinally">The delegate that performs a final action on the local state of each
- /// thread.</param>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="source"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="body"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the
- /// <paramref name="localInit"/> argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the
- /// <paramref name="localFinally"/> argument is null.</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when the
- /// SupportsDynamicPartitions property in the <paramref name="source"/> Partitioner returns
- /// false.</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when any
- /// methods in the <paramref name="source"/> Partitioner return null.</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when the
- /// GetPartitions() method in the <paramref name="source"/> Partitioner does not return
- /// the correct number of partitions.</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when the
- /// GetPartitions() method in the <paramref name="source"/> Partitioner returns an IList
- /// with at least one null value.</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when the
- /// GetDynamicPartitions() method in the <paramref name="source"/> Partitioner returns an
- /// IEnumerable whose GetEnumerator() method returns null.</exception>
- /// <exception cref="T:System.AggregateException">The exception that is thrown to contain an exception
- /// thrown from one of the specified delegates.</exception>
- /// <returns>A <see cref="T:System.Threading.Tasks.ParallelLoopResult">ParallelLoopResult</see> structure
- /// that contains information on what portion of the loop completed.</returns>
- /// <remarks>
- /// <para>
- /// The <see cref="T:System.Collections.Concurrent.Partitioner{TSource}">Partitioner</see> is used to retrieve
- /// the elements to be processed, in place of the original data source. If the current element's
- /// index is desired, the source must be an <see cref="T:System.Collections.Concurrent.OrderablePartitioner">
- /// OrderablePartitioner</see>.
- /// </para>
- /// <para>
- /// The <paramref name="body"/> delegate is invoked once for each element in the <paramref name="source"/>
- /// Partitioner. It is provided with the following parameters: the current element,
- /// a <see cref="System.Threading.Tasks.ParallelLoopState">ParallelLoopState</see> instance that may be
- /// used to break out of the loop prematurely, and some local state that may be shared amongst iterations
- /// that execute on the same thread.
- /// </para>
- /// <para>
- /// The <paramref name="localInit"/> delegate is invoked once for each thread that participates in the loop's
- /// execution and returns the initial local state for each of those threads. These initial states are passed to the first
- /// <paramref name="body"/> invocations on each thread. Then, every subsequent body invocation returns a possibly
- /// modified state value that is passed to the next body invocation. Finally, the last body invocation on each thread returns a state value
- /// that is passed to the <paramref name="localFinally"/> delegate. The localFinally delegate is invoked once per thread to perform a final
- /// action on each thread's local state.
- /// </para>
- /// </remarks>
- public static ParallelLoopResult ForEach<TSource, TLocal>(
- Partitioner<TSource> source,
- Func<TLocal> localInit,
- Func<TSource, ParallelLoopState, TLocal, TLocal> body,
- Action<TLocal> localFinally)
- {
- if (source == null)
- {
- throw new ArgumentNullException(nameof(source));
- }
- if (body == null)
- {
- throw new ArgumentNullException(nameof(body));
- }
- if (localInit == null)
- {
- throw new ArgumentNullException(nameof(localInit));
- }
- if (localFinally == null)
- {
- throw new ArgumentNullException(nameof(localFinally));
- }
-
- return PartitionerForEachWorker<TSource, TLocal>(source, s_defaultParallelOptions, null, null, null, body, null, localInit, localFinally);
- }
-
- /// <summary>
- /// Executes a for each operation on a <see cref="T:System.Collections.Concurrent.OrderablePartitioner{TSource}">
- /// OrderablePartitioner</see> in which iterations may run in parallel.
- /// </summary>
- /// <typeparam name="TSource">The type of the elements in <paramref name="source"/>.</typeparam>
- /// <typeparam name="TLocal">The type of the thread-local data.</typeparam>
- /// <param name="source">The OrderablePartitioner that contains the original data source.</param>
- /// <param name="localInit">The function delegate that returns the initial state of the local data
- /// for each thread.</param>
- /// <param name="body">The delegate that is invoked once per iteration.</param>
- /// <param name="localFinally">The delegate that performs a final action on the local state of each
- /// thread.</param>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="source"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="body"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the
- /// <paramref name="localInit"/> argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the
- /// <paramref name="localFinally"/> argument is null.</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when the
- /// SupportsDynamicPartitions property in the <paramref name="source"/> OrderablePartitioner returns
- /// false.</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when the
- /// KeysNormalized property in the <paramref name="source"/> OrderablePartitioner returns
- /// false.</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when any
- /// methods in the <paramref name="source"/> OrderablePartitioner return null.</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when the
- /// GetPartitions() or GetOrderablePartitions() methods in the <paramref name="source"/>
- /// OrderablePartitioner do not return the correct number of partitions.</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when the
- /// GetPartitions() or GetOrderablePartitions() methods in the <paramref name="source"/>
- /// OrderablePartitioner return an IList with at least one null value.</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when the
- /// GetDynamicPartitions() or GetDynamicOrderablePartitions() methods in the <paramref name="source"/>
- /// OrderablePartitioner return an IEnumerable whose GetEnumerator() method returns null.</exception>
- /// <exception cref="T:System.AggregateException">The exception that is thrown to contain an exception
- /// thrown from one of the specified delegates.</exception>
- /// <returns>A <see cref="T:System.Threading.Tasks.ParallelLoopResult">ParallelLoopResult</see> structure
- /// that contains information on what portion of the loop completed.</returns>
- /// <remarks>
- /// <para>
- /// The <see cref="T:System.Collections.Concurrent.Partitioner{TSource}">Partitioner</see> is used to retrieve
- /// the elements to be processed, in place of the original data source. If the current element's
- /// index is desired, the source must be an <see cref="T:System.Collections.Concurrent.OrderablePartitioner">
- /// OrderablePartitioner</see>.
- /// </para>
- /// <para>
- /// The <paramref name="body"/> delegate is invoked once for each element in the <paramref name="source"/>
- /// Partitioner. It is provided with the following parameters: the current element,
- /// a <see cref="System.Threading.Tasks.ParallelLoopState">ParallelLoopState</see> instance that may be
- /// used to break out of the loop prematurely, the current element's index (an Int64), and some local
- /// state that may be shared amongst iterations that execute on the same thread.
- /// </para>
- /// <para>
- /// The <paramref name="localInit"/> delegate is invoked once for each thread that participates in the loop's
- /// execution and returns the initial local state for each of those threads. These initial states are passed to the first
- /// <paramref name="body"/> invocations on each thread. Then, every subsequent body invocation returns a possibly
- /// modified state value that is passed to the next body invocation. Finally, the last body invocation on each thread returns a state value
- /// that is passed to the <paramref name="localFinally"/> delegate. The localFinally delegate is invoked once per thread to perform a final
- /// action on each thread's local state.
- /// </para>
- /// </remarks>
- public static ParallelLoopResult ForEach<TSource, TLocal>(
- OrderablePartitioner<TSource> source,
- Func<TLocal> localInit,
- Func<TSource, ParallelLoopState, long, TLocal, TLocal> body,
- Action<TLocal> localFinally)
- {
- if (source == null)
- {
- throw new ArgumentNullException(nameof(source));
- }
- if (body == null)
- {
- throw new ArgumentNullException(nameof(body));
- }
- if (localInit == null)
- {
- throw new ArgumentNullException(nameof(localInit));
- }
- if (localFinally == null)
- {
- throw new ArgumentNullException(nameof(localFinally));
- }
-
- if (!source.KeysNormalized)
- {
- throw new InvalidOperationException(Environment.GetResourceString("Parallel_ForEach_OrderedPartitionerKeysNotNormalized"));
- }
-
- return PartitionerForEachWorker<TSource, TLocal>(source, s_defaultParallelOptions, null, null, null, null, body, localInit, localFinally);
- }
-
- /// <summary>
- /// Executes a for each operation on a <see cref="T:System.Collections.Concurrent.Partitioner{TSource}">
- /// Partitioner</see> in which iterations may run in parallel.
- /// </summary>
- /// <typeparam name="TSource">The type of the elements in <paramref name="source"/>.</typeparam>
- /// <param name="source">The Partitioner that contains the original data source.</param>
- /// <param name="parallelOptions">A <see cref="T:System.Threading.Tasks.ParallelOptions">ParallelOptions</see>
- /// instance that configures the behavior of this operation.</param>
- /// <param name="body">The delegate that is invoked once per iteration.</param>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="source"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the
- /// <paramref name="parallelOptions"/> argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="body"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.OperationCanceledException">The exception that is thrown when the
- /// <see cref="T:System.Threading.CancellationToken">CancellationToken</see> in the <paramref name="parallelOptions"/>
- /// argument is set</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when the
- /// SupportsDynamicPartitions property in the <paramref name="source"/> Partitioner returns
- /// false.</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when any
- /// methods in the <paramref name="source"/> Partitioner return null.</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when the
- /// GetPartitions() method in the <paramref name="source"/> Partitioner does not return
- /// the correct number of partitions.</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when the
- /// GetPartitions() method in the <paramref name="source"/> Partitioner returns an IList
- /// with at least one null value.</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when the
- /// GetDynamicPartitions() method in the <paramref name="source"/> Partitioner returns an
- /// IEnumerable whose GetEnumerator() method returns null.</exception>
- /// <exception cref="T:System.AggregateException">The exception that is thrown to contain an exception
- /// thrown from one of the specified delegates.</exception>
- /// <exception cref="T:System.ObjectDisposedException">The exception that is thrown when the
- /// the <see cref="T:System.Threading.CancellationTokenSource">CancellationTokenSource</see> associated with the
- /// the <see cref="T:System.Threading.CancellationToken">CancellationToken</see> in the
- /// <paramref name="parallelOptions"/> has been disposed.</exception>
- /// <returns>A <see cref="T:System.Threading.Tasks.ParallelLoopResult">ParallelLoopResult</see> structure
- /// that contains information on what portion of the loop completed.</returns>
- /// <remarks>
- /// <para>
- /// The <see cref="T:System.Collections.Concurrent.Partitioner{TSource}">Partitioner</see> is used to retrieve
- /// the elements to be processed, in place of the original data source. If the current element's
- /// index is desired, the source must be an <see cref="T:System.Collections.Concurrent.OrderablePartitioner">
- /// OrderablePartitioner</see>.
- /// </para>
- /// <para>
- /// The <paramref name="body"/> delegate is invoked once for each element in the <paramref name="source"/>
- /// Partitioner. It is provided with the current element as a parameter.
- /// </para>
- /// </remarks>
- public static ParallelLoopResult ForEach<TSource>(
- Partitioner<TSource> source,
- ParallelOptions parallelOptions,
- Action<TSource> body)
- {
- if (source == null)
- {
- throw new ArgumentNullException(nameof(source));
- }
- if (body == null)
- {
- throw new ArgumentNullException(nameof(body));
- }
- if (parallelOptions == null)
- {
- throw new ArgumentNullException(nameof(parallelOptions));
- }
-
- return PartitionerForEachWorker<TSource, object>(source, parallelOptions, body, null, null, null, null, null, null);
- }
-
- /// <summary>
- /// Executes a for each operation on a <see cref="T:System.Collections.Concurrent.Partitioner{TSource}">
- /// Partitioner</see> in which iterations may run in parallel.
- /// </summary>
- /// <typeparam name="TSource">The type of the elements in <paramref name="source"/>.</typeparam>
- /// <param name="source">The Partitioner that contains the original data source.</param>
- /// <param name="parallelOptions">A <see cref="T:System.Threading.Tasks.ParallelOptions">ParallelOptions</see>
- /// instance that configures the behavior of this operation.</param>
- /// <param name="body">The delegate that is invoked once per iteration.</param>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="source"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the
- /// <paramref name="parallelOptions"/> argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="body"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.OperationCanceledException">The exception that is thrown when the
- /// <see cref="T:System.Threading.CancellationToken">CancellationToken</see> in the <paramref name="parallelOptions"/>
- /// argument is set</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when the
- /// SupportsDynamicPartitions property in the <paramref name="source"/> Partitioner returns
- /// false.</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when any
- /// methods in the <paramref name="source"/> Partitioner return null.</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when the
- /// GetPartitions() method in the <paramref name="source"/> Partitioner does not return
- /// the correct number of partitions.</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when the
- /// GetPartitions() method in the <paramref name="source"/> Partitioner returns an IList
- /// with at least one null value.</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when the
- /// GetDynamicPartitions() method in the <paramref name="source"/> Partitioner returns an
- /// IEnumerable whose GetEnumerator() method returns null.</exception>
- /// <exception cref="T:System.AggregateException">The exception that is thrown to contain an exception
- /// thrown from one of the specified delegates.</exception>
- /// <exception cref="T:System.ObjectDisposedException">The exception that is thrown when the
- /// the <see cref="T:System.Threading.CancellationTokenSource">CancellationTokenSource</see> associated with the
- /// the <see cref="T:System.Threading.CancellationToken">CancellationToken</see> in the
- /// <paramref name="parallelOptions"/> has been disposed.</exception>
- /// <returns>A <see cref="T:System.Threading.Tasks.ParallelLoopResult">ParallelLoopResult</see> structure
- /// that contains information on what portion of the loop completed.</returns>
- /// <remarks>
- /// <para>
- /// The <see cref="T:System.Collections.Concurrent.Partitioner{TSource}">Partitioner</see> is used to retrieve
- /// the elements to be processed, in place of the original data source. If the current element's
- /// index is desired, the source must be an <see cref="T:System.Collections.Concurrent.OrderablePartitioner">
- /// OrderablePartitioner</see>.
- /// </para>
- /// <para>
- /// The <paramref name="body"/> delegate is invoked once for each element in the <paramref name="source"/>
- /// Partitioner. It is provided with the following parameters: the current element,
- /// and a <see cref="System.Threading.Tasks.ParallelLoopState">ParallelLoopState</see> instance that may be
- /// used to break out of the loop prematurely.
- /// </para>
- /// </remarks>
- public static ParallelLoopResult ForEach<TSource>(
- Partitioner<TSource> source,
- ParallelOptions parallelOptions,
- Action<TSource, ParallelLoopState> body)
- {
- if (source == null)
- {
- throw new ArgumentNullException(nameof(source));
- }
- if (body == null)
- {
- throw new ArgumentNullException(nameof(body));
- }
- if (parallelOptions == null)
- {
- throw new ArgumentNullException(nameof(parallelOptions));
- }
-
- return PartitionerForEachWorker<TSource, object>(source, parallelOptions, null, body, null, null, null, null, null);
- }
-
- /// <summary>
- /// Executes a for each operation on a <see cref="T:System.Collections.Concurrent.OrderablePartitioner{TSource}">
- /// OrderablePartitioner</see> in which iterations may run in parallel.
- /// </summary>
- /// <typeparam name="TSource">The type of the elements in <paramref name="source"/>.</typeparam>
- /// <param name="source">The OrderablePartitioner that contains the original data source.</param>
- /// <param name="parallelOptions">A <see cref="T:System.Threading.Tasks.ParallelOptions">ParallelOptions</see>
- /// instance that configures the behavior of this operation.</param>
- /// <param name="body">The delegate that is invoked once per iteration.</param>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="source"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the
- /// <paramref name="parallelOptions"/> argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="body"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.OperationCanceledException">The exception that is thrown when the
- /// <see cref="T:System.Threading.CancellationToken">CancellationToken</see> in the <paramref name="parallelOptions"/>
- /// argument is set</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when the
- /// SupportsDynamicPartitions property in the <paramref name="source"/> OrderablePartitioner returns
- /// false.</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when the
- /// KeysNormalized property in the <paramref name="source"/> OrderablePartitioner returns
- /// false.</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when any
- /// methods in the <paramref name="source"/> OrderablePartitioner return null.</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when the
- /// GetPartitions() or GetOrderablePartitions() methods in the <paramref name="source"/>
- /// OrderablePartitioner do not return the correct number of partitions.</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when the
- /// GetPartitions() or GetOrderablePartitions() methods in the <paramref name="source"/>
- /// OrderablePartitioner return an IList with at least one null value.</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when the
- /// GetDynamicPartitions() or GetDynamicOrderablePartitions() methods in the <paramref name="source"/>
- /// OrderablePartitioner return an IEnumerable whose GetEnumerator() method returns null.</exception>
- /// <exception cref="T:System.AggregateException">The exception that is thrown to contain an exception
- /// thrown from one of the specified delegates.</exception>
- /// <exception cref="T:System.ObjectDisposedException">The exception that is thrown when the
- /// the <see cref="T:System.Threading.CancellationTokenSource">CancellationTokenSource</see> associated with the
- /// the <see cref="T:System.Threading.CancellationToken">CancellationToken</see> in the
- /// <paramref name="parallelOptions"/> has been disposed.</exception>
- /// <returns>A <see cref="T:System.Threading.Tasks.ParallelLoopResult">ParallelLoopResult</see> structure
- /// that contains information on what portion of the loop completed.</returns>
- /// <remarks>
- /// <para>
- /// The <see cref="T:System.Collections.Concurrent.Partitioner{TSource}">Partitioner</see> is used to retrieve
- /// the elements to be processed, in place of the original data source. If the current element's
- /// index is desired, the source must be an <see cref="T:System.Collections.Concurrent.OrderablePartitioner">
- /// OrderablePartitioner</see>.
- /// </para>
- /// <para>
- /// The <paramref name="body"/> delegate is invoked once for each element in the <paramref name="source"/>
- /// Partitioner. It is provided with the following parameters: the current element,
- /// a <see cref="System.Threading.Tasks.ParallelLoopState">ParallelLoopState</see> instance that may be
- /// used to break out of the loop prematurely, and the current element's index (an Int64).
- /// </para>
- /// </remarks>
- public static ParallelLoopResult ForEach<TSource>(
- OrderablePartitioner<TSource> source,
- ParallelOptions parallelOptions,
- Action<TSource, ParallelLoopState, long> body)
- {
- if (source == null)
- {
- throw new ArgumentNullException(nameof(source));
- }
- if (body == null)
- {
- throw new ArgumentNullException(nameof(body));
- }
- if (parallelOptions == null)
- {
- throw new ArgumentNullException(nameof(parallelOptions));
- }
-
- if (!source.KeysNormalized)
- {
- throw new InvalidOperationException(Environment.GetResourceString("Parallel_ForEach_OrderedPartitionerKeysNotNormalized"));
- }
-
- return PartitionerForEachWorker<TSource, object>(source, parallelOptions, null, null, body, null, null, null, null);
- }
-
- /// <summary>
- /// Executes a for each operation on a <see cref="T:System.Collections.Concurrent.Partitioner{TSource}">
- /// Partitioner</see> in which iterations may run in parallel.
- /// </summary>
- /// <typeparam name="TSource">The type of the elements in <paramref name="source"/>.</typeparam>
- /// <typeparam name="TLocal">The type of the thread-local data.</typeparam>
- /// <param name="source">The Partitioner that contains the original data source.</param>
- /// <param name="parallelOptions">A <see cref="T:System.Threading.Tasks.ParallelOptions">ParallelOptions</see>
- /// instance that configures the behavior of this operation.</param>
- /// <param name="localInit">The function delegate that returns the initial state of the local data
- /// for each thread.</param>
- /// <param name="body">The delegate that is invoked once per iteration.</param>
- /// <param name="localFinally">The delegate that performs a final action on the local state of each
- /// thread.</param>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="source"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the
- /// <paramref name="parallelOptions"/> argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="body"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the
- /// <paramref name="localInit"/> argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the
- /// <paramref name="localFinally"/> argument is null.</exception>
- /// <exception cref="T:System.OperationCanceledException">The exception that is thrown when the
- /// <see cref="T:System.Threading.CancellationToken">CancellationToken</see> in the <paramref name="parallelOptions"/>
- /// argument is set</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when the
- /// SupportsDynamicPartitions property in the <paramref name="source"/> Partitioner returns
- /// false.</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when any
- /// methods in the <paramref name="source"/> Partitioner return null.</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when the
- /// GetPartitions() method in the <paramref name="source"/> Partitioner does not return
- /// the correct number of partitions.</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when the
- /// GetPartitions() method in the <paramref name="source"/> Partitioner returns an IList
- /// with at least one null value.</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when the
- /// GetDynamicPartitions() method in the <paramref name="source"/> Partitioner returns an
- /// IEnumerable whose GetEnumerator() method returns null.</exception>
- /// <exception cref="T:System.AggregateException">The exception that is thrown to contain an exception
- /// thrown from one of the specified delegates.</exception>
- /// <exception cref="T:System.ObjectDisposedException">The exception that is thrown when the
- /// the <see cref="T:System.Threading.CancellationTokenSource">CancellationTokenSource</see> associated with the
- /// the <see cref="T:System.Threading.CancellationToken">CancellationToken</see> in the
- /// <paramref name="parallelOptions"/> has been disposed.</exception>
- /// <returns>A <see cref="T:System.Threading.Tasks.ParallelLoopResult">ParallelLoopResult</see> structure
- /// that contains information on what portion of the loop completed.</returns>
- /// <remarks>
- /// <para>
- /// The <see cref="T:System.Collections.Concurrent.Partitioner{TSource}">Partitioner</see> is used to retrieve
- /// the elements to be processed, in place of the original data source. If the current element's
- /// index is desired, the source must be an <see cref="T:System.Collections.Concurrent.OrderablePartitioner">
- /// OrderablePartitioner</see>.
- /// </para>
- /// <para>
- /// The <paramref name="body"/> delegate is invoked once for each element in the <paramref name="source"/>
- /// Partitioner. It is provided with the following parameters: the current element,
- /// a <see cref="System.Threading.Tasks.ParallelLoopState">ParallelLoopState</see> instance that may be
- /// used to break out of the loop prematurely, and some local state that may be shared amongst iterations
- /// that execute on the same thread.
- /// </para>
- /// <para>
- /// The <paramref name="localInit"/> delegate is invoked once for each thread that participates in the loop's
- /// execution and returns the initial local state for each of those threads. These initial states are passed to the first
- /// <paramref name="body"/> invocations on each thread. Then, every subsequent body invocation returns a possibly
- /// modified state value that is passed to the next body invocation. Finally, the last body invocation on each thread returns a state value
- /// that is passed to the <paramref name="localFinally"/> delegate. The localFinally delegate is invoked once per thread to perform a final
- /// action on each thread's local state.
- /// </para>
- /// </remarks>
- public static ParallelLoopResult ForEach<TSource, TLocal>(
- Partitioner<TSource> source,
- ParallelOptions parallelOptions,
- Func<TLocal> localInit,
- Func<TSource, ParallelLoopState, TLocal, TLocal> body,
- Action<TLocal> localFinally)
- {
- if (source == null)
- {
- throw new ArgumentNullException(nameof(source));
- }
- if (body == null)
- {
- throw new ArgumentNullException(nameof(body));
- }
- if (localInit == null)
- {
- throw new ArgumentNullException(nameof(localInit));
- }
- if (localFinally == null)
- {
- throw new ArgumentNullException(nameof(localFinally));
- }
- if (parallelOptions == null)
- {
- throw new ArgumentNullException(nameof(parallelOptions));
- }
-
- return PartitionerForEachWorker<TSource, TLocal>(source, parallelOptions, null, null, null, body, null, localInit, localFinally);
- }
-
- /// <summary>
- /// Executes a for each operation on a <see cref="T:System.Collections.Concurrent.OrderablePartitioner{TSource}">
- /// OrderablePartitioner</see> in which iterations may run in parallel.
- /// </summary>
- /// <typeparam name="TSource">The type of the elements in <paramref name="source"/>.</typeparam>
- /// <typeparam name="TLocal">The type of the thread-local data.</typeparam>
- /// <param name="source">The OrderablePartitioner that contains the original data source.</param>
- /// <param name="parallelOptions">A <see cref="T:System.Threading.Tasks.ParallelOptions">ParallelOptions</see>
- /// instance that configures the behavior of this operation.</param>
- /// <param name="localInit">The function delegate that returns the initial state of the local data
- /// for each thread.</param>
- /// <param name="body">The delegate that is invoked once per iteration.</param>
- /// <param name="localFinally">The delegate that performs a final action on the local state of each
- /// thread.</param>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="source"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the
- /// <paramref name="parallelOptions"/> argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the <paramref name="body"/>
- /// argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the
- /// <paramref name="localInit"/> argument is null.</exception>
- /// <exception cref="T:System.ArgumentNullException">The exception that is thrown when the
- /// <paramref name="localFinally"/> argument is null.</exception>
- /// <exception cref="T:System.OperationCanceledException">The exception that is thrown when the
- /// <see cref="T:System.Threading.CancellationToken">CancellationToken</see> in the <paramref name="parallelOptions"/>
- /// argument is set</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when the
- /// SupportsDynamicPartitions property in the <paramref name="source"/> OrderablePartitioner returns
- /// false.</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when the
- /// KeysNormalized property in the <paramref name="source"/> OrderablePartitioner returns
- /// false.</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when any
- /// methods in the <paramref name="source"/> OrderablePartitioner return null.</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when the
- /// GetPartitions() or GetOrderablePartitions() methods in the <paramref name="source"/>
- /// OrderablePartitioner do not return the correct number of partitions.</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when the
- /// GetPartitions() or GetOrderablePartitions() methods in the <paramref name="source"/>
- /// OrderablePartitioner return an IList with at least one null value.</exception>
- /// <exception cref="T:System.InvalidOperationException">The exception that is thrown when the
- /// GetDynamicPartitions() or GetDynamicOrderablePartitions() methods in the <paramref name="source"/>
- /// OrderablePartitioner return an IEnumerable whose GetEnumerator() method returns null.</exception>
- /// <exception cref="T:System.AggregateException">The exception that is thrown to contain an exception
- /// thrown from one of the specified delegates.</exception>
- /// <exception cref="T:System.ObjectDisposedException">The exception that is thrown when the
- /// the <see cref="T:System.Threading.CancellationTokenSource">CancellationTokenSource</see> associated with the
- /// the <see cref="T:System.Threading.CancellationToken">CancellationToken</see> in the
- /// <paramref name="parallelOptions"/> has been disposed.</exception>
- /// <returns>A <see cref="T:System.Threading.Tasks.ParallelLoopResult">ParallelLoopResult</see> structure
- /// that contains information on what portion of the loop completed.</returns>
- /// <remarks>
- /// <para>
- /// The <see cref="T:System.Collections.Concurrent.Partitioner{TSource}">Partitioner</see> is used to retrieve
- /// the elements to be processed, in place of the original data source. If the current element's
- /// index is desired, the source must be an <see cref="T:System.Collections.Concurrent.OrderablePartitioner">
- /// OrderablePartitioner</see>.
- /// </para>
- /// <para>
- /// The <paramref name="body"/> delegate is invoked once for each element in the <paramref name="source"/>
- /// Partitioner. It is provided with the following parameters: the current element,
- /// a <see cref="System.Threading.Tasks.ParallelLoopState">ParallelLoopState</see> instance that may be
- /// used to break out of the loop prematurely, the current element's index (an Int64), and some local
- /// state that may be shared amongst iterations that execute on the same thread.
- /// </para>
- /// <para>
- /// The <paramref name="localInit"/> delegate is invoked once for each thread that participates in the loop's
- /// execution and returns the initial local state for each of those threads. These initial states are passed to the first
- /// <paramref name="body"/> invocations on each thread. Then, every subsequent body invocation returns a possibly
- /// modified state value that is passed to the next body invocation. Finally, the last body invocation on each thread returns a state value
- /// that is passed to the <paramref name="localFinally"/> delegate. The localFinally delegate is invoked once per thread to perform a final
- /// action on each thread's local state.
- /// </para>
- /// </remarks>
- public static ParallelLoopResult ForEach<TSource, TLocal>(
- OrderablePartitioner<TSource> source,
- ParallelOptions parallelOptions,
- Func<TLocal> localInit,
- Func<TSource, ParallelLoopState, long, TLocal, TLocal> body,
- Action<TLocal> localFinally)
- {
- if (source == null)
- {
- throw new ArgumentNullException(nameof(source));
- }
- if (body == null)
- {
- throw new ArgumentNullException(nameof(body));
- }
- if (localInit == null)
- {
- throw new ArgumentNullException(nameof(localInit));
- }
- if (localFinally == null)
- {
- throw new ArgumentNullException(nameof(localFinally));
- }
- if (parallelOptions == null)
- {
- throw new ArgumentNullException(nameof(parallelOptions));
- }
-
- if (!source.KeysNormalized)
- {
- throw new InvalidOperationException(Environment.GetResourceString("Parallel_ForEach_OrderedPartitionerKeysNotNormalized"));
- }
-
- return PartitionerForEachWorker<TSource, TLocal>(source, parallelOptions, null, null, null, null, body, localInit, localFinally);
- }
-
- // Main worker method for Parallel.ForEach() calls w/ Partitioners.
- private static ParallelLoopResult PartitionerForEachWorker<TSource, TLocal>(
- Partitioner<TSource> source, // Might be OrderablePartitioner
- ParallelOptions parallelOptions,
- Action<TSource> simpleBody,
- Action<TSource, ParallelLoopState> bodyWithState,
- Action<TSource, ParallelLoopState, long> bodyWithStateAndIndex,
- Func<TSource, ParallelLoopState, TLocal, TLocal> bodyWithStateAndLocal,
- Func<TSource, ParallelLoopState, long, TLocal, TLocal> bodyWithEverything,
- Func<TLocal> localInit,
- Action<TLocal> localFinally)
- {
- Debug.Assert(((simpleBody == null ? 0 : 1) + (bodyWithState == null ? 0 : 1) +
- (bodyWithStateAndIndex == null ? 0 : 1) + (bodyWithStateAndLocal == null ? 0 : 1) + (bodyWithEverything == null ? 0 : 1)) == 1,
- "PartitionForEach: expected exactly one body function to be supplied");
- Debug.Assert((bodyWithStateAndLocal != null) || (bodyWithEverything != null) || (localInit == null && localFinally == null),
- "PartitionForEach: thread local functions should only be supplied for loops w/ thread local bodies");
-
- OrderablePartitioner<TSource> orderedSource = source as OrderablePartitioner<TSource>;
- Debug.Assert((orderedSource != null) || (bodyWithStateAndIndex == null && bodyWithEverything == null),
- "PartitionForEach: bodies with indices are only allowable for OrderablePartitioner");
-
- if (!source.SupportsDynamicPartitions)
- {
- throw new InvalidOperationException(Environment.GetResourceString("Parallel_ForEach_PartitionerNotDynamic"));
- }
-
- // Before getting started, do a quick peek to see if we have been canceled already
- if (parallelOptions.CancellationToken.IsCancellationRequested)
- {
- throw new OperationCanceledException(parallelOptions.CancellationToken);
- }
-
- // ETW event for Parallel For begin
- int forkJoinContextID = 0;
- Task callerTask = null;
- if (TplEtwProvider.Log.IsEnabled())
- {
- forkJoinContextID = Interlocked.Increment(ref s_forkJoinContextID);
- callerTask = Task.InternalCurrent;
- TplEtwProvider.Log.ParallelLoopBegin((callerTask != null ? callerTask.m_taskScheduler.Id : TaskScheduler.Current.Id), (callerTask != null ? callerTask.Id : 0),
- forkJoinContextID, TplEtwProvider.ForkJoinOperationType.ParallelForEach,
- 0, 0);
- }
-
- // For all loops we need a shared flag even though we don't have a body with state,
- // because the shared flag contains the exceptional bool, which triggers other workers
- // to exit their loops if one worker catches an exception
- ParallelLoopStateFlags64 sharedPStateFlags = new ParallelLoopStateFlags64();
-
- // Instantiate our result. Specifics will be filled in later.
- ParallelLoopResult result = new ParallelLoopResult();
-
- // Keep track of any cancellations
- OperationCanceledException oce = null;
-
- CancellationTokenRegistration ctr = new CancellationTokenRegistration();
-
- // if cancellation is enabled, we need to register a callback to stop the loop when it gets signaled
- if (parallelOptions.CancellationToken.CanBeCanceled)
- {
- ctr = parallelOptions.CancellationToken.InternalRegisterWithoutEC((o) =>
- {
- // Cause processing to stop
- sharedPStateFlags.Cancel();
- // Record our cancellation
- oce = new OperationCanceledException(parallelOptions.CancellationToken);
- }, null);
- }
-
- // Get our dynamic partitioner -- depends on whether source is castable to OrderablePartitioner
- // Also, do some error checking.
- IEnumerable<TSource> partitionerSource = null;
- IEnumerable<KeyValuePair<long, TSource>> orderablePartitionerSource = null;
- if (orderedSource != null)
- {
- orderablePartitionerSource = orderedSource.GetOrderableDynamicPartitions();
- if (orderablePartitionerSource == null)
- {
- throw new InvalidOperationException(Environment.GetResourceString("Parallel_ForEach_PartitionerReturnedNull"));
- }
- }
- else
- {
- partitionerSource = source.GetDynamicPartitions();
- if (partitionerSource == null)
- {
- throw new InvalidOperationException(Environment.GetResourceString("Parallel_ForEach_PartitionerReturnedNull"));
- }
- }
-
- ParallelForReplicatingTask rootTask = null;
-
- // This is the action that will be run by each replicable task.
- Action partitionAction = delegate
- {
- Task currentWorkerTask = Task.InternalCurrent;
-
- // ETW event for ParallelForEach Worker Fork
- if (TplEtwProvider.Log.IsEnabled())
- {
- TplEtwProvider.Log.ParallelFork((currentWorkerTask != null ? currentWorkerTask.m_taskScheduler.Id : TaskScheduler.Current.Id), (currentWorkerTask != null ? currentWorkerTask.Id : 0),
- forkJoinContextID);
- }
-
- TLocal localValue = default(TLocal);
- bool bLocalValueInitialized = false; // Tracks whether localInit ran without exceptions, so that we can skip localFinally if it wasn't
- IDisposable myPartitionToDispose = null;
-
- try
- {
- // Create a new state object that references the shared "stopped" and "exceptional" flags.
- // If needed, it will contain a new instance of thread-local state by invoking the selector.
- ParallelLoopState64 state = null;
-
- if (bodyWithState != null || bodyWithStateAndIndex != null)
- {
- state = new ParallelLoopState64(sharedPStateFlags);
- }
- else if (bodyWithStateAndLocal != null || bodyWithEverything != null)
- {
- state = new ParallelLoopState64(sharedPStateFlags);
- // If a thread-local selector was supplied, invoke it. Otherwise, stick with the default.
- if (localInit != null)
- {
- localValue = localInit();
- bLocalValueInitialized = true;
- }
- }
-
-
- bool bIsRootTask = (rootTask == currentWorkerTask);
-
- // initialize a loop timer which will help us decide whether we should exit early
- LoopTimer loopTimer = new LoopTimer(rootTask.ActiveChildCount);
-
- if (orderedSource != null)
- {
- // Use this path for OrderablePartitioner
-
-
- // first check if there's saved state from a previous replica that we might be replacing.
- // the only state to be passed down in such a transition is the enumerator
- IEnumerator<KeyValuePair<long, TSource>> myPartition = currentWorkerTask.SavedStateFromPreviousReplica as IEnumerator<KeyValuePair<long, TSource>>;
- if (myPartition == null)
- {
- // apparently we're a brand new replica, get a fresh enumerator from the partitioner
- myPartition = orderablePartitionerSource.GetEnumerator();
- if (myPartition == null)
- {
- throw new InvalidOperationException(Environment.GetResourceString("Parallel_ForEach_NullEnumerator"));
- }
- }
- myPartitionToDispose = myPartition;
-
- while (myPartition.MoveNext())
- {
- KeyValuePair<long, TSource> kvp = myPartition.Current;
- long index = kvp.Key;
- TSource value = kvp.Value;
-
- // Update our iteration index
- if (state != null) state.CurrentIteration = index;
-
- if (simpleBody != null)
- simpleBody(value);
- else if (bodyWithState != null)
- bodyWithState(value, state);
- else if (bodyWithStateAndIndex != null)
- bodyWithStateAndIndex(value, state, index);
- else if (bodyWithStateAndLocal != null)
- localValue = bodyWithStateAndLocal(value, state, localValue);
- else
- localValue = bodyWithEverything(value, state, index, localValue);
-
- if (sharedPStateFlags.ShouldExitLoop(index)) break;
-
- // Cooperative multitasking workaround for AppDomain fairness.
- // Check if allowed loop time is exceeded, if so save current state and return. The self replicating task logic
- // will detect this, and queue up a replacement task. Note that we don't do this on the root task.
- if (!bIsRootTask && loopTimer.LimitExceeded())
- {
- currentWorkerTask.SavedStateForNextReplica = myPartition;
- myPartitionToDispose = null;
- break;
- }
- }
-
- }
- else
- {
- // Use this path for Partitioner that is not OrderablePartitioner
-
- // first check if there's saved state from a previous replica that we might be replacing.
- // the only state to be passed down in such a transition is the enumerator
- IEnumerator<TSource> myPartition = currentWorkerTask.SavedStateFromPreviousReplica as IEnumerator<TSource>;
- if (myPartition == null)
- {
- // apparently we're a brand new replica, get a fresh enumerator from the partitioner
- myPartition = partitionerSource.GetEnumerator();
- if (myPartition == null)
- {
- throw new InvalidOperationException(Environment.GetResourceString("Parallel_ForEach_NullEnumerator"));
- }
- }
- myPartitionToDispose = myPartition;
-
- // I'm not going to try to maintain this
- if (state != null)
- state.CurrentIteration = 0;
-
- while (myPartition.MoveNext())
- {
- TSource t = myPartition.Current;
-
- if (simpleBody != null)
- simpleBody(t);
- else if (bodyWithState != null)
- bodyWithState(t, state);
- else if (bodyWithStateAndLocal != null)
- localValue = bodyWithStateAndLocal(t, state, localValue);
- else
- Debug.Assert(false, "PartitionerForEach: illegal body type in Partitioner handler");
-
-
- // Any break, stop or exception causes us to halt
- // We don't have the global indexing information to discriminate whether or not
- // we are before or after a break point.
- if (sharedPStateFlags.LoopStateFlags != ParallelLoopStateFlags.PLS_NONE)
- break;
-
- // Cooperative multitasking workaround for AppDomain fairness.
- // Check if allowed loop time is exceeded, if so save current state and return. The self replicating task logic
- // will detect this, and queue up a replacement task. Note that we don't do this on the root task.
- if (!bIsRootTask && loopTimer.LimitExceeded())
- {
- currentWorkerTask.SavedStateForNextReplica = myPartition;
- myPartitionToDispose = null;
- break;
- }
- }
- }
- }
- catch
- {
- // Inform other tasks of the exception, then rethrow
- sharedPStateFlags.SetExceptional();
- throw;
- }
- finally
- {
- if (localFinally != null && bLocalValueInitialized)
- {
- localFinally(localValue);
- }
-
- if (myPartitionToDispose != null)
- {
- myPartitionToDispose.Dispose();
- }
-
- // ETW event for ParallelFor Worker Join
- if (TplEtwProvider.Log.IsEnabled())
- {
- TplEtwProvider.Log.ParallelJoin((currentWorkerTask != null ? currentWorkerTask.m_taskScheduler.Id : TaskScheduler.Current.Id), (currentWorkerTask != null ? currentWorkerTask.Id : 0),
- forkJoinContextID);
- }
- }
- };
-
- try
- {
- // Create and start the self-replicating task.
- // This needs to be in try-block because it can throw in BuggyScheduler.MaxConcurrencyLevel
- rootTask = new ParallelForReplicatingTask(parallelOptions, partitionAction, TaskCreationOptions.None,
- InternalTaskOptions.SelfReplicating);
-
- // And process it's completion...
- // Moved inside try{} block because faulty scheduler may throw here.
- rootTask.RunSynchronously(parallelOptions.EffectiveTaskScheduler);
-
- rootTask.Wait();
-
- // If we made a cancellation registration, we need to clean it up now before observing the OCE
- // Otherwise we could be caught in the middle of a callback, and observe PLS_STOPPED, but oce = null
- if (parallelOptions.CancellationToken.CanBeCanceled)
- {
- ctr.Dispose();
- }
-
- // If we got through that with no exceptions, and we were canceled, then
- // throw our cancellation exception
- if (oce != null) throw oce;
- }
- catch (AggregateException aggExp)
- {
- // if we made a cancellation registration, and rootTask.Wait threw, we need to clean it up here
- if (parallelOptions.CancellationToken.CanBeCanceled)
- {
- ctr.Dispose();
- }
-
- // see if we can combine it into a single OCE. If not propagate the original exception
- ThrowIfReducableToSingleOCE(aggExp.InnerExceptions, parallelOptions.CancellationToken);
- throw;
- }
- catch (TaskSchedulerException)
- {
- // if we made a cancellation registration, and either we threw an exception constructing rootTask or
- // rootTask.RunSynchronously threw, we need to clean it up here.
- if (parallelOptions.CancellationToken.CanBeCanceled)
- {
- ctr.Dispose();
- }
- throw;
- }
- finally
- {
- int sb_status = sharedPStateFlags.LoopStateFlags;
- result.m_completed = (sb_status == ParallelLoopStateFlags.PLS_NONE);
- if ((sb_status & ParallelLoopStateFlags.PLS_BROKEN) != 0)
- {
- result.m_lowestBreakIteration = sharedPStateFlags.LowestBreakIteration;
- }
-
- if ((rootTask != null) && rootTask.IsCompleted) rootTask.Dispose();
-
- //dispose the partitioner source if it implements IDisposable
- IDisposable d = null;
- if (orderablePartitionerSource != null)
- {
- d = orderablePartitionerSource as IDisposable;
- }
- else
- {
- d = partitionerSource as IDisposable;
- }
-
- if (d != null)
- {
- d.Dispose();
- }
-
- // ETW event for Parallel For End
- if (TplEtwProvider.Log.IsEnabled())
- {
- TplEtwProvider.Log.ParallelLoopEnd((callerTask != null ? callerTask.m_taskScheduler.Id : TaskScheduler.Current.Id), (callerTask != null ? callerTask.Id : 0),
- forkJoinContextID, 0);
- }
- }
-
- return result;
- }
-
- /// <summary>
- /// Internal utility function that implements the OCE filtering behavior for all Parallel.* APIs.
- /// Throws a single OperationCancelledException object with the token if the Exception collection only contains
- /// OperationCancelledExceptions with the given CancellationToken.
- ///
- /// </summary>
- /// <param name="excCollection"> The exception collection to filter</param>
- /// <param name="ct"> The CancellationToken expected on all inner exceptions</param>
- /// <returns></returns>
- internal static void ThrowIfReducableToSingleOCE(IEnumerable<Exception> excCollection, CancellationToken ct)
- {
- bool bCollectionNotZeroLength = false;
- if (ct.IsCancellationRequested)
- {
- foreach (Exception e in excCollection)
- {
- bCollectionNotZeroLength = true;
- OperationCanceledException oce = e as OperationCanceledException;
- if (oce == null || oce.CancellationToken != ct)
- {
- // mismatch found
- return;
- }
- }
-
- // all exceptions are OCEs with this token, let's throw it
- if (bCollectionNotZeroLength) throw new OperationCanceledException(ct);
- }
- }
-
- internal struct LoopTimer
- {
- public LoopTimer(int nWorkerTaskIndex)
- {
- // This logic ensures that we have a diversity of timeouts across worker tasks (100, 150, 200, 250, 100, etc)
- // Otherwise all worker will try to timeout at precisely the same point, which is bad if the work is just about to finish
- int timeOut = s_BaseNotifyPeriodMS + (nWorkerTaskIndex % PlatformHelper.ProcessorCount) * s_NotifyPeriodIncrementMS;
-
- m_timeLimit = Environment.TickCount + timeOut;
- }
-
- public bool LimitExceeded()
- {
- Debug.Assert(m_timeLimit != 0, "Probably the default initializer for LoopTimer was used somewhere");
-
- // comparing against the next expected time saves an addition operation here
- // Also we omit the comparison for wrap around here. The only side effect is one extra early yield every 38 days.
- return (Environment.TickCount > m_timeLimit);
- }
-
- const int s_BaseNotifyPeriodMS = 100;
- const int s_NotifyPeriodIncrementMS = 50;
-
- private int m_timeLimit;
- }
-
- }
-
-}
diff --git a/src/mscorlib/src/System/Threading/Tasks/ParallelLoopState.cs b/src/mscorlib/src/System/Threading/Tasks/ParallelLoopState.cs
deleted file mode 100644
index 6a62cf8..0000000
--- a/src/mscorlib/src/System/Threading/Tasks/ParallelLoopState.cs
+++ /dev/null
@@ -1,641 +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.
-
-// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
-//
-// ParallelState.cs
-//
-//
-// A non-generic and generic parallel state class, used by the Parallel helper class
-// for parallel loop management.
-//
-// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-
-using System.Diagnostics;
-using System.Security.Permissions;
-using System.Diagnostics.Contracts;
-
-// Prevents compiler warnings/errors regarding the use of ref params in Interlocked methods
-#pragma warning disable 0420
-
-namespace System.Threading.Tasks
-{
-
- /// <summary>
- /// Enables iterations of <see cref="T:System.Threading.Tasks.Parallel"/> loops to interact with
- /// other iterations.
- /// </summary>
- [DebuggerDisplay("ShouldExitCurrentIteration = {ShouldExitCurrentIteration}")]
- public class ParallelLoopState
- {
- // Derived classes will track a ParallelStateFlags32 or ParallelStateFlags64.
- // So this is slightly redundant, but it enables us to implement some
- // methods in this base class.
- private ParallelLoopStateFlags m_flagsBase;
-
- internal ParallelLoopState(ParallelLoopStateFlags fbase)
- {
- m_flagsBase = fbase;
- }
-
- /// <summary>
- /// Internal/virtual support for ShouldExitCurrentIteration.
- /// </summary>
- internal virtual bool InternalShouldExitCurrentIteration
- {
- get
- {
- Debug.Assert(false);
- throw new NotSupportedException(
- Environment.GetResourceString("ParallelState_NotSupportedException_UnsupportedMethod"));
- }
- }
-
- /// <summary>
- /// Gets whether the current iteration of the loop should exit based
- /// on requests made by this or other iterations.
- /// </summary>
- /// <remarks>
- /// When an iteration of a loop calls <see cref="Break()"/> or <see cref="Stop()"/>, or
- /// when one throws an exception, or when the loop is canceled, the <see cref="Parallel"/> class will proactively
- /// attempt to prohibit additional iterations of the loop from starting execution.
- /// However, there may be cases where it is unable to prevent additional iterations from starting.
- /// It may also be the case that a long-running iteration has already begun execution. In such
- /// cases, iterations may explicitly check the <see cref="ShouldExitCurrentIteration"/> property and
- /// cease execution if the property returns true.
- /// </remarks>
- public bool ShouldExitCurrentIteration
- {
- get
- {
- return InternalShouldExitCurrentIteration;
- }
- }
-
- /// <summary>
- /// Gets whether any iteration of the loop has called <see cref="Stop()"/>.
- /// </summary>
- public bool IsStopped
- {
- get
- {
- return ((m_flagsBase.LoopStateFlags & ParallelLoopStateFlags.PLS_STOPPED) != 0);
- }
- }
-
- /// <summary>
- /// Gets whether any iteration of the loop has thrown an exception that went unhandled by that
- /// iteration.
- /// </summary>
- public bool IsExceptional
- {
- get
- {
- return ((m_flagsBase.LoopStateFlags & ParallelLoopStateFlags.PLS_EXCEPTIONAL) != 0);
- }
- }
-
- /// <summary>
- /// Internal/virtual support for LowestBreakIteration.
- /// </summary>
- internal virtual long? InternalLowestBreakIteration
- {
- get
- {
- Debug.Assert(false);
- throw new NotSupportedException(
- Environment.GetResourceString("ParallelState_NotSupportedException_UnsupportedMethod"));
- }
- }
-
- /// <summary>
- /// Gets the lowest iteration of the loop from which <see cref="Break()"/> was called.
- /// </summary>
- /// <remarks>
- /// If no iteration of the loop called <see cref="Break()"/>, this property will return null.
- /// </remarks>
- public long? LowestBreakIteration
- {
- get
- {
- return InternalLowestBreakIteration;
- }
- }
-
- /// <summary>
- /// Communicates that the <see cref="Parallel"/> loop should cease execution at the system's earliest
- /// convenience.
- /// </summary>
- /// <exception cref="T:System.InvalidOperationException">
- /// The <see cref="Break()"/> method was previously called. <see cref="Break()"/> and <see
- /// cref="Stop()"/> may not be used in combination by iterations of the same loop.
- /// </exception>
- /// <remarks>
- /// <para>
- /// <see cref="Stop()"/> may be used to communicate to the loop that no other iterations need be run.
- /// For long-running iterations that may already be executing, <see cref="Stop()"/> causes <see cref="IsStopped"/>
- /// to return true for all other iterations of the loop, such that another iteration may check <see
- /// cref="IsStopped"/> and exit early if it's observed to be true.
- /// </para>
- /// <para>
- /// <see cref="Stop()"/> is typically employed in search-based algorithms, where once a result is found,
- /// no other iterations need be executed.
- /// </para>
- /// </remarks>
- public void Stop()
- {
- m_flagsBase.Stop();
- }
-
- // Internal/virtual support for Break().
- internal virtual void InternalBreak()
- {
- Debug.Assert(false);
- throw new NotSupportedException(
- Environment.GetResourceString("ParallelState_NotSupportedException_UnsupportedMethod"));
- }
-
- /// <summary>
- /// Communicates that the <see cref="Parallel"/> loop should cease execution at the system's earliest
- /// convenience of iterations beyond the current iteration.
- /// </summary>
- /// <exception cref="T:System.InvalidOperationException">
- /// The <see cref="Stop()"/> method was previously called. <see cref="Break()"/> and <see cref="Stop()"/>
- /// may not be used in combination by iterations of the same loop.
- /// </exception>
- /// <remarks>
- /// <para>
- /// <see cref="Break()"/> may be used to communicate to the loop that no other iterations after the
- /// current iteration need be run. For example, if <see cref="Break()"/> is called from the 100th
- /// iteration of a for loop iterating in parallel from 0 to 1000, all iterations less than 100 should
- /// still be run, but the iterations from 101 through to 1000 are not necessary.
- /// </para>
- /// <para>
- /// For long-running iterations that may already be executing, <see cref="Break()"/> causes <see
- /// cref="LowestBreakIteration"/>
- /// to be set to the current iteration's index if the current index is less than the current value of
- /// <see cref="LowestBreakIteration"/>.
- /// </para>
- /// <para>
- /// <see cref="Break()"/> is typically employed in search-based algorithms where an ordering is
- /// present in the data source.
- /// </para>
- /// </remarks>
- public void Break()
- {
- InternalBreak();
- }
-
- // Helper method to avoid repeating Break() logic between ParallelState32 and ParallelState32<TLocal>
- internal static void Break(int iteration, ParallelLoopStateFlags32 pflags)
- {
- int oldValue = ParallelLoopStateFlags.PLS_NONE;
-
- // Attempt to change state from "not stopped or broken or canceled or exceptional" to "broken".
- if (!pflags.AtomicLoopStateUpdate(ParallelLoopStateFlags.PLS_BROKEN,
- ParallelLoopStateFlags.PLS_STOPPED | ParallelLoopStateFlags.PLS_EXCEPTIONAL | ParallelLoopStateFlags.PLS_CANCELED,
- ref oldValue))
- {
-
- // If we were already stopped, we have a problem
- if ((oldValue & ParallelLoopStateFlags.PLS_STOPPED) != 0)
- {
- throw new InvalidOperationException(
- Environment.GetResourceString("ParallelState_Break_InvalidOperationException_BreakAfterStop"));
- }
- else
- {
- // Apparently we previously got cancelled or became exceptional. No action necessary
- return;
- }
- }
-
- // replace shared LowestBreakIteration with CurrentIteration, but only if CurrentIteration
- // is less than LowestBreakIteration.
- int oldLBI = pflags.m_lowestBreakIteration;
- if (iteration < oldLBI)
- {
- SpinWait wait = new SpinWait();
- while (Interlocked.CompareExchange(
- ref pflags.m_lowestBreakIteration,
- iteration,
- oldLBI) != oldLBI)
- {
- wait.SpinOnce();
- oldLBI = pflags.m_lowestBreakIteration;
- if (iteration > oldLBI) break;
- }
- }
-
- }
-
- // Helper method to avoid repeating Break() logic between ParallelState64 and ParallelState64<TLocal>
- internal static void Break(long iteration, ParallelLoopStateFlags64 pflags)
- {
- int oldValue = ParallelLoopStateFlags.PLS_NONE;
-
- // Attempt to change state from "not stopped or broken or canceled or exceptional" to "broken".
- if (!pflags.AtomicLoopStateUpdate(ParallelLoopStateFlags.PLS_BROKEN,
- ParallelLoopStateFlags.PLS_STOPPED | ParallelLoopStateFlags.PLS_EXCEPTIONAL | ParallelLoopStateFlags.PLS_CANCELED,
- ref oldValue))
- {
-
- // If we were already stopped, we have a problem
- if ((oldValue & ParallelLoopStateFlags.PLS_STOPPED) != 0)
- {
- throw new InvalidOperationException(
- Environment.GetResourceString("ParallelState_Break_InvalidOperationException_BreakAfterStop"));
- }
- else
- {
- // Apparently we previously got cancelled or became exceptional. No action necessary
- return;
- }
- }
-
- // replace shared LowestBreakIteration with CurrentIteration, but only if CurrentIteration
- // is less than LowestBreakIteration.
- long oldLBI = pflags.LowestBreakIteration;
- if (iteration < oldLBI)
- {
- SpinWait wait = new SpinWait();
- while (Interlocked.CompareExchange(
- ref pflags.m_lowestBreakIteration,
- iteration,
- oldLBI) != oldLBI)
- {
- wait.SpinOnce();
- oldLBI = pflags.LowestBreakIteration;
- if (iteration > oldLBI) break;
- }
- }
-
- }
- }
-
- internal class ParallelLoopState32 : ParallelLoopState
- {
- private ParallelLoopStateFlags32 m_sharedParallelStateFlags;
- private int m_currentIteration = 0;
-
- /// <summary>
- /// Internal constructor to ensure an instance isn't created by users.
- /// </summary>
- /// <param name="sharedParallelStateFlags">A flag shared among all threads participating
- /// in the execution of a certain loop.</param>
- internal ParallelLoopState32(ParallelLoopStateFlags32 sharedParallelStateFlags)
- : base(sharedParallelStateFlags)
- {
- m_sharedParallelStateFlags = sharedParallelStateFlags;
- }
-
- /// <summary>
- /// Tracks the current loop iteration for the owning task.
- /// This is used to compute whether or not the task should
- /// terminate early due to a Break() call.
- /// </summary>
- internal int CurrentIteration {
- get { return m_currentIteration; }
- set { m_currentIteration = value; }
- }
-
- /// <summary>
- /// Returns true if we should be exiting from the current iteration
- /// due to Stop(), Break() or exception.
- /// </summary>
- internal override bool InternalShouldExitCurrentIteration
- {
- get { return m_sharedParallelStateFlags.ShouldExitLoop(CurrentIteration); }
- }
-
- /// <summary>
- /// Returns the lowest iteration at which Break() has been called, or
- /// null if Break() has not yet been called.
- /// </summary>
- internal override long? InternalLowestBreakIteration
- {
- get {return m_sharedParallelStateFlags.NullableLowestBreakIteration; }
- }
-
- /// <summary>
- /// Communicates that parallel tasks should stop when they reach a specified iteration element.
- /// (which is CurrentIteration of the caller).
- /// </summary>
- /// <exception cref="T:System.InvalidOperationException">Break() called after Stop().</exception>
- /// <remarks>
- /// This is shared with all other concurrent threads in the system which are participating in the
- /// loop's execution. After calling Break(), no additional iterations will be executed on
- /// the current thread, and other worker threads will execute once they get beyond the calling iteration.
- /// </remarks>
- internal override void InternalBreak()
- {
- ParallelLoopState.Break(CurrentIteration, m_sharedParallelStateFlags);
- }
- }
-
- /// <summary>
- /// Allows independent iterations of a parallel loop to interact with other iterations.
- /// </summary>
- internal class ParallelLoopState64 : ParallelLoopState
- {
- private ParallelLoopStateFlags64 m_sharedParallelStateFlags;
- private long m_currentIteration = 0;
-
- /// <summary>
- /// Internal constructor to ensure an instance isn't created by users.
- /// </summary>
- /// <param name="sharedParallelStateFlags">A flag shared among all threads participating
- /// in the execution of a certain loop.</param>
- internal ParallelLoopState64(ParallelLoopStateFlags64 sharedParallelStateFlags)
- : base(sharedParallelStateFlags)
- {
- m_sharedParallelStateFlags = sharedParallelStateFlags;
- }
-
- /// <summary>
- /// Tracks the current loop iteration for the owning task.
- /// This is used to compute whether or not the task should
- /// terminate early due to a Break() call.
- /// </summary>
- internal long CurrentIteration
- {
- // No interlocks needed, because this value is only accessed in a single thread.
- get {return m_currentIteration;}
- set {m_currentIteration = value; }
- }
-
- /// <summary>
- /// Returns true if we should be exiting from the current iteration
- /// due to Stop(), Break() or exception.
- /// </summary>
- internal override bool InternalShouldExitCurrentIteration
- {
- get { return m_sharedParallelStateFlags.ShouldExitLoop(CurrentIteration); }
- }
-
- /// <summary>
- /// Returns the lowest iteration at which Break() has been called, or
- /// null if Break() has not yet been called.
- /// </summary>
- internal override long? InternalLowestBreakIteration
- {
- // We don't need to worry about torn read/write here because
- // ParallelStateFlags64.LowestBreakIteration property is protected
- // by an Interlocked.Read().
- get { return m_sharedParallelStateFlags.NullableLowestBreakIteration; }
- }
-
- /// <summary>
- /// Communicates that parallel tasks should stop when they reach a specified iteration element.
- /// (which is CurrentIteration of the caller).
- /// </summary>
- /// <exception cref="T:System.InvalidOperationException">Break() called after Stop().</exception>
- /// <remarks>
- /// Atomically sets shared StoppedBroken flag to BROKEN, then atomically sets shared
- /// LowestBreakIteration to CurrentIteration, but only if CurrentIteration is less than
- /// LowestBreakIteration.
- /// </remarks>
- internal override void InternalBreak()
- {
- ParallelLoopState.Break(CurrentIteration, m_sharedParallelStateFlags);
- }
-
- }
-
- /// <summary>
- /// State information that is common between ParallelStateFlags class
- /// and ParallelStateFlags64 class.
- /// </summary>
- internal class ParallelLoopStateFlags
- {
- internal static int PLS_NONE;
- internal static int PLS_EXCEPTIONAL = 1;
- internal static int PLS_BROKEN = 2;
- internal static int PLS_STOPPED = 4;
- internal static int PLS_CANCELED = 8;
-
- private volatile int m_LoopStateFlags = PLS_NONE;
-
- internal int LoopStateFlags
- {
- get { return m_LoopStateFlags; }
- }
-
- internal bool AtomicLoopStateUpdate(int newState, int illegalStates)
- {
- int oldState = 0;
- return AtomicLoopStateUpdate(newState, illegalStates, ref oldState);
- }
-
- internal bool AtomicLoopStateUpdate(int newState, int illegalStates, ref int oldState)
- {
- SpinWait sw = new SpinWait();
-
- do
- {
- oldState = m_LoopStateFlags;
- if ((oldState & illegalStates) != 0) return false;
- if (Interlocked.CompareExchange(ref m_LoopStateFlags, oldState | newState, oldState) == oldState)
- {
- return true;
- }
- sw.SpinOnce();
- } while (true);
-
- }
-
- internal void SetExceptional()
- {
- // we can set the exceptional flag regardless of the state of other bits.
- AtomicLoopStateUpdate(PLS_EXCEPTIONAL, PLS_NONE);
- }
-
- internal void Stop()
- {
- // disallow setting of PLS_STOPPED bit only if PLS_BROKEN was already set
- if (!AtomicLoopStateUpdate(PLS_STOPPED, PLS_BROKEN))
- {
- throw new InvalidOperationException(
- Environment.GetResourceString("ParallelState_Stop_InvalidOperationException_StopAfterBreak"));
- }
- }
-
- // Returns true if StoppedBroken is updated to PLS_CANCELED.
- internal bool Cancel()
- {
- // we can set the canceled flag regardless of the state of other bits.
- return (AtomicLoopStateUpdate(PLS_CANCELED, PLS_NONE));
- }
- }
-
- /// <summary>
- /// An internal class used to share accounting information in 32-bit versions
- /// of For()/ForEach() loops.
- /// </summary>
- internal class ParallelLoopStateFlags32 : ParallelLoopStateFlags
- {
- // Records the lowest iteration at which a Break() has been called,
- // or Int32.MaxValue if no break has been called. Used directly
- // by Break().
- internal volatile int m_lowestBreakIteration = Int32.MaxValue;
-
- // Not strictly necessary, but maintains consistency with ParallelStateFlags64
- internal int LowestBreakIteration
- {
- get { return m_lowestBreakIteration; }
- }
-
- // Does some processing to convert m_lowestBreakIteration to a long?.
- internal long? NullableLowestBreakIteration
- {
- get
- {
- if (m_lowestBreakIteration == Int32.MaxValue) return null;
- else
- {
- // protect against torn read of 64-bit value
- long rval = m_lowestBreakIteration;
- if (IntPtr.Size >= 8) return rval;
- else return Interlocked.Read(ref rval);
- }
- }
- }
-
-
- /// <summary>
- /// Lets the caller know whether or not to prematurely exit the For/ForEach loop.
- /// If this returns true, then exit the loop. Otherwise, keep going.
- /// </summary>
- /// <param name="CallerIteration">The caller's current iteration point
- /// in the loop.</param>
- /// <remarks>
- /// The loop should exit on any one of the following conditions:
- /// (1) Stop() has been called by one or more tasks.
- /// (2) An exception has been raised by one or more tasks.
- /// (3) Break() has been called by one or more tasks, and
- /// CallerIteration exceeds the (lowest) iteration at which
- /// Break() was called.
- /// (4) The loop was canceled.
- /// </remarks>
- internal bool ShouldExitLoop(int CallerIteration)
- {
- int flags = LoopStateFlags;
- return (flags != PLS_NONE && (
- ((flags & (PLS_EXCEPTIONAL | PLS_STOPPED | PLS_CANCELED)) != 0) ||
- (((flags & PLS_BROKEN) != 0) && (CallerIteration > LowestBreakIteration))));
- }
-
- // This lighter version of ShouldExitLoop will be used when the body type doesn't contain a state.
- // Since simpler bodies cannot stop or break, we can safely skip checks for those flags here.
- internal bool ShouldExitLoop()
- {
- int flags = LoopStateFlags;
- return ((flags != PLS_NONE) && ((flags & (PLS_EXCEPTIONAL | PLS_CANCELED)) != 0));
- }
- }
-
- /// <summary>
- /// An internal class used to share accounting information in 64-bit versions
- /// of For()/ForEach() loops.
- /// </summary>
- internal class ParallelLoopStateFlags64 : ParallelLoopStateFlags
- {
- // Records the lowest iteration at which a Break() has been called,
- // or Int64.MaxValue if no break has been called. Used directly
- // by Break().
- internal long m_lowestBreakIteration = Int64.MaxValue;
-
- // Performs a conditionally interlocked read of m_lowestBreakIteration.
- internal long LowestBreakIteration
- {
- get
- {
- if (IntPtr.Size >= 8) return m_lowestBreakIteration;
- else return Interlocked.Read(ref m_lowestBreakIteration);
- }
- }
-
- // Does some processing to convert m_lowestBreakIteration to a long?.
- internal long? NullableLowestBreakIteration
- {
- get
- {
- if (m_lowestBreakIteration == Int64.MaxValue) return null;
- else
- {
- if (IntPtr.Size >= 8) return m_lowestBreakIteration;
- else return Interlocked.Read(ref m_lowestBreakIteration);
- }
- }
- }
-
- /// <summary>
- /// Lets the caller know whether or not to prematurely exit the For/ForEach loop.
- /// If this returns true, then exit the loop. Otherwise, keep going.
- /// </summary>
- /// <param name="CallerIteration">The caller's current iteration point
- /// in the loop.</param>
- /// <remarks>
- /// The loop should exit on any one of the following conditions:
- /// (1) Stop() has been called by one or more tasks.
- /// (2) An exception has been raised by one or more tasks.
- /// (3) Break() has been called by one or more tasks, and
- /// CallerIteration exceeds the (lowest) iteration at which
- /// Break() was called.
- /// (4) The loop has been canceled.
- /// </remarks>
- internal bool ShouldExitLoop(long CallerIteration)
- {
- int flags = LoopStateFlags;
- return (flags != PLS_NONE && (
- ((flags & (PLS_EXCEPTIONAL | PLS_STOPPED | PLS_CANCELED)) != 0) ||
- (((flags & PLS_BROKEN) != 0) && (CallerIteration > LowestBreakIteration))));
- }
-
- // This lighter version of ShouldExitLoop will be used when the body type doesn't contain a state.
- // Since simpler bodies cannot stop or break, we can safely skip checks for those flags here.
- internal bool ShouldExitLoop()
- {
- int flags = LoopStateFlags;
- return ((flags != PLS_NONE) && ((flags & (PLS_EXCEPTIONAL | PLS_CANCELED)) != 0));
- }
- }
-
- /// <summary>
- /// Provides completion status on the execution of a <see cref="Parallel"/> loop.
- /// </summary>
- /// <remarks>
- /// If <see cref="IsCompleted"/> returns true, then the loop ran to completion, such that all iterations
- /// of the loop were executed. If <see cref="IsCompleted"/> returns false and <see
- /// cref="LowestBreakIteration"/> returns null, a call to <see
- /// cref="System.Threading.Tasks.ParallelLoopState.Stop"/> was used to end the loop prematurely. If <see
- /// cref="IsCompleted"/> returns false and <see cref="LowestBreakIteration"/> returns a non-null integral
- /// value, <see cref="System.Threading.Tasks.ParallelLoopState.Break()"/> was used to end the loop prematurely.
- /// </remarks>
- public struct ParallelLoopResult
- {
- internal bool m_completed;
- internal long? m_lowestBreakIteration;
-
- /// <summary>
- /// Gets whether the loop ran to completion, such that all iterations of the loop were executed
- /// and the loop didn't receive a request to end prematurely.
- /// </summary>
- public bool IsCompleted { get { return m_completed; } }
-
- /// <summary>
- /// Gets the index of the lowest iteration from which <see
- /// cref="System.Threading.Tasks.ParallelLoopState.Break()"/>
- /// was called.
- /// </summary>
- /// <remarks>
- /// If <see cref="System.Threading.Tasks.ParallelLoopState.Break()"/> was not employed, this property will
- /// return null.
- /// </remarks>
- public long? LowestBreakIteration { get { return m_lowestBreakIteration; } }
- }
-
-}
-
-#pragma warning restore 0420
diff --git a/src/mscorlib/src/System/Threading/Tasks/ParallelRangeManager.cs b/src/mscorlib/src/System/Threading/Tasks/ParallelRangeManager.cs
deleted file mode 100644
index 49f61a6..0000000
--- a/src/mscorlib/src/System/Threading/Tasks/ParallelRangeManager.cs
+++ /dev/null
@@ -1,279 +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.
-
-// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
-//
-//
-//
-// Implements the algorithm for distributing loop indices to parallel loop workers
-//
-// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-
-using System;
-using System.Threading;
-using System.Diagnostics;
-using System.Diagnostics.Contracts;
-
-#pragma warning disable 0420
-
-namespace System.Threading.Tasks
-{
- /// <summary>
- /// Represents an index range
- /// </summary>
- internal struct IndexRange
- {
- // the From and To values for this range. These do not change.
- internal long m_nFromInclusive;
- internal long m_nToExclusive;
-
- // The shared index, stored as the offset from nFromInclusive. Using an offset rather than the actual
- // value saves us from overflows that can happen due to multiple workers racing to increment this.
- // All updates to this field need to be interlocked.
- internal volatile Shared<long> m_nSharedCurrentIndexOffset;
-
- // to be set to 1 by the worker that finishes this range. It's OK to do a non-interlocked write here.
- internal int m_bRangeFinished;
- }
-
-
- /// <summary>
- /// The RangeWorker struct wraps the state needed by a task that services the parallel loop
- /// </summary>
- internal struct RangeWorker
- {
- // reference to the IndexRange array allocated by the range manager
- internal readonly IndexRange[] m_indexRanges;
-
- // index of the current index range that this worker is grabbing chunks from
- internal int m_nCurrentIndexRange;
-
- // the step for this loop. Duplicated here for quick access (rather than jumping to rangemanager)
- internal long m_nStep;
-
- // increment value is the current amount that this worker will use
- // to increment the shared index of the range it's working on
- internal long m_nIncrementValue;
-
- // the increment value is doubled each time this worker finds work, and is capped at this value
- internal readonly long m_nMaxIncrementValue;
-
- /// <summary>
- /// Initializes a RangeWorker struct
- /// </summary>
- internal RangeWorker(IndexRange[] ranges, int nInitialRange, long nStep)
- {
- m_indexRanges = ranges;
- m_nCurrentIndexRange = nInitialRange;
- m_nStep = nStep;
-
- m_nIncrementValue = nStep;
-
- m_nMaxIncrementValue = Parallel.DEFAULT_LOOP_STRIDE * nStep;
- }
-
- /// <summary>
- /// Implements the core work search algorithm that will be used for this range worker.
- /// </summary>
- ///
- /// Usage pattern is:
- /// 1) the thread associated with this rangeworker calls FindNewWork
- /// 2) if we return true, the worker uses the nFromInclusiveLocal and nToExclusiveLocal values
- /// to execute the sequential loop
- /// 3) if we return false it means there is no more work left. It's time to quit.
- ///
- internal bool FindNewWork(out long nFromInclusiveLocal, out long nToExclusiveLocal)
- {
- // since we iterate over index ranges circularly, we will use the
- // count of visited ranges as our exit condition
- int numIndexRangesToVisit = m_indexRanges.Length;
-
- do
- {
- // local snap to save array access bounds checks in places where we only read fields
- IndexRange currentRange = m_indexRanges[m_nCurrentIndexRange];
-
- if (currentRange.m_bRangeFinished == 0)
- {
- if (m_indexRanges[m_nCurrentIndexRange].m_nSharedCurrentIndexOffset == null)
- {
- Interlocked.CompareExchange(ref m_indexRanges[m_nCurrentIndexRange].m_nSharedCurrentIndexOffset, new Shared<long>(0), null);
- }
-
- // this access needs to be on the array slot
- long nMyOffset = Interlocked.Add(ref m_indexRanges[m_nCurrentIndexRange].m_nSharedCurrentIndexOffset.Value,
- m_nIncrementValue) - m_nIncrementValue;
-
- if (currentRange.m_nToExclusive - currentRange.m_nFromInclusive > nMyOffset)
- {
- // we found work
-
- nFromInclusiveLocal = currentRange.m_nFromInclusive + nMyOffset;
- nToExclusiveLocal = nFromInclusiveLocal + m_nIncrementValue;
-
- // Check for going past end of range, or wrapping
- if ( (nToExclusiveLocal > currentRange.m_nToExclusive) || (nToExclusiveLocal < currentRange.m_nFromInclusive) )
- {
- nToExclusiveLocal = currentRange.m_nToExclusive;
- }
-
- // We will double our unit of increment until it reaches the maximum.
- if (m_nIncrementValue < m_nMaxIncrementValue)
- {
- m_nIncrementValue *= 2;
- if (m_nIncrementValue > m_nMaxIncrementValue)
- {
- m_nIncrementValue = m_nMaxIncrementValue;
- }
- }
-
- return true;
- }
- else
- {
- // this index range is completed, mark it so that others can skip it quickly
- Interlocked.Exchange(ref m_indexRanges[m_nCurrentIndexRange].m_bRangeFinished, 1);
- }
- }
-
- // move on to the next index range, in circular order.
- m_nCurrentIndexRange = (m_nCurrentIndexRange + 1) % m_indexRanges.Length;
- numIndexRangesToVisit--;
-
- } while (numIndexRangesToVisit > 0);
- // we've visited all index ranges possible => there's no work remaining
-
- nFromInclusiveLocal = 0;
- nToExclusiveLocal = 0;
-
- return false;
- }
-
-
- /// <summary>
- /// 32 bit integer version of FindNewWork. Assumes the ranges were initialized with 32 bit values.
- /// </summary>
- internal bool FindNewWork32(out int nFromInclusiveLocal32, out int nToExclusiveLocal32)
- {
- long nFromInclusiveLocal;
- long nToExclusiveLocal;
-
- bool bRetVal = FindNewWork(out nFromInclusiveLocal, out nToExclusiveLocal);
-
- Debug.Assert((nFromInclusiveLocal <= Int32.MaxValue) && (nFromInclusiveLocal >= Int32.MinValue) &&
- (nToExclusiveLocal <= Int32.MaxValue) && (nToExclusiveLocal >= Int32.MinValue));
-
- // convert to 32 bit before returning
- nFromInclusiveLocal32 = (int)nFromInclusiveLocal;
- nToExclusiveLocal32 = (int)nToExclusiveLocal;
-
- return bRetVal;
- }
- }
-
-
- /// <summary>
- /// Represents the entire loop operation, keeping track of workers and ranges.
- /// </summary>
- ///
- /// The usage pattern is:
- /// 1) The Parallel loop entry function (ForWorker) creates an instance of this class
- /// 2) Every thread joining to service the parallel loop calls RegisterWorker to grab a
- /// RangeWorker struct to wrap the state it will need to find and execute work,
- /// and they keep interacting with that struct until the end of the loop
- internal class RangeManager
- {
- internal readonly IndexRange[] m_indexRanges;
-
- internal int m_nCurrentIndexRangeToAssign;
- internal long m_nStep;
-
- /// <summary>
- /// Initializes a RangeManager with the given loop parameters, and the desired number of outer ranges
- /// </summary>
- internal RangeManager(long nFromInclusive, long nToExclusive, long nStep, int nNumExpectedWorkers)
- {
- m_nCurrentIndexRangeToAssign = 0;
- m_nStep = nStep;
-
- // Our signed math breaks down w/ nNumExpectedWorkers == 1. So change it to 2.
- if (nNumExpectedWorkers == 1)
- nNumExpectedWorkers = 2;
-
- //
- // calculate the size of each index range
- //
-
- ulong uSpan = (ulong)(nToExclusive - nFromInclusive);
- ulong uRangeSize = uSpan / (ulong) nNumExpectedWorkers; // rough estimate first
-
- uRangeSize -= uRangeSize % (ulong) nStep; // snap to multiples of nStep
- // otherwise index range transitions will derail us from nStep
-
- if (uRangeSize == 0)
- {
- uRangeSize = (ulong) nStep;
- }
-
- //
- // find the actual number of index ranges we will need
- //
- Debug.Assert((uSpan / uRangeSize) < Int32.MaxValue);
-
- int nNumRanges = (int)(uSpan / uRangeSize);
-
- if (uSpan % uRangeSize != 0)
- {
- nNumRanges++;
- }
-
-
- // Convert to signed so the rest of the logic works.
- // Should be fine so long as uRangeSize < Int64.MaxValue, which we guaranteed by setting #workers >= 2.
- long nRangeSize = (long)uRangeSize;
-
- // allocate the array of index ranges
- m_indexRanges = new IndexRange[nNumRanges];
-
- long nCurrentIndex = nFromInclusive;
- for (int i = 0; i < nNumRanges; i++)
- {
- // the fromInclusive of the new index range is always on nCurrentIndex
- m_indexRanges[i].m_nFromInclusive = nCurrentIndex;
- m_indexRanges[i].m_nSharedCurrentIndexOffset = null;
- m_indexRanges[i].m_bRangeFinished = 0;
-
- // now increment it to find the toExclusive value for our range
- nCurrentIndex += nRangeSize;
-
- // detect integer overflow or range overage and snap to nToExclusive
- if (nCurrentIndex < nCurrentIndex - nRangeSize ||
- nCurrentIndex > nToExclusive)
- {
- // this should only happen at the last index
- Debug.Assert(i == nNumRanges - 1);
-
- nCurrentIndex = nToExclusive;
- }
-
- // now that the end point of the new range is calculated, assign it.
- m_indexRanges[i].m_nToExclusive = nCurrentIndex;
- }
- }
-
- /// <summary>
- /// The function that needs to be called by each new worker thread servicing the parallel loop
- /// in order to get a RangeWorker struct that wraps the state for finding and executing indices
- /// </summary>
- internal RangeWorker RegisterNewWorker()
- {
- Debug.Assert(m_indexRanges != null && m_indexRanges.Length != 0);
-
- int nInitialRange = (Interlocked.Increment(ref m_nCurrentIndexRangeToAssign) - 1) % m_indexRanges.Length;
-
- return new RangeWorker(m_indexRanges, nInitialRange, m_nStep);
- }
- }
-}
-#pragma warning restore 0420
diff --git a/src/mscorlib/src/System/Threading/Tasks/ProducerConsumerQueues.cs b/src/mscorlib/src/System/Threading/Tasks/ProducerConsumerQueues.cs
index 6b9dfbb..545bf9a 100644
--- a/src/mscorlib/src/System/Threading/Tasks/ProducerConsumerQueues.cs
+++ b/src/mscorlib/src/System/Threading/Tasks/ProducerConsumerQueues.cs
@@ -52,11 +52,6 @@ namespace System.Threading.Tasks
/// <summary>Gets the number of items in the collection.</summary>
/// <remarks>In many implementations, this method will not be thread-safe.</remarks>
int Count { get; }
-
- /// <summary>A thread-safe way to get the number of items in the collection. May synchronize access by locking the provided synchronization object.</summary>
- /// <param name="syncObj">The sync object used to lock</param>
- /// <returns>The collection count</returns>
- int GetCountSafe(object syncObj);
}
/// <summary>
@@ -80,10 +75,6 @@ namespace System.Threading.Tasks
/// <summary>Gets the number of items in the collection.</summary>
int IProducerConsumerQueue<T>.Count { get { return base.Count; } }
-
- /// <summary>A thread-safe way to get the number of items in the collection. May synchronize access by locking the provided synchronization object.</summary>
- /// <remarks>ConcurrentQueue.Count is thread safe, no need to acquire the lock.</remarks>
- int IProducerConsumerQueue<T>.GetCountSafe(object syncObj) { return base.Count; }
}
/// <summary>
@@ -260,143 +251,6 @@ namespace System.Threading.Tasks
return true;
}
- /// <summary>Attempts to peek at an item in the queue.</summary>
- /// <param name="result">The peeked item.</param>
- /// <returns>true if an item could be peeked; otherwise, false.</returns>
- public bool TryPeek(out T result)
- {
- Segment segment = m_head;
- var array = segment.m_array;
- int first = segment.m_state.m_first; // local copy to avoid multiple volatile reads
-
- // Fast path: there's obviously data available in the current segment
- if (first != segment.m_state.m_lastCopy)
- {
- result = array[first];
- return true;
- }
- // Slow path: there may not be data available in the current segment
- else return TryPeekSlow(ref segment, ref array, out result);
- }
-
- /// <summary>Attempts to peek at an item in the queue.</summary>
- /// <param name="array">The array from which the item is peeked.</param>
- /// <param name="segment">The segment from which the item is peeked.</param>
- /// <param name="result">The peeked item.</param>
- /// <returns>true if an item could be peeked; otherwise, false.</returns>
- private bool TryPeekSlow(ref Segment segment, ref T[] array, out T result)
- {
- Contract.Requires(segment != null, "Expected a non-null segment.");
- Contract.Requires(array != null, "Expected a non-null item array.");
-
- if (segment.m_state.m_last != segment.m_state.m_lastCopy)
- {
- segment.m_state.m_lastCopy = segment.m_state.m_last;
- return TryPeek(out result); // will only recur once for this peek operation
- }
-
- if (segment.m_next != null && segment.m_state.m_first == segment.m_state.m_last)
- {
- segment = segment.m_next;
- array = segment.m_array;
- m_head = segment;
- }
-
- var first = segment.m_state.m_first; // local copy to avoid extraneous volatile reads
-
- if (first == segment.m_state.m_last)
- {
- result = default(T);
- return false;
- }
-
- result = array[first];
- return true;
- }
-
- /// <summary>Attempts to dequeue an item from the queue.</summary>
- /// <param name="predicate">The predicate that must return true for the item to be dequeued. If null, all items implicitly return true.</param>
- /// <param name="result">The dequeued item.</param>
- /// <returns>true if an item could be dequeued; otherwise, false.</returns>
- public bool TryDequeueIf(Predicate<T> predicate, out T result)
- {
- Segment segment = m_head;
- var array = segment.m_array;
- int first = segment.m_state.m_first; // local copy to avoid multiple volatile reads
-
- // Fast path: there's obviously data available in the current segment
- if (first != segment.m_state.m_lastCopy)
- {
- result = array[first];
- if (predicate == null || predicate(result))
- {
- array[first] = default(T); // Clear the slot to release the element
- segment.m_state.m_first = (first + 1) & (array.Length - 1);
- return true;
- }
- else
- {
- result = default(T);
- return false;
- }
- }
- // Slow path: there may not be data available in the current segment
- else return TryDequeueIfSlow(predicate, ref segment, ref array, out result);
- }
-
- /// <summary>Attempts to dequeue an item from the queue.</summary>
- /// <param name="predicate">The predicate that must return true for the item to be dequeued. If null, all items implicitly return true.</param>
- /// <param name="array">The array from which the item was dequeued.</param>
- /// <param name="segment">The segment from which the item was dequeued.</param>
- /// <param name="result">The dequeued item.</param>
- /// <returns>true if an item could be dequeued; otherwise, false.</returns>
- private bool TryDequeueIfSlow(Predicate<T> predicate, ref Segment segment, ref T[] array, out T result)
- {
- Contract.Requires(segment != null, "Expected a non-null segment.");
- Contract.Requires(array != null, "Expected a non-null item array.");
-
- if (segment.m_state.m_last != segment.m_state.m_lastCopy)
- {
- segment.m_state.m_lastCopy = segment.m_state.m_last;
- return TryDequeueIf(predicate, out result); // will only recur once for this dequeue operation
- }
-
- if (segment.m_next != null && segment.m_state.m_first == segment.m_state.m_last)
- {
- segment = segment.m_next;
- array = segment.m_array;
- m_head = segment;
- }
-
- var first = segment.m_state.m_first; // local copy to avoid extraneous volatile reads
-
- if (first == segment.m_state.m_last)
- {
- result = default(T);
- return false;
- }
-
- result = array[first];
- if (predicate == null || predicate(result))
- {
- array[first] = default(T); // Clear the slot to release the element
- segment.m_state.m_first = (first + 1) & (segment.m_array.Length - 1);
- segment.m_state.m_lastCopy = segment.m_state.m_last; // Refresh m_lastCopy to ensure that m_first has not passed m_lastCopy
- return true;
- }
- else
- {
- result = default(T);
- return false;
- }
- }
-
- public void Clear()
- {
- T ignored;
- while (TryDequeue(out ignored)) ;
- }
-
/// <summary>Gets whether the collection is currently empty.</summary>
/// <remarks>WARNING: This should not be used concurrently without further vetting.</remarks>
public bool IsEmpty
@@ -452,17 +306,6 @@ namespace System.Threading.Tasks
}
}
- /// <summary>A thread-safe way to get the number of items in the collection. May synchronize access by locking the provided synchronization object.</summary>
- /// <remarks>The Count is not thread safe, so we need to acquire the lock.</remarks>
- int IProducerConsumerQueue<T>.GetCountSafe(object syncObj)
- {
- Debug.Assert(syncObj != null, "The syncObj parameter is null.");
- lock (syncObj)
- {
- return Count;
- }
- }
-
/// <summary>A segment in the queue containing one or more items.</summary>
[StructLayout(LayoutKind.Sequential)]
private sealed class Segment
@@ -520,23 +363,9 @@ namespace System.Threading.Tasks
Contract.Requires(queue != null, "Expected a non-null queue.");
m_queue = queue;
}
-
- /// <summary>Gets the contents of the list.</summary>
- [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
- public T[] Items
- {
- get
- {
- List<T> list = new List<T>();
- foreach (T item in m_queue)
- list.Add(item);
- return list.ToArray();
- }
- }
}
}
-
/// <summary>A placeholder class for common padding constants and eventually routines.</summary>
static class PaddingHelpers
{
diff --git a/src/mscorlib/src/System/Threading/Tasks/TPLETWProvider.cs b/src/mscorlib/src/System/Threading/Tasks/TPLETWProvider.cs
index 325aa91..12cc1da 100644
--- a/src/mscorlib/src/System/Threading/Tasks/TPLETWProvider.cs
+++ b/src/mscorlib/src/System/Threading/Tasks/TPLETWProvider.cs
@@ -14,7 +14,6 @@ using System;
using System.Collections.Generic;
using System.Text;
using System.Security;
-using System.Security.Permissions;
using System.Runtime.CompilerServices;
namespace System.Threading.Tasks
@@ -61,17 +60,6 @@ namespace System.Threading.Tasks
/// <summary>Prevent external instantiation. All logging should go through the Log instance.</summary>
private TplEtwProvider() { }
- /// <summary>Type of a fork/join operation.</summary>
- public enum ForkJoinOperationType
- {
- /// <summary>Parallel.Invoke.</summary>
- ParallelInvoke=1,
- /// <summary>Parallel.For.</summary>
- ParallelFor=2,
- /// <summary>Parallel.ForEach.</summary>
- ParallelForEach=3
- }
-
/// <summary>Configured behavior of a task wait operation.</summary>
public enum TaskWaitBehavior : int
{
@@ -203,195 +191,6 @@ namespace System.Threading.Tasks
//-----------------------------------------------------------------------------------
//
- // Parallel Events
- //
-
- #region ParallelLoopBegin
- /// <summary>
- /// Denotes the entry point for a Parallel.For or Parallel.ForEach loop
- /// </summary>
- /// <param name="OriginatingTaskSchedulerID">The scheduler ID.</param>
- /// <param name="OriginatingTaskID">The task ID.</param>
- /// <param name="ForkJoinContextID">The loop ID.</param>
- /// <param name="OperationType">The kind of fork/join operation.</param>
- /// <param name="InclusiveFrom">The lower bound of the loop.</param>
- /// <param name="ExclusiveTo">The upper bound of the loop.</param>
- [Event(PARALLELLOOPBEGIN_ID, Level = EventLevel.Informational, ActivityOptions=EventActivityOptions.Recursive,
- Task = TplEtwProvider.Tasks.Loop, Opcode = EventOpcode.Start)]
- public void ParallelLoopBegin(
- int OriginatingTaskSchedulerID, int OriginatingTaskID, // PFX_COMMON_EVENT_HEADER
- int ForkJoinContextID, ForkJoinOperationType OperationType, // PFX_FORKJOIN_COMMON_EVENT_HEADER
- long InclusiveFrom, long ExclusiveTo)
- {
- if (IsEnabled() && IsEnabled(EventLevel.Informational, Keywords.Parallel))
- {
- // There is no explicit WriteEvent() overload matching this event's fields. Therefore calling
- // WriteEvent() would hit the "params" overload, which leads to an object allocation every time
- // this event is fired. To prevent that problem we will call WriteEventCore(), which works with
- // a stack based EventData array populated with the event fields.
- unsafe
- {
- EventData* eventPayload = stackalloc EventData[6];
-
- eventPayload[0].Size = sizeof(int);
- eventPayload[0].DataPointer = ((IntPtr) (&OriginatingTaskSchedulerID));
- eventPayload[1].Size = sizeof(int);
- eventPayload[1].DataPointer = ((IntPtr) (&OriginatingTaskID));
- eventPayload[2].Size = sizeof(int);
- eventPayload[2].DataPointer = ((IntPtr) (&ForkJoinContextID));
- eventPayload[3].Size = sizeof(int);
- eventPayload[3].DataPointer = ((IntPtr) (&OperationType));
- eventPayload[4].Size = sizeof(long);
- eventPayload[4].DataPointer = ((IntPtr) (&InclusiveFrom));
- eventPayload[5].Size = sizeof(long);
- eventPayload[5].DataPointer = ((IntPtr) (&ExclusiveTo));
-
- WriteEventCore(PARALLELLOOPBEGIN_ID, 6, eventPayload);
- }
- }
- }
- #endregion
-
- #region ParallelLoopEnd
- /// <summary>
- /// Denotes the end of a Parallel.For or Parallel.ForEach loop.
- /// </summary>
- /// <param name="OriginatingTaskSchedulerID">The scheduler ID.</param>
- /// <param name="OriginatingTaskID">The task ID.</param>
- /// <param name="ForkJoinContextID">The loop ID.</param>
- /// <param name="TotalIterations">the total number of iterations processed.</param>
- [Event(PARALLELLOOPEND_ID, Level = EventLevel.Informational, Task = TplEtwProvider.Tasks.Loop, Opcode = EventOpcode.Stop)]
- public void ParallelLoopEnd(
- int OriginatingTaskSchedulerID, int OriginatingTaskID, // PFX_COMMON_EVENT_HEADER
- int ForkJoinContextID, long TotalIterations)
- {
- if (IsEnabled() && IsEnabled(EventLevel.Informational, Keywords.Parallel))
- {
- // There is no explicit WriteEvent() overload matching this event's fields.
- // Therefore calling WriteEvent() would hit the "params" overload, which leads to an object allocation every time this event is fired.
- // To prevent that problem we will call WriteEventCore(), which works with a stack based EventData array populated with the event fields
- unsafe
- {
- EventData* eventPayload = stackalloc EventData[4];
-
- eventPayload[0].Size = sizeof(int);
- eventPayload[0].DataPointer = ((IntPtr) (&OriginatingTaskSchedulerID));
- eventPayload[1].Size = sizeof(int);
- eventPayload[1].DataPointer = ((IntPtr) (&OriginatingTaskID));
- eventPayload[2].Size = sizeof(int);
- eventPayload[2].DataPointer = ((IntPtr) (&ForkJoinContextID));
- eventPayload[3].Size = sizeof(long);
- eventPayload[3].DataPointer = ((IntPtr) (&TotalIterations));
-
- WriteEventCore(PARALLELLOOPEND_ID, 4, eventPayload);
- }
- }
- }
- #endregion
-
- #region ParallelInvokeBegin
- /// <summary>Denotes the entry point for a Parallel.Invoke call.</summary>
- /// <param name="OriginatingTaskSchedulerID">The scheduler ID.</param>
- /// <param name="OriginatingTaskID">The task ID.</param>
- /// <param name="ForkJoinContextID">The invoke ID.</param>
- /// <param name="OperationType">The kind of fork/join operation.</param>
- /// <param name="ActionCount">The number of actions being invoked.</param>
- [Event(PARALLELINVOKEBEGIN_ID, Level = EventLevel.Informational, ActivityOptions=EventActivityOptions.Recursive,
- Task = TplEtwProvider.Tasks.Invoke, Opcode = EventOpcode.Start)]
- public void ParallelInvokeBegin(
- int OriginatingTaskSchedulerID, int OriginatingTaskID, // PFX_COMMON_EVENT_HEADER
- int ForkJoinContextID, ForkJoinOperationType OperationType, // PFX_FORKJOIN_COMMON_EVENT_HEADER
- int ActionCount)
- {
- if (IsEnabled() && IsEnabled(EventLevel.Informational, Keywords.Parallel))
- {
- // There is no explicit WriteEvent() overload matching this event's fields.
- // Therefore calling WriteEvent() would hit the "params" overload, which leads to an object allocation every time this event is fired.
- // To prevent that problem we will call WriteEventCore(), which works with a stack based EventData array populated with the event fields
- unsafe
- {
- EventData* eventPayload = stackalloc EventData[5];
-
- eventPayload[0].Size = sizeof(int);
- eventPayload[0].DataPointer = ((IntPtr) (&OriginatingTaskSchedulerID));
- eventPayload[1].Size = sizeof(int);
- eventPayload[1].DataPointer = ((IntPtr) (&OriginatingTaskID));
- eventPayload[2].Size = sizeof(int);
- eventPayload[2].DataPointer = ((IntPtr) (&ForkJoinContextID));
- eventPayload[3].Size = sizeof(int);
- eventPayload[3].DataPointer = ((IntPtr) (&OperationType));
- eventPayload[4].Size = sizeof(int);
- eventPayload[4].DataPointer = ((IntPtr) (&ActionCount));
-
- WriteEventCore(PARALLELINVOKEBEGIN_ID, 5, eventPayload);
- }
- }
- }
- #endregion
-
- #region ParallelInvokeEnd
- /// <summary>
- /// Denotes the exit point for a Parallel.Invoke call.
- /// </summary>
- /// <param name="OriginatingTaskSchedulerID">The scheduler ID.</param>
- /// <param name="OriginatingTaskID">The task ID.</param>
- /// <param name="ForkJoinContextID">The invoke ID.</param>
- [Event(PARALLELINVOKEEND_ID, Level = EventLevel.Informational, Task = TplEtwProvider.Tasks.Invoke, Opcode = EventOpcode.Stop)]
- public void ParallelInvokeEnd(
- int OriginatingTaskSchedulerID, int OriginatingTaskID, // PFX_COMMON_EVENT_HEADER
- int ForkJoinContextID)
- {
- if (IsEnabled() && IsEnabled(EventLevel.Informational, Keywords.Parallel))
- {
- WriteEvent(PARALLELINVOKEEND_ID, OriginatingTaskSchedulerID, OriginatingTaskID, ForkJoinContextID);
- }
- }
- #endregion
-
- #region ParallelFork
- /// <summary>
- /// Denotes the start of an individual task that's part of a fork/join context.
- /// Before this event is fired, the start of the new fork/join context will be marked
- /// with another event that declares a unique context ID.
- /// </summary>
- /// <param name="OriginatingTaskSchedulerID">The scheduler ID.</param>
- /// <param name="OriginatingTaskID">The task ID.</param>
- /// <param name="ForkJoinContextID">The invoke ID.</param>
- [Event(PARALLELFORK_ID, Level = EventLevel.Verbose, ActivityOptions=EventActivityOptions.Recursive,
- Task = TplEtwProvider.Tasks.ForkJoin, Opcode = EventOpcode.Start)]
- public void ParallelFork(
- int OriginatingTaskSchedulerID, int OriginatingTaskID, // PFX_COMMON_EVENT_HEADER
- int ForkJoinContextID)
- {
- if (IsEnabled() && IsEnabled(EventLevel.Verbose, Keywords.Parallel))
- {
- WriteEvent(PARALLELFORK_ID, OriginatingTaskSchedulerID, OriginatingTaskID, ForkJoinContextID);
- }
- }
- #endregion
-
- #region ParallelJoin
- /// <summary>
- /// Denotes the end of an individual task that's part of a fork/join context.
- /// This should match a previous ParallelFork event with a matching "OriginatingTaskID"
- /// </summary>
- /// <param name="OriginatingTaskSchedulerID">The scheduler ID.</param>
- /// <param name="OriginatingTaskID">The task ID.</param>
- /// <param name="ForkJoinContextID">The invoke ID.</param>
- [Event(PARALLELJOIN_ID, Level = EventLevel.Verbose, Task = TplEtwProvider.Tasks.ForkJoin, Opcode = EventOpcode.Stop)]
- public void ParallelJoin(
- int OriginatingTaskSchedulerID, int OriginatingTaskID, // PFX_COMMON_EVENT_HEADER
- int ForkJoinContextID)
- {
- if (IsEnabled() && IsEnabled(EventLevel.Verbose, Keywords.Parallel))
- {
- WriteEvent(PARALLELJOIN_ID, OriginatingTaskSchedulerID, OriginatingTaskID, ForkJoinContextID);
- }
- }
- #endregion
-
- //-----------------------------------------------------------------------------------
- //
// Task Events
//
@@ -512,7 +311,7 @@ namespace System.Threading.Tasks
Level = EventLevel.Informational, Keywords = Keywords.TaskTransfer|Keywords.Tasks)]
public void TaskWaitBegin(
int OriginatingTaskSchedulerID, int OriginatingTaskID, // PFX_COMMON_EVENT_HEADER
- int TaskID, TaskWaitBehavior Behavior, int ContinueWithTaskID, int appDomain)
+ int TaskID, TaskWaitBehavior Behavior, int ContinueWithTaskID)
{
if (IsEnabled() && IsEnabled(EventLevel.Informational, Keywords.TaskTransfer|Keywords.Tasks))
{
@@ -534,8 +333,10 @@ namespace System.Threading.Tasks
Guid childActivityId = CreateGuidForTaskID(TaskID);
WriteEventWithRelatedActivityIdCore(TASKWAITBEGIN_ID, &childActivityId, 5, eventPayload);
}
- else
+ else
+ {
WriteEventCore(TASKWAITBEGIN_ID, 5, eventPayload);
+ }
}
}
}
@@ -688,7 +489,7 @@ namespace System.Threading.Tasks
}
}
- [NonEvent, System.Security.SecuritySafeCritical]
+ [NonEvent]
unsafe public void RunningContinuation(int TaskID, object Object) { RunningContinuation(TaskID, (long) *((void**) JitHelpers.UnsafeCastToStackPointer(ref Object))); }
[Event(20, Keywords = Keywords.Debug)]
private void RunningContinuation(int TaskID, long Object)
@@ -697,7 +498,7 @@ namespace System.Threading.Tasks
WriteEvent(20, TaskID, Object);
}
- [NonEvent, System.Security.SecuritySafeCritical]
+ [NonEvent]
unsafe public void RunningContinuationList(int TaskID, int Index, object Object) { RunningContinuationList(TaskID, Index, (long) *((void**) JitHelpers.UnsafeCastToStackPointer(ref Object))); }
[Event(21, Keywords = Keywords.Debug)]
@@ -707,9 +508,6 @@ namespace System.Threading.Tasks
WriteEvent(21, TaskID, Index, Object);
}
- [Event(22, Keywords = Keywords.Debug)]
- public void DebugMessage(string Message) { WriteEvent(22, Message); }
-
[Event(23, Keywords = Keywords.Debug)]
public void DebugFacilityMessage(string Facility, string Message) { WriteEvent(23, Facility, Message); }
diff --git a/src/mscorlib/src/System/Threading/Tasks/Task.cs b/src/mscorlib/src/System/Threading/Tasks/Task.cs
index cf081f7..7013c5c 100644
--- a/src/mscorlib/src/System/Threading/Tasks/Task.cs
+++ b/src/mscorlib/src/System/Threading/Tasks/Task.cs
@@ -18,7 +18,6 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.ExceptionServices;
using System.Security;
-using System.Security.Permissions;
using System.Threading;
using System.Diagnostics;
using System.Diagnostics.Contracts;
@@ -147,7 +146,6 @@ namespace System.Threading.Tasks
private static StackGuard t_stackGuard; // The stack guard object for this thread
internal static int s_taskIdCounter; //static counter used to generate unique task IDs
- private readonly static TaskFactory s_factory = new TaskFactory();
private volatile int m_taskId; // this task's unique ID. initialized only if it is ever requested
@@ -365,12 +363,9 @@ namespace System.Threading.Tasks
/// </summary>
/// <param name="action">The delegate that represents the code to execute in the Task.</param>
/// <exception cref="T:System.ArgumentNullException">The <paramref name="action"/> argument is null.</exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task(Action action)
: this(action, null, null, default(CancellationToken), TaskCreationOptions.None, InternalTaskOptions.None, null)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- PossiblyCaptureContext(ref stackMark);
}
/// <summary>
@@ -383,12 +378,9 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
/// has already been disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task(Action action, CancellationToken cancellationToken)
: this(action, null, null, cancellationToken, TaskCreationOptions.None, InternalTaskOptions.None, null)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- PossiblyCaptureContext(ref stackMark);
}
/// <summary>
@@ -406,12 +398,9 @@ namespace System.Threading.Tasks
/// The <paramref name="creationOptions"/> argument specifies an invalid value for <see
/// cref="T:System.Threading.Tasks.TaskCreationOptions"/>.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task(Action action, TaskCreationOptions creationOptions)
: this(action, null, Task.InternalCurrentIfAttached(creationOptions), default(CancellationToken), creationOptions, InternalTaskOptions.None, null)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- PossiblyCaptureContext(ref stackMark);
}
/// <summary>
@@ -433,12 +422,9 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
/// has already been disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task(Action action, CancellationToken cancellationToken, TaskCreationOptions creationOptions)
: this(action, null, Task.InternalCurrentIfAttached(creationOptions), cancellationToken, creationOptions, InternalTaskOptions.None, null)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- PossiblyCaptureContext(ref stackMark);
}
@@ -450,12 +436,9 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ArgumentNullException">
/// The <paramref name="action"/> argument is null.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task(Action<object> action, object state)
: this(action, state, null, default(CancellationToken), TaskCreationOptions.None, InternalTaskOptions.None, null)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- PossiblyCaptureContext(ref stackMark);
}
/// <summary>
@@ -470,12 +453,9 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
/// has already been disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task(Action<object> action, object state, CancellationToken cancellationToken)
: this(action, state, null, cancellationToken, TaskCreationOptions.None, InternalTaskOptions.None, null)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- PossiblyCaptureContext(ref stackMark);
}
/// <summary>
@@ -494,12 +474,9 @@ namespace System.Threading.Tasks
/// The <paramref name="creationOptions"/> argument specifies an invalid value for <see
/// cref="T:System.Threading.Tasks.TaskCreationOptions"/>.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task(Action<object> action, object state, TaskCreationOptions creationOptions)
: this(action, state, Task.InternalCurrentIfAttached(creationOptions), default(CancellationToken), creationOptions, InternalTaskOptions.None, null)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- PossiblyCaptureContext(ref stackMark);
}
/// <summary>
@@ -522,19 +499,9 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
/// has already been disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task(Action<object> action, object state, CancellationToken cancellationToken, TaskCreationOptions creationOptions)
: this(action, state, Task.InternalCurrentIfAttached(creationOptions), cancellationToken, creationOptions, InternalTaskOptions.None, null)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- PossiblyCaptureContext(ref stackMark);
- }
-
- internal Task(Action<object> action, object state, Task parent, CancellationToken cancellationToken,
- TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler, ref StackCrawlMark stackMark)
- : this(action, state, parent, cancellationToken, creationOptions, internalOptions, scheduler)
- {
- PossiblyCaptureContext(ref stackMark);
}
/// <summary>
@@ -557,10 +524,8 @@ namespace System.Threading.Tasks
}
Contract.EndContractBlock();
- // Keep a link to your parent if: (A) You are attached, or (B) you are self-replicating.
- if (parent != null &&
- ((creationOptions & TaskCreationOptions.AttachedToParent) != 0 ||
- (internalOptions & InternalTaskOptions.SelfReplicating) != 0))
+ // Keep a link to the parent if attached
+ if (parent != null && (creationOptions & TaskCreationOptions.AttachedToParent) != 0)
{
EnsureContingentPropertiesInitializedUnsafe().m_parent = parent;
}
@@ -586,6 +551,10 @@ namespace System.Threading.Tasks
m_stateObject = state;
m_taskScheduler = scheduler;
+ Debug.Assert(m_contingentProperties == null || m_contingentProperties.m_capturedContext == null,
+ "Captured an ExecutionContext when one was already captured.");
+ CapturedContext = ExecutionContext.Capture();
+
// Check for validity of options
if ((creationOptions &
~(TaskCreationOptions.AttachedToParent |
@@ -602,22 +571,13 @@ namespace System.Threading.Tasks
// Check the validity of internalOptions
int illegalInternalOptions =
(int) (internalOptions &
- ~(InternalTaskOptions.SelfReplicating |
- InternalTaskOptions.ChildReplica |
- InternalTaskOptions.PromiseTask |
+ ~(InternalTaskOptions.PromiseTask |
InternalTaskOptions.ContinuationTask |
InternalTaskOptions.LazyCancellation |
InternalTaskOptions.QueuedByRuntime));
Debug.Assert(illegalInternalOptions == 0, "TaskConstructorCore: Illegal internal options");
#endif
- // Throw exception if the user specifies both LongRunning and SelfReplicating
- if (((creationOptions & TaskCreationOptions.LongRunning) != 0) &&
- ((internalOptions & InternalTaskOptions.SelfReplicating) != 0))
- {
- ThrowHelper.ThrowInvalidOperationException(ExceptionResource.Task_ctor_LRandSR);
- }
-
// Assign options to m_stateAndOptionsFlag.
Debug.Assert(m_stateFlags == 0, "TaskConstructorCore: non-zero m_stateFlags");
Debug.Assert((((int)creationOptions) | OptionsMask) == OptionsMask, "TaskConstructorCore: options take too many bits");
@@ -648,9 +608,7 @@ namespace System.Threading.Tasks
// we need to do this as the very last thing in the construction path, because the CT registration could modify m_stateFlags
if (cancellationToken.CanBeCanceled)
{
- Debug.Assert((internalOptions &
- (InternalTaskOptions.ChildReplica | InternalTaskOptions.SelfReplicating | InternalTaskOptions.ContinuationTask)) == 0,
- "TaskConstructorCore: Did not expect to see cancelable token for replica/replicating or continuation task.");
+ Debug.Assert((internalOptions & InternalTaskOptions.ContinuationTask) == 0, "TaskConstructorCore: Did not expect to see cancelable token for continuation task.");
AssignCancellationToken(cancellationToken, null, null);
}
@@ -757,24 +715,6 @@ namespace System.Threading.Tasks
}
}
-
- /// <summary>
- /// Captures the ExecutionContext so long as flow isn't suppressed.
- /// </summary>
- /// <param name="stackMark">A stack crawl mark pointing to the frame of the caller.</param>
-
- internal void PossiblyCaptureContext(ref StackCrawlMark stackMark)
- {
- Debug.Assert(m_contingentProperties == null || m_contingentProperties.m_capturedContext == null,
- "Captured an ExecutionContext when one was already captured.");
-
- // In the legacy .NET 3.5 build, we don't have the optimized overload of Capture()
- // available, so we call the parameterless overload.
- CapturedContext = ExecutionContext.Capture(
- ref stackMark,
- ExecutionContext.CaptureOptions.IgnoreSyncCtx | ExecutionContext.CaptureOptions.OptimizeDefaultCase);
- }
-
// Internal property to process TaskCreationOptions access and mutation.
internal TaskCreationOptions Options
{
@@ -989,16 +929,14 @@ namespace System.Threading.Tasks
/// </summary>
internal void AddNewChild()
{
- Debug.Assert(Task.InternalCurrent == this || this.IsSelfReplicatingRoot, "Task.AddNewChild(): Called from an external context");
+ Debug.Assert(Task.InternalCurrent == this, "Task.AddNewChild(): Called from an external context");
var props = EnsureContingentPropertiesInitialized();
- if (props.m_completionCountdown == 1 && !IsSelfReplicatingRoot)
+ if (props.m_completionCountdown == 1)
{
// A count of 1 indicates so far there was only the parent, and this is the first child task
// Single kid => no fuss about who else is accessing the count. Let's save ourselves 100 cycles
- // We exclude self replicating root tasks from this optimization, because further child creation can take place on
- // other cores and with bad enough timing this write may not be visible to them.
props.m_completionCountdown++;
}
else
@@ -1264,7 +1202,7 @@ namespace System.Threading.Tasks
// Implicitly converts action to object and handles the meat of the StartNew() logic.
internal static Task InternalStartNew(
Task creatingTask, Delegate action, object state, CancellationToken cancellationToken, TaskScheduler scheduler,
- TaskCreationOptions options, InternalTaskOptions internalOptions, ref StackCrawlMark stackMark)
+ TaskCreationOptions options, InternalTaskOptions internalOptions)
{
// Validate arguments.
if (scheduler == null)
@@ -1276,7 +1214,6 @@ namespace System.Threading.Tasks
// Create and schedule the task. This throws an InvalidOperationException if already shut down.
// Here we add the InternalTaskOptions.QueuedByRuntime to the internalOptions, so that TaskConstructorCore can skip the cancellation token registration
Task t = new Task(action, state, creatingTask, cancellationToken, options, internalOptions | InternalTaskOptions.QueuedByRuntime, scheduler);
- t.PossiblyCaptureContext(ref stackMark);
t.ScheduleAndStart(false);
return t;
@@ -1615,23 +1552,10 @@ namespace System.Threading.Tasks
/// of <see cref="System.Threading.Tasks.TaskFactory"/>, as would result from using
/// the default constructor on TaskFactory.
/// </remarks>
- public static TaskFactory Factory { get { return s_factory; } }
-
- /// <summary>A task that's already been completed successfully.</summary>
- private static Task s_completedTask;
+ public static TaskFactory Factory { get; } = new TaskFactory();
/// <summary>Gets a task that's already been completed successfully.</summary>
- /// <remarks>May not always return the same instance.</remarks>
- public static Task CompletedTask
- {
- get
- {
- var completedTask = s_completedTask;
- if (completedTask == null)
- s_completedTask = completedTask = new Task(false, (TaskCreationOptions)InternalTaskOptions.DoNotDispose, default(CancellationToken)); // benign initialization race condition
- return completedTask;
- }
- }
+ public static Task CompletedTask { get; } = new Task(false, (TaskCreationOptions)InternalTaskOptions.DoNotDispose, default(CancellationToken));
/// <summary>
/// Provides an event that can be used to wait for completion.
@@ -1663,35 +1587,6 @@ namespace System.Threading.Tasks
}
}
- /// <summary>
- /// Determines whether this is the root task of a self replicating group.
- /// </summary>
- internal bool IsSelfReplicatingRoot
- {
- get
- {
- // Return true if self-replicating bit is set and child replica bit is not set
- return (Options & (TaskCreationOptions)(InternalTaskOptions.SelfReplicating | InternalTaskOptions.ChildReplica))
- == (TaskCreationOptions)InternalTaskOptions.SelfReplicating;
- }
- }
-
- /// <summary>
- /// Determines whether the task is a replica itself.
- /// </summary>
- internal bool IsChildReplica
- {
- get { return (Options & (TaskCreationOptions)InternalTaskOptions.ChildReplica) != 0; }
- }
-
- internal int ActiveChildCount
- {
- get
- {
- var props = Volatile.Read(ref m_contingentProperties);
- return props != null ? props.m_completionCountdown - 1 : 0;
- }
- }
/// <summary>
/// The property formerly known as IsFaulted.
@@ -1737,7 +1632,7 @@ namespace System.Threading.Tasks
}
else
{
- return m_contingentProperties?.m_capturedContext ?? ExecutionContext.PreAllocatedDefault;
+ return m_contingentProperties?.m_capturedContext ?? ExecutionContext.Default;
}
}
set
@@ -1747,7 +1642,7 @@ namespace System.Threading.Tasks
{
m_stateFlags |= TASK_STATE_EXECUTIONCONTEXT_IS_NULL;
}
- else if (!value.IsPreAllocatedDefault) // not the default context, then inflate the contingent properties and set it
+ else if (value != ExecutionContext.Default) // not the default context, then inflate the contingent properties and set it
{
EnsureContingentPropertiesInitializedUnsafe().m_capturedContext = value;
}
@@ -1755,32 +1650,6 @@ namespace System.Threading.Tasks
}
}
- /// <summary>
- /// Static helper function to copy specific ExecutionContext
- /// </summary>
- /// <param name="capturedContext">The captured context</param>
- /// <returns>The copied context, null if the capturedContext is null</returns>
- private static ExecutionContext CopyExecutionContext(ExecutionContext capturedContext)
- {
- if (capturedContext == null)
- return null;
- if (capturedContext.IsPreAllocatedDefault)
- return ExecutionContext.PreAllocatedDefault;
-
- return capturedContext.CreateCopy();
- }
-
-
-#if DEBUG
- /// <summary>
- /// Retrieves an identifier for the task.
- /// </summary>
- internal int InternalId
- {
- get { return GetHashCode(); }
- }
-#endif
-
/////////////
// methods
@@ -1920,7 +1789,7 @@ namespace System.Threading.Tasks
catch (ThreadAbortException tae)
{
AddException(tae);
- FinishThreadAbortedTask(true, false);
+ FinishThreadAbortedTask(delegateRan:false);
}
catch (Exception e)
{
@@ -1930,10 +1799,10 @@ namespace System.Threading.Tasks
AddException(tse);
Finish(false);
- // Now we need to mark ourselves as "handled" to avoid crashing the finalizer thread if we are called from StartNew()
- // or from the self replicating logic, because in both cases the exception is either propagated outside directly, or added
- // to an enclosing parent. However we won't do this for continuation tasks, because in that case we internally eat the exception
- // and therefore we need to make sure the user does later observe it explicitly or see it on the finalizer.
+ // Now we need to mark ourselves as "handled" to avoid crashing the finalizer thread if we are called from StartNew(),
+ // because the exception is either propagated outside directly, or added to an enclosing parent. However we won't do this for
+ // continuation tasks, because in that case we internally eat the exception and therefore we need to make sure the user does
+ // later observe it explicitly or see it on the finalizer.
if ((Options & (TaskCreationOptions)InternalTaskOptions.ContinuationTask) == 0)
{
@@ -2192,11 +2061,9 @@ namespace System.Threading.Tasks
var props = Volatile.Read(ref m_contingentProperties);
if (props == null || // no contingent properties means no children, so it's safe to complete ourselves
- (props.m_completionCountdown == 1 && !IsSelfReplicatingRoot) ||
+ (props.m_completionCountdown == 1) ||
// Count of 1 => either all children finished, or there were none. Safe to complete ourselves
// without paying the price of an Interlocked.Decrement.
- // However we need to exclude self replicating root tasks from this optimization, because
- // they can have children joining in, or finishing even after the root task delegate is done.
Interlocked.Decrement(ref props.m_completionCountdown) == 0) // Reaching this sub clause means there may be remaining active children,
// and we could be racing with one of them to call FinishStageTwo().
// So whoever does the final Interlocked.Dec is responsible to finish.
@@ -2424,19 +2291,13 @@ namespace System.Threading.Tasks
/// This makes a note in the state flags so that we avoid any costly synchronous operations in the finish codepath
/// such as inlined continuations
/// </summary>
- /// <param name="bTAEAddedToExceptionHolder">
- /// Indicates whether the ThreadAbortException was added to this task's exception holder.
- /// This should always be true except for the case of non-root self replicating task copies.
- /// </param>
/// <param name="delegateRan">Whether the delegate was executed.</param>
- internal void FinishThreadAbortedTask(bool bTAEAddedToExceptionHolder, bool delegateRan)
+ internal void FinishThreadAbortedTask(bool delegateRan)
{
- Debug.Assert(!bTAEAddedToExceptionHolder || m_contingentProperties?.m_exceptionsHolder != null,
- "FinishThreadAbortedTask() called on a task whose exception holder wasn't initialized");
+ Debug.Assert(m_contingentProperties?.m_exceptionsHolder != null,
+ "FinishThreadAbortedTask() called on a task whose exception holder wasn't initialized");
- // this will only be false for non-root self replicating task copies, because all of their exceptions go to the root task.
- if (bTAEAddedToExceptionHolder)
- m_contingentProperties.m_exceptionsHolder.MarkAsHandled(false);
+ m_contingentProperties.m_exceptionsHolder.MarkAsHandled(false);
// If this method has already been called for this task, or if this task has already completed, then
// return before actually calling Finish().
@@ -2447,220 +2308,33 @@ namespace System.Threading.Tasks
}
Finish(delegateRan);
-
}
/// <summary>
- /// Executes the task. This method will only be called once, and handles bookeeping associated with
- /// self-replicating tasks, in addition to performing necessary exception marshaling.
+ /// Executes the task. This method will only be called once, and handles any necessary exception marshaling.
/// </summary>
private void Execute()
{
- if (IsSelfReplicatingRoot)
+ try
{
- ExecuteSelfReplicating(this);
+ InnerInvoke();
}
- else
+ catch (ThreadAbortException tae)
{
- try
- {
- InnerInvoke();
- }
- catch (ThreadAbortException tae)
- {
- // Don't record the TAE or call FinishThreadAbortedTask for a child replica task --
- // it's already been done downstream.
- if (!IsChildReplica)
- {
- // Record this exception in the task's exception list
- HandleException(tae);
+ // Record this exception in the task's exception list
+ HandleException(tae);
- // This is a ThreadAbortException and it will be rethrown from this catch clause, causing us to
- // skip the regular Finish codepath. In order not to leave the task unfinished, we now call
- // FinishThreadAbortedTask here.
- FinishThreadAbortedTask(true, true);
- }
- }
- catch (Exception exn)
- {
- // Record this exception in the task's exception list
- HandleException(exn);
- }
+ // This is a ThreadAbortException and it will be rethrown from this catch clause, causing us to
+ // skip the regular Finish codepath. In order not to leave the task unfinished, we now call
+ // FinishThreadAbortedTask here.
+ FinishThreadAbortedTask(delegateRan: true);
}
- }
-
- // Allows (internal) deriving classes to support limited replication.
- // (By default, replication is basically unlimited).
- internal virtual bool ShouldReplicate()
- {
- return true;
- }
-
- // Allows (internal) deriving classes to instantiate the task replica as a Task super class of their choice
- // (By default, we create a regular Task instance)
- internal virtual Task CreateReplicaTask(Action<object> taskReplicaDelegate, Object stateObject, Task parentTask, TaskScheduler taskScheduler,
- TaskCreationOptions creationOptionsForReplica, InternalTaskOptions internalOptionsForReplica)
- {
- return new Task(taskReplicaDelegate, stateObject, parentTask, default(CancellationToken),
- creationOptionsForReplica, internalOptionsForReplica, parentTask.ExecutingTaskScheduler);
- }
-
- // Allows internal deriving classes to support replicas that exit prematurely and want to pass on state to the next replica
- internal virtual Object SavedStateForNextReplica
- {
- get { return null; }
-
- set { /*do nothing*/ }
- }
-
- // Allows internal deriving classes to support replicas that exit prematurely and want to pass on state to the next replica
- internal virtual Object SavedStateFromPreviousReplica
- {
- get { return null; }
-
- set { /*do nothing*/ }
- }
-
- // Allows internal deriving classes to support replicas that exit prematurely and want to hand over the child replica that they
- // had queued, so that the replacement replica can work with that child task instead of queuing up yet another one
- internal virtual Task HandedOverChildReplica
- {
- get { return null; }
-
- set { /* do nothing*/ }
- }
-
- private static void ExecuteSelfReplicating(Task root)
- {
- TaskCreationOptions creationOptionsForReplicas = root.CreationOptions | TaskCreationOptions.AttachedToParent;
- InternalTaskOptions internalOptionsForReplicas =
- InternalTaskOptions.ChildReplica | // child replica flag disables self replication for the replicas themselves.
- InternalTaskOptions.SelfReplicating | // we still want to identify this as part of a self replicating group
- InternalTaskOptions.QueuedByRuntime; // we queue and cancel these tasks internally, so don't allow CT registration to take place
-
-
- // Important Note: The child replicas we launch from here will be attached the root replica (by virtue of the root.CreateReplicaTask call)
- // because we need the root task to receive all their exceptions, and to block until all of them return
-
-
- // This variable is captured in a closure and shared among all replicas.
- bool replicasAreQuitting = false;
-
- // Set up a delegate that will form the body of the root and all recursively created replicas.
- Action<object> taskReplicaDelegate = null;
- taskReplicaDelegate = delegate
+ catch (Exception exn)
{
- Task currentTask = Task.InternalCurrent;
-
-
- // Check if a child task has been handed over by a prematurely quiting replica that we might be a replacement for.
- Task childTask = currentTask.HandedOverChildReplica;
-
- if (childTask == null)
- {
- // Apparently we are not a replacement task. This means we need to queue up a child task for replication to progress
-
- // Down-counts a counter in the root task.
- if (!root.ShouldReplicate()) return;
-
- // If any of the replicas have quit, we will do so ourselves.
- if (Volatile.Read(ref replicasAreQuitting))
- {
- return;
- }
-
- // Propagate a copy of the context from the root task. It may be null if flow was suppressed.
- ExecutionContext creatorContext = root.CapturedContext;
-
-
- childTask = root.CreateReplicaTask(taskReplicaDelegate, root.m_stateObject, root, root.ExecutingTaskScheduler,
- creationOptionsForReplicas, internalOptionsForReplicas);
-
- childTask.CapturedContext = CopyExecutionContext(creatorContext);
-
- childTask.ScheduleAndStart(false);
- }
-
-
-
- // Finally invoke the meat of the task.
- // Note that we are directly calling root.InnerInvoke() even though we are currently be in the action delegate of a child replica
- // This is because the actual work was passed down in that delegate, and the action delegate of the child replica simply contains this
- // replication control logic.
- try
- {
- // passing in currentTask only so that the parallel debugger can find it
- root.InnerInvokeWithArg(currentTask);
- }
- catch (Exception exn)
- {
- // Record this exception in the root task's exception list
- root.HandleException(exn);
-
- if (exn is ThreadAbortException)
- {
- // If this is a ThreadAbortException it will escape this catch clause, causing us to skip the regular Finish codepath
- // In order not to leave the task unfinished, we now call FinishThreadAbortedTask here
- currentTask.FinishThreadAbortedTask(false, true);
- }
- }
-
- Object savedState = currentTask.SavedStateForNextReplica;
-
- // check for premature exit
- if (savedState != null)
- {
- // the replica decided to exit early
- // we need to queue up a replacement, attach the saved state, and yield the thread right away
-
- Task replacementReplica = root.CreateReplicaTask(taskReplicaDelegate, root.m_stateObject, root, root.ExecutingTaskScheduler,
- creationOptionsForReplicas, internalOptionsForReplicas);
-
- // Propagate a copy of the context from the root task to the replacement task
- ExecutionContext creatorContext = root.CapturedContext;
- replacementReplica.CapturedContext = CopyExecutionContext(creatorContext);
-
- replacementReplica.HandedOverChildReplica = childTask;
- replacementReplica.SavedStateFromPreviousReplica = savedState;
-
- replacementReplica.ScheduleAndStart(false);
- }
- else
- {
- // The replica finished normally, which means it can't find more work to grab.
- // Time to mark replicas quitting
-
- replicasAreQuitting = true;
-
- // InternalCancel() could conceivably throw in the underlying scheduler's TryDequeue() method.
- // If it does, then make sure that we record it.
- try
- {
- childTask.InternalCancel(true);
- }
- catch (Exception e)
- {
- // Apparently TryDequeue threw an exception. Before propagating that exception, InternalCancel should have
- // attempted an atomic state transition and a call to CancellationCleanupLogic() on this task. So we know
- // the task was properly cleaned up if it was possible.
- //
- // Now all we need to do is to Record the exception in the root task.
-
- root.HandleException(e);
- }
-
- // No specific action needed if the child could not be canceled
- // because we attached it to the root task, which should therefore be receiving any exceptions from the child,
- // and root.wait will not return before this child finishes anyway.
-
- }
- };
-
- //
- // Now we execute as the root task
- //
- taskReplicaDelegate(null);
+ // Record this exception in the task's exception list
+ HandleException(exn);
+ }
}
/// <summary>
@@ -2683,7 +2357,7 @@ namespace System.Threading.Tasks
if (!IsCompleted)
{
HandleException(tae);
- FinishThreadAbortedTask(true, false);
+ FinishThreadAbortedTask(delegateRan:false);
}
}
@@ -2693,10 +2367,10 @@ namespace System.Threading.Tasks
///
/// </summary>
/// <param name="bPreventDoubleExecution"> Performs atomic updates to prevent double execution. Should only be set to true
- /// in codepaths servicing user provided TaskSchedulers. The ConcRT or ThreadPool schedulers don't need this. </param>
+ /// in codepaths servicing user provided TaskSchedulers. The ThreadPool scheduler doesn't need this. </param>
internal bool ExecuteEntry(bool bPreventDoubleExecution)
{
- if (bPreventDoubleExecution || ((Options & (TaskCreationOptions)InternalTaskOptions.SelfReplicating) != 0))
+ if (bPreventDoubleExecution)
{
int previousState = 0;
@@ -2772,18 +2446,10 @@ namespace System.Threading.Tasks
}
else
{
- if (IsSelfReplicatingRoot || IsChildReplica)
- {
- CapturedContext = CopyExecutionContext(ec);
- }
-
// Run the task. We need a simple shim that converts the
// object back into a Task object, so that we can Execute it.
- // Lazily initialize the callback delegate; benign race condition
- var callback = s_ecCallback;
- if (callback == null) s_ecCallback = callback = new ContextCallback(ExecutionContextCallback);
- ExecutionContext.Run(ec, callback, this, true);
+ ExecutionContext.Run(ec, s_ecCallback, this);
}
if (AsyncCausalityTracer.LoggingOn)
@@ -2810,16 +2476,7 @@ namespace System.Threading.Tasks
}
}
- // Cached callback delegate that's lazily initialized due to ContextCallback being SecurityCritical
- private static ContextCallback s_ecCallback;
-
- private static void ExecutionContextCallback(object obj)
- {
- Task task = obj as Task;
- Debug.Assert(task != null, "expected a task object");
- task.Execute();
- }
-
+ private static readonly ContextCallback s_ecCallback = obj => ((Task)obj).Execute();
/// <summary>
/// The actual code which invokes the body of the task. This can be overriden in derived types.
@@ -2844,21 +2501,6 @@ namespace System.Threading.Tasks
}
/// <summary>
- /// Alternate InnerInvoke prototype to be called from ExecuteSelfReplicating() so that
- /// the Parallel Debugger can discover the actual task being invoked.
- /// Details: Here, InnerInvoke is actually being called on the rootTask object while we are actually executing the
- /// childTask. And the debugger needs to discover the childTask, so we pass that down as an argument.
- /// The NoOptimization and NoInlining flags ensure that the childTask pointer is retained, and that this
- /// function appears on the callstack.
- /// </summary>
- /// <param name="childTask"></param>
- [MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
- internal void InnerInvokeWithArg(Task childTask)
- {
- InnerInvoke();
- }
-
- /// <summary>
/// Performs whatever handling is necessary for an unhandled exception. Normally
/// this just entails adding the exception to the holder object.
/// </summary>
@@ -2917,10 +2559,9 @@ namespace System.Threading.Tasks
/// true to attempt to marshal the continuation back to the original context captured; otherwise, false.
/// </param>
/// <param name="flowExecutionContext">Whether to flow ExecutionContext across the await.</param>
- /// <param name="stackMark">A stack crawl mark tied to execution context.</param>
/// <exception cref="System.InvalidOperationException">The awaiter was not properly initialized.</exception>
internal void SetContinuationForAwait(
- Action continuationAction, bool continueOnCapturedContext, bool flowExecutionContext, ref StackCrawlMark stackMark)
+ Action continuationAction, bool continueOnCapturedContext, bool flowExecutionContext)
{
Contract.Requires(continuationAction != null);
@@ -2941,7 +2582,7 @@ namespace System.Threading.Tasks
var syncCtx = SynchronizationContext.CurrentNoFlow;
if (syncCtx != null && syncCtx.GetType() != typeof(SynchronizationContext))
{
- tc = new SynchronizationContextAwaitTaskContinuation(syncCtx, continuationAction, flowExecutionContext, ref stackMark);
+ tc = new SynchronizationContextAwaitTaskContinuation(syncCtx, continuationAction, flowExecutionContext);
}
else
{
@@ -2950,7 +2591,7 @@ namespace System.Threading.Tasks
var scheduler = TaskScheduler.InternalCurrent;
if (scheduler != null && scheduler != TaskScheduler.Default)
{
- tc = new TaskSchedulerAwaitTaskContinuation(scheduler, continuationAction, flowExecutionContext, ref stackMark);
+ tc = new TaskSchedulerAwaitTaskContinuation(scheduler, continuationAction, flowExecutionContext);
}
}
}
@@ -2962,7 +2603,7 @@ namespace System.Threading.Tasks
// ExecutionContext, we need to capture it and wrap it in an AwaitTaskContinuation.
// Otherwise, we're targeting the default scheduler and we don't need to flow ExecutionContext, so
// we don't actually need a continuation object. We can just store/queue the action itself.
- tc = new AwaitTaskContinuation(continuationAction, flowExecutionContext: true, stackMark: ref stackMark);
+ tc = new AwaitTaskContinuation(continuationAction, flowExecutionContext: true);
}
// Now register the continuation, and if we couldn't register it because the task is already completing,
@@ -3190,7 +2831,7 @@ namespace System.Threading.Tasks
Task currentTask = Task.InternalCurrent;
etwLog.TaskWaitBegin(
(currentTask != null ? currentTask.m_taskScheduler.Id : TaskScheduler.Default.Id), (currentTask != null ? currentTask.Id : 0),
- this.Id, TplEtwProvider.TaskWaitBehavior.Synchronous, 0, System.Threading.Thread.GetDomainID());
+ this.Id, TplEtwProvider.TaskWaitBehavior.Synchronous, 0);
}
bool returnValue = IsCompleted;
@@ -3377,7 +3018,7 @@ namespace System.Threading.Tasks
}
}
- bool bRequiresAtomicStartTransition = (ts != null && ts.RequiresAtomicStartTransition) || ((Options & (TaskCreationOptions)InternalTaskOptions.SelfReplicating) != 0);
+ bool bRequiresAtomicStartTransition = ts != null && ts.RequiresAtomicStartTransition;
if (!bPopSucceeded && bCancelNonExecutingOnly && bRequiresAtomicStartTransition)
{
@@ -3715,11 +3356,9 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ArgumentNullException">
/// The <paramref name="continuationAction"/> argument is null.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task ContinueWith(Action<Task> continuationAction)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith(continuationAction, TaskScheduler.Current, default(CancellationToken), TaskContinuationOptions.None, ref stackMark);
+ return ContinueWith(continuationAction, TaskScheduler.Current, default(CancellationToken), TaskContinuationOptions.None);
}
/// <summary>
@@ -3742,11 +3381,9 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
/// has already been disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task ContinueWith(Action<Task> continuationAction, CancellationToken cancellationToken)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith(continuationAction, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None, ref stackMark);
+ return ContinueWith(continuationAction, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None);
}
/// <summary>
@@ -3771,11 +3408,9 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ArgumentNullException">
/// The <paramref name="scheduler"/> argument is null.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task ContinueWith(Action<Task> continuationAction, TaskScheduler scheduler)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith(continuationAction, scheduler, default(CancellationToken), TaskContinuationOptions.None, ref stackMark);
+ return ContinueWith(continuationAction, scheduler, default(CancellationToken), TaskContinuationOptions.None);
}
/// <summary>
@@ -3806,11 +3441,9 @@ namespace System.Threading.Tasks
/// The <paramref name="continuationOptions"/> argument specifies an invalid value for <see
/// cref="T:System.Threading.Tasks.TaskContinuationOptions">TaskContinuationOptions</see>.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task ContinueWith(Action<Task> continuationAction, TaskContinuationOptions continuationOptions)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith(continuationAction, TaskScheduler.Current, default(CancellationToken), continuationOptions, ref stackMark);
+ return ContinueWith(continuationAction, TaskScheduler.Current, default(CancellationToken), continuationOptions);
}
/// <summary>
@@ -3851,17 +3484,15 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
/// has already been disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task ContinueWith(Action<Task> continuationAction, CancellationToken cancellationToken,
TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith(continuationAction, scheduler, cancellationToken, continuationOptions, ref stackMark);
+ return ContinueWith(continuationAction, scheduler, cancellationToken, continuationOptions);
}
// Same as the above overload, just with a stack mark parameter.
private Task ContinueWith(Action<Task> continuationAction, TaskScheduler scheduler,
- CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, ref StackCrawlMark stackMark)
+ CancellationToken cancellationToken, TaskContinuationOptions continuationOptions)
{
// Throw on continuation with null action
if (continuationAction == null)
@@ -3882,8 +3513,7 @@ namespace System.Threading.Tasks
Task continuationTask = new ContinuationTaskFromTask(
this, continuationAction, null,
- creationOptions, internalOptions,
- ref stackMark
+ creationOptions, internalOptions
);
// Register the continuation. If synchronous execution is requested, this may
@@ -3913,11 +3543,9 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ArgumentNullException">
/// The <paramref name="continuationAction"/> argument is null.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task ContinueWith(Action<Task, Object> continuationAction, Object state)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith(continuationAction, state, TaskScheduler.Current, default(CancellationToken), TaskContinuationOptions.None, ref stackMark);
+ return ContinueWith(continuationAction, state, TaskScheduler.Current, default(CancellationToken), TaskContinuationOptions.None);
}
/// <summary>
@@ -3941,11 +3569,9 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
/// has already been disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task ContinueWith(Action<Task, Object> continuationAction, Object state, CancellationToken cancellationToken)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith(continuationAction, state, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None, ref stackMark);
+ return ContinueWith(continuationAction, state, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None);
}
/// <summary>
@@ -3971,11 +3597,9 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ArgumentNullException">
/// The <paramref name="scheduler"/> argument is null.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task ContinueWith(Action<Task, Object> continuationAction, Object state, TaskScheduler scheduler)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith(continuationAction, state, scheduler, default(CancellationToken), TaskContinuationOptions.None, ref stackMark);
+ return ContinueWith(continuationAction, state, scheduler, default(CancellationToken), TaskContinuationOptions.None);
}
/// <summary>
@@ -4007,11 +3631,9 @@ namespace System.Threading.Tasks
/// The <paramref name="continuationOptions"/> argument specifies an invalid value for <see
/// cref="T:System.Threading.Tasks.TaskContinuationOptions">TaskContinuationOptions</see>.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task ContinueWith(Action<Task, Object> continuationAction, Object state, TaskContinuationOptions continuationOptions)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith(continuationAction, state, TaskScheduler.Current, default(CancellationToken), continuationOptions, ref stackMark);
+ return ContinueWith(continuationAction, state, TaskScheduler.Current, default(CancellationToken), continuationOptions);
}
/// <summary>
@@ -4053,17 +3675,15 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
/// has already been disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task ContinueWith(Action<Task, Object> continuationAction, Object state, CancellationToken cancellationToken,
TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith(continuationAction, state, scheduler, cancellationToken, continuationOptions, ref stackMark);
+ return ContinueWith(continuationAction, state, scheduler, cancellationToken, continuationOptions);
}
// Same as the above overload, just with a stack mark parameter.
private Task ContinueWith(Action<Task, Object> continuationAction, Object state, TaskScheduler scheduler,
- CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, ref StackCrawlMark stackMark)
+ CancellationToken cancellationToken, TaskContinuationOptions continuationOptions)
{
// Throw on continuation with null action
if (continuationAction == null)
@@ -4084,8 +3704,7 @@ namespace System.Threading.Tasks
Task continuationTask = new ContinuationTaskFromTask(
this, continuationAction, state,
- creationOptions, internalOptions,
- ref stackMark
+ creationOptions, internalOptions
);
// Register the continuation. If synchronous execution is requested, this may
@@ -4118,12 +3737,10 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ArgumentNullException">
/// The <paramref name="continuationFunction"/> argument is null.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWith<TResult>(Func<Task, TResult> continuationFunction)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
return ContinueWith<TResult>(continuationFunction, TaskScheduler.Current, default(CancellationToken),
- TaskContinuationOptions.None, ref stackMark);
+ TaskContinuationOptions.None);
}
@@ -4150,11 +3767,9 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
/// has already been disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWith<TResult>(Func<Task, TResult> continuationFunction, CancellationToken cancellationToken)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith<TResult>(continuationFunction, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None, ref stackMark);
+ return ContinueWith<TResult>(continuationFunction, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None);
}
/// <summary>
@@ -4182,11 +3797,9 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ArgumentNullException">
/// The <paramref name="scheduler"/> argument is null.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWith<TResult>(Func<Task, TResult> continuationFunction, TaskScheduler scheduler)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith<TResult>(continuationFunction, scheduler, default(CancellationToken), TaskContinuationOptions.None, ref stackMark);
+ return ContinueWith<TResult>(continuationFunction, scheduler, default(CancellationToken), TaskContinuationOptions.None);
}
/// <summary>
@@ -4220,11 +3833,9 @@ namespace System.Threading.Tasks
/// The <paramref name="continuationOptions"/> argument specifies an invalid value for <see
/// cref="T:System.Threading.Tasks.TaskContinuationOptions">TaskContinuationOptions</see>.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWith<TResult>(Func<Task, TResult> continuationFunction, TaskContinuationOptions continuationOptions)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith<TResult>(continuationFunction, TaskScheduler.Current, default(CancellationToken), continuationOptions, ref stackMark);
+ return ContinueWith<TResult>(continuationFunction, TaskScheduler.Current, default(CancellationToken), continuationOptions);
}
/// <summary>
@@ -4268,17 +3879,15 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
/// has already been disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWith<TResult>(Func<Task, TResult> continuationFunction, CancellationToken cancellationToken,
TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith<TResult>(continuationFunction, scheduler, cancellationToken, continuationOptions, ref stackMark);
+ return ContinueWith<TResult>(continuationFunction, scheduler, cancellationToken, continuationOptions);
}
// Same as the above overload, just with a stack mark parameter.
private Task<TResult> ContinueWith<TResult>(Func<Task, TResult> continuationFunction, TaskScheduler scheduler,
- CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, ref StackCrawlMark stackMark)
+ CancellationToken cancellationToken, TaskContinuationOptions continuationOptions)
{
// Throw on continuation with null function
if (continuationFunction == null)
@@ -4299,8 +3908,7 @@ namespace System.Threading.Tasks
Task<TResult> continuationTask = new ContinuationResultTaskFromTask<TResult>(
this, continuationFunction, null,
- creationOptions, internalOptions,
- ref stackMark
+ creationOptions, internalOptions
);
// Register the continuation. If synchronous execution is requested, this may
@@ -4333,12 +3941,10 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ArgumentNullException">
/// The <paramref name="continuationFunction"/> argument is null.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWith<TResult>(Func<Task, Object, TResult> continuationFunction, Object state)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
return ContinueWith<TResult>(continuationFunction, state, TaskScheduler.Current, default(CancellationToken),
- TaskContinuationOptions.None, ref stackMark);
+ TaskContinuationOptions.None);
}
@@ -4366,11 +3972,9 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
/// has already been disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWith<TResult>(Func<Task, Object, TResult> continuationFunction, Object state, CancellationToken cancellationToken)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith<TResult>(continuationFunction, state, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None, ref stackMark);
+ return ContinueWith<TResult>(continuationFunction, state, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None);
}
/// <summary>
@@ -4399,11 +4003,9 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ArgumentNullException">
/// The <paramref name="scheduler"/> argument is null.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWith<TResult>(Func<Task, Object, TResult> continuationFunction, Object state, TaskScheduler scheduler)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith<TResult>(continuationFunction, state, scheduler, default(CancellationToken), TaskContinuationOptions.None, ref stackMark);
+ return ContinueWith<TResult>(continuationFunction, state, scheduler, default(CancellationToken), TaskContinuationOptions.None);
}
/// <summary>
@@ -4438,11 +4040,9 @@ namespace System.Threading.Tasks
/// The <paramref name="continuationOptions"/> argument specifies an invalid value for <see
/// cref="T:System.Threading.Tasks.TaskContinuationOptions">TaskContinuationOptions</see>.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWith<TResult>(Func<Task, Object, TResult> continuationFunction, Object state, TaskContinuationOptions continuationOptions)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith<TResult>(continuationFunction, state, TaskScheduler.Current, default(CancellationToken), continuationOptions, ref stackMark);
+ return ContinueWith<TResult>(continuationFunction, state, TaskScheduler.Current, default(CancellationToken), continuationOptions);
}
/// <summary>
@@ -4487,17 +4087,15 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
/// has already been disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWith<TResult>(Func<Task, Object, TResult> continuationFunction, Object state, CancellationToken cancellationToken,
TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith<TResult>(continuationFunction, state, scheduler, cancellationToken, continuationOptions, ref stackMark);
+ return ContinueWith<TResult>(continuationFunction, state, scheduler, cancellationToken, continuationOptions);
}
// Same as the above overload, just with a stack mark parameter.
private Task<TResult> ContinueWith<TResult>(Func<Task, Object, TResult> continuationFunction, Object state, TaskScheduler scheduler,
- CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, ref StackCrawlMark stackMark)
+ CancellationToken cancellationToken, TaskContinuationOptions continuationOptions)
{
// Throw on continuation with null function
if (continuationFunction == null)
@@ -4518,8 +4116,7 @@ namespace System.Threading.Tasks
Task<TResult> continuationTask = new ContinuationResultTaskFromTask<TResult>(
this, continuationFunction, state,
- creationOptions, internalOptions,
- ref stackMark
+ creationOptions, internalOptions
);
// Register the continuation. If synchronous execution is requested, this may
@@ -5207,49 +4804,6 @@ namespace System.Threading.Tasks
}
/// <summary>
- /// Internal WaitAll implementation which is meant to be used with small number of tasks,
- /// optimized for Parallel.Invoke and other structured primitives.
- /// </summary>
- internal static void FastWaitAll(Task[] tasks)
- {
- Contract.Requires(tasks != null);
-
- List<Exception> exceptions = null;
-
- // Collects incomplete tasks in "waitedOnTaskList" and their cooperative events in "cooperativeEventList"
- for (int i = tasks.Length - 1; i >= 0; i--)
- {
- if (!tasks[i].IsCompleted)
- {
- // Just attempting to inline here... result doesn't matter.
- // We'll do a second pass to do actual wait on each task, and to aggregate their exceptions.
- // If the task is inlined here, it will register as IsCompleted in the second pass
- // and will just give us the exception.
- tasks[i].WrappedTryRunInline();
- }
- }
-
- // Wait on the tasks.
- for (int i = tasks.Length - 1; i >= 0; i--)
- {
- var task = tasks[i];
- task.SpinThenBlockingWait(Timeout.Infinite, default(CancellationToken));
- AddExceptionsForCompletedTask(ref exceptions, task);
-
- // Note that unlike other wait code paths, we do not check
- // task.NotifyDebuggerOfWaitCompletionIfNecessary() here, because this method is currently
- // only used from contexts where the tasks couldn't have that bit set, namely
- // Parallel.Invoke. If that ever changes, such checks should be added here.
- }
-
- // If one or more threw exceptions, aggregate them.
- if (exceptions != null)
- {
- ThrowHelper.ThrowAggregateException(exceptions);
- }
- }
-
- /// <summary>
/// This internal function is only meant to be called by WaitAll()
/// If the completed task is canceled or it has other exceptions, here we will add those
/// into the passed in exception list (which will be lazily initialized here).
@@ -5582,12 +5136,10 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ArgumentNullException">
/// The <paramref name="action"/> parameter was null.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public static Task Run(Action action)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
return Task.InternalStartNew(null, action, null, default(CancellationToken), TaskScheduler.Default,
- TaskCreationOptions.DenyChildAttach, InternalTaskOptions.None, ref stackMark);
+ TaskCreationOptions.DenyChildAttach, InternalTaskOptions.None);
}
/// <summary>
@@ -5602,12 +5154,10 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">
/// The <see cref="T:System.CancellationTokenSource"/> associated with <paramref name="cancellationToken"/> was disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public static Task Run(Action action, CancellationToken cancellationToken)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
return Task.InternalStartNew(null, action, null, cancellationToken, TaskScheduler.Default,
- TaskCreationOptions.DenyChildAttach, InternalTaskOptions.None, ref stackMark);
+ TaskCreationOptions.DenyChildAttach, InternalTaskOptions.None);
}
/// <summary>
@@ -5618,12 +5168,10 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ArgumentNullException">
/// The <paramref name="function"/> parameter was null.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public static Task<TResult> Run<TResult>(Func<TResult> function)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
return Task<TResult>.StartNew(null, function, default(CancellationToken),
- TaskCreationOptions.DenyChildAttach, InternalTaskOptions.None, TaskScheduler.Default, ref stackMark);
+ TaskCreationOptions.DenyChildAttach, InternalTaskOptions.None, TaskScheduler.Default);
}
/// <summary>
@@ -5638,12 +5186,10 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">
/// The <see cref="T:System.CancellationTokenSource"/> associated with <paramref name="cancellationToken"/> was disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public static Task<TResult> Run<TResult>(Func<TResult> function, CancellationToken cancellationToken)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
return Task<TResult>.StartNew(null, function, cancellationToken,
- TaskCreationOptions.DenyChildAttach, InternalTaskOptions.None, TaskScheduler.Default, ref stackMark);
+ TaskCreationOptions.DenyChildAttach, InternalTaskOptions.None, TaskScheduler.Default);
}
/// <summary>
@@ -6693,102 +6239,6 @@ namespace System.Threading.Tasks
public TaskStatus Status { get { return m_task.Status; } }
}
- // Special purpose derivation of Task that supports limited replication through
- // overriding the ShouldReplicate() method. This is used by the Parallel.For/ForEach
- // methods.
- internal class ParallelForReplicatingTask : Task
- {
- // Member variables
- private int m_replicationDownCount; // downcounter to control replication
-
- //
- // Constructors
- //
-
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
- internal ParallelForReplicatingTask(
- ParallelOptions parallelOptions, Action action, TaskCreationOptions creationOptions, InternalTaskOptions internalOptions)
- : base(action, null, Task.InternalCurrent, default(CancellationToken), creationOptions, internalOptions | InternalTaskOptions.SelfReplicating, null)
- {
- // Compute the down count based on scheduler/DOP info in parallelOptions.
- m_replicationDownCount = parallelOptions.EffectiveMaxConcurrencyLevel;
-
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- PossiblyCaptureContext(ref stackMark);
- }
-
-
- // Controls degree of replication. If downcounter is initialized to -1, then
- // replication will be allowed to "run wild". Otherwise, this method decrements
- // the downcounter each time it is called, calling false when it is called with
- // a zero downcounter. This method returning false effectively ends the replication
- // of the associated ParallelForReplicatingTask.
- internal override bool ShouldReplicate()
- {
- if (m_replicationDownCount == -1) return true; // "run wild"
-
- if (m_replicationDownCount > 0) // Decrement and return true if not called with 0 downcount
- {
- m_replicationDownCount--;
- return true;
- }
-
- return false; // We're done replicating
- }
-
- internal override Task CreateReplicaTask(Action<object> taskReplicaDelegate, Object stateObject, Task parentTask, TaskScheduler taskScheduler,
- TaskCreationOptions creationOptionsForReplica, InternalTaskOptions internalOptionsForReplica)
- {
- return new ParallelForReplicaTask(taskReplicaDelegate, stateObject, parentTask, taskScheduler,
- creationOptionsForReplica, internalOptionsForReplica);
- }
-
-
- }
-
- internal class ParallelForReplicaTask : Task
- {
- internal object m_stateForNextReplica; // some replicas may quit prematurely, in which case they will use this variable
- // to save state they want to be picked up by the next replica queued to the same thread
-
- internal object m_stateFromPreviousReplica; // some replicas may quit prematurely, in which case they will use this variable
- // to save state they want to be picked up by the next replica queued to the same thread
-
- internal Task m_handedOverChildReplica; // some replicas may quit prematurely, in which case they will use this variable
- // to hand over the child replica they had queued to the next task that will replace them
-
- internal ParallelForReplicaTask(Action<object> taskReplicaDelegate, Object stateObject, Task parentTask, TaskScheduler taskScheduler,
- TaskCreationOptions creationOptionsForReplica, InternalTaskOptions internalOptionsForReplica) :
- base(taskReplicaDelegate, stateObject, parentTask, default(CancellationToken), creationOptionsForReplica, internalOptionsForReplica, taskScheduler)
- {
- }
-
- // Allows internal deriving classes to support replicas that exit prematurely and want to pass on state to the next replica
- internal override Object SavedStateForNextReplica
- {
- get { return m_stateForNextReplica; }
-
- set { m_stateForNextReplica = value; }
- }
-
- // Allows internal deriving classes to support replicas that exit prematurely and want to pass on state to the next replica
- internal override Object SavedStateFromPreviousReplica
- {
- get { return m_stateFromPreviousReplica; }
-
- set { m_stateFromPreviousReplica = value; }
- }
-
- // Allows internal deriving classes to support replicas that exit prematurely and want to hand over the child replica that they
- // had queued, so that the replacement replica can work with that child task instead of queuing up yet another one
- internal override Task HandedOverChildReplica
- {
- get { return m_handedOverChildReplica; }
-
- set { m_handedOverChildReplica = value; }
- }
- }
-
/// <summary>
/// Specifies flags that control optional behavior for the creation and execution of tasks.
/// </summary>
@@ -6856,10 +6306,8 @@ namespace System.Threading.Tasks
/// <summary>Used to filter out internal vs. public task creation options.</summary>
InternalOptionsMask = 0x0000FF00,
- ChildReplica = 0x0100,
ContinuationTask = 0x0200,
PromiseTask = 0x0400,
- SelfReplicating = 0x0800,
/// <summary>
/// Store the presence of TaskContinuationOptions.LazyCancellation, since it does not directly
diff --git a/src/mscorlib/src/System/Threading/Tasks/TaskCompletionSource.cs b/src/mscorlib/src/System/Threading/Tasks/TaskCompletionSource.cs
index 320f704..bf9f9cb 100644
--- a/src/mscorlib/src/System/Threading/Tasks/TaskCompletionSource.cs
+++ b/src/mscorlib/src/System/Threading/Tasks/TaskCompletionSource.cs
@@ -17,7 +17,6 @@ using System.Diagnostics.Contracts;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Runtime.ExceptionServices;
-using System.Security.Permissions;
using System.Threading;
// Disable the "reference to volatile field not treated as volatile" error.
@@ -203,22 +202,6 @@ namespace System.Threading.Tasks
return rval;
}
- /// <summary>Attempts to transition the underlying task to the faulted state.</summary>
- /// <param name="exceptions">The collection of exception dispatch infos to bind to this task.</param>
- /// <returns>True if the operation was successful; otherwise, false.</returns>
- /// <remarks>Unlike the public methods, this method doesn't currently validate that its arguments are correct.</remarks>
- internal bool TrySetException(IEnumerable<ExceptionDispatchInfo> exceptions)
- {
- Debug.Assert(exceptions != null);
-#if DEBUG
- foreach(var edi in exceptions) Debug.Assert(edi != null, "Contents must be non-null");
-#endif
-
- bool rval = m_task.TrySetException(exceptions);
- if (!rval && !m_task.IsCompleted) SpinUntilCompleted();
- return rval;
- }
-
/// <summary>
/// Transitions the underlying
/// <see cref="T:System.Threading.Tasks.Task{TResult}"/> into the
diff --git a/src/mscorlib/src/System/Threading/Tasks/TaskContinuation.cs b/src/mscorlib/src/System/Threading/Tasks/TaskContinuation.cs
index 70b9418d..3c6ccd8 100644
--- a/src/mscorlib/src/System/Threading/Tasks/TaskContinuation.cs
+++ b/src/mscorlib/src/System/Threading/Tasks/TaskContinuation.cs
@@ -29,13 +29,12 @@ namespace System.Threading.Tasks
private Task m_antecedent;
public ContinuationTaskFromTask(
- Task antecedent, Delegate action, object state, TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, ref StackCrawlMark stackMark) :
+ Task antecedent, Delegate action, object state, TaskCreationOptions creationOptions, InternalTaskOptions internalOptions) :
base(action, state, Task.InternalCurrentIfAttached(creationOptions), default(CancellationToken), creationOptions, internalOptions, null)
{
Contract.Requires(action is Action<Task> || action is Action<Task, object>,
"Invalid delegate type in ContinuationTaskFromTask");
m_antecedent = antecedent;
- PossiblyCaptureContext(ref stackMark);
}
/// <summary>
@@ -77,13 +76,12 @@ namespace System.Threading.Tasks
private Task m_antecedent;
public ContinuationResultTaskFromTask(
- Task antecedent, Delegate function, object state, TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, ref StackCrawlMark stackMark) :
+ Task antecedent, Delegate function, object state, TaskCreationOptions creationOptions, InternalTaskOptions internalOptions) :
base(function, state, Task.InternalCurrentIfAttached(creationOptions), default(CancellationToken), creationOptions, internalOptions, null)
{
Contract.Requires(function is Func<Task, TResult> || function is Func<Task, object, TResult>,
"Invalid delegate type in ContinuationResultTaskFromTask");
m_antecedent = antecedent;
- PossiblyCaptureContext(ref stackMark);
}
/// <summary>
@@ -125,13 +123,12 @@ namespace System.Threading.Tasks
private Task<TAntecedentResult> m_antecedent;
public ContinuationTaskFromResultTask(
- Task<TAntecedentResult> antecedent, Delegate action, object state, TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, ref StackCrawlMark stackMark) :
+ Task<TAntecedentResult> antecedent, Delegate action, object state, TaskCreationOptions creationOptions, InternalTaskOptions internalOptions) :
base(action, state, Task.InternalCurrentIfAttached(creationOptions), default(CancellationToken), creationOptions, internalOptions, null)
{
Contract.Requires(action is Action<Task<TAntecedentResult>> || action is Action<Task<TAntecedentResult>, object>,
"Invalid delegate type in ContinuationTaskFromResultTask");
m_antecedent = antecedent;
- PossiblyCaptureContext(ref stackMark);
}
/// <summary>
@@ -173,13 +170,12 @@ namespace System.Threading.Tasks
private Task<TAntecedentResult> m_antecedent;
public ContinuationResultTaskFromResultTask(
- Task<TAntecedentResult> antecedent, Delegate function, object state, TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, ref StackCrawlMark stackMark) :
+ Task<TAntecedentResult> antecedent, Delegate function, object state, TaskCreationOptions creationOptions, InternalTaskOptions internalOptions) :
base(function, state, Task.InternalCurrentIfAttached(creationOptions), default(CancellationToken), creationOptions, internalOptions, null)
{
Contract.Requires(function is Func<Task<TAntecedentResult>, TResult> || function is Func<Task<TAntecedentResult>, object, TResult>,
"Invalid delegate type in ContinuationResultTaskFromResultTask");
m_antecedent = antecedent;
- PossiblyCaptureContext(ref stackMark);
}
/// <summary>
@@ -392,10 +388,9 @@ namespace System.Threading.Tasks
/// <param name="context">The synchronization context with which to invoke the action. Must not be null.</param>
/// <param name="action">The action to invoke. Must not be null.</param>
/// <param name="flowExecutionContext">Whether to capture and restore ExecutionContext.</param>
- /// <param name="stackMark">The captured stack mark.</param>
internal SynchronizationContextAwaitTaskContinuation(
- SynchronizationContext context, Action action, bool flowExecutionContext, ref StackCrawlMark stackMark) :
- base(action, flowExecutionContext, ref stackMark)
+ SynchronizationContext context, Action action, bool flowExecutionContext) :
+ base(action, flowExecutionContext)
{
Debug.Assert(context != null);
m_syncContext = context;
@@ -479,10 +474,9 @@ namespace System.Threading.Tasks
/// <param name="scheduler">The task scheduler with which to invoke the action. Must not be null.</param>
/// <param name="action">The action to invoke. Must not be null.</param>
/// <param name="flowExecutionContext">Whether to capture and restore ExecutionContext.</param>
- /// <param name="stackMark">The captured stack mark.</param>
internal TaskSchedulerAwaitTaskContinuation(
- TaskScheduler scheduler, Action action, bool flowExecutionContext, ref StackCrawlMark stackMark) :
- base(action, flowExecutionContext, ref stackMark)
+ TaskScheduler scheduler, Action action, bool flowExecutionContext) :
+ base(action, flowExecutionContext)
{
Debug.Assert(scheduler != null);
m_scheduler = scheduler;
@@ -543,29 +537,13 @@ namespace System.Threading.Tasks
/// <summary>Initializes the continuation.</summary>
/// <param name="action">The action to invoke. Must not be null.</param>
/// <param name="flowExecutionContext">Whether to capture and restore ExecutionContext.</param>
- /// <param name="stackMark">The captured stack mark with which to construct an ExecutionContext.</param>
- internal AwaitTaskContinuation(Action action, bool flowExecutionContext, ref StackCrawlMark stackMark)
- {
- Contract.Requires(action != null);
- m_action = action;
- if (flowExecutionContext)
- {
- m_capturedContext = ExecutionContext.Capture(
- ref stackMark,
- ExecutionContext.CaptureOptions.IgnoreSyncCtx | ExecutionContext.CaptureOptions.OptimizeDefaultCase);
- }
- }
-
- /// <summary>Initializes the continuation.</summary>
- /// <param name="action">The action to invoke. Must not be null.</param>
- /// <param name="flowExecutionContext">Whether to capture and restore ExecutionContext.</param>
internal AwaitTaskContinuation(Action action, bool flowExecutionContext)
{
Contract.Requires(action != null);
m_action = action;
if (flowExecutionContext)
{
- m_capturedContext = ExecutionContext.FastCapture();
+ m_capturedContext = ExecutionContext.Capture();
}
}
@@ -670,11 +648,7 @@ namespace System.Threading.Tasks
// If there is an execution context, get the cached delegate and run the action under the context.
else
{
- try
- {
- ExecutionContext.Run(m_capturedContext, GetInvokeActionCallback(), m_action, true);
- }
- finally { m_capturedContext.Dispose(); }
+ ExecutionContext.Run(m_capturedContext, GetInvokeActionCallback(), m_action);
}
}
finally
@@ -689,8 +663,7 @@ namespace System.Threading.Tasks
void IThreadPoolWorkItem.ExecuteWorkItem()
{
// inline the fast path
- if (m_capturedContext == null && !TplEtwProvider.Log.IsEnabled()
- )
+ if (m_capturedContext == null && !TplEtwProvider.Log.IsEnabled())
{
m_action();
}
@@ -739,7 +712,7 @@ namespace System.Threading.Tasks
// If there's no captured context, just run the callback directly.
if (m_capturedContext == null) callback(state);
// Otherwise, use the captured context to do so.
- else ExecutionContext.Run(m_capturedContext, callback, state, true);
+ else ExecutionContext.Run(m_capturedContext, callback, state);
}
catch (Exception exc) // we explicitly do not request handling of dangerous exceptions like AVs
{
@@ -749,9 +722,6 @@ namespace System.Threading.Tasks
{
// Restore the current task information
if (prevCurrentTask != null) currentTask = prevCurrentTask;
-
- // Clean up after the execution context, which is only usable once.
- if (m_capturedContext != null) m_capturedContext.Dispose();
}
}
diff --git a/src/mscorlib/src/System/Threading/Tasks/TaskExceptionHolder.cs b/src/mscorlib/src/System/Threading/Tasks/TaskExceptionHolder.cs
index 45817da..ee1112a 100644
--- a/src/mscorlib/src/System/Threading/Tasks/TaskExceptionHolder.cs
+++ b/src/mscorlib/src/System/Threading/Tasks/TaskExceptionHolder.cs
@@ -149,23 +149,6 @@ namespace System.Threading.Tasks
/// Add an exception to the holder. This will ensure the holder is
/// in the proper state (handled/unhandled) depending on the list's contents.
/// </summary>
- /// <param name="exceptionObject">
- /// An exception object (either an Exception, an ExceptionDispatchInfo,
- /// an IEnumerable{Exception}, or an IEnumerable{ExceptionDispatchInfo})
- /// to add to the list.
- /// </param>
- /// <remarks>
- /// Must be called under lock.
- /// </remarks>
- internal void Add(object exceptionObject)
- {
- Add(exceptionObject, representsCancellation: false);
- }
-
- /// <summary>
- /// Add an exception to the holder. This will ensure the holder is
- /// in the proper state (handled/unhandled) depending on the list's contents.
- /// </summary>
/// <param name="representsCancellation">
/// Whether the exception represents a cancellation request (true) or a fault (false).
/// </param>
diff --git a/src/mscorlib/src/System/Threading/Tasks/TaskFactory.cs b/src/mscorlib/src/System/Threading/Tasks/TaskFactory.cs
index aa4c2df..89ba298 100644
--- a/src/mscorlib/src/System/Threading/Tasks/TaskFactory.cs
+++ b/src/mscorlib/src/System/Threading/Tasks/TaskFactory.cs
@@ -15,7 +15,6 @@
using System;
using System.Collections.Generic;
using System.Security;
-using System.Security.Permissions;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Diagnostics;
@@ -225,7 +224,7 @@ namespace System.Threading.Tasks
TaskCreationOptions.PreferFairness |
TaskCreationOptions.RunContinuationsAsynchronously)) != 0)
{
- throw new ArgumentOutOfRangeException(nameof(creationOptions));
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.creationOptions);
}
Contract.EndContractBlock();
}
@@ -293,13 +292,11 @@ namespace System.Threading.Tasks
/// unless creation and scheduling must be separated, StartNew is the recommended
/// approach for both simplicity and performance.
/// </remarks>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task StartNew(Action action)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
Task currTask = Task.InternalCurrent;
return Task.InternalStartNew(currTask, action, null, m_defaultCancellationToken, GetDefaultScheduler(currTask),
- m_defaultCreationOptions, InternalTaskOptions.None, ref stackMark);
+ m_defaultCreationOptions, InternalTaskOptions.None);
}
/// <summary>
@@ -320,13 +317,11 @@ namespace System.Threading.Tasks
/// unless creation and scheduling must be separated, StartNew is the recommended
/// approach for both simplicity and performance.
/// </remarks>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task StartNew(Action action, CancellationToken cancellationToken)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
Task currTask = Task.InternalCurrent;
return Task.InternalStartNew(currTask, action, null, cancellationToken, GetDefaultScheduler(currTask),
- m_defaultCreationOptions, InternalTaskOptions.None, ref stackMark);
+ m_defaultCreationOptions, InternalTaskOptions.None);
}
/// <summary>
@@ -350,13 +345,11 @@ namespace System.Threading.Tasks
/// However, unless creation and scheduling must be separated, StartNew is the recommended approach
/// for both simplicity and performance.
/// </remarks>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task StartNew(Action action, TaskCreationOptions creationOptions)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
Task currTask = Task.InternalCurrent;
return Task.InternalStartNew(currTask, action, null, m_defaultCancellationToken, GetDefaultScheduler(currTask), creationOptions,
- InternalTaskOptions.None, ref stackMark);
+ InternalTaskOptions.None);
}
/// <summary>
@@ -391,22 +384,11 @@ namespace System.Threading.Tasks
/// However, unless creation and scheduling must be separated, StartNew is the recommended approach
/// for both simplicity and performance.
/// </remarks>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task StartNew(Action action, CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskScheduler scheduler)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
return Task.InternalStartNew(
Task.InternalCurrentIfAttached(creationOptions), action, null, cancellationToken, scheduler, creationOptions,
- InternalTaskOptions.None, ref stackMark);
- }
-
- // Internal version includes InternalTaskOptions for Parallel.Invoke() support.
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
- internal Task StartNew(Action action, CancellationToken cancellationToken, TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler)
- {
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return Task.InternalStartNew(
- Task.InternalCurrentIfAttached(creationOptions), action, null, cancellationToken, scheduler, creationOptions, internalOptions, ref stackMark);
+ InternalTaskOptions.None);
}
@@ -427,13 +409,11 @@ namespace System.Threading.Tasks
/// However, unless creation and scheduling must be separated, StartNew is the recommended approach
/// for both simplicity and performance.
/// </remarks>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task StartNew(Action<Object> action, Object state)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
Task currTask = Task.InternalCurrent;
return Task.InternalStartNew(currTask, action, state, m_defaultCancellationToken, GetDefaultScheduler(currTask),
- m_defaultCreationOptions, InternalTaskOptions.None, ref stackMark);
+ m_defaultCreationOptions, InternalTaskOptions.None);
}
@@ -458,13 +438,11 @@ namespace System.Threading.Tasks
/// However, unless creation and scheduling must be separated, StartNew is the recommended approach
/// for both simplicity and performance.
/// </remarks>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task StartNew(Action<Object> action, Object state, CancellationToken cancellationToken)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
Task currTask = Task.InternalCurrent;
return Task.InternalStartNew(currTask, action, state, cancellationToken, GetDefaultScheduler(currTask),
- m_defaultCreationOptions, InternalTaskOptions.None, ref stackMark);
+ m_defaultCreationOptions, InternalTaskOptions.None);
}
/// <summary>
@@ -490,13 +468,11 @@ namespace System.Threading.Tasks
/// However, unless creation and scheduling must be separated, StartNew is the recommended approach
/// for both simplicity and performance.
/// </remarks>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task StartNew(Action<Object> action, Object state, TaskCreationOptions creationOptions)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
Task currTask = Task.InternalCurrent;
return Task.InternalStartNew(currTask, action, state, m_defaultCancellationToken, GetDefaultScheduler(currTask),
- creationOptions, InternalTaskOptions.None, ref stackMark);
+ creationOptions, InternalTaskOptions.None);
}
/// <summary>
@@ -533,14 +509,12 @@ namespace System.Threading.Tasks
/// However, unless creation and scheduling must be separated, StartNew is the recommended approach
/// for both simplicity and performance.
/// </remarks>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task StartNew(Action<Object> action, Object state, CancellationToken cancellationToken,
TaskCreationOptions creationOptions, TaskScheduler scheduler)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
return Task.InternalStartNew(
Task.InternalCurrentIfAttached(creationOptions), action, state, cancellationToken, scheduler,
- creationOptions, InternalTaskOptions.None, ref stackMark);
+ creationOptions, InternalTaskOptions.None);
}
/// <summary>
@@ -562,13 +536,11 @@ namespace System.Threading.Tasks
/// However, unless creation and scheduling must be separated, StartNew is the recommended approach
/// for both simplicity and performance.
/// </remarks>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> StartNew<TResult>(Func<TResult> function)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
Task currTask = Task.InternalCurrent;
return Task<TResult>.StartNew(currTask, function, m_defaultCancellationToken,
- m_defaultCreationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask), ref stackMark);
+ m_defaultCreationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask));
}
@@ -595,13 +567,11 @@ namespace System.Threading.Tasks
/// However, unless creation and scheduling must be separated, StartNew is the recommended approach
/// for both simplicity and performance.
/// </remarks>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> StartNew<TResult>(Func<TResult> function, CancellationToken cancellationToken)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
Task currTask = Task.InternalCurrent;
return Task<TResult>.StartNew(currTask, function, cancellationToken,
- m_defaultCreationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask), ref stackMark);
+ m_defaultCreationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask));
}
/// <summary>
@@ -629,13 +599,11 @@ namespace System.Threading.Tasks
/// However, unless creation and scheduling must be separated, StartNew is the recommended approach
/// for both simplicity and performance.
/// </remarks>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> StartNew<TResult>(Func<TResult> function, TaskCreationOptions creationOptions)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
Task currTask = Task.InternalCurrent;
return Task<TResult>.StartNew(currTask, function, m_defaultCancellationToken,
- creationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask), ref stackMark);
+ creationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask));
}
/// <summary>
@@ -674,13 +642,11 @@ namespace System.Threading.Tasks
/// However, unless creation and scheduling must be separated, StartNew is the recommended approach
/// for both simplicity and performance.
/// </remarks>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> StartNew<TResult>(Func<TResult> function, CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskScheduler scheduler)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
return Task<TResult>.StartNew(
Task.InternalCurrentIfAttached(creationOptions), function, cancellationToken,
- creationOptions, InternalTaskOptions.None, scheduler, ref stackMark);
+ creationOptions, InternalTaskOptions.None, scheduler);
}
/// <summary>
@@ -704,13 +670,11 @@ namespace System.Threading.Tasks
/// However, unless creation and scheduling must be separated, StartNew is the recommended approach
/// for both simplicity and performance.
/// </remarks>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> StartNew<TResult>(Func<Object, TResult> function, Object state)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
Task currTask = Task.InternalCurrent;
return Task<TResult>.StartNew(currTask, function, state, m_defaultCancellationToken,
- m_defaultCreationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask), ref stackMark);
+ m_defaultCreationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask));
}
@@ -739,13 +703,11 @@ namespace System.Threading.Tasks
/// However, unless creation and scheduling must be separated, StartNew is the recommended approach
/// for both simplicity and performance.
/// </remarks>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> StartNew<TResult>(Func<Object, TResult> function, Object state, CancellationToken cancellationToken)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
Task currTask = Task.InternalCurrent;
return Task<TResult>.StartNew(currTask, function, state, cancellationToken,
- m_defaultCreationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask), ref stackMark);
+ m_defaultCreationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask));
}
/// <summary>
@@ -775,13 +737,11 @@ namespace System.Threading.Tasks
/// However, unless creation and scheduling must be separated, StartNew is the recommended approach
/// for both simplicity and performance.
/// </remarks>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> StartNew<TResult>(Func<Object, TResult> function, Object state, TaskCreationOptions creationOptions)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
Task currTask = Task.InternalCurrent;
return Task<TResult>.StartNew(currTask, function, state, m_defaultCancellationToken,
- creationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask), ref stackMark);
+ creationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask));
}
/// <summary>
@@ -822,14 +782,12 @@ namespace System.Threading.Tasks
/// However, unless creation and scheduling must be separated, StartNew is the recommended approach
/// for both simplicity and performance.
/// </remarks>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> StartNew<TResult>(Func<Object, TResult> function, Object state, CancellationToken cancellationToken,
TaskCreationOptions creationOptions, TaskScheduler scheduler)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
return Task<TResult>.StartNew(
Task.InternalCurrentIfAttached(creationOptions), function, state, cancellationToken,
- creationOptions, InternalTaskOptions.None, scheduler, ref stackMark);
+ creationOptions, InternalTaskOptions.None, scheduler);
}
//
@@ -850,13 +808,11 @@ namespace System.Threading.Tasks
/// <paramref name="endMethod"/> argument is null.</exception>
/// <returns>A <see cref="T:System.Threading.Tasks.Task">Task</see> that represents the asynchronous
/// operation.</returns>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task FromAsync(
IAsyncResult asyncResult,
Action<IAsyncResult> endMethod)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return FromAsync(asyncResult, endMethod, m_defaultCreationOptions, DefaultScheduler, ref stackMark);
+ return FromAsync(asyncResult, endMethod, m_defaultCreationOptions, DefaultScheduler);
}
/// <summary>
@@ -878,14 +834,12 @@ namespace System.Threading.Tasks
/// value.</exception>
/// <returns>A <see cref="T:System.Threading.Tasks.Task">Task</see> that represents the asynchronous
/// operation.</returns>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task FromAsync(
IAsyncResult asyncResult,
Action<IAsyncResult> endMethod,
TaskCreationOptions creationOptions)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return FromAsync(asyncResult, endMethod, creationOptions, DefaultScheduler, ref stackMark);
+ return FromAsync(asyncResult, endMethod, creationOptions, DefaultScheduler);
}
/// <summary>
@@ -911,26 +865,13 @@ namespace System.Threading.Tasks
/// value.</exception>
/// <returns>A <see cref="T:System.Threading.Tasks.Task">Task</see> that represents the asynchronous
/// operation.</returns>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task FromAsync(
IAsyncResult asyncResult,
Action<IAsyncResult> endMethod,
TaskCreationOptions creationOptions,
TaskScheduler scheduler)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return FromAsync(asyncResult, endMethod, creationOptions, scheduler, ref stackMark);
- }
-
- // private version that supports StackCrawlMark.
- private Task FromAsync(
- IAsyncResult asyncResult,
- Action<IAsyncResult> endMethod,
- TaskCreationOptions creationOptions,
- TaskScheduler scheduler,
- ref StackCrawlMark stackMark)
- {
- return TaskFactory<VoidTaskResult>.FromAsyncImpl(asyncResult, null, endMethod, creationOptions, scheduler, ref stackMark);
+ return TaskFactory<VoidTaskResult>.FromAsyncImpl(asyncResult, null, endMethod, creationOptions, scheduler);
}
/// <summary>
@@ -1228,12 +1169,10 @@ namespace System.Threading.Tasks
/// <paramref name="endMethod"/> argument is null.</exception>
/// <returns>A <see cref="T:System.Threading.Tasks.Task{TResult}">Task</see> that represents the
/// asynchronous operation.</returns>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> FromAsync<TResult>(
IAsyncResult asyncResult, Func<IAsyncResult, TResult> endMethod)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return TaskFactory<TResult>.FromAsyncImpl(asyncResult, endMethod, null, m_defaultCreationOptions, DefaultScheduler, ref stackMark);
+ return TaskFactory<TResult>.FromAsyncImpl(asyncResult, endMethod, null, m_defaultCreationOptions, DefaultScheduler);
}
/// <summary>
@@ -1258,12 +1197,10 @@ namespace System.Threading.Tasks
/// value.</exception>
/// <returns>A <see cref="T:System.Threading.Tasks.Task{TResult}">Task</see> that represents the
/// asynchronous operation.</returns>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> FromAsync<TResult>(
IAsyncResult asyncResult, Func<IAsyncResult, TResult> endMethod, TaskCreationOptions creationOptions)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return TaskFactory<TResult>.FromAsyncImpl(asyncResult, endMethod, null, creationOptions, DefaultScheduler, ref stackMark);
+ return TaskFactory<TResult>.FromAsyncImpl(asyncResult, endMethod, null, creationOptions, DefaultScheduler);
}
/// <summary>
@@ -1292,12 +1229,10 @@ namespace System.Threading.Tasks
/// value.</exception>
/// <returns>A <see cref="T:System.Threading.Tasks.Task{TResult}">Task</see> that represents the
/// asynchronous operation.</returns>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> FromAsync<TResult>(
IAsyncResult asyncResult, Func<IAsyncResult, TResult> endMethod, TaskCreationOptions creationOptions, TaskScheduler scheduler)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return TaskFactory<TResult>.FromAsyncImpl(asyncResult, endMethod, null, creationOptions, scheduler, ref stackMark);
+ return TaskFactory<TResult>.FromAsyncImpl(asyncResult, endMethod, null, creationOptions, scheduler);
}
/// <summary>
@@ -1606,7 +1541,7 @@ namespace System.Threading.Tasks
TaskCreationOptions.PreferFairness |
TaskCreationOptions.LongRunning)) != 0)
{
- throw new ArgumentOutOfRangeException(nameof(creationOptions));
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.creationOptions);
}
}
@@ -1798,14 +1733,12 @@ namespace System.Threading.Tasks
/// <paramref name="tasks"/> array contains a null value.</exception>
/// <exception cref="T:System.ArgumentException">The exception that is thrown when the
/// <paramref name="tasks"/> array is empty.</exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task ContinueWhenAll(Task[] tasks, Action<Task[]> continuationAction)
{
if (continuationAction == null) throw new ArgumentNullException(nameof(continuationAction));
Contract.EndContractBlock();
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return TaskFactory<VoidTaskResult>.ContinueWhenAllImpl(tasks, null, continuationAction, m_defaultContinuationOptions, m_defaultCancellationToken, DefaultScheduler, ref stackMark);
+ return TaskFactory<VoidTaskResult>.ContinueWhenAllImpl(tasks, null, continuationAction, m_defaultContinuationOptions, m_defaultCancellationToken, DefaultScheduler);
}
@@ -1830,14 +1763,12 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
/// has already been disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task ContinueWhenAll(Task[] tasks, Action<Task[]> continuationAction, CancellationToken cancellationToken)
{
if (continuationAction == null) throw new ArgumentNullException(nameof(continuationAction));
Contract.EndContractBlock();
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return TaskFactory<VoidTaskResult>.ContinueWhenAllImpl(tasks, null, continuationAction, m_defaultContinuationOptions, cancellationToken, DefaultScheduler, ref stackMark);
+ return TaskFactory<VoidTaskResult>.ContinueWhenAllImpl(tasks, null, continuationAction, m_defaultContinuationOptions, cancellationToken, DefaultScheduler);
}
/// <summary>
@@ -1867,14 +1798,12 @@ namespace System.Threading.Tasks
/// which constrain for which <see cref="System.Threading.Tasks.TaskStatus">TaskStatus</see> states a continuation
/// will be executed, are illegal with ContinueWhenAll.
/// </remarks>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task ContinueWhenAll(Task[] tasks, Action<Task[]> continuationAction, TaskContinuationOptions continuationOptions)
{
if (continuationAction == null) throw new ArgumentNullException(nameof(continuationAction));
Contract.EndContractBlock();
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return TaskFactory<VoidTaskResult>.ContinueWhenAllImpl(tasks, null, continuationAction, continuationOptions, m_defaultCancellationToken, DefaultScheduler, ref stackMark);
+ return TaskFactory<VoidTaskResult>.ContinueWhenAllImpl(tasks, null, continuationAction, continuationOptions, m_defaultCancellationToken, DefaultScheduler);
}
/// <summary>
@@ -1914,15 +1843,13 @@ namespace System.Threading.Tasks
/// which constrain for which <see cref="System.Threading.Tasks.TaskStatus">TaskStatus</see> states a continuation
/// will be executed, are illegal with ContinueWhenAll.
/// </remarks>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task ContinueWhenAll(Task[] tasks, Action<Task[]> continuationAction, CancellationToken cancellationToken,
TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
{
if (continuationAction == null) throw new ArgumentNullException(nameof(continuationAction));
Contract.EndContractBlock();
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return TaskFactory<VoidTaskResult>.ContinueWhenAllImpl(tasks, null, continuationAction, continuationOptions, cancellationToken, scheduler, ref stackMark);
+ return TaskFactory<VoidTaskResult>.ContinueWhenAllImpl(tasks, null, continuationAction, continuationOptions, cancellationToken, scheduler);
}
/// <summary>
@@ -1942,14 +1869,12 @@ namespace System.Threading.Tasks
/// <paramref name="tasks"/> array contains a null value.</exception>
/// <exception cref="T:System.ArgumentException">The exception that is thrown when the
/// <paramref name="tasks"/> array is empty.</exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task ContinueWhenAll<TAntecedentResult>(Task<TAntecedentResult>[] tasks, Action<Task<TAntecedentResult>[]> continuationAction)
{
if (continuationAction == null) throw new ArgumentNullException(nameof(continuationAction));
Contract.EndContractBlock();
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return TaskFactory<VoidTaskResult>.ContinueWhenAllImpl<TAntecedentResult>(tasks, null, continuationAction, m_defaultContinuationOptions, m_defaultCancellationToken, DefaultScheduler, ref stackMark);
+ return TaskFactory<VoidTaskResult>.ContinueWhenAllImpl<TAntecedentResult>(tasks, null, continuationAction, m_defaultContinuationOptions, m_defaultCancellationToken, DefaultScheduler);
}
@@ -1975,15 +1900,13 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
/// has already been disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task ContinueWhenAll<TAntecedentResult>(Task<TAntecedentResult>[] tasks, Action<Task<TAntecedentResult>[]> continuationAction,
CancellationToken cancellationToken)
{
if (continuationAction == null) throw new ArgumentNullException(nameof(continuationAction));
Contract.EndContractBlock();
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return TaskFactory<VoidTaskResult>.ContinueWhenAllImpl<TAntecedentResult>(tasks, null, continuationAction, m_defaultContinuationOptions, cancellationToken, DefaultScheduler, ref stackMark);
+ return TaskFactory<VoidTaskResult>.ContinueWhenAllImpl<TAntecedentResult>(tasks, null, continuationAction, m_defaultContinuationOptions, cancellationToken, DefaultScheduler);
}
/// <summary>
@@ -2014,15 +1937,13 @@ namespace System.Threading.Tasks
/// which constrain for which <see cref="System.Threading.Tasks.TaskStatus">TaskStatus</see> states a continuation
/// will be executed, are illegal with ContinueWhenAll.
/// </remarks>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task ContinueWhenAll<TAntecedentResult>(Task<TAntecedentResult>[] tasks, Action<Task<TAntecedentResult>[]> continuationAction,
TaskContinuationOptions continuationOptions)
{
if (continuationAction == null) throw new ArgumentNullException(nameof(continuationAction));
Contract.EndContractBlock();
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return TaskFactory<VoidTaskResult>.ContinueWhenAllImpl<TAntecedentResult>(tasks, null, continuationAction, continuationOptions, m_defaultCancellationToken, DefaultScheduler, ref stackMark);
+ return TaskFactory<VoidTaskResult>.ContinueWhenAllImpl<TAntecedentResult>(tasks, null, continuationAction, continuationOptions, m_defaultCancellationToken, DefaultScheduler);
}
/// <summary>
@@ -2063,15 +1984,13 @@ namespace System.Threading.Tasks
/// which constrain for which <see cref="System.Threading.Tasks.TaskStatus">TaskStatus</see> states a continuation
/// will be executed, are illegal with ContinueWhenAll.
/// </remarks>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task ContinueWhenAll<TAntecedentResult>(Task<TAntecedentResult>[] tasks, Action<Task<TAntecedentResult>[]> continuationAction,
CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
{
if (continuationAction == null) throw new ArgumentNullException(nameof(continuationAction));
Contract.EndContractBlock();
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return TaskFactory<VoidTaskResult>.ContinueWhenAllImpl<TAntecedentResult>(tasks, null, continuationAction, continuationOptions, cancellationToken, scheduler, ref stackMark);
+ return TaskFactory<VoidTaskResult>.ContinueWhenAllImpl<TAntecedentResult>(tasks, null, continuationAction, continuationOptions, cancellationToken, scheduler);
}
/// <summary>
@@ -2094,14 +2013,12 @@ namespace System.Threading.Tasks
/// <paramref name="tasks"/> array contains a null value.</exception>
/// <exception cref="T:System.ArgumentException">The exception that is thrown when the
/// <paramref name="tasks"/> array is empty.</exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWhenAll<TResult>(Task[] tasks, Func<Task[], TResult> continuationFunction)
{
if (continuationFunction == null) throw new ArgumentNullException(nameof(continuationFunction));
Contract.EndContractBlock();
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return TaskFactory<TResult>.ContinueWhenAllImpl(tasks, continuationFunction, null, m_defaultContinuationOptions, m_defaultCancellationToken, DefaultScheduler, ref stackMark);
+ return TaskFactory<TResult>.ContinueWhenAllImpl(tasks, continuationFunction, null, m_defaultContinuationOptions, m_defaultCancellationToken, DefaultScheduler);
}
@@ -2130,14 +2047,12 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
/// has already been disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWhenAll<TResult>(Task[] tasks, Func<Task[], TResult> continuationFunction, CancellationToken cancellationToken)
{
if (continuationFunction == null) throw new ArgumentNullException(nameof(continuationFunction));
Contract.EndContractBlock();
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return TaskFactory<TResult>.ContinueWhenAllImpl(tasks, continuationFunction, null, m_defaultContinuationOptions, cancellationToken, DefaultScheduler, ref stackMark);
+ return TaskFactory<TResult>.ContinueWhenAllImpl(tasks, continuationFunction, null, m_defaultContinuationOptions, cancellationToken, DefaultScheduler);
}
/// <summary>
@@ -2171,14 +2086,12 @@ namespace System.Threading.Tasks
/// which constrain for which <see cref="System.Threading.Tasks.TaskStatus">TaskStatus</see> states a continuation
/// will be executed, are illegal with ContinueWhenAll.
/// </remarks>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWhenAll<TResult>(Task[] tasks, Func<Task[], TResult> continuationFunction, TaskContinuationOptions continuationOptions)
{
if (continuationFunction == null) throw new ArgumentNullException(nameof(continuationFunction));
Contract.EndContractBlock();
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return TaskFactory<TResult>.ContinueWhenAllImpl(tasks, continuationFunction, null, continuationOptions, m_defaultCancellationToken, DefaultScheduler, ref stackMark);
+ return TaskFactory<TResult>.ContinueWhenAllImpl(tasks, continuationFunction, null, continuationOptions, m_defaultCancellationToken, DefaultScheduler);
}
/// <summary>
@@ -2222,15 +2135,13 @@ namespace System.Threading.Tasks
/// which constrain for which <see cref="System.Threading.Tasks.TaskStatus">TaskStatus</see> states a continuation
/// will be executed, are illegal with ContinueWhenAll.
/// </remarks>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWhenAll<TResult>(Task[] tasks, Func<Task[], TResult> continuationFunction, CancellationToken cancellationToken,
TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
{
if (continuationFunction == null) throw new ArgumentNullException(nameof(continuationFunction));
Contract.EndContractBlock();
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return TaskFactory<TResult>.ContinueWhenAllImpl(tasks, continuationFunction, null, continuationOptions, cancellationToken, scheduler, ref stackMark);
+ return TaskFactory<TResult>.ContinueWhenAllImpl(tasks, continuationFunction, null, continuationOptions, cancellationToken, scheduler);
}
@@ -2255,14 +2166,12 @@ namespace System.Threading.Tasks
/// <paramref name="tasks"/> array contains a null value.</exception>
/// <exception cref="T:System.ArgumentException">The exception that is thrown when the
/// <paramref name="tasks"/> array is empty.</exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWhenAll<TAntecedentResult, TResult>(Task<TAntecedentResult>[] tasks, Func<Task<TAntecedentResult>[], TResult> continuationFunction)
{
if (continuationFunction == null) throw new ArgumentNullException(nameof(continuationFunction));
Contract.EndContractBlock();
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return TaskFactory<TResult>.ContinueWhenAllImpl<TAntecedentResult>(tasks, continuationFunction, null, m_defaultContinuationOptions, m_defaultCancellationToken, DefaultScheduler, ref stackMark);
+ return TaskFactory<TResult>.ContinueWhenAllImpl<TAntecedentResult>(tasks, continuationFunction, null, m_defaultContinuationOptions, m_defaultCancellationToken, DefaultScheduler);
}
/// <summary>
@@ -2291,15 +2200,13 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
/// has already been disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWhenAll<TAntecedentResult, TResult>(Task<TAntecedentResult>[] tasks, Func<Task<TAntecedentResult>[], TResult> continuationFunction,
CancellationToken cancellationToken)
{
if (continuationFunction == null) throw new ArgumentNullException(nameof(continuationFunction));
Contract.EndContractBlock();
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return TaskFactory<TResult>.ContinueWhenAllImpl<TAntecedentResult>(tasks, continuationFunction, null, m_defaultContinuationOptions, cancellationToken, DefaultScheduler, ref stackMark);
+ return TaskFactory<TResult>.ContinueWhenAllImpl<TAntecedentResult>(tasks, continuationFunction, null, m_defaultContinuationOptions, cancellationToken, DefaultScheduler);
}
/// <summary>
@@ -2334,15 +2241,13 @@ namespace System.Threading.Tasks
/// which constrain for which <see cref="System.Threading.Tasks.TaskStatus">TaskStatus</see> states a continuation
/// will be executed, are illegal with ContinueWhenAll.
/// </remarks>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWhenAll<TAntecedentResult, TResult>(Task<TAntecedentResult>[] tasks, Func<Task<TAntecedentResult>[], TResult> continuationFunction,
TaskContinuationOptions continuationOptions)
{
if (continuationFunction == null) throw new ArgumentNullException(nameof(continuationFunction));
Contract.EndContractBlock();
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return TaskFactory<TResult>.ContinueWhenAllImpl<TAntecedentResult>(tasks, continuationFunction, null, continuationOptions, m_defaultCancellationToken, DefaultScheduler, ref stackMark);
+ return TaskFactory<TResult>.ContinueWhenAllImpl<TAntecedentResult>(tasks, continuationFunction, null, continuationOptions, m_defaultCancellationToken, DefaultScheduler);
}
/// <summary>
@@ -2387,15 +2292,13 @@ namespace System.Threading.Tasks
/// which constrain for which <see cref="System.Threading.Tasks.TaskStatus">TaskStatus</see> states a continuation
/// will be executed, are illegal with ContinueWhenAll.
/// </remarks>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWhenAll<TAntecedentResult, TResult>(Task<TAntecedentResult>[] tasks, Func<Task<TAntecedentResult>[], TResult> continuationFunction,
CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
{
if (continuationFunction == null) throw new ArgumentNullException(nameof(continuationFunction));
Contract.EndContractBlock();
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return TaskFactory<TResult>.ContinueWhenAllImpl<TAntecedentResult>(tasks, continuationFunction, null, continuationOptions, cancellationToken, scheduler, ref stackMark);
+ return TaskFactory<TResult>.ContinueWhenAllImpl<TAntecedentResult>(tasks, continuationFunction, null, continuationOptions, cancellationToken, scheduler);
}
//
@@ -2505,7 +2408,23 @@ namespace System.Threading.Tasks
checkArgsOnly = true;
}
// Otherwise, add the completion action and keep going.
- else task.AddCompletionAction(promise);
+ else
+ {
+ task.AddCompletionAction(promise);
+ if (promise.IsCompleted)
+ {
+ // One of the previous tasks that already had its continuation registered may have
+ // raced to complete with our adding the continuation to this task. The completion
+ // routine would have gone through and removed the continuation from all of the tasks
+ // with which it was already registered, but if the race causes this continuation to
+ // be added after that, it'll never be removed. As such, after adding the continuation,
+ // we check to see whether the promise has already completed, and if it has, we try to
+ // manually remove the continuation from this task. If it was already removed, it'll be
+ // a nop, and if we race to remove it, the synchronization in RemoveContinuation will
+ // keep things consistent.
+ task.RemoveContinuation(promise);
+ }
+ }
}
return promise;
@@ -2528,14 +2447,12 @@ namespace System.Threading.Tasks
/// <paramref name="tasks"/> array contains a null value.</exception>
/// <exception cref="T:System.ArgumentException">The exception that is thrown when the
/// <paramref name="tasks"/> array is empty.</exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task ContinueWhenAny(Task[] tasks, Action<Task> continuationAction)
{
if (continuationAction == null) throw new ArgumentNullException(nameof(continuationAction));
Contract.EndContractBlock();
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return TaskFactory<VoidTaskResult>.ContinueWhenAnyImpl(tasks, null, continuationAction, m_defaultContinuationOptions, m_defaultCancellationToken, DefaultScheduler, ref stackMark);
+ return TaskFactory<VoidTaskResult>.ContinueWhenAnyImpl(tasks, null, continuationAction, m_defaultContinuationOptions, m_defaultCancellationToken, DefaultScheduler);
}
/// <summary>
@@ -2559,14 +2476,12 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
/// has already been disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task ContinueWhenAny(Task[] tasks, Action<Task> continuationAction, CancellationToken cancellationToken)
{
if (continuationAction == null) throw new ArgumentNullException(nameof(continuationAction));
Contract.EndContractBlock();
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return TaskFactory<VoidTaskResult>.ContinueWhenAnyImpl(tasks, null, continuationAction, m_defaultContinuationOptions, cancellationToken, DefaultScheduler, ref stackMark);
+ return TaskFactory<VoidTaskResult>.ContinueWhenAnyImpl(tasks, null, continuationAction, m_defaultContinuationOptions, cancellationToken, DefaultScheduler);
}
/// <summary>
@@ -2596,14 +2511,12 @@ namespace System.Threading.Tasks
/// which constrain for which <see cref="System.Threading.Tasks.TaskStatus">TaskStatus</see> states a continuation
/// will be executed, are illegal with ContinueWhenAny.
/// </remarks>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task ContinueWhenAny(Task[] tasks, Action<Task> continuationAction, TaskContinuationOptions continuationOptions)
{
if (continuationAction == null) throw new ArgumentNullException(nameof(continuationAction));
Contract.EndContractBlock();
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return TaskFactory<VoidTaskResult>.ContinueWhenAnyImpl(tasks, null, continuationAction, continuationOptions, m_defaultCancellationToken, DefaultScheduler, ref stackMark);
+ return TaskFactory<VoidTaskResult>.ContinueWhenAnyImpl(tasks, null, continuationAction, continuationOptions, m_defaultCancellationToken, DefaultScheduler);
}
/// <summary>
@@ -2643,15 +2556,13 @@ namespace System.Threading.Tasks
/// which constrain for which <see cref="System.Threading.Tasks.TaskStatus">TaskStatus</see> states a continuation
/// will be executed, are illegal with ContinueWhenAny.
/// </remarks>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task ContinueWhenAny(Task[] tasks, Action<Task> continuationAction, CancellationToken cancellationToken,
TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
{
if (continuationAction == null) throw new ArgumentNullException(nameof(continuationAction));
Contract.EndContractBlock();
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return TaskFactory<VoidTaskResult>.ContinueWhenAnyImpl(tasks, null, continuationAction, continuationOptions, cancellationToken, scheduler, ref stackMark);
+ return TaskFactory<VoidTaskResult>.ContinueWhenAnyImpl(tasks, null, continuationAction, continuationOptions, cancellationToken, scheduler);
}
@@ -2675,14 +2586,12 @@ namespace System.Threading.Tasks
/// <paramref name="tasks"/> array contains a null value.</exception>
/// <exception cref="T:System.ArgumentException">The exception that is thrown when the
/// <paramref name="tasks"/> array is empty.</exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWhenAny<TResult>(Task[] tasks, Func<Task, TResult> continuationFunction)
{
if (continuationFunction == null) throw new ArgumentNullException(nameof(continuationFunction));
Contract.EndContractBlock();
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return TaskFactory<TResult>.ContinueWhenAnyImpl(tasks, continuationFunction, null, m_defaultContinuationOptions, m_defaultCancellationToken, DefaultScheduler, ref stackMark);
+ return TaskFactory<TResult>.ContinueWhenAnyImpl(tasks, continuationFunction, null, m_defaultContinuationOptions, m_defaultCancellationToken, DefaultScheduler);
}
/// <summary>
@@ -2710,14 +2619,12 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
/// has already been disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWhenAny<TResult>(Task[] tasks, Func<Task, TResult> continuationFunction, CancellationToken cancellationToken)
{
if (continuationFunction == null) throw new ArgumentNullException(nameof(continuationFunction));
Contract.EndContractBlock();
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return TaskFactory<TResult>.ContinueWhenAnyImpl(tasks, continuationFunction, null, m_defaultContinuationOptions, cancellationToken, DefaultScheduler, ref stackMark);
+ return TaskFactory<TResult>.ContinueWhenAnyImpl(tasks, continuationFunction, null, m_defaultContinuationOptions, cancellationToken, DefaultScheduler);
}
/// <summary>
@@ -2751,14 +2658,12 @@ namespace System.Threading.Tasks
/// which constrain for which <see cref="System.Threading.Tasks.TaskStatus">TaskStatus</see> states a continuation
/// will be executed, are illegal with ContinueWhenAny.
/// </remarks>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWhenAny<TResult>(Task[] tasks, Func<Task, TResult> continuationFunction, TaskContinuationOptions continuationOptions)
{
if (continuationFunction == null) throw new ArgumentNullException(nameof(continuationFunction));
Contract.EndContractBlock();
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return TaskFactory<TResult>.ContinueWhenAnyImpl(tasks, continuationFunction, null,continuationOptions, m_defaultCancellationToken, DefaultScheduler, ref stackMark);
+ return TaskFactory<TResult>.ContinueWhenAnyImpl(tasks, continuationFunction, null,continuationOptions, m_defaultCancellationToken, DefaultScheduler);
}
/// <summary>
@@ -2802,15 +2707,13 @@ namespace System.Threading.Tasks
/// which constrain for which <see cref="System.Threading.Tasks.TaskStatus">TaskStatus</see> states a continuation
/// will be executed, are illegal with ContinueWhenAny.
/// </remarks>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWhenAny<TResult>(Task[] tasks, Func<Task, TResult> continuationFunction, CancellationToken cancellationToken,
TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
{
if (continuationFunction == null) throw new ArgumentNullException(nameof(continuationFunction));
Contract.EndContractBlock();
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return TaskFactory<TResult>.ContinueWhenAnyImpl(tasks, continuationFunction, null, continuationOptions, cancellationToken, scheduler, ref stackMark);
+ return TaskFactory<TResult>.ContinueWhenAnyImpl(tasks, continuationFunction, null, continuationOptions, cancellationToken, scheduler);
}
/// <summary>
@@ -2834,12 +2737,10 @@ namespace System.Threading.Tasks
/// <paramref name="tasks"/> array contains a null value.</exception>
/// <exception cref="T:System.ArgumentException">The exception that is thrown when the
/// <paramref name="tasks"/> array is empty.</exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWhenAny<TAntecedentResult, TResult>(Task<TAntecedentResult>[] tasks, Func<Task<TAntecedentResult>, TResult> continuationFunction)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
if (continuationFunction == null) throw new ArgumentNullException(nameof(continuationFunction));
- return TaskFactory<TResult>.ContinueWhenAnyImpl<TAntecedentResult>(tasks, continuationFunction, null, m_defaultContinuationOptions, m_defaultCancellationToken, DefaultScheduler, ref stackMark);
+ return TaskFactory<TResult>.ContinueWhenAnyImpl<TAntecedentResult>(tasks, continuationFunction, null, m_defaultContinuationOptions, m_defaultCancellationToken, DefaultScheduler);
}
/// <summary>
@@ -2868,15 +2769,13 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
/// has already been disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWhenAny<TAntecedentResult, TResult>(Task<TAntecedentResult>[] tasks, Func<Task<TAntecedentResult>, TResult> continuationFunction,
CancellationToken cancellationToken)
{
if (continuationFunction == null) throw new ArgumentNullException(nameof(continuationFunction));
Contract.EndContractBlock();
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return TaskFactory<TResult>.ContinueWhenAnyImpl<TAntecedentResult>(tasks, continuationFunction, null, m_defaultContinuationOptions, cancellationToken, DefaultScheduler, ref stackMark);
+ return TaskFactory<TResult>.ContinueWhenAnyImpl<TAntecedentResult>(tasks, continuationFunction, null, m_defaultContinuationOptions, cancellationToken, DefaultScheduler);
}
/// <summary>
@@ -2911,15 +2810,13 @@ namespace System.Threading.Tasks
/// which constrain for which <see cref="System.Threading.Tasks.TaskStatus">TaskStatus</see> states a continuation
/// will be executed, are illegal with ContinueWhenAny.
/// </remarks>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWhenAny<TAntecedentResult, TResult>(Task<TAntecedentResult>[] tasks, Func<Task<TAntecedentResult>, TResult> continuationFunction,
TaskContinuationOptions continuationOptions)
{
if (continuationFunction == null) throw new ArgumentNullException(nameof(continuationFunction));
Contract.EndContractBlock();
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return TaskFactory<TResult>.ContinueWhenAnyImpl<TAntecedentResult>(tasks, continuationFunction, null, continuationOptions, m_defaultCancellationToken, DefaultScheduler, ref stackMark);
+ return TaskFactory<TResult>.ContinueWhenAnyImpl<TAntecedentResult>(tasks, continuationFunction, null, continuationOptions, m_defaultCancellationToken, DefaultScheduler);
}
/// <summary>
@@ -2964,15 +2861,13 @@ namespace System.Threading.Tasks
/// which constrain for which <see cref="System.Threading.Tasks.TaskStatus">TaskStatus</see> states a continuation
/// will be executed, are illegal with ContinueWhenAny.
/// </remarks>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWhenAny<TAntecedentResult, TResult>(Task<TAntecedentResult>[] tasks, Func<Task<TAntecedentResult>, TResult> continuationFunction,
CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
{
if (continuationFunction == null) throw new ArgumentNullException(nameof(continuationFunction));
Contract.EndContractBlock();
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return TaskFactory<TResult>.ContinueWhenAnyImpl<TAntecedentResult>(tasks, continuationFunction, null, continuationOptions, cancellationToken, scheduler, ref stackMark);
+ return TaskFactory<TResult>.ContinueWhenAnyImpl<TAntecedentResult>(tasks, continuationFunction, null, continuationOptions, cancellationToken, scheduler);
}
@@ -2993,14 +2888,12 @@ namespace System.Threading.Tasks
/// <paramref name="tasks"/> array contains a null value.</exception>
/// <exception cref="T:System.ArgumentException">The exception that is thrown when the
/// <paramref name="tasks"/> array is empty.</exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task ContinueWhenAny<TAntecedentResult>(Task<TAntecedentResult>[] tasks, Action<Task<TAntecedentResult>> continuationAction)
{
if (continuationAction == null) throw new ArgumentNullException(nameof(continuationAction));
Contract.EndContractBlock();
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return TaskFactory<VoidTaskResult>.ContinueWhenAnyImpl<TAntecedentResult>(tasks, null, continuationAction, m_defaultContinuationOptions, m_defaultCancellationToken, DefaultScheduler, ref stackMark);
+ return TaskFactory<VoidTaskResult>.ContinueWhenAnyImpl<TAntecedentResult>(tasks, null, continuationAction, m_defaultContinuationOptions, m_defaultCancellationToken, DefaultScheduler);
}
/// <summary>
@@ -3025,15 +2918,13 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
/// has already been disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task ContinueWhenAny<TAntecedentResult>(Task<TAntecedentResult>[] tasks, Action<Task<TAntecedentResult>> continuationAction,
CancellationToken cancellationToken)
{
if (continuationAction == null) throw new ArgumentNullException(nameof(continuationAction));
Contract.EndContractBlock();
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return TaskFactory<VoidTaskResult>.ContinueWhenAnyImpl<TAntecedentResult>(tasks, null, continuationAction, m_defaultContinuationOptions, cancellationToken, DefaultScheduler, ref stackMark);
+ return TaskFactory<VoidTaskResult>.ContinueWhenAnyImpl<TAntecedentResult>(tasks, null, continuationAction, m_defaultContinuationOptions, cancellationToken, DefaultScheduler);
}
/// <summary>
@@ -3064,15 +2955,13 @@ namespace System.Threading.Tasks
/// which constrain for which <see cref="System.Threading.Tasks.TaskStatus">TaskStatus</see> states a continuation
/// will be executed, are illegal with ContinueWhenAny.
/// </remarks>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task ContinueWhenAny<TAntecedentResult>(Task<TAntecedentResult>[] tasks, Action<Task<TAntecedentResult>> continuationAction,
TaskContinuationOptions continuationOptions)
{
if (continuationAction == null) throw new ArgumentNullException(nameof(continuationAction));
Contract.EndContractBlock();
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return TaskFactory<VoidTaskResult>.ContinueWhenAnyImpl<TAntecedentResult>(tasks, null, continuationAction, continuationOptions, m_defaultCancellationToken, DefaultScheduler, ref stackMark);
+ return TaskFactory<VoidTaskResult>.ContinueWhenAnyImpl<TAntecedentResult>(tasks, null, continuationAction, continuationOptions, m_defaultCancellationToken, DefaultScheduler);
}
/// <summary>
@@ -3113,15 +3002,13 @@ namespace System.Threading.Tasks
/// which constrain for which <see cref="System.Threading.Tasks.TaskStatus">TaskStatus</see> states a continuation
/// will be executed, are illegal with ContinueWhenAny.
/// </remarks>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task ContinueWhenAny<TAntecedentResult>(Task<TAntecedentResult>[] tasks, Action<Task<TAntecedentResult>> continuationAction,
CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
{
if (continuationAction == null) throw new ArgumentNullException(nameof(continuationAction));
Contract.EndContractBlock();
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return TaskFactory<VoidTaskResult>.ContinueWhenAnyImpl<TAntecedentResult>(tasks, null, continuationAction, continuationOptions, cancellationToken, scheduler, ref stackMark);
+ return TaskFactory<VoidTaskResult>.ContinueWhenAnyImpl<TAntecedentResult>(tasks, null, continuationAction, continuationOptions, cancellationToken, scheduler);
}
// Check task array and return a defensive copy.
diff --git a/src/mscorlib/src/System/Threading/Tasks/TaskScheduler.cs b/src/mscorlib/src/System/Threading/Tasks/TaskScheduler.cs
index fad3fc0..d68c3fe 100644
--- a/src/mscorlib/src/System/Threading/Tasks/TaskScheduler.cs
+++ b/src/mscorlib/src/System/Threading/Tasks/TaskScheduler.cs
@@ -16,7 +16,6 @@ using System.Collections.Generic;
using System.Globalization;
using System.Threading;
using System.Security;
-using System.Security.Permissions;
using System.Collections.Concurrent;
using System.Diagnostics.Contracts;
using System.Diagnostics;
diff --git a/src/mscorlib/src/System/Threading/Tasks/future.cs b/src/mscorlib/src/System/Threading/Tasks/future.cs
index 0c3fec8..15136f1 100644
--- a/src/mscorlib/src/System/Threading/Tasks/future.cs
+++ b/src/mscorlib/src/System/Threading/Tasks/future.cs
@@ -16,7 +16,6 @@ using System.Runtime;
using System.Runtime.CompilerServices;
using System.Runtime.ExceptionServices;
using System.Security;
-using System.Security.Permissions;
using System.Threading;
using System.Diagnostics;
using System.Diagnostics.Contracts;
@@ -128,13 +127,10 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ArgumentException">
/// The <paramref name="function"/> argument is null.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task(Func<TResult> function)
: this(function, null, default(CancellationToken),
TaskCreationOptions.None, InternalTaskOptions.None, null)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- PossiblyCaptureContext(ref stackMark);
}
@@ -152,13 +148,10 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
/// has already been disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task(Func<TResult> function, CancellationToken cancellationToken)
: this(function, null, cancellationToken,
TaskCreationOptions.None, InternalTaskOptions.None, null)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- PossiblyCaptureContext(ref stackMark);
}
/// <summary>
@@ -179,12 +172,9 @@ namespace System.Threading.Tasks
/// The <paramref name="creationOptions"/> argument specifies an invalid value for <see
/// cref="T:System.Threading.Tasks.TaskCreationOptions"/>.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task(Func<TResult> function, TaskCreationOptions creationOptions)
: this(function, Task.InternalCurrentIfAttached(creationOptions), default(CancellationToken), creationOptions, InternalTaskOptions.None, null)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- PossiblyCaptureContext(ref stackMark);
}
/// <summary>
@@ -209,12 +199,9 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
/// has already been disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task(Func<TResult> function, CancellationToken cancellationToken, TaskCreationOptions creationOptions)
: this(function, Task.InternalCurrentIfAttached(creationOptions), cancellationToken, creationOptions, InternalTaskOptions.None, null)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- PossiblyCaptureContext(ref stackMark);
}
/// <summary>
@@ -228,13 +215,10 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ArgumentException">
/// The <paramref name="function"/> argument is null.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task(Func<object, TResult> function, object state)
: this(function, state, null, default(CancellationToken),
TaskCreationOptions.None, InternalTaskOptions.None, null)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- PossiblyCaptureContext(ref stackMark);
}
/// <summary>
@@ -252,13 +236,10 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
/// has already been disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task(Func<object, TResult> function, object state, CancellationToken cancellationToken)
: this(function, state, null, cancellationToken,
TaskCreationOptions.None, InternalTaskOptions.None, null)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- PossiblyCaptureContext(ref stackMark);
}
/// <summary>
@@ -280,13 +261,10 @@ namespace System.Threading.Tasks
/// The <paramref name="creationOptions"/> argument specifies an invalid value for <see
/// cref="T:System.Threading.Tasks.TaskCreationOptions"/>.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task(Func<object, TResult> function, object state, TaskCreationOptions creationOptions)
: this(function, state, Task.InternalCurrentIfAttached(creationOptions), default(CancellationToken),
creationOptions, InternalTaskOptions.None, null)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- PossiblyCaptureContext(ref stackMark);
}
@@ -313,23 +291,10 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
/// has already been disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task(Func<object, TResult> function, object state, CancellationToken cancellationToken, TaskCreationOptions creationOptions)
: this(function, state, Task.InternalCurrentIfAttached(creationOptions), cancellationToken,
creationOptions, InternalTaskOptions.None, null)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- PossiblyCaptureContext(ref stackMark);
- }
-
- internal Task(
- Func<TResult> valueSelector, Task parent, CancellationToken cancellationToken,
- TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler,
- ref StackCrawlMark stackMark) :
- this(valueSelector, parent, cancellationToken,
- creationOptions, internalOptions, scheduler)
- {
- PossiblyCaptureContext(ref stackMark);
}
/// <summary>
@@ -341,24 +306,10 @@ namespace System.Threading.Tasks
/// <param name="cancellationToken">The CancellationToken for the task.</param>
/// <param name="creationOptions">Options to control the future's behavior.</param>
/// <param name="internalOptions">Internal options to control the future's behavior.</param>
- /// <exception cref="T:System.ArgumentOutOfRangeException">The <paramref name="creationOptions"/> argument specifies
- /// a SelfReplicating <see cref="Task{TResult}"/>, which is illegal."/>.</exception>
internal Task(Func<TResult> valueSelector, Task parent, CancellationToken cancellationToken,
TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler) :
base(valueSelector, null, parent, cancellationToken, creationOptions, internalOptions, scheduler)
{
- if ((internalOptions & InternalTaskOptions.SelfReplicating) != 0)
- {
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.creationOptions, ExceptionResource.TaskT_ctor_SelfReplicating);
- }
- }
-
- internal Task(
- Func<object, TResult> valueSelector, object state, Task parent, CancellationToken cancellationToken,
- TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler, ref StackCrawlMark stackMark) :
- this(valueSelector, state, parent, cancellationToken, creationOptions, internalOptions, scheduler)
- {
- PossiblyCaptureContext(ref stackMark);
}
/// <summary>
@@ -371,22 +322,16 @@ namespace System.Threading.Tasks
/// <param name="scheduler">The task scheduler which will be used to execute the future.</param>
/// <param name="creationOptions">Options to control the future's behavior.</param>
/// <param name="internalOptions">Internal options to control the future's behavior.</param>
- /// <exception cref="T:System.ArgumentOutOfRangeException">The <paramref name="creationOptions"/> argument specifies
- /// a SelfReplicating <see cref="Task{TResult}"/>, which is illegal."/>.</exception>
internal Task(Delegate valueSelector, object state, Task parent, CancellationToken cancellationToken,
TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler) :
base(valueSelector, state, parent, cancellationToken, creationOptions, internalOptions, scheduler)
{
- if ((internalOptions & InternalTaskOptions.SelfReplicating) != 0)
- {
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.creationOptions, ExceptionResource.TaskT_ctor_SelfReplicating);
- }
}
// Internal method used by TaskFactory<TResult>.StartNew() methods
internal static Task<TResult> StartNew(Task parent, Func<TResult> function, CancellationToken cancellationToken,
- TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler, ref StackCrawlMark stackMark)
+ TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler)
{
if (function == null)
{
@@ -396,13 +341,9 @@ namespace System.Threading.Tasks
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.scheduler);
}
- if ((internalOptions & InternalTaskOptions.SelfReplicating) != 0)
- {
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.creationOptions, ExceptionResource.TaskT_ctor_SelfReplicating);
- }
// Create and schedule the future.
- Task<TResult> f = new Task<TResult>(function, parent, cancellationToken, creationOptions, internalOptions | InternalTaskOptions.QueuedByRuntime, scheduler, ref stackMark);
+ Task<TResult> f = new Task<TResult>(function, parent, cancellationToken, creationOptions, internalOptions | InternalTaskOptions.QueuedByRuntime, scheduler);
f.ScheduleAndStart(false);
return f;
@@ -410,7 +351,7 @@ namespace System.Threading.Tasks
// Internal method used by TaskFactory<TResult>.StartNew() methods
internal static Task<TResult> StartNew(Task parent, Func<object, TResult> function, object state, CancellationToken cancellationToken,
- TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler, ref StackCrawlMark stackMark)
+ TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler)
{
if (function == null)
{
@@ -420,13 +361,9 @@ namespace System.Threading.Tasks
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.scheduler);
}
- if ((internalOptions & InternalTaskOptions.SelfReplicating) != 0)
- {
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.creationOptions, ExceptionResource.TaskT_ctor_SelfReplicating);
- }
// Create and schedule the future.
- Task<TResult> f = new Task<TResult>(function, state, parent, cancellationToken, creationOptions, internalOptions | InternalTaskOptions.QueuedByRuntime, scheduler, ref stackMark);
+ Task<TResult> f = new Task<TResult>(function, state, parent, cancellationToken, creationOptions, internalOptions | InternalTaskOptions.QueuedByRuntime, scheduler);
f.ScheduleAndStart(false);
return f;
@@ -726,11 +663,9 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ArgumentNullException">
/// The <paramref name="continuationAction"/> argument is null.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task ContinueWith(Action<Task<TResult>> continuationAction)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith(continuationAction, TaskScheduler.Current, default(CancellationToken), TaskContinuationOptions.None, ref stackMark);
+ return ContinueWith(continuationAction, TaskScheduler.Current, default(CancellationToken), TaskContinuationOptions.None);
}
@@ -754,11 +689,9 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
/// has already been disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task ContinueWith(Action<Task<TResult>> continuationAction, CancellationToken cancellationToken)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith(continuationAction, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None, ref stackMark);
+ return ContinueWith(continuationAction, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None);
}
@@ -784,11 +717,9 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ArgumentNullException">
/// The <paramref name="scheduler"/> argument is null.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task ContinueWith(Action<Task<TResult>> continuationAction, TaskScheduler scheduler)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith(continuationAction, scheduler, default(CancellationToken), TaskContinuationOptions.None, ref stackMark);
+ return ContinueWith(continuationAction, scheduler, default(CancellationToken), TaskContinuationOptions.None);
}
/// <summary>
@@ -819,11 +750,9 @@ namespace System.Threading.Tasks
/// The <paramref name="continuationOptions"/> argument specifies an invalid value for <see
/// cref="T:System.Threading.Tasks.TaskContinuationOptions">TaskContinuationOptions</see>.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task ContinueWith(Action<Task<TResult>> continuationAction, TaskContinuationOptions continuationOptions)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith(continuationAction, TaskScheduler.Current, default(CancellationToken), continuationOptions, ref stackMark);
+ return ContinueWith(continuationAction, TaskScheduler.Current, default(CancellationToken), continuationOptions);
}
/// <summary>
@@ -864,17 +793,15 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
/// has already been disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task ContinueWith(Action<Task<TResult>> continuationAction, CancellationToken cancellationToken,
TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith(continuationAction, scheduler, cancellationToken, continuationOptions, ref stackMark);
+ return ContinueWith(continuationAction, scheduler, cancellationToken, continuationOptions);
}
// Same as the above overload, only with a stack mark.
internal Task ContinueWith(Action<Task<TResult>> continuationAction, TaskScheduler scheduler, CancellationToken cancellationToken,
- TaskContinuationOptions continuationOptions, ref StackCrawlMark stackMark)
+ TaskContinuationOptions continuationOptions)
{
if (continuationAction == null)
{
@@ -895,8 +822,7 @@ namespace System.Threading.Tasks
Task continuationTask = new ContinuationTaskFromResultTask<TResult>(
this, continuationAction, null,
- creationOptions, internalOptions,
- ref stackMark
+ creationOptions, internalOptions
);
// Register the continuation. If synchronous execution is requested, this may
@@ -926,11 +852,9 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ArgumentNullException">
/// The <paramref name="continuationAction"/> argument is null.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task ContinueWith(Action<Task<TResult>, Object> continuationAction, Object state)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith(continuationAction, state, TaskScheduler.Current, default(CancellationToken), TaskContinuationOptions.None, ref stackMark);
+ return ContinueWith(continuationAction, state, TaskScheduler.Current, default(CancellationToken), TaskContinuationOptions.None);
}
@@ -955,11 +879,9 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
/// has already been disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task ContinueWith(Action<Task<TResult>, Object> continuationAction, Object state,CancellationToken cancellationToken)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith(continuationAction, state, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None, ref stackMark);
+ return ContinueWith(continuationAction, state, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None);
}
@@ -986,11 +908,9 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ArgumentNullException">
/// The <paramref name="scheduler"/> argument is null.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task ContinueWith(Action<Task<TResult>, Object> continuationAction, Object state, TaskScheduler scheduler)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith(continuationAction, state, scheduler, default(CancellationToken), TaskContinuationOptions.None, ref stackMark);
+ return ContinueWith(continuationAction, state, scheduler, default(CancellationToken), TaskContinuationOptions.None);
}
/// <summary>
@@ -1022,11 +942,9 @@ namespace System.Threading.Tasks
/// The <paramref name="continuationOptions"/> argument specifies an invalid value for <see
/// cref="T:System.Threading.Tasks.TaskContinuationOptions">TaskContinuationOptions</see>.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task ContinueWith(Action<Task<TResult>, Object> continuationAction, Object state,TaskContinuationOptions continuationOptions)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith(continuationAction, state, TaskScheduler.Current, default(CancellationToken), continuationOptions, ref stackMark);
+ return ContinueWith(continuationAction, state, TaskScheduler.Current, default(CancellationToken), continuationOptions);
}
/// <summary>
@@ -1068,17 +986,15 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
/// has already been disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task ContinueWith(Action<Task<TResult>, Object> continuationAction, Object state, CancellationToken cancellationToken,
TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith(continuationAction, state, scheduler, cancellationToken, continuationOptions, ref stackMark);
+ return ContinueWith(continuationAction, state, scheduler, cancellationToken, continuationOptions);
}
// Same as the above overload, only with a stack mark.
internal Task ContinueWith(Action<Task<TResult>, Object> continuationAction, Object state, TaskScheduler scheduler, CancellationToken cancellationToken,
- TaskContinuationOptions continuationOptions, ref StackCrawlMark stackMark)
+ TaskContinuationOptions continuationOptions)
{
if (continuationAction == null)
{
@@ -1099,8 +1015,7 @@ namespace System.Threading.Tasks
Task continuationTask = new ContinuationTaskFromResultTask<TResult>(
this, continuationAction, state,
- creationOptions, internalOptions,
- ref stackMark
+ creationOptions, internalOptions
);
// Register the continuation. If synchronous execution is requested, this may
@@ -1133,11 +1048,9 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ArgumentNullException">
/// The <paramref name="continuationFunction"/> argument is null.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TNewResult> ContinueWith<TNewResult>(Func<Task<TResult>, TNewResult> continuationFunction)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith<TNewResult>(continuationFunction, TaskScheduler.Current, default(CancellationToken), TaskContinuationOptions.None, ref stackMark);
+ return ContinueWith<TNewResult>(continuationFunction, TaskScheduler.Current, default(CancellationToken), TaskContinuationOptions.None);
}
@@ -1164,11 +1077,9 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
/// has already been disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TNewResult> ContinueWith<TNewResult>(Func<Task<TResult>, TNewResult> continuationFunction, CancellationToken cancellationToken)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith<TNewResult>(continuationFunction, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None, ref stackMark);
+ return ContinueWith<TNewResult>(continuationFunction, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None);
}
/// <summary>
@@ -1196,11 +1107,9 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ArgumentNullException">
/// The <paramref name="scheduler"/> argument is null.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TNewResult> ContinueWith<TNewResult>(Func<Task<TResult>, TNewResult> continuationFunction, TaskScheduler scheduler)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith<TNewResult>(continuationFunction, scheduler, default(CancellationToken), TaskContinuationOptions.None, ref stackMark);
+ return ContinueWith<TNewResult>(continuationFunction, scheduler, default(CancellationToken), TaskContinuationOptions.None);
}
/// <summary>
@@ -1240,11 +1149,9 @@ namespace System.Threading.Tasks
/// The <paramref name="continuationOptions"/> argument specifies an invalid value for <see
/// cref="T:System.Threading.Tasks.TaskContinuationOptions">TaskContinuationOptions</see>.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TNewResult> ContinueWith<TNewResult>(Func<Task<TResult>, TNewResult> continuationFunction, TaskContinuationOptions continuationOptions)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith<TNewResult>(continuationFunction, TaskScheduler.Current, default(CancellationToken), continuationOptions, ref stackMark);
+ return ContinueWith<TNewResult>(continuationFunction, TaskScheduler.Current, default(CancellationToken), continuationOptions);
}
/// <summary>
@@ -1295,17 +1202,15 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
/// has already been disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TNewResult> ContinueWith<TNewResult>(Func<Task<TResult>, TNewResult> continuationFunction, CancellationToken cancellationToken,
TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith<TNewResult>(continuationFunction, scheduler, cancellationToken, continuationOptions, ref stackMark);
+ return ContinueWith<TNewResult>(continuationFunction, scheduler, cancellationToken, continuationOptions);
}
// Same as the above overload, just with a stack mark.
internal Task<TNewResult> ContinueWith<TNewResult>(Func<Task<TResult>, TNewResult> continuationFunction, TaskScheduler scheduler,
- CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, ref StackCrawlMark stackMark)
+ CancellationToken cancellationToken, TaskContinuationOptions continuationOptions)
{
if (continuationFunction == null)
{
@@ -1326,8 +1231,7 @@ namespace System.Threading.Tasks
Task<TNewResult> continuationFuture = new ContinuationResultTaskFromResultTask<TResult,TNewResult>(
this, continuationFunction, null,
- creationOptions, internalOptions,
- ref stackMark
+ creationOptions, internalOptions
);
// Register the continuation. If synchronous execution is requested, this may
@@ -1360,11 +1264,9 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ArgumentNullException">
/// The <paramref name="continuationFunction"/> argument is null.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TNewResult> ContinueWith<TNewResult>(Func<Task<TResult>, Object, TNewResult> continuationFunction, Object state)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith<TNewResult>(continuationFunction, state, TaskScheduler.Current, default(CancellationToken), TaskContinuationOptions.None, ref stackMark);
+ return ContinueWith<TNewResult>(continuationFunction, state, TaskScheduler.Current, default(CancellationToken), TaskContinuationOptions.None);
}
@@ -1392,12 +1294,10 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
/// has already been disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TNewResult> ContinueWith<TNewResult>(Func<Task<TResult>, Object, TNewResult> continuationFunction, Object state,
CancellationToken cancellationToken)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith<TNewResult>(continuationFunction, state, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None, ref stackMark);
+ return ContinueWith<TNewResult>(continuationFunction, state, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None);
}
/// <summary>
@@ -1426,12 +1326,10 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ArgumentNullException">
/// The <paramref name="scheduler"/> argument is null.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TNewResult> ContinueWith<TNewResult>(Func<Task<TResult>, Object, TNewResult> continuationFunction, Object state,
TaskScheduler scheduler)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith<TNewResult>(continuationFunction, state, scheduler, default(CancellationToken), TaskContinuationOptions.None, ref stackMark);
+ return ContinueWith<TNewResult>(continuationFunction, state, scheduler, default(CancellationToken), TaskContinuationOptions.None);
}
/// <summary>
@@ -1472,12 +1370,10 @@ namespace System.Threading.Tasks
/// The <paramref name="continuationOptions"/> argument specifies an invalid value for <see
/// cref="T:System.Threading.Tasks.TaskContinuationOptions">TaskContinuationOptions</see>.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TNewResult> ContinueWith<TNewResult>(Func<Task<TResult>, Object, TNewResult> continuationFunction, Object state,
TaskContinuationOptions continuationOptions)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith<TNewResult>(continuationFunction, state, TaskScheduler.Current, default(CancellationToken), continuationOptions, ref stackMark);
+ return ContinueWith<TNewResult>(continuationFunction, state, TaskScheduler.Current, default(CancellationToken), continuationOptions);
}
/// <summary>
@@ -1529,17 +1425,15 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
/// has already been disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TNewResult> ContinueWith<TNewResult>(Func<Task<TResult>, Object, TNewResult> continuationFunction, Object state,
CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith<TNewResult>(continuationFunction, state, scheduler, cancellationToken, continuationOptions, ref stackMark);
+ return ContinueWith<TNewResult>(continuationFunction, state, scheduler, cancellationToken, continuationOptions);
}
// Same as the above overload, just with a stack mark.
internal Task<TNewResult> ContinueWith<TNewResult>(Func<Task<TResult>, Object, TNewResult> continuationFunction, Object state,
- TaskScheduler scheduler, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, ref StackCrawlMark stackMark)
+ TaskScheduler scheduler, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions)
{
if (continuationFunction == null)
{
@@ -1560,8 +1454,7 @@ namespace System.Threading.Tasks
Task<TNewResult> continuationFuture = new ContinuationResultTaskFromResultTask<TResult,TNewResult>(
this, continuationFunction, state,
- creationOptions, internalOptions,
- ref stackMark
+ creationOptions, internalOptions
);
// Register the continuation. If synchronous execution is requested, this may
diff --git a/src/mscorlib/src/System/Threading/Thread.cs b/src/mscorlib/src/System/Threading/Thread.cs
index 8294c20..d280027 100644
--- a/src/mscorlib/src/System/Threading/Thread.cs
+++ b/src/mscorlib/src/System/Threading/Thread.cs
@@ -19,8 +19,6 @@ namespace System.Threading {
using System.Runtime;
using System.Runtime.InteropServices;
using System;
- using System.Security.Permissions;
- using System.Security.Principal;
using System.Globalization;
using System.Collections.Generic;
using System.Runtime.Serialization;
@@ -103,11 +101,7 @@ namespace System.Threading {
}
}
- // deliberately not [serializable]
- [ClassInterface(ClassInterfaceType.None)]
- [ComDefaultInterface(typeof(_Thread))]
- [System.Runtime.InteropServices.ComVisible(true)]
- public sealed class Thread : RuntimeThread, _Thread
+ public sealed class Thread : RuntimeThread
{
/*=========================================================================
** Data accessed from managed code that needs to be defined in
@@ -120,10 +114,6 @@ namespace System.Threading {
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;
/*=========================================================================
@@ -149,47 +139,25 @@ namespace System.Threading {
private bool m_ForbidExecutionContextMutation;
#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]
internal static CultureInfo m_CurrentCulture;
[ThreadStatic]
internal static CultureInfo m_CurrentUICulture;
-#endif
static AsyncLocal<CultureInfo> s_asyncLocalCurrentCulture;
static AsyncLocal<CultureInfo> s_asyncLocalCurrentUICulture;
static void AsyncLocalSetCurrentCulture(AsyncLocalValueChangedArgs<CultureInfo> args)
{
-#if FEATURE_LEAK_CULTURE_INFO
- Thread.CurrentThread.m_CurrentCulture = args.CurrentValue;
-#else
m_CurrentCulture = args.CurrentValue;
-#endif // FEATURE_LEAK_CULTURE_INFO
}
static void AsyncLocalSetCurrentUICulture(AsyncLocalValueChangedArgs<CultureInfo> args)
{
-#if FEATURE_LEAK_CULTURE_INFO
- Thread.CurrentThread.m_CurrentUICulture = args.CurrentValue;
-#else
m_CurrentUICulture = args.CurrentValue;
-#endif // FEATURE_LEAK_CULTURE_INFO
}
// Adding an empty default ctor for annotation purposes
@@ -209,7 +177,7 @@ namespace System.Threading {
SetStartHelper((Delegate)start,0); //0 will setup Thread with default stackSize
}
- public Thread(ThreadStart start, int maxStackSize) {
+ internal Thread(ThreadStart start, int maxStackSize) {
if (start == null) {
throw new ArgumentNullException(nameof(start));
}
@@ -226,7 +194,7 @@ namespace System.Threading {
SetStartHelper((Delegate)start, 0);
}
- public Thread(ParameterizedThreadStart start, int maxStackSize) {
+ internal Thread(ParameterizedThreadStart start, int maxStackSize) {
if (start == null) {
throw new ArgumentNullException(nameof(start));
}
@@ -236,7 +204,6 @@ namespace System.Threading {
SetStartHelper((Delegate)start, maxStackSize);
}
- [ComVisible(false)]
public override int GetHashCode()
{
return m_ManagedThreadId;
@@ -244,7 +211,6 @@ namespace System.Threading {
extern public new int ManagedThreadId
{
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
get;
}
@@ -310,14 +276,11 @@ namespace System.Threading {
// 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);
+ ExecutionContext ec = ExecutionContext.Capture();
t.SetExecutionContextHelper(ec);
}
- IPrincipal principal = null;
- StartInternal(principal, ref stackMark);
+ StartInternal(ref stackMark);
}
internal ExecutionContext ExecutionContext
@@ -333,30 +296,7 @@ namespace System.Threading {
}
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- private extern void StartInternal(IPrincipal principal, ref StackCrawlMark stackMark);
-#if FEATURE_COMPRESSEDSTACK
- /// <internalonly/>
- [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"));
- }
-
- [MethodImplAttribute(MethodImplOptions.InternalCall), ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
- internal extern IntPtr SetAppDomainStack( SafeCompressedStackHandle csHandle);
-
- [MethodImplAttribute(MethodImplOptions.InternalCall), ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
- internal extern void RestoreAppDomainStack( IntPtr appDomainStack);
-
-
- /// <internalonly/>
- [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
+ private extern void StartInternal(ref StackCrawlMark stackMark);
// Helper method to get a logical thread ID for StringBuilder (for
@@ -366,43 +306,6 @@ namespace System.Threading {
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.
- =========================================================================*/
-#pragma warning disable 618
- [SecurityPermissionAttribute(SecurityAction.Demand, ControlThread = true)]
-#pragma warning restore 618
- public void Abort()
- {
- AbortInternal();
- }
-
- // Internal helper (since we can't place security demands on
- // ecalls/fcalls).
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- private extern void AbortInternal();
-
- public bool Join(TimeSpan timeout)
- {
- long tm = (long)timeout.TotalMilliseconds;
- if (tm < -1 || tm > (long) Int32.MaxValue)
- throw new ArgumentOutOfRangeException(nameof(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.
@@ -435,10 +338,8 @@ namespace System.Threading {
a explict busy loop because the hardware can be informed that it is busy waiting. */
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
private static extern void SpinWaitInternal(int iterations);
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
public static new void SpinWait(int iterations)
{
SpinWaitInternal(iterations);
@@ -446,17 +347,14 @@ namespace System.Threading {
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
[SuppressUnmanagedCodeSecurity]
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
private static extern bool YieldInternal();
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
- public static new bool Yield()
+ internal static new bool Yield()
{
return YieldInternal();
}
public static new Thread CurrentThread {
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
get {
Contract.Ensures(Contract.Result<Thread>() != null);
return GetCurrentThreadNative();
@@ -467,8 +365,7 @@ namespace System.Threading {
private void SetStartHelper(Delegate start, int maxStackSize)
{
- // We only support default stacks in CoreCLR
- Debug.Assert(maxStackSize == 0);
+ Debug.Assert(maxStackSize >= 0);
ThreadHelper threadStartCallBack = new ThreadHelper(start);
if(start is ThreadStart)
@@ -481,10 +378,6 @@ namespace System.Threading {
}
}
- [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
- [SuppressUnmanagedCodeSecurity]
- private static extern ulong GetProcessDefaultStackSize();
-
/*=========================================================================
** PRIVATE Sets the IThreadable interface for the thread. Assumes that
** start != null.
@@ -495,122 +388,21 @@ namespace System.Threading {
/*=========================================================================
** Clean up the thread when it goes away.
=========================================================================*/
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
~Thread()
{
// Delegate to the unmanaged portion.
InternalFinalize();
}
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private extern void InternalFinalize();
#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
- {
- get
- {
- return (ApartmentState)GetApartmentStateNative();
- }
-
- set
- {
- SetApartmentStateNative((int)value, true);
- }
- }
-
- public void SetApartmentState(ApartmentState state)
- {
- bool result = SetApartmentStateHelper(state, true);
- if (!result)
- throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ApartmentStateSwitchFailed"));
- }
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private extern void StartupSetApartmentStateInternal();
#endif // FEATURE_COMINTEROP_APARTMENT_SUPPORT
- /*=========================================================================
- ** Allocates an un-named data slot. The slot is allocated on ALL the
- ** threads.
- =========================================================================*/
- 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.
- =========================================================================*/
- 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.
- =========================================================================*/
- 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.
- =========================================================================*/
- 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.
- =========================================================================*/
- 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.
- =========================================================================*/
- 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);
- }
-
-
// #threadCultureInfo
//
// Background:
@@ -623,10 +415,6 @@ namespace System.Threading {
// - 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).
@@ -636,10 +424,6 @@ namespace System.Threading {
// 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
- [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
@@ -680,16 +464,8 @@ namespace System.Threading {
// 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 (!AppContextSwitches.NoAsyncCurrentCulture)
{
@@ -708,8 +484,6 @@ namespace System.Threading {
}
}
-#if FEATURE_LEAK_CULTURE_INFO
-#endif
internal CultureInfo GetCurrentUICultureNoAppX() {
Contract.Ensures(Contract.Result<CultureInfo>() != null);
@@ -725,25 +499,11 @@ namespace System.Threading {
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
-#endif
}
// This returns the exposed context for a given context ID.
-#if FEATURE_LEAK_CULTURE_INFO
- [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
@@ -772,8 +532,6 @@ namespace System.Threading {
}
}
-#if FEATURE_LEAK_CULTURE_INFO
-#endif
set {
if (null==value) {
throw new ArgumentNullException(nameof(value));
@@ -783,16 +541,8 @@ namespace System.Threading {
// 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 (!AppContextSwitches.NoAsyncCurrentCulture)
{
@@ -810,8 +560,6 @@ namespace System.Threading {
}
}
-#if FEATURE_LEAK_CULTURE_INFO
-#endif
private CultureInfo GetCurrentCultureNoAppX() {
#if FEATURE_COREFX_GLOBALIZATION
@@ -826,25 +574,13 @@ namespace System.Threading {
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
-#endif
}
-#if !FEATURE_LEAK_CULTURE_INFO
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
[SuppressUnmanagedCodeSecurity]
private static extern void nativeInitCultureAccessors();
-#endif
/*======================================================================
** Returns the current domain in which current thread is running.
@@ -855,7 +591,7 @@ namespace System.Threading {
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private static extern AppDomain GetFastDomainInternal();
- public static AppDomain GetDomain()
+ internal static AppDomain GetDomain()
{
Contract.Ensures(Contract.Result<AppDomain>() != null);
@@ -872,7 +608,7 @@ namespace System.Threading {
/*
* This returns a unique id to identify an appdomain.
*/
- public static int GetDomainID()
+ internal static int GetDomainID()
{
return GetDomain().GetId();
}
@@ -899,267 +635,9 @@ namespace System.Threading {
[SuppressUnmanagedCodeSecurity]
private static extern void InformThreadNameChange(ThreadHandle t, String name, int len);
- internal Object AbortReason {
- get {
- object result = null;
- try
- {
- result = GetAbortReason();
- }
- catch (Exception e)
- {
- throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ExceptionStateCrossAppDomain"), e);
- }
- return result;
- }
- set { SetAbortReason(value); }
- }
-
- /*=========================================================================
- ** 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;
- }
-
[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;
- }
- }
-
- // 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).
- [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.
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- internal extern Object GetAbortReason();
-
- // Helper function to clear the AbortReason. Takes care of
- // AppDomain related cleanup if required.
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- internal extern void ClearAbortReason();
-
-
} // 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
diff --git a/src/mscorlib/src/System/Threading/ThreadAbortException.cs b/src/mscorlib/src/System/Threading/ThreadAbortException.cs
index 09ad4e1..2592504 100644
--- a/src/mscorlib/src/System/Threading/ThreadAbortException.cs
+++ b/src/mscorlib/src/System/Threading/ThreadAbortException.cs
@@ -21,7 +21,6 @@ namespace System.Threading
using System.Runtime.Serialization;
using System.Runtime.CompilerServices;
- [System.Runtime.InteropServices.ComVisible(true)]
[Serializable]
public sealed class ThreadAbortException : SystemException
{
@@ -36,10 +35,5 @@ namespace System.Threading
: base(info, context)
{
}
-
- public Object ExceptionState
- {
- get {return Thread.CurrentThread.AbortReason;}
- }
}
}
diff --git a/src/mscorlib/src/System/Threading/ThreadInterruptedException.cs b/src/mscorlib/src/System/Threading/ThreadInterruptedException.cs
index 0056611..71c0964 100644
--- a/src/mscorlib/src/System/Threading/ThreadInterruptedException.cs
+++ b/src/mscorlib/src/System/Threading/ThreadInterruptedException.cs
@@ -17,7 +17,6 @@ namespace System.Threading {
using System;
using System.Runtime.Serialization;
- [System.Runtime.InteropServices.ComVisible(true)]
[Serializable]
public class ThreadInterruptedException : SystemException {
public ThreadInterruptedException()
diff --git a/src/mscorlib/src/System/Threading/ThreadLocal.cs b/src/mscorlib/src/System/Threading/ThreadLocal.cs
index 2b996cb..eedf6d0 100644
--- a/src/mscorlib/src/System/Threading/ThreadLocal.cs
+++ b/src/mscorlib/src/System/Threading/ThreadLocal.cs
@@ -16,7 +16,6 @@
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
using System.Collections.Generic;
-using System.Security.Permissions;
using System.Diagnostics;
using System.Diagnostics.Contracts;
diff --git a/src/mscorlib/src/System/Threading/ThreadPool.cs b/src/mscorlib/src/System/Threading/ThreadPool.cs
index 451b15d..adf0615 100644
--- a/src/mscorlib/src/System/Threading/ThreadPool.cs
+++ b/src/mscorlib/src/System/Threading/ThreadPool.cs
@@ -11,36 +11,20 @@
**
=============================================================================*/
-#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.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Diagnostics.Contracts;
+using System.Diagnostics.Tracing;
+using System.Runtime.CompilerServices;
+using System.Runtime.ConstrainedExecution;
+using System.Runtime.InteropServices;
+using System.Security;
+using Microsoft.Win32;
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.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
@@ -55,78 +39,76 @@ namespace System.Threading
public static bool enableWorkerTracking;
public static readonly ThreadPoolWorkQueue workQueue = new ThreadPoolWorkQueue();
-
- static ThreadPoolGlobals()
- {
- }
}
internal sealed class ThreadPoolWorkQueue
{
- // Simple sparsely populated array to allow lock-free reading.
- internal class SparseArray<T> where T : class
+ internal static class WorkStealingQueueList
{
- private volatile T[] m_array;
+ private static volatile WorkStealingQueue[] _queues = new WorkStealingQueue[0];
- internal SparseArray(int initialSize)
- {
- m_array = new T[initialSize];
- }
+ public static WorkStealingQueue[] Queues => _queues;
- internal T[] Current
- {
- get { return m_array; }
- }
-
- internal int Add(T e)
+ public static void Add(WorkStealingQueue queue)
{
+ Debug.Assert(queue != null);
while (true)
{
- T[] array = m_array;
- lock (array)
+ WorkStealingQueue[] oldQueues = _queues;
+ Debug.Assert(Array.IndexOf(oldQueues, queue) == -1);
+
+ var newQueues = new WorkStealingQueue[oldQueues.Length + 1];
+ Array.Copy(oldQueues, 0, newQueues, 0, oldQueues.Length);
+ newQueues[newQueues.Length - 1] = queue;
+ if (Interlocked.CompareExchange(ref _queues, newQueues, oldQueues) == oldQueues)
{
- for (int i = 0; i < array.Length; i++)
- {
- if (array[i] == null)
- {
- Volatile.Write(ref array[i], e);
- return i;
- }
- else if (i == array.Length - 1)
- {
- // Must resize. If there was a race condition, we start over again.
- if (array != m_array)
- continue;
-
- T[] newArray = new T[array.Length * 2];
- Array.Copy(array, newArray, i + 1);
- newArray[i + 1] = e;
- m_array = newArray;
- return i + 1;
- }
- }
+ break;
}
}
}
- internal void Remove(T e)
+ public static void Remove(WorkStealingQueue queue)
{
- T[] array = m_array;
- lock (array)
+ Debug.Assert(queue != null);
+ while (true)
{
- for (int i = 0; i < m_array.Length; i++)
+ WorkStealingQueue[] oldQueues = _queues;
+ if (oldQueues.Length == 0)
{
- if (m_array[i] == e)
- {
- Volatile.Write(ref m_array[i], null);
- break;
- }
+ return;
+ }
+
+ int pos = Array.IndexOf(oldQueues, queue);
+ if (pos == -1)
+ {
+ Debug.Fail("Should have found the queue");
+ return;
+ }
+
+ var newQueues = new WorkStealingQueue[oldQueues.Length - 1];
+ if (pos == 0)
+ {
+ Array.Copy(oldQueues, 1, newQueues, 0, newQueues.Length);
+ }
+ else if (pos == oldQueues.Length - 1)
+ {
+ Array.Copy(oldQueues, 0, newQueues, 0, newQueues.Length);
+ }
+ else
+ {
+ Array.Copy(oldQueues, 0, newQueues, 0, pos);
+ Array.Copy(oldQueues, pos + 1, newQueues, pos, newQueues.Length - pos);
+ }
+
+ if (Interlocked.CompareExchange(ref _queues, newQueues, oldQueues) == oldQueues)
+ {
+ break;
}
}
}
}
- internal class WorkStealingQueue
+ internal sealed class WorkStealingQueue
{
private const int INITIAL_SIZE = 32;
internal volatile IThreadPoolWorkItem[] m_array = new IThreadPoolWorkItem[INITIAL_SIZE];
@@ -142,7 +124,7 @@ namespace System.Threading
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)
{
@@ -176,7 +158,7 @@ namespace System.Threading
finally
{
if (lockTaken)
- m_foreignLock.Exit(true);
+ m_foreignLock.Exit(useMemoryBarrier:true);
}
}
@@ -201,7 +183,7 @@ namespace System.Threading
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];
@@ -218,7 +200,7 @@ namespace System.Threading
finally
{
if (lockTaken)
- m_foreignLock.Exit(false);
+ m_foreignLock.Exit(useMemoryBarrier:false);
}
}
}
@@ -229,13 +211,9 @@ namespace System.Threading
// Fast path: check the tail. If equal, we can skip the lock.
if (m_array[(m_tailIndex - 1) & m_mask] == obj)
{
- IThreadPoolWorkItem unused;
- if (LocalPop(out unused))
- {
- Debug.Assert(unused == obj);
- return true;
- }
- return false;
+ IThreadPoolWorkItem unused = LocalPop();
+ Debug.Assert(unused == null || unused == obj);
+ return unused != null;
}
// Else, do an O(N) search for the work item. The theory of work stealing and our
@@ -276,7 +254,7 @@ namespace System.Threading
finally
{
if (lockTaken)
- m_foreignLock.Exit(false);
+ m_foreignLock.Exit(useMemoryBarrier:false);
}
}
}
@@ -284,19 +262,20 @@ namespace System.Threading
return false;
}
+ public IThreadPoolWorkItem LocalPop() => m_headIndex < m_tailIndex ? LocalPopCore() : null;
+
[SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "Reviewed for thread safety")]
- public bool LocalPop(out IThreadPoolWorkItem obj)
+ private IThreadPoolWorkItem LocalPopCore()
{
while (true)
{
- // Decrement the tail using a fence to ensure subsequent read doesn't come before.
int tail = m_tailIndex;
if (m_headIndex >= tail)
{
- obj = null;
- return false;
+ return null;
}
+ // Decrement the tail using a fence to ensure subsequent read doesn't come before.
tail -= 1;
Interlocked.Exchange(ref m_tailIndex, tail);
@@ -304,13 +283,13 @@ namespace System.Threading
if (m_headIndex <= tail)
{
int idx = tail & m_mask;
- obj = Volatile.Read(ref m_array[idx]);
+ IThreadPoolWorkItem obj = Volatile.Read(ref m_array[idx]);
// Check for nulls in the array.
if (obj == null) continue;
m_array[idx] = null;
- return true;
+ return obj;
}
else
{
@@ -324,241 +303,93 @@ namespace System.Threading
{
// Element still available. Take it.
int idx = tail & m_mask;
- obj = Volatile.Read(ref m_array[idx]);
+ IThreadPoolWorkItem obj = Volatile.Read(ref m_array[idx]);
// Check for nulls in the array.
if (obj == null) continue;
m_array[idx] = null;
- return true;
+ return obj;
}
else
{
// If we encountered a race condition and element was stolen, restore the tail.
m_tailIndex = tail + 1;
- obj = null;
- return false;
+ return null;
}
}
finally
{
if (lockTaken)
- m_foreignLock.Exit(false);
+ m_foreignLock.Exit(useMemoryBarrier:false);
}
}
}
}
- public bool TrySteal(out IThreadPoolWorkItem obj, ref bool missedSteal)
- {
- return TrySteal(out obj, ref missedSteal, 0); // no blocking by default.
- }
+ public bool CanSteal => m_headIndex < m_tailIndex;
- private bool TrySteal(out IThreadPoolWorkItem obj, ref bool missedSteal, int millisecondsTimeout)
+ public IThreadPoolWorkItem TrySteal(ref bool missedSteal)
{
- obj = null;
-
while (true)
{
- if (m_headIndex >= m_tailIndex)
- return false;
-
- bool taken = false;
- try
+ if (CanSteal)
{
- m_foreignLock.TryEnter(millisecondsTimeout, ref taken);
- if (taken)
+ bool taken = false;
+ try
{
- // Increment head, and ensure read of tail doesn't move before it (fence).
- int head = m_headIndex;
- Interlocked.Exchange(ref m_headIndex, head + 1);
-
- if (head < m_tailIndex)
+ m_foreignLock.TryEnter(ref taken);
+ if (taken)
{
- int idx = head & m_mask;
- obj = Volatile.Read(ref m_array[idx]);
+ // Increment head, and ensure read of tail doesn't move before it (fence).
+ int head = m_headIndex;
+ Interlocked.Exchange(ref m_headIndex, head + 1);
- // Check for nulls in the array.
- if (obj == null) continue;
+ if (head < m_tailIndex)
+ {
+ int idx = head & m_mask;
+ IThreadPoolWorkItem obj = Volatile.Read(ref m_array[idx]);
- m_array[idx] = null;
- return true;
- }
- else
- {
- // Failed, restore head.
- m_headIndex = head;
- obj = null;
- missedSteal = true;
+ // Check for nulls in the array.
+ if (obj == null) continue;
+
+ m_array[idx] = null;
+ return obj;
+ }
+ else
+ {
+ // Failed, restore head.
+ m_headIndex = head;
+ }
}
}
- else
+ finally
{
- missedSteal = true;
+ if (taken)
+ m_foreignLock.Exit(useMemoryBarrier:false);
}
- }
- finally
- {
- if (taken)
- m_foreignLock.Exit(false);
- }
-
- return false;
- }
- }
- }
-
- internal class QueueSegment
- {
- // Holds a segment of the queue. Enqueues/Dequeues start at element 0, and work their way up.
- internal readonly IThreadPoolWorkItem[] nodes;
- private const int QueueSegmentLength = 256;
-
- // Holds the indexes of the lowest and highest valid elements of the nodes array.
- // The low index is in the lower 16 bits, high index is in the upper 16 bits.
- // Use GetIndexes and CompareExchangeIndexes to manipulate this.
- private volatile int indexes;
-
- // The next segment in the queue.
- public volatile QueueSegment Next;
-
-
- const int SixteenBits = 0xffff;
-
- void GetIndexes(out int upper, out int lower)
- {
- int i = indexes;
- upper = (i >> 16) & SixteenBits;
- lower = i & SixteenBits;
-
- Debug.Assert(upper >= lower);
- Debug.Assert(upper <= nodes.Length);
- Debug.Assert(lower <= nodes.Length);
- Debug.Assert(upper >= 0);
- Debug.Assert(lower >= 0);
- }
- bool CompareExchangeIndexes(ref int prevUpper, int newUpper, ref int prevLower, int newLower)
- {
- Debug.Assert(newUpper >= newLower);
- Debug.Assert(newUpper <= nodes.Length);
- Debug.Assert(newLower <= nodes.Length);
- Debug.Assert(newUpper >= 0);
- Debug.Assert(newLower >= 0);
- Debug.Assert(newUpper >= prevUpper);
- Debug.Assert(newLower >= prevLower);
- Debug.Assert(newUpper == prevUpper ^ newLower == prevLower);
-
- int oldIndexes = (prevUpper << 16) | (prevLower & SixteenBits);
- int newIndexes = (newUpper << 16) | (newLower & SixteenBits);
- int prevIndexes = Interlocked.CompareExchange(ref indexes, newIndexes, oldIndexes);
- prevUpper = (prevIndexes >> 16) & SixteenBits;
- prevLower = prevIndexes & SixteenBits;
- return prevIndexes == oldIndexes;
- }
-
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
- public QueueSegment()
- {
- Debug.Assert(QueueSegmentLength <= SixteenBits);
- nodes = new IThreadPoolWorkItem[QueueSegmentLength];
- }
-
-
- public bool IsUsedUp()
- {
- int upper, lower;
- GetIndexes(out upper, out lower);
- return (upper == nodes.Length) &&
- (lower == nodes.Length);
- }
-
- public bool TryEnqueue(IThreadPoolWorkItem node)
- {
- //
- // If there's room in this segment, atomically increment the upper count (to reserve
- // space for this node), then store the node.
- // Note that this leaves a window where it will look like there is data in that
- // array slot, but it hasn't been written yet. This is taken care of in TryDequeue
- // with a busy-wait loop, waiting for the element to become non-null. This implies
- // that we can never store null nodes in this data structure.
- //
- Debug.Assert(null != node);
-
- int upper, lower;
- GetIndexes(out upper, out lower);
-
- while (true)
- {
- if (upper == nodes.Length)
- return false;
-
- if (CompareExchangeIndexes(ref upper, upper + 1, ref lower, lower))
- {
- Debug.Assert(Volatile.Read(ref nodes[upper]) == null);
- Volatile.Write(ref nodes[upper], node);
- return true;
+ missedSteal = true;
}
- }
- }
-
- [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "Reviewed for thread safety")]
- public bool TryDequeue(out IThreadPoolWorkItem node)
- {
- //
- // If there are nodes in this segment, increment the lower count, then take the
- // element we find there.
- //
- int upper, lower;
- GetIndexes(out upper, out lower);
-
- while(true)
- {
- if (lower == upper)
- {
- node = null;
- return false;
- }
-
- if (CompareExchangeIndexes(ref upper, upper, ref lower, lower + 1))
- {
- // It's possible that a concurrent call to Enqueue hasn't yet
- // written the node reference to the array. We need to spin until
- // it shows up.
- SpinWait spinner = new SpinWait();
- while ((node = Volatile.Read(ref nodes[lower])) == null)
- spinner.SpinOnce();
-
- // Null-out the reference so the object can be GC'd earlier.
- nodes[lower] = null;
- return true;
- }
+ return null;
}
}
}
- // The head and tail of the queue. We enqueue to the head, and dequeue from the tail.
- internal volatile QueueSegment queueHead;
- internal volatile QueueSegment queueTail;
internal bool loggingEnabled;
-
- internal static readonly SparseArray<WorkStealingQueue> allThreadQueues = new SparseArray<WorkStealingQueue>(16);
+ internal readonly ConcurrentQueue<IThreadPoolWorkItem> workItems = new ConcurrentQueue<IThreadPoolWorkItem>();
private volatile int numOutstandingThreadRequests = 0;
public ThreadPoolWorkQueue()
{
- queueTail = queueHead = new QueueSegment();
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()
{
@@ -602,12 +433,12 @@ namespace System.Threading
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)
{
@@ -615,18 +446,7 @@ namespace System.Threading
}
else
{
- QueueSegment head = queueHead;
-
- while (!head.TryEnqueue(callback))
- {
- Interlocked.CompareExchange(ref head.Next, new QueueSegment(), null);
-
- while (head.Next != null)
- {
- Interlocked.CompareExchange(ref queueHead, head.Next, head);
- head = queueHead;
- }
- }
+ workItems.Enqueue(callback);
}
EnsureThreadRequested();
@@ -635,67 +455,43 @@ namespace System.Threading
internal bool LocalFindAndPop(IThreadPoolWorkItem callback)
{
ThreadPoolWorkQueueThreadLocals tl = ThreadPoolWorkQueueThreadLocals.threadLocals;
- if (null == tl)
- return false;
-
- return tl.workStealingQueue.LocalFindAndPop(callback);
+ return tl != null && tl.workStealingQueue.LocalFindAndPop(callback);
}
- public void Dequeue(ThreadPoolWorkQueueThreadLocals tl, out IThreadPoolWorkItem callback, out bool missedSteal)
+ public IThreadPoolWorkItem Dequeue(ThreadPoolWorkQueueThreadLocals tl, ref bool missedSteal)
{
- callback = null;
- missedSteal = false;
- WorkStealingQueue wsq = tl.workStealingQueue;
+ WorkStealingQueue localWsq = tl.workStealingQueue;
+ IThreadPoolWorkItem callback;
- if (wsq.LocalPop(out callback))
- Debug.Assert(null != callback);
-
- if (null == callback)
+ if ((callback = localWsq.LocalPop()) == null && // first try the local queue
+ !workItems.TryDequeue(out callback)) // then try the global queue
{
- QueueSegment tail = queueTail;
- while (true)
- {
- if (tail.TryDequeue(out callback))
- {
- Debug.Assert(null != callback);
- break;
- }
-
- if (null == tail.Next || !tail.IsUsedUp())
- {
- break;
- }
- else
- {
- Interlocked.CompareExchange(ref queueTail, tail.Next, tail);
- tail = queueTail;
- }
- }
- }
-
- if (null == callback)
- {
- WorkStealingQueue[] otherQueues = allThreadQueues.Current;
- int c = otherQueues.Length;
+ // finally try to steal from another thread's local queue
+ WorkStealingQueue[] queues = WorkStealingQueueList.Queues;
+ int c = queues.Length;
+ Debug.Assert(c > 0, "There must at least be a queue for this thread.");
int maxIndex = c - 1;
int i = tl.random.Next(c);
while (c > 0)
{
i = (i < maxIndex) ? i + 1 : 0;
- WorkStealingQueue otherQueue = Volatile.Read(ref otherQueues[i]);
- if (otherQueue != null &&
- otherQueue != wsq &&
- otherQueue.TrySteal(out callback, ref missedSteal))
+ WorkStealingQueue otherQueue = queues[i];
+ if (otherQueue != localWsq && otherQueue.CanSteal)
{
- Debug.Assert(null != callback);
- break;
+ callback = otherQueue.TrySteal(ref missedSteal);
+ if (callback != null)
+ {
+ break;
+ }
}
c--;
}
}
+
+ return callback;
}
- static internal bool Dispatch()
+ internal static bool Dispatch()
{
var workQueue = ThreadPoolGlobals.workQueue;
//
@@ -735,85 +531,66 @@ namespace System.Threading
//
while ((Environment.TickCount - quantumStartTime) < ThreadPoolGlobals.TP_QUANTUM)
{
- //
- // Dequeue and EnsureThreadRequested must be protected from ThreadAbortException.
- // These are fast, so this will not delay aborts/AD-unloads for very long.
- //
- try { }
- finally
- {
- bool missedSteal = false;
- workQueue.Dequeue(tl, out workItem, out missedSteal);
-
- if (workItem == null)
- {
- //
- // No work. We're going to return to the VM once we leave this protected region.
- // If we missed a steal, though, there may be more work in the queue.
- // Instead of looping around and trying again, we'll just request another thread. This way
- // we won't starve other AppDomains while we spin trying to get locks, and hopefully the thread
- // that owns the contended work-stealing queue will pick up its own workitems in the meantime,
- // which will be more efficient than this thread doing it anyway.
- //
- needAnotherThread = missedSteal;
- }
- else
- {
- //
- // If we found work, there may be more work. Ask for another thread so that the other work can be processed
- // in parallel. Note that this will only ask for a max of #procs threads, so it's safe to call it for every dequeue.
- //
- workQueue.EnsureThreadRequested();
- }
- }
+ bool missedSteal = false;
+ workItem = workQueue.Dequeue(tl, ref missedSteal);
if (workItem == null)
{
+ //
+ // No work. We're going to return to the VM once we leave this protected region.
+ // If we missed a steal, though, there may be more work in the queue.
+ // Instead of looping around and trying again, we'll just request another thread. This way
+ // we won't starve other AppDomains while we spin trying to get locks, and hopefully the thread
+ // that owns the contended work-stealing queue will pick up its own workitems in the meantime,
+ // which will be more efficient than this thread doing it anyway.
+ //
+ needAnotherThread = missedSteal;
+
// Tell the VM we're returning normally, not because Hill Climbing asked us to return.
return true;
}
- else
- {
- if (workQueue.loggingEnabled)
- System.Diagnostics.Tracing.FrameworkEventSource.Log.ThreadPoolDequeueWorkObject(workItem);
- //
- // Execute the workitem outside of any finally blocks, so that it can be aborted if needed.
- //
- if (ThreadPoolGlobals.enableWorkerTracking)
+ if (workQueue.loggingEnabled)
+ System.Diagnostics.Tracing.FrameworkEventSource.Log.ThreadPoolDequeueWorkObject(workItem);
+
+ //
+ // If we found work, there may be more work. Ask for another thread so that the other work can be processed
+ // in parallel. Note that this will only ask for a max of #procs threads, so it's safe to call it for every dequeue.
+ //
+ workQueue.EnsureThreadRequested();
+
+ //
+ // Execute the workitem outside of any finally blocks, so that it can be aborted if needed.
+ //
+ if (ThreadPoolGlobals.enableWorkerTracking)
+ {
+ bool reportedStatus = false;
+ try
{
- bool reportedStatus = false;
- try
- {
- try { }
- finally
- {
- ThreadPool.ReportThreadStatus(true);
- reportedStatus = true;
- }
- workItem.ExecuteWorkItem();
- workItem = null;
- }
- finally
- {
- if (reportedStatus)
- ThreadPool.ReportThreadStatus(false);
- }
+ ThreadPool.ReportThreadStatus(isWorking: true);
+ reportedStatus = true;
+ workItem.ExecuteWorkItem();
}
- else
+ finally
{
- workItem.ExecuteWorkItem();
- workItem = null;
+ if (reportedStatus)
+ ThreadPool.ReportThreadStatus(isWorking: false);
}
-
- //
- // Notify the VM that we executed this workitem. This is also our opportunity to ask whether Hill Climbing wants
- // us to return the thread to the pool or not.
- //
- if (!ThreadPool.NotifyWorkItemComplete())
- return false;
}
+ else
+ {
+ workItem.ExecuteWorkItem();
+ }
+ workItem = null;
+
+ //
+ // Notify the VM that we executed this workitem. This is also our opportunity to ask whether Hill Climbing wants
+ // us to return the thread to the pool or not.
+ //
+ if (!ThreadPool.NotifyWorkItemComplete())
+ return false;
}
+
// If we get here, it's because our quantum expired. Tell the VM we're returning normally.
return true;
}
@@ -825,8 +602,7 @@ namespace System.Threading
// 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.
@@ -845,11 +621,36 @@ namespace System.Threading
}
// 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;
}
}
+ // Simple random number generator. We don't need great randomness, we just need a little and for it to be fast.
+ internal struct FastRandom // xorshift prng
+ {
+ private uint _w, _x, _y, _z;
+
+ public FastRandom(int seed)
+ {
+ _x = (uint)seed;
+ _w = 88675123;
+ _y = 362436069;
+ _z = 521288629;
+ }
+
+ public int Next(int maxValue)
+ {
+ Debug.Assert(maxValue > 0);
+
+ uint t = _x ^ (_x << 11);
+ _x = _y; _y = _z; _z = _w;
+ _w = _w ^ (_w >> 19) ^ (t ^ (t >> 8));
+
+ return (int)(_w % (uint)maxValue);
+ }
+ }
+
// Holds a WorkStealingQueue, and remmoves it from the list when this object is no longer referened.
internal sealed class ThreadPoolWorkQueueThreadLocals
{
@@ -858,13 +659,13 @@ namespace System.Threading
public readonly ThreadPoolWorkQueue workQueue;
public readonly ThreadPoolWorkQueue.WorkStealingQueue workStealingQueue;
- public readonly Random random = new Random(Thread.CurrentThread.ManagedThreadId);
+ public FastRandom random = new FastRandom(Thread.CurrentThread.ManagedThreadId); // mutable struct, do not copy or make readonly
public ThreadPoolWorkQueueThreadLocals(ThreadPoolWorkQueue tpq)
{
workQueue = tpq;
workStealingQueue = new ThreadPoolWorkQueue.WorkStealingQueue();
- ThreadPoolWorkQueue.allThreadQueues.Add(workStealingQueue);
+ ThreadPoolWorkQueue.WorkStealingQueueList.Add(workStealingQueue);
}
private void CleanUp()
@@ -873,28 +674,15 @@ namespace System.Threading
{
if (null != workQueue)
{
- bool done = false;
- while (!done)
+ IThreadPoolWorkItem cb;
+ while ((cb = workStealingQueue.LocalPop()) != null)
{
- // Ensure that we won't be aborted between LocalPop and Enqueue.
- try { }
- finally
- {
- IThreadPoolWorkItem cb = null;
- if (workStealingQueue.LocalPop(out cb))
- {
- Debug.Assert(null != cb);
- workQueue.Enqueue(cb, true);
- }
- else
- {
- done = true;
- }
- }
+ Debug.Assert(null != cb);
+ workQueue.Enqueue(cb, forceGlobal: true);
}
}
- ThreadPoolWorkQueue.allThreadQueues.Remove(workStealingQueue);
+ ThreadPoolWorkQueue.WorkStealingQueueList.Remove(workStealingQueue);
}
}
@@ -912,34 +700,19 @@ namespace System.Threading
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)
{
registeredWaitHandle = handle;
}
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
internal void SetWaitObject(WaitHandle waitObject)
{
// needed for DangerousAddRef
@@ -957,7 +730,6 @@ namespace System.Threading
}
}
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
internal bool Unregister(
WaitHandle waitObject // object to be notified when all callbacks to delegates have completed
)
@@ -1009,10 +781,8 @@ namespace System.Threading
return result;
}
- private bool ValidHandle()
- {
- return (registeredWaitHandle != InvalidHandle && registeredWaitHandle != IntPtr.Zero);
- }
+ private bool ValidHandle() =>
+ registeredWaitHandle != InvalidHandle && registeredWaitHandle != IntPtr.Zero;
~RegisteredWaitHandleSafe()
{
@@ -1071,9 +841,8 @@ namespace System.Threading
private static extern bool UnregisterWaitNative(IntPtr handle, SafeHandle waitObject);
}
-[System.Runtime.InteropServices.ComVisible(true)]
public sealed class RegisteredWaitHandle : MarshalByRefObject {
- private RegisteredWaitHandleSafe internalRegisteredWait;
+ private readonly RegisteredWaitHandleSafe internalRegisteredWait;
internal RegisteredWaitHandle()
{
@@ -1090,8 +859,6 @@ namespace System.Threading
internalRegisteredWait.SetWaitObject(waitObject);
}
-
-[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
@@ -1101,10 +868,8 @@ namespace System.Threading
}
}
- [System.Runtime.InteropServices.ComVisible(true)]
public delegate void WaitCallback(Object state);
- [System.Runtime.InteropServices.ComVisible(true)]
public delegate void WaitOrTimerCallback(Object state, bool timedOut); // signalled or timed out
//
@@ -1115,10 +880,7 @@ namespace System.Threading
//
internal static class _ThreadPoolWaitCallback
{
- static internal bool PerformWaitCallback()
- {
- return ThreadPoolWorkQueue.Dispatch();
- }
+ internal static bool PerformWaitCallback() => ThreadPoolWorkQueue.Dispatch();
}
//
@@ -1138,11 +900,9 @@ namespace System.Threading
internal sealed class QueueUserWorkItemCallback : IThreadPoolWorkItem
{
- static QueueUserWorkItemCallback() {}
-
private WaitCallback callback;
- private ExecutionContext context;
- private Object state;
+ private readonly ExecutionContext context;
+ private readonly Object state;
#if DEBUG
volatile int executed;
@@ -1173,7 +933,7 @@ namespace System.Threading
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)
@@ -1184,7 +944,7 @@ namespace System.Threading
}
else
{
- ExecutionContext.Run(context, ccb, this, true);
+ ExecutionContext.Run(context, ccb, this);
}
}
@@ -1193,16 +953,16 @@ namespace System.Threading
#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);
}
@@ -1210,10 +970,8 @@ namespace System.Threading
internal sealed class QueueUserWorkItemCallbackDefaultContext : IThreadPoolWorkItem
{
- static QueueUserWorkItemCallbackDefaultContext() { }
-
private WaitCallback callback;
- private Object state;
+ private readonly Object state;
#if DEBUG
private volatile int executed;
@@ -1243,9 +1001,9 @@ namespace System.Threading
void IThreadPoolWorkItem.ExecuteWorkItem()
{
#if DEBUG
- MarkExecuted(false);
+ MarkExecuted(aborted:false);
#endif
- ExecutionContext.Run(ExecutionContext.PreAllocatedDefault, ccb, this, true);
+ ExecutionContext.Run(ExecutionContext.Default, ccb, this);
}
void IThreadPoolWorkItem.MarkAborted(ThreadAbortException tae)
@@ -1253,16 +1011,16 @@ namespace System.Threading
#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);
@@ -1271,46 +1029,38 @@ namespace System.Threading
internal class _ThreadPoolWaitOrTimerCallback
{
- static _ThreadPoolWaitOrTimerCallback() {}
-
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)
+ internal _ThreadPoolWaitOrTimerCallback(WaitOrTimerCallback waitOrTimerCallback, Object state, bool compressStack)
{
_waitOrTimerCallback = waitOrTimerCallback;
_state = state;
- if (compressStack && !ExecutionContext.IsFlowSuppressed())
+ if (compressStack)
{
// capture the exection context
- _executionContext = ExecutionContext.Capture(
- ref stackMark,
- ExecutionContext.CaptureOptions.IgnoreSyncCtx | ExecutionContext.CaptureOptions.OptimizeDefaultCase);
+ _executionContext = ExecutionContext.Capture();
}
}
- 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!");
@@ -1322,20 +1072,13 @@ namespace System.Threading
}
else
{
- using (ExecutionContext executionContext = helper._executionContext.CreateCopy())
- {
- if (timedOut)
- ExecutionContext.Run(executionContext, _ccbt, helper, true);
- else
- ExecutionContext.Run(executionContext, _ccbf, helper, true);
- }
+ ExecutionContext.Run(helper._executionContext, timedOut ? _ccbt : _ccbf, helper);
}
}
}
[CLSCompliant(false)]
- [System.Runtime.InteropServices.ComVisible(true)]
unsafe public delegate void IOCompletionCallback(uint errorCode, // Error code
uint numBytes, // No. of bytes transferred
NativeOverlapped* pOVERLAP // ptr to OVERLAP structure
@@ -1343,7 +1086,6 @@ namespace System.Threading
public static class ThreadPool
{
-
public static bool SetMaxThreads(int workerThreads, int completionPortThreads)
{
return SetMaxThreadsNative(workerThreads, completionPortThreads);
@@ -1412,7 +1154,7 @@ namespace System.Threading
if (callBack != null)
{
- _ThreadPoolWaitOrTimerCallback callBackHelper = new _ThreadPoolWaitOrTimerCallback(callBack, state, compressStack, ref stackMark);
+ _ThreadPoolWaitOrTimerCallback callBackHelper = new _ThreadPoolWaitOrTimerCallback(callBack, state, compressStack);
state = (Object)callBackHelper;
// call SetWaitObject before native call so that waitObject won't be closed before threadpoolmgr registration
// this could occur if callback were to fire before SetWaitObject does its addref
@@ -1533,141 +1275,84 @@ namespace System.Threading
StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
return RegisterWaitForSingleObject(waitObject,callBack,state,(UInt32)tm,executeOnlyOnce,ref stackMark,false);
}
-
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
- public static bool QueueUserWorkItem(
- WaitCallback callBack, // NOTE: we do not expose options that allow the callback to be queued as an APC
- Object state
- )
- {
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return QueueUserWorkItemHelper(callBack,state,ref stackMark,true);
- }
-
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
- public static bool QueueUserWorkItem(
- WaitCallback callBack // NOTE: we do not expose options that allow the callback to be queued as an APC
- )
- {
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return QueueUserWorkItemHelper(callBack,null,ref stackMark,true);
- }
-
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
- public static bool UnsafeQueueUserWorkItem(
- WaitCallback callBack, // NOTE: we do not expose options that allow the callback to be queued as an APC
- Object state
- )
- {
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return QueueUserWorkItemHelper(callBack,state,ref stackMark,false);
- }
- //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 )
- {
- bool success = true;
+ public static bool QueueUserWorkItem(WaitCallback callBack) =>
+ QueueUserWorkItem(callBack, null);
- if (callBack != null)
+ public static bool QueueUserWorkItem(WaitCallback callBack, object state)
+ {
+ 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.
+ ThrowHelper.ThrowArgumentNullException(ExceptionArgument.callBack);
+ }
- EnsureVMInitialized();
+ EnsureVMInitialized();
- //
- // 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;
+ ExecutionContext context = ExecutionContext.Ca