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/AbandonedMutexException.cs85
-rw-r--r--src/mscorlib/src/System/Threading/ApartmentState.cs27
-rw-r--r--src/mscorlib/src/System/Threading/AsyncLocal.cs487
-rw-r--r--src/mscorlib/src/System/Threading/AutoResetEvent.cs24
-rw-r--r--src/mscorlib/src/System/Threading/CancellationToken.cs32
-rw-r--r--src/mscorlib/src/System/Threading/CancellationTokenRegistration.cs6
-rw-r--r--src/mscorlib/src/System/Threading/CancellationTokenSource.cs48
-rw-r--r--src/mscorlib/src/System/Threading/ClrThreadPoolBoundHandle.cs319
-rw-r--r--src/mscorlib/src/System/Threading/ClrThreadPoolBoundHandleOverlapped.cs52
-rw-r--r--src/mscorlib/src/System/Threading/ClrThreadPoolPreAllocatedOverlapped.cs105
-rw-r--r--src/mscorlib/src/System/Threading/CountdownEvent.cs589
-rw-r--r--src/mscorlib/src/System/Threading/EventResetMode.cs26
-rw-r--r--src/mscorlib/src/System/Threading/EventWaitHandle.cs59
-rw-r--r--src/mscorlib/src/System/Threading/ExecutionContext.cs380
-rw-r--r--src/mscorlib/src/System/Threading/Interlocked.cs45
-rw-r--r--src/mscorlib/src/System/Threading/LazyInitializer.cs131
-rw-r--r--src/mscorlib/src/System/Threading/LockRecursionException.cs30
-rw-r--r--src/mscorlib/src/System/Threading/ManualResetEvent.cs24
-rw-r--r--src/mscorlib/src/System/Threading/ManualResetEventSlim.cs16
-rw-r--r--src/mscorlib/src/System/Threading/Monitor.cs35
-rw-r--r--src/mscorlib/src/System/Threading/Mutex.cs92
-rw-r--r--src/mscorlib/src/System/Threading/Overlapped.cs100
-rw-r--r--src/mscorlib/src/System/Threading/ParameterizedThreadStart.cs23
-rw-r--r--src/mscorlib/src/System/Threading/ReaderWriterLockSlim.cs1311
-rw-r--r--src/mscorlib/src/System/Threading/Semaphore.cs32
-rw-r--r--src/mscorlib/src/System/Threading/SemaphoreFullException.cs27
-rw-r--r--src/mscorlib/src/System/Threading/SemaphoreSlim.cs37
-rw-r--r--src/mscorlib/src/System/Threading/SendOrPostCallback.cs16
-rw-r--r--src/mscorlib/src/System/Threading/SpinWait.cs59
-rw-r--r--src/mscorlib/src/System/Threading/SynchronizationContext.cs46
-rw-r--r--src/mscorlib/src/System/Threading/SynchronizationLockException.cs43
-rw-r--r--src/mscorlib/src/System/Threading/Tasks/AsyncCausalityTracer.cs34
-rw-r--r--src/mscorlib/src/System/Threading/Tasks/ConcurrentExclusiveSchedulerPair.cs30
-rw-r--r--src/mscorlib/src/System/Threading/Tasks/FutureFactory.cs39
-rw-r--r--src/mscorlib/src/System/Threading/Tasks/IAsyncCausalityTracerStatics.cs10
-rw-r--r--src/mscorlib/src/System/Threading/Tasks/ProducerConsumerQueues.cs14
-rw-r--r--src/mscorlib/src/System/Threading/Tasks/TPLETWProvider.cs196
-rw-r--r--src/mscorlib/src/System/Threading/Tasks/Task.cs511
-rw-r--r--src/mscorlib/src/System/Threading/Tasks/TaskCanceledException.cs93
-rw-r--r--src/mscorlib/src/System/Threading/Tasks/TaskCompletionSource.cs8
-rw-r--r--src/mscorlib/src/System/Threading/Tasks/TaskContinuation.cs33
-rw-r--r--src/mscorlib/src/System/Threading/Tasks/TaskExceptionHolder.cs38
-rw-r--r--src/mscorlib/src/System/Threading/Tasks/TaskFactory.cs73
-rw-r--r--src/mscorlib/src/System/Threading/Tasks/TaskScheduler.cs75
-rw-r--r--src/mscorlib/src/System/Threading/Tasks/TaskSchedulerException.cs81
-rw-r--r--src/mscorlib/src/System/Threading/Tasks/TaskToApm.cs6
-rw-r--r--src/mscorlib/src/System/Threading/Tasks/ThreadPoolTaskScheduler.cs24
-rw-r--r--src/mscorlib/src/System/Threading/Tasks/future.cs43
-rw-r--r--src/mscorlib/src/System/Threading/Thread.cs251
-rw-r--r--src/mscorlib/src/System/Threading/ThreadAbortException.cs39
-rw-r--r--src/mscorlib/src/System/Threading/ThreadInterruptedException.cs41
-rw-r--r--src/mscorlib/src/System/Threading/ThreadLocal.cs23
-rw-r--r--src/mscorlib/src/System/Threading/ThreadPool.cs259
-rw-r--r--src/mscorlib/src/System/Threading/ThreadPriority.cs31
-rw-r--r--src/mscorlib/src/System/Threading/ThreadStart.cs23
-rw-r--r--src/mscorlib/src/System/Threading/ThreadStartException.cs37
-rw-r--r--src/mscorlib/src/System/Threading/ThreadState.cs35
-rw-r--r--src/mscorlib/src/System/Threading/ThreadStateException.cs40
-rw-r--r--src/mscorlib/src/System/Threading/Timeout.cs19
-rw-r--r--src/mscorlib/src/System/Threading/Timer.cs159
-rw-r--r--src/mscorlib/src/System/Threading/Volatile.cs53
-rw-r--r--src/mscorlib/src/System/Threading/WaitHandle.cs203
-rw-r--r--src/mscorlib/src/System/Threading/WaitHandleCannotBeOpenedException.cs36
63 files changed, 3138 insertions, 3725 deletions
diff --git a/src/mscorlib/src/System/Threading/AbandonedMutexException.cs b/src/mscorlib/src/System/Threading/AbandonedMutexException.cs
deleted file mode 100644
index 6b4977fbc5..0000000000
--- a/src/mscorlib/src/System/Threading/AbandonedMutexException.cs
+++ /dev/null
@@ -1,85 +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.
-
-//
-//
-// AbandonedMutexException
-// Thrown when a wait completes because one or more mutexes was abandoned.
-// AbandonedMutexs indicate serious error in user code or machine state.
-////////////////////////////////////////////////////////////////////////////////
-
-namespace System.Threading {
-
- using System;
- using System.Runtime.Serialization;
- using System.Threading;
- using System.Runtime.InteropServices;
-
- [Serializable]
- [ComVisibleAttribute(false)]
- public class AbandonedMutexException : SystemException {
-
- private int m_MutexIndex = -1;
- private Mutex m_Mutex = null;
-
- public AbandonedMutexException()
- : base(Environment.GetResourceString("Threading.AbandonedMutexException")) {
- SetErrorCode(__HResults.COR_E_ABANDONEDMUTEX);
- }
-
- public AbandonedMutexException(String message)
- : base(message) {
- SetErrorCode(__HResults.COR_E_ABANDONEDMUTEX);
- }
-
- public AbandonedMutexException(String message, Exception inner )
- : base(message, inner) {
- SetErrorCode(__HResults.COR_E_ABANDONEDMUTEX);
- }
-
- public AbandonedMutexException(int location, WaitHandle handle)
- : base(Environment.GetResourceString("Threading.AbandonedMutexException")) {
- SetErrorCode(__HResults.COR_E_ABANDONEDMUTEX);
- SetupException(location,handle);
- }
-
- public AbandonedMutexException(String message,int location, WaitHandle handle)
- : base(message) {
- SetErrorCode(__HResults.COR_E_ABANDONEDMUTEX);
- SetupException(location,handle);
- }
-
- public AbandonedMutexException(String message, Exception inner,int location, WaitHandle handle )
- : base(message, inner) {
- SetErrorCode(__HResults.COR_E_ABANDONEDMUTEX);
- SetupException(location,handle);
- }
-
- private void SetupException(int location, WaitHandle handle)
- {
- m_MutexIndex = location;
- if(handle != null)
- m_Mutex = handle as Mutex;
- }
-
- protected AbandonedMutexException(SerializationInfo info, StreamingContext context) : base(info, context) {
- }
-
- public Mutex Mutex
- {
- get {
- return m_Mutex;
- }
- }
-
- public int MutexIndex
- {
- get{
- return m_MutexIndex;
- }
- }
-
- }
-}
-
diff --git a/src/mscorlib/src/System/Threading/ApartmentState.cs b/src/mscorlib/src/System/Threading/ApartmentState.cs
deleted file mode 100644
index 1edf0af98a..0000000000
--- a/src/mscorlib/src/System/Threading/ApartmentState.cs
+++ /dev/null
@@ -1,27 +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: Enum to represent the different threading models
-**
-**
-=============================================================================*/
-
-namespace System.Threading {
-
- [Serializable]
- public enum ApartmentState
- {
- /*=========================================================================
- ** Constants for thread apartment states.
- =========================================================================*/
- STA = 0,
- MTA = 1,
- Unknown = 2
- }
-}
diff --git a/src/mscorlib/src/System/Threading/AsyncLocal.cs b/src/mscorlib/src/System/Threading/AsyncLocal.cs
deleted file mode 100644
index 8c4319bd2c..0000000000
--- a/src/mscorlib/src/System/Threading/AsyncLocal.cs
+++ /dev/null
@@ -1,487 +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.Collections.Generic;
-using System.Diagnostics;
-using System.Diagnostics.Contracts;
-using System.Security;
-
-namespace System.Threading
-{
- //
- // AsyncLocal<T> represents "ambient" data that is local to a given asynchronous control flow, such as an
- // async method. For example, say you want to associate a culture with a given async flow:
- //
- // static AsyncLocal<Culture> s_currentCulture = new AsyncLocal<Culture>();
- //
- // static async Task SomeOperationAsync(Culture culture)
- // {
- // s_currentCulture.Value = culture;
- //
- // await FooAsync();
- // }
- //
- // static async Task FooAsync()
- // {
- // PrintStringWithCulture(s_currentCulture.Value);
- // }
- //
- // AsyncLocal<T> also provides optional notifications when the value associated with the current thread
- // changes, either because it was explicitly changed by setting the Value property, or implicitly changed
- // when the thread encountered an "await" or other context transition. For example, we might want our
- // current culture to be communicated to the OS as well:
- //
- // static AsyncLocal<Culture> s_currentCulture = new AsyncLocal<Culture>(
- // args =>
- // {
- // NativeMethods.SetThreadCulture(args.CurrentValue.LCID);
- // });
- //
- public sealed class AsyncLocal<T> : IAsyncLocal
- {
- private readonly Action<AsyncLocalValueChangedArgs<T>> m_valueChangedHandler;
-
- //
- // Constructs an AsyncLocal<T> that does not receive change notifications.
- //
- public AsyncLocal()
- {
- }
-
- //
- // Constructs an AsyncLocal<T> with a delegate that is called whenever the current value changes
- // on any thread.
- //
- public AsyncLocal(Action<AsyncLocalValueChangedArgs<T>> valueChangedHandler)
- {
- m_valueChangedHandler = valueChangedHandler;
- }
-
- public T Value
- {
- get
- {
- object obj = ExecutionContext.GetLocalValue(this);
- return (obj == null) ? default(T) : (T)obj;
- }
- set
- {
- ExecutionContext.SetLocalValue(this, value, m_valueChangedHandler != null);
- }
- }
-
- void IAsyncLocal.OnValueChanged(object previousValueObj, object currentValueObj, bool contextChanged)
- {
- Debug.Assert(m_valueChangedHandler != null);
- T previousValue = previousValueObj == null ? default(T) : (T)previousValueObj;
- T currentValue = currentValueObj == null ? default(T) : (T)currentValueObj;
- m_valueChangedHandler(new AsyncLocalValueChangedArgs<T>(previousValue, currentValue, contextChanged));
- }
- }
-
- //
- // Interface to allow non-generic code in ExecutionContext to call into the generic AsyncLocal<T> type.
- //
- internal interface IAsyncLocal
- {
- void OnValueChanged(object previousValue, object currentValue, bool contextChanged);
- }
-
- public struct AsyncLocalValueChangedArgs<T>
- {
- public T PreviousValue { get; private set; }
- public T CurrentValue { get; private set; }
-
- //
- // If the value changed because we changed to a different ExecutionContext, this is true. If it changed
- // because someone set the Value property, this is false.
- //
- public bool ThreadContextChanged { get; private set; }
-
- internal AsyncLocalValueChangedArgs(T previousValue, T currentValue, bool contextChanged)
- : this()
- {
- PreviousValue = previousValue;
- CurrentValue = currentValue;
- ThreadContextChanged = contextChanged;
- }
- }
-
- //
- // Interface used to store an IAsyncLocal => object mapping in ExecutionContext.
- // Implementations are specialized based on the number of elements in the immutable
- // map in order to minimize memory consumption and look-up times.
- //
- interface IAsyncLocalValueMap
- {
- bool TryGetValue(IAsyncLocal key, out object value);
- IAsyncLocalValueMap Set(IAsyncLocal key, object value);
- }
-
- //
- // Utility functions for getting/creating instances of IAsyncLocalValueMap
- //
- internal static class AsyncLocalValueMap
- {
- public static IAsyncLocalValueMap Empty { get; } = new EmptyAsyncLocalValueMap();
-
- // Instance without any key/value pairs. Used as a singleton/
- private sealed class EmptyAsyncLocalValueMap : IAsyncLocalValueMap
- {
- public IAsyncLocalValueMap Set(IAsyncLocal key, object value)
- {
- // If the value isn't null, then create a new one-element map to store
- // the key/value pair. If it is null, then we're still empty.
- return value != null ?
- new OneElementAsyncLocalValueMap(key, value) :
- (IAsyncLocalValueMap)this;
- }
-
- public bool TryGetValue(IAsyncLocal key, out object value)
- {
- value = null;
- return false;
- }
- }
-
- // Instance with one key/value pair.
- private sealed class OneElementAsyncLocalValueMap : IAsyncLocalValueMap
- {
- private readonly IAsyncLocal _key1;
- private readonly object _value1;
-
- public OneElementAsyncLocalValueMap(IAsyncLocal key, object value)
- {
- _key1 = key; _value1 = value;
- }
-
- public IAsyncLocalValueMap Set(IAsyncLocal key, object value)
- {
- if (value != null)
- {
- // The value is non-null. If the key matches one already contained in this map,
- // then create a new one-element map with the updated value, otherwise create
- // a two-element map with the additional key/value.
- return ReferenceEquals(key, _key1) ?
- new OneElementAsyncLocalValueMap(key, value) :
- (IAsyncLocalValueMap)new TwoElementAsyncLocalValueMap(_key1, _value1, key, value);
- }
- else
- {
- // The value is null. If the key exists in this map, remove it by downgrading to an empty map.
- // Otherwise, there's nothing to add or remove, so just return this map.
- return ReferenceEquals(key, _key1) ?
- Empty :
- (IAsyncLocalValueMap)this;
- }
- }
-
- public bool TryGetValue(IAsyncLocal key, out object value)
- {
- if (ReferenceEquals(key, _key1))
- {
- value = _value1;
- return true;
- }
- else
- {
- value = null;
- return false;
- }
- }
- }
-
- // Instance with two key/value pairs.
- private sealed class TwoElementAsyncLocalValueMap : IAsyncLocalValueMap
- {
- private readonly IAsyncLocal _key1, _key2;
- private readonly object _value1, _value2;
-
- public TwoElementAsyncLocalValueMap(IAsyncLocal key1, object value1, IAsyncLocal key2, object value2)
- {
- _key1 = key1; _value1 = value1;
- _key2 = key2; _value2 = value2;
- }
-
- public IAsyncLocalValueMap Set(IAsyncLocal key, object value)
- {
- if (value != null)
- {
- // The value is non-null. If the key matches one already contained in this map,
- // then create a new two-element map with the updated value, otherwise create
- // a three-element map with the additional key/value.
- return
- ReferenceEquals(key, _key1) ? new TwoElementAsyncLocalValueMap(key, value, _key2, _value2) :
- ReferenceEquals(key, _key2) ? new TwoElementAsyncLocalValueMap(_key1, _value1, key, value) :
- (IAsyncLocalValueMap)new ThreeElementAsyncLocalValueMap(_key1, _value1, _key2, _value2, key, value);
- }
- else
- {
- // The value is null. If the key exists in this map, remove it by downgrading to a one-element map
- // without the key. Otherwise, there's nothing to add or remove, so just return this map.
- return
- ReferenceEquals(key, _key1) ? new OneElementAsyncLocalValueMap(_key2, _value2) :
- ReferenceEquals(key, _key2) ? new OneElementAsyncLocalValueMap(_key1, _value1) :
- (IAsyncLocalValueMap)this;
- }
- }
-
- public bool TryGetValue(IAsyncLocal key, out object value)
- {
- if (ReferenceEquals(key, _key1))
- {
- value = _value1;
- return true;
- }
- else if (ReferenceEquals(key, _key2))
- {
- value = _value2;
- return true;
- }
- else
- {
- value = null;
- return false;
- }
- }
- }
-
- // Instance with three key/value pairs.
- private sealed class ThreeElementAsyncLocalValueMap : IAsyncLocalValueMap
- {
- private readonly IAsyncLocal _key1, _key2, _key3;
- private readonly object _value1, _value2, _value3;
-
- public ThreeElementAsyncLocalValueMap(IAsyncLocal key1, object value1, IAsyncLocal key2, object value2, IAsyncLocal key3, object value3)
- {
- _key1 = key1; _value1 = value1;
- _key2 = key2; _value2 = value2;
- _key3 = key3; _value3 = value3;
- }
-
- public IAsyncLocalValueMap Set(IAsyncLocal key, object value)
- {
- if (value != null)
- {
- // The value is non-null. If the key matches one already contained in this map,
- // then create a new three-element map with the updated value.
- if (ReferenceEquals(key, _key1)) return new ThreeElementAsyncLocalValueMap(key, value, _key2, _value2, _key3, _value3);
- if (ReferenceEquals(key, _key2)) return new ThreeElementAsyncLocalValueMap(_key1, _value1, key, value, _key3, _value3);
- if (ReferenceEquals(key, _key3)) return new ThreeElementAsyncLocalValueMap(_key1, _value1, _key2, _value2, key, value);
-
- // The key doesn't exist in this map, so upgrade to a multi map that contains
- // the additional key/value pair.
- var multi = new MultiElementAsyncLocalValueMap(4);
- multi.UnsafeStore(0, _key1, _value1);
- multi.UnsafeStore(1, _key2, _value2);
- multi.UnsafeStore(2, _key3, _value3);
- multi.UnsafeStore(3, key, value);
- return multi;
- }
- else
- {
- // The value is null. If the key exists in this map, remove it by downgrading to a two-element map
- // without the key. Otherwise, there's nothing to add or remove, so just return this map.
- return
- ReferenceEquals(key, _key1) ? new TwoElementAsyncLocalValueMap(_key2, _value2, _key3, _value3) :
- ReferenceEquals(key, _key2) ? new TwoElementAsyncLocalValueMap(_key1, _value1, _key3, _value3) :
- ReferenceEquals(key, _key3) ? new TwoElementAsyncLocalValueMap(_key1, _value1, _key2, _value2) :
- (IAsyncLocalValueMap)this;
- }
- }
-
- public bool TryGetValue(IAsyncLocal key, out object value)
- {
- if (ReferenceEquals(key, _key1))
- {
- value = _value1;
- return true;
- }
- else if (ReferenceEquals(key, _key2))
- {
- value = _value2;
- return true;
- }
- else if (ReferenceEquals(key, _key3))
- {
- value = _value3;
- return true;
- }
- else
- {
- value = null;
- return false;
- }
- }
- }
-
- // Instance with up to 16 key/value pairs.
- private sealed class MultiElementAsyncLocalValueMap : IAsyncLocalValueMap
- {
- internal const int MaxMultiElements = 16;
- private readonly KeyValuePair<IAsyncLocal, object>[] _keyValues;
-
- internal MultiElementAsyncLocalValueMap(int count)
- {
- Debug.Assert(count <= MaxMultiElements);
- _keyValues = new KeyValuePair<IAsyncLocal, object>[count];
- }
-
- internal void UnsafeStore(int index, IAsyncLocal key, object value)
- {
- Debug.Assert(index < _keyValues.Length);
- _keyValues[index] = new KeyValuePair<IAsyncLocal, object>(key, value);
- }
-
- public IAsyncLocalValueMap Set(IAsyncLocal key, object value)
- {
- // Find the key in this map.
- for (int i = 0; i < _keyValues.Length; i++)
- {
- if (ReferenceEquals(key, _keyValues[i].Key))
- {
- // The key is in the map. If the value isn't null, then create a new map of the same
- // size that has all of the same pairs, with this new key/value pair overwriting the old.
- if (value != null)
- {
- var multi = new MultiElementAsyncLocalValueMap(_keyValues.Length);
- Array.Copy(_keyValues, 0, multi._keyValues, 0, _keyValues.Length);
- multi._keyValues[i] = new KeyValuePair<IAsyncLocal, object>(key, value);
- return multi;
- }
- else if (_keyValues.Length == 4)
- {
- // The value is null, and we only have four elements, one of which we're removing,
- // so downgrade to a three-element map, without the matching element.
- return
- i == 0 ? new ThreeElementAsyncLocalValueMap(_keyValues[1].Key, _keyValues[1].Value, _keyValues[2].Key, _keyValues[2].Value, _keyValues[3].Key, _keyValues[3].Value) :
- i == 1 ? new ThreeElementAsyncLocalValueMap(_keyValues[0].Key, _keyValues[0].Value, _keyValues[2].Key, _keyValues[2].Value, _keyValues[3].Key, _keyValues[3].Value) :
- i == 2 ? new ThreeElementAsyncLocalValueMap(_keyValues[0].Key, _keyValues[0].Value, _keyValues[1].Key, _keyValues[1].Value, _keyValues[3].Key, _keyValues[3].Value) :
- (IAsyncLocalValueMap)new ThreeElementAsyncLocalValueMap(_keyValues[0].Key, _keyValues[0].Value, _keyValues[1].Key, _keyValues[1].Value, _keyValues[2].Key, _keyValues[2].Value);
- }
- else
- {
- // The value is null, and we have enough elements remaining to warrant a multi map.
- // Create a new one and copy all of the elements from this one, except the one to be removed.
- var multi = new MultiElementAsyncLocalValueMap(_keyValues.Length - 1);
- if (i != 0) Array.Copy(_keyValues, 0, multi._keyValues, 0, i);
- if (i != _keyValues.Length - 1) Array.Copy(_keyValues, i + 1, multi._keyValues, i, _keyValues.Length - i - 1);
- return multi;
- }
- }
- }
-
- // The key does not already exist in this map.
-
- // If the value is null, then we can simply return this same map, as there's nothing to add or remove.
- if (value == null)
- {
- return this;
- }
-
- // We need to create a new map that has the additional key/value pair.
- // If with the addition we can still fit in a multi map, create one.
- if (_keyValues.Length < MaxMultiElements)
- {
- var multi = new MultiElementAsyncLocalValueMap(_keyValues.Length + 1);
- Array.Copy(_keyValues, 0, multi._keyValues, 0, _keyValues.Length);
- multi._keyValues[_keyValues.Length] = new KeyValuePair<IAsyncLocal, object>(key, value);
- return multi;
- }
-
- // Otherwise, upgrade to a many map.
- var many = new ManyElementAsyncLocalValueMap(MaxMultiElements + 1);
- foreach (KeyValuePair<IAsyncLocal, object> pair in _keyValues)
- {
- many[pair.Key] = pair.Value;
- }
- many[key] = value;
- return many;
- }
-
- public bool TryGetValue(IAsyncLocal key, out object value)
- {
- foreach (KeyValuePair<IAsyncLocal, object> pair in _keyValues)
- {
- if (ReferenceEquals(key, pair.Key))
- {
- value = pair.Value;
- return true;
- }
- }
- value = null;
- return false;
- }
- }
-
- // Instance with any number of key/value pairs.
- private sealed class ManyElementAsyncLocalValueMap : Dictionary<IAsyncLocal, object>, IAsyncLocalValueMap
- {
- public ManyElementAsyncLocalValueMap(int capacity) : base(capacity) { }
-
- public IAsyncLocalValueMap Set(IAsyncLocal key, object value)
- {
- int count = Count;
- bool containsKey = ContainsKey(key);
-
- // If the value being set exists, create a new many map, copy all of the elements from this one,
- // and then store the new key/value pair into it. This is the most common case.
- if (value != null)
- {
- var map = new ManyElementAsyncLocalValueMap(count + (containsKey ? 0 : 1));
- foreach (KeyValuePair<IAsyncLocal, object> pair in this)
- {
- map[pair.Key] = pair.Value;
- }
- map[key] = value;
- return map;
- }
-
- // Otherwise, the value is null, which means null is being stored into an AsyncLocal.Value.
- // Since there's no observable difference at the API level between storing null and the key
- // not existing at all, we can downgrade to a smaller map rather than storing null.
-
- // If the key is contained in this map, we're going to create a new map that's one pair smaller.
- if (containsKey)
- {
- // If the new count would be within range of a multi map instead of a many map,
- // downgrade to the many map, which uses less memory and is faster to access.
- // Otherwise, just create a new many map that's missing this key.
- if (count == MultiElementAsyncLocalValueMap.MaxMultiElements + 1)
- {
- var multi = new MultiElementAsyncLocalValueMap(MultiElementAsyncLocalValueMap.MaxMultiElements);
- int index = 0;
- foreach (KeyValuePair<IAsyncLocal, object> pair in this)
- {
- if (!ReferenceEquals(key, pair.Key))
- {
- multi.UnsafeStore(index++, pair.Key, pair.Value);
- }
- }
- Debug.Assert(index == MultiElementAsyncLocalValueMap.MaxMultiElements);
- return multi;
- }
- else
- {
- var map = new ManyElementAsyncLocalValueMap(count - 1);
- foreach (KeyValuePair<IAsyncLocal, object> pair in this)
- {
- if (!ReferenceEquals(key, pair.Key))
- {
- map[pair.Key] = pair.Value;
- }
- }
- Debug.Assert(map.Count == count - 1);
- return map;
- }
- }
-
- // We were storing null, but the key wasn't in the map, so there's nothing to change.
- // Just return this instance.
- return this;
- }
- }
- }
-}
diff --git a/src/mscorlib/src/System/Threading/AutoResetEvent.cs b/src/mscorlib/src/System/Threading/AutoResetEvent.cs
deleted file mode 100644
index fc6b2301ca..0000000000
--- a/src/mscorlib/src/System/Threading/AutoResetEvent.cs
+++ /dev/null
@@ -1,24 +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: An example of a WaitHandle class
-**
-**
-=============================================================================*/
-namespace System.Threading {
-
- using System;
- using System.Runtime.InteropServices;
-
- 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 b68ba4c046..8bddfc90dd 100644
--- a/src/mscorlib/src/System/Threading/CancellationToken.cs
+++ b/src/mscorlib/src/System/Threading/CancellationToken.cs
@@ -78,14 +78,14 @@ namespace System.Threading
/// particularly in situations where related objects are being canceled concurrently.
/// </para>
/// </remarks>
- public bool IsCancellationRequested
+ public bool IsCancellationRequested
{
get
{
return m_source != null && m_source.IsCancellationRequested;
}
}
-
+
/// <summary>
/// Gets whether this token is capable of being in the canceled state.
/// </summary>
@@ -153,12 +153,12 @@ namespace System.Threading
public CancellationToken(bool canceled) :
this()
{
- if(canceled)
+ if (canceled)
m_source = CancellationTokenSource.InternalGetStaticSource(canceled);
}
/* Methods */
-
+
private readonly static Action<Object> s_ActionToActionObjShunt = new Action<Object>(ActionToActionObjShunt);
private static void ActionToActionObjShunt(object obj)
@@ -190,7 +190,7 @@ namespace System.Threading
{
if (callback == null)
throw new ArgumentNullException(nameof(callback));
-
+
return Register(
s_ActionToActionObjShunt,
callback,
@@ -225,7 +225,7 @@ namespace System.Threading
{
if (callback == null)
throw new ArgumentNullException(nameof(callback));
-
+
return Register(
s_ActionToActionObjShunt,
callback,
@@ -301,7 +301,7 @@ namespace System.Threading
true // useExecutionContext=true
);
}
-
+
// helper for internal registration needs that don't require an EC capture (e.g. creating linked token sources, or registering unstarted TPL tasks)
// has a handy signature, and skips capturing execution context.
internal CancellationTokenRegistration InternalRegisterWithoutEC(Action<object> callback, Object state)
@@ -366,14 +366,14 @@ namespace System.Threading
{
return other.m_source == CancellationTokenSource.InternalGetStaticSource(false);
}
-
+
if (other.m_source == null)
{
return m_source == CancellationTokenSource.InternalGetStaticSource(false);
}
// general case, we check if the sources are identical
-
+
return m_source == other.m_source;
}
@@ -392,7 +392,7 @@ namespace System.Threading
{
if (other is CancellationToken)
{
- return Equals((CancellationToken) other);
+ return Equals((CancellationToken)other);
}
return false;
@@ -410,9 +410,9 @@ namespace System.Threading
return CancellationTokenSource.InternalGetStaticSource(false).GetHashCode();
}
- return m_source.GetHashCode();
+ return m_source.GetHashCode();
}
-
+
/// <summary>
/// Determines whether two <see cref="T:System.Threading.CancellationToken">CancellationToken</see> instances are equal.
/// </summary>
@@ -455,7 +455,7 @@ namespace System.Threading
/// cref="T:System.Threading.CancellationTokenSource">CancellationTokenSource</see> has been disposed.</exception>
public void ThrowIfCancellationRequested()
{
- if (IsCancellationRequested)
+ if (IsCancellationRequested)
ThrowOperationCanceledException();
}
@@ -469,17 +469,17 @@ namespace System.Threading
// Throws an OCE; separated out to enable better inlining of ThrowIfCancellationRequested
private void ThrowOperationCanceledException()
{
- throw new OperationCanceledException(Environment.GetResourceString("OperationCanceled"), this);
+ throw new OperationCanceledException(SR.OperationCanceled, this);
}
private static void ThrowObjectDisposedException()
{
- throw new ObjectDisposedException(null, Environment.GetResourceString("CancellationToken_SourceDisposed"));
+ throw new ObjectDisposedException(null, SR.CancellationToken_SourceDisposed);
}
// -----------------------------------
// Private helpers
-
+
private void InitializeDefaultSource()
{
// Lazy is slower, and although multiple threads may try and set m_source repeatedly, the race condition is benign.
diff --git a/src/mscorlib/src/System/Threading/CancellationTokenRegistration.cs b/src/mscorlib/src/System/Threading/CancellationTokenRegistration.cs
index 89e98fa3c8..be760fab3f 100644
--- a/src/mscorlib/src/System/Threading/CancellationTokenRegistration.cs
+++ b/src/mscorlib/src/System/Threading/CancellationTokenRegistration.cs
@@ -62,7 +62,7 @@ namespace System.Threading
// Remove the entry from the array.
// This call includes a full memory fence which prevents potential reorderings of the reads below
bool deregisterOccurred = TryDeregister();
-
+
// We guarantee that we will not return if the callback is being executed (assuming we are not currently called by the callback itself)
// We achieve this by the following rules:
// 1. if we are called in the context of an executing callback, no need to wait (determined by tracking callback-executor threadID)
@@ -124,7 +124,7 @@ namespace System.Threading
/// </returns>
public override bool Equals(object obj)
{
- return ((obj is CancellationTokenRegistration) && Equals((CancellationTokenRegistration) obj));
+ return ((obj is CancellationTokenRegistration) && Equals((CancellationTokenRegistration)obj));
}
/// <summary>
@@ -152,7 +152,7 @@ namespace System.Threading
{
if (m_registrationInfo.Source != null)
return m_registrationInfo.Source.GetHashCode() ^ m_registrationInfo.Index.GetHashCode();
-
+
return m_registrationInfo.Index.GetHashCode();
}
}
diff --git a/src/mscorlib/src/System/Threading/CancellationTokenSource.cs b/src/mscorlib/src/System/Threading/CancellationTokenSource.cs
index 1e70d6f30f..2707292ed2 100644
--- a/src/mscorlib/src/System/Threading/CancellationTokenSource.cs
+++ b/src/mscorlib/src/System/Threading/CancellationTokenSource.cs
@@ -45,18 +45,18 @@ namespace System.Threading
// the actual callback lists are only created on demand.
// Storing a registered callback costs around >60bytes, hence some overhead for the lists array is OK
// At most 24 lists seems reasonable, and caps the cost of the listsArray to 96bytes(32-bit,24-way) or 192bytes(64-bit,24-way).
- private static readonly int s_nLists = (PlatformHelper.ProcessorCount > 24) ? 24 : PlatformHelper.ProcessorCount;
+ private static readonly int s_nLists = (PlatformHelper.ProcessorCount > 24) ? 24 : PlatformHelper.ProcessorCount;
private volatile ManualResetEvent m_kernelEvent; //lazily initialized if required.
private volatile SparselyPopulatedArray<CancellationCallbackInfo>[] m_registeredCallbacksLists;
-
+
// legal values for m_state
private const int CANNOT_BE_CANCELED = 0;
private const int NOT_CANCELED = 1;
private const int NOTIFYING = 2;
private const int NOTIFYINGCOMPLETE = 3;
-
+
//m_state uses the pattern "volatile int32 reads, with cmpxch writes" which is safe for updates and cannot suffer torn reads.
private volatile int m_state;
@@ -68,13 +68,13 @@ namespace System.Threading
private volatile int m_threadIDExecutingCallbacks = -1;
private bool m_disposed;
-
+
// we track the running callback to assist ctr.Dispose() to wait for the target callback to complete.
private volatile CancellationCallbackInfo m_executingCallback;
// provided for CancelAfter and timer-related constructors
private volatile Timer m_timer;
-
+
// ----------------------
// ** public properties
@@ -168,11 +168,11 @@ namespace System.Threading
// fast path if already allocated.
if (m_kernelEvent != null)
return m_kernelEvent;
-
+
// lazy-init the mre.
ManualResetEvent mre = new ManualResetEvent(false);
if (Interlocked.CompareExchange(ref m_kernelEvent, mre, null) != null)
- {
+ {
((IDisposable)mre).Dispose();
}
@@ -211,9 +211,9 @@ namespace System.Threading
return 0;
int count = 0;
- foreach(SparselyPopulatedArray<CancellationCallbackInfo> sparseArray in callbackLists)
+ foreach (SparselyPopulatedArray<CancellationCallbackInfo> sparseArray in callbackLists)
{
- if(sparseArray != null)
+ if (sparseArray != null)
{
SparselyPopulatedArrayFragment<CancellationCallbackInfo> currCallbacks = sparseArray.Head;
while (currCallbacks != null)
@@ -379,7 +379,7 @@ namespace System.Threading
public void Cancel(bool throwOnFirstException)
{
ThrowIfDisposed();
- NotifyCancellation(throwOnFirstException);
+ NotifyCancellation(throwOnFirstException);
}
/// <summary>
@@ -476,7 +476,7 @@ namespace System.Threading
}
}
-
+
// It is possible that m_timer has already been disposed, so we must do
// the following in a try/catch block.
try
@@ -490,7 +490,6 @@ namespace System.Threading
// would not be a good way to deal with the observe/dispose
// race condition.
}
-
}
private static readonly TimerCallback s_timerCallback = new TimerCallback(TimerCallbackLogic);
@@ -601,7 +600,7 @@ namespace System.Threading
// separation enables inlining of ThrowIfDisposed
private static void ThrowObjectDisposedException()
{
- throw new ObjectDisposedException(null, Environment.GetResourceString("CancellationTokenSource_Disposed"));
+ throw new ObjectDisposedException(null, SR.CancellationTokenSource_Disposed);
}
/// <summary>
@@ -716,7 +715,7 @@ namespace System.Threading
// Record the threadID being used for running the callbacks.
ThreadIDExecutingCallbacks = Thread.CurrentThread.ManagedThreadId;
-
+
// Set the event if it's been lazily initialized and hasn't yet been disposed of. Dispose may
// be running concurrently, in which case either it'll have set m_kernelEvent back to null and
// we won't see it here, or it'll see that we've transitioned to NOTIFYING and will skip disposing it,
@@ -755,7 +754,7 @@ namespace System.Threading
Interlocked.Exchange(ref m_state, NOTIFYINGCOMPLETE);
return;
}
-
+
try
{
for (int index = 0; index < callbackLists.Length; index++)
@@ -799,13 +798,13 @@ namespace System.Threading
CancellationCallbackCoreWork(args);
}
}
- catch(Exception ex)
+ catch (Exception ex)
{
if (throwOnFirstException)
throw;
-
+
// Otherwise, log it and proceed.
- if(exceptionList == null)
+ if (exceptionList == null)
exceptionList = new List<Exception>();
exceptionList.Add(ex);
}
@@ -821,7 +820,7 @@ namespace System.Threading
{
m_state = NOTIFYINGCOMPLETE;
m_executingCallback = null;
- Thread.MemoryBarrier(); // for safety, prevent reorderings crossing this point and seeing inconsistent state.
+ Interlocked.MemoryBarrier(); // for safety, prevent reorderings crossing this point and seeing inconsistent state.
}
if (exceptionList != null)
@@ -892,7 +891,7 @@ namespace System.Threading
switch (tokens.Length)
{
case 0:
- throw new ArgumentException(Environment.GetResourceString("CancellationToken_CreateLinkedToken_TokensIsEmpty"));
+ throw new ArgumentException(SR.CancellationToken_CreateLinkedToken_TokensIsEmpty);
case 1:
return CreateLinkedTokenSource(tokens[0]);
case 2:
@@ -1004,7 +1003,7 @@ namespace System.Threading
{
internal SparselyPopulatedArrayFragment<CancellationCallbackInfo> m_currArrayFragment;
internal int m_currArrayIndex;
-
+
public CancellationCallbackCoreWorkArguments(SparselyPopulatedArrayFragment<CancellationCallbackInfo> currArrayFragment, int currArrayIndex)
{
m_currArrayFragment = currArrayFragment;
@@ -1040,7 +1039,6 @@ namespace System.Threading
{
TargetSyncContext = targetSyncContext;
}
-
}
internal CancellationCallbackInfo(
@@ -1066,7 +1064,7 @@ namespace System.Threading
// Lazily initialize the callback delegate; benign race condition
var callback = s_executionContextCallback;
if (callback == null) s_executionContextCallback = callback = new ContextCallback(ExecutionContextCallback);
-
+
ExecutionContext.Run(
TargetExecutionContext,
callback,
@@ -1176,7 +1174,7 @@ namespace System.Threading
// If the slot is null, try to CAS our element into it.
int tryIndex = (start + i) % c;
Debug.Assert(tryIndex >= 0 && tryIndex < curr.m_elements.Length, "tryIndex is outside of bounds");
-
+
if (curr.m_elements[tryIndex] == null && Interlocked.CompareExchange(ref curr.m_elements[tryIndex], element, null) == null)
{
// We adjust the free count by --. Note: if this drops to 0, we will skip
@@ -1282,7 +1280,7 @@ namespace System.Threading
internal T SafeAtomicRemove(int index, T expectedElement)
{
T prevailingValue = Interlocked.CompareExchange(ref m_elements[index], null, expectedElement);
- if (prevailingValue != null)
+ if (prevailingValue != null)
++m_freeCount;
return prevailingValue;
}
diff --git a/src/mscorlib/src/System/Threading/ClrThreadPoolBoundHandle.cs b/src/mscorlib/src/System/Threading/ClrThreadPoolBoundHandle.cs
new file mode 100644
index 0000000000..d0cc5afbae
--- /dev/null
+++ b/src/mscorlib/src/System/Threading/ClrThreadPoolBoundHandle.cs
@@ -0,0 +1,319 @@
+// 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.Diagnostics;
+using System.Runtime.InteropServices;
+
+namespace System.Threading
+{
+ //
+ // Implementation of ThreadPoolBoundHandle that sits on top of the CLR's ThreadPool and Overlapped infrastructure
+ //
+
+ /// <summary>
+ /// Represents an I/O handle that is bound to the system thread pool and enables low-level
+ /// components to receive notifications for asynchronous I/O operations.
+ /// </summary>
+ public sealed partial class ThreadPoolBoundHandle : IDisposable
+ {
+ private readonly SafeHandle _handle;
+ private bool _isDisposed;
+
+ private ThreadPoolBoundHandle(SafeHandle handle)
+ {
+ _handle = handle;
+ }
+
+ /// <summary>
+ /// Gets the bound operating system handle.
+ /// </summary>
+ /// <value>
+ /// A <see cref="SafeHandle"/> object that holds the bound operating system handle.
+ /// </value>
+ public SafeHandle Handle
+ {
+ get { return _handle; }
+ }
+
+ /// <summary>
+ /// Returns a <see cref="ThreadPoolBoundHandle"/> for the specific handle,
+ /// which is bound to the system thread pool.
+ /// </summary>
+ /// <param name="handle">
+ /// A <see cref="SafeHandle"/> object that holds the operating system handle. The
+ /// handle must have been opened for overlapped I/O on the unmanaged side.
+ /// </param>
+ /// <returns>
+ /// <see cref="ThreadPoolBoundHandle"/> for <paramref name="handle"/>, which
+ /// is bound to the system thread pool.
+ /// </returns>
+ /// <exception cref="ArgumentNullException">
+ /// <paramref name="handle"/> is <see langword="null"/>.
+ /// </exception>
+ /// <exception cref="ArgumentException">
+ /// <paramref name="handle"/> has been disposed.
+ /// <para>
+ /// -or-
+ /// </para>
+ /// <paramref name="handle"/> does not refer to a valid I/O handle.
+ /// <para>
+ /// -or-
+ /// </para>
+ /// <paramref name="handle"/> refers to a handle that has not been opened
+ /// for overlapped I/O.
+ /// <para>
+ /// -or-
+ /// </para>
+ /// <paramref name="handle"/> refers to a handle that has already been bound.
+ /// </exception>
+ /// <remarks>
+ /// This method should be called once per handle.
+ /// <para>
+ /// -or-
+ /// </para>
+ /// <see cref="ThreadPoolBoundHandle"/> does not take ownership of <paramref name="handle"/>,
+ /// it remains the responsibility of the caller to call <see cref="SafeHandle.Dispose"/>.
+ /// </remarks>
+ public static ThreadPoolBoundHandle BindHandle(SafeHandle handle)
+ {
+ if (handle == null)
+ throw new ArgumentNullException(nameof(handle));
+
+ if (handle.IsClosed || handle.IsInvalid)
+ throw new ArgumentException(SR.Argument_InvalidHandle, nameof(handle));
+
+ try
+ {
+ // ThreadPool.BindHandle will always return true, otherwise, it throws. See the underlying FCall
+ // implementation in ThreadPoolNative::CorBindIoCompletionCallback to see the implementation.
+ bool succeeded = ThreadPool.BindHandle(handle);
+ Debug.Assert(succeeded);
+ }
+ catch (Exception ex)
+ { // BindHandle throws ApplicationException on full CLR and Exception on CoreCLR.
+ // We do not let either of these leak and convert them to ArgumentException to
+ // indicate that the specified handles are invalid.
+
+ if (ex.HResult == System.HResults.E_HANDLE) // Bad handle
+ throw new ArgumentException(SR.Argument_InvalidHandle, nameof(handle));
+
+ if (ex.HResult == System.HResults.E_INVALIDARG) // Handle already bound or sync handle
+ throw new ArgumentException(SR.Argument_AlreadyBoundOrSyncHandle, nameof(handle));
+
+ throw;
+ }
+
+ return new ThreadPoolBoundHandle(handle);
+ }
+
+ /// <summary>
+ /// Returns an unmanaged pointer to a <see cref="NativeOverlapped"/> structure, specifying
+ /// a delegate that is invoked when the asynchronous I/O operation is complete, a user-provided
+ /// object providing context, and managed objects that serve as buffers.
+ /// </summary>
+ /// <param name="callback">
+ /// An <see cref="IOCompletionCallback"/> delegate that represents the callback method
+ /// invoked when the asynchronous I/O operation completes.
+ /// </param>
+ /// <param name="state">
+ /// A user-provided object that distinguishes this <see cref="NativeOverlapped"/> from other
+ /// <see cref="NativeOverlapped"/> instances. Can be <see langword="null"/>.
+ /// </param>
+ /// <param name="pinData">
+ /// An object or array of objects representing the input or output buffer for the operation. Each
+ /// object represents a buffer, for example an array of bytes. Can be <see langword="null"/>.
+ /// </param>
+ /// <returns>
+ /// An unmanaged pointer to a <see cref="NativeOverlapped"/> structure.
+ /// </returns>
+ /// <remarks>
+ /// <para>
+ /// The unmanaged pointer returned by this method can be passed to the operating system in
+ /// overlapped I/O operations. The <see cref="NativeOverlapped"/> structure is fixed in
+ /// physical memory until <see cref="FreeNativeOverlapped(NativeOverlapped*)"/> is called.
+ /// </para>
+ /// <para>
+ /// The buffer or buffers specified in <paramref name="pinData"/> must be the same as those passed
+ /// to the unmanaged operating system function that performs the asynchronous I/O.
+ /// </para>
+ /// <note>
+ /// The buffers specified in <paramref name="pinData"/> are pinned for the duration of
+ /// the I/O operation.
+ /// </note>
+ /// </remarks>
+ /// <exception cref="ArgumentNullException">
+ /// <paramref name="callback"/> is <see langword="null"/>.
+ /// </exception>
+ /// <exception cref="ObjectDisposedException">
+ /// This method was called after the <see cref="ThreadPoolBoundHandle"/> was disposed.
+ /// </exception>
+ [CLSCompliant(false)]
+ public unsafe NativeOverlapped* AllocateNativeOverlapped(IOCompletionCallback callback, object state, object pinData)
+ {
+ if (callback == null)
+ throw new ArgumentNullException(nameof(callback));
+
+ EnsureNotDisposed();
+
+ ThreadPoolBoundHandleOverlapped overlapped = new ThreadPoolBoundHandleOverlapped(callback, state, pinData, preAllocated: null);
+ overlapped._boundHandle = this;
+ return overlapped._nativeOverlapped;
+ }
+
+ /// <summary>
+ /// Returns an unmanaged pointer to a <see cref="NativeOverlapped"/> structure, using the callback,
+ /// state, and buffers associated with the specified <see cref="PreAllocatedOverlapped"/> object.
+ /// </summary>
+ /// <param name="preAllocated">
+ /// A <see cref="PreAllocatedOverlapped"/> object from which to create the NativeOverlapped pointer.
+ /// </param>
+ /// <returns>
+ /// An unmanaged pointer to a <see cref="NativeOverlapped"/> structure.
+ /// </returns>
+ /// <remarks>
+ /// <para>
+ /// The unmanaged pointer returned by this method can be passed to the operating system in
+ /// overlapped I/O operations. The <see cref="NativeOverlapped"/> structure is fixed in
+ /// physical memory until <see cref="FreeNativeOverlapped(NativeOverlapped*)"/> is called.
+ /// </para>
+ /// </remarks>
+ /// <exception cref="ArgumentNullException">
+ /// <paramref name="preAllocated"/> is <see langword="null"/>.
+ /// </exception>
+ /// <exception cref="ArgumentException">
+ /// <paramref name="preAllocated"/> is currently in use for another I/O operation.
+ /// </exception>
+ /// <exception cref="ObjectDisposedException">
+ /// This method was called after the <see cref="ThreadPoolBoundHandle"/> was disposed, or
+ /// this method was called after <paramref name="preAllocated"/> was disposed.
+ /// </exception>
+ /// <seealso cref="PreAllocatedOverlapped"/>
+ [CLSCompliant(false)]
+ public unsafe NativeOverlapped* AllocateNativeOverlapped(PreAllocatedOverlapped preAllocated)
+ {
+ if (preAllocated == null)
+ throw new ArgumentNullException(nameof(preAllocated));
+
+ EnsureNotDisposed();
+
+ preAllocated.AddRef();
+ try
+ {
+ ThreadPoolBoundHandleOverlapped overlapped = preAllocated._overlapped;
+
+ if (overlapped._boundHandle != null)
+ throw new ArgumentException(SR.Argument_PreAllocatedAlreadyAllocated, nameof(preAllocated));
+
+ overlapped._boundHandle = this;
+
+ return overlapped._nativeOverlapped;
+ }
+ catch
+ {
+ preAllocated.Release();
+ throw;
+ }
+ }
+
+ /// <summary>
+ /// Frees the unmanaged memory associated with a <see cref="NativeOverlapped"/> structure
+ /// allocated by the <see cref="AllocateNativeOverlapped"/> method.
+ /// </summary>
+ /// <param name="overlapped">
+ /// An unmanaged pointer to the <see cref="NativeOverlapped"/> structure to be freed.
+ /// </param>
+ /// <remarks>
+ /// <note type="caution">
+ /// You must call the <see cref="FreeNativeOverlapped(NativeOverlapped*)"/> method exactly once
+ /// on every <see cref="NativeOverlapped"/> unmanaged pointer allocated using the
+ /// <see cref="AllocateNativeOverlapped"/> method.
+ /// If you do not call the <see cref="FreeNativeOverlapped(NativeOverlapped*)"/> method, you will
+ /// leak memory. If you call the <see cref="FreeNativeOverlapped(NativeOverlapped*)"/> method more
+ /// than once on the same <see cref="NativeOverlapped"/> unmanaged pointer, memory will be corrupted.
+ /// </note>
+ /// </remarks>
+ /// <exception cref="ArgumentNullException">
+ /// <paramref name="overlapped"/> is <see langword="null"/>.
+ /// </exception>
+ /// <exception cref="ObjectDisposedException">
+ /// This method was called after the <see cref="ThreadPoolBoundHandle"/> was disposed.
+ /// </exception>
+ [CLSCompliant(false)]
+ public unsafe void FreeNativeOverlapped(NativeOverlapped* overlapped)
+ {
+ if (overlapped == null)
+ throw new ArgumentNullException(nameof(overlapped));
+
+ // Note: we explicitly allow FreeNativeOverlapped calls after the ThreadPoolBoundHandle has been Disposed.
+
+ ThreadPoolBoundHandleOverlapped wrapper = GetOverlappedWrapper(overlapped, this);
+
+ if (wrapper._boundHandle != this)
+ throw new ArgumentException(SR.Argument_NativeOverlappedWrongBoundHandle, nameof(overlapped));
+
+ if (wrapper._preAllocated != null)
+ wrapper._preAllocated.Release();
+ else
+ Overlapped.Free(overlapped);
+ }
+
+ /// <summary>
+ /// Returns the user-provided object specified when the <see cref="NativeOverlapped"/> instance was
+ /// allocated using the <see cref="AllocateNativeOverlapped(IOCompletionCallback, object, byte[])"/>.
+ /// </summary>
+ /// <param name="overlapped">
+ /// An unmanaged pointer to the <see cref="NativeOverlapped"/> structure from which to return the
+ /// asscociated user-provided object.
+ /// </param>
+ /// <returns>
+ /// A user-provided object that distinguishes this <see cref="NativeOverlapped"/>
+ /// from other <see cref="NativeOverlapped"/> instances, otherwise, <see langword="null"/> if one was
+ /// not specified when the instance was allocated using <see cref="AllocateNativeOverlapped"/>.
+ /// </returns>
+ /// <exception cref="ArgumentNullException">
+ /// <paramref name="overlapped"/> is <see langword="null"/>.
+ /// </exception>
+ [CLSCompliant(false)]
+ public unsafe static object GetNativeOverlappedState(NativeOverlapped* overlapped)
+ {
+ if (overlapped == null)
+ throw new ArgumentNullException(nameof(overlapped));
+
+ ThreadPoolBoundHandleOverlapped wrapper = GetOverlappedWrapper(overlapped, null);
+ Debug.Assert(wrapper._boundHandle != null);
+ return wrapper._userState;
+ }
+
+ private static unsafe ThreadPoolBoundHandleOverlapped GetOverlappedWrapper(NativeOverlapped* overlapped, ThreadPoolBoundHandle expectedBoundHandle)
+ {
+ ThreadPoolBoundHandleOverlapped wrapper;
+ try
+ {
+ wrapper = (ThreadPoolBoundHandleOverlapped)Overlapped.Unpack(overlapped);
+ }
+ catch (NullReferenceException ex)
+ {
+ throw new ArgumentException(SR.Argument_NativeOverlappedAlreadyFree, nameof(overlapped), ex);
+ }
+
+ return wrapper;
+ }
+
+ public void Dispose()
+ {
+ // .NET Native's version of ThreadPoolBoundHandle that wraps the Win32 ThreadPool holds onto
+ // native resources so it needs to be disposable. To match the contract, we are also disposable.
+ // We also implement a disposable state to mimic behavior between this implementation and
+ // .NET Native's version (code written against us, will also work against .NET Native's version).
+ _isDisposed = true;
+ }
+
+
+ private void EnsureNotDisposed()
+ {
+ if (_isDisposed)
+ throw new ObjectDisposedException(GetType().ToString());
+ }
+ }
+}
diff --git a/src/mscorlib/src/System/Threading/ClrThreadPoolBoundHandleOverlapped.cs b/src/mscorlib/src/System/Threading/ClrThreadPoolBoundHandleOverlapped.cs
new file mode 100644
index 0000000000..1aea2a294b
--- /dev/null
+++ b/src/mscorlib/src/System/Threading/ClrThreadPoolBoundHandleOverlapped.cs
@@ -0,0 +1,52 @@
+// 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.
+
+namespace System.Threading
+{
+ /// <summary>
+ /// Overlapped subclass adding data needed by ThreadPoolBoundHandle.
+ /// </summary>
+ internal sealed class ThreadPoolBoundHandleOverlapped : Overlapped
+ {
+ private static readonly unsafe IOCompletionCallback s_completionCallback = CompletionCallback;
+
+ private readonly IOCompletionCallback _userCallback;
+ internal readonly object _userState;
+ internal PreAllocatedOverlapped _preAllocated;
+ internal unsafe NativeOverlapped* _nativeOverlapped;
+ internal ThreadPoolBoundHandle _boundHandle;
+ internal bool _completed;
+
+ public unsafe ThreadPoolBoundHandleOverlapped(IOCompletionCallback callback, object state, object pinData, PreAllocatedOverlapped preAllocated)
+ {
+ _userCallback = callback;
+ _userState = state;
+ _preAllocated = preAllocated;
+
+ _nativeOverlapped = Pack(s_completionCallback, pinData);
+ _nativeOverlapped->OffsetLow = 0; // CLR reuses NativeOverlapped instances and does not reset these
+ _nativeOverlapped->OffsetHigh = 0;
+ }
+
+ private unsafe static void CompletionCallback(uint errorCode, uint numBytes, NativeOverlapped* nativeOverlapped)
+ {
+ ThreadPoolBoundHandleOverlapped overlapped = (ThreadPoolBoundHandleOverlapped)Overlapped.Unpack(nativeOverlapped);
+
+ //
+ // The Win32 thread pool implementation of ThreadPoolBoundHandle does not permit reuse of NativeOverlapped
+ // pointers without freeing them and allocating new a new one. We need to ensure that code using the CLR
+ // ThreadPool implementation follows those rules.
+ //
+ if (overlapped._completed)
+ throw new InvalidOperationException(SR.InvalidOperation_NativeOverlappedReused);
+
+ overlapped._completed = true;
+
+ if (overlapped._boundHandle == null)
+ throw new InvalidOperationException(SR.Argument_NativeOverlappedAlreadyFree);
+
+ overlapped._userCallback(errorCode, numBytes, nativeOverlapped);
+ }
+ }
+}
diff --git a/src/mscorlib/src/System/Threading/ClrThreadPoolPreAllocatedOverlapped.cs b/src/mscorlib/src/System/Threading/ClrThreadPoolPreAllocatedOverlapped.cs
new file mode 100644
index 0000000000..a42e0c7983
--- /dev/null
+++ b/src/mscorlib/src/System/Threading/ClrThreadPoolPreAllocatedOverlapped.cs
@@ -0,0 +1,105 @@
+// 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.
+
+namespace System.Threading
+{
+ /// <summary>
+ /// Represents pre-allocated state for native overlapped I/O operations.
+ /// </summary>
+ /// <seealso cref="ThreadPoolBoundHandle.AllocateNativeOverlapped(PreAllocatedOverlapped)"/>
+ public sealed class PreAllocatedOverlapped : IDisposable, IDeferredDisposable
+ {
+ internal readonly ThreadPoolBoundHandleOverlapped _overlapped;
+ private DeferredDisposableLifetime<PreAllocatedOverlapped> _lifetime;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="PreAllocatedOverlapped"/> class, specifying
+ /// a delegate that is invoked when each asynchronous I/O operation is complete, a user-provided
+ /// object providing context, and managed objects that serve as buffers.
+ /// </summary>
+ /// <param name="callback">
+ /// An <see cref="IOCompletionCallback"/> delegate that represents the callback method
+ /// invoked when each asynchronous I/O operation completes.
+ /// </param>
+ /// <param name="state">
+ /// A user-provided object that distinguishes <see cref="NativeOverlapped"/> instance produced from this
+ /// object from other <see cref="NativeOverlapped"/> instances. Can be <see langword="null"/>.
+ /// </param>
+ /// <param name="pinData">
+ /// An object or array of objects representing the input or output buffer for the operations. Each
+ /// object represents a buffer, for example an array of bytes. Can be <see langword="null"/>.
+ /// </param>
+ /// <remarks>
+ /// The new <see cref="PreAllocatedOverlapped"/> instance can be passed to
+ /// <see cref="ThreadPoolBoundHandle.AllocateNativeOverlapped(PreAllocatedOverlapped)"/>, to produce
+ /// a <see cref="NativeOverlapped"/> instance that can be passed to the operating system in overlapped
+ /// I/O operations. A single <see cref="PreAllocatedOverlapped"/> instance can only be used for
+ /// a single native I/O operation at a time. However, the state stored in the <see cref="PreAllocatedOverlapped"/>
+ /// instance can be reused for subsequent native operations.
+ /// <note>
+ /// The buffers specified in <paramref name="pinData"/> are pinned until <see cref="Dispose"/> is called.
+ /// </note>
+ /// </remarks>
+ /// <exception cref="ArgumentNullException">
+ /// <paramref name="callback"/> is <see langword="null"/>.
+ /// </exception>
+ /// <exception cref="ObjectDisposedException">
+ /// This method was called after the <see cref="ThreadPoolBoundHandle"/> was disposed.
+ /// </exception>
+ [CLSCompliant(false)]
+ public unsafe PreAllocatedOverlapped(IOCompletionCallback callback, object state, object pinData)
+ {
+ if (callback == null)
+ throw new ArgumentNullException(nameof(callback));
+
+ _overlapped = new ThreadPoolBoundHandleOverlapped(callback, state, pinData, this);
+ }
+
+ internal bool AddRef()
+ {
+ return _lifetime.AddRef(this);
+ }
+
+ internal void Release()
+ {
+ _lifetime.Release(this);
+ }
+
+ /// <summary>
+ /// Frees the resources associated with this <see cref="PreAllocatedOverlapped"/> instance.
+ /// </summary>
+ public unsafe void Dispose()
+ {
+ _lifetime.Dispose(this);
+ GC.SuppressFinalize(this);
+ }
+
+ ~PreAllocatedOverlapped()
+ {
+ //
+ // During shutdown, don't automatically clean up, because this instance may still be
+ // reachable/usable by other code.
+ //
+ if (!Environment.HasShutdownStarted)
+ Dispose();
+ }
+
+ unsafe void IDeferredDisposable.OnFinalRelease(bool disposed)
+ {
+ if (_overlapped != null)
+ {
+ if (disposed)
+ {
+ Overlapped.Free(_overlapped._nativeOverlapped);
+ }
+ else
+ {
+ _overlapped._boundHandle = null;
+ _overlapped._completed = false;
+ *_overlapped._nativeOverlapped = default(NativeOverlapped);
+ }
+ }
+ }
+ }
+}
diff --git a/src/mscorlib/src/System/Threading/CountdownEvent.cs b/src/mscorlib/src/System/Threading/CountdownEvent.cs
deleted file mode 100644
index af055e347e..0000000000
--- a/src/mscorlib/src/System/Threading/CountdownEvent.cs
+++ /dev/null
@@ -1,589 +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 simple coordination data structure that we use for fork/join style parallelism.
-//
-// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-
-using System;
-using System.Runtime.InteropServices;
-using System.Threading;
-using System.Diagnostics;
-using System.Diagnostics.Contracts;
-
-namespace System.Threading
-{
-
- /// <summary>
- /// Represents a synchronization primitive that is signaled when its count reaches zero.
- /// </summary>
- /// <remarks>
- /// All public and protected members of <see cref="CountdownEvent"/> are thread-safe and may be used
- /// concurrently from multiple threads, with the exception of Dispose, which
- /// must only be used when all other operations on the <see cref="CountdownEvent"/> have
- /// completed, and Reset, which should only be used when no other threads are
- /// accessing the event.
- /// </remarks>
- [DebuggerDisplay("Initial Count={InitialCount}, Current Count={CurrentCount}")]
- public class CountdownEvent : IDisposable
- {
- // CountdownEvent is a simple synchronization primitive used for fork/join parallelism. We create a
- // latch with a count of N; threads then signal the latch, which decrements N by 1; other threads can
- // wait on the latch at any point; when the latch count reaches 0, all threads are woken and
- // subsequent waiters return without waiting. The implementation internally lazily creates a true
- // Win32 event as needed. We also use some amount of spinning on MP machines before falling back to a
- // wait.
-
- private int m_initialCount; // The original # of signals the latch was instantiated with.
- private volatile int m_currentCount; // The # of outstanding signals before the latch transitions to a signaled state.
- private ManualResetEventSlim m_event; // An event used to manage blocking and signaling.
- private volatile bool m_disposed; // Whether the latch has been disposed.
-
- /// <summary>
- /// Initializes a new instance of <see cref="T:System.Threading.CountdownEvent"/> class with the
- /// specified count.
- /// </summary>
- /// <param name="initialCount">The number of signals required to set the <see
- /// cref="T:System.Threading.CountdownEvent"/>.</param>
- /// <exception cref="T:System.ArgumentOutOfRangeException"><paramref name="initialCount"/> is less
- /// than 0.</exception>
- public CountdownEvent(int initialCount)
- {
- if (initialCount < 0)
- {
- throw new ArgumentOutOfRangeException(nameof(initialCount));
- }
-
- m_initialCount = initialCount;
- m_currentCount = initialCount;
-
- // Allocate a thin event, which internally defers creation of an actual Win32 event.
- m_event = new ManualResetEventSlim();
-
- // If the latch was created with a count of 0, then it's already in the signaled state.
- if (initialCount == 0)
- {
- m_event.Set();
- }
- }
-
- /// <summary>
- /// Gets the number of remaining signals required to set the event.
- /// </summary>
- /// <value>
- /// The number of remaining signals required to set the event.
- /// </value>
- public int CurrentCount
- {
- get
- {
- int observedCount = m_currentCount;
- return observedCount < 0 ? 0 : observedCount;
- }
- }
-
- /// <summary>
- /// Gets the numbers of signals initially required to set the event.
- /// </summary>
- /// <value>
- /// The number of signals initially required to set the event.
- /// </value>
- public int InitialCount
- {
- get { return m_initialCount; }
- }
-
- /// <summary>
- /// Determines whether the event is set.
- /// </summary>
- /// <value>true if the event is set; otherwise, false.</value>
- public bool IsSet
- {
- get
- {
- // The latch is "completed" if its current count has reached 0. Note that this is NOT
- // the same thing is checking the event's IsCompleted property. There is a tiny window
- // of time, after the final decrement of the current count to 0 and before setting the
- // event, where the two values are out of sync.
- return (m_currentCount <= 0);
- }
- }
-
- /// <summary>
- /// Gets a <see cref="T:System.Threading.WaitHandle"/> that is used to wait for the event to be set.
- /// </summary>
- /// <value>A <see cref="T:System.Threading.WaitHandle"/> that is used to wait for the event to be set.</value>
- /// <exception cref="T:System.ObjectDisposedException">The current instance has already been disposed.</exception>
- /// <remarks>
- /// <see cref="WaitHandle"/> should only be used if it's needed for integration with code bases
- /// that rely on having a WaitHandle. If all that's needed is to wait for the <see cref="CountdownEvent"/>
- /// to be set, the <see cref="Wait()"/> method should be preferred.
- /// </remarks>
- public WaitHandle WaitHandle
- {
- get
- {
- ThrowIfDisposed();
- return m_event.WaitHandle;
- }
- }
-
- /// <summary>
- /// Releases all resources used by the current instance of <see cref="T:System.Threading.CountdownEvent"/>.
- /// </summary>
- /// <remarks>
- /// Unlike most of the members of <see cref="CountdownEvent"/>, <see cref="Dispose()"/> is not
- /// thread-safe and may not be used concurrently with other members of this instance.
- /// </remarks>
- public void Dispose()
- {
- // Gets rid of this latch's associated resources. This can consist of a Win32 event
- // which is (lazily) allocated by the underlying thin event. This method is not safe to
- // call concurrently -- i.e. a caller must coordinate to ensure only one thread is using
- // the latch at the time of the call to Dispose.
-
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- /// <summary>
- /// When overridden in a derived class, releases the unmanaged resources used by the
- /// <see cref="T:System.Threading.CountdownEvent"/>, and optionally releases the managed resources.
- /// </summary>
- /// <param name="disposing">true to release both managed and unmanaged resources; false to release
- /// only unmanaged resources.</param>
- /// <remarks>
- /// Unlike most of the members of <see cref="CountdownEvent"/>, <see cref="Dispose()"/> is not
- /// thread-safe and may not be used concurrently with other members of this instance.
- /// </remarks>
- protected virtual void Dispose(bool disposing)
- {
- if (disposing)
- {
- m_event.Dispose();
- m_disposed = true;
- }
- }
-
- /// <summary>
- /// Registers a signal with the <see cref="T:System.Threading.CountdownEvent"/>, decrementing its
- /// count.
- /// </summary>
- /// <returns>true if the signal caused the count to reach zero and the event was set; otherwise,
- /// false.</returns>
- /// <exception cref="T:System.InvalidOperationException">The current instance is already set.
- /// </exception>
- /// <exception cref="T:System.ObjectDisposedException">The current instance has already been
- /// disposed.</exception>
- public bool Signal()
- {
- ThrowIfDisposed();
- Debug.Assert(m_event != null);
-
- if (m_currentCount <= 0)
- {
- throw new InvalidOperationException(Environment.GetResourceString("CountdownEvent_Decrement_BelowZero"));
- }
-#pragma warning disable 0420
- int newCount = Interlocked.Decrement(ref m_currentCount);
-#pragma warning restore 0420
- if (newCount == 0)
- {
- m_event.Set();
- return true;
- }
- else if (newCount < 0)
- {
- //if the count is decremented below zero, then throw, it's OK to keep the count negative, and we shouldn't set the event here
- //because there was a thread already which decremented it to zero and set the event
- throw new InvalidOperationException(Environment.GetResourceString("CountdownEvent_Decrement_BelowZero"));
- }
-
- return false;
- }
-
- /// <summary>
- /// Registers multiple signals with the <see cref="T:System.Threading.CountdownEvent"/>,
- /// decrementing its count by the specified amount.
- /// </summary>
- /// <param name="signalCount">The number of signals to register.</param>
- /// <returns>true if the signals caused the count to reach zero and the event was set; otherwise,
- /// false.</returns>
- /// <exception cref="T:System.InvalidOperationException">
- /// The current instance is already set. -or- Or <paramref name="signalCount"/> is greater than <see
- /// cref="CurrentCount"/>.
- /// </exception>
- /// <exception cref="T:System.ArgumentOutOfRangeException"><paramref name="signalCount"/> is less
- /// than 1.</exception>
- /// <exception cref="T:System.ObjectDisposedException">The current instance has already been
- /// disposed.</exception>
- public bool Signal(int signalCount)
- {
- if (signalCount <= 0)
- {
- throw new ArgumentOutOfRangeException(nameof(signalCount));
- }
-
- ThrowIfDisposed();
- Debug.Assert(m_event != null);
-
- int observedCount;
- SpinWait spin = new SpinWait();
- while (true)
- {
- observedCount = m_currentCount;
-
- // If the latch is already signaled, we will fail.
- if (observedCount < signalCount)
- {
- throw new InvalidOperationException(Environment.GetResourceString("CountdownEvent_Decrement_BelowZero"));
- }
-
- // This disables the "CS0420: a reference to a volatile field will not be treated as volatile" warning
- // for this statement. This warning is clearly senseless for Interlocked operations.
-#pragma warning disable 0420
- if (Interlocked.CompareExchange(ref m_currentCount, observedCount - signalCount, observedCount) == observedCount)
-#pragma warning restore 0420
- {
- break;
- }
-
- // The CAS failed. Spin briefly and try again.
- spin.SpinOnce();
- }
-
- // If we were the last to signal, set the event.
- if (observedCount == signalCount)
- {
- m_event.Set();
- return true;
- }
-
- Debug.Assert(m_currentCount >= 0, "latch was decremented below zero");
- return false;
- }
-
- /// <summary>
- /// Increments the <see cref="T:System.Threading.CountdownEvent"/>'s current count by one.
- /// </summary>
- /// <exception cref="T:System.InvalidOperationException">The current instance is already
- /// set.</exception>
- /// <exception cref="T:System.InvalidOperationException"><see cref="CurrentCount"/> is equal to <see
- /// cref="T:System.Int32.MaxValue"/>.</exception>
- /// <exception cref="T:System.ObjectDisposedException">
- /// The current instance has already been disposed.
- /// </exception>
- public void AddCount()
- {
- AddCount(1);
- }
-
- /// <summary>
- /// Attempts to increment the <see cref="T:System.Threading.CountdownEvent"/>'s current count by one.
- /// </summary>
- /// <returns>true if the increment succeeded; otherwise, false. If <see cref="CurrentCount"/> is
- /// already at zero. this will return false.</returns>
- /// <exception cref="T:System.InvalidOperationException"><see cref="CurrentCount"/> is equal to <see
- /// cref="T:System.Int32.MaxValue"/>.</exception>
- /// <exception cref="T:System.ObjectDisposedException">The current instance has already been
- /// disposed.</exception>
- public bool TryAddCount()
- {
- return TryAddCount(1);
- }
-
- /// <summary>
- /// Increments the <see cref="T:System.Threading.CountdownEvent"/>'s current count by a specified
- /// value.
- /// </summary>
- /// <param name="signalCount">The value by which to increase <see cref="CurrentCount"/>.</param>
- /// <exception cref="T:System.ArgumentOutOfRangeException"><paramref name="signalCount"/> is less than
- /// 0.</exception>
- /// <exception cref="T:System.InvalidOperationException">The current instance is already
- /// set.</exception>
- /// <exception cref="T:System.InvalidOperationException"><see cref="CurrentCount"/> is equal to <see
- /// cref="T:System.Int32.MaxValue"/>.</exception>
- /// <exception cref="T:System.ObjectDisposedException">The current instance has already been
- /// disposed.</exception>
- public void AddCount(int signalCount)
- {
- if (!TryAddCount(signalCount))
- {
- throw new InvalidOperationException(Environment.GetResourceString("CountdownEvent_Increment_AlreadyZero"));
- }
- }
-
- /// <summary>
- /// Attempts to increment the <see cref="T:System.Threading.CountdownEvent"/>'s current count by a
- /// specified value.
- /// </summary>
- /// <param name="signalCount">The value by which to increase <see cref="CurrentCount"/>.</param>
- /// <returns>true if the increment succeeded; otherwise, false. If <see cref="CurrentCount"/> is
- /// already at zero this will return false.</returns>
- /// <exception cref="T:System.ArgumentOutOfRangeException"><paramref name="signalCount"/> is less
- /// than 0.</exception>
- /// <exception cref="T:System.InvalidOperationException">The current instance is already
- /// set.</exception>
- /// <exception cref="T:System.InvalidOperationException"><see cref="CurrentCount"/> is equal to <see
- /// cref="T:System.Int32.MaxValue"/>.</exception>
- /// <exception cref="T:System.ObjectDisposedException">The current instance has already been
- /// disposed.</exception>
- public bool TryAddCount(int signalCount)
- {
- if (signalCount <= 0)
- {
- throw new ArgumentOutOfRangeException(nameof(signalCount));
- }
-
- ThrowIfDisposed();
-
- // Loop around until we successfully increment the count.
- int observedCount;
- SpinWait spin = new SpinWait();
- while (true)
- {
- observedCount = m_currentCount;
-
- if (observedCount <= 0)
- {
- return false;
- }
- else if (observedCount > (Int32.MaxValue - signalCount))
- {
- throw new InvalidOperationException(Environment.GetResourceString("CountdownEvent_Increment_AlreadyMax"));
- }
-
- // This disables the "CS0420: a reference to a volatile field will not be treated as volatile" warning
- // for this statement. This warning is clearly senseless for Interlocked operations.
-#pragma warning disable 0420
- if (Interlocked.CompareExchange(ref m_currentCount, observedCount + signalCount, observedCount) == observedCount)
-#pragma warning restore 0420
- {
- break;
- }
-
- // The CAS failed. Spin briefly and try again.
- spin.SpinOnce();
- }
-
- return true;
- }
-
- /// <summary>
- /// Resets the <see cref="CurrentCount"/> to the value of <see cref="InitialCount"/>.
- /// </summary>
- /// <remarks>
- /// Unlike most of the members of <see cref="CountdownEvent"/>, Reset is not
- /// thread-safe and may not be used concurrently with other members of this instance.
- /// </remarks>
- /// <exception cref="T:System.ObjectDisposedException">The current instance has already been
- /// disposed..</exception>
- public void Reset()
- {
- Reset(m_initialCount);
- }
-
- /// <summary>
- /// Resets the <see cref="CurrentCount"/> to a specified value.
- /// </summary>
- /// <param name="count">The number of signals required to set the <see
- /// cref="T:System.Threading.CountdownEvent"/>.</param>
- /// <remarks>
- /// Unlike most of the members of <see cref="CountdownEvent"/>, Reset is not
- /// thread-safe and may not be used concurrently with other members of this instance.
- /// </remarks>
- /// <exception cref="T:System.ArgumentOutOfRangeException"><paramref name="count"/> is
- /// less than 0.</exception>
- /// <exception cref="T:System.ObjectDisposedException">The current instance has alread been disposed.</exception>
- public void Reset(int count)
- {
- ThrowIfDisposed();
-
- if (count < 0)
- {
- throw new ArgumentOutOfRangeException(nameof(count));
- }
-
- m_currentCount = count;
- m_initialCount = count;
-
- if (count == 0)
- {
- m_event.Set();
- }
- else
- {
- m_event.Reset();
- }
- }
-
- /// <summary>
- /// Blocks the current thread until the <see cref="T:System.Threading.CountdownEvent"/> is set.
- /// </summary>
- /// <remarks>
- /// The caller of this method blocks indefinitely until the current instance is set. The caller will
- /// return immediately if the event is currently in a set state.
- /// </remarks>
- /// <exception cref="T:System.ObjectDisposedException">The current instance has already been
- /// disposed.</exception>
- public void Wait()
- {
- Wait(Timeout.Infinite, new CancellationToken());
- }
-
-
- /// <summary>
- /// Blocks the current thread until the <see cref="T:System.Threading.CountdownEvent"/> is set, while
- /// observing a <see cref="T:System.Threading.CancellationToken"/>.
- /// </summary>
- /// <param name="cancellationToken">The <see cref="T:System.Threading.CancellationToken"/> to
- /// observe.</param>
- /// <remarks>
- /// The caller of this method blocks indefinitely until the current instance is set. The caller will
- /// return immediately if the event is currently in a set state. If the
- /// <see cref="T:System.Threading.CancellationToken">CancellationToken</see> being observed
- /// is canceled during the wait operation, an <see cref="T:System.OperationCanceledException"/>
- /// will be thrown.
- /// </remarks>
- /// <exception cref="T:System.OperationCanceledException"><paramref name="cancellationToken"/> has been
- /// canceled.</exception>
- /// <exception cref="T:System.ObjectDisposedException">The current instance has already been
- /// disposed.</exception>
- public void Wait(CancellationToken cancellationToken)
- {
- Wait(Timeout.Infinite, cancellationToken);
- }
-
- /// <summary>
- /// Blocks the current thread until the <see cref="T:System.Threading.CountdownEvent"/> is set, using a
- /// <see cref="T:System.TimeSpan"/> to measure the time interval.
- /// </summary>
- /// <param name="timeout">A <see cref="T:System.TimeSpan"/> that represents the number of
- /// milliseconds to wait, or a <see cref="T:System.TimeSpan"/> that represents -1 milliseconds to
- /// wait indefinitely.</param>
- /// <returns>true if the <see cref="System.Threading.CountdownEvent"/> was set; otherwise,
- /// false.</returns>
- /// <exception cref="T:System.ArgumentOutOfRangeException"><paramref name="timeout"/> is a negative
- /// number other than -1 milliseconds, which represents an infinite time-out -or- timeout is greater
- /// than <see cref="System.Int32.MaxValue"/>.</exception>
- /// <exception cref="T:System.ObjectDisposedException">The current instance has already been
- /// disposed.</exception>
- public bool Wait(TimeSpan timeout)
- {
- long totalMilliseconds = (long)timeout.TotalMilliseconds;
- if (totalMilliseconds < -1 || totalMilliseconds > int.MaxValue)
- {
- throw new ArgumentOutOfRangeException(nameof(timeout));
- }
-
- return Wait((int)totalMilliseconds, new CancellationToken());
- }
-
- /// <summary>
- /// Blocks the current thread until the <see cref="T:System.Threading.CountdownEvent"/> is set, using
- /// a <see cref="T:System.TimeSpan"/> to measure the time interval, while observing a
- /// <see cref="T:System.Threading.CancellationToken"/>.
- /// </summary>
- /// <param name="timeout">A <see cref="T:System.TimeSpan"/> that represents the number of
- /// milliseconds to wait, or a <see cref="T:System.TimeSpan"/> that represents -1 milliseconds to
- /// wait indefinitely.</param>
- /// <param name="cancellationToken">The <see cref="T:System.Threading.CancellationToken"/> to
- /// observe.</param>
- /// <returns>true if the <see cref="System.Threading.CountdownEvent"/> was set; otherwise,
- /// false.</returns>
- /// <exception cref="T:System.ArgumentOutOfRangeException"><paramref name="timeout"/> is a negative
- /// number other than -1 milliseconds, which represents an infinite time-out -or- timeout is greater
- /// than <see cref="System.Int32.MaxValue"/>.</exception>
- /// <exception cref="T:System.ObjectDisposedException">The current instance has already been
- /// disposed.</exception>
- /// <exception cref="T:System.OperationCanceledException"><paramref name="cancellationToken"/> has
- /// been canceled.</exception>
- public bool Wait(TimeSpan timeout, CancellationToken cancellationToken)
- {
- long totalMilliseconds = (long)timeout.TotalMilliseconds;
- if (totalMilliseconds < -1 || totalMilliseconds > int.MaxValue)
- {
- throw new ArgumentOutOfRangeException(nameof(timeout));
- }
-
- return Wait((int)totalMilliseconds, cancellationToken);
- }
-
- /// <summary>
- /// Blocks the current thread until the <see cref="T:System.Threading.CountdownEvent"/> is set, using a
- /// 32-bit signed integer to measure the time interval.
- /// </summary>
- /// <param name="millisecondsTimeout">The number of milliseconds to wait, or <see
- /// cref="Timeout.Infinite"/>(-1) to wait indefinitely.</param>
- /// <returns>true if the <see cref="System.Threading.CountdownEvent"/> was set; otherwise,
- /// false.</returns>
- /// <exception cref="ArgumentOutOfRangeException"><paramref name="millisecondsTimeout"/> is a
- /// negative number other than -1, which represents an infinite time-out.</exception>
- /// <exception cref="T:System.ObjectDisposedException">The current instance has already been
- /// disposed.</exception>
- public bool Wait(int millisecondsTimeout)
- {
- return Wait(millisecondsTimeout, new CancellationToken());
- }
-
- /// <summary>
- /// Blocks the current thread until the <see cref="T:System.Threading.CountdownEvent"/> is set, using a
- /// 32-bit signed integer to measure the time interval, while observing a
- /// <see cref="T:System.Threading.CancellationToken"/>.
- /// </summary>
- /// <param name="millisecondsTimeout">The number of milliseconds to wait, or <see
- /// cref="Timeout.Infinite"/>(-1) to wait indefinitely.</param>
- /// <param name="cancellationToken">The <see cref="T:System.Threading.CancellationToken"/> to
- /// observe.</param>
- /// <returns>true if the <see cref="System.Threading.CountdownEvent"/> was set; otherwise,
- /// false.</returns>
- /// <exception cref="ArgumentOutOfRangeException"><paramref name="millisecondsTimeout"/> is a
- /// negative number other than -1, which represents an infinite time-out.</exception>
- /// <exception cref="T:System.ObjectDisposedException">The current instance has already been
- /// disposed.</exception>
- /// <exception cref="T:System.OperationCanceledException"><paramref name="cancellationToken"/> has
- /// been canceled.</exception>
- public bool Wait(int millisecondsTimeout, CancellationToken cancellationToken)
- {
- if (millisecondsTimeout < -1)
- {
- throw new ArgumentOutOfRangeException(nameof(millisecondsTimeout));
- }
-
- ThrowIfDisposed();
- cancellationToken.ThrowIfCancellationRequested();
-
- bool returnValue = IsSet;
-
- // If not completed yet, wait on the event.
- if (!returnValue)
- {
- // ** the actual wait
- returnValue = m_event.Wait(millisecondsTimeout, cancellationToken);
- //the Wait will throw OCE itself if the token is canceled.
- }
-
- return returnValue;
- }
-
- // --------------------------------------
- // Private methods
-
-
- /// <summary>
- /// Throws an exception if the latch has been disposed.
- /// </summary>
- private void ThrowIfDisposed()
- {
- if (m_disposed)
- {
- throw new ObjectDisposedException("CountdownEvent");
- }
- }
- }
-}
diff --git a/src/mscorlib/src/System/Threading/EventResetMode.cs b/src/mscorlib/src/System/Threading/EventResetMode.cs
deleted file mode 100644
index edafab9bb5..0000000000
--- a/src/mscorlib/src/System/Threading/EventResetMode.cs
+++ /dev/null
@@ -1,26 +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.
-
-//
-/*=============================================================================
-**
-** Enum: EventResetMode
-**
-**
-** Purpose: Enum to determine the Event type to create
-**
-**
-=============================================================================*/
-
-
-namespace System.Threading
-{
- using System.Runtime.InteropServices;
- [ComVisibleAttribute(false)]
- public enum EventResetMode
- {
- AutoReset = 0,
- ManualReset = 1
- }
-}
diff --git a/src/mscorlib/src/System/Threading/EventWaitHandle.cs b/src/mscorlib/src/System/Threading/EventWaitHandle.cs
index 0268948a5c..611d9de7e7 100644
--- a/src/mscorlib/src/System/Threading/EventWaitHandle.cs
+++ b/src/mscorlib/src/System/Threading/EventWaitHandle.cs
@@ -39,25 +39,25 @@ namespace System.Threading
[ComVisibleAttribute(true)]
public class EventWaitHandle : WaitHandle
{
- public EventWaitHandle(bool initialState, EventResetMode mode) : this(initialState,mode,null) { }
+ public EventWaitHandle(bool initialState, EventResetMode mode) : this(initialState, mode, null) { }
public EventWaitHandle(bool initialState, EventResetMode mode, string name)
{
- if(name != null)
+ if (name != null)
{
#if PLATFORM_UNIX
- throw new PlatformNotSupportedException(Environment.GetResourceString("PlatformNotSupported_NamedSynchronizationPrimitives"));
+ throw new PlatformNotSupportedException(SR.PlatformNotSupported_NamedSynchronizationPrimitives);
#else
if (System.IO.Path.MaxPath < name.Length)
{
- throw new ArgumentException(Environment.GetResourceString("Argument_WaitHandleNameTooLong", Path.MaxPath), nameof(name));
+ throw new ArgumentException(SR.Format(SR.Argument_WaitHandleNameTooLong, Path.MaxPath), nameof(name));
}
#endif
}
Contract.EndContractBlock();
-
+
SafeWaitHandle _handle = null;
- switch(mode)
+ switch (mode)
{
case EventResetMode.ManualReset:
_handle = Win32Native.CreateEvent(null, true, initialState, name);
@@ -67,16 +67,16 @@ namespace System.Threading
break;
default:
- throw new ArgumentException(Environment.GetResourceString("Argument_InvalidFlag",name));
+ throw new ArgumentException(SR.Format(SR.Argument_InvalidFlag, name));
};
-
+
if (_handle.IsInvalid)
{
int errorCode = Marshal.GetLastWin32Error();
-
+
_handle.SetHandleAsInvalid();
- if(null != name && 0 != name.Length && Win32Native.ERROR_INVALID_HANDLE == errorCode)
- throw new WaitHandleCannotBeOpenedException(Environment.GetResourceString("Threading.WaitHandleCannotBeOpenedException_InvalidHandle",name));
+ if (null != name && 0 != name.Length && Win32Native.ERROR_INVALID_HANDLE == errorCode)
+ throw new WaitHandleCannotBeOpenedException(SR.Format(SR.Threading_WaitHandleCannotBeOpenedException_InvalidHandle, name));
__Error.WinIOError(errorCode, name);
}
@@ -90,14 +90,14 @@ namespace System.Threading
internal unsafe EventWaitHandle(bool initialState, EventResetMode mode, string name, out bool createdNew, EventWaitHandleSecurity eventSecurity)
{
- if(name != null)
+ if (name != null)
{
#if PLATFORM_UNIX
- throw new PlatformNotSupportedException(Environment.GetResourceString("PlatformNotSupported_NamedSynchronizationPrimitives"));
+ throw new PlatformNotSupportedException(SR.PlatformNotSupported_NamedSynchronizationPrimitives);
#else
if (System.IO.Path.MaxPath < name.Length)
{
- throw new ArgumentException(Environment.GetResourceString("Argument_WaitHandleNameTooLong", Path.MaxPath), nameof(name));
+ throw new ArgumentException(SR.Format(SR.Argument_WaitHandleNameTooLong, Path.MaxPath), nameof(name));
}
#endif
}
@@ -106,7 +106,7 @@ namespace System.Threading
SafeWaitHandle _handle = null;
Boolean isManualReset;
- switch(mode)
+ switch (mode)
{
case EventResetMode.ManualReset:
isManualReset = true;
@@ -116,7 +116,7 @@ namespace System.Threading
break;
default:
- throw new ArgumentException(Environment.GetResourceString("Argument_InvalidFlag",name));
+ throw new ArgumentException(SR.Format(SR.Argument_InvalidFlag, name));
};
_handle = Win32Native.CreateEvent(secAttrs, isManualReset, initialState, name);
@@ -124,10 +124,9 @@ namespace System.Threading
if (_handle.IsInvalid)
{
-
_handle.SetHandleAsInvalid();
- if(null != name && 0 != name.Length && Win32Native.ERROR_INVALID_HANDLE == errorCode)
- throw new WaitHandleCannotBeOpenedException(Environment.GetResourceString("Threading.WaitHandleCannotBeOpenedException_InvalidHandle",name));
+ if (null != name && 0 != name.Length && Win32Native.ERROR_INVALID_HANDLE == errorCode)
+ throw new WaitHandleCannotBeOpenedException(SR.Format(SR.Threading_WaitHandleCannotBeOpenedException_InvalidHandle, name));
__Error.WinIOError(errorCode, name);
}
@@ -154,7 +153,7 @@ namespace System.Threading
throw new WaitHandleCannotBeOpenedException();
case OpenExistingResult.NameInvalid:
- throw new WaitHandleCannotBeOpenedException(Environment.GetResourceString("Threading.WaitHandleCannotBeOpenedException_InvalidHandle", name));
+ throw new WaitHandleCannotBeOpenedException(SR.Format(SR.Threading_WaitHandleCannotBeOpenedException_InvalidHandle, name));
case OpenExistingResult.PathNotFound:
__Error.WinIOError(Win32Native.ERROR_PATH_NOT_FOUND, "");
@@ -173,23 +172,23 @@ namespace System.Threading
private static OpenExistingResult OpenExistingWorker(string name, EventWaitHandleRights rights, out EventWaitHandle result)
{
#if PLATFORM_UNIX
- throw new PlatformNotSupportedException(Environment.GetResourceString("PlatformNotSupported_NamedSynchronizationPrimitives"));
+ throw new PlatformNotSupportedException(SR.PlatformNotSupported_NamedSynchronizationPrimitives);
#else
if (name == null)
{
- throw new ArgumentNullException(nameof(name), Environment.GetResourceString("ArgumentNull_WithParamName"));
+ throw new ArgumentNullException(nameof(name), SR.ArgumentNull_WithParamName);
}
- if(name.Length == 0)
+ if (name.Length == 0)
{
- throw new ArgumentException(Environment.GetResourceString("Argument_EmptyName"), nameof(name));
+ throw new ArgumentException(SR.Argument_EmptyName, nameof(name));
}
- if(null != name && System.IO.Path.MaxPath < name.Length)
+ if (null != name && System.IO.Path.MaxPath < name.Length)
{
- throw new ArgumentException(Environment.GetResourceString("Argument_WaitHandleNameTooLong", Path.MaxPath), nameof(name));
+ throw new ArgumentException(SR.Format(SR.Argument_WaitHandleNameTooLong, Path.MaxPath), nameof(name));
}
-
+
Contract.EndContractBlock();
result = null;
@@ -200,14 +199,14 @@ namespace System.Threading
{
int errorCode = Marshal.GetLastWin32Error();
- if(Win32Native.ERROR_FILE_NOT_FOUND == errorCode || Win32Native.ERROR_INVALID_NAME == errorCode)
+ if (Win32Native.ERROR_FILE_NOT_FOUND == errorCode || Win32Native.ERROR_INVALID_NAME == errorCode)
return OpenExistingResult.NameNotFound;
if (Win32Native.ERROR_PATH_NOT_FOUND == errorCode)
return OpenExistingResult.PathNotFound;
- if(null != name && 0 != name.Length && Win32Native.ERROR_INVALID_HANDLE == errorCode)
+ if (null != name && 0 != name.Length && Win32Native.ERROR_INVALID_HANDLE == errorCode)
return OpenExistingResult.NameInvalid;
//this is for passed through Win32Native Errors
- __Error.WinIOError(errorCode,"");
+ __Error.WinIOError(errorCode, "");
}
result = new EventWaitHandle(myHandle);
return OpenExistingResult.Success;
diff --git a/src/mscorlib/src/System/Threading/ExecutionContext.cs b/src/mscorlib/src/System/Threading/ExecutionContext.cs
deleted file mode 100644
index 47a55a3bb9..0000000000
--- a/src/mscorlib/src/System/Threading/ExecutionContext.cs
+++ /dev/null
@@ -1,380 +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: Capture execution context for a thread
-**
-**
-===========================================================*/
-namespace System.Threading
-{
- using System;
- using System.Security;
- using System.Runtime.Remoting;
- using System.Collections;
- using System.Collections.Generic;
- using System.Reflection;
- using System.Runtime.ExceptionServices;
- using System.Runtime.Serialization;
- using System.Runtime.InteropServices;
- using System.Runtime.CompilerServices;
- using System.Runtime.ConstrainedExecution;
- using System.Diagnostics;
- using System.Diagnostics.Contracts;
- using System.Diagnostics.CodeAnalysis;
-
- public delegate void ContextCallback(Object state);
-
- internal struct ExecutionContextSwitcher
- {
- internal ExecutionContext m_ec;
- internal SynchronizationContext m_sc;
-
- internal void Undo(Thread currentThread)
- {
- Debug.Assert(currentThread == Thread.CurrentThread);
-
- // The common case is that these have not changed, so avoid the cost of a write if not needed.
- if (currentThread.SynchronizationContext != m_sc)
- {
- currentThread.SynchronizationContext = m_sc;
- }
-
- if (currentThread.ExecutionContext != m_ec)
- {
- ExecutionContext.Restore(currentThread, m_ec);
- }
- }
- }
-
- [Serializable]
- public sealed class ExecutionContext : IDisposable, ISerializable
- {
- internal static readonly ExecutionContext Default = new ExecutionContext();
-
- private readonly IAsyncLocalValueMap m_localValues;
- private readonly IAsyncLocal[] m_localChangeNotifications;
- private readonly bool m_isFlowSuppressed;
-
- private ExecutionContext()
- {
- m_localValues = AsyncLocalValueMap.Empty;
- m_localChangeNotifications = Array.Empty<IAsyncLocal>();
- }
-
- private ExecutionContext(
- IAsyncLocalValueMap localValues,
- IAsyncLocal[] localChangeNotifications,
- bool isFlowSuppressed)
- {
- m_localValues = localValues;
- m_localChangeNotifications = localChangeNotifications;
- m_isFlowSuppressed = isFlowSuppressed;
- }
-
- public void GetObjectData(SerializationInfo info, StreamingContext context)
- {
- if (info == null)
- {
- throw new ArgumentNullException(nameof(info));
- }
- Contract.EndContractBlock();
- }
-
- private ExecutionContext(SerializationInfo info, StreamingContext context)
- {
- }
-
- public static ExecutionContext Capture()
- {
- ExecutionContext executionContext = Thread.CurrentThread.ExecutionContext;
- return
- executionContext == null ? Default :
- executionContext.m_isFlowSuppressed ? null :
- executionContext;
- }
-
- private ExecutionContext ShallowClone(bool isFlowSuppressed)
- {
- Debug.Assert(isFlowSuppressed != m_isFlowSuppressed);
-
- if (!isFlowSuppressed &&
- m_localValues == Default.m_localValues &&
- m_localChangeNotifications == Default.m_localChangeNotifications)
- {
- return null; // implies the default context
- }
- return new ExecutionContext(m_localValues, m_localChangeNotifications, isFlowSuppressed);
- }
-
- public static AsyncFlowControl SuppressFlow()
- {
- Thread currentThread = Thread.CurrentThread;
- ExecutionContext executionContext = currentThread.ExecutionContext ?? Default;
- if (executionContext.m_isFlowSuppressed)
- {
- throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_CannotSupressFlowMultipleTimes"));
- }
- Contract.EndContractBlock();
-
- executionContext = executionContext.ShallowClone(isFlowSuppressed: true);
- var asyncFlowControl = new AsyncFlowControl();
- currentThread.ExecutionContext = executionContext;
- asyncFlowControl.Initialize(currentThread);
- return asyncFlowControl;
- }
-
- public static void RestoreFlow()
- {
- Thread currentThread = Thread.CurrentThread;
- ExecutionContext executionContext = currentThread.ExecutionContext;
- if (executionContext == null || !executionContext.m_isFlowSuppressed)
- {
- throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_CannotRestoreUnsupressedFlow"));
- }
- Contract.EndContractBlock();
-
- currentThread.ExecutionContext = executionContext.ShallowClone(isFlowSuppressed: false);
- }
-
- public static bool IsFlowSuppressed()
- {
- ExecutionContext executionContext = Thread.CurrentThread.ExecutionContext;
- return executionContext != null && executionContext.m_isFlowSuppressed;
- }
-
- [HandleProcessCorruptedStateExceptions]
- public static void Run(ExecutionContext executionContext, ContextCallback callback, Object state)
- {
- if (executionContext == null)
- throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_NullContext"));
-
- Thread currentThread = Thread.CurrentThread;
- ExecutionContextSwitcher ecsw = default(ExecutionContextSwitcher);
- try
- {
- EstablishCopyOnWriteScope(currentThread, ref ecsw);
- ExecutionContext.Restore(currentThread, executionContext);
- callback(state);
- }
- catch
- {
- // Note: we have a "catch" rather than a "finally" because we want
- // to stop the first pass of EH here. That way we can restore the previous
- // context before any of our callers' EH filters run. That means we need to
- // end the scope separately in the non-exceptional case below.
- ecsw.Undo(currentThread);
- throw;
- }
- ecsw.Undo(currentThread);
- }
-
- internal static void Restore(Thread currentThread, ExecutionContext executionContext)
- {
- Debug.Assert(currentThread == Thread.CurrentThread);
-
- ExecutionContext previous = currentThread.ExecutionContext ?? Default;
- currentThread.ExecutionContext = executionContext;
-
- // New EC could be null if that's what ECS.Undo saved off.
- // For the purposes of dealing with context change, treat this as the default EC
- executionContext = executionContext ?? Default;
-
- if (previous != executionContext)
- {
- OnContextChanged(previous, executionContext);
- }
- }
-
- static internal void EstablishCopyOnWriteScope(Thread currentThread, ref ExecutionContextSwitcher ecsw)
- {
- Debug.Assert(currentThread == Thread.CurrentThread);
-
- ecsw.m_ec = currentThread.ExecutionContext;
- ecsw.m_sc = currentThread.SynchronizationContext;
- }
-
- [HandleProcessCorruptedStateExceptions]
- private static void OnContextChanged(ExecutionContext previous, ExecutionContext current)
- {
- Debug.Assert(previous != null);
- Debug.Assert(current != null);
- Debug.Assert(previous != current);
-
- foreach (IAsyncLocal local in previous.m_localChangeNotifications)
- {
- object previousValue;
- object currentValue;
- previous.m_localValues.TryGetValue(local, out previousValue);
- current.m_localValues.TryGetValue(local, out currentValue);
-
- if (previousValue != currentValue)
- local.OnValueChanged(previousValue, currentValue, true);
- }
-
- if (current.m_localChangeNotifications != previous.m_localChangeNotifications)
- {
- try
- {
- foreach (IAsyncLocal local in current.m_localChangeNotifications)
- {
- // If the local has a value in the previous context, we already fired the event for that local
- // in the code above.
- object previousValue;
- if (!previous.m_localValues.TryGetValue(local, out previousValue))
- {
- object currentValue;
- current.m_localValues.TryGetValue(local, out currentValue);
-
- if (previousValue != currentValue)
- local.OnValueChanged(previousValue, currentValue, true);
- }
- }
- }
- catch (Exception ex)
- {
- Environment.FailFast(
- Environment.GetResourceString("ExecutionContext_ExceptionInAsyncLocalNotification"),
- ex);
- }
- }
- }
-
- internal static object GetLocalValue(IAsyncLocal local)
- {
- ExecutionContext current = Thread.CurrentThread.ExecutionContext;
- if (current == null)
- return null;
-
- object value;
- current.m_localValues.TryGetValue(local, out value);
- return value;
- }
-
- internal static void SetLocalValue(IAsyncLocal local, object newValue, bool needChangeNotifications)
- {
- ExecutionContext current = Thread.CurrentThread.ExecutionContext ?? ExecutionContext.Default;
-
- object previousValue;
- bool hadPreviousValue = current.m_localValues.TryGetValue(local, out previousValue);
-
- if (previousValue == newValue)
- return;
-
- IAsyncLocalValueMap newValues = current.m_localValues.Set(local, newValue);
-
- //
- // Either copy the change notification array, or create a new one, depending on whether we need to add a new item.
- //
- IAsyncLocal[] newChangeNotifications = current.m_localChangeNotifications;
- if (needChangeNotifications)
- {
- if (hadPreviousValue)
- {
- Debug.Assert(Array.IndexOf(newChangeNotifications, local) >= 0);
- }
- else
- {
- int newNotificationIndex = newChangeNotifications.Length;
- Array.Resize(ref newChangeNotifications, newNotificationIndex + 1);
- newChangeNotifications[newNotificationIndex] = local;
- }
- }
-
- Thread.CurrentThread.ExecutionContext =
- new ExecutionContext(newValues, newChangeNotifications, current.m_isFlowSuppressed);
-
- if (needChangeNotifications)
- {
- local.OnValueChanged(previousValue, newValue, false);
- }
- }
-
- public ExecutionContext CreateCopy()
- {
- return this; // since CoreCLR's ExecutionContext is immutable, we don't need to create copies.
- }
-
- public void Dispose()
- {
- // For CLR compat only
- }
- }
-
- public struct AsyncFlowControl : IDisposable
- {
- private Thread _thread;
-
- internal void Initialize(Thread currentThread)
- {
- Debug.Assert(currentThread == Thread.CurrentThread);
- _thread = currentThread;
- }
-
- public void Undo()
- {
- if (_thread == null)
- {
- throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_CannotUseAFCMultiple"));
- }
- if (Thread.CurrentThread != _thread)
- {
- throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_CannotUseAFCOtherThread"));
- }
-
- // An async flow control cannot be undone when a different execution context is applied. The desktop framework
- // mutates the execution context when its state changes, and only changes the instance when an execution context
- // is applied (for instance, through ExecutionContext.Run). The framework prevents a suppressed-flow execution
- // context from being applied by returning null from ExecutionContext.Capture, so the only type of execution
- // context that can be applied is one whose flow is not suppressed. After suppressing flow and changing an async
- // local's value, the desktop framework verifies that a different execution context has not been applied by
- // checking the execution context instance against the one saved from when flow was suppressed. In .NET Core,
- // since the execution context instance will change after changing the async local's value, it verifies that a
- // different execution context has not been applied, by instead ensuring that the current execution context's
- // flow is suppressed.
- if (!ExecutionContext.IsFlowSuppressed())
- {
- throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_AsyncFlowCtrlCtxMismatch"));
- }
- Contract.EndContractBlock();
-
- _thread = null;
- ExecutionContext.RestoreFlow();
- }
-
- public void Dispose()
- {
- Undo();
- }
-
- public override bool Equals(object obj)
- {
- return obj is AsyncFlowControl && Equals((AsyncFlowControl)obj);
- }
-
- public bool Equals(AsyncFlowControl obj)
- {
- return _thread == obj._thread;
- }
-
- public override int GetHashCode()
- {
- return _thread?.GetHashCode() ?? 0;
- }
-
- public static bool operator ==(AsyncFlowControl a, AsyncFlowControl b)
- {
- return a.Equals(b);
- }
-
- public static bool operator !=(AsyncFlowControl a, AsyncFlowControl b)
- {
- return !(a == b);
- }
- }
-}
-
-
diff --git a/src/mscorlib/src/System/Threading/Interlocked.cs b/src/mscorlib/src/System/Threading/Interlocked.cs
index 131d51a65b..7e2c2aeeab 100644
--- a/src/mscorlib/src/System/Threading/Interlocked.cs
+++ b/src/mscorlib/src/System/Threading/Interlocked.cs
@@ -3,21 +3,24 @@
// See the LICENSE file in the project root for more information.
//
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.ConstrainedExecution;
+using System.Runtime.Versioning;
+using System.Runtime;
+using System.Runtime.InteropServices;
+using System.Security;
+
namespace System.Threading
{
- using System;
- using System.Runtime.CompilerServices;
- using System.Runtime.ConstrainedExecution;
- using System.Runtime.Versioning;
- using System.Runtime;
-
// After much discussion, we decided the Interlocked class doesn't need
// any HPA's for synchronization or external threading. They hurt C#'s
// codegen for the yield keyword, and arguably they didn't protect much.
// Instead, they penalized people (and compilers) for writing threadsafe
// code.
public static class Interlocked
- {
+ {
/******************************
* Increment
* Implemented: int
@@ -102,16 +105,16 @@ namespace System.Threading
*****************************/
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- public static extern int CompareExchange(ref int location1, int value, int comparand);
+ public static extern int CompareExchange(ref int location1, int value, int comparand);
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- public static extern long CompareExchange(ref long location1, long value, long comparand);
+ public static extern long CompareExchange(ref long location1, long value, long comparand);
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- public static extern float CompareExchange(ref float location1, float value, float comparand);
+ public static extern float CompareExchange(ref float location1, float value, float comparand);
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- public static extern double CompareExchange(ref double location1, double value, double comparand);
+ public static extern double CompareExchange(ref double location1, double value, double comparand);
[MethodImplAttribute(MethodImplOptions.InternalCall)]
public static extern Object CompareExchange(ref Object location1, Object value, Object comparand);
@@ -142,7 +145,7 @@ namespace System.Threading
* See getILIntrinsicImplementationForInterlocked() in VM\JitInterface.cpp
* for details.
*****************************************************************/
-
+
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'
@@ -169,28 +172,34 @@ namespace System.Threading
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern long ExchangeAdd(ref long location1, long value);
- public static int Add(ref int location1, int value)
+ public static int Add(ref int location1, int value)
{
return ExchangeAdd(ref location1, value) + value;
}
- public static long Add(ref long location1, long value)
+ public static long Add(ref long location1, long value)
{
return ExchangeAdd(ref location1, value) + value;
}
-
+
/******************************
* Read
*****************************/
public static long Read(ref long location)
{
- return Interlocked.CompareExchange(ref location,0,0);
+ return Interlocked.CompareExchange(ref location, 0, 0);
}
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ public static extern void MemoryBarrier();
+
+ [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
+ [SuppressUnmanagedCodeSecurity]
+ private static extern void _MemoryBarrierProcessWide();
- public static void MemoryBarrier()
+ public static void MemoryBarrierProcessWide()
{
- Thread.MemoryBarrier();
+ _MemoryBarrierProcessWide();
}
}
}
diff --git a/src/mscorlib/src/System/Threading/LazyInitializer.cs b/src/mscorlib/src/System/Threading/LazyInitializer.cs
index af32673d03..d585ba6c35 100644
--- a/src/mscorlib/src/System/Threading/LazyInitializer.cs
+++ b/src/mscorlib/src/System/Threading/LazyInitializer.cs
@@ -13,40 +13,9 @@
using System.Diagnostics;
using System.Diagnostics.Contracts;
+
namespace System.Threading
{
-
- /// <summary>
- /// Specifies how a <see cref="T:System.Threading.Lazy{T}"/> instance should synchronize access among multiple threads.
- /// </summary>
- public enum LazyThreadSafetyMode
- {
- /// <summary>
- /// This mode makes no guarantees around the thread-safety of the <see cref="T:System.Threading.Lazy{T}"/> instance. If used from multiple threads, the behavior of the <see cref="T:System.Threading.Lazy{T}"/> is undefined.
- /// This mode should be used when a <see cref="T:System.Threading.Lazy{T}"/> is guaranteed to never be initialized from more than one thread simultaneously and high performance is crucial.
- /// If valueFactory throws an exception when the <see cref="T:System.Threading.Lazy{T}"/> is initialized, the exception will be cached and returned on subsequent accesses to Value. Also, if valueFactory recursively
- /// accesses Value on this <see cref="T:System.Threading.Lazy{T}"/> instance, a <see cref="T:System.InvalidOperationException"/> will be thrown.
- /// </summary>
- None,
-
- /// <summary>
- /// When multiple threads attempt to simultaneously initialize a <see cref="T:System.Threading.Lazy{T}"/> instance, this mode allows each thread to execute the
- /// valueFactory but only the first thread to complete initialization will be allowed to set the final value of the <see cref="T:System.Threading.Lazy{T}"/>.
- /// Once initialized successfully, any future calls to Value will return the cached result. If valueFactory throws an exception on any thread, that exception will be
- /// propagated out of Value. If any thread executes valueFactory without throwing an exception and, therefore, successfully sets the value, that value will be returned on
- /// subsequent accesses to Value from any thread. If no thread succeeds in setting the value, IsValueCreated will remain false and subsequent accesses to Value will result in
- /// the valueFactory delegate re-executing. Also, if valueFactory recursively accesses Value on this <see cref="T:System.Threading.Lazy{T}"/> instance, an exception will NOT be thrown.
- /// </summary>
- PublicationOnly,
-
- /// <summary>
- /// This mode uses locks to ensure that only a single thread can initialize a <see cref="T:System.Threading.Lazy{T}"/> instance in a thread-safe manner. In general,
- /// taken if this mode is used in conjunction with a <see cref="T:System.Threading.Lazy{T}"/> valueFactory delegate that uses locks internally, a deadlock can occur if not
- /// handled carefully. If valueFactory throws an exception when the<see cref="T:System.Threading.Lazy{T}"/> is initialized, the exception will be cached and returned on
- /// subsequent accesses to Value. Also, if valueFactory recursively accesses Value on this <see cref="T:System.Threading.Lazy{T}"/> instance, a <see cref="T:System.InvalidOperationException"/> will be thrown.
- /// </summary>
- ExecutionAndPublication
- }
/// <summary>
/// Provides lazy initialization routines.
/// </summary>
@@ -82,16 +51,8 @@ namespace System.Threading
/// if an object was not used and to then dispose of the object appropriately.
/// </para>
/// </remarks>
- public static T EnsureInitialized<T>(ref T target) where T : class
- {
- // Fast path.
- if (Volatile.Read<T>(ref target) != null)
- {
- return target;
- }
-
- return EnsureInitializedCore<T>(ref target, LazyHelpers<T>.s_activatorFactorySelector);
- }
+ public static T EnsureInitialized<T>(ref T target) where T : class =>
+ Volatile.Read<T>(ref target) ?? EnsureInitializedCore<T>(ref target, LazyHelpers<T>.s_activatorFactorySelector);
/// <summary>
/// Initializes a target reference type using the specified function if it has not already been
@@ -121,16 +82,8 @@ namespace System.Threading
/// if an object was not used and to then dispose of the object appropriately.
/// </para>
/// </remarks>
- public static T EnsureInitialized<T>(ref T target, Func<T> valueFactory) where T : class
- {
- // Fast path.
- if (Volatile.Read<T>(ref target) != null)
- {
- return target;
- }
-
- return EnsureInitializedCore<T>(ref target, valueFactory);
- }
+ public static T EnsureInitialized<T>(ref T target, Func<T> valueFactory) where T : class =>
+ Volatile.Read<T>(ref target) ?? EnsureInitializedCore<T>(ref target, valueFactory);
/// <summary>
/// Initialize the target using the given delegate (slow path).
@@ -144,7 +97,7 @@ namespace System.Threading
T value = valueFactory();
if (value == null)
{
- throw new InvalidOperationException(Environment.GetResourceString("Lazy_StaticInit_InvalidOperation"));
+ throw new InvalidOperationException(SR.Lazy_StaticInit_InvalidOperation);
}
Interlocked.CompareExchange(ref target, value, null);
@@ -152,7 +105,6 @@ namespace System.Threading
return target;
}
-
/// <summary>
/// Initializes a target reference or value type with its default constructor if it has not already
/// been initialized.
@@ -198,11 +150,33 @@ namespace System.Threading
return target;
}
-
return EnsureInitializedCore<T>(ref target, ref initialized, ref syncLock, valueFactory);
}
/// <summary>
+ /// Ensure the lock object is intialized.
+ /// </summary>
+ /// <param name="syncLock">A reference to a location containing a mutual exclusive lock. If <paramref name="syncLock"/> is null,
+ /// a new object will be instantiated.</param>
+ /// <returns>Initialized lock object.</returns>
+ private static object EnsureLockInitialized(ref object syncLock) =>
+ syncLock ??
+ Interlocked.CompareExchange(ref syncLock, new object(), null) ??
+ syncLock;
+
+ /// <summary>
+ /// Initializes a target reference type with a specified function if it has not already been initialized.
+ /// </summary>
+ /// <typeparam name="T">The type of the reference to be initialized. Has to be reference type.</typeparam>
+ /// <param name="target">A reference of type <typeparamref name="T"/> to initialize if it has not already been initialized.</param>
+ /// <param name="syncLock">A reference to an object used as the mutually exclusive lock for initializing
+ /// <paramref name="target"/>. If <paramref name="syncLock"/> is null, a new object will be instantiated.</param>
+ /// <param name="valueFactory">The <see cref="T:System.Func{T}"/> invoked to initialize the reference.</param>
+ /// <returns>The initialized value of type <typeparamref name="T"/>.</returns>
+ public static T EnsureInitialized<T>(ref T target, ref object syncLock, Func<T> valueFactory) where T : class =>
+ Volatile.Read(ref target) ?? EnsureInitializedCore<T>(ref target, ref syncLock, valueFactory);
+
+ /// <summary>
/// Ensure the target is initialized and return the value (slow path). This overload permits nulls
/// and also works for value type targets. Uses the supplied function to create the value.
/// </summary>
@@ -217,35 +191,52 @@ namespace System.Threading
/// <returns>The initialized object.</returns>
private static T EnsureInitializedCore<T>(ref T target, ref bool initialized, ref object syncLock, Func<T> valueFactory)
{
- // Lazily initialize the lock if necessary.
- object slock = syncLock;
- if (slock == null)
+ // Lazily initialize the lock if necessary and, then double check if initialization is still required.
+ lock (EnsureLockInitialized(ref syncLock))
{
- object newLock = new object();
- slock = Interlocked.CompareExchange(ref syncLock, newLock, null);
- if (slock == null)
+ if (!Volatile.Read(ref initialized))
{
- slock = newLock;
+ target = valueFactory();
+ Volatile.Write(ref initialized, true);
}
}
- // Now double check that initialization is still required.
- lock (slock)
+ return target;
+ }
+
+ /// <summary>
+ /// Ensure the target is initialized and return the value (slow path). This overload works only for reference type targets.
+ /// Uses the supplied function to create the value.
+ /// </summary>
+ /// <typeparam name="T">The type of target. Has to be reference type.</typeparam>
+ /// <param name="target">A reference to the target to be initialized.</param>
+ /// <param name="syncLock">A reference to a location containing a mutual exclusive lock. If <paramref name="syncLock"/> is null,
+ /// a new object will be instantiated.</param>
+ /// <param name="valueFactory">
+ /// The <see cref="T:System.Func{T}"/> to invoke in order to produce the lazily-initialized value.
+ /// </param>
+ /// <returns>The initialized object.</returns>
+ private static T EnsureInitializedCore<T>(ref T target, ref object syncLock, Func<T> valueFactory) where T : class
+ {
+ // Lazily initialize the lock if necessary and, then double check if initialization is still required.
+ lock (EnsureLockInitialized(ref syncLock))
{
- if (!Volatile.Read(ref initialized))
+ if (Volatile.Read(ref target) == null)
{
- target = valueFactory();
- Volatile.Write(ref initialized, true);
+ Volatile.Write(ref target, valueFactory());
+ if (target == null)
+ {
+ throw new InvalidOperationException(SR.Lazy_StaticInit_InvalidOperation);
+ }
}
}
return target;
}
-
}
// Caches the activation selector function to avoid delegate allocations.
- static class LazyHelpers<T>
+ internal static class LazyHelpers<T>
{
internal static Func<T> s_activatorFactorySelector = new Func<T>(ActivatorFactorySelector);
@@ -257,7 +248,7 @@ namespace System.Threading
}
catch (MissingMethodException)
{
- throw new MissingMemberException(Environment.GetResourceString("Lazy_CreateValue_NoParameterlessCtorForT"));
+ throw new MissingMemberException(SR.Lazy_CreateValue_NoParameterlessCtorForT);
}
}
}
diff --git a/src/mscorlib/src/System/Threading/LockRecursionException.cs b/src/mscorlib/src/System/Threading/LockRecursionException.cs
deleted file mode 100644
index 40f04b00b4..0000000000
--- a/src/mscorlib/src/System/Threading/LockRecursionException.cs
+++ /dev/null
@@ -1,30 +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:
-// This exception represents a failed attempt to recursively
-// acquire a lock, because the particular lock kind doesn't
-// support it in its current state.
-============================================================*/
-
-namespace System.Threading
-{
- using System;
- using System.Runtime.Serialization;
- using System.Runtime.CompilerServices;
-
- [Serializable]
- public class LockRecursionException : System.Exception
- {
- public LockRecursionException() { }
- public LockRecursionException(string message) : base(message) { }
- protected LockRecursionException(SerializationInfo info, StreamingContext context) : base(info, context) { }
- public LockRecursionException(string message, Exception innerException) : base(message, innerException) { }
- }
-
-}
diff --git a/src/mscorlib/src/System/Threading/ManualResetEvent.cs b/src/mscorlib/src/System/Threading/ManualResetEvent.cs
deleted file mode 100644
index a8e012fb43..0000000000
--- a/src/mscorlib/src/System/Threading/ManualResetEvent.cs
+++ /dev/null
@@ -1,24 +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: An example of a WaitHandle class
-**
-**
-=============================================================================*/
-namespace System.Threading {
-
- using System;
- using System.Runtime.InteropServices;
-
- 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 2d57b4102b..402a76cdc7 100644
--- a/src/mscorlib/src/System/Threading/ManualResetEventSlim.cs
+++ b/src/mscorlib/src/System/Threading/ManualResetEventSlim.cs
@@ -20,7 +20,6 @@ using System.Diagnostics.Contracts;
namespace System.Threading
{
-
// ManualResetEventSlim wraps a manual-reset event internally with a little bit of
// spinning. When an event will be set imminently, it is often advantageous to avoid
// a 4k+ cycle context switch in favor of briefly spinning. Therefore we layer on to
@@ -98,7 +97,6 @@ namespace System.Threading
/// </remarks>
public WaitHandle WaitHandle
{
-
get
{
ThrowIfDisposed();
@@ -165,11 +163,10 @@ namespace System.Threading
// it is possible for the max number of waiters to be exceeded via user-code, hence we use a real exception here.
if (value >= NumWaitersState_MaxValue)
- throw new InvalidOperationException(String.Format(Environment.GetResourceString("ManualResetEventSlim_ctor_TooManyWaiters"), NumWaitersState_MaxValue));
+ throw new InvalidOperationException(String.Format(SR.ManualResetEventSlim_ctor_TooManyWaiters, NumWaitersState_MaxValue));
UpdateStateAtomically(value << NumWaitersState_ShiftCount, NumWaitersState_BitMask);
}
-
}
//-----------------------------------------------------------------------------------
@@ -184,7 +181,6 @@ namespace System.Threading
public ManualResetEventSlim()
: this(false)
{
-
}
/// <summary>
@@ -222,7 +218,7 @@ namespace System.Threading
{
throw new ArgumentOutOfRangeException(
nameof(spinCount),
- String.Format(Environment.GetResourceString("ManualResetEventSlim_ctor_SpinCountOutOfRange"), SpinCountState_MaxValue));
+ String.Format(SR.ManualResetEventSlim_ctor_SpinCountOutOfRange, SpinCountState_MaxValue));
}
// We will suppress default spin because the user specified a count.
@@ -236,14 +232,13 @@ namespace System.Threading
/// <param name="spinCount">The spin count that decides when the event will block.</param>
private void Initialize(bool initialState, int spinCount)
{
- this.m_combinedState = initialState ? (1 << SignalledState_ShiftCount) : 0;
+ m_combinedState = initialState ? (1 << SignalledState_ShiftCount) : 0;
//the spinCount argument has been validated by the ctors.
//but we now sanity check our predefined constants.
Debug.Assert(DEFAULT_SPIN_SP >= 0, "Internal error - DEFAULT_SPIN_SP is outside the legal range.");
Debug.Assert(DEFAULT_SPIN_SP <= SpinCountState_MaxValue, "Internal error - DEFAULT_SPIN_SP is outside the legal range.");
SpinCount = PlatformHelper.IsSingleProcessor ? DEFAULT_SPIN_SP : spinCount;
-
}
/// <summary>
@@ -283,7 +278,6 @@ namespace System.Threading
}
else
{
-
// Now that the event is published, verify that the state hasn't changed since
// we snapped the preInitializeState. Another thread could have done that
// between our initial observation above and here. The barrier incurred from
@@ -337,7 +331,6 @@ namespace System.Threading
Debug.Assert(m_lock != null); //if waiters>0, then m_lock has already been created.
lock (m_lock)
{
-
Monitor.PulseAll(m_lock);
}
}
@@ -665,7 +658,6 @@ namespace System.Threading
// Now just loop back around, and the right thing will happen. Either:
// 1. We had a spurious wake-up due to some other wait being canceled via a different cancellationToken (rewait)
// or 2. the wait was successful. (the loop will break)
-
}
}
}
@@ -725,7 +717,7 @@ namespace System.Threading
private void ThrowIfDisposed()
{
if ((m_combinedState & Dispose_BitMask) != 0)
- throw new ObjectDisposedException(Environment.GetResourceString("ManualResetEventSlim_Disposed"));
+ throw new ObjectDisposedException(SR.ManualResetEventSlim_Disposed);
}
/// <summary>
diff --git a/src/mscorlib/src/System/Threading/Monitor.cs b/src/mscorlib/src/System/Threading/Monitor.cs
index fdbc384243..3ace3335aa 100644
--- a/src/mscorlib/src/System/Threading/Monitor.cs
+++ b/src/mscorlib/src/System/Threading/Monitor.cs
@@ -14,19 +14,20 @@
=============================================================================*/
-namespace System.Threading {
-
- using System;
- using System.Runtime;
- using System.Runtime.Remoting;
- using System.Threading;
- using System.Runtime.CompilerServices;
- using System.Runtime.ConstrainedExecution;
- using System.Runtime.Versioning;
- using System.Diagnostics;
- using System.Diagnostics.Contracts;
-
- public static class Monitor
+
+using System;
+using System.Runtime;
+using System.Runtime.Remoting;
+using System.Threading;
+using System.Runtime.CompilerServices;
+using System.Runtime.ConstrainedExecution;
+using System.Runtime.Versioning;
+using System.Diagnostics;
+using System.Diagnostics.Contracts;
+
+namespace System.Threading
+{
+ public static class Monitor
{
/*=========================================================================
** Obtain the monitor lock of obj. Will block if another thread holds the lock
@@ -56,7 +57,7 @@ namespace System.Threading {
private static void ThrowLockTakenException()
{
- throw new ArgumentException(Environment.GetResourceString("Argument_MustBeFalse"), "lockTaken");
+ throw new ArgumentException(SR.Argument_MustBeFalse, "lockTaken");
}
[MethodImplAttribute(MethodImplOptions.InternalCall)]
@@ -75,7 +76,7 @@ namespace System.Threading {
=========================================================================*/
[MethodImplAttribute(MethodImplOptions.InternalCall)]
public static extern void Exit(Object obj);
-
+
/*=========================================================================
** Similar to Enter, but will never block. That is, if the current thread can
** acquire the monitor lock without blocking, it will do so and TRUE will
@@ -99,7 +100,7 @@ namespace System.Threading {
ReliableEnterTimeout(obj, 0, ref lockTaken);
}
-
+
/*=========================================================================
** Version of TryEnter that will block, but only up to a timeout period
** expressed in milliseconds. If timeout == Timeout.Infinite the method
@@ -121,7 +122,7 @@ namespace System.Threading {
{
long tm = (long)timeout.TotalMilliseconds;
if (tm < -1 || tm > (long)Int32.MaxValue)
- throw new ArgumentOutOfRangeException(nameof(timeout), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
+ throw new ArgumentOutOfRangeException(nameof(timeout), SR.ArgumentOutOfRange_NeedNonNegOrNegative1);
return (int)tm;
}
diff --git a/src/mscorlib/src/System/Threading/Mutex.cs b/src/mscorlib/src/System/Threading/Mutex.cs
index dcb821307a..454a323f9a 100644
--- a/src/mscorlib/src/System/Threading/Mutex.cs
+++ b/src/mscorlib/src/System/Threading/Mutex.cs
@@ -11,8 +11,9 @@
**
**
=============================================================================*/
-namespace System.Threading
-{
+
+namespace System.Threading
+{
using System;
using System.Threading;
using System.Runtime.CompilerServices;
@@ -28,7 +29,7 @@ namespace System.Threading
public sealed class Mutex : WaitHandle
{
- static bool dummyBool;
+ private static bool dummyBool;
internal class MutexSecurity
{
@@ -46,12 +47,12 @@ namespace System.Threading
// 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 PLATFORM_WINDOWS
if (name != null && System.IO.Path.MaxPath < name.Length)
{
- throw new ArgumentException(Environment.GetResourceString("Argument_WaitHandleNameTooLong", Path.MaxPath), nameof(name));
+ throw new ArgumentException(SR.Format(SR.Argument_WaitHandleNameTooLong, Path.MaxPath), nameof(name));
}
-#endif
+#endif // PLATFORM_WINDOWS
Contract.EndContractBlock();
Win32Native.SECURITY_ATTRIBUTES secAttrs = null;
@@ -67,20 +68,20 @@ namespace System.Threading
RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(
tryCode,
cleanupCode,
- cleanupInfo);
+ cleanupInfo);
createdNew = tryCodeHelper.m_newMutex;
}
- internal class MutexTryCodeHelper
+ internal class MutexTryCodeHelper
{
- bool m_initiallyOwned;
- MutexCleanupInfo m_cleanupInfo;
+ private bool m_initiallyOwned;
+ private MutexCleanupInfo m_cleanupInfo;
internal bool m_newMutex;
- String m_name;
- Win32Native.SECURITY_ATTRIBUTES m_secAttrs;
- Mutex m_mutex;
+ private String m_name;
+ private Win32Native.SECURITY_ATTRIBUTES m_secAttrs;
+ private Mutex m_mutex;
- internal MutexTryCodeHelper(bool initiallyOwned,MutexCleanupInfo cleanupInfo, String name, Win32Native.SECURITY_ATTRIBUTES secAttrs, Mutex mutex)
+ internal MutexTryCodeHelper(bool initiallyOwned, MutexCleanupInfo cleanupInfo, String name, Win32Native.SECURITY_ATTRIBUTES secAttrs, Mutex mutex)
{
Debug.Assert(name == null || name.Length != 0);
@@ -92,16 +93,16 @@ namespace System.Threading
}
internal void MutexTryCode(object userData)
- {
+ {
SafeWaitHandle mutexHandle = null;
// try block
RuntimeHelpers.PrepareConstrainedRegions();
- try
+ try
{
}
- finally
+ finally
{
- if (m_initiallyOwned)
+ if (m_initiallyOwned)
{
m_cleanupInfo.inCriticalRegion = true;
}
@@ -109,15 +110,15 @@ namespace System.Threading
int errorCode = 0;
RuntimeHelpers.PrepareConstrainedRegions();
- try
+ try
{
}
- finally
+ finally
{
errorCode = CreateMutexHandle(m_initiallyOwned, m_name, m_secAttrs, out mutexHandle);
- }
+ }
- if (mutexHandle.IsInvalid)
+ if (mutexHandle.IsInvalid)
{
mutexHandle.SetHandleAsInvalid();
if (m_name != null)
@@ -127,11 +128,11 @@ 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", Interop.Sys.MaxName), "name");
+ throw new ArgumentException(SR.Format(SR.Argument_WaitHandleNameTooLong, Interop.Sys.MaxName), "name");
#endif
case Win32Native.ERROR_INVALID_HANDLE:
- throw new WaitHandleCannotBeOpenedException(Environment.GetResourceString("Threading.WaitHandleCannotBeOpenedException_InvalidHandle", m_name));
+ throw new WaitHandleCannotBeOpenedException(SR.Format(SR.Threading_WaitHandleCannotBeOpenedException_InvalidHandle, m_name));
}
}
__Error.WinIOError(errorCode, m_name);
@@ -140,19 +141,21 @@ namespace System.Threading
m_mutex.SetHandleInternal(mutexHandle);
m_mutex.hasThreadAffinity = true;
-
}
}
private void MutexCleanupCode(Object userData, bool exceptionThrown)
{
- MutexCleanupInfo cleanupInfo = (MutexCleanupInfo) userData;
-
+ MutexCleanupInfo cleanupInfo = (MutexCleanupInfo)userData;
+
// If hasThreadAffinity isn't true, we've thrown an exception in the above try, and we must free the mutex
// on this OS thread before ending our thread affninity.
- if(!hasThreadAffinity) {
- if (cleanupInfo.mutexHandle != null && !cleanupInfo.mutexHandle.IsInvalid) {
- if( cleanupInfo.inCriticalRegion) {
+ if (!hasThreadAffinity)
+ {
+ if (cleanupInfo.mutexHandle != null && !cleanupInfo.mutexHandle.IsInvalid)
+ {
+ if (cleanupInfo.inCriticalRegion)
+ {
Win32Native.ReleaseMutex(cleanupInfo.mutexHandle);
}
cleanupInfo.mutexHandle.Dispose();
@@ -171,7 +174,8 @@ namespace System.Threading
}
}
- public Mutex(bool initiallyOwned, String name) : this(initiallyOwned, name, out dummyBool) {
+ public Mutex(bool initiallyOwned, String name) : this(initiallyOwned, name, out dummyBool)
+ {
}
public Mutex(bool initiallyOwned) : this(initiallyOwned, null, out dummyBool)
@@ -181,7 +185,7 @@ namespace System.Threading
public Mutex() : this(false, null, out dummyBool)
{
}
-
+
private Mutex(SafeWaitHandle handle)
{
SetHandleInternal(handle);
@@ -190,7 +194,7 @@ namespace System.Threading
public static Mutex OpenExisting(string name)
{
- return OpenExisting(name, (MutexRights) 0);
+ return OpenExisting(name, (MutexRights)0);
}
internal enum MutexRights
@@ -206,7 +210,7 @@ namespace System.Threading
throw new WaitHandleCannotBeOpenedException();
case OpenExistingResult.NameInvalid:
- throw new WaitHandleCannotBeOpenedException(Environment.GetResourceString("Threading.WaitHandleCannotBeOpenedException_InvalidHandle", name));
+ throw new WaitHandleCannotBeOpenedException(SR.Format(SR.Threading_WaitHandleCannotBeOpenedException_InvalidHandle, name));
case OpenExistingResult.PathNotFound:
__Error.WinIOError(Win32Native.ERROR_PATH_NOT_FOUND, name);
@@ -226,17 +230,17 @@ namespace System.Threading
{
if (name == null)
{
- throw new ArgumentNullException(nameof(name), Environment.GetResourceString("ArgumentNull_WithParamName"));
+ throw new ArgumentNullException(nameof(name), SR.ArgumentNull_WithParamName);
}
- if(name.Length == 0)
+ if (name.Length == 0)
{
- throw new ArgumentException(Environment.GetResourceString("Argument_EmptyName"), nameof(name));
+ throw new ArgumentException(SR.Argument_EmptyName, nameof(name));
}
#if !PLATFORM_UNIX
- if(System.IO.Path.MaxPath < name.Length)
+ if (System.IO.Path.MaxPath < name.Length)
{
- throw new ArgumentException(Environment.GetResourceString("Argument_WaitHandleNameTooLong", Path.MaxPath), nameof(name));
+ throw new ArgumentException(SR.Format(SR.Argument_WaitHandleNameTooLong, Path.MaxPath), nameof(name));
}
#endif
Contract.EndContractBlock();
@@ -258,11 +262,11 @@ 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", Interop.Sys.MaxName), nameof(name));
+ throw new ArgumentException(SR.Format(SR.Argument_WaitHandleNameTooLong, Interop.Sys.MaxName), nameof(name));
}
#endif
- if(Win32Native.ERROR_FILE_NOT_FOUND == errorCode || Win32Native.ERROR_INVALID_NAME == errorCode)
+ if (Win32Native.ERROR_FILE_NOT_FOUND == errorCode || Win32Native.ERROR_INVALID_NAME == errorCode)
return OpenExistingResult.NameNotFound;
if (Win32Native.ERROR_PATH_NOT_FOUND == errorCode)
return OpenExistingResult.PathNotFound;
@@ -270,7 +274,7 @@ namespace System.Threading
return OpenExistingResult.NameInvalid;
// this is for passed through Win32Native Errors
- __Error.WinIOError(errorCode,name);
+ __Error.WinIOError(errorCode, name);
}
result = new Mutex(myHandle);
@@ -287,11 +291,11 @@ namespace System.Threading
}
else
{
- throw new ApplicationException(Environment.GetResourceString("Arg_SynchronizationLockException"));
+ throw new ApplicationException(SR.Arg_SynchronizationLockException);
}
}
- static int CreateMutexHandle(bool initiallyOwned, String name, Win32Native.SECURITY_ATTRIBUTES securityAttribute, out SafeWaitHandle mutexHandle)
+ private 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 d3caff5e74..0830ee6b6c 100644
--- a/src/mscorlib/src/System/Threading/Overlapped.cs
+++ b/src/mscorlib/src/System/Threading/Overlapped.cs
@@ -24,18 +24,18 @@
=============================================================================*/
-namespace System.Threading
-{
- using System;
- using System.Runtime.InteropServices;
- using System.Runtime.CompilerServices;
- using System.Runtime.Versioning;
- using System.Security;
- using System.Runtime.ConstrainedExecution;
- using System.Diagnostics;
- using System.Diagnostics.Contracts;
- using System.Collections.Concurrent;
-
+using System;
+using System.Runtime.InteropServices;
+using System.Runtime.CompilerServices;
+using System.Runtime.Versioning;
+using System.Security;
+using System.Runtime.ConstrainedExecution;
+using System.Diagnostics;
+using System.Diagnostics.Contracts;
+using System.Collections.Concurrent;
+
+namespace System.Threading
+{
#region struct NativeOverlapped
// Valuetype that represents the (unmanaged) Win32 OVERLAPPED structure
@@ -45,11 +45,11 @@ namespace System.Threading
[System.Runtime.InteropServices.StructLayout(LayoutKind.Sequential)]
public struct NativeOverlapped
{
- public IntPtr InternalLow;
- public IntPtr InternalHigh;
- public int OffsetLow;
- public int OffsetHigh;
- public IntPtr EventHandle;
+ public IntPtr InternalLow;
+ public IntPtr InternalHigh;
+ public int OffsetLow;
+ public int OffsetHigh;
+ public IntPtr EventHandle;
}
#endregion struct NativeOverlapped
@@ -59,15 +59,11 @@ namespace System.Threading
unsafe internal class _IOCompletionCallback
{
- IOCompletionCallback _ioCompletionCallback;
- ExecutionContext _executionContext;
- uint _errorCode; // Error code
- uint _numBytes; // No. of bytes transferred
- NativeOverlapped* _pOVERLAP;
-
- static _IOCompletionCallback()
- {
- }
+ private IOCompletionCallback _ioCompletionCallback;
+ private ExecutionContext _executionContext;
+ private uint _errorCode; // Error code
+ private uint _numBytes; // No. of bytes transferred
+ private NativeOverlapped* _pOVERLAP;
internal _IOCompletionCallback(IOCompletionCallback ioCompletionCallback)
{
@@ -79,12 +75,12 @@ namespace System.Threading
static internal ContextCallback _ccb = new ContextCallback(IOCompletionCallback_Context);
static internal void IOCompletionCallback_Context(Object state)
{
- _IOCompletionCallback helper = (_IOCompletionCallback)state;
- Debug.Assert(helper != null,"_IOCompletionCallback cannot be null");
+ _IOCompletionCallback helper = (_IOCompletionCallback)state;
+ Debug.Assert(helper != null, "_IOCompletionCallback cannot be null");
helper._ioCompletionCallback(helper._errorCode, helper._numBytes, helper._pOVERLAP);
}
-
+
// call back helper
static unsafe internal void PerformIOCompletionCallback(uint errorCode, // Error code
uint numBytes, // No. of bytes transferred
@@ -97,13 +93,13 @@ namespace System.Threading
do
{
overlapped = OverlappedData.GetOverlappedFromNative(pOVERLAP).m_overlapped;
- helper = overlapped.iocbHelper;
+ helper = overlapped.iocbHelper;
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);
+ callback(errorCode, numBytes, pOVERLAP);
}
else
{
@@ -112,12 +108,11 @@ namespace System.Threading
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);
-
}
}
@@ -147,7 +142,7 @@ namespace System.Threading
internal NativeOverlapped m_nativeOverlapped;
// Adding an empty default ctor for annotation purposes
- internal OverlappedData(){}
+ internal OverlappedData() { }
internal void ReInitialize()
{
@@ -169,8 +164,9 @@ namespace System.Threading
unsafe internal NativeOverlapped* Pack(IOCompletionCallback iocb, Object userData)
{
- if (!m_pinSelf.IsNull()) {
- throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_Overlapped_Pack"));
+ if (!m_pinSelf.IsNull())
+ {
+ throw new InvalidOperationException(SR.InvalidOperation_Overlapped_Pack);
}
if (iocb != null)
@@ -199,9 +195,10 @@ namespace System.Threading
}
unsafe internal NativeOverlapped* UnsafePack(IOCompletionCallback iocb, Object userData)
- {
- if (!m_pinSelf.IsNull()) {
- throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_Overlapped_Pack"));
+ {
+ if (!m_pinSelf.IsNull())
+ {
+ throw new InvalidOperationException(SR.InvalidOperation_Overlapped_Pack);
}
m_userObject = userData;
if (m_userObject != null)
@@ -225,7 +222,7 @@ namespace System.Threading
get { return m_nativeOverlapped.EventHandle; }
set { m_nativeOverlapped.EventHandle = value; }
}
-
+
[MethodImplAttribute(MethodImplOptions.InternalCall)]
unsafe private extern NativeOverlapped* AllocateNativeOverlapped();
@@ -233,7 +230,7 @@ namespace System.Threading
unsafe internal static extern void FreeNativeOverlapped(NativeOverlapped* nativeOverlappedPtr);
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- unsafe internal static extern OverlappedData GetOverlappedFromNative(NativeOverlapped* nativeOverlappedPtr);
+ unsafe internal static extern OverlappedData GetOverlappedFromNative(NativeOverlapped* nativeOverlappedPtr);
[MethodImplAttribute(MethodImplOptions.InternalCall)]
unsafe internal static extern void CheckVMForIOPacket(out NativeOverlapped* pOVERLAP, out uint errorCode, out uint numBytes);
@@ -244,21 +241,20 @@ namespace System.Threading
#region class Overlapped
- /// <internalonly/>
public class Overlapped
{
private OverlappedData m_overlappedData;
- private static PinnableBufferCache s_overlappedDataCache = new PinnableBufferCache("System.Threading.OverlappedData", ()=> new OverlappedData());
-
- public Overlapped()
+ private static PinnableBufferCache s_overlappedDataCache = new PinnableBufferCache("System.Threading.OverlappedData", () => new OverlappedData());
+
+ public Overlapped()
{
- m_overlappedData = (OverlappedData) s_overlappedDataCache.Allocate();
+ m_overlappedData = (OverlappedData)s_overlappedDataCache.Allocate();
m_overlappedData.m_overlapped = this;
}
public Overlapped(int offsetLo, int offsetHi, IntPtr hEvent, IAsyncResult ar)
{
- m_overlappedData = (OverlappedData) s_overlappedDataCache.Allocate();
+ m_overlappedData = (OverlappedData)s_overlappedDataCache.Allocate();
m_overlappedData.m_overlapped = this;
m_overlappedData.m_nativeOverlapped.OffsetLow = offsetLo;
m_overlappedData.m_nativeOverlapped.OffsetHigh = offsetHi;
@@ -321,7 +317,7 @@ namespace System.Threading
[CLSCompliant(false)]
unsafe public NativeOverlapped* Pack(IOCompletionCallback iocb)
{
- return Pack (iocb, null);
+ return Pack(iocb, null);
}
[CLSCompliant(false)]
@@ -334,12 +330,12 @@ namespace System.Threading
[CLSCompliant(false)]
unsafe public NativeOverlapped* UnsafePack(IOCompletionCallback iocb)
{
- return UnsafePack (iocb, null);
+ return UnsafePack(iocb, null);
}
[CLSCompliant(false)]
unsafe public NativeOverlapped* UnsafePack(IOCompletionCallback iocb, Object userData)
- {
+ {
return m_overlappedData.UnsafePack(iocb, userData);
}
@@ -355,7 +351,7 @@ namespace System.Threading
Contract.EndContractBlock();
Overlapped overlapped = OverlappedData.GetOverlappedFromNative(nativeOverlappedPtr).m_overlapped;
-
+
return overlapped;
}
@@ -373,9 +369,7 @@ namespace System.Threading
overlappedData.ReInitialize();
s_overlappedDataCache.Free(overlappedData);
}
-
}
#endregion class Overlapped
-
} // namespace
diff --git a/src/mscorlib/src/System/Threading/ParameterizedThreadStart.cs b/src/mscorlib/src/System/Threading/ParameterizedThreadStart.cs
deleted file mode 100644
index 32b63153c4..0000000000
--- a/src/mscorlib/src/System/Threading/ParameterizedThreadStart.cs
+++ /dev/null
@@ -1,23 +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: This class is a Delegate which defines the start method
-** for starting a thread. That method must match this delegate.
-**
-**
-=============================================================================*/
-
-
-namespace System.Threading {
- using System.Threading;
- using System.Runtime.InteropServices;
-
- [ComVisibleAttribute(false)]
- public delegate void ParameterizedThreadStart(object obj);
-}
diff --git a/src/mscorlib/src/System/Threading/ReaderWriterLockSlim.cs b/src/mscorlib/src/System/Threading/ReaderWriterLockSlim.cs
new file mode 100644
index 0000000000..98517ad85f
--- /dev/null
+++ b/src/mscorlib/src/System/Threading/ReaderWriterLockSlim.cs
@@ -0,0 +1,1311 @@
+// 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 Internal.Runtime.Augments;
+using System.Diagnostics; // for TraceInformation
+using System.Threading;
+using System.Runtime.CompilerServices;
+
+namespace System.Threading
+{
+ public enum LockRecursionPolicy
+ {
+ NoRecursion = 0,
+ SupportsRecursion = 1,
+ }
+
+ //
+ // ReaderWriterCount tracks how many of each kind of lock is held by each thread.
+ // We keep a linked list for each thread, attached to a ThreadStatic field.
+ // These are reused wherever possible, so that a given thread will only
+ // allocate N of these, where N is the maximum number of locks held simultaneously
+ // by that thread.
+ //
+ internal class ReaderWriterCount
+ {
+ // Which lock does this object belong to? This is a numeric ID for two reasons:
+ // 1) We don't want this field to keep the lock object alive, and a WeakReference would
+ // be too expensive.
+ // 2) Setting the value of a long is faster than setting the value of a reference.
+ // The "hot" paths in ReaderWriterLockSlim are short enough that this actually
+ // matters.
+ public long lockID;
+
+ // How many reader locks does this thread hold on this ReaderWriterLockSlim instance?
+ public int readercount;
+
+ // Ditto for writer/upgrader counts. These are only used if the lock allows recursion.
+ // But we have to have the fields on every ReaderWriterCount instance, because
+ // we reuse it for different locks.
+ public int writercount;
+ public int upgradecount;
+
+ // Next RWC in this thread's list.
+ public ReaderWriterCount next;
+ }
+
+ /// <summary>
+ /// A reader-writer lock implementation that is intended to be simple, yet very
+ /// efficient. In particular only 1 interlocked operation is taken for any lock
+ /// operation (we use spin locks to achieve this). The spin lock is never held
+ /// for more than a few instructions (in particular, we never call event APIs
+ /// or in fact any non-trivial API while holding the spin lock).
+ /// </summary>
+ public class ReaderWriterLockSlim : IDisposable
+ {
+ //Specifying if locked can be reacquired recursively.
+ private bool _fIsReentrant;
+
+ // Lock specification for myLock: This lock protects exactly the local fields associated with this
+ // instance of ReaderWriterLockSlim. It does NOT protect the memory associated with
+ // the events that hang off this lock (eg writeEvent, readEvent upgradeEvent).
+ private int _myLock;
+
+ //The variables controlling spinning behavior of Mylock(which is a spin-lock)
+
+ private const int LockSpinCycles = 20;
+ private const int LockSpinCount = 10;
+ private const int LockSleep0Count = 5;
+
+ // These variables allow use to avoid Setting events (which is expensive) if we don't have to.
+ private uint _numWriteWaiters; // maximum number of threads that can be doing a WaitOne on the writeEvent
+ private uint _numReadWaiters; // maximum number of threads that can be doing a WaitOne on the readEvent
+ private uint _numWriteUpgradeWaiters; // maximum number of threads that can be doing a WaitOne on the upgradeEvent (at most 1).
+ private uint _numUpgradeWaiters;
+
+ //Variable used for quick check when there are no waiters.
+ private bool _fNoWaiters;
+
+ private int _upgradeLockOwnerId;
+ private int _writeLockOwnerId;
+
+ // conditions we wait on.
+ private EventWaitHandle _writeEvent; // threads waiting to acquire a write lock go here.
+ private EventWaitHandle _readEvent; // threads waiting to acquire a read lock go here (will be released in bulk)
+ private EventWaitHandle _upgradeEvent; // thread waiting to acquire the upgrade lock
+ private EventWaitHandle _waitUpgradeEvent; // thread waiting to upgrade from the upgrade lock to a write lock go here (at most one)
+
+ // Every lock instance has a unique ID, which is used by ReaderWriterCount to associate itself with the lock
+ // without holding a reference to it.
+ private static long s_nextLockID;
+ private long _lockID;
+
+ // See comments on ReaderWriterCount.
+ [ThreadStatic]
+ private static ReaderWriterCount t_rwc;
+
+ private bool _fUpgradeThreadHoldingRead;
+
+ private const int MaxSpinCount = 20;
+
+ //The uint, that contains info like if the writer lock is held, num of
+ //readers etc.
+ private uint _owners;
+
+ //Various R/W masks
+ //Note:
+ //The Uint is divided as follows:
+ //
+ //Writer-Owned Waiting-Writers Waiting Upgraders Num-Readers
+ // 31 30 29 28.......0
+ //
+ //Dividing the uint, allows to vastly simplify logic for checking if a
+ //reader should go in etc. Setting the writer bit will automatically
+ //make the value of the uint much larger than the max num of readers
+ //allowed, thus causing the check for max_readers to fail.
+
+ private const uint WRITER_HELD = 0x80000000;
+ private const uint WAITING_WRITERS = 0x40000000;
+ private const uint WAITING_UPGRADER = 0x20000000;
+
+ //The max readers is actually one less then its theoretical max.
+ //This is done in order to prevent reader count overflows. If the reader
+ //count reaches max, other readers will wait.
+ private const uint MAX_READER = 0x10000000 - 2;
+
+ private const uint READER_MASK = 0x10000000 - 1;
+
+ private bool _fDisposed;
+
+ private void InitializeThreadCounts()
+ {
+ _upgradeLockOwnerId = -1;
+ _writeLockOwnerId = -1;
+ }
+
+ public ReaderWriterLockSlim()
+ : this(LockRecursionPolicy.NoRecursion)
+ {
+ }
+
+ public ReaderWriterLockSlim(LockRecursionPolicy recursionPolicy)
+ {
+ if (recursionPolicy == LockRecursionPolicy.SupportsRecursion)
+ {
+ _fIsReentrant = true;
+ }
+ InitializeThreadCounts();
+ _fNoWaiters = true;
+ _lockID = Interlocked.Increment(ref s_nextLockID);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static bool IsRWEntryEmpty(ReaderWriterCount rwc)
+ {
+ if (rwc.lockID == 0)
+ return true;
+ else if (rwc.readercount == 0 && rwc.writercount == 0 && rwc.upgradecount == 0)
+ return true;
+ else
+ return false;
+ }
+
+ private bool IsRwHashEntryChanged(ReaderWriterCount lrwc)
+ {
+ return lrwc.lockID != _lockID;
+ }
+
+ /// <summary>
+ /// This routine retrieves/sets the per-thread counts needed to enforce the
+ /// various rules related to acquiring the lock.
+ ///
+ /// DontAllocate is set to true if the caller just wants to get an existing
+ /// entry for this thread, but doesn't want to add one if an existing one
+ /// could not be found.
+ /// </summary>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private ReaderWriterCount GetThreadRWCount(bool dontAllocate)
+ {
+ ReaderWriterCount rwc = t_rwc;
+ ReaderWriterCount empty = null;
+ while (rwc != null)
+ {
+ if (rwc.lockID == _lockID)
+ return rwc;
+
+ if (!dontAllocate && empty == null && IsRWEntryEmpty(rwc))
+ empty = rwc;
+
+ rwc = rwc.next;
+ }
+
+ if (dontAllocate)
+ return null;
+
+ if (empty == null)
+ {
+ empty = new ReaderWriterCount();
+ empty.next = t_rwc;
+ t_rwc = empty;
+ }
+
+ empty.lockID = _lockID;
+ return empty;
+ }
+
+ public void EnterReadLock()
+ {
+ TryEnterReadLock(-1);
+ }
+
+ //
+ // Common timeout support
+ //
+ private struct TimeoutTracker
+ {
+ private int _total;
+ private int _start;
+
+ public TimeoutTracker(TimeSpan timeout)
+ {
+ long ltm = (long)timeout.TotalMilliseconds;
+ if (ltm < -1 || ltm > (long)Int32.MaxValue)
+ throw new ArgumentOutOfRangeException(nameof(timeout));
+ _total = (int)ltm;
+ if (_total != -1 && _total != 0)
+ _start = Environment.TickCount;
+ else
+ _start = 0;
+ }
+
+ public TimeoutTracker(int millisecondsTimeout)
+ {
+ if (millisecondsTimeout < -1)
+ throw new ArgumentOutOfRangeException(nameof(millisecondsTimeout));
+ _total = millisecondsTimeout;
+ if (_total != -1 && _total != 0)
+ _start = Environment.TickCount;
+ else
+ _start = 0;
+ }
+
+ public int RemainingMilliseconds
+ {
+ get
+ {
+ if (_total == -1 || _total == 0)
+ return _total;
+
+ int elapsed = Environment.TickCount - _start;
+ // elapsed may be negative if TickCount has overflowed by 2^31 milliseconds.
+ if (elapsed < 0 || elapsed >= _total)
+ return 0;
+
+ return _total - elapsed;
+ }
+ }
+
+ public bool IsExpired
+ {
+ get
+ {
+ return RemainingMilliseconds == 0;
+ }
+ }
+ }
+
+ public bool TryEnterReadLock(TimeSpan timeout)
+ {
+ return TryEnterReadLock(new TimeoutTracker(timeout));
+ }
+
+ public bool TryEnterReadLock(int millisecondsTimeout)
+ {
+ return TryEnterReadLock(new TimeoutTracker(millisecondsTimeout));
+ }
+
+ private bool TryEnterReadLock(TimeoutTracker timeout)
+ {
+ return TryEnterReadLockCore(timeout);
+ }
+
+ private bool TryEnterReadLockCore(TimeoutTracker timeout)
+ {
+ if (_fDisposed)
+ throw new ObjectDisposedException(null);
+
+ ReaderWriterCount lrwc = null;
+ int id = Environment.CurrentManagedThreadId;
+
+ if (!_fIsReentrant)
+ {
+ if (id == _writeLockOwnerId)
+ {
+ //Check for AW->AR
+ throw new LockRecursionException(SR.LockRecursionException_ReadAfterWriteNotAllowed);
+ }
+
+ EnterMyLock();
+
+ lrwc = GetThreadRWCount(false);
+
+ //Check if the reader lock is already acquired. Note, we could
+ //check the presence of a reader by not allocating rwc (But that
+ //would lead to two lookups in the common case. It's better to keep
+ //a count in the structure).
+ if (lrwc.readercount > 0)
+ {
+ ExitMyLock();
+ throw new LockRecursionException(SR.LockRecursionException_RecursiveReadNotAllowed);
+ }
+ else if (id == _upgradeLockOwnerId)
+ {
+ //The upgrade lock is already held.
+ //Update the global read counts and exit.
+
+ lrwc.readercount++;
+ _owners++;
+ ExitMyLock();
+ return true;
+ }
+ }
+ else
+ {
+ EnterMyLock();
+ lrwc = GetThreadRWCount(false);
+ if (lrwc.readercount > 0)
+ {
+ lrwc.readercount++;
+ ExitMyLock();
+ return true;
+ }
+ else if (id == _upgradeLockOwnerId)
+ {
+ //The upgrade lock is already held.
+ //Update the global read counts and exit.
+ lrwc.readercount++;
+ _owners++;
+ ExitMyLock();
+ _fUpgradeThreadHoldingRead = true;
+ return true;
+ }
+ else if (id == _writeLockOwnerId)
+ {
+ //The write lock is already held.
+ //Update global read counts here,
+ lrwc.readercount++;
+ _owners++;
+ ExitMyLock();
+ return true;
+ }
+ }
+
+ bool retVal = true;
+
+ int spincount = 0;
+
+ for (; ;)
+ {
+ // We can enter a read lock if there are only read-locks have been given out
+ // and a writer is not trying to get in.
+
+ if (_owners < MAX_READER)
+ {
+ // Good case, there is no contention, we are basically done
+ _owners++; // Indicate we have another reader
+ lrwc.readercount++;
+ break;
+ }
+
+ if (spincount < MaxSpinCount)
+ {
+ ExitMyLock();
+ if (timeout.IsExpired)
+ return false;
+ spincount++;
+ SpinWait(spincount);
+ EnterMyLock();
+ //The per-thread structure may have been recycled as the lock is acquired (due to message pumping), load again.
+ if (IsRwHashEntryChanged(lrwc))
+ lrwc = GetThreadRWCount(false);
+ continue;
+ }
+
+ // Drat, we need to wait. Mark that we have waiters and wait.
+ if (_readEvent == null) // Create the needed event
+ {
+ LazyCreateEvent(ref _readEvent, false);
+ if (IsRwHashEntryChanged(lrwc))
+ lrwc = GetThreadRWCount(false);
+ continue; // since we left the lock, start over.
+ }
+
+ retVal = WaitOnEvent(_readEvent, ref _numReadWaiters, timeout, isWriteWaiter: false);
+ if (!retVal)
+ {
+ return false;
+ }
+ if (IsRwHashEntryChanged(lrwc))
+ lrwc = GetThreadRWCount(false);
+ }
+
+ ExitMyLock();
+ return retVal;
+ }
+
+ public void EnterWriteLock()
+ {
+ TryEnterWriteLock(-1);
+ }
+
+ public bool TryEnterWriteLock(TimeSpan timeout)
+ {
+ return TryEnterWriteLock(new TimeoutTracker(timeout));
+ }
+
+ public bool TryEnterWriteLock(int millisecondsTimeout)
+ {
+ return TryEnterWriteLock(new TimeoutTracker(millisecondsTimeout));
+ }
+
+ private bool TryEnterWriteLock(TimeoutTracker timeout)
+ {
+ return TryEnterWriteLockCore(timeout);
+ }
+
+ private bool TryEnterWriteLockCore(TimeoutTracker timeout)
+ {
+ if (_fDisposed)
+ throw new ObjectDisposedException(null);
+
+ int id = Environment.CurrentManagedThreadId;
+ ReaderWriterCount lrwc;
+ bool upgradingToWrite = false;
+
+ if (!_fIsReentrant)
+ {
+ if (id == _writeLockOwnerId)
+ {
+ //Check for AW->AW
+ throw new LockRecursionException(SR.LockRecursionException_RecursiveWriteNotAllowed);
+ }
+ else if (id == _upgradeLockOwnerId)
+ {
+ //AU->AW case is allowed once.
+ upgradingToWrite = true;
+ }
+
+ EnterMyLock();
+ lrwc = GetThreadRWCount(true);
+
+ //Can't acquire write lock with reader lock held.
+ if (lrwc != null && lrwc.readercount > 0)
+ {
+ ExitMyLock();
+ throw new LockRecursionException(SR.LockRecursionException_WriteAfterReadNotAllowed);
+ }
+ }
+ else
+ {
+ EnterMyLock();
+ lrwc = GetThreadRWCount(false);
+
+ if (id == _writeLockOwnerId)
+ {
+ lrwc.writercount++;
+ ExitMyLock();
+ return true;
+ }
+ else if (id == _upgradeLockOwnerId)
+ {
+ upgradingToWrite = true;
+ }
+ else if (lrwc.readercount > 0)
+ {
+ //Write locks may not be acquired if only read locks have been
+ //acquired.
+ ExitMyLock();
+ throw new LockRecursionException(SR.LockRecursionException_WriteAfterReadNotAllowed);
+ }
+ }
+
+ int spincount = 0;
+ bool retVal = true;
+
+ for (; ;)
+ {
+ if (IsWriterAcquired())
+ {
+ // Good case, there is no contention, we are basically done
+ SetWriterAcquired();
+ break;
+ }
+
+ //Check if there is just one upgrader, and no readers.
+ //Assumption: Only one thread can have the upgrade lock, so the
+ //following check will fail for all other threads that may sneak in
+ //when the upgrading thread is waiting.
+
+ if (upgradingToWrite)
+ {
+ uint readercount = GetNumReaders();
+
+ if (readercount == 1)
+ {
+ //Good case again, there is just one upgrader, and no readers.
+ SetWriterAcquired(); // indicate we have a writer.
+ break;
+ }
+ else if (readercount == 2)
+ {
+ if (lrwc != null)
+ {
+ if (IsRwHashEntryChanged(lrwc))
+ lrwc = GetThreadRWCount(false);
+
+ if (lrwc.readercount > 0)
+ {
+ //This check is needed for EU->ER->EW case, as the owner count will be two.
+ Debug.Assert(_fIsReentrant);
+ Debug.Assert(_fUpgradeThreadHoldingRead);
+
+ //Good case again, there is just one upgrader, and no readers.
+ SetWriterAcquired(); // indicate we have a writer.
+ break;
+ }
+ }
+ }
+ }
+
+ if (spincount < MaxSpinCount)
+ {
+ ExitMyLock();
+ if (timeout.IsExpired)
+ return false;
+ spincount++;
+ SpinWait(spincount);
+ EnterMyLock();
+ continue;
+ }
+
+ if (upgradingToWrite)
+ {
+ if (_waitUpgradeEvent == null) // Create the needed event
+ {
+ LazyCreateEvent(ref _waitUpgradeEvent, true);
+ continue; // since we left the lock, start over.
+ }
+
+ Debug.Assert(_numWriteUpgradeWaiters == 0, "There can be at most one thread with the upgrade lock held.");
+
+ retVal = WaitOnEvent(_waitUpgradeEvent, ref _numWriteUpgradeWaiters, timeout, isWriteWaiter: true);
+
+ //The lock is not held in case of failure.
+ if (!retVal)
+ return false;
+ }
+ else
+ {
+ // Drat, we need to wait. Mark that we have waiters and wait.
+ if (_writeEvent == null) // create the needed event.
+ {
+ LazyCreateEvent(ref _writeEvent, true);
+ continue; // since we left the lock, start over.
+ }
+
+ retVal = WaitOnEvent(_writeEvent, ref _numWriteWaiters, timeout, isWriteWaiter: true);
+ //The lock is not held in case of failure.
+ if (!retVal)
+ return false;
+ }
+ }
+
+ Debug.Assert((_owners & WRITER_HELD) > 0);
+
+ if (_fIsReentrant)
+ {
+ if (IsRwHashEntryChanged(lrwc))
+ lrwc = GetThreadRWCount(false);
+ lrwc.writercount++;
+ }
+
+ ExitMyLock();
+
+ _writeLockOwnerId = id;
+
+ return true;
+ }
+
+ public void EnterUpgradeableReadLock()
+ {
+ TryEnterUpgradeableReadLock(-1);
+ }
+
+ public bool TryEnterUpgradeableReadLock(TimeSpan timeout)
+ {
+ return TryEnterUpgradeableReadLock(new TimeoutTracker(timeout));
+ }
+
+ public bool TryEnterUpgradeableReadLock(int millisecondsTimeout)
+ {
+ return TryEnterUpgradeableReadLock(new TimeoutTracker(millisecondsTimeout));
+ }
+
+ private bool TryEnterUpgradeableReadLock(TimeoutTracker timeout)
+ {
+ return TryEnterUpgradeableReadLockCore(timeout);
+ }
+
+ private bool TryEnterUpgradeableReadLockCore(TimeoutTracker timeout)
+ {
+ if (_fDisposed)
+ throw new ObjectDisposedException(null);
+
+ int id = Environment.CurrentManagedThreadId;
+ ReaderWriterCount lrwc;
+
+ if (!_fIsReentrant)
+ {
+ if (id == _upgradeLockOwnerId)
+ {
+ //Check for AU->AU
+ throw new LockRecursionException(SR.LockRecursionException_RecursiveUpgradeNotAllowed);
+ }
+ else if (id == _writeLockOwnerId)
+ {
+ //Check for AU->AW
+ throw new LockRecursionException(SR.LockRecursionException_UpgradeAfterWriteNotAllowed);
+ }
+
+ EnterMyLock();
+ lrwc = GetThreadRWCount(true);
+ //Can't acquire upgrade lock with reader lock held.
+ if (lrwc != null && lrwc.readercount > 0)
+ {
+ ExitMyLock();
+ throw new LockRecursionException(SR.LockRecursionException_UpgradeAfterReadNotAllowed);
+ }
+ }
+ else
+ {
+ EnterMyLock();
+ lrwc = GetThreadRWCount(false);
+
+ if (id == _upgradeLockOwnerId)
+ {
+ lrwc.upgradecount++;
+ ExitMyLock();
+ return true;
+ }
+ else if (id == _writeLockOwnerId)
+ {
+ //Write lock is already held, Just update the global state
+ //to show presence of upgrader.
+ Debug.Assert((_owners & WRITER_HELD) > 0);
+ _owners++;
+ _upgradeLockOwnerId = id;
+ lrwc.upgradecount++;
+ if (lrwc.readercount > 0)
+ _fUpgradeThreadHoldingRead = true;
+ ExitMyLock();
+ return true;
+ }
+ else if (lrwc.readercount > 0)
+ {
+ //Upgrade locks may not be acquired if only read locks have been
+ //acquired.
+ ExitMyLock();
+ throw new LockRecursionException(SR.LockRecursionException_UpgradeAfterReadNotAllowed);
+ }
+ }
+
+ bool retVal = true;
+
+ int spincount = 0;
+
+ for (; ;)
+ {
+ //Once an upgrade lock is taken, it's like having a reader lock held
+ //until upgrade or downgrade operations are performed.
+
+ if ((_upgradeLockOwnerId == -1) && (_owners < MAX_READER))
+ {
+ _owners++;
+ _upgradeLockOwnerId = id;
+ break;
+ }
+
+ if (spincount < MaxSpinCount)
+ {
+ ExitMyLock();
+ if (timeout.IsExpired)
+ return false;
+ spincount++;
+ SpinWait(spincount);
+ EnterMyLock();
+ continue;
+ }
+
+ // Drat, we need to wait. Mark that we have waiters and wait.
+ if (_upgradeEvent == null) // Create the needed event
+ {
+ LazyCreateEvent(ref _upgradeEvent, true);
+ continue; // since we left the lock, start over.
+ }
+
+ //Only one thread with the upgrade lock held can proceed.
+ retVal = WaitOnEvent(_upgradeEvent, ref _numUpgradeWaiters, timeout, isWriteWaiter: false);
+ if (!retVal)
+ return false;
+ }
+
+ if (_fIsReentrant)
+ {
+ //The lock may have been dropped getting here, so make a quick check to see whether some other
+ //thread did not grab the entry.
+ if (IsRwHashEntryChanged(lrwc))
+ lrwc = GetThreadRWCount(false);
+ lrwc.upgradecount++;
+ }
+
+ ExitMyLock();
+
+ return true;
+ }
+
+ public void ExitReadLock()
+ {
+ ReaderWriterCount lrwc = null;
+
+ EnterMyLock();
+
+ lrwc = GetThreadRWCount(true);
+
+ if (lrwc == null || lrwc.readercount < 1)
+ {
+ //You have to be holding the read lock to make this call.
+ ExitMyLock();
+ throw new SynchronizationLockException(SR.SynchronizationLockException_MisMatchedRead);
+ }
+
+ if (_fIsReentrant)
+ {
+ if (lrwc.readercount > 1)
+ {
+ lrwc.readercount--;
+ ExitMyLock();
+ return;
+ }
+
+ if (Environment.CurrentManagedThreadId == _upgradeLockOwnerId)
+ {
+ _fUpgradeThreadHoldingRead = false;
+ }
+ }
+
+ Debug.Assert(_owners > 0, "ReleasingReaderLock: releasing lock and no read lock taken");
+
+ --_owners;
+
+ Debug.Assert(lrwc.readercount == 1);
+ lrwc.readercount--;
+
+ ExitAndWakeUpAppropriateWaiters();
+ }
+
+ public void ExitWriteLock()
+ {
+ ReaderWriterCount lrwc;
+ if (!_fIsReentrant)
+ {
+ if (Environment.CurrentManagedThreadId != _writeLockOwnerId)
+ {
+ //You have to be holding the write lock to make this call.
+ throw new SynchronizationLockException(SR.SynchronizationLockException_MisMatchedWrite);
+ }
+ EnterMyLock();
+ }
+ else
+ {
+ EnterMyLock();
+ lrwc = GetThreadRWCount(false);
+
+ if (lrwc == null)
+ {
+ ExitMyLock();
+ throw new SynchronizationLockException(SR.SynchronizationLockException_MisMatchedWrite);
+ }
+
+ if (lrwc.writercount < 1)
+ {
+ ExitMyLock();
+ throw new SynchronizationLockException(SR.SynchronizationLockException_MisMatchedWrite);
+ }
+
+ lrwc.writercount--;
+
+ if (lrwc.writercount > 0)
+ {
+ ExitMyLock();
+ return;
+ }
+ }
+
+ Debug.Assert((_owners & WRITER_HELD) > 0, "Calling ReleaseWriterLock when no write lock is held");
+
+ ClearWriterAcquired();
+
+ _writeLockOwnerId = -1;
+
+ ExitAndWakeUpAppropriateWaiters();
+ }
+
+ public void ExitUpgradeableReadLock()
+ {
+ ReaderWriterCount lrwc;
+ if (!_fIsReentrant)
+ {
+ if (Environment.CurrentManagedThreadId != _upgradeLockOwnerId)
+ {
+ //You have to be holding the upgrade lock to make this call.
+ throw new SynchronizationLockException(SR.SynchronizationLockException_MisMatchedUpgrade);
+ }
+ EnterMyLock();
+ }
+ else
+ {
+ EnterMyLock();
+ lrwc = GetThreadRWCount(true);
+
+ if (lrwc == null)
+ {
+ ExitMyLock();
+ throw new SynchronizationLockException(SR.SynchronizationLockException_MisMatchedUpgrade);
+ }
+
+ if (lrwc.upgradecount < 1)
+ {
+ ExitMyLock();
+ throw new SynchronizationLockException(SR.SynchronizationLockException_MisMatchedUpgrade);
+ }
+
+ lrwc.upgradecount--;
+
+ if (lrwc.upgradecount > 0)
+ {
+ ExitMyLock();
+ return;
+ }
+
+ _fUpgradeThreadHoldingRead = false;
+ }
+
+ _owners--;
+ _upgradeLockOwnerId = -1;
+
+ ExitAndWakeUpAppropriateWaiters();
+ }
+
+ /// <summary>
+ /// A routine for lazily creating a event outside the lock (so if errors
+ /// happen they are outside the lock and that we don't do much work
+ /// while holding a spin lock). If all goes well, reenter the lock and
+ /// set 'waitEvent'
+ /// </summary>
+ private void LazyCreateEvent(ref EventWaitHandle waitEvent, bool makeAutoResetEvent)
+ {
+#if DEBUG
+ Debug.Assert(MyLockHeld);
+ Debug.Assert(waitEvent == null);
+#endif
+ ExitMyLock();
+ EventWaitHandle newEvent;
+ if (makeAutoResetEvent)
+ newEvent = new AutoResetEvent(false);
+ else
+ newEvent = new ManualResetEvent(false);
+ EnterMyLock();
+ if (waitEvent == null) // maybe someone snuck in.
+ waitEvent = newEvent;
+ else
+ newEvent.Dispose();
+ }
+
+ /// <summary>
+ /// Waits on 'waitEvent' with a timeout
+ /// Before the wait 'numWaiters' is incremented and is restored before leaving this routine.
+ /// </summary>
+ private bool WaitOnEvent(
+ EventWaitHandle waitEvent,
+ ref uint numWaiters,
+ TimeoutTracker timeout,
+ bool isWriteWaiter)
+ {
+#if DEBUG
+ Debug.Assert(MyLockHeld);
+#endif
+ waitEvent.Reset();
+ numWaiters++;
+ _fNoWaiters = false;
+
+ //Setting these bits will prevent new readers from getting in.
+ if (_numWriteWaiters == 1)
+ SetWritersWaiting();
+ if (_numWriteUpgradeWaiters == 1)
+ SetUpgraderWaiting();
+
+ bool waitSuccessful = false;
+ ExitMyLock(); // Do the wait outside of any lock
+
+ try
+ {
+ waitSuccessful = waitEvent.WaitOne(timeout.RemainingMilliseconds);
+ }
+ finally
+ {
+ EnterMyLock();
+ --numWaiters;
+
+ if (_numWriteWaiters == 0 && _numWriteUpgradeWaiters == 0 && _numUpgradeWaiters == 0 && _numReadWaiters == 0)
+ _fNoWaiters = true;
+
+ if (_numWriteWaiters == 0)
+ ClearWritersWaiting();
+ if (_numWriteUpgradeWaiters == 0)
+ ClearUpgraderWaiting();
+
+ if (!waitSuccessful) // We may also be about to throw for some reason. Exit myLock.
+ {
+ if (isWriteWaiter)
+ {
+ // Write waiters block read waiters from acquiring the lock. Since this was the last write waiter, try
+ // to wake up the appropriate read waiters.
+ ExitAndWakeUpAppropriateReadWaiters();
+ }
+ else
+ ExitMyLock();
+ }
+ }
+ return waitSuccessful;
+ }
+
+ /// <summary>
+ /// Determines the appropriate events to set, leaves the locks, and sets the events.
+ /// </summary>
+ private void ExitAndWakeUpAppropriateWaiters()
+ {
+#if DEBUG
+ Debug.Assert(MyLockHeld);
+#endif
+ if (_fNoWaiters)
+ {
+ ExitMyLock();
+ return;
+ }
+
+ ExitAndWakeUpAppropriateWaitersPreferringWriters();
+ }
+
+ private void ExitAndWakeUpAppropriateWaitersPreferringWriters()
+ {
+ uint readercount = GetNumReaders();
+
+ //We need this case for EU->ER->EW case, as the read count will be 2 in
+ //that scenario.
+ if (_fIsReentrant)
+ {
+ if (_numWriteUpgradeWaiters > 0 && _fUpgradeThreadHoldingRead && readercount == 2)
+ {
+ ExitMyLock(); // Exit before signaling to improve efficiency (wakee will need the lock)
+ _waitUpgradeEvent.Set(); // release all upgraders (however there can be at most one).
+ return;
+ }
+ }
+
+ if (readercount == 1 && _numWriteUpgradeWaiters > 0)
+ {
+ //We have to be careful now, as we are dropping the lock.
+ //No new writes should be allowed to sneak in if an upgrade
+ //was pending.
+
+ ExitMyLock(); // Exit before signaling to improve efficiency (wakee will need the lock)
+ _waitUpgradeEvent.Set(); // release all upgraders (however there can be at most one).
+ }
+ else if (readercount == 0 && _numWriteWaiters > 0)
+ {
+ ExitMyLock(); // Exit before signaling to improve efficiency (wakee will need the lock)
+ _writeEvent.Set(); // release one writer.
+ }
+ else
+ {
+ ExitAndWakeUpAppropriateReadWaiters();
+ }
+ }
+
+ private void ExitAndWakeUpAppropriateReadWaiters()
+ {
+#if DEBUG
+ Debug.Assert(MyLockHeld);
+#endif
+
+ if (_numWriteWaiters != 0 || _numWriteUpgradeWaiters != 0 || _fNoWaiters)
+ {
+ ExitMyLock();
+ return;
+ }
+
+ Debug.Assert(_numReadWaiters != 0 || _numUpgradeWaiters != 0);
+
+ bool setReadEvent = _numReadWaiters != 0;
+ bool setUpgradeEvent = _numUpgradeWaiters != 0 && _upgradeLockOwnerId == -1;
+
+ ExitMyLock(); // Exit before signaling to improve efficiency (wakee will need the lock)
+
+ if (setReadEvent)
+ _readEvent.Set(); // release all readers.
+
+ if (setUpgradeEvent)
+ _upgradeEvent.Set(); //release one upgrader.
+ }
+
+ private bool IsWriterAcquired()
+ {
+ return (_owners & ~WAITING_WRITERS) == 0;
+ }
+
+ private void SetWriterAcquired()
+ {
+ _owners |= WRITER_HELD; // indicate we have a writer.
+ }
+
+ private void ClearWriterAcquired()
+ {
+ _owners &= ~WRITER_HELD;
+ }
+
+ private void SetWritersWaiting()
+ {
+ _owners |= WAITING_WRITERS;
+ }
+
+ private void ClearWritersWaiting()
+ {
+ _owners &= ~WAITING_WRITERS;
+ }
+
+ private void SetUpgraderWaiting()
+ {
+ _owners |= WAITING_UPGRADER;
+ }
+
+ private void ClearUpgraderWaiting()
+ {
+ _owners &= ~WAITING_UPGRADER;
+ }
+
+ private uint GetNumReaders()
+ {
+ return _owners & READER_MASK;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private void EnterMyLock()
+ {
+ if (Interlocked.CompareExchange(ref _myLock, 1, 0) != 0)
+ EnterMyLockSpin();
+ }
+
+ private void EnterMyLockSpin()
+ {
+ int pc = Environment.ProcessorCount;
+ for (int i = 0; ; i++)
+ {
+ if (i < LockSpinCount && pc > 1)
+ {
+ RuntimeThread.SpinWait(LockSpinCycles * (i + 1)); // Wait a few dozen instructions to let another processor release lock.
+ }
+ else if (i < (LockSpinCount + LockSleep0Count))
+ {
+ RuntimeThread.Sleep(0); // Give up my quantum.
+ }
+ else
+ {
+ RuntimeThread.Sleep(1); // Give up my quantum.
+ }
+
+ if (_myLock == 0 && Interlocked.CompareExchange(ref _myLock, 1, 0) == 0)
+ return;
+ }
+ }
+
+ private void ExitMyLock()
+ {
+ Debug.Assert(_myLock != 0, "Exiting spin lock that is not held");
+ Volatile.Write(ref _myLock, 0);
+ }
+
+#if DEBUG
+ private bool MyLockHeld { get { return _myLock != 0; } }
+#endif
+
+ private static void SpinWait(int SpinCount)
+ {
+ //Exponential back-off
+ if ((SpinCount < 5) && (Environment.ProcessorCount > 1))
+ {
+ RuntimeThread.SpinWait(LockSpinCycles * SpinCount);
+ }
+ else
+ {
+ RuntimeThread.Sleep(0);
+ }
+
+ // Don't want to Sleep(1) in this spin wait:
+ // - Don't want to spin for that long, since a proper wait will follow when the spin wait fails. The artifical
+ // delay introduced by Sleep(1) will in some cases be much longer than desired.
+ // - Sleep(1) would put the thread into a wait state, and a proper wait will follow when the spin wait fails
+ // anyway, so it's preferable to put the thread into the proper wait state
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ }
+
+ private void Dispose(bool disposing)
+ {
+ if (disposing && !_fDisposed)
+ {
+ if (WaitingReadCount > 0 || WaitingUpgradeCount > 0 || WaitingWriteCount > 0)
+ throw new SynchronizationLockException(SR.SynchronizationLockException_IncorrectDispose);
+
+ if (IsReadLockHeld || IsUpgradeableReadLockHeld || IsWriteLockHeld)
+ throw new SynchronizationLockException(SR.SynchronizationLockException_IncorrectDispose);
+
+ if (_writeEvent != null)
+ {
+ _writeEvent.Dispose();
+ _writeEvent = null;
+ }
+
+ if (_readEvent != null)
+ {
+ _readEvent.Dispose();
+ _readEvent = null;
+ }
+
+ if (_upgradeEvent != null)
+ {
+ _upgradeEvent.Dispose();
+ _upgradeEvent = null;
+ }
+
+ if (_waitUpgradeEvent != null)
+ {
+ _waitUpgradeEvent.Dispose();
+ _waitUpgradeEvent = null;
+ }
+
+ _fDisposed = true;
+ }
+ }
+
+ public bool IsReadLockHeld
+ {
+ get
+ {
+ if (RecursiveReadCount > 0)
+ return true;
+ else
+ return false;
+ }
+ }
+
+ public bool IsUpgradeableReadLockHeld
+ {
+ get
+ {
+ if (RecursiveUpgradeCount > 0)
+ return true;
+ else
+ return false;
+ }
+ }
+
+ public bool IsWriteLockHeld
+ {
+ get
+ {
+ if (RecursiveWriteCount > 0)
+ return true;
+ else
+ return false;
+ }
+ }
+
+ public LockRecursionPolicy RecursionPolicy
+ {
+ get
+ {
+ if (_fIsReentrant)
+ {
+ return LockRecursionPolicy.SupportsRecursion;
+ }
+ else
+ {
+ return LockRecursionPolicy.NoRecursion;
+ }
+ }
+ }
+
+ public int CurrentReadCount
+ {
+ get
+ {
+ int numreaders = (int)GetNumReaders();
+
+ if (_upgradeLockOwnerId != -1)
+ return numreaders - 1;
+ else
+ return numreaders;
+ }
+ }
+
+
+ public int RecursiveReadCount
+ {
+ get
+ {
+ int count = 0;
+ ReaderWriterCount lrwc = GetThreadRWCount(true);
+ if (lrwc != null)
+ count = lrwc.readercount;
+
+ return count;
+ }
+ }
+
+ public int RecursiveUpgradeCount
+ {
+ get
+ {
+ if (_fIsReentrant)
+ {
+ int count = 0;
+
+ ReaderWriterCount lrwc = GetThreadRWCount(true);
+ if (lrwc != null)
+ count = lrwc.upgradecount;
+
+ return count;
+ }
+ else
+ {
+ if (Environment.CurrentManagedThreadId == _upgradeLockOwnerId)
+ return 1;
+ else
+ return 0;
+ }
+ }
+ }
+
+ public int RecursiveWriteCount
+ {
+ get
+ {
+ if (_fIsReentrant)
+ {
+ int count = 0;
+
+ ReaderWriterCount lrwc = GetThreadRWCount(true);
+ if (lrwc != null)
+ count = lrwc.writercount;
+
+ return count;
+ }
+ else
+ {
+ if (Environment.CurrentManagedThreadId == _writeLockOwnerId)
+ return 1;
+ else
+ return 0;
+ }
+ }
+ }
+
+ public int WaitingReadCount
+ {
+ get
+ {
+ return (int)_numReadWaiters;
+ }
+ }
+
+ public int WaitingUpgradeCount
+ {
+ get
+ {
+ return (int)_numUpgradeWaiters;
+ }
+ }
+
+ public int WaitingWriteCount
+ {
+ get
+ {
+ return (int)_numWriteWaiters;
+ }
+ }
+ }
+}
diff --git a/src/mscorlib/src/System/Threading/Semaphore.cs b/src/mscorlib/src/System/Threading/Semaphore.cs
index 1eac4aaaeb..ae353cc3e3 100644
--- a/src/mscorlib/src/System/Threading/Semaphore.cs
+++ b/src/mscorlib/src/System/Threading/Semaphore.cs
@@ -20,17 +20,17 @@ namespace System.Threading
{
if (initialCount < 0)
{
- throw new ArgumentOutOfRangeException(nameof(initialCount), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
+ throw new ArgumentOutOfRangeException(nameof(initialCount), SR.ArgumentOutOfRange_NeedNonNegNum);
}
if (maximumCount < 1)
{
- throw new ArgumentOutOfRangeException(nameof(maximumCount), Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum"));
+ throw new ArgumentOutOfRangeException(nameof(maximumCount), SR.ArgumentOutOfRange_NeedPosNum);
}
if (initialCount > maximumCount)
{
- throw new ArgumentException(Environment.GetResourceString("Argument_SemaphoreInitialMaximum"));
+ throw new ArgumentException(SR.Argument_SemaphoreInitialMaximum);
}
SafeWaitHandle myHandle = CreateSemaphone(initialCount, maximumCount, name);
@@ -41,7 +41,7 @@ namespace System.Threading
if (null != name && 0 != name.Length && Win32Native.ERROR_INVALID_HANDLE == errorCode)
throw new WaitHandleCannotBeOpenedException(
- Environment.GetResourceString("Threading.WaitHandleCannotBeOpenedException_InvalidHandle", name));
+ SR.Format(SR.Threading_WaitHandleCannotBeOpenedException_InvalidHandle, name));
__Error.WinIOError();
}
@@ -52,17 +52,17 @@ namespace System.Threading
{
if (initialCount < 0)
{
- throw new ArgumentOutOfRangeException(nameof(initialCount), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
+ throw new ArgumentOutOfRangeException(nameof(initialCount), SR.ArgumentOutOfRange_NeedNonNegNum);
}
if (maximumCount < 1)
{
- throw new ArgumentOutOfRangeException(nameof(maximumCount), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
+ throw new ArgumentOutOfRangeException(nameof(maximumCount), SR.ArgumentOutOfRange_NeedNonNegNum);
}
if (initialCount > maximumCount)
{
- throw new ArgumentException(Environment.GetResourceString("Argument_SemaphoreInitialMaximum"));
+ throw new ArgumentException(SR.Argument_SemaphoreInitialMaximum);
}
SafeWaitHandle myHandle = CreateSemaphone(initialCount, maximumCount, name);
@@ -72,7 +72,7 @@ namespace System.Threading
{
if (null != name && 0 != name.Length && Win32Native.ERROR_INVALID_HANDLE == errorCode)
throw new WaitHandleCannotBeOpenedException(
- Environment.GetResourceString("Threading.WaitHandleCannotBeOpenedException_InvalidHandle", name));
+ SR.Format(SR.Threading_WaitHandleCannotBeOpenedException_InvalidHandle, name));
__Error.WinIOError();
}
createdNew = errorCode != Win32Native.ERROR_ALREADY_EXISTS;
@@ -89,10 +89,10 @@ namespace System.Threading
if (name != null)
{
#if PLATFORM_UNIX
- throw new PlatformNotSupportedException(Environment.GetResourceString("PlatformNotSupported_NamedSynchronizationPrimitives"));
+ throw new PlatformNotSupportedException(SR.PlatformNotSupported_NamedSynchronizationPrimitives);
#else
if (name.Length > Path.MaxPath)
- throw new ArgumentException(Environment.GetResourceString("Argument_WaitHandleNameTooLong", Path.MaxPath), nameof(name));
+ throw new ArgumentException(SR.Format(SR.Argument_WaitHandleNameTooLong, Path.MaxPath), nameof(name));
#endif
}
@@ -111,7 +111,7 @@ namespace System.Threading
case OpenExistingResult.NameNotFound:
throw new WaitHandleCannotBeOpenedException();
case OpenExistingResult.NameInvalid:
- throw new WaitHandleCannotBeOpenedException(Environment.GetResourceString("Threading.WaitHandleCannotBeOpenedException_InvalidHandle", name));
+ throw new WaitHandleCannotBeOpenedException(SR.Format(SR.Threading_WaitHandleCannotBeOpenedException_InvalidHandle, name));
case OpenExistingResult.PathNotFound:
throw new IOException(Win32Native.GetMessage(Win32Native.ERROR_PATH_NOT_FOUND));
default:
@@ -127,14 +127,14 @@ namespace System.Threading
private static OpenExistingResult OpenExistingWorker(string name, out Semaphore result)
{
#if PLATFORM_UNIX
- throw new PlatformNotSupportedException(Environment.GetResourceString("PlatformNotSupported_NamedSynchronizationPrimitives"));
+ throw new PlatformNotSupportedException(SR.PlatformNotSupported_NamedSynchronizationPrimitives);
#else
if (name == null)
- throw new ArgumentNullException(nameof(name), Environment.GetResourceString("ArgumentNull_WithParamName"));
+ throw new ArgumentNullException(nameof(name), SR.ArgumentNull_WithParamName);
if (name.Length == 0)
- throw new ArgumentException(Environment.GetResourceString("Argument_EmptyName"), nameof(name));
+ throw new ArgumentException(SR.Argument_EmptyName, nameof(name));
if (name.Length > Path.MaxPath)
- throw new ArgumentException(Environment.GetResourceString("Argument_WaitHandleNameTooLong", Path.MaxPath), nameof(name));
+ throw new ArgumentException(SR.Format(SR.Argument_WaitHandleNameTooLong, Path.MaxPath), nameof(name));
const int SYNCHRONIZE = 0x00100000;
const int SEMAPHORE_MODIFY_STATE = 0x00000002;
@@ -173,7 +173,7 @@ namespace System.Threading
{
if (releaseCount < 1)
{
- throw new ArgumentOutOfRangeException(nameof(releaseCount), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
+ throw new ArgumentOutOfRangeException(nameof(releaseCount), SR.ArgumentOutOfRange_NeedNonNegNum);
}
//If ReleaseSempahore returns false when the specified value would cause
diff --git a/src/mscorlib/src/System/Threading/SemaphoreFullException.cs b/src/mscorlib/src/System/Threading/SemaphoreFullException.cs
deleted file mode 100644
index 01c5040b7e..0000000000
--- a/src/mscorlib/src/System/Threading/SemaphoreFullException.cs
+++ /dev/null
@@ -1,27 +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.
-
-namespace System.Threading {
- using System;
- using System.Runtime.Serialization;
- using System.Runtime.InteropServices;
-
- [Serializable]
- [ComVisibleAttribute(false)]
- public class SemaphoreFullException : SystemException {
-
- public SemaphoreFullException() : base(Environment.GetResourceString("Threading_SemaphoreFullException")){
- }
-
- public SemaphoreFullException(String message) : base(message) {
- }
-
- public SemaphoreFullException(String message, Exception innerException) : base(message, innerException) {
- }
-
- protected SemaphoreFullException(SerializationInfo info, StreamingContext context) : base (info, context) {
- }
- }
-}
-
diff --git a/src/mscorlib/src/System/Threading/SemaphoreSlim.cs b/src/mscorlib/src/System/Threading/SemaphoreSlim.cs
index c3b43d9585..97bbae18cc 100644
--- a/src/mscorlib/src/System/Threading/SemaphoreSlim.cs
+++ b/src/mscorlib/src/System/Threading/SemaphoreSlim.cs
@@ -1,4 +1,4 @@
-// Licensed to the .NET Foundation under one or more agreements.
+// 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.
@@ -21,6 +21,7 @@ using System.Diagnostics.Contracts;
using System.Threading.Tasks;
// The class will be part of the current System.Threading namespace
+
namespace System.Threading
{
/// <summary>
@@ -84,7 +85,7 @@ namespace System.Threading
private sealed class TaskNode : Task<bool>, IThreadPoolWorkItem
{
internal TaskNode Prev, Next;
- internal TaskNode() : base() {}
+ internal TaskNode() : base() { }
void IThreadPoolWorkItem.ExecuteWorkItem()
{
@@ -177,13 +178,13 @@ namespace System.Threading
if (initialCount < 0 || initialCount > maxCount)
{
throw new ArgumentOutOfRangeException(
- nameof(initialCount), initialCount, GetResourceString("SemaphoreSlim_ctor_InitialCountWrong"));
+ nameof(initialCount), initialCount, SR.SemaphoreSlim_ctor_InitialCountWrong);
}
//validate input
if (maxCount <= 0)
{
- throw new ArgumentOutOfRangeException(nameof(maxCount), maxCount, GetResourceString("SemaphoreSlim_ctor_MaxCountWrong"));
+ throw new ArgumentOutOfRangeException(nameof(maxCount), maxCount, SR.SemaphoreSlim_ctor_MaxCountWrong);
}
m_maxCount = maxCount;
@@ -240,7 +241,7 @@ namespace System.Threading
if (totalMilliseconds < -1 || totalMilliseconds > Int32.MaxValue)
{
throw new System.ArgumentOutOfRangeException(
- nameof(timeout), timeout, GetResourceString("SemaphoreSlim_Wait_TimeoutWrong"));
+ nameof(timeout), timeout, SR.SemaphoreSlim_Wait_TimeoutWrong);
}
// Call wait with the timeout milliseconds
@@ -270,7 +271,7 @@ namespace System.Threading
if (totalMilliseconds < -1 || totalMilliseconds > Int32.MaxValue)
{
throw new System.ArgumentOutOfRangeException(
- nameof(timeout), timeout, GetResourceString("SemaphoreSlim_Wait_TimeoutWrong"));
+ nameof(timeout), timeout, SR.SemaphoreSlim_Wait_TimeoutWrong);
}
// Call wait with the timeout milliseconds
@@ -313,7 +314,7 @@ namespace System.Threading
if (millisecondsTimeout < -1)
{
throw new ArgumentOutOfRangeException(
- nameof(millisecondsTimeout), millisecondsTimeout, GetResourceString("SemaphoreSlim_Wait_TimeoutWrong"));
+ nameof(millisecondsTimeout), millisecondsTimeout, SR.SemaphoreSlim_Wait_TimeoutWrong);
}
cancellationToken.ThrowIfCancellationRequested();
@@ -370,7 +371,7 @@ namespace System.Threading
Debug.Assert(m_asyncTail != null, "tail should not be null if head isn't");
asyncWaitTask = WaitAsync(millisecondsTimeout, cancellationToken);
}
- // There are no async waiters, so we can proceed with normal synchronous waiting.
+ // There are no async waiters, so we can proceed with normal synchronous waiting.
else
{
// If the count > 0 we are good to move on.
@@ -399,7 +400,7 @@ namespace System.Threading
// defer to synchronous waiters in priority, which means that if it's possible an asynchronous
// waiter didn't get released because a synchronous waiter was present, we need to ensure
// that synchronous waiter succeeds so that they have a chance to release.
- Debug.Assert(!waitSuccessful || m_currentCount > 0,
+ Debug.Assert(!waitSuccessful || m_currentCount > 0,
"If the wait was successful, there should be count available.");
if (m_currentCount > 0)
{
@@ -574,7 +575,7 @@ namespace System.Threading
if (totalMilliseconds < -1 || totalMilliseconds > Int32.MaxValue)
{
throw new System.ArgumentOutOfRangeException(
- nameof(timeout), timeout, GetResourceString("SemaphoreSlim_Wait_TimeoutWrong"));
+ nameof(timeout), timeout, SR.SemaphoreSlim_Wait_TimeoutWrong);
}
// Call wait with the timeout milliseconds
@@ -607,7 +608,7 @@ namespace System.Threading
if (millisecondsTimeout < -1)
{
throw new ArgumentOutOfRangeException(
- nameof(millisecondsTimeout), millisecondsTimeout, GetResourceString("SemaphoreSlim_Wait_TimeoutWrong"));
+ nameof(millisecondsTimeout), millisecondsTimeout, SR.SemaphoreSlim_Wait_TimeoutWrong);
}
// Bail early for cancellation
@@ -628,9 +629,9 @@ namespace System.Threading
// No counts, if timeout is zero fail fast
return s_falseTask;
}
- // If there aren't, create and return a task to the caller.
- // The task will be completed either when they've successfully acquired
- // the semaphore or when the timeout expired or cancellation was requested.
+ // If there aren't, create and return a task to the caller.
+ // The task will be completed either when they've successfully acquired
+ // the semaphore or when the timeout expired or cancellation was requested.
else
{
Debug.Assert(m_currentCount == 0, "m_currentCount should never be negative");
@@ -771,7 +772,7 @@ namespace System.Threading
if (releaseCount < 1)
{
throw new ArgumentOutOfRangeException(
- nameof(releaseCount), releaseCount, GetResourceString("SemaphoreSlim_Release_CountWrong"));
+ nameof(releaseCount), releaseCount, SR.SemaphoreSlim_Release_CountWrong);
}
int returnCount;
@@ -882,7 +883,7 @@ namespace System.Threading
}
-
+
/// <summary>
/// Private helper method to wake up waiters when a cancellationToken gets canceled.
/// </summary>
@@ -905,7 +906,7 @@ namespace System.Threading
{
if (m_lockObj == null)
{
- throw new ObjectDisposedException(null, GetResourceString("SemaphoreSlim_Disposed"));
+ throw new ObjectDisposedException(null, SR.SemaphoreSlim_Disposed);
}
}
@@ -915,7 +916,7 @@ namespace System.Threading
/// <param name="str">The key string</param>
private static string GetResourceString(string str)
{
- return Environment.GetResourceString(str);
+ return SR.GetResourceString(str);
}
#endregion
}
diff --git a/src/mscorlib/src/System/Threading/SendOrPostCallback.cs b/src/mscorlib/src/System/Threading/SendOrPostCallback.cs
deleted file mode 100644
index b81d2bff64..0000000000
--- a/src/mscorlib/src/System/Threading/SendOrPostCallback.cs
+++ /dev/null
@@ -1,16 +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: Represents a method to be called when a message is to be dispatched to a synchronization context.
-**
-**
-===========================================================*/
-
-namespace System.Threading
-{
- public delegate void SendOrPostCallback(Object state);
-}
diff --git a/src/mscorlib/src/System/Threading/SpinWait.cs b/src/mscorlib/src/System/Threading/SpinWait.cs
index 8431f6564f..30d7aa679c 100644
--- a/src/mscorlib/src/System/Threading/SpinWait.cs
+++ b/src/mscorlib/src/System/Threading/SpinWait.cs
@@ -51,7 +51,7 @@ namespace System.Threading
/// <remarks>
/// <para>
/// <see cref="SpinWait"/> encapsulates common spinning logic. On single-processor machines, yields are
- /// always used instead of busy waits, and on computers with Intel™ processors employing Hyper-Threading™
+ /// always used instead of busy waits, and on computers with Intel processors employing Hyper-Threading
/// technology, it helps to prevent hardware thread starvation. SpinWait encapsulates a good mixture of
/// spinning and true yielding.
/// </para>
@@ -71,7 +71,6 @@ namespace System.Threading
/// </remarks>
public struct SpinWait
{
-
// These constants determine the frequency of yields versus spinning. The
// numbers may seem fairly arbitrary, but were derived with at least some
// thought in the design document. I fully expect they will need to change
@@ -188,7 +187,7 @@ namespace System.Threading
public static void SpinUntil(Func<bool> condition)
{
#if DEBUG
- bool result =
+ bool result =
#endif
SpinUntil(condition, Timeout.Infinite);
#if DEBUG
@@ -215,7 +214,7 @@ namespace System.Threading
if (totalMilliseconds < -1 || totalMilliseconds > Int32.MaxValue)
{
throw new System.ArgumentOutOfRangeException(
- nameof(timeout), timeout, Environment.GetResourceString("SpinWait_SpinUntil_TimeoutWrong"));
+ nameof(timeout), timeout, SR.SpinWait_SpinUntil_TimeoutWrong);
}
// Call wait with the timeout milliseconds
@@ -237,11 +236,11 @@ namespace System.Threading
if (millisecondsTimeout < Timeout.Infinite)
{
throw new ArgumentOutOfRangeException(
- nameof(millisecondsTimeout), millisecondsTimeout, Environment.GetResourceString("SpinWait_SpinUntil_TimeoutWrong"));
+ nameof(millisecondsTimeout), millisecondsTimeout, SR.SpinWait_SpinUntil_TimeoutWrong);
}
if (condition == null)
{
- throw new ArgumentNullException(nameof(condition), Environment.GetResourceString("SpinWait_SpinUntil_ArgumentNull"));
+ throw new ArgumentNullException(nameof(condition), SR.SpinWait_SpinUntil_ArgumentNull);
}
uint startTime = 0;
if (millisecondsTimeout != 0 && millisecondsTimeout != Timeout.Infinite)
@@ -267,7 +266,6 @@ namespace System.Threading
}
}
return true;
-
}
#endregion
@@ -314,51 +312,4 @@ namespace System.Threading
get { return ProcessorCount == 1; }
}
}
-
- /// <summary>
- /// A helper class to capture a start time using Environment.TickCout as a time in milliseconds, also updates a given timeout bu subtracting the current time from
- /// the start time
- /// </summary>
- internal static class TimeoutHelper
- {
- /// <summary>
- /// Returns the Environment.TickCount as a start time in milliseconds as a uint, TickCount tools over from postive to negative every ~ 25 days
- /// then ~25 days to back to positive again, uint is sued to ignore the sign and double the range to 50 days
- /// </summary>
- /// <returns></returns>
- public static uint GetTime()
- {
- return (uint)Environment.TickCount;
- }
-
- /// <summary>
- /// Helper function to measure and update the elapsed time
- /// </summary>
- /// <param name="startTime"> The first time (in milliseconds) observed when the wait started</param>
- /// <param name="originalWaitMillisecondsTimeout">The orginal wait timeoutout in milliseconds</param>
- /// <returns>The new wait time in milliseconds, -1 if the time expired</returns>
- public static int UpdateTimeOut(uint startTime, int originalWaitMillisecondsTimeout)
- {
- // The function must be called in case the time out is not infinite
- Debug.Assert(originalWaitMillisecondsTimeout != Timeout.Infinite);
-
- uint elapsedMilliseconds = (GetTime() - startTime);
-
- // Check the elapsed milliseconds is greater than max int because this property is uint
- if (elapsedMilliseconds > int.MaxValue)
- {
- return 0;
- }
-
- // Subtract the elapsed time from the current wait time
- int currentWaitTimeout = originalWaitMillisecondsTimeout - (int)elapsedMilliseconds; ;
- if (currentWaitTimeout <= 0)
- {
- return 0;
- }
-
- return currentWaitTimeout;
- }
- }
-
}
diff --git a/src/mscorlib/src/System/Threading/SynchronizationContext.cs b/src/mscorlib/src/System/Threading/SynchronizationContext.cs
index f4b3c79409..676a198ee7 100644
--- a/src/mscorlib/src/System/Threading/SynchronizationContext.cs
+++ b/src/mscorlib/src/System/Threading/SynchronizationContext.cs
@@ -11,7 +11,7 @@
===========================================================*/
namespace System.Threading
-{
+{
using Microsoft.Win32.SafeHandles;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
@@ -27,7 +27,7 @@ namespace System.Threading
[Flags]
- enum SynchronizationContextProperties
+ internal enum SynchronizationContextProperties
{
None = 0,
RequireWaitNotification = 0x1
@@ -41,27 +41,27 @@ namespace System.Threading
[FriendAccessAllowed]
internal class WinRTSynchronizationContextFactoryBase
{
- public virtual SynchronizationContext Create(object coreDispatcher) {return null;}
+ public virtual SynchronizationContext Create(object coreDispatcher) { return null; }
}
#endif //FEATURE_COMINTEROP
public class SynchronizationContext
{
- SynchronizationContextProperties _props = SynchronizationContextProperties.None;
-
+ private SynchronizationContextProperties _props = SynchronizationContextProperties.None;
+
public SynchronizationContext()
{
}
-
+
// helper delegate to statically bind to Wait method
private delegate int WaitDelegate(IntPtr[] waitHandles, bool waitAll, int millisecondsTimeout);
- static Type s_cachedPreparedType1;
- static Type s_cachedPreparedType2;
- static Type s_cachedPreparedType3;
- static Type s_cachedPreparedType4;
- static Type s_cachedPreparedType5;
+ private static Type s_cachedPreparedType1;
+ private static Type s_cachedPreparedType2;
+ private static Type s_cachedPreparedType3;
+ private static Type s_cachedPreparedType4;
+ private static Type s_cachedPreparedType5;
// protected so that only the derived sync context class can enable these flags
[SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "We never dereference s_cachedPreparedType*, so ordering is unimportant")]
@@ -87,11 +87,11 @@ namespace System.Threading
{
RuntimeHelpers.PrepareDelegate(new WaitDelegate(this.Wait));
- if (s_cachedPreparedType1 == null) s_cachedPreparedType1 = type;
- else if (s_cachedPreparedType2 == null) s_cachedPreparedType2 = type;
- else if (s_cachedPreparedType3 == null) s_cachedPreparedType3 = type;
- else if (s_cachedPreparedType4 == null) s_cachedPreparedType4 = type;
- else if (s_cachedPreparedType5 == null) s_cachedPreparedType5 = type;
+ if (s_cachedPreparedType1 == null) s_cachedPreparedType1 = type;
+ else if (s_cachedPreparedType2 == null) s_cachedPreparedType2 = type;
+ else if (s_cachedPreparedType3 == null) s_cachedPreparedType3 = type;
+ else if (s_cachedPreparedType4 == null) s_cachedPreparedType4 = type;
+ else if (s_cachedPreparedType5 == null) s_cachedPreparedType5 = type;
}
_props |= SynchronizationContextProperties.RequireWaitNotification;
@@ -99,10 +99,10 @@ namespace System.Threading
public bool IsWaitNotificationRequired()
{
- return ((_props & SynchronizationContextProperties.RequireWaitNotification) != 0);
+ return ((_props & SynchronizationContextProperties.RequireWaitNotification) != 0);
}
-
+
public virtual void Send(SendOrPostCallback d, Object state)
{
d(state);
@@ -113,7 +113,7 @@ namespace System.Threading
ThreadPool.QueueUserWorkItem(new WaitCallback(d), state);
}
-
+
/// <summary>
/// Optional override for subclasses, for responding to notification that operation is starting.
/// </summary>
@@ -159,9 +159,9 @@ namespace System.Threading
Thread.CurrentThread.SynchronizationContext = syncContext;
}
- public static SynchronizationContext Current
+ public static SynchronizationContext Current
{
- get
+ get
{
SynchronizationContext context = Thread.CurrentThread.SynchronizationContext;
@@ -189,7 +189,7 @@ namespace System.Threading
{
Debug.Assert(Environment.IsWinRTSupported);
Debug.Assert(AppDomain.IsAppXModel());
-
+
//
// We call into the VM to get the dispatcher. This is because:
//
@@ -207,7 +207,7 @@ namespace System.Threading
return null;
}
- static WinRTSynchronizationContextFactoryBase s_winRTContextFactory;
+ private static WinRTSynchronizationContextFactoryBase s_winRTContextFactory;
private static WinRTSynchronizationContextFactoryBase GetWinRTSynchronizationContextFactory()
{
diff --git a/src/mscorlib/src/System/Threading/SynchronizationLockException.cs b/src/mscorlib/src/System/Threading/SynchronizationLockException.cs
deleted file mode 100644
index de42c1f232..0000000000
--- a/src/mscorlib/src/System/Threading/SynchronizationLockException.cs
+++ /dev/null
@@ -1,43 +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: Wait(), Notify() or NotifyAll() was called from an unsynchronized
-** block of code.
-**
-**
-=============================================================================*/
-
-namespace System.Threading {
-
- using System;
- using System.Runtime.Serialization;
- [Serializable]
- public class SynchronizationLockException : SystemException {
- public SynchronizationLockException()
- : base(Environment.GetResourceString("Arg_SynchronizationLockException")) {
- SetErrorCode(__HResults.COR_E_SYNCHRONIZATIONLOCK);
- }
-
- public SynchronizationLockException(String message)
- : base(message) {
- SetErrorCode(__HResults.COR_E_SYNCHRONIZATIONLOCK);
- }
-
- public SynchronizationLockException(String message, Exception innerException)
- : base(message, innerException) {
- SetErrorCode(__HResults.COR_E_SYNCHRONIZATIONLOCK);
- }
-
- protected SynchronizationLockException(SerializationInfo info, StreamingContext context) : base (info, context) {
- }
- }
-
-}
-
-
diff --git a/src/mscorlib/src/System/Threading/Tasks/AsyncCausalityTracer.cs b/src/mscorlib/src/System/Threading/Tasks/AsyncCausalityTracer.cs
index ec7c5aaeea..ec154f9efb 100644
--- a/src/mscorlib/src/System/Threading/Tasks/AsyncCausalityTracer.cs
+++ b/src/mscorlib/src/System/Threading/Tasks/AsyncCausalityTracer.cs
@@ -21,7 +21,6 @@ using WFD = Windows.Foundation.Diagnostics;
namespace System.Threading.Tasks
{
-
[FriendAccessAllowed]
internal enum CausalityTraceLevel
{
@@ -85,13 +84,13 @@ namespace System.Threading.Tasks
[FriendAccessAllowed]
internal static class AsyncCausalityTracer
{
- static internal void EnableToETW(bool enabled)
+ static internal void EnableToETW(bool enabled)
{
#if FEATURE_COMINTEROP
if (enabled)
- f_LoggingOn |= Loggers.ETW;
- else
- f_LoggingOn &= ~Loggers.ETW;
+ f_LoggingOn |= Loggers.ETW;
+ else
+ f_LoggingOn &= ~Loggers.ETW;
#endif
}
@@ -121,7 +120,8 @@ namespace System.Threading.Tasks
// The loggers that this Tracer knows about.
[Flags]
- private enum Loggers : byte {
+ private enum Loggers : byte
+ {
CausalityTracer = 1,
ETW = 2
}
@@ -148,7 +148,7 @@ namespace System.Threading.Tasks
int hresult = Microsoft.Win32.UnsafeNativeMethods.RoGetActivationFactory(ClassId, ref guid, out factory);
if (hresult < 0 || factory == null) return; //This prevents having an exception thrown in case IAsyncCausalityTracerStatics isn't registered.
-
+
s_TracerFactory = (WFD.IAsyncCausalityTracerStatics)factory;
EventRegistrationToken token = s_TracerFactory.add_TracingStatusChanged(new EventHandler<WFD.TracingStatusChangedEventArgs>(TracingStatusChangedHandler));
@@ -161,15 +161,14 @@ namespace System.Threading.Tasks
// doing here depends on internal state.
LogAndDisable(ex);
}
-
}
private static void TracingStatusChangedHandler(Object sender, WFD.TracingStatusChangedEventArgs args)
{
if (args.Enabled)
- f_LoggingOn |= Loggers.CausalityTracer;
- else
- f_LoggingOn &= ~Loggers.CausalityTracer;
+ f_LoggingOn |= Loggers.CausalityTracer;
+ else
+ f_LoggingOn &= ~Loggers.CausalityTracer;
}
#endif
@@ -185,11 +184,11 @@ namespace System.Threading.Tasks
try
{
if ((f_LoggingOn & Loggers.ETW) != 0)
- TplEtwProvider.Log.TraceOperationBegin(taskId, operationName, (long) relatedContext);
+ TplEtwProvider.Log.TraceOperationBegin(taskId, operationName, (long)relatedContext);
if ((f_LoggingOn & Loggers.CausalityTracer) != 0)
s_TracerFactory.TraceOperationCreation((WFD.CausalityTraceLevel)traceLevel, s_CausalitySource, s_PlatformId, GetOperationId((uint)taskId), operationName, relatedContext);
}
- catch(Exception ex)
+ catch (Exception ex)
{
//view function comment
LogAndDisable(ex);
@@ -209,7 +208,7 @@ namespace System.Threading.Tasks
if ((f_LoggingOn & Loggers.CausalityTracer) != 0)
s_TracerFactory.TraceOperationCompletion((WFD.CausalityTraceLevel)traceLevel, s_CausalitySource, s_PlatformId, GetOperationId((uint)taskId), (WFD.AsyncCausalityStatus)status);
}
- catch(Exception ex)
+ catch (Exception ex)
{
//view function comment
LogAndDisable(ex);
@@ -228,7 +227,7 @@ namespace System.Threading.Tasks
if ((f_LoggingOn & Loggers.CausalityTracer) != 0)
s_TracerFactory.TraceOperationRelation((WFD.CausalityTraceLevel)traceLevel, s_CausalitySource, s_PlatformId, GetOperationId((uint)taskId), (WFD.CausalityRelation)relation);
}
- catch(Exception ex)
+ catch (Exception ex)
{
//view function comment
LogAndDisable(ex);
@@ -247,7 +246,7 @@ namespace System.Threading.Tasks
if ((f_LoggingOn & Loggers.CausalityTracer) != 0)
s_TracerFactory.TraceSynchronousWorkStart((WFD.CausalityTraceLevel)traceLevel, s_CausalitySource, s_PlatformId, GetOperationId((uint)taskId), (WFD.CausalitySynchronousWork)work);
}
- catch(Exception ex)
+ catch (Exception ex)
{
//view function comment
LogAndDisable(ex);
@@ -266,7 +265,7 @@ namespace System.Threading.Tasks
if ((f_LoggingOn & Loggers.CausalityTracer) != 0)
s_TracerFactory.TraceSynchronousWorkCompletion((WFD.CausalityTraceLevel)traceLevel, s_CausalitySource, (WFD.CausalitySynchronousWork)work);
}
- catch(Exception ex)
+ catch (Exception ex)
{
//view function comment
LogAndDisable(ex);
@@ -288,6 +287,5 @@ namespace System.Threading.Tasks
{
return (((ulong)AppDomain.CurrentDomain.Id) << 32) + taskId;
}
-
}
}
diff --git a/src/mscorlib/src/System/Threading/Tasks/ConcurrentExclusiveSchedulerPair.cs b/src/mscorlib/src/System/Threading/Tasks/ConcurrentExclusiveSchedulerPair.cs
index a87406a493..07a673bf4e 100644
--- a/src/mscorlib/src/System/Threading/Tasks/ConcurrentExclusiveSchedulerPair.cs
+++ b/src/mscorlib/src/System/Threading/Tasks/ConcurrentExclusiveSchedulerPair.cs
@@ -72,22 +72,25 @@ namespace System.Threading.Tasks
/// Initializes the ConcurrentExclusiveSchedulerPair.
/// </summary>
public ConcurrentExclusiveSchedulerPair() :
- this(TaskScheduler.Default, DefaultMaxConcurrencyLevel, DEFAULT_MAXITEMSPERTASK) { }
+ this(TaskScheduler.Default, DefaultMaxConcurrencyLevel, DEFAULT_MAXITEMSPERTASK)
+ { }
/// <summary>
/// Initializes the ConcurrentExclusiveSchedulerPair to target the specified scheduler.
/// </summary>
/// <param name="taskScheduler">The target scheduler on which this pair should execute.</param>
public ConcurrentExclusiveSchedulerPair(TaskScheduler taskScheduler) :
- this(taskScheduler, DefaultMaxConcurrencyLevel, DEFAULT_MAXITEMSPERTASK) { }
+ this(taskScheduler, DefaultMaxConcurrencyLevel, DEFAULT_MAXITEMSPERTASK)
+ { }
/// <summary>
/// Initializes the ConcurrentExclusiveSchedulerPair to target the specified scheduler with a maximum concurrency level.
/// </summary>
/// <param name="taskScheduler">The target scheduler on which this pair should execute.</param>
/// <param name="maxConcurrencyLevel">The maximum number of tasks to run concurrently.</param>
- public ConcurrentExclusiveSchedulerPair(TaskScheduler taskScheduler, int maxConcurrencyLevel) :
- this(taskScheduler, maxConcurrencyLevel, DEFAULT_MAXITEMSPERTASK) { }
+ public ConcurrentExclusiveSchedulerPair(TaskScheduler taskScheduler, int maxConcurrencyLevel) :
+ this(taskScheduler, maxConcurrencyLevel, DEFAULT_MAXITEMSPERTASK)
+ { }
/// <summary>
/// Initializes the ConcurrentExclusiveSchedulerPair to target the specified scheduler with a maximum
@@ -141,7 +144,7 @@ namespace System.Threading.Tasks
}
/// <summary>Gets a <see cref="System.Threading.Tasks.Task"/> that will complete when the scheduler has completed processing.</summary>
- public Task Completion
+ public Task Completion
{
// ValueLock not needed, but it's ok if it's held
get { return EnsureCompletionStateInitialized().Task; }
@@ -162,7 +165,7 @@ namespace System.Threading.Tasks
}
/// <summary>Sets that completion has been requested.</summary>
- private void RequestCompletion()
+ private void RequestCompletion()
{
ContractAssertMonitorStatus(ValueLock, held: true);
EnsureCompletionStateInitialized().m_completionRequested = true;
@@ -190,9 +193,9 @@ namespace System.Threading.Tasks
// Now, only allow shutdown if an exception occurred or if there are no more tasks to process.
var cs = EnsureCompletionStateInitialized();
- return
+ return
(cs.m_exceptions != null && cs.m_exceptions.Count > 0) ||
- (m_concurrentTaskScheduler.m_tasks.IsEmpty && m_exclusiveTaskScheduler.m_tasks.IsEmpty);
+ (m_concurrentTaskScheduler.m_tasks.IsEmpty && m_exclusiveTaskScheduler.m_tasks.IsEmpty);
}
}
@@ -330,7 +333,7 @@ namespace System.Threading.Tasks
}
}
}
-
+
// Check to see if all tasks have completed and if completion has been requested.
CleanupStateIfCompletingAndQuiesced();
}
@@ -370,7 +373,7 @@ namespace System.Threading.Tasks
// We're no longer processing exclusive tasks on the current thread
ProcessingMode currentMode;
m_threadProcessingMapping.TryRemove(Thread.CurrentThread.ManagedThreadId, out currentMode);
- Debug.Assert(currentMode == ProcessingMode.ProcessingExclusiveTask,
+ Debug.Assert(currentMode == ProcessingMode.ProcessingExclusiveTask,
"Somehow we ended up escaping exclusive mode.");
lock (ValueLock)
@@ -720,7 +723,7 @@ namespace System.Threading.Tasks
return mode;
}
}
-
+
/// <summary>Asserts that a given synchronization object is either held or not held.</summary>
/// <param name="syncObj">The monitor to check.</param>
/// <param name="held">Whether we want to assert that it's currently held or not held.</param>
@@ -748,7 +751,7 @@ namespace System.Threading.Tasks
Debug.Assert(Monitor.IsEntered(syncObj) == held, "The locking scheme was not correctly followed.");
#endif
}
-
+
/// <summary>Gets the options to use for tasks.</summary>
/// <param name="isReplacementReplica">If this task is being created to replace another.</param>
/// <remarks>
@@ -758,7 +761,7 @@ namespace System.Threading.Tasks
/// <returns>The options to use.</returns>
internal static TaskCreationOptions GetCreationOptionsForTask(bool isReplacementReplica = false)
{
- TaskCreationOptions options =
+ TaskCreationOptions options =
#if PRENET45
TaskCreationOptions.None;
#else
@@ -784,5 +787,4 @@ namespace System.Threading.Tasks
Completed = 0x8
}
}
-
}
diff --git a/src/mscorlib/src/System/Threading/Tasks/FutureFactory.cs b/src/mscorlib/src/System/Threading/Tasks/FutureFactory.cs
index 137afa11f5..60a7c81dcf 100644
--- a/src/mscorlib/src/System/Threading/Tasks/FutureFactory.cs
+++ b/src/mscorlib/src/System/Threading/Tasks/FutureFactory.cs
@@ -568,8 +568,6 @@ namespace System.Threading.Tasks
promise.DangerousSetResult(result);
}
}
-
-
}
}
@@ -691,7 +689,7 @@ namespace System.Threading.Tasks
// RespectParentCancellation.
Task t = new Task(new Action<object>(delegate
{
- FromAsyncCoreLogic(asyncResult, endFunction, endAction, promise, requiresSynchronization:true);
+ FromAsyncCoreLogic(asyncResult, endFunction, endAction, promise, requiresSynchronization: true);
}),
(object)null, null,
default(CancellationToken), TaskCreationOptions.None, InternalTaskOptions.None, null);
@@ -706,7 +704,7 @@ namespace System.Threading.Tasks
if (asyncResult.IsCompleted)
{
- try { t.InternalRunSynchronously(scheduler, waitForCompletion:false); }
+ try { t.InternalRunSynchronously(scheduler, waitForCompletion: false); }
catch (Exception e) { promise.TrySetException(e); } // catch and log any scheduler exceptions
}
else
@@ -792,7 +790,7 @@ namespace System.Threading.Tasks
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.endMethod);
Contract.Requires((endFunction != null) != (endAction != null), "Both endFunction and endAction were non-null");
-
+
TaskFactory.CheckFromAsyncOptions(creationOptions, true);
Task<TResult> promise = new Task<TResult>(state, creationOptions);
@@ -943,7 +941,6 @@ namespace System.Threading.Tasks
}
catch
{
-
if (AsyncCausalityTracer.LoggingOn)
AsyncCausalityTracer.TraceOperationCompletion(CausalityTraceLevel.Required, promise.Id, AsyncCausalityStatus.Error);
@@ -1241,7 +1238,7 @@ namespace System.Threading.Tasks
internal static Task<TResult> FromAsyncTrim<TInstance, TArgs>(
TInstance thisRef, TArgs args,
Func<TInstance, TArgs, AsyncCallback, object, IAsyncResult> beginMethod,
- Func<TInstance, IAsyncResult, TResult> endMethod)
+ Func<TInstance, IAsyncResult, TResult> endMethod)
where TInstance : class
{
// Validate arguments, but only with asserts, as this is an internal only implementation.
@@ -1319,7 +1316,7 @@ namespace System.Threading.Tasks
// we'll instead complete the promise at the call site.
if (!asyncResult.CompletedSynchronously)
{
- promise.Complete(thisRef, endMethod, asyncResult, requiresSynchronization:true);
+ promise.Complete(thisRef, endMethod, asyncResult, requiresSynchronization: true);
}
}
@@ -1661,7 +1658,7 @@ namespace System.Threading.Tasks
return ContinueWhenAllImpl<TAntecedentResult>(tasks, continuationFunction, null, continuationOptions, cancellationToken, scheduler);
}
-
+
// Core implementation of ContinueWhenAll -- the generic version
// 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,
@@ -1744,10 +1741,10 @@ namespace System.Threading.Tasks
//the following delegate avoids closure capture as much as possible
//completedTasks.Result == tasksCopy;
//state == continuationFunction
- (completedTasks, state) =>
+ (completedTasks, state) =>
{
completedTasks.NotifyDebuggerOfWaitCompletionIfNecessary();
- return ((Func<Task[], TResult>)state)(completedTasks.Result);
+ return ((Func<Task[], TResult>)state)(completedTasks.Result);
},
continuationFunction, scheduler, cancellationToken, continuationOptions);
}
@@ -1755,13 +1752,13 @@ namespace System.Threading.Tasks
{
Debug.Assert(continuationAction != null);
return starter.ContinueWith<TResult>(
- //the following delegate avoids closure capture as much as possible
- //completedTasks.Result == tasksCopy;
- //state == continuationAction
- (completedTasks, state) =>
+ //the following delegate avoids closure capture as much as possible
+ //completedTasks.Result == tasksCopy;
+ //state == continuationAction
+ (completedTasks, state) =>
{
completedTasks.NotifyDebuggerOfWaitCompletionIfNecessary();
- ((Action<Task[]>)state)(completedTasks.Result); return default(TResult);
+ ((Action<Task[]>)state)(completedTasks.Result); return default(TResult);
},
continuationAction, scheduler, cancellationToken, continuationOptions);
}
@@ -2054,7 +2051,7 @@ namespace System.Threading.Tasks
// check arguments
TaskFactory.CheckMultiTaskContinuationOptions(continuationOptions);
if (tasks == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.tasks);
- if(tasks.Length == 0) ThrowHelper.ThrowArgumentException( ExceptionResource.Task_MultiTaskContinuation_EmptyTaskList, ExceptionArgument.tasks);
+ if (tasks.Length == 0) ThrowHelper.ThrowArgumentException(ExceptionResource.Task_MultiTaskContinuation_EmptyTaskList, ExceptionArgument.tasks);
//ArgumentNullException of continuationFunction or continuationAction is checked by the caller
Contract.Requires((continuationFunction != null) != (continuationAction != null), "Expected exactly one of endFunction/endAction to be non-null");
@@ -2076,8 +2073,8 @@ namespace System.Threading.Tasks
if (continuationFunction != null)
{
return starter.ContinueWith(
- //the following delegate avoids closure capture as much as possible
- //completedTask.Result is the winning task; state == continuationAction
+ //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);
}
@@ -2132,7 +2129,7 @@ namespace System.Threading.Tasks
Debug.Assert(continuationAction != null);
return starter.ContinueWith<TResult>(
// Use a cached delegate
- GenericDelegateCache<TAntecedentResult,TResult>.CWAnyActionDelegate,
+ GenericDelegateCache<TAntecedentResult, TResult>.CWAnyActionDelegate,
continuationAction, scheduler, cancellationToken, continuationOptions);
}
}
@@ -2180,7 +2177,5 @@ namespace System.Threading.Tasks
action(wrappedAntecedents.Result);
return default(TResult);
};
-
}
-
}
diff --git a/src/mscorlib/src/System/Threading/Tasks/IAsyncCausalityTracerStatics.cs b/src/mscorlib/src/System/Threading/Tasks/IAsyncCausalityTracerStatics.cs
index 32efd771a0..17dd1f8bde 100644
--- a/src/mscorlib/src/System/Threading/Tasks/IAsyncCausalityTracerStatics.cs
+++ b/src/mscorlib/src/System/Threading/Tasks/IAsyncCausalityTracerStatics.cs
@@ -13,6 +13,7 @@ using System.Runtime.InteropServices.WindowsRuntime;
// Windows.Foundation.Diagnostics cannot be referenced from managed code because
// they're hidden by the metadata adapter. We redeclare the interfaces manually
// to be able to talk to native WinRT objects.
+
namespace Windows.Foundation.Diagnostics
{
[ComImport]
@@ -47,16 +48,16 @@ namespace Windows.Foundation.Diagnostics
[WindowsRuntimeImport]
internal sealed class TracingStatusChangedEventArgs : ITracingStatusChangedEventArgs
{
- public extern bool Enabled
+ public extern bool Enabled
{
[MethodImpl(MethodImplOptions.InternalCall)]
get;
}
-
- public extern CausalityTraceLevel TraceLevel
+
+ public extern CausalityTraceLevel TraceLevel
{
[MethodImpl(MethodImplOptions.InternalCall)]
- get;
+ get;
}
}
@@ -97,5 +98,4 @@ namespace Windows.Foundation.Diagnostics
Error = 3,
Started = 0
}
-
}
diff --git a/src/mscorlib/src/System/Threading/Tasks/ProducerConsumerQueues.cs b/src/mscorlib/src/System/Threading/Tasks/ProducerConsumerQueues.cs
index 545bf9a5e5..f9d5f89398 100644
--- a/src/mscorlib/src/System/Threading/Tasks/ProducerConsumerQueues.cs
+++ b/src/mscorlib/src/System/Threading/Tasks/ProducerConsumerQueues.cs
@@ -182,7 +182,8 @@ namespace System.Threading.Tasks
newSegment.m_state.m_last = 1;
newSegment.m_state.m_lastCopy = 1;
- try { } finally
+ try { }
+ finally
{
// Finally block to protect against corruption due to a thread abort
// between setting m_next and setting m_tail.
@@ -271,8 +272,8 @@ namespace System.Threading.Tasks
{
for (Segment segment = m_head; segment != null; segment = segment.m_next)
{
- for (int pt = segment.m_state.m_first;
- pt != segment.m_state.m_last;
+ for (int pt = segment.m_state.m_first;
+ pt != segment.m_state.m_last;
pt = (pt + 1) & (segment.m_array.Length - 1))
{
yield return segment.m_array[pt];
@@ -307,7 +308,7 @@ namespace System.Threading.Tasks
}
/// <summary>A segment in the queue containing one or more items.</summary>
- [StructLayout(LayoutKind.Sequential)]
+ [StructLayout(LayoutKind.Sequential)]
private sealed class Segment
{
/// <summary>The next segment in the linked list of segments.</summary>
@@ -367,7 +368,7 @@ namespace System.Threading.Tasks
}
/// <summary>A placeholder class for common padding constants and eventually routines.</summary>
- static class PaddingHelpers
+ internal static class PaddingHelpers
{
/// <summary>A size greater than or equal to the size of the most common CPU cache lines.</summary>
internal const int CACHE_LINE_SIZE = 128;
@@ -375,8 +376,7 @@ namespace System.Threading.Tasks
/// <summary>Padding structure used to minimize false sharing in SingleProducerSingleConsumerQueue{T}.</summary>
[StructLayout(LayoutKind.Explicit, Size = PaddingHelpers.CACHE_LINE_SIZE - sizeof(Int32))] // Based on common case of 64-byte cache lines
- struct PaddingFor32
+ internal struct PaddingFor32
{
}
-
}
diff --git a/src/mscorlib/src/System/Threading/Tasks/TPLETWProvider.cs b/src/mscorlib/src/System/Threading/Tasks/TPLETWProvider.cs
index 12cc1daa63..33bf792370 100644
--- a/src/mscorlib/src/System/Threading/Tasks/TPLETWProvider.cs
+++ b/src/mscorlib/src/System/Threading/Tasks/TPLETWProvider.cs
@@ -16,21 +16,21 @@ using System.Text;
using System.Security;
using System.Runtime.CompilerServices;
+using System.Diagnostics.Tracing;
+
namespace System.Threading.Tasks
{
- using System.Diagnostics.Tracing;
-
/// <summary>Provides an event source for tracing TPL information.</summary>
[EventSource(
Name = "System.Threading.Tasks.TplEventSource",
- Guid = "2e5dba47-a3d2-4d16-8ee0-6671ffdcd7b5",
- LocalizationResources = System.CoreLib.Name)]
+ Guid = "2e5dba47-a3d2-4d16-8ee0-6671ffdcd7b5",
+ LocalizationResources = "FxResources.System.Private.CoreLib.SR")]
internal sealed class TplEtwProvider : EventSource
{
/// Used to determine if tasks should generate Activity IDs for themselves
internal bool TasksSetActivityIds; // This keyword is set
internal bool Debug;
- private bool DebugActivityId;
+ private bool DebugActivityId;
/// <summary>
/// Get callbacks when the ETW sends us commands`
@@ -42,11 +42,11 @@ namespace System.Threading.Tasks
AsyncCausalityTracer.EnableToETW(true);
else if (command.Command == EventCommand.Disable)
AsyncCausalityTracer.EnableToETW(false);
-
- if (IsEnabled(EventLevel.Informational, Keywords.TasksFlowActivityIds))
+
+ if (IsEnabled(EventLevel.Informational, Keywords.TasksFlowActivityIds))
ActivityTracker.Instance.Enable();
- else
- TasksSetActivityIds = IsEnabled(EventLevel.Informational, Keywords.TasksSetActivityIds);
+ else
+ TasksSetActivityIds = IsEnabled(EventLevel.Informational, Keywords.TasksSetActivityIds);
Debug = IsEnabled(EventLevel.Informational, Keywords.Debug);
DebugActivityId = IsEnabled(EventLevel.Informational, Keywords.DebugActivityId);
@@ -99,49 +99,49 @@ namespace System.Threading.Tasks
/// This sets activity IDS and logs when tasks are schedules (or waits begin)
/// But are otherwise silent
/// </summary>
- public const EventKeywords TaskTransfer = (EventKeywords) 1;
+ public const EventKeywords TaskTransfer = (EventKeywords)1;
/// <summary>
/// TaskTranser events plus events when tasks start and stop
/// </summary>
- public const EventKeywords Tasks = (EventKeywords) 2;
+ public const EventKeywords Tasks = (EventKeywords)2;
/// <summary>
/// Events associted with the higher level parallel APIs
/// </summary>
- public const EventKeywords Parallel = (EventKeywords) 4;
+ public const EventKeywords Parallel = (EventKeywords)4;
/// <summary>
/// These are relatively verbose events that effectively just redirect
/// the windows AsyncCausalityTracer to ETW
/// </summary>
- public const EventKeywords AsyncCausalityOperation = (EventKeywords) 8;
- public const EventKeywords AsyncCausalityRelation = (EventKeywords) 0x10;
- public const EventKeywords AsyncCausalitySynchronousWork = (EventKeywords) 0x20;
+ public const EventKeywords AsyncCausalityOperation = (EventKeywords)8;
+ public const EventKeywords AsyncCausalityRelation = (EventKeywords)0x10;
+ public const EventKeywords AsyncCausalitySynchronousWork = (EventKeywords)0x20;
/// <summary>
/// Emit the stops as well as the schedule/start events
/// </summary>
- public const EventKeywords TaskStops = (EventKeywords) 0x40;
+ public const EventKeywords TaskStops = (EventKeywords)0x40;
/// <summary>
/// TasksFlowActivityIds indicate that activity ID flow from one task
/// to any task created by it.
/// </summary>
- public const EventKeywords TasksFlowActivityIds = (EventKeywords) 0x80;
+ public const EventKeywords TasksFlowActivityIds = (EventKeywords)0x80;
/// <summary>
/// TasksSetActivityIds will cause the task operations to set Activity Ids
/// This option is incompatible with TasksFlowActivityIds flow is ignored
/// if that keyword is set. This option is likley to be removed in the future
/// </summary>
- public const EventKeywords TasksSetActivityIds = (EventKeywords) 0x10000;
+ public const EventKeywords TasksSetActivityIds = (EventKeywords)0x10000;
/// <summary>
/// Relatively Verbose logging meant for debugging the Task library itself. Will probably be removed in the future
/// </summary>
- public const EventKeywords Debug = (EventKeywords) 0x20000;
+ public const EventKeywords Debug = (EventKeywords)0x20000;
/// <summary>
/// Relatively Verbose logging meant for debugging the Task library itself. Will probably be removed in the future
/// </summary>
- public const EventKeywords DebugActivityId = (EventKeywords) 0x40000;
+ public const EventKeywords DebugActivityId = (EventKeywords)0x40000;
}
/// <summary>Enabled for all keywords.</summary>
@@ -182,18 +182,18 @@ namespace System.Threading.Tasks
/// <summary>A continuation of a taskWaitEnd is complete </summary>
private const int TASKWAITCONTINUATIONSTARTED_ID = 19;
- private const int TRACEOPERATIONSTART_ID = 14;
- private const int TRACEOPERATIONSTOP_ID = 15;
- private const int TRACEOPERATIONRELATION_ID = 16;
+ private const int TRACEOPERATIONSTART_ID = 14;
+ private const int TRACEOPERATIONSTOP_ID = 15;
+ private const int TRACEOPERATIONRELATION_ID = 16;
private const int TRACESYNCHRONOUSWORKSTART_ID = 17;
- private const int TRACESYNCHRONOUSWORKSTOP_ID = 18;
+ private const int TRACESYNCHRONOUSWORKSTOP_ID = 18;
+
-
//-----------------------------------------------------------------------------------
//
// Task Events
//
-
+
// These are all verbose events, so we need to call IsEnabled(EventLevel.Verbose, ALL_KEYWORDS)
// call. However since the IsEnabled(l,k) call is more expensive than IsEnabled(), we only want
// to incur this cost when instrumentation is enabled. So the Task codepaths that call these
@@ -208,36 +208,36 @@ namespace System.Threading.Tasks
/// <param name="TaskID">The task ID.</param>
/// <param name="CreatingTaskID">The task ID</param>
/// <param name="TaskCreationOptions">The options used to create the task.</param>
- [Event(TASKSCHEDULED_ID, Task = Tasks.TaskScheduled, Version=1, Opcode = EventOpcode.Send,
- Level = EventLevel.Informational, Keywords = Keywords.TaskTransfer|Keywords.Tasks)]
+ [Event(TASKSCHEDULED_ID, Task = Tasks.TaskScheduled, Version = 1, Opcode = EventOpcode.Send,
+ Level = EventLevel.Informational, Keywords = Keywords.TaskTransfer | Keywords.Tasks)]
public void TaskScheduled(
int OriginatingTaskSchedulerID, int OriginatingTaskID, // PFX_COMMON_EVENT_HEADER
int TaskID, int CreatingTaskID, int TaskCreationOptions, int appDomain)
{
// IsEnabled() call is an inlined quick check that makes this very fast when provider is off
- if (IsEnabled() && IsEnabled(EventLevel.Informational, Keywords.TaskTransfer|Keywords.Tasks))
+ if (IsEnabled() && IsEnabled(EventLevel.Informational, Keywords.TaskTransfer | Keywords.Tasks))
{
unsafe
{
EventData* eventPayload = stackalloc EventData[6];
eventPayload[0].Size = sizeof(int);
- eventPayload[0].DataPointer = ((IntPtr) (&OriginatingTaskSchedulerID));
+ eventPayload[0].DataPointer = ((IntPtr)(&OriginatingTaskSchedulerID));
eventPayload[1].Size = sizeof(int);
- eventPayload[1].DataPointer = ((IntPtr) (&OriginatingTaskID));
+ eventPayload[1].DataPointer = ((IntPtr)(&OriginatingTaskID));
eventPayload[2].Size = sizeof(int);
- eventPayload[2].DataPointer = ((IntPtr) (&TaskID));
+ eventPayload[2].DataPointer = ((IntPtr)(&TaskID));
eventPayload[3].Size = sizeof(int);
- eventPayload[3].DataPointer = ((IntPtr) (&CreatingTaskID));
+ eventPayload[3].DataPointer = ((IntPtr)(&CreatingTaskID));
eventPayload[4].Size = sizeof(int);
- eventPayload[4].DataPointer = ((IntPtr) (&TaskCreationOptions));
+ eventPayload[4].DataPointer = ((IntPtr)(&TaskCreationOptions));
eventPayload[5].Size = sizeof(int);
- eventPayload[5].DataPointer = ((IntPtr) (&appDomain));
+ eventPayload[5].DataPointer = ((IntPtr)(&appDomain));
if (TasksSetActivityIds)
{
Guid childActivityId = CreateGuidForTaskID(TaskID);
WriteEventWithRelatedActivityIdCore(TASKSCHEDULED_ID, &childActivityId, 6, eventPayload);
}
- else
+ else
WriteEventCore(TASKSCHEDULED_ID, 6, eventPayload);
}
}
@@ -251,13 +251,13 @@ namespace System.Threading.Tasks
/// <param name="OriginatingTaskSchedulerID">The scheduler ID.</param>
/// <param name="OriginatingTaskID">The task ID.</param>
/// <param name="TaskID">The task ID.</param>
- [Event(TASKSTARTED_ID,
+ [Event(TASKSTARTED_ID,
Level = EventLevel.Informational, Keywords = Keywords.Tasks)]
public void TaskStarted(
int OriginatingTaskSchedulerID, int OriginatingTaskID, // PFX_COMMON_EVENT_HEADER
int TaskID)
{
- if (IsEnabled(EventLevel.Informational, Keywords.Tasks))
+ if (IsEnabled(EventLevel.Informational, Keywords.Tasks))
WriteEvent(TASKSTARTED_ID, OriginatingTaskSchedulerID, OriginatingTaskID, TaskID);
}
#endregion
@@ -270,33 +270,33 @@ namespace System.Threading.Tasks
/// <param name="OriginatingTaskID">The task ID.</param>
/// <param name="TaskID">The task ID.</param>
/// <param name="IsExceptional">Whether the task completed due to an error.</param>
- [Event(TASKCOMPLETED_ID, Version=1,
+ [Event(TASKCOMPLETED_ID, Version = 1,
Level = EventLevel.Informational, Keywords = Keywords.TaskStops)]
public void TaskCompleted(
int OriginatingTaskSchedulerID, int OriginatingTaskID, // PFX_COMMON_EVENT_HEADER
int TaskID, bool IsExceptional)
{
- if (IsEnabled(EventLevel.Informational, Keywords.Tasks))
+ if (IsEnabled(EventLevel.Informational, Keywords.Tasks))
{
unsafe
{
EventData* eventPayload = stackalloc EventData[4];
Int32 isExceptionalInt = IsExceptional ? 1 : 0;
eventPayload[0].Size = sizeof(int);
- eventPayload[0].DataPointer = ((IntPtr) (&OriginatingTaskSchedulerID));
+ eventPayload[0].DataPointer = ((IntPtr)(&OriginatingTaskSchedulerID));
eventPayload[1].Size = sizeof(int);
- eventPayload[1].DataPointer = ((IntPtr) (&OriginatingTaskID));
+ eventPayload[1].DataPointer = ((IntPtr)(&OriginatingTaskID));
eventPayload[2].Size = sizeof(int);
- eventPayload[2].DataPointer = ((IntPtr) (&TaskID));
+ eventPayload[2].DataPointer = ((IntPtr)(&TaskID));
eventPayload[3].Size = sizeof(int);
- eventPayload[3].DataPointer = ((IntPtr) (&isExceptionalInt));
+ eventPayload[3].DataPointer = ((IntPtr)(&isExceptionalInt));
WriteEventCore(TASKCOMPLETED_ID, 4, eventPayload);
}
- }
+ }
}
#endregion
- #region TaskWaitBegin
+ #region TaskWaitBegin
/// <summary>
/// Fired when starting to wait for a taks's completion explicitly or implicitly.
/// </summary>
@@ -307,13 +307,13 @@ namespace System.Threading.Tasks
/// <param name="ContinueWithTaskID">If known, if 'TaskID' has a 'continueWith' task, mention give its ID here.
/// 0 means unknown. This allows better visualization of the common sequential chaining case.</param>
/// </summary>
- [Event(TASKWAITBEGIN_ID, Version=3, Task = TplEtwProvider.Tasks.TaskWait, Opcode = EventOpcode.Send,
- Level = EventLevel.Informational, Keywords = Keywords.TaskTransfer|Keywords.Tasks)]
+ [Event(TASKWAITBEGIN_ID, Version = 3, Task = TplEtwProvider.Tasks.TaskWait, Opcode = EventOpcode.Send,
+ 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)
{
- if (IsEnabled() && IsEnabled(EventLevel.Informational, Keywords.TaskTransfer|Keywords.Tasks))
+ if (IsEnabled() && IsEnabled(EventLevel.Informational, Keywords.TaskTransfer | Keywords.Tasks))
{
unsafe
{
@@ -348,7 +348,7 @@ namespace System.Threading.Tasks
/// <param name="OriginatingTaskSchedulerID">The scheduler ID.</param>
/// <param name="OriginatingTaskID">The task ID.</param>
/// <param name="TaskID">The task ID.</param>
- [Event(TASKWAITEND_ID,
+ [Event(TASKWAITEND_ID,
Level = EventLevel.Verbose, Keywords = Keywords.Tasks)]
public void TaskWaitEnd(
int OriginatingTaskSchedulerID, int OriginatingTaskID, // PFX_COMMON_EVENT_HEADER
@@ -395,23 +395,23 @@ namespace System.Threading.Tasks
/// <param name="OriginatingTaskSchedulerID">The scheduler ID.</param>
/// <param name="OriginatingTaskID">The task ID.</param>
/// <param name="TaskID">The activityId for the continuation.</param>
- [Event(AWAITTASKCONTINUATIONSCHEDULED_ID, Task = Tasks.AwaitTaskContinuationScheduled, Opcode = EventOpcode.Send,
- Level = EventLevel.Informational, Keywords = Keywords.TaskTransfer|Keywords.Tasks)]
+ [Event(AWAITTASKCONTINUATIONSCHEDULED_ID, Task = Tasks.AwaitTaskContinuationScheduled, Opcode = EventOpcode.Send,
+ Level = EventLevel.Informational, Keywords = Keywords.TaskTransfer | Keywords.Tasks)]
public void AwaitTaskContinuationScheduled(
int OriginatingTaskSchedulerID, int OriginatingTaskID, // PFX_COMMON_EVENT_HEADER
int ContinuwWithTaskId)
{
- if (IsEnabled() && IsEnabled(EventLevel.Informational, Keywords.TaskTransfer|Keywords.Tasks))
- {
+ if (IsEnabled() && IsEnabled(EventLevel.Informational, Keywords.TaskTransfer | Keywords.Tasks))
+ {
unsafe
{
EventData* eventPayload = stackalloc EventData[3];
eventPayload[0].Size = sizeof(int);
- eventPayload[0].DataPointer = ((IntPtr) (&OriginatingTaskSchedulerID));
+ eventPayload[0].DataPointer = ((IntPtr)(&OriginatingTaskSchedulerID));
eventPayload[1].Size = sizeof(int);
- eventPayload[1].DataPointer = ((IntPtr) (&OriginatingTaskID));
+ eventPayload[1].DataPointer = ((IntPtr)(&OriginatingTaskID));
eventPayload[2].Size = sizeof(int);
- eventPayload[2].DataPointer = ((IntPtr) (&ContinuwWithTaskId));
+ eventPayload[2].DataPointer = ((IntPtr)(&ContinuwWithTaskId));
if (TasksSetActivityIds)
{
Guid continuationActivityId = CreateGuidForTaskID(ContinuwWithTaskId);
@@ -423,116 +423,116 @@ namespace System.Threading.Tasks
}
}
- [Event(TRACEOPERATIONSTART_ID, Version=1,
+ [Event(TRACEOPERATIONSTART_ID, Version = 1,
Level = EventLevel.Informational, Keywords = Keywords.AsyncCausalityOperation)]
public void TraceOperationBegin(int TaskID, string OperationName, long RelatedContext)
{
- if (IsEnabled() && IsEnabled(EventLevel.Informational, Keywords.AsyncCausalityOperation))
+ if (IsEnabled() && IsEnabled(EventLevel.Informational, Keywords.AsyncCausalityOperation))
{
unsafe
{
- fixed(char* operationNamePtr = OperationName)
+ fixed (char* operationNamePtr = OperationName)
{
EventData* eventPayload = stackalloc EventData[3];
eventPayload[0].Size = sizeof(int);
- eventPayload[0].DataPointer = ((IntPtr) (&TaskID));
+ eventPayload[0].DataPointer = ((IntPtr)(&TaskID));
eventPayload[1].Size = ((OperationName.Length + 1) * 2);
- eventPayload[1].DataPointer = ((IntPtr) operationNamePtr);
+ eventPayload[1].DataPointer = ((IntPtr)operationNamePtr);
eventPayload[2].Size = sizeof(long);
- eventPayload[2].DataPointer = ((IntPtr) (&RelatedContext));
+ eventPayload[2].DataPointer = ((IntPtr)(&RelatedContext));
WriteEventCore(TRACEOPERATIONSTART_ID, 3, eventPayload);
}
}
- }
+ }
}
- [Event(TRACEOPERATIONRELATION_ID, Version=1,
+ [Event(TRACEOPERATIONRELATION_ID, Version = 1,
Level = EventLevel.Informational, Keywords = Keywords.AsyncCausalityRelation)]
public void TraceOperationRelation(int TaskID, CausalityRelation Relation)
{
- if (IsEnabled() && IsEnabled(EventLevel.Informational, Keywords.AsyncCausalityRelation))
- WriteEvent(TRACEOPERATIONRELATION_ID, TaskID,(int) Relation); // optmized overload for this exists
+ if (IsEnabled() && IsEnabled(EventLevel.Informational, Keywords.AsyncCausalityRelation))
+ WriteEvent(TRACEOPERATIONRELATION_ID, TaskID, (int)Relation); // optmized overload for this exists
}
- [Event(TRACEOPERATIONSTOP_ID, Version=1,
+ [Event(TRACEOPERATIONSTOP_ID, Version = 1,
Level = EventLevel.Informational, Keywords = Keywords.AsyncCausalityOperation)]
public void TraceOperationEnd(int TaskID, AsyncCausalityStatus Status)
{
- if (IsEnabled() && IsEnabled(EventLevel.Informational, Keywords.AsyncCausalityOperation))
- WriteEvent(TRACEOPERATIONSTOP_ID, TaskID,(int) Status); // optmized overload for this exists
+ if (IsEnabled() && IsEnabled(EventLevel.Informational, Keywords.AsyncCausalityOperation))
+ WriteEvent(TRACEOPERATIONSTOP_ID, TaskID, (int)Status); // optmized overload for this exists
}
- [Event(TRACESYNCHRONOUSWORKSTART_ID, Version=1,
+ [Event(TRACESYNCHRONOUSWORKSTART_ID, Version = 1,
Level = EventLevel.Informational, Keywords = Keywords.AsyncCausalitySynchronousWork)]
public void TraceSynchronousWorkBegin(int TaskID, CausalitySynchronousWork Work)
{
- if (IsEnabled() && IsEnabled(EventLevel.Informational, Keywords.AsyncCausalitySynchronousWork))
- WriteEvent(TRACESYNCHRONOUSWORKSTART_ID, TaskID,(int) Work); // optmized overload for this exists
+ if (IsEnabled() && IsEnabled(EventLevel.Informational, Keywords.AsyncCausalitySynchronousWork))
+ WriteEvent(TRACESYNCHRONOUSWORKSTART_ID, TaskID, (int)Work); // optmized overload for this exists
}
- [Event(TRACESYNCHRONOUSWORKSTOP_ID, Version=1,
+ [Event(TRACESYNCHRONOUSWORKSTOP_ID, Version = 1,
Level = EventLevel.Informational, Keywords = Keywords.AsyncCausalitySynchronousWork)]
public void TraceSynchronousWorkEnd(CausalitySynchronousWork Work)
{
- if (IsEnabled() && IsEnabled(EventLevel.Informational, Keywords.AsyncCausalitySynchronousWork))
+ if (IsEnabled() && IsEnabled(EventLevel.Informational, Keywords.AsyncCausalitySynchronousWork))
{
unsafe
{
EventData* eventPayload = stackalloc EventData[1];
eventPayload[0].Size = sizeof(int);
- eventPayload[0].DataPointer = ((IntPtr) (&Work));
+ eventPayload[0].DataPointer = ((IntPtr)(&Work));
WriteEventCore(TRACESYNCHRONOUSWORKSTOP_ID, 1, eventPayload);
}
- }
+ }
}
[NonEvent]
- unsafe public void RunningContinuation(int TaskID, object Object) { RunningContinuation(TaskID, (long) *((void**) JitHelpers.UnsafeCastToStackPointer(ref Object))); }
+ 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)
- {
+ private void RunningContinuation(int TaskID, long Object)
+ {
if (Debug)
- WriteEvent(20, TaskID, Object);
+ WriteEvent(20, TaskID, Object);
}
[NonEvent]
- unsafe public void RunningContinuationList(int TaskID, int Index, object Object) { RunningContinuationList(TaskID, Index, (long) *((void**) JitHelpers.UnsafeCastToStackPointer(ref Object))); }
+ unsafe public void RunningContinuationList(int TaskID, int Index, object Object) { RunningContinuationList(TaskID, Index, (long)*((void**)JitHelpers.UnsafeCastToStackPointer(ref Object))); }
[Event(21, Keywords = Keywords.Debug)]
- public void RunningContinuationList(int TaskID, int Index, long Object)
- {
+ public void RunningContinuationList(int TaskID, int Index, long Object)
+ {
if (Debug)
- WriteEvent(21, TaskID, Index, Object);
- }
+ WriteEvent(21, TaskID, Index, Object);
+ }
[Event(23, Keywords = Keywords.Debug)]
- public void DebugFacilityMessage(string Facility, string Message) { WriteEvent(23, Facility, Message); }
+ public void DebugFacilityMessage(string Facility, string Message) { WriteEvent(23, Facility, Message); }
[Event(24, Keywords = Keywords.Debug)]
- public void DebugFacilityMessage1(string Facility, string Message, string Value1) { WriteEvent(24, Facility, Message, Value1); }
+ public void DebugFacilityMessage1(string Facility, string Message, string Value1) { WriteEvent(24, Facility, Message, Value1); }
[Event(25, Keywords = Keywords.DebugActivityId)]
public void SetActivityId(Guid NewId)
{
if (DebugActivityId)
- WriteEvent(25, NewId);
- }
+ WriteEvent(25, NewId);
+ }
[Event(26, Keywords = Keywords.Debug)]
- public void NewID(int TaskID)
- {
+ public void NewID(int TaskID)
+ {
if (Debug)
- WriteEvent(26, TaskID);
- }
+ WriteEvent(26, TaskID);
+ }
/// <summary>
/// Activity IDs are GUIDS but task IDS are integers (and are not unique across appdomains
/// This routine creates a process wide unique GUID given a task ID
/// </summary>
- internal static Guid CreateGuidForTaskID(int taskID)
+ internal static Guid CreateGuidForTaskID(int taskID)
{
// The thread pool generated a process wide unique GUID from a task GUID by
// using the taskGuid, the appdomain ID, and 8 bytes of 'randomization' chosen by
@@ -540,9 +540,9 @@ namespace System.Threading.Tasks
// These were generated by CreateGuid, and are reasonably random (and thus unlikley to collide
uint pid = EventSource.s_currentPid;
int appDomainID = System.Threading.Thread.GetDomainID();
- return new Guid(taskID,
- (short) appDomainID , (short) (appDomainID >> 16),
- (byte)pid, (byte)(pid >> 8), (byte)(pid >> 16), (byte)(pid >> 24),
+ return new Guid(taskID,
+ (short)appDomainID, (short)(appDomainID >> 16),
+ (byte)pid, (byte)(pid >> 8), (byte)(pid >> 16), (byte)(pid >> 24),
0xff, 0xdc, 0xd7, 0xb5);
}
}
diff --git a/src/mscorlib/src/System/Threading/Tasks/Task.cs b/src/mscorlib/src/System/Threading/Tasks/Task.cs
index 7013c5c5e0..8e2e6a4cb0 100644
--- a/src/mscorlib/src/System/Threading/Tasks/Task.cs
+++ b/src/mscorlib/src/System/Threading/Tasks/Task.cs
@@ -29,7 +29,6 @@ using System.Diagnostics.Tracing;
namespace System.Threading.Tasks
{
-
/// <summary>
/// Utility class for allocating structs as heap variables
/// </summary>
@@ -41,7 +40,6 @@ namespace System.Threading.Tasks
{
this.Value = value;
}
-
}
/// <summary>
@@ -271,7 +269,7 @@ namespace System.Threading.Tasks
// but haven't yet been waited on by the parent, lazily initialized.
internal volatile List<Task> m_exceptionalChildren;
// A task's parent, or null if parent-less. Only set during Task construction.
- internal Task m_parent;
+ internal Task m_parent;
/// <summary>
/// Sets the internal completion event.
@@ -569,8 +567,8 @@ namespace System.Threading.Tasks
#if DEBUG
// Check the validity of internalOptions
- int illegalInternalOptions =
- (int) (internalOptions &
+ int illegalInternalOptions =
+ (int)(internalOptions &
~(InternalTaskOptions.PromiseTask |
InternalTaskOptions.ContinuationTask |
InternalTaskOptions.LazyCancellation |
@@ -581,27 +579,26 @@ namespace System.Threading.Tasks
// 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");
- var tmpFlags = (int)creationOptions | (int)internalOptions;
- if ((m_action == null) || ((internalOptions & InternalTaskOptions.ContinuationTask) != 0))
- {
- // For continuation tasks or TaskCompletionSource.Tasks, begin life in the
- // WaitingForActivation state rather than the Created state.
- tmpFlags |= TASK_STATE_WAITINGFORACTIVATION;
- }
- m_stateFlags = tmpFlags; // one write to the volatile m_stateFlags instead of two when setting the above options
+ int tmpFlags = (int)creationOptions | (int)internalOptions; // one write to the volatile m_stateFlags instead of two when setting the above options
+ m_stateFlags = m_action == null || (internalOptions & InternalTaskOptions.ContinuationTask) != 0 ?
+ tmpFlags | TASK_STATE_WAITINGFORACTIVATION :
+ tmpFlags;
// Now is the time to add the new task to the children list
// of the creating task if the options call for it.
// We can safely call the creator task's AddNewChild() method to register it,
// because at this point we are already on its thread of execution.
- Task parent = m_contingentProperties?.m_parent;
- if (parent != null
- && ((creationOptions & TaskCreationOptions.AttachedToParent) != 0)
- && ((parent.CreationOptions & TaskCreationOptions.DenyChildAttach) == 0)
- )
+ ContingentProperties props = m_contingentProperties;
+ if (props != null)
{
- parent.AddNewChild();
+ Task parent = props.m_parent;
+ if (parent != null
+ && ((creationOptions & TaskCreationOptions.AttachedToParent) != 0)
+ && ((parent.CreationOptions & TaskCreationOptions.DenyChildAttach) == 0))
+ {
+ parent.AddNewChild();
+ }
}
// if we have a non-null cancellationToken, allocate the contingent properties to save it
@@ -716,14 +713,7 @@ namespace System.Threading.Tasks
}
// Internal property to process TaskCreationOptions access and mutation.
- internal TaskCreationOptions Options
- {
- get
- {
- int stateFlags = m_stateFlags; // "cast away" volatility to enable inlining of OptionsMethod
- return OptionsMethod(stateFlags);
- }
- }
+ internal TaskCreationOptions Options => OptionsMethod(m_stateFlags);
// Similar to Options property, but allows for the use of a cached flags value rather than
// a read of the volatile m_stateFlags field.
@@ -737,11 +727,16 @@ namespace System.Threading.Tasks
// no illegalBits are set. Returns true on success, false on failure.
internal bool AtomicStateUpdate(int newBits, int illegalBits)
{
- // This could be implemented in terms of:
- // internal bool AtomicStateUpdate(int newBits, int illegalBits, ref int oldFlags);
- // but for high-throughput perf, that delegation's cost is noticeable.
+ int oldFlags = m_stateFlags;
+ return
+ (oldFlags & illegalBits) == 0 &&
+ (Interlocked.CompareExchange(ref m_stateFlags, oldFlags | newBits, oldFlags) == oldFlags ||
+ AtomicStateUpdateSlow(newBits, illegalBits));
+ }
- SpinWait sw = new SpinWait();
+ private bool AtomicStateUpdateSlow(int newBits, int illegalBits)
+ {
+ var sw = new SpinWait();
do
{
int oldFlags = m_stateFlags;
@@ -900,7 +895,6 @@ namespace System.Threading.Tasks
return AtomicStateUpdate(TASK_STATE_STARTED, TASK_STATE_CANCELED | TASK_STATE_STARTED);
}
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal bool FireTaskScheduledIfNeeded(TaskScheduler ts)
{
var etwLog = TplEtwProvider.Log;
@@ -1789,7 +1783,7 @@ namespace System.Threading.Tasks
catch (ThreadAbortException tae)
{
AddException(tae);
- FinishThreadAbortedTask(delegateRan:false);
+ FinishThreadAbortedTask(delegateRan: false);
}
catch (Exception e)
{
@@ -2041,32 +2035,45 @@ namespace System.Threading.Tasks
/// <summary>
/// Signals completion of this particular task.
///
- /// The bUserDelegateExecuted parameter indicates whether this Finish() call comes following the
+ /// The userDelegateExecute parameter indicates whether this Finish() call comes following the
/// full execution of the user delegate.
///
- /// If bUserDelegateExecuted is false, it mean user delegate wasn't invoked at all (either due to
+ /// If userDelegateExecute is false, it mean user delegate wasn't invoked at all (either due to
/// a cancellation request, or because this task is a promise style Task). In this case, the steps
/// involving child tasks (i.e. WaitForChildren) will be skipped.
///
/// </summary>
- internal void Finish(bool bUserDelegateExecuted)
+ internal void Finish(bool userDelegateExecute)
+ {
+ if (m_contingentProperties == null)
+ {
+ FinishStageTwo();
+ }
+ else
+ {
+ FinishSlow(userDelegateExecute);
+ }
+ }
+
+ private void FinishSlow(bool userDelegateExecute)
{
- if (!bUserDelegateExecuted)
+ Debug.Assert(userDelegateExecute || m_contingentProperties != null);
+
+ if (!userDelegateExecute)
{
// delegate didn't execute => no children. We can safely call the remaining finish stages
FinishStageTwo();
}
else
{
- var props = Volatile.Read(ref m_contingentProperties);
+ ContingentProperties props = m_contingentProperties;
- if (props == null || // no contingent properties means no children, so it's safe to complete ourselves
- (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.
+ // Count of 1 => either all children finished, or there were none. Safe to complete ourselves
+ // without paying the price of an Interlocked.Decrement.
+ if ((props.m_completionCountdown == 1) ||
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.
+ // and we could be racing with one of them to call FinishStageTwo().
+ // So whoever does the final Interlocked.Dec is responsible to finish.
{
FinishStageTwo();
}
@@ -2086,8 +2093,7 @@ namespace System.Threading.Tasks
// Now is the time to prune exceptional children. We'll walk the list and removes the ones whose exceptions we might have observed after they threw.
// we use a local variable for exceptional children here because some other thread may be nulling out m_contingentProperties.m_exceptionalChildren
- List<Task> exceptionalChildren = props != null ? props.m_exceptionalChildren : null;
-
+ List<Task> exceptionalChildren = props.m_exceptionalChildren;
if (exceptionalChildren != null)
{
lock (exceptionalChildren)
@@ -2106,12 +2112,17 @@ namespace System.Threading.Tasks
/// It can happen i) either on the thread that originally executed this task (if no children were spawned, or they all completed by the time this task's delegate quit)
/// ii) or on the thread that executed the last child.
/// </summary>
- internal void FinishStageTwo()
+ private void FinishStageTwo()
{
- AddExceptionsFromChildren();
-
// At this point, the task is done executing and waiting for its children,
// we can transition our task to a completion state.
+
+ ContingentProperties cp = Volatile.Read(ref m_contingentProperties);
+ if (cp != null)
+ {
+ AddExceptionsFromChildren(cp);
+ }
+
int completionState;
if (ExceptionRecorded)
{
@@ -2160,7 +2171,7 @@ namespace System.Threading.Tasks
// Set the completion event if it's been lazy allocated.
// And if we made a cancellation registration, it's now unnecessary.
- var cp = Volatile.Read(ref m_contingentProperties);
+ cp = Volatile.Read(ref m_contingentProperties); // need to re-read after updating state
if (cp != null)
{
cp.SetCompleted();
@@ -2187,6 +2198,17 @@ namespace System.Threading.Tasks
m_action = null;
// Notify parent if this was an attached task
+ if (m_contingentProperties != null)
+ {
+ NotifyParentIfPotentiallyAttachedTask();
+ }
+
+ // Activate continuations (if any).
+ FinishContinuations();
+ }
+
+ internal void NotifyParentIfPotentiallyAttachedTask()
+ {
Task parent = m_contingentProperties?.m_parent;
if (parent != null
&& ((parent.CreationOptions & TaskCreationOptions.DenyChildAttach) == 0)
@@ -2194,9 +2216,6 @@ namespace System.Threading.Tasks
{
parent.ProcessChildCompletion(this);
}
-
- // Activate continuations (if any).
- FinishContinuations();
}
/// <summary>
@@ -2232,7 +2251,6 @@ namespace System.Threading.Tasks
tmp.Add(childTask);
}
}
-
}
if (Interlocked.Decrement(ref props.m_completionCountdown) == 0)
@@ -2248,14 +2266,15 @@ namespace System.Threading.Tasks
/// This is to be called just before the task does its final state transition.
/// It traverses the list of exceptional children, and appends their aggregate exceptions into this one's exception list
/// </summary>
- internal void AddExceptionsFromChildren()
+ internal void AddExceptionsFromChildren(ContingentProperties props)
{
+ Debug.Assert(props != null);
+
// In rare occurences during AppDomainUnload() processing, it is possible for this method to be called
// simultaneously on the same task from two different contexts. This can result in m_exceptionalChildren
// being nulled out while it is being processed, which could lead to a NullReferenceException. To
// protect ourselves, we'll cache m_exceptionalChildren in a local variable.
- var props = Volatile.Read(ref m_contingentProperties);
- List<Task> exceptionalChildren = props?.m_exceptionalChildren;
+ List<Task> exceptionalChildren = props.m_exceptionalChildren;
if (exceptionalChildren != null)
{
@@ -2310,40 +2329,13 @@ namespace System.Threading.Tasks
Finish(delegateRan);
}
-
- /// <summary>
- /// Executes the task. This method will only be called once, and handles any necessary exception marshaling.
- /// </summary>
- private void Execute()
- {
- try
- {
- InnerInvoke();
- }
- catch (ThreadAbortException 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(delegateRan: true);
- }
- catch (Exception exn)
- {
- // Record this exception in the task's exception list
- HandleException(exn);
- }
- }
-
/// <summary>
/// IThreadPoolWorkItem override, which is the entry function for this task when the TP scheduler decides to run it.
///
/// </summary>
void IThreadPoolWorkItem.ExecuteWorkItem()
{
- ExecuteEntry(false);
+ ExecuteEntryUnsafe();
}
/// <summary>
@@ -2357,46 +2349,58 @@ namespace System.Threading.Tasks
if (!IsCompleted)
{
HandleException(tae);
- FinishThreadAbortedTask(delegateRan:false);
+ FinishThreadAbortedTask(delegateRan: false);
}
}
/// <summary>
/// Outermost entry function to execute this task. Handles all aspects of executing a task on the caller thread.
- /// Currently this is called by IThreadPoolWorkItem.ExecuteWorkItem(), and TaskManager.TryExecuteInline.
- ///
/// </summary>
- /// <param name="bPreventDoubleExecution"> Performs atomic updates to prevent double execution. Should only be set to true
- /// in codepaths servicing user provided TaskSchedulers. The ThreadPool scheduler doesn't need this. </param>
- internal bool ExecuteEntry(bool bPreventDoubleExecution)
+ internal bool ExecuteEntry()
{
- if (bPreventDoubleExecution)
+ // Do atomic state transition from queued to invoked. If we observe a task that's already invoked,
+ // we will return false so that TaskScheduler.ExecuteTask can throw an exception back to the custom scheduler.
+ // However we don't want this exception to be throw if the task was already canceled, because it's a
+ // legitimate scenario for custom schedulers to dequeue a task and mark it as canceled (example: throttling scheduler)
+ int previousState = 0;
+ if (!AtomicStateUpdate(TASK_STATE_DELEGATE_INVOKED,
+ TASK_STATE_DELEGATE_INVOKED | TASK_STATE_COMPLETED_MASK,
+ ref previousState) && (previousState & TASK_STATE_CANCELED) == 0)
{
- int previousState = 0;
+ // This task has already been invoked. Don't invoke it again.
+ return false;
+ }
- // Do atomic state transition from queued to invoked. If we observe a task that's already invoked,
- // we will return false so that TaskScheduler.ExecuteTask can throw an exception back to the custom scheduler.
- // However we don't want this exception to be throw if the task was already canceled, because it's a
- // legitimate scenario for custom schedulers to dequeue a task and mark it as canceled (example: throttling scheduler)
- if (!AtomicStateUpdate(TASK_STATE_DELEGATE_INVOKED,
- TASK_STATE_DELEGATE_INVOKED | TASK_STATE_COMPLETED_MASK,
- ref previousState) && (previousState & TASK_STATE_CANCELED) == 0)
- {
- // This task has already been invoked. Don't invoke it again.
- return false;
- }
+ if (!IsCancellationRequested & !IsCanceled)
+ {
+ ExecuteWithThreadLocal(ref t_currentTask);
}
else
{
- // Remember that we started running the task delegate.
- m_stateFlags |= TASK_STATE_DELEGATE_INVOKED;
+ ExecuteEntryCancellationRequestedOrCanceled();
}
- if (!IsCancellationRequested && !IsCanceled)
+ return true;
+ }
+
+ internal void ExecuteEntryUnsafe() // used instead of ExecuteEntry() when we don't have to worry about double-execution prevent
+ {
+ // Remember that we started running the task delegate.
+ m_stateFlags |= TASK_STATE_DELEGATE_INVOKED;
+
+ if (!IsCancellationRequested & !IsCanceled)
{
ExecuteWithThreadLocal(ref t_currentTask);
}
- else if (!IsCanceled)
+ else
+ {
+ ExecuteEntryCancellationRequestedOrCanceled();
+ }
+ }
+
+ internal void ExecuteEntryCancellationRequestedOrCanceled()
+ {
+ if (!IsCanceled)
{
int prevState = Interlocked.Exchange(ref m_stateFlags, m_stateFlags | TASK_STATE_CANCELED);
if ((prevState & TASK_STATE_CANCELED) == 0)
@@ -2404,8 +2408,6 @@ namespace System.Threading.Tasks
CancellationCleanupLogic();
}
}
-
- return true;
}
// A trick so we can refer to the TLS slot with a byref.
@@ -2429,30 +2431,44 @@ namespace System.Threading.Tasks
etwLog.TaskStarted(TaskScheduler.Current.Id, 0, this.Id);
}
- if (AsyncCausalityTracer.LoggingOn)
+ bool loggingOn = AsyncCausalityTracer.LoggingOn;
+ if (loggingOn)
AsyncCausalityTracer.TraceSynchronousWorkStart(CausalityTraceLevel.Required, this.Id, CausalitySynchronousWork.Execution);
-
try
{
// place the current task into TLS.
currentTaskSlot = this;
- ExecutionContext ec = CapturedContext;
- if (ec == null)
+ // Execute the task body
+ try
{
- // No context, just run the task directly.
- Execute();
+ ExecutionContext ec = CapturedContext;
+ if (ec == null)
+ {
+ // No context, just run the task directly.
+ InnerInvoke();
+ }
+ else
+ {
+ // Invoke it under the captured ExecutionContext
+ ExecutionContext.Run(ec, s_ecCallback, this);
+ }
}
- else
+ catch (Exception exn)
{
- // Run the task. We need a simple shim that converts the
- // object back into a Task object, so that we can Execute it.
-
- ExecutionContext.Run(ec, s_ecCallback, this);
+ // Record this exception in the task's exception list
+ HandleException(exn);
+ if (exn is ThreadAbortException)
+ {
+ // 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);
+ }
}
- if (AsyncCausalityTracer.LoggingOn)
+ if (loggingOn)
AsyncCausalityTracer.TraceSynchronousWorkCompletion(CausalityTraceLevel.Required, CausalitySynchronousWork.Execution);
Finish(true);
@@ -2460,7 +2476,7 @@ namespace System.Threading.Tasks
finally
{
currentTaskSlot = previousTask;
-
+
// ETW event for Task Completed
if (etwIsEnabled)
{
@@ -2476,7 +2492,7 @@ namespace System.Threading.Tasks
}
}
- private static readonly ContextCallback s_ecCallback = obj => ((Task)obj).Execute();
+ private static readonly ContextCallback s_ecCallback = obj => ((Task)obj).InnerInvoke();
/// <summary>
/// The actual code which invokes the body of the task. This can be overriden in derived types.
@@ -2973,7 +2989,6 @@ namespace System.Threading.Tasks
{
Thread.SpinWait(PlatformHelper.ProcessorCount * (4 << i));
}
-
}
return IsCompleted;
@@ -3031,12 +3046,10 @@ namespace System.Threading.Tasks
// So we need to remeber whether we actually did the flip, so we can do clean up (finish continuations etc)
mustCleanup = AtomicStateUpdate(TASK_STATE_CANCELED, TASK_STATE_DELEGATE_INVOKED | TASK_STATE_CANCELED);
-
// PS: This is slightly different from the regular cancellation codepath
// since we record the cancellation request *after* doing the state transition.
// However that shouldn't matter too much because the task was never invoked, thus can't have children
}
-
}
if (!bCancelNonExecutingOnly || bPopSucceeded || mustCleanup)
@@ -3125,7 +3138,7 @@ namespace System.Threading.Tasks
oce = edi.SourceException as OperationCanceledException;
Debug.Assert(oce != null, "Expected EDI to contain an OCE");
}
- Debug.Assert(oce.CancellationToken == tokenToRecord,
+ Debug.Assert(oce.CancellationToken == tokenToRecord,
"Expected OCE's token to match the provided token.");
#endif
AddException(cancellationException, representsCancellation: true);
@@ -3191,7 +3204,18 @@ namespace System.Threading.Tasks
{
// Atomically store the fact that this task is completing. From this point on, the adding of continuations will
// result in the continuations being run/launched directly rather than being added to the continuation list.
+ // Then if we grabbed any continuations, run them.
object continuationObject = Interlocked.Exchange(ref m_continuationObject, s_taskCompletionSentinel);
+ if (continuationObject != null)
+ {
+ RunContinuations(continuationObject);
+ }
+ }
+
+ private void RunContinuations(object continuationObject) // separated out of FinishContinuations to enable it to be inlined
+ {
+ Debug.Assert(continuationObject != null);
+
TplEtwProvider etw = TplEtwProvider.Log;
bool tplEtwProviderLoggingEnabled = etw.IsEnabled();
if (tplEtwProviderLoggingEnabled)
@@ -3199,136 +3223,125 @@ namespace System.Threading.Tasks
etw.RunningContinuation(Id, continuationObject);
}
- // If continuationObject == null, then we don't have any continuations to process
- if (continuationObject != null)
- {
-
- if (AsyncCausalityTracer.LoggingOn)
- AsyncCausalityTracer.TraceSynchronousWorkStart(CausalityTraceLevel.Required, this.Id, CausalitySynchronousWork.CompletionNotification);
+ if (AsyncCausalityTracer.LoggingOn)
+ AsyncCausalityTracer.TraceSynchronousWorkStart(CausalityTraceLevel.Required, this.Id, CausalitySynchronousWork.CompletionNotification);
- // Skip synchronous execution of continuations if this task's thread was aborted
- bool bCanInlineContinuations = !(((m_stateFlags & TASK_STATE_THREAD_WAS_ABORTED) != 0) ||
- (Thread.CurrentThread.ThreadState == ThreadState.AbortRequested) ||
- ((m_stateFlags & (int)TaskCreationOptions.RunContinuationsAsynchronously) != 0));
+ // Skip synchronous execution of continuations if this task's thread was aborted
+ bool bCanInlineContinuations = !(((m_stateFlags & TASK_STATE_THREAD_WAS_ABORTED) != 0) ||
+ (Thread.CurrentThread.ThreadState == ThreadState.AbortRequested) ||
+ ((m_stateFlags & (int)TaskCreationOptions.RunContinuationsAsynchronously) != 0));
- // Handle the single-Action case
- Action singleAction = continuationObject as Action;
- if (singleAction != null)
- {
- AwaitTaskContinuation.RunOrScheduleAction(singleAction, bCanInlineContinuations, ref t_currentTask);
- LogFinishCompletionNotification();
- return;
- }
+ // Handle the single-Action case
+ Action singleAction = continuationObject as Action;
+ if (singleAction != null)
+ {
+ AwaitTaskContinuation.RunOrScheduleAction(singleAction, bCanInlineContinuations, ref t_currentTask);
+ LogFinishCompletionNotification();
+ return;
+ }
- // Handle the single-ITaskCompletionAction case
- ITaskCompletionAction singleTaskCompletionAction = continuationObject as ITaskCompletionAction;
- if (singleTaskCompletionAction != null)
+ // Handle the single-ITaskCompletionAction case
+ ITaskCompletionAction singleTaskCompletionAction = continuationObject as ITaskCompletionAction;
+ if (singleTaskCompletionAction != null)
+ {
+ if (bCanInlineContinuations || !singleTaskCompletionAction.InvokeMayRunArbitraryCode)
{
- if (bCanInlineContinuations || !singleTaskCompletionAction.InvokeMayRunArbitraryCode)
- {
- singleTaskCompletionAction.Invoke(this);
- }
- else
- {
- ThreadPool.UnsafeQueueCustomWorkItem(new CompletionActionInvoker(singleTaskCompletionAction, this), forceGlobal: false);
- }
- LogFinishCompletionNotification();
- return;
+ singleTaskCompletionAction.Invoke(this);
}
-
- // Handle the single-TaskContinuation case
- TaskContinuation singleTaskContinuation = continuationObject as TaskContinuation;
- if (singleTaskContinuation != null)
+ else
{
- singleTaskContinuation.Run(this, bCanInlineContinuations);
- LogFinishCompletionNotification();
- return;
+ ThreadPool.UnsafeQueueCustomWorkItem(new CompletionActionInvoker(singleTaskCompletionAction, this), forceGlobal: false);
}
+ LogFinishCompletionNotification();
+ return;
+ }
- // Not a single; attempt to cast as list
- List<object> continuations = continuationObject as List<object>;
+ // Handle the single-TaskContinuation case
+ TaskContinuation singleTaskContinuation = continuationObject as TaskContinuation;
+ if (singleTaskContinuation != null)
+ {
+ singleTaskContinuation.Run(this, bCanInlineContinuations);
+ LogFinishCompletionNotification();
+ return;
+ }
- if (continuations == null)
- {
- LogFinishCompletionNotification();
- return; // Not a single or a list; just return
- }
+ // Not a single; it must be a list.
+ List<object> continuations = (List<object>)continuationObject;
- //
- // Begin processing of continuation list
- //
+ //
+ // Begin processing of continuation list
+ //
- // Wait for any concurrent adds or removes to be retired
- lock (continuations) { }
- int continuationCount = continuations.Count;
+ // Wait for any concurrent adds or removes to be retired
+ lock (continuations) { }
+ int continuationCount = continuations.Count;
- // Fire the asynchronous continuations first ...
- for (int i = 0; i < continuationCount; i++)
+ // Fire the asynchronous continuations first ...
+ for (int i = 0; i < continuationCount; i++)
+ {
+ // Synchronous continuation tasks will have the ExecuteSynchronously option,
+ // and we're looking for asynchronous tasks...
+ var tc = continuations[i] as StandardTaskContinuation;
+ if (tc != null && (tc.m_options & TaskContinuationOptions.ExecuteSynchronously) == 0)
{
- // Synchronous continuation tasks will have the ExecuteSynchronously option,
- // and we're looking for asynchronous tasks...
- var tc = continuations[i] as StandardTaskContinuation;
- if (tc != null && (tc.m_options & TaskContinuationOptions.ExecuteSynchronously) == 0)
+ if (tplEtwProviderLoggingEnabled)
{
- if (tplEtwProviderLoggingEnabled)
- {
- etw.RunningContinuationList(Id, i, tc);
- }
- continuations[i] = null; // so that we can skip this later
- tc.Run(this, bCanInlineContinuations);
+ etw.RunningContinuationList(Id, i, tc);
}
+ continuations[i] = null; // so that we can skip this later
+ tc.Run(this, bCanInlineContinuations);
}
+ }
- // ... and then fire the synchronous continuations (if there are any).
- // This includes ITaskCompletionAction, AwaitTaskContinuations, and
- // Action delegates, which are all by default implicitly synchronous.
- for (int i = 0; i < continuationCount; i++)
+ // ... and then fire the synchronous continuations (if there are any).
+ // This includes ITaskCompletionAction, AwaitTaskContinuations, and
+ // Action delegates, which are all by default implicitly synchronous.
+ for (int i = 0; i < continuationCount; i++)
+ {
+ object currentContinuation = continuations[i];
+ if (currentContinuation == null) continue;
+ continuations[i] = null; // to enable free'ing up memory earlier
+ if (tplEtwProviderLoggingEnabled)
{
- object currentContinuation = continuations[i];
- if (currentContinuation == null) continue;
- continuations[i] = null; // to enable free'ing up memory earlier
- if (tplEtwProviderLoggingEnabled)
- {
- etw.RunningContinuationList(Id, i, currentContinuation);
- }
+ etw.RunningContinuationList(Id, i, currentContinuation);
+ }
- // If the continuation is an Action delegate, it came from an await continuation,
- // and we should use AwaitTaskContinuation to run it.
- Action ad = currentContinuation as Action;
- if (ad != null)
+ // If the continuation is an Action delegate, it came from an await continuation,
+ // and we should use AwaitTaskContinuation to run it.
+ Action ad = currentContinuation as Action;
+ if (ad != null)
+ {
+ AwaitTaskContinuation.RunOrScheduleAction(ad, bCanInlineContinuations, ref t_currentTask);
+ }
+ else
+ {
+ // If it's a TaskContinuation object of some kind, invoke it.
+ TaskContinuation tc = currentContinuation as TaskContinuation;
+ if (tc != null)
{
- AwaitTaskContinuation.RunOrScheduleAction(ad, bCanInlineContinuations, ref t_currentTask);
+ // We know that this is a synchronous continuation because the
+ // asynchronous ones have been weeded out
+ tc.Run(this, bCanInlineContinuations);
}
+ // Otherwise, it must be an ITaskCompletionAction, so invoke it.
else
{
- // If it's a TaskContinuation object of some kind, invoke it.
- TaskContinuation tc = currentContinuation as TaskContinuation;
- if (tc != null)
+ Debug.Assert(currentContinuation is ITaskCompletionAction, "Expected continuation element to be Action, TaskContinuation, or ITaskContinuationAction");
+ var action = (ITaskCompletionAction)currentContinuation;
+
+ if (bCanInlineContinuations || !action.InvokeMayRunArbitraryCode)
{
- // We know that this is a synchronous continuation because the
- // asynchronous ones have been weeded out
- tc.Run(this, bCanInlineContinuations);
+ action.Invoke(this);
}
- // Otherwise, it must be an ITaskCompletionAction, so invoke it.
else
{
- Debug.Assert(currentContinuation is ITaskCompletionAction, "Expected continuation element to be Action, TaskContinuation, or ITaskContinuationAction");
- var action = (ITaskCompletionAction)currentContinuation;
-
- if (bCanInlineContinuations || !action.InvokeMayRunArbitraryCode)
- {
- action.Invoke(this);
- }
- else
- {
- ThreadPool.UnsafeQueueCustomWorkItem(new CompletionActionInvoker(action, this), forceGlobal: false);
- }
+ ThreadPool.UnsafeQueueCustomWorkItem(new CompletionActionInvoker(action, this), forceGlobal: false);
}
}
}
-
- LogFinishCompletionNotification();
}
+
+ LogFinishCompletionNotification();
}
private void LogFinishCompletionNotification()
@@ -4140,29 +4153,29 @@ namespace System.Threading.Tasks
out InternalTaskOptions internalOptions)
{
// This is used a couple of times below
- TaskContinuationOptions NotOnAnything =
+ const TaskContinuationOptions NotOnAnything =
TaskContinuationOptions.NotOnCanceled |
TaskContinuationOptions.NotOnFaulted |
TaskContinuationOptions.NotOnRanToCompletion;
- TaskContinuationOptions creationOptionsMask =
+ const TaskContinuationOptions CreationOptionsMask =
TaskContinuationOptions.PreferFairness |
TaskContinuationOptions.LongRunning |
TaskContinuationOptions.DenyChildAttach |
TaskContinuationOptions.HideScheduler |
- TaskContinuationOptions.AttachedToParent|
+ TaskContinuationOptions.AttachedToParent |
TaskContinuationOptions.RunContinuationsAsynchronously;
// Check that LongRunning and ExecuteSynchronously are not specified together
- TaskContinuationOptions illegalMask = TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.LongRunning;
- if ((continuationOptions & illegalMask) == illegalMask)
+ const TaskContinuationOptions IllegalMask = TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.LongRunning;
+ if ((continuationOptions & IllegalMask) == IllegalMask)
{
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.continuationOptions, ExceptionResource.Task_ContinueWith_ESandLR);
}
// Check that no illegal options were specified
if ((continuationOptions &
- ~(creationOptionsMask | NotOnAnything |
+ ~(CreationOptionsMask | NotOnAnything |
TaskContinuationOptions.LazyCancellation | TaskContinuationOptions.ExecuteSynchronously)) != 0)
{
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.continuationOptions);
@@ -4175,14 +4188,12 @@ namespace System.Threading.Tasks
}
// This passes over all but LazyCancellation, which has no representation in TaskCreationOptions
- creationOptions = (TaskCreationOptions)(continuationOptions & creationOptionsMask);
-
- // internalOptions has at least ContinuationTask ...
- internalOptions = InternalTaskOptions.ContinuationTask;
+ creationOptions = (TaskCreationOptions)(continuationOptions & CreationOptionsMask);
- // ... and possibly LazyCancellation
- if ((continuationOptions & TaskContinuationOptions.LazyCancellation) != 0)
- internalOptions |= InternalTaskOptions.LazyCancellation;
+ // internalOptions has at least ContinuationTask and possibly LazyCancellation
+ internalOptions = (continuationOptions & TaskContinuationOptions.LazyCancellation) != 0 ?
+ InternalTaskOptions.ContinuationTask | InternalTaskOptions.LazyCancellation :
+ InternalTaskOptions.ContinuationTask;
}
@@ -4417,7 +4428,6 @@ namespace System.Threading.Tasks
{
// null out that TaskContinuation entry, which will be interpreted as "to be cleaned up"
continuationsLocalListRef[index] = null;
-
}
}
}
@@ -4500,7 +4510,6 @@ namespace System.Threading.Tasks
}
return WaitAll(tasks, (int)totalMilliseconds);
-
}
/// <summary>
@@ -5020,6 +5029,10 @@ namespace System.Threading.Tasks
signaledTaskIndex = Array.IndexOf(tasks, firstCompleted.Result);
Debug.Assert(signaledTaskIndex >= 0);
}
+ else
+ {
+ TaskFactory.CommonCWAnyLogicCleanup(firstCompleted);
+ }
}
// We need to prevent the tasks array from being GC'ed until we come out of the wait.
@@ -5103,7 +5116,7 @@ namespace System.Threading.Tasks
Debug.Assert(succeeded, "This should always succeed on a new task.");
return task;
}
-
+
/// <summary>Creates a <see cref="Task"/> that's completed due to cancellation with the specified token.</summary>
/// <param name="cancellationToken">The token with which to complete the task.</param>
/// <returns>The canceled task.</returns>
@@ -5112,7 +5125,7 @@ namespace System.Threading.Tasks
{
return FromCanceled(cancellationToken);
}
-
+
/// <summary>Creates a <see cref="Task{TResult}"/> that's completed due to cancellation with the specified token.</summary>
/// <typeparam name="TResult">The type of the result returned by the task.</typeparam>
/// <param name="cancellationToken">The token with which to complete the task.</param>
@@ -5122,7 +5135,7 @@ namespace System.Threading.Tasks
{
return FromCanceled<TResult>(cancellationToken);
}
-
+
#endregion
#region Run methods
@@ -6120,8 +6133,8 @@ namespace System.Threading.Tasks
internal virtual Delegate[] GetDelegateContinuationsForDebugger()
{
//Avoid an infinite loop by making sure the continuation object is not a reference to istelf.
- if (this.m_continuationObject != this)
- return GetDelegatesFromContinuationObject(this.m_continuationObject);
+ if (m_continuationObject != this)
+ return GetDelegatesFromContinuationObject(m_continuationObject);
else
return null;
}
@@ -6192,11 +6205,8 @@ namespace System.Threading.Tasks
private static Task[] GetActiveTasks()
{
-
return new List<Task>(s_currentActiveTasks.Values).ToArray();
}
-
-
}
internal sealed class CompletionActionInvoker : IThreadPoolWorkItem
@@ -6715,5 +6725,4 @@ namespace System.Threading.Tasks
public bool InvokeMayRunArbitraryCode { get { return true; } }
}
-
}
diff --git a/src/mscorlib/src/System/Threading/Tasks/TaskCanceledException.cs b/src/mscorlib/src/System/Threading/Tasks/TaskCanceledException.cs
deleted file mode 100644
index f15e3e783a..0000000000
--- a/src/mscorlib/src/System/Threading/Tasks/TaskCanceledException.cs
+++ /dev/null
@@ -1,93 +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.
-
-// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
-//
-//
-//
-// An exception for task cancellations.
-//
-// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-
-using System;
-using System.Runtime.InteropServices;
-using System.Runtime.Serialization;
-
-namespace System.Threading.Tasks
-{
-
- /// <summary>
- /// Represents an exception used to communicate task cancellation.
- /// </summary>
- [Serializable]
- public class TaskCanceledException : OperationCanceledException
- {
-
- [NonSerialized]
- private Task m_canceledTask; // The task which has been canceled.
-
- /// <summary>
- /// Initializes a new instance of the <see cref="T:System.Threading.Tasks.TaskCanceledException"/> class.
- /// </summary>
- public TaskCanceledException() : base(Environment.GetResourceString("TaskCanceledException_ctor_DefaultMessage"))
- {
- }
-
- /// <summary>
- /// Initializes a new instance of the <see cref="T:System.Threading.Tasks.TaskCanceledException"/>
- /// class with a specified error message.
- /// </summary>
- /// <param name="message">The error message that explains the reason for the exception.</param>
- public TaskCanceledException(string message) : base(message)
- {
- }
-
- /// <summary>
- /// Initializes a new instance of the <see cref="T:System.Threading.Tasks.TaskCanceledException"/>
- /// class with a specified error message and a reference to the inner exception that is the cause of
- /// this exception.
- /// </summary>
- /// <param name="message">The error message that explains the reason for the exception.</param>
- /// <param name="innerException">The exception that is the cause of the current exception.</param>
- public TaskCanceledException(string message, Exception innerException) : base(message, innerException)
- {
- }
-
- /// <summary>
- /// Initializes a new instance of the <see cref="T:System.Threading.Tasks.TaskCanceledException"/> class
- /// with a reference to the <see cref="T:System.Threading.Tasks.Task"/> that has been canceled.
- /// </summary>
- /// <param name="task">A task that has been canceled.</param>
- public TaskCanceledException(Task task) :
- base(Environment.GetResourceString("TaskCanceledException_ctor_DefaultMessage"), task!=null ? task.CancellationToken:new CancellationToken())
- {
- m_canceledTask = task;
- }
-
- /// <summary>
- /// Initializes a new instance of the <see cref="T:System.Threading.Tasks.TaskCanceledException"/>
- /// class with serialized data.
- /// </summary>
- /// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo"/> that holds the serialized object data about the exception being thrown.</param>
- /// <param name="context">The <see cref="T:System.Runtime.Serialization.StreamingContext"/> that contains contextual information about the source or destination. </param>
- protected TaskCanceledException(SerializationInfo info, StreamingContext context) : base(info, context)
- {
- }
-
- /// <summary>
- /// Gets the task associated with this exception.
- /// </summary>
- /// <remarks>
- /// It is permissible for no Task to be associated with a
- /// <see cref="T:System.Threading.Tasks.TaskCanceledException"/>, in which case
- /// this property will return null.
- /// </remarks>
- public Task Task
- {
- get { return m_canceledTask; }
- }
-
- }
-
-}
diff --git a/src/mscorlib/src/System/Threading/Tasks/TaskCompletionSource.cs b/src/mscorlib/src/System/Threading/Tasks/TaskCompletionSource.cs
index bf9f9cbb2c..0c80afd22c 100644
--- a/src/mscorlib/src/System/Threading/Tasks/TaskCompletionSource.cs
+++ b/src/mscorlib/src/System/Threading/Tasks/TaskCompletionSource.cs
@@ -131,7 +131,7 @@ namespace System.Threading.Tasks
{
// Spin wait until the completion is finalized by another thread.
var sw = new SpinWait();
- while (!m_task.IsCompleted)
+ while (!m_task.IsCompleted)
sw.SpinOnce();
}
@@ -185,7 +185,7 @@ namespace System.Threading.Tasks
public bool TrySetException(IEnumerable<Exception> exceptions)
{
if (exceptions == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.exceptions);
-
+
List<Exception> defensiveCopy = new List<Exception>();
foreach (Exception e in exceptions)
{
@@ -276,7 +276,7 @@ namespace System.Threading.Tasks
public bool TrySetResult(TResult result)
{
bool rval = m_task.TrySetResult(result);
- if (!rval && !m_task.IsCompleted) SpinUntilCompleted();
+ if (!rval) SpinUntilCompleted();
return rval;
}
@@ -346,7 +346,7 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">The <see cref="Task"/> was disposed.</exception>
public void SetCanceled()
{
- if(!TrySetCanceled())
+ if (!TrySetCanceled())
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.TaskT_TransitionToFinal_AlreadyCompleted);
}
}
diff --git a/src/mscorlib/src/System/Threading/Tasks/TaskContinuation.cs b/src/mscorlib/src/System/Threading/Tasks/TaskContinuation.cs
index 3c6ccd8dd4..848a0ecbc2 100644
--- a/src/mscorlib/src/System/Threading/Tasks/TaskContinuation.cs
+++ b/src/mscorlib/src/System/Threading/Tasks/TaskContinuation.cs
@@ -32,7 +32,7 @@ namespace System.Threading.Tasks
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>,
+ Contract.Requires(action is Action<Task> || action is Action<Task, object>,
"Invalid delegate type in ContinuationTaskFromTask");
m_antecedent = antecedent;
}
@@ -45,7 +45,7 @@ namespace System.Threading.Tasks
// Get and null out the antecedent. This is crucial to avoid a memory
// leak with long chains of continuations.
var antecedent = m_antecedent;
- Debug.Assert(antecedent != null,
+ Debug.Assert(antecedent != null,
"No antecedent was set for the ContinuationTaskFromTask.");
m_antecedent = null;
@@ -79,7 +79,7 @@ namespace System.Threading.Tasks
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>,
+ Contract.Requires(function is Func<Task, TResult> || function is Func<Task, object, TResult>,
"Invalid delegate type in ContinuationResultTaskFromTask");
m_antecedent = antecedent;
}
@@ -92,7 +92,7 @@ namespace System.Threading.Tasks
// Get and null out the antecedent. This is crucial to avoid a memory
// leak with long chains of continuations.
var antecedent = m_antecedent;
- Debug.Assert(antecedent != null,
+ Debug.Assert(antecedent != null,
"No antecedent was set for the ContinuationResultTaskFromTask.");
m_antecedent = null;
@@ -126,7 +126,7 @@ namespace System.Threading.Tasks
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>,
+ Contract.Requires(action is Action<Task<TAntecedentResult>> || action is Action<Task<TAntecedentResult>, object>,
"Invalid delegate type in ContinuationTaskFromResultTask");
m_antecedent = antecedent;
}
@@ -139,7 +139,7 @@ namespace System.Threading.Tasks
// Get and null out the antecedent. This is crucial to avoid a memory
// leak with long chains of continuations.
var antecedent = m_antecedent;
- Debug.Assert(antecedent != null,
+ Debug.Assert(antecedent != null,
"No antecedent was set for the ContinuationTaskFromResultTask.");
m_antecedent = null;
@@ -186,7 +186,7 @@ namespace System.Threading.Tasks
// Get and null out the antecedent. This is crucial to avoid a memory
// leak with long chains of continuations.
var antecedent = m_antecedent;
- Debug.Assert(antecedent != null,
+ Debug.Assert(antecedent != null,
"No antecedent was set for the ContinuationResultTaskFromResultTask.");
m_antecedent = null;
@@ -276,7 +276,6 @@ namespace System.Threading.Tasks
}
internal abstract Delegate[] GetDelegateContinuationsForDebugger();
-
}
/// <summary>Provides the standard implementation of a task continuation.</summary>
@@ -505,7 +504,8 @@ namespace System.Threading.Tasks
// Create the continuation task task. If we're allowed to inline, try to do so.
// The target scheduler may still deny us from executing on this thread, in which case this'll be queued.
- var task = CreateTask(state => {
+ var task = CreateTask(state =>
+ {
try { ((Action)state)(); }
catch (Exception exc) { ThrowAsyncIfNecessary(exc); }
}, m_action, m_scheduler);
@@ -558,10 +558,10 @@ namespace System.Threading.Tasks
Contract.Requires(scheduler != null);
return new Task(
- action, state, null, default(CancellationToken),
- TaskCreationOptions.None, InternalTaskOptions.QueuedByRuntime, scheduler)
- {
- CapturedContext = m_capturedContext
+ action, state, null, default(CancellationToken),
+ TaskCreationOptions.None, InternalTaskOptions.QueuedByRuntime, scheduler)
+ {
+ CapturedContext = m_capturedContext
};
}
@@ -590,7 +590,7 @@ namespace System.Threading.Tasks
// We couldn't inline, so now we need to schedule it
ThreadPool.UnsafeQueueCustomWorkItem(this, forceGlobal: false);
- }
+ }
}
/// <summary>
@@ -626,7 +626,7 @@ namespace System.Threading.Tasks
}
/// <summary>IThreadPoolWorkItem override, which is the entry function for this when the ThreadPool scheduler decides to run it.</summary>
- void ExecuteWorkItemHelper()
+ private void ExecuteWorkItemHelper()
{
var etwLog = TplEtwProvider.Log;
Guid savedActivityId = Guid.Empty;
@@ -645,7 +645,7 @@ namespace System.Threading.Tasks
{
m_action();
}
- // If there is an execution context, get the cached delegate and run the action under the context.
+ // If there is an execution context, get the cached delegate and run the action under the context.
else
{
ExecutionContext.Run(m_capturedContext, GetInvokeActionCallback(), m_action);
@@ -815,5 +815,4 @@ namespace System.Threading.Tasks
return new Delegate[] { AsyncMethodBuilderCore.TryGetStateMachineForDebugger(m_action) };
}
}
-
}
diff --git a/src/mscorlib/src/System/Threading/Tasks/TaskExceptionHolder.cs b/src/mscorlib/src/System/Threading/Tasks/TaskExceptionHolder.cs
index ee1112a93f..1385d907e0 100644
--- a/src/mscorlib/src/System/Threading/Tasks/TaskExceptionHolder.cs
+++ b/src/mscorlib/src/System/Threading/Tasks/TaskExceptionHolder.cs
@@ -70,9 +70,9 @@ namespace System.Threading.Tasks
private static void EnsureADUnloadCallbackRegistered()
{
- if (s_adUnloadEventHandler == null &&
- Interlocked.CompareExchange( ref s_adUnloadEventHandler,
- AppDomainUnloadCallback,
+ if (s_adUnloadEventHandler == null &&
+ Interlocked.CompareExchange(ref s_adUnloadEventHandler,
+ AppDomainUnloadCallback,
null) == null)
{
AppDomain.CurrentDomain.DomainUnload += s_adUnloadEventHandler;
@@ -93,7 +93,7 @@ namespace System.Threading.Tasks
// We need to do this filtering because all TaskExceptionHolders will be finalized during shutdown or unload
// regardles of reachability of the task (i.e. even if the user code was about to observe the task's exception),
// which can otherwise lead to spurious crashes during shutdown.
- if (m_faultExceptions != null && !m_isHandled &&
+ if (m_faultExceptions != null && !m_isHandled &&
!Environment.HasShutdownStarted && !AppDomain.CurrentDomain.IsFinalizingForUnload() && !s_domainUnloadStarted)
{
// We don't want to crash the finalizer thread if any ThreadAbortExceptions
@@ -124,14 +124,14 @@ namespace System.Threading.Tasks
// will have been marked as handled before even getting here.
// Give users a chance to keep this exception from crashing the process
-
+
// First, publish the unobserved exception and allow users to observe it
AggregateException exceptionToThrow = new AggregateException(
- Environment.GetResourceString("TaskExceptionHolder_UnhandledException"),
+ SR.TaskExceptionHolder_UnhandledException,
m_faultExceptions);
UnobservedTaskExceptionEventArgs ueea = new UnobservedTaskExceptionEventArgs(exceptionToThrow);
TaskScheduler.PublishUnobservedTaskException(m_task, ueea);
-
+
// Now, if we are still unobserved and we're configured to crash on unobserved, throw the exception.
// We need to publish the event above even if we're not going to crash, hence
// why this check doesn't come at the beginning of the method.
@@ -164,7 +164,7 @@ namespace System.Threading.Tasks
{
Contract.Requires(exceptionObject != null, "TaskExceptionHolder.Add(): Expected a non-null exceptionObject");
Contract.Requires(
- exceptionObject is Exception || exceptionObject is IEnumerable<Exception> ||
+ exceptionObject is Exception || exceptionObject is IEnumerable<Exception> ||
exceptionObject is ExceptionDispatchInfo || exceptionObject is IEnumerable<ExceptionDispatchInfo>,
"TaskExceptionHolder.Add(): Expected Exception, IEnumerable<Exception>, ExceptionDispatchInfo, or IEnumerable<ExceptionDispatchInfo>");
@@ -180,16 +180,16 @@ namespace System.Threading.Tasks
private void SetCancellationException(object exceptionObject)
{
Contract.Requires(exceptionObject != null, "Expected exceptionObject to be non-null.");
-
- Debug.Assert(m_cancellationException == null,
+
+ Debug.Assert(m_cancellationException == null,
"Expected SetCancellationException to be called only once.");
- // Breaking this assumption will overwrite a previously OCE,
- // and implies something may be wrong elsewhere, since there should only ever be one.
+ // Breaking this assumption will overwrite a previously OCE,
+ // and implies something may be wrong elsewhere, since there should only ever be one.
- Debug.Assert(m_faultExceptions == null,
+ Debug.Assert(m_faultExceptions == null,
"Expected SetCancellationException to be called before any faults were added.");
- // Breaking this assumption shouldn't hurt anything here, but it implies something may be wrong elsewhere.
- // If this changes, make sure to only conditionally mark as handled below.
+ // Breaking this assumption shouldn't hurt anything here, but it implies something may be wrong elsewhere.
+ // If this changes, make sure to only conditionally mark as handled below.
// Store the cancellation exception
var oce = exceptionObject as OperationCanceledException;
@@ -267,21 +267,21 @@ namespace System.Threading.Tasks
exceptions.AddRange(ediColl);
#if DEBUG
Debug.Assert(exceptions.Count > 0, "There should be at least one dispatch info.");
- foreach(var tmp in exceptions)
+ foreach (var tmp in exceptions)
{
Debug.Assert(tmp != null, "No dispatch infos should be null");
}
#endif
}
- // Anything else is a programming error
+ // Anything else is a programming error
else
{
- throw new ArgumentException(Environment.GetResourceString("TaskExceptionHolder_UnknownExceptionType"), nameof(exceptionObject));
+ throw new ArgumentException(SR.TaskExceptionHolder_UnknownExceptionType, nameof(exceptionObject));
}
}
}
}
-
+
// If all of the exceptions are ThreadAbortExceptions and/or
// AppDomainUnloadExceptions, we do not want the finalization
diff --git a/src/mscorlib/src/System/Threading/Tasks/TaskFactory.cs b/src/mscorlib/src/System/Threading/Tasks/TaskFactory.cs
index 89ba2988ca..e193d0e4e2 100644
--- a/src/mscorlib/src/System/Threading/Tasks/TaskFactory.cs
+++ b/src/mscorlib/src/System/Threading/Tasks/TaskFactory.cs
@@ -40,30 +40,20 @@ namespace System.Threading.Tasks
public class TaskFactory
{
// member variables
- private CancellationToken m_defaultCancellationToken;
- private TaskScheduler m_defaultScheduler;
- private TaskCreationOptions m_defaultCreationOptions;
- private TaskContinuationOptions m_defaultContinuationOptions;
+ private readonly CancellationToken m_defaultCancellationToken;
+ private readonly TaskScheduler m_defaultScheduler;
+ private readonly TaskCreationOptions m_defaultCreationOptions;
+ private readonly TaskContinuationOptions m_defaultContinuationOptions;
-
- private TaskScheduler DefaultScheduler
- {
- get
- {
- if (m_defaultScheduler == null) return TaskScheduler.Current;
- else return m_defaultScheduler;
- }
- }
+ private TaskScheduler DefaultScheduler => m_defaultScheduler ?? TaskScheduler.Current;
// sister method to above property -- avoids a TLS lookup
private TaskScheduler GetDefaultScheduler(Task currTask)
{
- if (m_defaultScheduler != null) return m_defaultScheduler;
- else if ((currTask != null)
- && ((currTask.CreationOptions & TaskCreationOptions.HideScheduler) == 0)
- )
- return currTask.ExecutingTaskScheduler;
- else return TaskScheduler.Default;
+ return
+ m_defaultScheduler ??
+ (currTask != null && (currTask.CreationOptions & TaskCreationOptions.HideScheduler) == 0 ? currTask.ExecutingTaskScheduler :
+ TaskScheduler.Default);
}
/* Constructors */
@@ -1528,9 +1518,9 @@ namespace System.Threading.Tasks
{
// Options detected here cause exceptions in FromAsync methods that take beginMethod as a parameter
if ((creationOptions & TaskCreationOptions.LongRunning) != 0)
- throw new ArgumentOutOfRangeException(nameof(creationOptions), Environment.GetResourceString("Task_FromAsync_LongRunning"));
+ throw new ArgumentOutOfRangeException(nameof(creationOptions), SR.Task_FromAsync_LongRunning);
if ((creationOptions & TaskCreationOptions.PreferFairness) != 0)
- throw new ArgumentOutOfRangeException(nameof(creationOptions), Environment.GetResourceString("Task_FromAsync_PreferFairness"));
+ throw new ArgumentOutOfRangeException(nameof(creationOptions), SR.Task_FromAsync_PreferFairness);
}
// Check for general validity of options
@@ -2325,7 +2315,7 @@ namespace System.Threading.Tasks
{
Contract.Requires(tasks != null, "Expected non-null collection of tasks");
_tasks = tasks;
-
+
if (AsyncCausalityTracer.LoggingOn)
AsyncCausalityTracer.TraceOperationCreation(CausalityTraceLevel.Required, this.Id, "TaskFactory.ContinueWhenAny", 0);
@@ -2337,7 +2327,8 @@ namespace System.Threading.Tasks
public void Invoke(Task completingTask)
{
- if (Interlocked.CompareExchange(ref m_firstTaskAlreadyCompleted, 1, 0) == 0)
+ if (m_firstTaskAlreadyCompleted == 0 &&
+ Interlocked.Exchange(ref m_firstTaskAlreadyCompleted, 1) == 0)
{
if (AsyncCausalityTracer.LoggingOn)
{
@@ -2367,7 +2358,6 @@ namespace System.Threading.Tasks
!task.IsCompleted) task.RemoveContinuation(this);
}
_tasks = null;
-
}
}
@@ -2382,17 +2372,18 @@ namespace System.Threading.Tasks
{
Contract.Requires(tasks != null);
- // Create a promise task to be returned to the user
+ // Create a promise task to be returned to the user.
+ // (If this logic ever changes, also update CommonCWAnyLogicCleanup.)
var promise = new CompleteOnInvokePromise(tasks);
// At the completion of any of the tasks, complete the promise.
bool checkArgsOnly = false;
int numTasks = tasks.Count;
- for(int i=0; i<numTasks; i++)
+ for (int i = 0; i < numTasks; i++)
{
var task = tasks[i];
- if (task == null) throw new ArgumentException(Environment.GetResourceString("Task_MultiTaskContinuation_NullTask"), nameof(tasks));
+ if (task == null) throw new ArgumentException(SR.Task_MultiTaskContinuation_NullTask, nameof(tasks));
if (checkArgsOnly) continue;
@@ -2430,6 +2421,17 @@ namespace System.Threading.Tasks
return promise;
}
+ /// <summary>
+ /// Cleans up the operations performed by CommonCWAnyLogic in a case where
+ /// the created continuation task is being discarded.
+ /// </summary>
+ /// <param name="continuation">The task returned from CommonCWAnyLogic.</param>
+ internal static void CommonCWAnyLogicCleanup(Task<Task> continuation)
+ {
+ // Force cleanup of the promise (e.g. removing continuations from each
+ // constituent task), by completing the promise with any value.
+ ((CompleteOnInvokePromise)continuation).Invoke(null);
+ }
/// <summary>
/// Creates a continuation <see cref="T:System.Threading.Tasks.Task">Task</see>
@@ -2663,7 +2665,7 @@ namespace System.Threading.Tasks
if (continuationFunction == null) throw new ArgumentNullException(nameof(continuationFunction));
Contract.EndContractBlock();
- return TaskFactory<TResult>.ContinueWhenAnyImpl(tasks, continuationFunction, null,continuationOptions, m_defaultCancellationToken, DefaultScheduler);
+ return TaskFactory<TResult>.ContinueWhenAnyImpl(tasks, continuationFunction, null, continuationOptions, m_defaultCancellationToken, DefaultScheduler);
}
/// <summary>
@@ -2775,7 +2777,7 @@ namespace System.Threading.Tasks
if (continuationFunction == null) throw new ArgumentNullException(nameof(continuationFunction));
Contract.EndContractBlock();
- return TaskFactory<TResult>.ContinueWhenAnyImpl<TAntecedentResult>(tasks, continuationFunction, null, m_defaultContinuationOptions, cancellationToken, DefaultScheduler);
+ return TaskFactory<TResult>.ContinueWhenAnyImpl<TAntecedentResult>(tasks, continuationFunction, null, m_defaultContinuationOptions, cancellationToken, DefaultScheduler);
}
/// <summary>
@@ -3018,7 +3020,7 @@ namespace System.Threading.Tasks
if (tasks == null)
throw new ArgumentNullException(nameof(tasks));
if (tasks.Length == 0)
- throw new ArgumentException(Environment.GetResourceString("Task_MultiTaskContinuation_EmptyTaskList"), nameof(tasks));
+ throw new ArgumentException(SR.Task_MultiTaskContinuation_EmptyTaskList, nameof(tasks));
Contract.EndContractBlock();
Task[] tasksCopy = new Task[tasks.Length];
@@ -3027,7 +3029,7 @@ namespace System.Threading.Tasks
tasksCopy[i] = tasks[i];
if (tasksCopy[i] == null)
- throw new ArgumentException(Environment.GetResourceString("Task_MultiTaskContinuation_NullTask"), nameof(tasks));
+ throw new ArgumentException(SR.Task_MultiTaskContinuation_NullTask, nameof(tasks));
}
return tasksCopy;
@@ -3038,7 +3040,7 @@ namespace System.Threading.Tasks
if (tasks == null)
throw new ArgumentNullException(nameof(tasks));
if (tasks.Length == 0)
- throw new ArgumentException(Environment.GetResourceString("Task_MultiTaskContinuation_EmptyTaskList"), nameof(tasks));
+ throw new ArgumentException(SR.Task_MultiTaskContinuation_EmptyTaskList, nameof(tasks));
Contract.EndContractBlock();
Task<TResult>[] tasksCopy = new Task<TResult>[tasks.Length];
@@ -3047,7 +3049,7 @@ namespace System.Threading.Tasks
tasksCopy[i] = tasks[i];
if (tasksCopy[i] == null)
- throw new ArgumentException(Environment.GetResourceString("Task_MultiTaskContinuation_NullTask"), nameof(tasks));
+ throw new ArgumentException(SR.Task_MultiTaskContinuation_NullTask, nameof(tasks));
}
return tasksCopy;
@@ -3066,7 +3068,7 @@ namespace System.Threading.Tasks
const TaskContinuationOptions illegalMask = TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.LongRunning;
if ((continuationOptions & illegalMask) == illegalMask)
{
- throw new ArgumentOutOfRangeException(nameof(continuationOptions), Environment.GetResourceString("Task_ContinueWith_ESandLR"));
+ throw new ArgumentOutOfRangeException(nameof(continuationOptions), SR.Task_ContinueWith_ESandLR);
}
// Check that no nonsensical options are specified.
@@ -3085,9 +3087,8 @@ namespace System.Threading.Tasks
// Check that no "fire" options are specified.
if ((continuationOptions & NotOnAny) != 0)
- throw new ArgumentOutOfRangeException(nameof(continuationOptions), Environment.GetResourceString("Task_MultiTaskContinuation_FireOptions"));
+ throw new ArgumentOutOfRangeException(nameof(continuationOptions), SR.Task_MultiTaskContinuation_FireOptions);
Contract.EndContractBlock();
}
}
-
}
diff --git a/src/mscorlib/src/System/Threading/Tasks/TaskScheduler.cs b/src/mscorlib/src/System/Threading/Tasks/TaskScheduler.cs
index d68c3fedc4..45d398f0eb 100644
--- a/src/mscorlib/src/System/Threading/Tasks/TaskScheduler.cs
+++ b/src/mscorlib/src/System/Threading/Tasks/TaskScheduler.cs
@@ -11,6 +11,7 @@
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// Disable the "reference to volatile field not treated as volatile" error.
#pragma warning disable 0420
+
using System;
using System.Collections.Generic;
using System.Globalization;
@@ -23,7 +24,6 @@ using System.Runtime.CompilerServices;
namespace System.Threading.Tasks
{
-
/// <summary>
/// Represents an abstract scheduler for tasks.
/// </summary>
@@ -46,7 +46,7 @@ namespace System.Threading.Tasks
//
// User Provided Methods and Properties
//
-
+
/// <summary>
/// Queues a <see cref="T:System.Threading.Tasks.Task">Task</see> to the scheduler.
/// </summary>
@@ -168,7 +168,7 @@ namespace System.Threading.Tasks
//
// Internal overridable methods
//
-
+
/// <summary>
/// Attempts to execute the target task synchronously.
@@ -183,14 +183,14 @@ namespace System.Threading.Tasks
// Do not inline TaskCompletionSource-style (a.k.a. "promise") tasks.
// No need to attempt inlining if the task body was already run (i.e. either TASK_STATE_DELEGATE_INVOKED or TASK_STATE_CANCELED bits set)
TaskScheduler ets = task.ExecutingTaskScheduler;
-
+
// Delegate cross-scheduler inlining requests to target scheduler
- if(ets != this && ets !=null) return ets.TryRunInline(task, taskWasPreviouslyQueued);
+ if (ets != this && ets != null) return ets.TryRunInline(task, taskWasPreviouslyQueued);
StackGuard currentStackGuard;
- if( (ets == null) ||
+ if ((ets == null) ||
(task.m_action == null) ||
- task.IsDelegateInvoked ||
+ task.IsDelegateInvoked ||
task.IsCanceled ||
(currentStackGuard = Task.CurrentStackGuard).TryBeginInliningScope() == false)
{
@@ -203,7 +203,10 @@ namespace System.Threading.Tasks
bool bInlined = false;
try
{
- task.FireTaskScheduledIfNeeded(this);
+ if (TplEtwProvider.Log.IsEnabled())
+ {
+ task.FireTaskScheduledIfNeeded(this);
+ }
bInlined = TryExecuteTaskInline(task, taskWasPreviouslyQueued);
}
finally
@@ -213,9 +216,9 @@ namespace System.Threading.Tasks
// If the custom scheduler returned true, we should either have the TASK_STATE_DELEGATE_INVOKED or TASK_STATE_CANCELED bit set
// Otherwise the scheduler is buggy
- if (bInlined && !(task.IsDelegateInvoked || task.IsCanceled))
+ if (bInlined && !(task.IsDelegateInvoked || task.IsCanceled))
{
- throw new InvalidOperationException(Environment.GetResourceString("TaskScheduler_InconsistentStateAfterTryExecuteTaskInline"));
+ throw new InvalidOperationException(SR.TaskScheduler_InconsistentStateAfterTryExecuteTaskInline);
}
return bInlined;
@@ -237,7 +240,7 @@ namespace System.Threading.Tasks
/// Notifies the scheduler that a work item has made progress.
/// </summary>
internal virtual void NotifyWorkItemProgress()
- {
+ {
}
/// <summary>
@@ -256,7 +259,10 @@ namespace System.Threading.Tasks
{
Contract.Requires(task != null);
- task.FireTaskScheduledIfNeeded(this);
+ if (TplEtwProvider.Log.IsEnabled())
+ {
+ task.FireTaskScheduledIfNeeded(this);
+ }
this.QueueTask(task);
}
@@ -269,7 +275,7 @@ namespace System.Threading.Tasks
// The global container that keeps track of TaskScheduler instances for debugging purposes.
private static ConditionalWeakTable<TaskScheduler, object> s_activeTaskSchedulers;
-
+
// An AppDomain-wide default manager.
private static readonly TaskScheduler s_defaultTaskScheduler = new ThreadPoolTaskScheduler();
@@ -316,7 +322,7 @@ namespace System.Threading.Tasks
/// <summary>
/// Gets the default <see cref="System.Threading.Tasks.TaskScheduler">TaskScheduler</see> instance.
/// </summary>
- public static TaskScheduler Default
+ public static TaskScheduler Default
{
get
{
@@ -331,7 +337,7 @@ namespace System.Threading.Tasks
/// <remarks>
/// When not called from within a task, <see cref="Current"/> will return the <see cref="Default"/> scheduler.
/// </remarks>
- public static TaskScheduler Current
+ public static TaskScheduler Current
{
get
{
@@ -352,7 +358,7 @@ namespace System.Threading.Tasks
get
{
Task currentTask = Task.InternalCurrent;
- return ( (currentTask != null)
+ return ((currentTask != null)
&& ((currentTask.CreationOptions & TaskCreationOptions.HideScheduler) == 0)
) ? currentTask.ExecutingTaskScheduler : null;
}
@@ -398,7 +404,7 @@ namespace System.Threading.Tasks
{
newId = Interlocked.Increment(ref s_taskSchedulerIdCounter);
} while (newId == 0);
-
+
Interlocked.CompareExchange(ref m_taskSchedulerId, newId, 0);
}
@@ -437,10 +443,10 @@ namespace System.Threading.Tasks
{
if (task.ExecutingTaskScheduler != this)
{
- throw new InvalidOperationException(Environment.GetResourceString("TaskScheduler_ExecuteTask_WrongTaskScheduler"));
+ throw new InvalidOperationException(SR.TaskScheduler_ExecuteTask_WrongTaskScheduler);
}
- return task.ExecuteEntry(true);
+ return task.ExecuteEntry();
}
////////////////////////////////////////////////////////////
@@ -477,12 +483,12 @@ namespace System.Threading.Tasks
lock (_unobservedTaskExceptionLockObject) _unobservedTaskException -= value;
}
}
-
-
+
+
////////////////////////////////////////////////////////////
//
// Internal methods
@@ -588,19 +594,18 @@ namespace System.Threading.Tasks
m_taskScheduler = scheduler;
}
- // returns the scheduler’s Id
+ // returns the scheduler�s Id
public Int32 Id
- {
- get { return m_taskScheduler.Id; }
+ {
+ get { return m_taskScheduler.Id; }
}
- // returns the scheduler’s GetScheduledTasks
- public IEnumerable<Task> ScheduledTasks
+ // returns the scheduler�s GetScheduledTasks
+ public IEnumerable<Task> ScheduledTasks
{
get { return m_taskScheduler.GetScheduledTasks(); }
}
}
-
}
@@ -626,11 +631,10 @@ namespace System.Threading.Tasks
// make sure we have a synccontext to work with
if (synContext == null)
{
- throw new InvalidOperationException(Environment.GetResourceString("TaskScheduler_FromCurrentSynchronizationContext_NoCurrent"));
+ throw new InvalidOperationException(SR.TaskScheduler_FromCurrentSynchronizationContext_NoCurrent);
}
m_synchronizationContext = synContext;
-
}
/// <summary>
@@ -684,16 +688,7 @@ namespace System.Threading.Tasks
}
// preallocated SendOrPostCallback delegate
- private static SendOrPostCallback s_postCallback = new SendOrPostCallback(PostCallback);
-
- // this is where the actual task invocation occures
- private static void PostCallback(object obj)
- {
- Task task = (Task) obj;
-
- // calling ExecuteEntry with double execute check enabled because a user implemented SynchronizationContext could be buggy
- task.ExecuteEntry(true);
- }
+ private static readonly SendOrPostCallback s_postCallback = s => ((Task)s).ExecuteEntry(); // with double-execute check because SC could be buggy
}
/// <summary>
@@ -728,7 +723,7 @@ namespace System.Threading.Tasks
/// Gets whether this exception has been marked as "observed."
/// </summary>
public bool Observed { get { return m_observed; } }
-
+
/// <summary>
/// The Exception that went unobserved.
/// </summary>
diff --git a/src/mscorlib/src/System/Threading/Tasks/TaskSchedulerException.cs b/src/mscorlib/src/System/Threading/Tasks/TaskSchedulerException.cs
deleted file mode 100644
index 1d85e49342..0000000000
--- a/src/mscorlib/src/System/Threading/Tasks/TaskSchedulerException.cs
+++ /dev/null
@@ -1,81 +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.
-
-// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
-//
-//
-//
-// An exception for task schedulers.
-//
-// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-
-using System;
-using System.Runtime.InteropServices;
-using System.Runtime.Serialization;
-
-namespace System.Threading.Tasks
-{
-
- /// <summary>
- /// Represents an exception used to communicate an invalid operation by a
- /// <see cref="T:System.Threading.Tasks.TaskScheduler"/>.
- /// </summary>
- [Serializable]
- public class TaskSchedulerException : Exception
- {
- /// <summary>
- /// Initializes a new instance of the <see cref="T:System.Threading.Tasks.TaskSchedulerException"/> class.
- /// </summary>
- public TaskSchedulerException() : base(Environment.GetResourceString("TaskSchedulerException_ctor_DefaultMessage")) //
- {
- }
-
- /// <summary>
- /// Initializes a new instance of the <see cref="T:System.Threading.Tasks.TaskSchedulerException"/>
- /// class with a specified error message.
- /// </summary>
- /// <param name="message">The error message that explains the reason for the exception.</param>
- public TaskSchedulerException(string message) : base(message)
- {
- }
-
- /// <summary>
- /// Initializes a new instance of the <see cref="T:System.Threading.Tasks.TaskSchedulerException"/>
- /// class using the default error message and a reference to the inner exception that is the cause of
- /// this exception.
- /// </summary>
- /// <param name="innerException">The exception that is the cause of the current exception.</param>
- public TaskSchedulerException(Exception innerException)
- : base(Environment.GetResourceString("TaskSchedulerException_ctor_DefaultMessage"), innerException)
- {
- }
-
- /// <summary>
- /// Initializes a new instance of the <see cref="T:System.Threading.Tasks.TaskSchedulerException"/>
- /// class with a specified error message and a reference to the inner exception that is the cause of
- /// this exception.
- /// </summary>
- /// <param name="message">The error message that explains the reason for the exception.</param>
- /// <param name="innerException">The exception that is the cause of the current exception.</param>
- public TaskSchedulerException(string message, Exception innerException) : base(message, innerException)
- {
- }
-
- /// <summary>
- /// Initializes a new instance of the <see cref="T:System.Threading.Tasks.TaskSchedulerException"/>
- /// class with serialized data.
- /// </summary>
- /// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo"/> that holds
- /// the serialized object data about the exception being thrown.</param>
- /// <param name="context">The <see cref="T:System.Runtime.Serialization.StreamingContext"/> that
- /// contains contextual information about the source or destination. </param>
- protected TaskSchedulerException(SerializationInfo info, StreamingContext context)
- : base(info, context)
- {
- }
-
-
- }
-
-}
diff --git a/src/mscorlib/src/System/Threading/Tasks/TaskToApm.cs b/src/mscorlib/src/System/Threading/Tasks/TaskToApm.cs
index 90743aeec5..fdd62c95f5 100644
--- a/src/mscorlib/src/System/Threading/Tasks/TaskToApm.cs
+++ b/src/mscorlib/src/System/Threading/Tasks/TaskToApm.cs
@@ -60,7 +60,7 @@ namespace System.Threading.Tasks
{
// Asynchronous completion
asyncResult = task.AsyncState == state ? (IAsyncResult)task : new TaskWrapperAsyncResult(task, state, completedSynchronously: false);
- if (callback != null)
+ if (callback != null)
InvokeCallbackWhenTaskCompletes(task, callback, asyncResult);
}
return asyncResult;
@@ -129,7 +129,7 @@ namespace System.Threading.Tasks
// We use OnCompleted rather than ContinueWith in order to avoid running synchronously
// if the task has already completed by the time we get here. This is separated out into
// its own method currently so that we only pay for the closure if necessary.
- antecedent.ConfigureAwait(continueOnCapturedContext:false)
+ antecedent.ConfigureAwait(continueOnCapturedContext: false)
.GetAwaiter()
.OnCompleted(() => callback(asyncResult));
@@ -167,7 +167,7 @@ namespace System.Threading.Tasks
/// <param name="task">The Task to wrap.</param>
/// <param name="state">The new AsyncState value</param>
/// <param name="completedSynchronously">The new CompletedSynchronously value.</param>
- internal TaskWrapperAsyncResult(Task task, object state, bool completedSynchronously)
+ internal TaskWrapperAsyncResult(Task task, object state, bool completedSynchronously)
{
Contract.Requires(task != null);
Contract.Requires(!completedSynchronously || task.IsCompleted, "If completedSynchronously is true, the task must be completed.");
diff --git a/src/mscorlib/src/System/Threading/Tasks/ThreadPoolTaskScheduler.cs b/src/mscorlib/src/System/Threading/Tasks/ThreadPoolTaskScheduler.cs
index 5c6ca9bb76..e69a89fe66 100644
--- a/src/mscorlib/src/System/Threading/Tasks/ThreadPoolTaskScheduler.cs
+++ b/src/mscorlib/src/System/Threading/Tasks/ThreadPoolTaskScheduler.cs
@@ -23,7 +23,7 @@ namespace System.Threading.Tasks
/// <summary>
/// An implementation of TaskScheduler that uses the ThreadPool scheduler
/// </summary>
- internal sealed class ThreadPoolTaskScheduler: TaskScheduler
+ internal sealed class ThreadPoolTaskScheduler : TaskScheduler
{
/// <summary>
/// Constructs a new ThreadPool task scheduler object
@@ -34,15 +34,7 @@ namespace System.Threading.Tasks
}
// static delegate for threads allocated to handle LongRunning tasks.
- private static readonly ParameterizedThreadStart s_longRunningThreadWork = new ParameterizedThreadStart(LongRunningThreadWork);
-
- private static void LongRunningThreadWork(object obj)
- {
- Contract.Requires(obj != null, "TaskScheduler.LongRunningThreadWork: obj is null");
- Task t = obj as Task;
- Debug.Assert(t != null, "TaskScheduler.LongRunningThreadWork: t is null");
- t.ExecuteEntry(false);
- }
+ private static readonly ParameterizedThreadStart s_longRunningThreadWork = s => ((Task)s).ExecuteEntryUnsafe();
/// <summary>
/// Schedules a task to the ThreadPool.
@@ -64,11 +56,11 @@ namespace System.Threading.Tasks
ThreadPool.UnsafeQueueCustomWorkItem(task, forceToGlobalQueue);
}
}
-
+
/// <summary>
/// This internal function will do this:
/// (1) If the task had previously been queued, attempt to pop it and return false if that fails.
- /// (2) Propagate the return value from Task.ExecuteEntry() back to the caller.
+ /// (2) Return whether the task is executed
///
/// IMPORTANT NOTE: TryExecuteTaskInline will NOT throw task exceptions itself. Any wait code path using this function needs
/// to account for exceptions that need to be propagated, and throw themselves accordingly.
@@ -79,19 +71,17 @@ namespace System.Threading.Tasks
if (taskWasPreviouslyQueued && !ThreadPool.TryPopCustomWorkItem(task))
return false;
- // Propagate the return value of Task.ExecuteEntry()
- bool rval = false;
try
{
- rval = task.ExecuteEntry(false); // handles switching Task.Current etc.
+ task.ExecuteEntryUnsafe(); // handles switching Task.Current etc.
}
finally
{
// Only call NWIP() if task was previously queued
- if(taskWasPreviouslyQueued) NotifyWorkItemProgress();
+ if (taskWasPreviouslyQueued) NotifyWorkItemProgress();
}
- return rval;
+ return true;
}
protected internal override bool TryDequeue(Task task)
diff --git a/src/mscorlib/src/System/Threading/Tasks/future.cs b/src/mscorlib/src/System/Threading/Tasks/future.cs
index 15136f12bf..26c2388e6b 100644
--- a/src/mscorlib/src/System/Threading/Tasks/future.cs
+++ b/src/mscorlib/src/System/Threading/Tasks/future.cs
@@ -82,20 +82,20 @@ namespace System.Threading.Tasks
internal static readonly Func<Task<Task>, Task<TResult>> TaskWhenAnyCast = completed => (Task<TResult>)completed.Result;
// Construct a promise-style task without any options.
- internal Task() :
+ internal Task() :
base()
{
}
// Construct a promise-style task with state and options.
internal Task(object state, TaskCreationOptions options) :
- base(state, options, promiseStyle:true)
+ base(state, options, promiseStyle: true)
{
}
// Construct a pre-completed Task<TResult>
- internal Task(TResult result) :
+ internal Task(TResult result) :
base(false, TaskCreationOptions.None, default(CancellationToken))
{
m_result = result;
@@ -372,9 +372,9 @@ namespace System.Threading.Tasks
// Debugger support
private string DebuggerDisplayResultDescription
{
- get
+ get
{
- return IsRanToCompletion ? "" + m_result : Environment.GetResourceString("TaskT_DebuggerNoResult");
+ return IsRanToCompletion ? "" + m_result : SR.TaskT_DebuggerNoResult;
}
}
@@ -392,7 +392,6 @@ namespace System.Threading.Tasks
// internal helper function breaks out logic used by TaskCompletionSource
internal bool TrySetResult(TResult result)
{
- if (IsCompleted) return false;
Debug.Assert(m_action == null, "Task<T>.TrySetResult(): non-null m_action");
// "Reserve" the completion for this task, while making sure that: (1) No prior reservation
@@ -413,12 +412,13 @@ namespace System.Threading.Tasks
// and which can be summarized more concisely with the following snippet from
// FinishStageTwo, omitting everything that doesn't pertain to TrySetResult.
Interlocked.Exchange(ref m_stateFlags, m_stateFlags | TASK_STATE_RAN_TO_COMPLETION);
-
- var cp = m_contingentProperties;
- if (cp != null) cp.SetCompleted();
-
- FinishStageThree();
-
+ ContingentProperties props = m_contingentProperties;
+ if (props != null)
+ {
+ NotifyParentIfPotentiallyAttachedTask();
+ props.SetCompleted();
+ }
+ FinishContinuations();
return true;
}
@@ -441,7 +441,7 @@ namespace System.Threading.Tasks
bool success = TrySetResult(result);
// Nobody else has had a chance to complete this Task yet, so we should succeed.
- Debug.Assert(success);
+ Debug.Assert(success);
}
else
{
@@ -477,7 +477,7 @@ namespace System.Threading.Tasks
{
Debug.Assert(!IsWaitNotificationEnabledOrNotRanToCompletion,
"Should only be used when the task completed successfully and there's no wait notification enabled");
- return m_result;
+ return m_result;
}
}
@@ -539,7 +539,6 @@ namespace System.Threading.Tasks
}
return returnValue;
-
}
// internal helper function breaks out logic used by TaskCompletionSource and AsyncMethodBuilder
@@ -879,7 +878,7 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
/// has already been disposed.
/// </exception>
- public Task ContinueWith(Action<Task<TResult>, Object> continuationAction, Object state,CancellationToken cancellationToken)
+ public Task ContinueWith(Action<Task<TResult>, Object> continuationAction, Object state, CancellationToken cancellationToken)
{
return ContinueWith(continuationAction, state, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None);
}
@@ -942,7 +941,7 @@ namespace System.Threading.Tasks
/// The <paramref name="continuationOptions"/> argument specifies an invalid value for <see
/// cref="T:System.Threading.Tasks.TaskContinuationOptions">TaskContinuationOptions</see>.
/// </exception>
- public Task ContinueWith(Action<Task<TResult>, Object> continuationAction, Object state,TaskContinuationOptions continuationOptions)
+ public Task ContinueWith(Action<Task<TResult>, Object> continuationAction, Object state, TaskContinuationOptions continuationOptions)
{
return ContinueWith(continuationAction, state, TaskScheduler.Current, default(CancellationToken), continuationOptions);
}
@@ -1014,7 +1013,7 @@ namespace System.Threading.Tasks
out internalOptions);
Task continuationTask = new ContinuationTaskFromResultTask<TResult>(
- this, continuationAction, state,
+ this, continuationAction, state,
creationOptions, internalOptions
);
@@ -1229,7 +1228,7 @@ namespace System.Threading.Tasks
out creationOptions,
out internalOptions);
- Task<TNewResult> continuationFuture = new ContinuationResultTaskFromResultTask<TResult,TNewResult>(
+ Task<TNewResult> continuationFuture = new ContinuationResultTaskFromResultTask<TResult, TNewResult>(
this, continuationFunction, null,
creationOptions, internalOptions
);
@@ -1452,7 +1451,7 @@ namespace System.Threading.Tasks
out creationOptions,
out internalOptions);
- Task<TNewResult> continuationFuture = new ContinuationResultTaskFromResultTask<TResult,TNewResult>(
+ Task<TNewResult> continuationFuture = new ContinuationResultTaskFromResultTask<TResult, TNewResult>(
this, continuationFunction, state,
creationOptions, internalOptions
);
@@ -1467,7 +1466,7 @@ namespace System.Threading.Tasks
#endregion
#endregion
-
+
/// <summary>
/// Subscribes an <see cref="IObserver{TResult}"/> to receive notification of the final state of this <see cref="Task{TResult}"/>.
/// </summary>
@@ -1553,7 +1552,5 @@ namespace System.Threading.Tasks
public int Id { get { return m_task.Id; } }
public bool CancellationPending { get { return (m_task.Status == TaskStatus.WaitingToRun) && m_task.CancellationToken.IsCancellationRequested; } }
public TaskStatus Status { get { return m_task.Status; } }
-
-
}
}
diff --git a/src/mscorlib/src/System/Threading/Thread.cs b/src/mscorlib/src/System/Threading/Thread.cs
index d28002729a..70a5d06f7a 100644
--- a/src/mscorlib/src/System/Threading/Thread.cs
+++ b/src/mscorlib/src/System/Threading/Thread.cs
@@ -14,7 +14,8 @@
using Internal.Runtime.Augments;
-namespace System.Threading {
+namespace System.Threading
+{
using System.Threading;
using System.Runtime;
using System.Runtime.InteropServices;
@@ -33,11 +34,9 @@ namespace System.Threading {
internal class ThreadHelper
{
- static ThreadHelper() {}
-
- Delegate _start;
- Object _startArg = null;
- ExecutionContext _executionContext = null;
+ private Delegate _start;
+ private Object _startArg = null;
+ private ExecutionContext _executionContext = null;
internal ThreadHelper(Delegate start)
{
_start = start;
@@ -49,7 +48,7 @@ namespace System.Threading {
}
static internal ContextCallback _ccb = new ContextCallback(ThreadStart_Context);
-
+
static private void ThreadStart_Context(Object state)
{
ThreadHelper t = (ThreadHelper)state;
@@ -65,9 +64,9 @@ namespace System.Threading {
// call back helper
internal void ThreadStart(object obj)
- {
+ {
_startArg = obj;
- if (_executionContext != null)
+ if (_executionContext != null)
{
ExecutionContext.Run(_executionContext, _ccb, (Object)this);
}
@@ -80,7 +79,7 @@ namespace System.Threading {
// call back helper
internal void ThreadStart()
{
- if (_executionContext != null)
+ if (_executionContext != null)
{
ExecutionContext.Run(_executionContext, _ccb, (Object)this);
}
@@ -101,7 +100,7 @@ namespace System.Threading {
}
}
- public sealed class Thread : RuntimeThread
+ internal sealed class Thread : RuntimeThread
{
/*=========================================================================
** Data accessed from managed code that needs to be defined in
@@ -111,10 +110,10 @@ namespace System.Threading {
private ExecutionContext m_ExecutionContext; // this call context follows the logical thread
private SynchronizationContext m_SynchronizationContext; // On CoreCLR, this is maintained separately from ExecutionContext
- private String m_Name;
- private Delegate m_Delegate; // Delegate
+ private String m_Name;
+ private Delegate m_Delegate; // Delegate
- private Object m_ThreadStartArg;
+ private Object m_ThreadStartArg;
/*=========================================================================
** The base implementation of Thread is all native. The following fields
@@ -126,10 +125,10 @@ namespace System.Threading {
#pragma warning disable 414 // These fields are not used from managed.
// IntPtrs need to be together, and before ints, because IntPtrs are 64-bit
// fields on 64-bit platforms, where they will be sorted together.
-
- private IntPtr DONT_USE_InternalThread; // Pointer
- private int m_Priority; // INT32
- private int m_ManagedThreadId; // INT32
+
+ private IntPtr DONT_USE_InternalThread; // Pointer
+ private int m_Priority; // INT32
+ private int m_ManagedThreadId; // INT32
#pragma warning restore 414
#pragma warning restore 169
@@ -143,25 +142,12 @@ namespace System.Threading {
// with native code
// See code:#threadCultureInfo
[ThreadStatic]
- internal static CultureInfo m_CurrentCulture;
+ internal static CultureInfo m_CurrentCulture;
[ThreadStatic]
- internal static CultureInfo m_CurrentUICulture;
-
- static AsyncLocal<CultureInfo> s_asyncLocalCurrentCulture;
- static AsyncLocal<CultureInfo> s_asyncLocalCurrentUICulture;
-
- static void AsyncLocalSetCurrentCulture(AsyncLocalValueChangedArgs<CultureInfo> args)
- {
- m_CurrentCulture = args.CurrentValue;
- }
-
- static void AsyncLocalSetCurrentUICulture(AsyncLocalValueChangedArgs<CultureInfo> args)
- {
- m_CurrentUICulture = args.CurrentValue;
- }
+ internal static CultureInfo m_CurrentUICulture;
// Adding an empty default ctor for annotation purposes
- internal Thread(){}
+ internal Thread() { }
/*=========================================================================
** Creates a new Thread object which will begin execution at
@@ -169,37 +155,45 @@ namespace System.Threading {
**
** Exceptions: ArgumentNullException if start == null.
=========================================================================*/
- public Thread(ThreadStart start) {
- if (start == null) {
+ public Thread(ThreadStart start)
+ {
+ if (start == null)
+ {
throw new ArgumentNullException(nameof(start));
}
Contract.EndContractBlock();
- SetStartHelper((Delegate)start,0); //0 will setup Thread with default stackSize
+ SetStartHelper((Delegate)start, 0); //0 will setup Thread with default stackSize
}
- internal Thread(ThreadStart start, int maxStackSize) {
- if (start == null) {
+ internal Thread(ThreadStart start, int maxStackSize)
+ {
+ if (start == null)
+ {
throw new ArgumentNullException(nameof(start));
}
if (0 > maxStackSize)
- throw new ArgumentOutOfRangeException(nameof(maxStackSize),Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
+ throw new ArgumentOutOfRangeException(nameof(maxStackSize), SR.ArgumentOutOfRange_NeedNonNegNum);
Contract.EndContractBlock();
SetStartHelper((Delegate)start, maxStackSize);
}
- public Thread(ParameterizedThreadStart start) {
- if (start == null) {
+ public Thread(ParameterizedThreadStart start)
+ {
+ if (start == null)
+ {
throw new ArgumentNullException(nameof(start));
}
Contract.EndContractBlock();
SetStartHelper((Delegate)start, 0);
}
- internal Thread(ParameterizedThreadStart start, int maxStackSize) {
- if (start == null) {
+ internal Thread(ParameterizedThreadStart start, int maxStackSize)
+ {
+ if (start == null)
+ {
throw new ArgumentNullException(nameof(start));
}
if (0 > maxStackSize)
- throw new ArgumentOutOfRangeException(nameof(maxStackSize),Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
+ throw new ArgumentOutOfRangeException(nameof(maxStackSize), SR.ArgumentOutOfRange_NeedNonNegNum);
Contract.EndContractBlock();
SetStartHelper((Delegate)start, maxStackSize);
}
@@ -224,7 +218,7 @@ namespace System.Threading {
// There are ways how to create an unitialized objects through remoting, etc. Avoid AVing in the EE by throwing a nice
// exception here.
if (thread.IsNull())
- throw new ArgumentException(null, Environment.GetResourceString("Argument_InvalidHandle"));
+ throw new ArgumentException(null, SR.Argument_InvalidHandle);
return new ThreadHandle(thread);
}
@@ -237,24 +231,24 @@ namespace System.Threading {
**
** Exceptions: ThreadStateException if the thread has already been started.
=========================================================================*/
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
+ [System.Security.DynamicSecurityMethod] // Methods containing StackCrawlMark local var has to be marked DynamicSecurityMethod
public new void Start()
{
StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
Start(ref stackMark);
}
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
+ [System.Security.DynamicSecurityMethod] // Methods containing StackCrawlMark local var has to be marked DynamicSecurityMethod
public new void Start(object parameter)
{
//In the case of a null delegate (second call to start on same thread)
// StartInternal method will take care of the error reporting
- if(m_Delegate is ThreadStart)
+ if (m_Delegate is ThreadStart)
{
//We expect the thread to be setup with a ParameterizedThreadStart
// if this constructor is called.
//If we got here then that wasn't the case
- throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ThreadWrongThreadStart"));
+ throw new InvalidOperationException(SR.InvalidOperation_ThreadWrongThreadStart);
}
m_ThreadStartArg = parameter;
StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
@@ -285,7 +279,7 @@ namespace System.Threading {
internal ExecutionContext ExecutionContext
{
- get { return m_ExecutionContext; }
+ get { return m_ExecutionContext; }
set { m_ExecutionContext = value; }
}
@@ -320,15 +314,15 @@ namespace System.Threading {
{
SleepInternal(millisecondsTimeout);
// Ensure we don't return to app code when the pause is underway
- if(AppDomainPauseManager.IsPaused)
+ if (AppDomainPauseManager.IsPaused)
AppDomainPauseManager.ResumeEvent.WaitOneWithoutFAS();
}
public static void Sleep(TimeSpan timeout)
{
long tm = (long)timeout.TotalMilliseconds;
- if (tm < -1 || tm > (long) Int32.MaxValue)
- throw new ArgumentOutOfRangeException(nameof(timeout), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
+ if (tm < -1 || tm > (long)Int32.MaxValue)
+ throw new ArgumentOutOfRangeException(nameof(timeout), SR.ArgumentOutOfRange_NeedNonNegOrNegative1);
Sleep((int)tm);
}
@@ -353,9 +347,11 @@ namespace System.Threading {
{
return YieldInternal();
}
-
- public static new Thread CurrentThread {
- get {
+
+ public static new Thread CurrentThread
+ {
+ get
+ {
Contract.Ensures(Contract.Result<Thread>() != null);
return GetCurrentThreadNative();
}
@@ -368,14 +364,14 @@ namespace System.Threading {
Debug.Assert(maxStackSize >= 0);
ThreadHelper threadStartCallBack = new ThreadHelper(start);
- if(start is ThreadStart)
+ if (start is ThreadStart)
{
SetStart(new ThreadStart(threadStartCallBack.ThreadStart), maxStackSize);
}
else
{
SetStart(new ParameterizedThreadStart(threadStartCallBack.ThreadStart), maxStackSize);
- }
+ }
}
/*=========================================================================
@@ -437,72 +433,26 @@ namespace System.Threading {
// app domain get unloaded there is a code to clean up the culture from the thread
// using the code in AppDomain::ReleaseDomainStores.
- public CultureInfo CurrentUICulture {
- get {
+ public CultureInfo CurrentUICulture
+ {
+ get
+ {
Contract.Ensures(Contract.Result<CultureInfo>() != null);
-#if FEATURE_APPX && !FEATURE_COREFX_GLOBALIZATION
- if(AppDomain.IsAppXModel()) {
- return CultureInfo.GetCultureInfoForUserPreferredLanguageInAppX() ?? GetCurrentUICultureNoAppX();
- }
- else
-#endif
- {
- return GetCurrentUICultureNoAppX();
- }
+ return CultureInfo.CurrentUICulture;
}
- set {
- if (value == null) {
- throw new ArgumentNullException(nameof(value));
- }
- Contract.EndContractBlock();
-
- //If they're trying to use a Culture with a name that we can't use in resource lookup,
- //don't even let them set it on the thread.
- CultureInfo.VerifyCultureName(value, true);
-
+ set
+ {
// If you add more pre-conditions to this method, check to see if you also need to
// add them to CultureInfo.DefaultThreadCurrentUICulture.set.
if (m_CurrentUICulture == null && m_CurrentCulture == null)
nativeInitCultureAccessors();
- if (!AppContextSwitches.NoAsyncCurrentCulture)
- {
- if (s_asyncLocalCurrentUICulture == null)
- {
- Interlocked.CompareExchange(ref s_asyncLocalCurrentUICulture, new AsyncLocal<CultureInfo>(AsyncLocalSetCurrentUICulture), null);
- }
-
- // this one will set m_CurrentUICulture too
- s_asyncLocalCurrentUICulture.Value = value;
- }
- else
- {
- m_CurrentUICulture = value;
- }
+ CultureInfo.CurrentUICulture = value;
}
}
- internal CultureInfo GetCurrentUICultureNoAppX() {
-
- Contract.Ensures(Contract.Result<CultureInfo>() != null);
-
-#if FEATURE_COREFX_GLOBALIZATION
- return CultureInfo.CurrentUICulture;
-#else
-
- // Fetch a local copy of m_CurrentUICulture to
- // avoid race conditions that malicious user can introduce
- if (m_CurrentUICulture == null) {
- CultureInfo appDomainDefaultUICulture = CultureInfo.DefaultThreadCurrentUICulture;
- return (appDomainDefaultUICulture != null ? appDomainDefaultUICulture : CultureInfo.UserDefaultUICulture);
- }
-
- return m_CurrentUICulture;
-#endif
- }
-
// This returns the exposed context for a given context ID.
// As the culture can be customized object then we cannot hold any
@@ -517,25 +467,16 @@ namespace System.Threading {
// app domain get unloaded there is a code to clean up the culture from the thread
// using the code in AppDomain::ReleaseDomainStores.
- public CultureInfo CurrentCulture {
- get {
+ public CultureInfo CurrentCulture
+ {
+ get
+ {
Contract.Ensures(Contract.Result<CultureInfo>() != null);
-
-#if FEATURE_APPX && !FEATURE_COREFX_GLOBALIZATION
- if(AppDomain.IsAppXModel()) {
- return CultureInfo.GetCultureInfoForUserPreferredLanguageInAppX() ?? GetCurrentCultureNoAppX();
- }
- else
-#endif
- {
- return GetCurrentCultureNoAppX();
- }
+ return CultureInfo.CurrentCulture;
}
- set {
- if (null==value) {
- throw new ArgumentNullException(nameof(value));
- }
+ set
+ {
Contract.EndContractBlock();
// If you add more pre-conditions to this method, check to see if you also need to
@@ -543,39 +484,9 @@ namespace System.Threading {
if (m_CurrentCulture == null && m_CurrentUICulture == null)
nativeInitCultureAccessors();
-
- if (!AppContextSwitches.NoAsyncCurrentCulture)
- {
- if (s_asyncLocalCurrentCulture == null)
- {
- Interlocked.CompareExchange(ref s_asyncLocalCurrentCulture, new AsyncLocal<CultureInfo>(AsyncLocalSetCurrentCulture), null);
- }
- // this one will set m_CurrentCulture too
- s_asyncLocalCurrentCulture.Value = value;
- }
- else
- {
- m_CurrentCulture = value;
- }
- }
- }
-
- private CultureInfo GetCurrentCultureNoAppX() {
-
-#if FEATURE_COREFX_GLOBALIZATION
- return CultureInfo.CurrentCulture;
-#else
- Contract.Ensures(Contract.Result<CultureInfo>() != null);
-
- // Fetch a local copy of m_CurrentCulture to
- // avoid race conditions that malicious user can introduce
- if (m_CurrentCulture == null) {
- CultureInfo appDomainDefaultCulture = CultureInfo.DefaultThreadCurrentCulture;
- return (appDomainDefaultCulture != null ? appDomainDefaultCulture : CultureInfo.UserDefaultCulture);
+
+ CultureInfo.CurrentCulture = value;
}
-
- return m_CurrentCulture;
-#endif
}
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
@@ -616,14 +527,18 @@ namespace System.Threading {
// Retrieves the name of the thread.
//
- public new String Name {
- get {
+ public new String Name
+ {
+ get
+ {
return m_Name;
}
- set {
- lock(this) {
+ set
+ {
+ lock (this)
+ {
if (m_Name != null)
- throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_WriteOnce"));
+ throw new InvalidOperationException(SR.InvalidOperation_WriteOnce);
m_Name = value;
InformThreadNameChange(GetNativeHandle(), value, (value != null) ? value.Length : 0);
@@ -635,9 +550,6 @@ namespace System.Threading {
[SuppressUnmanagedCodeSecurity]
private static extern void InformThreadNameChange(ThreadHandle t, String name, int len);
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- public static extern void MemoryBarrier();
-
} // 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
@@ -651,5 +563,4 @@ namespace System.Threading {
LookForMyCallersCaller = 2,
LookForThread = 3
}
-
}
diff --git a/src/mscorlib/src/System/Threading/ThreadAbortException.cs b/src/mscorlib/src/System/Threading/ThreadAbortException.cs
deleted file mode 100644
index 25925048bf..0000000000
--- a/src/mscorlib/src/System/Threading/ThreadAbortException.cs
+++ /dev/null
@@ -1,39 +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: An exception class which is thrown into a thread to cause it to
-** abort. This is a special non-catchable exception and results in
-** the thread's death. This is thrown by the VM only and can NOT be
-** thrown by any user thread, and subclassing this is useless.
-**
-**
-=============================================================================*/
-
-namespace System.Threading
-{
- using System;
- using System.Runtime.Serialization;
- using System.Runtime.CompilerServices;
-
- [Serializable]
- public sealed class ThreadAbortException : SystemException
- {
- private ThreadAbortException()
- : base(GetMessageFromNativeResources(ExceptionMessageKind.ThreadAbort))
- {
- SetErrorCode(__HResults.COR_E_THREADABORTED);
- }
-
- //required for serialization
- internal ThreadAbortException(SerializationInfo info, StreamingContext context)
- : base(info, context)
- {
- }
- }
-}
diff --git a/src/mscorlib/src/System/Threading/ThreadInterruptedException.cs b/src/mscorlib/src/System/Threading/ThreadInterruptedException.cs
index 71c09649e2..9122df0d3e 100644
--- a/src/mscorlib/src/System/Threading/ThreadInterruptedException.cs
+++ b/src/mscorlib/src/System/Threading/ThreadInterruptedException.cs
@@ -12,29 +12,36 @@
**
**
=============================================================================*/
-namespace System.Threading {
- using System.Threading;
- using System;
- using System.Runtime.Serialization;
+using System.Threading;
+using System;
+using System.Runtime.Serialization;
+
+namespace System.Threading
+{
[Serializable]
- public class ThreadInterruptedException : SystemException {
- public ThreadInterruptedException()
- : base(GetMessageFromNativeResources(ExceptionMessageKind.ThreadInterrupted)) {
- SetErrorCode(__HResults.COR_E_THREADINTERRUPTED);
+ public class ThreadInterruptedException : SystemException
+ {
+ public ThreadInterruptedException()
+ : base(GetMessageFromNativeResources(ExceptionMessageKind.ThreadInterrupted))
+ {
+ HResult = __HResults.COR_E_THREADINTERRUPTED;
}
-
- public ThreadInterruptedException(String message)
- : base(message) {
- SetErrorCode(__HResults.COR_E_THREADINTERRUPTED);
+
+ public ThreadInterruptedException(String message)
+ : base(message)
+ {
+ HResult = __HResults.COR_E_THREADINTERRUPTED;
}
-
- public ThreadInterruptedException(String message, Exception innerException)
- : base(message, innerException) {
- SetErrorCode(__HResults.COR_E_THREADINTERRUPTED);
+
+ public ThreadInterruptedException(String message, Exception innerException)
+ : base(message, innerException)
+ {
+ HResult = __HResults.COR_E_THREADINTERRUPTED;
}
- protected ThreadInterruptedException(SerializationInfo info, StreamingContext context) : base (info, context) {
+ protected ThreadInterruptedException(SerializationInfo info, StreamingContext context) : base(info, context)
+ {
}
}
}
diff --git a/src/mscorlib/src/System/Threading/ThreadLocal.cs b/src/mscorlib/src/System/Threading/ThreadLocal.cs
index eedf6d0c81..64b8a60196 100644
--- a/src/mscorlib/src/System/Threading/ThreadLocal.cs
+++ b/src/mscorlib/src/System/Threading/ThreadLocal.cs
@@ -36,7 +36,6 @@ namespace System.Threading
[DebuggerDisplay("IsValueCreated={IsValueCreated}, Value={ValueForDebugDisplay}, Count={ValuesCountForDebugDisplay}")]
public class ThreadLocal<T> : IDisposable
{
-
// a delegate that returns the created value, if null the created value will be default(T)
private Func<T> m_valueFactory;
@@ -48,10 +47,10 @@ namespace System.Threading
// the ThreadLocal<T> instance.
//
[ThreadStatic]
- static LinkedSlotVolatile[] ts_slotArray;
+ private static LinkedSlotVolatile[] ts_slotArray;
[ThreadStatic]
- static FinalizationHelper ts_finalizationHelper;
+ private static FinalizationHelper ts_finalizationHelper;
// Slot ID of this ThreadLocal<> instance. We store a bitwise complement of the ID (that is ~ID), which allows us to distinguish
// between the case when ID is 0 and an incompletely initialized object, either due to a thread abort in the constructor, or
@@ -276,7 +275,7 @@ namespace System.Threading
&& id < slotArray.Length // Is the table large enough?
&& (slot = slotArray[id].Value) != null // Has a LinkedSlot object has been allocated for this ID?
&& m_initialized // Has the instance *still* not been disposed (important for a race condition with Dispose)?
- )
+ )
{
// We verified that the instance has not been disposed *after* we got a reference to the slot.
// This guarantees that we have a reference to the right slot.
@@ -324,7 +323,7 @@ namespace System.Threading
int id = ~m_idComplement;
if (id < 0)
{
- throw new ObjectDisposedException(Environment.GetResourceString("ThreadLocal_Disposed"));
+ throw new ObjectDisposedException(SR.ThreadLocal_Disposed);
}
Debugger.NotifyOfCrossThreadDependency();
@@ -341,7 +340,7 @@ namespace System.Threading
if (IsValueCreated)
{
- throw new InvalidOperationException(Environment.GetResourceString("ThreadLocal_Value_RecursiveCallsToValue"));
+ throw new InvalidOperationException(SR.ThreadLocal_Value_RecursiveCallsToValue);
}
}
@@ -357,7 +356,7 @@ namespace System.Threading
// If the object has been disposed, id will be -1.
if (id < 0)
{
- throw new ObjectDisposedException(Environment.GetResourceString("ThreadLocal_Disposed"));
+ throw new ObjectDisposedException(SR.ThreadLocal_Disposed);
}
// If a slot array has not been created on this thread yet, create it.
@@ -395,7 +394,7 @@ namespace System.Threading
if (!m_initialized)
{
- throw new ObjectDisposedException(Environment.GetResourceString("ThreadLocal_Disposed"));
+ throw new ObjectDisposedException(SR.ThreadLocal_Disposed);
}
slot.Value = value;
@@ -417,7 +416,7 @@ namespace System.Threading
// Dispose also executes under a lock.
if (!m_initialized)
{
- throw new ObjectDisposedException(Environment.GetResourceString("ThreadLocal_Disposed"));
+ throw new ObjectDisposedException(SR.ThreadLocal_Disposed);
}
LinkedSlot firstRealNode = m_linkedSlot.Next;
@@ -455,11 +454,11 @@ namespace System.Threading
{
if (!m_trackAllValues)
{
- throw new InvalidOperationException(Environment.GetResourceString("ThreadLocal_ValuesNotAvailable"));
+ throw new InvalidOperationException(SR.ThreadLocal_ValuesNotAvailable);
}
var list = GetValuesAsList(); // returns null if disposed
- if (list == null) throw new ObjectDisposedException(Environment.GetResourceString("ThreadLocal_Disposed"));
+ if (list == null) throw new ObjectDisposedException(SR.ThreadLocal_Disposed);
return list;
}
}
@@ -512,7 +511,7 @@ namespace System.Threading
int id = ~m_idComplement;
if (id < 0)
{
- throw new ObjectDisposedException(Environment.GetResourceString("ThreadLocal_Disposed"));
+ throw new ObjectDisposedException(SR.ThreadLocal_Disposed);
}
LinkedSlotVolatile[] slotArray = ts_slotArray;
diff --git a/src/mscorlib/src/System/Threading/ThreadPool.cs b/src/mscorlib/src/System/Threading/ThreadPool.cs
index adf0615819..0084050c43 100644
--- a/src/mscorlib/src/System/Threading/ThreadPool.cs
+++ b/src/mscorlib/src/System/Threading/ThreadPool.cs
@@ -33,8 +33,6 @@ namespace System.Threading
public static readonly int processorCount = Environment.ProcessorCount;
- public static readonly bool tpHosted = ThreadPool.IsThreadPoolHosted();
-
public static volatile bool vmTpInitialized;
public static bool enableWorkerTracking;
@@ -124,7 +122,7 @@ namespace System.Threading
private volatile int m_headIndex = START_INDEX;
private volatile int m_tailIndex = START_INDEX;
- private SpinLock m_foreignLock = new SpinLock(enableThreadOwnerTracking:false);
+ private SpinLock m_foreignLock = new SpinLock(enableThreadOwnerTracking: false);
public void LocalPush(IThreadPoolWorkItem obj)
{
@@ -158,7 +156,7 @@ namespace System.Threading
finally
{
if (lockTaken)
- m_foreignLock.Exit(useMemoryBarrier:true);
+ m_foreignLock.Exit(useMemoryBarrier: true);
}
}
@@ -200,7 +198,7 @@ namespace System.Threading
finally
{
if (lockTaken)
- m_foreignLock.Exit(useMemoryBarrier:false);
+ m_foreignLock.Exit(useMemoryBarrier: false);
}
}
}
@@ -254,7 +252,7 @@ namespace System.Threading
finally
{
if (lockTaken)
- m_foreignLock.Exit(useMemoryBarrier:false);
+ m_foreignLock.Exit(useMemoryBarrier: false);
}
}
}
@@ -321,7 +319,7 @@ namespace System.Threading
finally
{
if (lockTaken)
- m_foreignLock.Exit(useMemoryBarrier:false);
+ m_foreignLock.Exit(useMemoryBarrier: false);
}
}
}
@@ -366,7 +364,7 @@ namespace System.Threading
finally
{
if (taken)
- m_foreignLock.Exit(useMemoryBarrier:false);
+ m_foreignLock.Exit(useMemoryBarrier: false);
}
missedSteal = true;
@@ -381,10 +379,10 @@ namespace System.Threading
internal readonly ConcurrentQueue<IThreadPoolWorkItem> workItems = new ConcurrentQueue<IThreadPoolWorkItem>();
private volatile int numOutstandingThreadRequests = 0;
-
+
public ThreadPoolWorkQueue()
{
- loggingEnabled = FrameworkEventSource.Log.IsEnabled(EventLevel.Verbose, FrameworkEventSource.Keywords.ThreadPool|FrameworkEventSource.Keywords.ThreadTransfer);
+ loggingEnabled = FrameworkEventSource.Log.IsEnabled(EventLevel.Verbose, FrameworkEventSource.Keywords.ThreadPool | FrameworkEventSource.Keywords.ThreadTransfer);
}
public ThreadPoolWorkQueueThreadLocals EnsureCurrentThreadHasQueue() =>
@@ -401,7 +399,7 @@ namespace System.Threading
int count = numOutstandingThreadRequests;
while (count < ThreadPoolGlobals.processorCount)
{
- int prev = Interlocked.CompareExchange(ref numOutstandingThreadRequests, count+1, count);
+ int prev = Interlocked.CompareExchange(ref numOutstandingThreadRequests, count + 1, count);
if (prev == count)
{
ThreadPool.RequestWorkerThread();
@@ -439,7 +437,7 @@ namespace System.Threading
ThreadPoolWorkQueueThreadLocals tl = null;
if (!forceGlobal)
tl = ThreadPoolWorkQueueThreadLocals.threadLocals;
-
+
if (null != tl)
{
tl.workStealingQueue.LocalPush(callback);
@@ -511,7 +509,7 @@ namespace System.Threading
workQueue.MarkThreadRequestSatisfied();
// Has the desire for logging changed since the last time we entered?
- workQueue.loggingEnabled = FrameworkEventSource.Log.IsEnabled(EventLevel.Verbose, FrameworkEventSource.Keywords.ThreadPool|FrameworkEventSource.Keywords.ThreadTransfer);
+ workQueue.loggingEnabled = FrameworkEventSource.Log.IsEnabled(EventLevel.Verbose, FrameworkEventSource.Keywords.ThreadPool | FrameworkEventSource.Keywords.ThreadTransfer);
//
// Assume that we're going to need another thread if this one returns to the VM. We'll set this to
@@ -603,7 +601,7 @@ namespace System.Threading
// who waits for the task to complete.
//
workItem?.MarkAborted(tae);
-
+
//
// In this case, the VM is going to request another thread on our behalf. No need to do it twice.
//
@@ -707,7 +705,7 @@ namespace System.Threading
private volatile int m_lock = 0;
internal IntPtr GetHandle() => registeredWaitHandle;
-
+
internal void SetHandle(IntPtr handle)
{
registeredWaitHandle = handle;
@@ -731,7 +729,7 @@ namespace System.Threading
}
internal bool Unregister(
- WaitHandle waitObject // object to be notified when all callbacks to delegates have completed
+ WaitHandle waitObject // object to be notified when all callbacks to delegates have completed
)
{
bool result = false;
@@ -745,7 +743,7 @@ namespace System.Threading
// lock(this) cannot be used reliably in Cer since thin lock could be
// promoted to syncblock and that is not a guaranteed operation
bool bLockTaken = false;
- do
+ do
{
if (Interlocked.CompareExchange(ref m_lock, 1, 0) == 0)
{
@@ -807,8 +805,8 @@ namespace System.Threading
// This will result in a "leak" of sorts (since the handle will not be cleaned up)
// but the process is exiting anyway.
//
- // During AD-unload, we don’t finalize live objects until all threads have been
- // aborted out of the AD. Since these locked regions are CERs, we won’t abort them
+ // During AD-unload, we don�t finalize live objects until all threads have been
+ // aborted out of the AD. Since these locked regions are CERs, we won�t abort them
// while the lock is held. So there should be no leak on AD-unload.
//
if (Interlocked.CompareExchange(ref m_lock, 1, 0) == 0)
@@ -841,9 +839,10 @@ namespace System.Threading
private static extern bool UnregisterWaitNative(IntPtr handle, SafeHandle waitObject);
}
- public sealed class RegisteredWaitHandle : MarshalByRefObject {
+ public sealed class RegisteredWaitHandle : MarshalByRefObject
+ {
private readonly RegisteredWaitHandleSafe internalRegisteredWait;
-
+
internal RegisteredWaitHandle()
{
internalRegisteredWait = new RegisteredWaitHandleSafe();
@@ -851,23 +850,23 @@ namespace System.Threading
internal void SetHandle(IntPtr handle)
{
- internalRegisteredWait.SetHandle(handle);
+ internalRegisteredWait.SetHandle(handle);
}
internal void SetWaitObject(WaitHandle waitObject)
{
- internalRegisteredWait.SetWaitObject(waitObject);
+ internalRegisteredWait.SetWaitObject(waitObject);
}
// 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
+ WaitHandle waitObject // object to be notified when all callbacks to delegates have completed
)
{
return internalRegisteredWait.Unregister(waitObject);
}
}
-
+
public delegate void WaitCallback(Object state);
public delegate void WaitOrTimerCallback(Object state, bool timedOut); // signalled or timed out
@@ -905,16 +904,16 @@ namespace System.Threading
private readonly Object state;
#if DEBUG
- volatile int executed;
+ private volatile int executed;
~QueueUserWorkItemCallback()
{
Debug.Assert(
- executed != 0 || Environment.HasShutdownStarted || AppDomain.CurrentDomain.IsFinalizingForUnload(),
+ executed != 0 || Environment.HasShutdownStarted || AppDomain.CurrentDomain.IsFinalizingForUnload(),
"A QueueUserWorkItemCallback was never called!");
}
- void MarkExecuted(bool aborted)
+ private void MarkExecuted(bool aborted)
{
GC.SuppressFinalize(this);
Debug.Assert(
@@ -933,7 +932,7 @@ namespace System.Threading
void IThreadPoolWorkItem.ExecuteWorkItem()
{
#if DEBUG
- MarkExecuted(aborted:false);
+ MarkExecuted(aborted: false);
#endif
// call directly if it is an unsafe call OR EC flow is suppressed
if (context == null)
@@ -953,7 +952,7 @@ 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(aborted:true);
+ MarkExecuted(aborted: true);
#endif
}
@@ -983,7 +982,7 @@ namespace System.Threading
"A QueueUserWorkItemCallbackDefaultContext was never called!");
}
- void MarkExecuted(bool aborted)
+ private void MarkExecuted(bool aborted)
{
GC.SuppressFinalize(this);
Debug.Assert(
@@ -1001,7 +1000,7 @@ namespace System.Threading
void IThreadPoolWorkItem.ExecuteWorkItem()
{
#if DEBUG
- MarkExecuted(aborted:false);
+ MarkExecuted(aborted: false);
#endif
ExecutionContext.Run(ExecutionContext.Default, ccb, this);
}
@@ -1011,7 +1010,7 @@ 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(aborted:true);
+ MarkExecuted(aborted: true);
#endif
}
@@ -1029,9 +1028,9 @@ namespace System.Threading
internal class _ThreadPoolWaitOrTimerCallback
{
- WaitOrTimerCallback _waitOrTimerCallback;
- ExecutionContext _executionContext;
- Object _state;
+ private WaitOrTimerCallback _waitOrTimerCallback;
+ private ExecutionContext _executionContext;
+ private Object _state;
private static readonly ContextCallback _ccbt = new ContextCallback(WaitOrTimerCallback_Context_t);
private static readonly ContextCallback _ccbf = new ContextCallback(WaitOrTimerCallback_Context_f);
@@ -1046,23 +1045,23 @@ namespace System.Threading
_executionContext = ExecutionContext.Capture();
}
}
-
+
private static void WaitOrTimerCallback_Context_t(Object state) =>
- WaitOrTimerCallback_Context(state, timedOut:true);
+ WaitOrTimerCallback_Context(state, timedOut: true);
private static void WaitOrTimerCallback_Context_f(Object state) =>
- WaitOrTimerCallback_Context(state, timedOut:false);
+ WaitOrTimerCallback_Context(state, timedOut: false);
private static void WaitOrTimerCallback_Context(Object state, bool timedOut)
{
_ThreadPoolWaitOrTimerCallback helper = (_ThreadPoolWaitOrTimerCallback)state;
helper._waitOrTimerCallback(helper._state, timedOut);
}
-
+
// call back helper
internal static void PerformWaitOrTimerCallback(Object state, bool timedOut)
{
- _ThreadPoolWaitOrTimerCallback helper = (_ThreadPoolWaitOrTimerCallback)state;
+ _ThreadPoolWaitOrTimerCallback helper = (_ThreadPoolWaitOrTimerCallback)state;
Debug.Assert(helper != null, "Null state passed to PerformWaitOrTimerCallback!");
// call directly if it is an unsafe call OR EC flow is suppressed
if (helper._executionContext == null)
@@ -1074,15 +1073,14 @@ namespace System.Threading
{
ExecutionContext.Run(helper._executionContext, timedOut ? _ccbt : _ccbf, helper);
}
- }
-
+ }
}
[CLSCompliant(false)]
unsafe public delegate void IOCompletionCallback(uint errorCode, // Error code
uint numBytes, // No. of bytes transferred
NativeOverlapped* pOVERLAP // ptr to OVERLAP structure
- );
+ );
public static class ThreadPool
{
@@ -1112,42 +1110,42 @@ namespace System.Threading
}
[CLSCompliant(false)]
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
+ [System.Security.DynamicSecurityMethod] // Methods containing StackCrawlMark local var has to be marked DynamicSecurityMethod
public static RegisteredWaitHandle RegisterWaitForSingleObject( // throws RegisterWaitException
- WaitHandle waitObject,
- WaitOrTimerCallback callBack,
- Object state,
- uint millisecondsTimeOutInterval,
- bool executeOnlyOnce // NOTE: we do not allow other options that allow the callback to be queued as an APC
+ WaitHandle waitObject,
+ WaitOrTimerCallback callBack,
+ Object state,
+ uint millisecondsTimeOutInterval,
+ bool executeOnlyOnce // NOTE: we do not allow other options that allow the callback to be queued as an APC
)
{
StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return RegisterWaitForSingleObject(waitObject,callBack,state,millisecondsTimeOutInterval,executeOnlyOnce,ref stackMark,true);
+ return RegisterWaitForSingleObject(waitObject, callBack, state, millisecondsTimeOutInterval, executeOnlyOnce, ref stackMark, true);
}
[CLSCompliant(false)]
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
+ [System.Security.DynamicSecurityMethod] // Methods containing StackCrawlMark local var has to be marked DynamicSecurityMethod
public static RegisteredWaitHandle UnsafeRegisterWaitForSingleObject( // throws RegisterWaitException
- WaitHandle waitObject,
- WaitOrTimerCallback callBack,
- Object state,
- uint millisecondsTimeOutInterval,
- bool executeOnlyOnce // NOTE: we do not allow other options that allow the callback to be queued as an APC
+ WaitHandle waitObject,
+ WaitOrTimerCallback callBack,
+ Object state,
+ uint millisecondsTimeOutInterval,
+ bool executeOnlyOnce // NOTE: we do not allow other options that allow the callback to be queued as an APC
)
{
StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return RegisterWaitForSingleObject(waitObject,callBack,state,millisecondsTimeOutInterval,executeOnlyOnce,ref stackMark,false);
+ return RegisterWaitForSingleObject(waitObject, callBack, state, millisecondsTimeOutInterval, executeOnlyOnce, ref stackMark, false);
}
private static RegisteredWaitHandle RegisterWaitForSingleObject( // throws RegisterWaitException
- WaitHandle waitObject,
- WaitOrTimerCallback callBack,
- Object state,
- uint millisecondsTimeOutInterval,
- bool executeOnlyOnce, // NOTE: we do not allow other options that allow the callback to be queued as an APC
+ WaitHandle waitObject,
+ WaitOrTimerCallback callBack,
+ Object state,
+ uint millisecondsTimeOutInterval,
+ bool executeOnlyOnce, // NOTE: we do not allow other options that allow the callback to be queued as an APC
ref StackCrawlMark stackMark,
- bool compressStack
+ bool compressStack
)
{
RegisteredWaitHandle registeredWaitHandle = new RegisteredWaitHandle();
@@ -1160,7 +1158,7 @@ namespace System.Threading
// this could occur if callback were to fire before SetWaitObject does its addref
registeredWaitHandle.SetWaitObject(waitObject);
IntPtr nativeRegisteredWaitHandle = RegisterWaitForSingleObjectNative(waitObject,
- state,
+ state,
millisecondsTimeOutInterval,
executeOnlyOnce,
registeredWaitHandle,
@@ -1176,104 +1174,104 @@ namespace System.Threading
}
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
+ [System.Security.DynamicSecurityMethod] // Methods containing StackCrawlMark local var has to be marked DynamicSecurityMethod
public static RegisteredWaitHandle RegisterWaitForSingleObject( // throws RegisterWaitException
- WaitHandle waitObject,
- WaitOrTimerCallback callBack,
- Object state,
- int millisecondsTimeOutInterval,
- bool executeOnlyOnce // NOTE: we do not allow other options that allow the callback to be queued as an APC
+ WaitHandle waitObject,
+ WaitOrTimerCallback callBack,
+ Object state,
+ int millisecondsTimeOutInterval,
+ bool executeOnlyOnce // NOTE: we do not allow other options that allow the callback to be queued as an APC
)
{
if (millisecondsTimeOutInterval < -1)
- throw new ArgumentOutOfRangeException(nameof(millisecondsTimeOutInterval), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
+ throw new ArgumentOutOfRangeException(nameof(millisecondsTimeOutInterval), SR.ArgumentOutOfRange_NeedNonNegOrNegative1);
Contract.EndContractBlock();
StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return RegisterWaitForSingleObject(waitObject,callBack,state,(UInt32)millisecondsTimeOutInterval,executeOnlyOnce,ref stackMark,true);
+ return RegisterWaitForSingleObject(waitObject, callBack, state, (UInt32)millisecondsTimeOutInterval, executeOnlyOnce, ref stackMark, true);
}
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
+ [System.Security.DynamicSecurityMethod] // Methods containing StackCrawlMark local var has to be marked DynamicSecurityMethod
public static RegisteredWaitHandle UnsafeRegisterWaitForSingleObject( // throws RegisterWaitException
- WaitHandle waitObject,
- WaitOrTimerCallback callBack,
- Object state,
- int millisecondsTimeOutInterval,
- bool executeOnlyOnce // NOTE: we do not allow other options that allow the callback to be queued as an APC
+ WaitHandle waitObject,
+ WaitOrTimerCallback callBack,
+ Object state,
+ int millisecondsTimeOutInterval,
+ bool executeOnlyOnce // NOTE: we do not allow other options that allow the callback to be queued as an APC
)
{
if (millisecondsTimeOutInterval < -1)
- throw new ArgumentOutOfRangeException(nameof(millisecondsTimeOutInterval), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
+ throw new ArgumentOutOfRangeException(nameof(millisecondsTimeOutInterval), SR.ArgumentOutOfRange_NeedNonNegOrNegative1);
Contract.EndContractBlock();
StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return RegisterWaitForSingleObject(waitObject,callBack,state,(UInt32)millisecondsTimeOutInterval,executeOnlyOnce,ref stackMark,false);
+ return RegisterWaitForSingleObject(waitObject, callBack, state, (UInt32)millisecondsTimeOutInterval, executeOnlyOnce, ref stackMark, false);
}
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
+ [System.Security.DynamicSecurityMethod] // Methods containing StackCrawlMark local var has to be marked DynamicSecurityMethod
public static RegisteredWaitHandle RegisterWaitForSingleObject( // throws RegisterWaitException
- WaitHandle waitObject,
+ WaitHandle waitObject,
WaitOrTimerCallback callBack,
- Object state,
- long millisecondsTimeOutInterval,
- bool executeOnlyOnce // NOTE: we do not allow other options that allow the callback to be queued as an APC
+ Object state,
+ long millisecondsTimeOutInterval,
+ bool executeOnlyOnce // NOTE: we do not allow other options that allow the callback to be queued as an APC
)
{
if (millisecondsTimeOutInterval < -1)
- throw new ArgumentOutOfRangeException(nameof(millisecondsTimeOutInterval), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
+ throw new ArgumentOutOfRangeException(nameof(millisecondsTimeOutInterval), SR.ArgumentOutOfRange_NeedNonNegOrNegative1);
Contract.EndContractBlock();
StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return RegisterWaitForSingleObject(waitObject,callBack,state,(UInt32)millisecondsTimeOutInterval,executeOnlyOnce,ref stackMark,true);
+ return RegisterWaitForSingleObject(waitObject, callBack, state, (UInt32)millisecondsTimeOutInterval, executeOnlyOnce, ref stackMark, true);
}
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
+ [System.Security.DynamicSecurityMethod] // Methods containing StackCrawlMark local var has to be marked DynamicSecurityMethod
public static RegisteredWaitHandle UnsafeRegisterWaitForSingleObject( // throws RegisterWaitException
- WaitHandle waitObject,
+ WaitHandle waitObject,
WaitOrTimerCallback callBack,
- Object state,
- long millisecondsTimeOutInterval,
- bool executeOnlyOnce // NOTE: we do not allow other options that allow the callback to be queued as an APC
+ Object state,
+ long millisecondsTimeOutInterval,
+ bool executeOnlyOnce // NOTE: we do not allow other options that allow the callback to be queued as an APC
)
{
if (millisecondsTimeOutInterval < -1)
- throw new ArgumentOutOfRangeException(nameof(millisecondsTimeOutInterval), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
+ throw new ArgumentOutOfRangeException(nameof(millisecondsTimeOutInterval), SR.ArgumentOutOfRange_NeedNonNegOrNegative1);
Contract.EndContractBlock();
StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return RegisterWaitForSingleObject(waitObject,callBack,state,(UInt32)millisecondsTimeOutInterval,executeOnlyOnce,ref stackMark,false);
+ return RegisterWaitForSingleObject(waitObject, callBack, state, (UInt32)millisecondsTimeOutInterval, executeOnlyOnce, ref stackMark, false);
}
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
+ [System.Security.DynamicSecurityMethod] // Methods containing StackCrawlMark local var has to be marked DynamicSecurityMethod
public static RegisteredWaitHandle RegisterWaitForSingleObject(
- WaitHandle waitObject,
- WaitOrTimerCallback callBack,
- Object state,
- TimeSpan timeout,
- bool executeOnlyOnce
+ WaitHandle waitObject,
+ WaitOrTimerCallback callBack,
+ Object state,
+ TimeSpan timeout,
+ bool executeOnlyOnce
)
{
long tm = (long)timeout.TotalMilliseconds;
if (tm < -1)
- throw new ArgumentOutOfRangeException(nameof(timeout), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
- if (tm > (long) Int32.MaxValue)
- throw new ArgumentOutOfRangeException(nameof(timeout), Environment.GetResourceString("ArgumentOutOfRange_LessEqualToIntegerMaxVal"));
+ throw new ArgumentOutOfRangeException(nameof(timeout), SR.ArgumentOutOfRange_NeedNonNegOrNegative1);
+ if (tm > (long)Int32.MaxValue)
+ throw new ArgumentOutOfRangeException(nameof(timeout), SR.ArgumentOutOfRange_LessEqualToIntegerMaxVal);
StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return RegisterWaitForSingleObject(waitObject,callBack,state,(UInt32)tm,executeOnlyOnce,ref stackMark,true);
+ return RegisterWaitForSingleObject(waitObject, callBack, state, (UInt32)tm, executeOnlyOnce, ref stackMark, true);
}
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
+ [System.Security.DynamicSecurityMethod] // Methods containing StackCrawlMark local var has to be marked DynamicSecurityMethod
public static RegisteredWaitHandle UnsafeRegisterWaitForSingleObject(
- WaitHandle waitObject,
- WaitOrTimerCallback callBack,
- Object state,
- TimeSpan timeout,
- bool executeOnlyOnce
+ WaitHandle waitObject,
+ WaitOrTimerCallback callBack,
+ Object state,
+ TimeSpan timeout,
+ bool executeOnlyOnce
)
{
long tm = (long)timeout.TotalMilliseconds;
if (tm < -1)
- throw new ArgumentOutOfRangeException(nameof(timeout), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
- if (tm > (long) Int32.MaxValue)
- throw new ArgumentOutOfRangeException(nameof(timeout), Environment.GetResourceString("ArgumentOutOfRange_LessEqualToIntegerMaxVal"));
+ throw new ArgumentOutOfRangeException(nameof(timeout), SR.ArgumentOutOfRange_NeedNonNegOrNegative1);
+ if (tm > (long)Int32.MaxValue)
+ throw new ArgumentOutOfRangeException(nameof(timeout), SR.ArgumentOutOfRange_LessEqualToIntegerMaxVal);
StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return RegisterWaitForSingleObject(waitObject,callBack,state,(UInt32)tm,executeOnlyOnce,ref stackMark,false);
+ return RegisterWaitForSingleObject(waitObject, callBack, state, (UInt32)tm, executeOnlyOnce, ref stackMark, false);
}
public static bool QueueUserWorkItem(WaitCallback callBack) =>
@@ -1428,7 +1426,7 @@ namespace System.Threading
EnsureVMInitializedCore(); // separate out to help with inlining
}
}
-
+
private static void EnsureVMInitializedCore()
{
ThreadPool.InitializeVMTp(ref ThreadPoolGlobals.enableWorkerTracking);
@@ -1436,7 +1434,7 @@ namespace System.Threading
}
// Native methods:
-
+
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private static extern bool SetMinThreadsNative(int workerThreads, int completionPortThreads);
@@ -1468,22 +1466,19 @@ namespace System.Threading
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern void NotifyWorkItemProgressNative();
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- internal static extern bool IsThreadPoolHosted();
-
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
[SuppressUnmanagedCodeSecurity]
private static extern void InitializeVMTp(ref bool enableWorkerTracking);
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- private static extern IntPtr RegisterWaitForSingleObjectNative(
- WaitHandle waitHandle,
- Object state,
- uint timeOutInterval,
- bool executeOnlyOnce,
- RegisteredWaitHandle registeredWaitHandle,
- ref StackCrawlMark stackMark,
- bool compressStack
+ private static extern IntPtr RegisterWaitForSingleObjectNative(
+ WaitHandle waitHandle,
+ Object state,
+ uint timeOutInterval,
+ bool executeOnlyOnce,
+ RegisteredWaitHandle registeredWaitHandle,
+ ref StackCrawlMark stackMark,
+ bool compressStack
);
@@ -1497,15 +1492,17 @@ namespace System.Threading
{
if (osHandle == null)
throw new ArgumentNullException(nameof(osHandle));
-
+
bool ret = false;
bool mustReleaseSafeHandle = false;
RuntimeHelpers.PrepareConstrainedRegions();
- try {
+ try
+ {
osHandle.DangerousAddRef(ref mustReleaseSafeHandle);
ret = BindIOCompletionCallbackNative(osHandle.DangerousGetHandle());
}
- finally {
+ finally
+ {
if (mustReleaseSafeHandle)
osHandle.DangerousRelease();
}
diff --git a/src/mscorlib/src/System/Threading/ThreadPriority.cs b/src/mscorlib/src/System/Threading/ThreadPriority.cs
deleted file mode 100644
index 6303c2fd94..0000000000
--- a/src/mscorlib/src/System/Threading/ThreadPriority.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.
-
-//
-/*=============================================================================
-**
-**
-**
-** Purpose: Enums for the priorities of a Thread
-**
-**
-=============================================================================*/
-
-namespace System.Threading {
- using System.Threading;
-
- [Serializable]
- public enum ThreadPriority
- {
- /*=========================================================================
- ** Constants for thread priorities.
- =========================================================================*/
- Lowest = 0,
- BelowNormal = 1,
- Normal = 2,
- AboveNormal = 3,
- Highest = 4
-
- }
-}
diff --git a/src/mscorlib/src/System/Threading/ThreadStart.cs b/src/mscorlib/src/System/Threading/ThreadStart.cs
deleted file mode 100644
index e4beddcd75..0000000000
--- a/src/mscorlib/src/System/Threading/ThreadStart.cs
+++ /dev/null
@@ -1,23 +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: This class is a Delegate which defines the start method
-** for starting a thread. That method must match this delegate.
-**
-**
-=============================================================================*/
-
-namespace System.Threading {
- using System.Threading;
-
- // Define the delegate
- // NOTE: If you change the signature here, there is code in COMSynchronization
- // that invokes this delegate in native.
- public delegate void ThreadStart();
-}
diff --git a/src/mscorlib/src/System/Threading/ThreadStartException.cs b/src/mscorlib/src/System/Threading/ThreadStartException.cs
deleted file mode 100644
index 33fb460b3d..0000000000
--- a/src/mscorlib/src/System/Threading/ThreadStartException.cs
+++ /dev/null
@@ -1,37 +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.
-
-//
-
-namespace System.Threading
-{
- using System;
- using System.Runtime.Serialization;
- using System.Runtime.InteropServices;
-
- [Serializable]
- public sealed class ThreadStartException : SystemException
- {
- private ThreadStartException()
- : base(Environment.GetResourceString("Arg_ThreadStartException"))
- {
- SetErrorCode(__HResults.COR_E_THREADSTART);
- }
-
- private ThreadStartException(Exception reason)
- : base(Environment.GetResourceString("Arg_ThreadStartException"), reason)
- {
- SetErrorCode(__HResults.COR_E_THREADSTART);
- }
-
- //required for serialization
- internal ThreadStartException(SerializationInfo info, StreamingContext context)
- : base(info, context)
- {
- }
-
- }
-}
-
-
diff --git a/src/mscorlib/src/System/Threading/ThreadState.cs b/src/mscorlib/src/System/Threading/ThreadState.cs
deleted file mode 100644
index 2d953f384a..0000000000
--- a/src/mscorlib/src/System/Threading/ThreadState.cs
+++ /dev/null
@@ -1,35 +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: Enum to represent the different thread states
-**
-**
-=============================================================================*/
-
-namespace System.Threading {
-
-[Serializable]
-[Flags]
- public enum ThreadState
- {
- /*=========================================================================
- ** Constants for thread states.
- =========================================================================*/
- Running = 0,
- StopRequested = 1,
- SuspendRequested = 2,
- Background = 4,
- Unstarted = 8,
- Stopped = 16,
- WaitSleepJoin = 32,
- Suspended = 64,
- AbortRequested = 128,
- Aborted = 256
- }
-}
diff --git a/src/mscorlib/src/System/Threading/ThreadStateException.cs b/src/mscorlib/src/System/Threading/ThreadStateException.cs
deleted file mode 100644
index 97c03ce06c..0000000000
--- a/src/mscorlib/src/System/Threading/ThreadStateException.cs
+++ /dev/null
@@ -1,40 +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: An exception class to indicate that the Thread class is in an
-** invalid state for the method.
-**
-**
-=============================================================================*/
-
-namespace System.Threading {
- using System;
- using System.Runtime.Serialization;
- [Serializable]
- public class ThreadStateException : SystemException {
- public ThreadStateException()
- : base(Environment.GetResourceString("Arg_ThreadStateException")) {
- SetErrorCode(__HResults.COR_E_THREADSTATE);
- }
-
- public ThreadStateException(String message)
- : base(message) {
- SetErrorCode(__HResults.COR_E_THREADSTATE);
- }
-
- public ThreadStateException(String message, Exception innerException)
- : base(message, innerException) {
- SetErrorCode(__HResults.COR_E_THREADSTATE);
- }
-
- protected ThreadStateException(SerializationInfo info, StreamingContext context) : base (info, context) {
- }
- }
-
-}
diff --git a/src/mscorlib/src/System/Threading/Timeout.cs b/src/mscorlib/src/System/Threading/Timeout.cs
deleted file mode 100644
index 80bdbccf4e..0000000000
--- a/src/mscorlib/src/System/Threading/Timeout.cs
+++ /dev/null
@@ -1,19 +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.
-
-namespace System.Threading {
- using System.Threading;
- using System;
- // A constant used by methods that take a timeout (Object.Wait, Thread.Sleep
- // etc) to indicate that no timeout should occur.
- //
- public static class Timeout
- {
- public static readonly TimeSpan InfiniteTimeSpan = new TimeSpan(0, 0, 0, 0, Timeout.Infinite);
-
- public const int Infinite = -1;
- internal const uint UnsignedInfinite = unchecked((uint)-1);
- }
-
-}
diff --git a/src/mscorlib/src/System/Threading/Timer.cs b/src/mscorlib/src/System/Threading/Timer.cs
index 93d2922799..960f815d64 100644
--- a/src/mscorlib/src/System/Threading/Timer.cs
+++ b/src/mscorlib/src/System/Threading/Timer.cs
@@ -4,7 +4,7 @@
//
-namespace System.Threading
+namespace System.Threading
{
using System;
using System.Security;
@@ -19,7 +19,7 @@ namespace System.Threading
using Microsoft.Win32.SafeHandles;
-
+
public delegate void TimerCallback(Object state);
//
@@ -43,12 +43,12 @@ namespace System.Threading
//
// Note that all instance methods of this class require that the caller hold a lock on TimerQueue.Instance.
//
- class TimerQueue
+ internal class TimerQueue
{
#region singleton pattern implementation
// The one-and-only TimerQueue for the AppDomain.
- static TimerQueue s_queue = new TimerQueue();
+ private static TimerQueue s_queue = new TimerQueue();
public static TimerQueue Instance
{
@@ -100,7 +100,7 @@ namespace System.Threading
//
// We use a SafeHandle to ensure that the native timer is destroyed when the AppDomain is unloaded.
//
- class AppDomainTimerSafeHandle : SafeHandleZeroOrMinusOneIsInvalid
+ private class AppDomainTimerSafeHandle : SafeHandleZeroOrMinusOneIsInvalid
{
public AppDomainTimerSafeHandle()
: base(true)
@@ -113,11 +113,11 @@ namespace System.Threading
}
}
- AppDomainTimerSafeHandle m_appDomainTimer;
+ private AppDomainTimerSafeHandle m_appDomainTimer;
- bool m_isAppDomainTimerScheduled;
- int m_currentAppDomainTimerStartTicks;
- uint m_currentAppDomainTimerDuration;
+ private bool m_isAppDomainTimerScheduled;
+ private int m_currentAppDomainTimerStartTicks;
+ private uint m_currentAppDomainTimerDuration;
private bool EnsureAppDomainTimerFiresBy(uint requestedDuration)
{
@@ -145,13 +145,13 @@ namespace System.Threading
// If Pause is underway then do not schedule the timers
// A later update during resume will re-schedule
- if(m_pauseTicks != 0)
+ if (m_pauseTicks != 0)
{
Debug.Assert(!m_isAppDomainTimerScheduled);
Debug.Assert(m_appDomainTimer == null);
return true;
}
-
+
if (m_appDomainTimer == null || m_appDomainTimer.IsInvalid)
{
Debug.Assert(!m_isAppDomainTimerScheduled);
@@ -195,15 +195,15 @@ namespace System.Threading
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
[SuppressUnmanagedCodeSecurity]
- static extern AppDomainTimerSafeHandle CreateAppDomainTimer(uint dueTime);
+ private static extern AppDomainTimerSafeHandle CreateAppDomainTimer(uint dueTime);
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
[SuppressUnmanagedCodeSecurity]
- static extern bool ChangeAppDomainTimer(AppDomainTimerSafeHandle handle, uint dueTime);
+ private static extern bool ChangeAppDomainTimer(AppDomainTimerSafeHandle handle, uint dueTime);
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
[SuppressUnmanagedCodeSecurity]
- static extern bool DeleteAppDomainTimer(IntPtr handle);
+ private static extern bool DeleteAppDomainTimer(IntPtr handle);
#endregion
@@ -212,10 +212,10 @@ namespace System.Threading
//
// The list of timers
//
- TimerQueueTimer m_timers;
+ private TimerQueueTimer m_timers;
- volatile int m_pauseTicks = 0; // Time when Pause was called
+ private volatile int m_pauseTicks = 0; // Time when Pause was called
//
@@ -386,7 +386,7 @@ namespace System.Threading
//
// A timer in our TimerQueue.
//
- sealed class TimerQueueTimer
+ internal sealed class TimerQueueTimer
{
//
// All fields of this class are protected by a lock on TimerQueue.Instance.
@@ -414,9 +414,9 @@ namespace System.Threading
//
// Info about the user's callback
//
- readonly TimerCallback m_timerCallback;
- readonly Object m_state;
- readonly ExecutionContext m_executionContext;
+ private readonly TimerCallback m_timerCallback;
+ private readonly Object m_state;
+ private readonly ExecutionContext m_executionContext;
//
@@ -426,9 +426,9 @@ namespace System.Threading
// m_callbacksRunning. We set m_notifyWhenNoCallbacksRunning only when m_callbacksRunning
// reaches zero.
//
- int m_callbacksRunning;
- volatile bool m_canceled;
- volatile WaitHandle m_notifyWhenNoCallbacksRunning;
+ private int m_callbacksRunning;
+ private volatile bool m_canceled;
+ private volatile WaitHandle m_notifyWhenNoCallbacksRunning;
internal TimerQueueTimer(TimerCallback timerCallback, object state, uint dueTime, uint period)
@@ -455,7 +455,7 @@ namespace System.Threading
lock (TimerQueue.Instance)
{
if (m_canceled)
- throw new ObjectDisposedException(null, Environment.GetResourceString("ObjectDisposed_Generic"));
+ throw new ObjectDisposedException(null, SR.ObjectDisposed_Generic);
// prevent ThreadAbort while updating state
try { }
@@ -612,17 +612,17 @@ namespace System.Threading
// change, because any code that happened to be suppressing finalization of Timer objects would now
// unwittingly be changing the lifetime of those timers.
//
- sealed class TimerHolder
+ internal sealed class TimerHolder
{
internal TimerQueueTimer m_timer;
-
- public TimerHolder(TimerQueueTimer timer)
- {
- m_timer = timer;
+
+ public TimerHolder(TimerQueueTimer timer)
+ {
+ m_timer = timer;
}
- ~TimerHolder()
- {
+ ~TimerHolder()
+ {
//
// If shutdown has started, another thread may be suspended while holding the timer lock.
// So we can't safely close the timer.
@@ -636,7 +636,7 @@ namespace System.Threading
if (Environment.HasShutdownStarted || AppDomain.CurrentDomain.IsFinalizingForUnload())
return;
- m_timer.Close();
+ m_timer.Close();
}
public void Close()
@@ -651,7 +651,6 @@ namespace System.Threading
GC.SuppressFinalize(this);
return result;
}
-
}
@@ -661,64 +660,64 @@ namespace System.Threading
private TimerHolder m_timer;
- public Timer(TimerCallback callback,
- Object state,
- int dueTime,
- int period)
+ public Timer(TimerCallback callback,
+ Object state,
+ int dueTime,
+ int period)
{
if (dueTime < -1)
- throw new ArgumentOutOfRangeException(nameof(dueTime), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
- if (period < -1 )
- throw new ArgumentOutOfRangeException(nameof(period), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
+ throw new ArgumentOutOfRangeException(nameof(dueTime), SR.ArgumentOutOfRange_NeedNonNegOrNegative1);
+ if (period < -1)
+ throw new ArgumentOutOfRangeException(nameof(period), SR.ArgumentOutOfRange_NeedNonNegOrNegative1);
Contract.EndContractBlock();
- TimerSetup(callback,state,(UInt32)dueTime,(UInt32)period);
+ TimerSetup(callback, state, (UInt32)dueTime, (UInt32)period);
}
- public Timer(TimerCallback callback,
- Object state,
- TimeSpan dueTime,
- TimeSpan period)
- {
+ public Timer(TimerCallback callback,
+ Object state,
+ TimeSpan dueTime,
+ TimeSpan period)
+ {
long dueTm = (long)dueTime.TotalMilliseconds;
if (dueTm < -1)
- throw new ArgumentOutOfRangeException(nameof(dueTm),Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
+ throw new ArgumentOutOfRangeException(nameof(dueTm), SR.ArgumentOutOfRange_NeedNonNegOrNegative1);
if (dueTm > MAX_SUPPORTED_TIMEOUT)
- throw new ArgumentOutOfRangeException(nameof(dueTm),Environment.GetResourceString("ArgumentOutOfRange_TimeoutTooLarge"));
+ throw new ArgumentOutOfRangeException(nameof(dueTm), SR.ArgumentOutOfRange_TimeoutTooLarge);
long periodTm = (long)period.TotalMilliseconds;
if (periodTm < -1)
- throw new ArgumentOutOfRangeException(nameof(periodTm),Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
+ throw new ArgumentOutOfRangeException(nameof(periodTm), SR.ArgumentOutOfRange_NeedNonNegOrNegative1);
if (periodTm > MAX_SUPPORTED_TIMEOUT)
- throw new ArgumentOutOfRangeException(nameof(periodTm),Environment.GetResourceString("ArgumentOutOfRange_PeriodTooLarge"));
+ throw new ArgumentOutOfRangeException(nameof(periodTm), SR.ArgumentOutOfRange_PeriodTooLarge);
- TimerSetup(callback,state,(UInt32)dueTm,(UInt32)periodTm);
+ TimerSetup(callback, state, (UInt32)dueTm, (UInt32)periodTm);
}
[CLSCompliant(false)]
- public Timer(TimerCallback callback,
- Object state,
- UInt32 dueTime,
- UInt32 period)
+ public Timer(TimerCallback callback,
+ Object state,
+ UInt32 dueTime,
+ UInt32 period)
{
- TimerSetup(callback,state,dueTime,period);
+ TimerSetup(callback, state, dueTime, period);
}
- public Timer(TimerCallback callback,
- Object state,
- long dueTime,
- long period)
+ public Timer(TimerCallback callback,
+ Object state,
+ long dueTime,
+ long period)
{
if (dueTime < -1)
- throw new ArgumentOutOfRangeException(nameof(dueTime),Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
+ throw new ArgumentOutOfRangeException(nameof(dueTime), SR.ArgumentOutOfRange_NeedNonNegOrNegative1);
if (period < -1)
- throw new ArgumentOutOfRangeException(nameof(period),Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
+ throw new ArgumentOutOfRangeException(nameof(period), SR.ArgumentOutOfRange_NeedNonNegOrNegative1);
if (dueTime > MAX_SUPPORTED_TIMEOUT)
- throw new ArgumentOutOfRangeException(nameof(dueTime),Environment.GetResourceString("ArgumentOutOfRange_TimeoutTooLarge"));
+ throw new ArgumentOutOfRangeException(nameof(dueTime), SR.ArgumentOutOfRange_TimeoutTooLarge);
if (period > MAX_SUPPORTED_TIMEOUT)
- throw new ArgumentOutOfRangeException(nameof(period),Environment.GetResourceString("ArgumentOutOfRange_PeriodTooLarge"));
+ throw new ArgumentOutOfRangeException(nameof(period), SR.ArgumentOutOfRange_PeriodTooLarge);
Contract.EndContractBlock();
- TimerSetup(callback,state,(UInt32) dueTime, (UInt32) period);
+ TimerSetup(callback, state, (UInt32)dueTime, (UInt32)period);
}
public Timer(TimerCallback callback)
@@ -727,12 +726,12 @@ namespace System.Threading
int period = -1; // Change after a timer instance is created. This is to avoid the potential
// for a timer to be fired before the returned value is assigned to the variable,
// potentially causing the callback to reference a bogus value (if passing the timer to the callback).
-
+
TimerSetup(callback, this, (UInt32)dueTime, (UInt32)period);
}
private void TimerSetup(TimerCallback callback,
- Object state,
+ Object state,
UInt32 dueTime,
UInt32 period)
{
@@ -742,13 +741,13 @@ namespace System.Threading
m_timer = new TimerHolder(new TimerQueueTimer(callback, state, dueTime, period));
}
-
+
public bool Change(int dueTime, int period)
{
- if (dueTime < -1 )
- throw new ArgumentOutOfRangeException(nameof(dueTime),Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
+ if (dueTime < -1)
+ throw new ArgumentOutOfRangeException(nameof(dueTime), SR.ArgumentOutOfRange_NeedNonNegOrNegative1);
if (period < -1)
- throw new ArgumentOutOfRangeException(nameof(period),Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
+ throw new ArgumentOutOfRangeException(nameof(period), SR.ArgumentOutOfRange_NeedNonNegOrNegative1);
Contract.EndContractBlock();
return m_timer.m_timer.Change((UInt32)dueTime, (UInt32)period);
@@ -756,7 +755,7 @@ namespace System.Threading
public bool Change(TimeSpan dueTime, TimeSpan period)
{
- return Change((long) dueTime.TotalMilliseconds, (long) period.TotalMilliseconds);
+ return Change((long)dueTime.TotalMilliseconds, (long)period.TotalMilliseconds);
}
[CLSCompliant(false)]
@@ -767,28 +766,28 @@ namespace System.Threading
public bool Change(long dueTime, long period)
{
- if (dueTime < -1 )
- throw new ArgumentOutOfRangeException(nameof(dueTime), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
+ if (dueTime < -1)
+ throw new ArgumentOutOfRangeException(nameof(dueTime), SR.ArgumentOutOfRange_NeedNonNegOrNegative1);
if (period < -1)
- throw new ArgumentOutOfRangeException(nameof(period), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
+ throw new ArgumentOutOfRangeException(nameof(period), SR.ArgumentOutOfRange_NeedNonNegOrNegative1);
if (dueTime > MAX_SUPPORTED_TIMEOUT)
- throw new ArgumentOutOfRangeException(nameof(dueTime), Environment.GetResourceString("ArgumentOutOfRange_TimeoutTooLarge"));
+ throw new ArgumentOutOfRangeException(nameof(dueTime), SR.ArgumentOutOfRange_TimeoutTooLarge);
if (period > MAX_SUPPORTED_TIMEOUT)
- throw new ArgumentOutOfRangeException(nameof(period), Environment.GetResourceString("ArgumentOutOfRange_PeriodTooLarge"));
+ throw new ArgumentOutOfRangeException(nameof(period), SR.ArgumentOutOfRange_PeriodTooLarge);
Contract.EndContractBlock();
return m_timer.m_timer.Change((UInt32)dueTime, (UInt32)period);
}
-
+
public bool Dispose(WaitHandle notifyObject)
{
- if (notifyObject==null)
+ if (notifyObject == null)
throw new ArgumentNullException(nameof(notifyObject));
Contract.EndContractBlock();
return m_timer.Close(notifyObject);
}
-
+
public void Dispose()
{
m_timer.Close();
diff --git a/src/mscorlib/src/System/Threading/Volatile.cs b/src/mscorlib/src/System/Threading/Volatile.cs
index c94a69ab7b..6aac8d63cd 100644
--- a/src/mscorlib/src/System/Threading/Volatile.cs
+++ b/src/mscorlib/src/System/Threading/Volatile.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
//
+
using System;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
@@ -33,7 +34,7 @@ namespace System.Threading
// The VM will replace this with a more efficient implementation.
//
var value = location;
- Thread.MemoryBarrier();
+ Interlocked.MemoryBarrier();
return value;
}
@@ -45,7 +46,7 @@ namespace System.Threading
// The VM will replace this with a more efficient implementation.
//
var value = location;
- Thread.MemoryBarrier();
+ Interlocked.MemoryBarrier();
return value;
}
@@ -56,7 +57,7 @@ namespace System.Threading
// The VM will replace this with a more efficient implementation.
//
var value = location;
- Thread.MemoryBarrier();
+ Interlocked.MemoryBarrier();
return value;
}
@@ -67,7 +68,7 @@ namespace System.Threading
// The VM will replace this with a more efficient implementation.
//
var value = location;
- Thread.MemoryBarrier();
+ Interlocked.MemoryBarrier();
return value;
}
@@ -79,7 +80,7 @@ namespace System.Threading
// The VM will replace this with a more efficient implementation.
//
var value = location;
- Thread.MemoryBarrier();
+ Interlocked.MemoryBarrier();
return value;
}
@@ -90,7 +91,7 @@ namespace System.Threading
// The VM will replace this with a more efficient implementation.
//
var value = location;
- Thread.MemoryBarrier();
+ Interlocked.MemoryBarrier();
return value;
}
@@ -102,7 +103,7 @@ namespace System.Threading
// The VM will replace this with a more efficient implementation.
//
var value = location;
- Thread.MemoryBarrier();
+ Interlocked.MemoryBarrier();
return value;
}
@@ -114,7 +115,7 @@ namespace System.Threading
// The VM will replace this with a more efficient implementation.
//
var value = location;
- Thread.MemoryBarrier();
+ Interlocked.MemoryBarrier();
return value;
}
@@ -126,7 +127,7 @@ namespace System.Threading
// The VM will replace this with a more efficient implementation.
//
var value = location;
- Thread.MemoryBarrier();
+ Interlocked.MemoryBarrier();
return value;
}
#else
@@ -165,7 +166,7 @@ namespace System.Threading
// The VM will replace this with a more efficient implementation.
//
var value = location;
- Thread.MemoryBarrier();
+ Interlocked.MemoryBarrier();
return value;
}
@@ -177,7 +178,7 @@ namespace System.Threading
// The VM will replace this with a more efficient implementation.
//
var value = location;
- Thread.MemoryBarrier();
+ Interlocked.MemoryBarrier();
return value;
}
@@ -188,7 +189,7 @@ namespace System.Threading
// The VM will replace this with a more efficient implementation.
//
var value = location;
- Thread.MemoryBarrier();
+ Interlocked.MemoryBarrier();
return value;
}
@@ -211,7 +212,7 @@ namespace System.Threading
// The VM will replace this with a more efficient implementation.
//
var value = location;
- Thread.MemoryBarrier();
+ Interlocked.MemoryBarrier();
return value;
}
@@ -224,7 +225,7 @@ namespace System.Threading
//
// The VM will replace this with a more efficient implementation.
//
- Thread.MemoryBarrier();
+ Interlocked.MemoryBarrier();
location = value;
}
@@ -235,7 +236,7 @@ namespace System.Threading
//
// The VM will replace this with a more efficient implementation.
//
- Thread.MemoryBarrier();
+ Interlocked.MemoryBarrier();
location = value;
}
@@ -245,7 +246,7 @@ namespace System.Threading
//
// The VM will replace this with a more efficient implementation.
//
- Thread.MemoryBarrier();
+ Interlocked.MemoryBarrier();
location = value;
}
@@ -255,7 +256,7 @@ namespace System.Threading
//
// The VM will replace this with a more efficient implementation.
//
- Thread.MemoryBarrier();
+ Interlocked.MemoryBarrier();
location = value;
}
@@ -266,7 +267,7 @@ namespace System.Threading
//
// The VM will replace this with a more efficient implementation.
//
- Thread.MemoryBarrier();
+ Interlocked.MemoryBarrier();
location = value;
}
@@ -276,7 +277,7 @@ namespace System.Threading
//
// The VM will replace this with a more efficient implementation.
//
- Thread.MemoryBarrier();
+ Interlocked.MemoryBarrier();
location = value;
}
@@ -287,7 +288,7 @@ namespace System.Threading
//
// The VM will replace this with a more efficient implementation.
//
- Thread.MemoryBarrier();
+ Interlocked.MemoryBarrier();
location = value;
}
@@ -298,7 +299,7 @@ namespace System.Threading
//
// The VM will replace this with a more efficient implementation.
//
- Thread.MemoryBarrier();
+ Interlocked.MemoryBarrier();
location = value;
}
@@ -309,7 +310,7 @@ namespace System.Threading
//
// The VM will replace this with a more efficient implementation.
//
- Thread.MemoryBarrier();
+ Interlocked.MemoryBarrier();
location = value;
}
#else
@@ -353,7 +354,7 @@ namespace System.Threading
//
// The VM will replace this with a more efficient implementation.
//
- Thread.MemoryBarrier();
+ Interlocked.MemoryBarrier();
location = value;
}
@@ -364,7 +365,7 @@ namespace System.Threading
//
// The VM will replace this with a more efficient implementation.
//
- Thread.MemoryBarrier();
+ Interlocked.MemoryBarrier();
location = value;
}
@@ -374,7 +375,7 @@ namespace System.Threading
//
// The VM will replace this with a more efficient implementation.
//
- Thread.MemoryBarrier();
+ Interlocked.MemoryBarrier();
location = value;
}
@@ -396,7 +397,7 @@ namespace System.Threading
//
// The VM will replace this with a more efficient implementation.
//
- Thread.MemoryBarrier();
+ Interlocked.MemoryBarrier();
location = value;
}
}
diff --git a/src/mscorlib/src/System/Threading/WaitHandle.cs b/src/mscorlib/src/System/Threading/WaitHandle.cs
index d4dcd710be..f3412d264f 100644
--- a/src/mscorlib/src/System/Threading/WaitHandle.cs
+++ b/src/mscorlib/src/System/Threading/WaitHandle.cs
@@ -26,8 +26,9 @@ namespace System.Threading
using System.Diagnostics.CodeAnalysis;
using Win32Native = Microsoft.Win32.Win32Native;
- public abstract class WaitHandle : MarshalByRefObject, IDisposable {
- public const int WaitTimeout = 0x102;
+ public abstract class WaitHandle : MarshalByRefObject, IDisposable
+ {
+ public const int WaitTimeout = 0x102;
private const int MAX_WAITHANDLES = 64;
@@ -57,7 +58,7 @@ namespace System.Threading
NameInvalid
}
- protected WaitHandle()
+ protected WaitHandle()
{
Init();
}
@@ -68,12 +69,12 @@ namespace System.Threading
waitHandle = InvalidHandle;
hasThreadAffinity = false;
}
-
-
+
+
[Obsolete("Use the SafeWaitHandle property instead.")]
- public virtual IntPtr Handle
+ public virtual IntPtr Handle
{
- get { return safeWaitHandle == null ? InvalidHandle : safeWaitHandle.DangerousGetHandle();}
+ get { return safeWaitHandle == null ? InvalidHandle : safeWaitHandle.DangerousGetHandle(); }
set
{
if (value == InvalidHandle)
@@ -92,13 +93,13 @@ namespace System.Threading
}
else
{
- safeWaitHandle = new SafeWaitHandle(value, true);
+ safeWaitHandle = new SafeWaitHandle(value, true);
}
waitHandle = value;
}
}
- public SafeWaitHandle SafeWaitHandle
+ public SafeWaitHandle SafeWaitHandle
{
get
{
@@ -111,23 +112,23 @@ namespace System.Threading
set
{
- // Set safeWaitHandle and waitHandle in a CER so we won't take
- // a thread abort between the statements and leave the wait
- // handle in an invalid state. Note this routine is not thread
- // safe however.
- RuntimeHelpers.PrepareConstrainedRegions();
+ // Set safeWaitHandle and waitHandle in a CER so we won't take
+ // a thread abort between the statements and leave the wait
+ // handle in an invalid state. Note this routine is not thread
+ // safe however.
+ RuntimeHelpers.PrepareConstrainedRegions();
try { }
finally
{
if (value == null)
{
- safeWaitHandle = null;
- waitHandle = InvalidHandle;
+ safeWaitHandle = null;
+ waitHandle = InvalidHandle;
}
else
{
- safeWaitHandle = value;
- waitHandle = safeWaitHandle.DangerousGetHandle();
+ safeWaitHandle = value;
+ waitHandle = safeWaitHandle.DangerousGetHandle();
}
}
}
@@ -147,41 +148,41 @@ namespace System.Threading
safeWaitHandle = handle;
waitHandle = handle.DangerousGetHandle();
}
-
- public virtual bool WaitOne (int millisecondsTimeout, bool exitContext)
+
+ public virtual bool WaitOne(int millisecondsTimeout, bool exitContext)
{
if (millisecondsTimeout < -1)
{
- throw new ArgumentOutOfRangeException(nameof(millisecondsTimeout), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
+ throw new ArgumentOutOfRangeException(nameof(millisecondsTimeout), SR.ArgumentOutOfRange_NeedNonNegOrNegative1);
}
Contract.EndContractBlock();
- return WaitOne((long)millisecondsTimeout,exitContext);
+ return WaitOne((long)millisecondsTimeout, exitContext);
}
- public virtual bool WaitOne (TimeSpan timeout, bool exitContext)
+ public virtual bool WaitOne(TimeSpan timeout, bool exitContext)
{
long tm = (long)timeout.TotalMilliseconds;
- if (-1 > tm || (long) Int32.MaxValue < tm)
+ if (-1 > tm || (long)Int32.MaxValue < tm)
{
- throw new ArgumentOutOfRangeException(nameof(timeout), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
+ throw new ArgumentOutOfRangeException(nameof(timeout), SR.ArgumentOutOfRange_NeedNonNegOrNegative1);
}
- return WaitOne(tm,exitContext);
+ return WaitOne(tm, exitContext);
}
- public virtual bool WaitOne ()
+ public virtual bool WaitOne()
{
//Infinite Timeout
- return WaitOne(-1,false);
+ return WaitOne(-1, false);
}
public virtual bool WaitOne(int millisecondsTimeout)
{
- return WaitOne(millisecondsTimeout, false);
+ return WaitOne(millisecondsTimeout, false);
}
public virtual bool WaitOne(TimeSpan timeout)
{
- return WaitOne(timeout, false);
+ return WaitOne(timeout, false);
}
[SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "Reviewed for thread-safety.")]
@@ -194,28 +195,28 @@ namespace System.Threading
{
if (waitableSafeHandle == null)
{
- throw new ObjectDisposedException(null, Environment.GetResourceString("ObjectDisposed_Generic"));
+ throw new ObjectDisposedException(null, SR.ObjectDisposed_Generic);
}
Contract.EndContractBlock();
int ret = WaitOneNative(waitableSafeHandle, (uint)millisecondsTimeout, hasThreadAffinity, exitContext);
- if(AppDomainPauseManager.IsPaused)
+ if (AppDomainPauseManager.IsPaused)
AppDomainPauseManager.ResumeEvent.WaitOneWithoutFAS();
-
+
if (ret == WAIT_ABANDONED)
{
ThrowAbandonedMutexException();
}
return (ret != WaitTimeout);
}
-
+
internal bool WaitOneWithoutFAS()
{
// version of waitone without fast application switch (FAS) support
// This is required to support the Wait which FAS needs (otherwise recursive dependency comes in)
if (safeWaitHandle == null)
{
- throw new ObjectDisposedException(null, Environment.GetResourceString("ObjectDisposed_Generic"));
+ throw new ObjectDisposedException(null, SR.ObjectDisposed_Generic);
}
Contract.EndContractBlock();
@@ -226,11 +227,11 @@ namespace System.Threading
ThrowAbandonedMutexException();
}
return (ret != WaitTimeout);
- }
+ }
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private static extern int WaitOneNative(SafeHandle waitableSafeHandle, uint millisecondsTimeout, bool hasThreadAffinity, bool exitContext);
-
+
/*========================================================================
** Waits for signal from all the objects.
** timeout indicates how long to wait before the method returns.
@@ -239,17 +240,17 @@ namespace System.Threading
** If exitContext is true then the synchronization domain for the context
** (if in a synchronized context) is exited before the wait and reacquired
========================================================================*/
-
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
+
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
private static extern int WaitMultiple(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext, bool WaitAll);
public static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext)
{
if (waitHandles == null)
{
- throw new ArgumentNullException(nameof(waitHandles), Environment.GetResourceString("ArgumentNull_Waithandles"));
+ throw new ArgumentNullException(nameof(waitHandles), SR.ArgumentNull_Waithandles);
}
- if(waitHandles.Length == 0)
+ if (waitHandles.Length == 0)
{
//
// Some history: in CLR 1.0 and 1.1, we threw ArgumentException in this case, which was correct.
@@ -260,24 +261,24 @@ namespace System.Threading
// in CoreCLR, and ArgumentNullException in the desktop CLR. This is ugly, but so is breaking
// user code.
//
- throw new ArgumentException(Environment.GetResourceString("Argument_EmptyWaithandleArray"));
+ throw new ArgumentException(SR.Argument_EmptyWaithandleArray);
}
if (waitHandles.Length > MAX_WAITHANDLES)
{
- throw new NotSupportedException(Environment.GetResourceString("NotSupported_MaxWaitHandles"));
+ throw new NotSupportedException(SR.NotSupported_MaxWaitHandles);
}
if (-1 > millisecondsTimeout)
{
- throw new ArgumentOutOfRangeException(nameof(millisecondsTimeout), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
+ throw new ArgumentOutOfRangeException(nameof(millisecondsTimeout), SR.ArgumentOutOfRange_NeedNonNegOrNegative1);
}
Contract.EndContractBlock();
WaitHandle[] internalWaitHandles = new WaitHandle[waitHandles.Length];
- for (int i = 0; i < waitHandles.Length; i ++)
+ for (int i = 0; i < waitHandles.Length; i++)
{
WaitHandle waitHandle = waitHandles[i];
if (waitHandle == null)
- throw new ArgumentNullException("waitHandles[" + i + "]", Environment.GetResourceString("ArgumentNull_ArrayElement"));
+ throw new ArgumentNullException("waitHandles[" + i + "]", SR.ArgumentNull_ArrayElement);
internalWaitHandles[i] = waitHandle;
}
@@ -288,51 +289,51 @@ namespace System.Threading
int ret = WaitMultiple(internalWaitHandles, millisecondsTimeout, exitContext, true /* waitall*/ );
- if(AppDomainPauseManager.IsPaused)
+ if (AppDomainPauseManager.IsPaused)
AppDomainPauseManager.ResumeEvent.WaitOneWithoutFAS();
- if ((WAIT_ABANDONED <= ret) && (WAIT_ABANDONED+internalWaitHandles.Length > ret))
+ if ((WAIT_ABANDONED <= ret) && (WAIT_ABANDONED + internalWaitHandles.Length > ret))
{
//In the case of WaitAll the OS will only provide the
// information that mutex was abandoned.
// It won't tell us which one. So we can't set the Index or provide access to the Mutex
ThrowAbandonedMutexException();
- }
+ }
GC.KeepAlive(internalWaitHandles);
return (ret != WaitTimeout);
}
public static bool WaitAll(
- WaitHandle[] waitHandles,
+ WaitHandle[] waitHandles,
TimeSpan timeout,
bool exitContext)
{
long tm = (long)timeout.TotalMilliseconds;
- if (-1 > tm || (long) Int32.MaxValue < tm)
+ if (-1 > tm || (long)Int32.MaxValue < tm)
{
- throw new ArgumentOutOfRangeException(nameof(timeout), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
+ throw new ArgumentOutOfRangeException(nameof(timeout), SR.ArgumentOutOfRange_NeedNonNegOrNegative1);
}
- return WaitAll(waitHandles,(int)tm, exitContext);
+ return WaitAll(waitHandles, (int)tm, exitContext);
}
-
+
/*========================================================================
** Shorthand for WaitAll with timeout = Timeout.Infinite and exitContext = true
========================================================================*/
public static bool WaitAll(WaitHandle[] waitHandles)
{
- return WaitAll(waitHandles, Timeout.Infinite, true);
+ return WaitAll(waitHandles, Timeout.Infinite, true);
}
public static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout)
{
- return WaitAll(waitHandles, millisecondsTimeout, true);
+ return WaitAll(waitHandles, millisecondsTimeout, true);
}
public static bool WaitAll(WaitHandle[] waitHandles, TimeSpan timeout)
{
- return WaitAll(waitHandles, timeout, true);
+ return WaitAll(waitHandles, timeout, true);
}
@@ -344,33 +345,33 @@ namespace System.Threading
** If exitContext is true then the synchronization domain for the context
** (if in a synchronized context) is exited before the wait and reacquired
========================================================================*/
-
+
public static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext)
{
- if (waitHandles==null)
+ if (waitHandles == null)
{
- throw new ArgumentNullException(nameof(waitHandles), Environment.GetResourceString("ArgumentNull_Waithandles"));
+ throw new ArgumentNullException(nameof(waitHandles), SR.ArgumentNull_Waithandles);
}
- if(waitHandles.Length == 0)
+ if (waitHandles.Length == 0)
{
- throw new ArgumentException(Environment.GetResourceString("Argument_EmptyWaithandleArray"));
+ throw new ArgumentException(SR.Argument_EmptyWaithandleArray);
}
if (MAX_WAITHANDLES < waitHandles.Length)
{
- throw new NotSupportedException(Environment.GetResourceString("NotSupported_MaxWaitHandles"));
+ throw new NotSupportedException(SR.NotSupported_MaxWaitHandles);
}
if (-1 > millisecondsTimeout)
{
- throw new ArgumentOutOfRangeException(nameof(millisecondsTimeout), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
+ throw new ArgumentOutOfRangeException(nameof(millisecondsTimeout), SR.ArgumentOutOfRange_NeedNonNegOrNegative1);
}
Contract.EndContractBlock();
WaitHandle[] internalWaitHandles = new WaitHandle[waitHandles.Length];
- for (int i = 0; i < waitHandles.Length; i ++)
+ for (int i = 0; i < waitHandles.Length; i++)
{
WaitHandle waitHandle = waitHandles[i];
if (waitHandle == null)
- throw new ArgumentNullException("waitHandles[" + i + "]", Environment.GetResourceString("ArgumentNull_ArrayElement"));
+ throw new ArgumentNullException("waitHandles[" + i + "]", SR.ArgumentNull_ArrayElement);
internalWaitHandles[i] = waitHandle;
}
@@ -380,41 +381,41 @@ namespace System.Threading
#endif
int ret = WaitMultiple(internalWaitHandles, millisecondsTimeout, exitContext, false /* waitany*/ );
- if(AppDomainPauseManager.IsPaused)
+ if (AppDomainPauseManager.IsPaused)
AppDomainPauseManager.ResumeEvent.WaitOneWithoutFAS();
- if ((WAIT_ABANDONED <= ret) && (WAIT_ABANDONED+internalWaitHandles.Length > ret))
+ if ((WAIT_ABANDONED <= ret) && (WAIT_ABANDONED + internalWaitHandles.Length > ret))
{
- int mutexIndex = ret -WAIT_ABANDONED;
- if(0 <= mutexIndex && mutexIndex < internalWaitHandles.Length)
+ int mutexIndex = ret - WAIT_ABANDONED;
+ if (0 <= mutexIndex && mutexIndex < internalWaitHandles.Length)
{
- ThrowAbandonedMutexException(mutexIndex,internalWaitHandles[mutexIndex]);
+ ThrowAbandonedMutexException(mutexIndex, internalWaitHandles[mutexIndex]);
}
else
{
ThrowAbandonedMutexException();
}
}
-
+
GC.KeepAlive(internalWaitHandles);
- return ret;
+ return ret;
}
public static int WaitAny(
- WaitHandle[] waitHandles,
+ WaitHandle[] waitHandles,
TimeSpan timeout,
bool exitContext)
{
long tm = (long)timeout.TotalMilliseconds;
- if (-1 > tm || (long) Int32.MaxValue < tm)
+ if (-1 > tm || (long)Int32.MaxValue < tm)
{
- throw new ArgumentOutOfRangeException(nameof(timeout), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
+ throw new ArgumentOutOfRangeException(nameof(timeout), SR.ArgumentOutOfRange_NeedNonNegOrNegative1);
}
- return WaitAny(waitHandles,(int)tm, exitContext);
+ return WaitAny(waitHandles, (int)tm, exitContext);
}
public static int WaitAny(WaitHandle[] waitHandles, TimeSpan timeout)
{
- return WaitAny(waitHandles, timeout, true);
+ return WaitAny(waitHandles, timeout, true);
}
@@ -428,7 +429,7 @@ namespace System.Threading
public static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout)
{
- return WaitAny(waitHandles, millisecondsTimeout, true);
+ return WaitAny(waitHandles, millisecondsTimeout, true);
}
/*=================================================
@@ -436,20 +437,20 @@ namespace System.Threading
== SignalAndWait
==
==================================================*/
-#if !PLATFORM_UNIX
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- private static extern int SignalAndWaitOne(SafeWaitHandle waitHandleToSignal,SafeWaitHandle waitHandleToWaitOn, int millisecondsTimeout,
- bool hasThreadAffinity, bool exitContext);
-#endif // !PLATFORM_UNIX
+#if PLATFORM_WINDOWS
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ private static extern int SignalAndWaitOne(SafeWaitHandle waitHandleToSignal, SafeWaitHandle waitHandleToWaitOn, int millisecondsTimeout,
+ bool hasThreadAffinity, bool exitContext);
+#endif // PLATFORM_WINDOWS
public static bool SignalAndWait(
WaitHandle toSignal,
WaitHandle toWaitOn)
{
#if PLATFORM_UNIX
- throw new PlatformNotSupportedException();
+ throw new PlatformNotSupportedException(SR.Arg_PlatformNotSupported); // https://github.com/dotnet/coreclr/issues/10441
#else
- return SignalAndWait(toSignal,toWaitOn,-1,false);
+ return SignalAndWait(toSignal, toWaitOn, -1, false);
#endif
}
@@ -460,14 +461,14 @@ namespace System.Threading
bool exitContext)
{
#if PLATFORM_UNIX
- throw new PlatformNotSupportedException();
+ throw new PlatformNotSupportedException(SR.Arg_PlatformNotSupported); // https://github.com/dotnet/coreclr/issues/10441
#else
long tm = (long)timeout.TotalMilliseconds;
- if (-1 > tm || (long) Int32.MaxValue < tm)
+ if (-1 > tm || (long)Int32.MaxValue < tm)
{
- throw new ArgumentOutOfRangeException(nameof(timeout), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
+ throw new ArgumentOutOfRangeException(nameof(timeout), SR.ArgumentOutOfRange_NeedNonNegOrNegative1);
}
- return SignalAndWait(toSignal,toWaitOn,(int)tm,exitContext);
+ return SignalAndWait(toSignal, toWaitOn, (int)tm, exitContext);
#endif
}
@@ -479,38 +480,38 @@ namespace System.Threading
bool exitContext)
{
#if PLATFORM_UNIX
- throw new PlatformNotSupportedException();
+ throw new PlatformNotSupportedException(SR.Arg_PlatformNotSupported); // https://github.com/dotnet/coreclr/issues/10441
#else
- if(null == toSignal)
+ if (null == toSignal)
{
throw new ArgumentNullException(nameof(toSignal));
}
- if(null == toWaitOn)
+ if (null == toWaitOn)
{
throw new ArgumentNullException(nameof(toWaitOn));
}
if (-1 > millisecondsTimeout)
{
- throw new ArgumentOutOfRangeException(nameof(millisecondsTimeout), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
+ throw new ArgumentOutOfRangeException(nameof(millisecondsTimeout), SR.ArgumentOutOfRange_NeedNonNegOrNegative1);
}
Contract.EndContractBlock();
//NOTE: This API is not supporting Pause/Resume as it's not exposed in CoreCLR (not in WP or SL)
- int ret = SignalAndWaitOne(toSignal.safeWaitHandle,toWaitOn.safeWaitHandle,millisecondsTimeout,
- toWaitOn.hasThreadAffinity,exitContext);
+ int ret = SignalAndWaitOne(toSignal.safeWaitHandle, toWaitOn.safeWaitHandle, millisecondsTimeout,
+ toWaitOn.hasThreadAffinity, exitContext);
- if(WAIT_ABANDONED == ret)
+ if (WAIT_ABANDONED == ret)
{
ThrowAbandonedMutexException();
}
- if(ERROR_TOO_MANY_POSTS == ret)
+ if (ERROR_TOO_MANY_POSTS == ret)
{
- throw new InvalidOperationException(Environment.GetResourceString("Threading.WaitHandleTooManyPosts"));
+ throw new InvalidOperationException(SR.Threading_WaitHandleTooManyPosts);
}
//Object was signaled
- if(WAIT_OBJECT_0 == ret)
+ if (WAIT_OBJECT_0 == ret)
{
return true;
}
@@ -535,7 +536,7 @@ namespace System.Threading
Dispose(true);
GC.SuppressFinalize(this);
}
-
+
protected virtual void Dispose(bool explicitDisposing)
{
if (safeWaitHandle != null)
diff --git a/src/mscorlib/src/System/Threading/WaitHandleCannotBeOpenedException.cs b/src/mscorlib/src/System/Threading/WaitHandleCannotBeOpenedException.cs
deleted file mode 100644
index 68445a78d9..0000000000
--- a/src/mscorlib/src/System/Threading/WaitHandleCannotBeOpenedException.cs
+++ /dev/null
@@ -1,36 +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.
-
-//
-namespace System.Threading
-{
- using System;
- using System.Runtime.Serialization;
- using System.Runtime.InteropServices;
-
- [Serializable]
- [ComVisibleAttribute(false)]
-
- public class WaitHandleCannotBeOpenedException : ApplicationException {
- public WaitHandleCannotBeOpenedException() : base(Environment.GetResourceString("Threading.WaitHandleCannotBeOpenedException"))
- {
- SetErrorCode(__HResults.COR_E_WAITHANDLECANNOTBEOPENED);
- }
-
- public WaitHandleCannotBeOpenedException(String message) : base(message)
- {
- SetErrorCode(__HResults.COR_E_WAITHANDLECANNOTBEOPENED);
- }
-
- public WaitHandleCannotBeOpenedException(String message, Exception innerException) : base(message, innerException)
- {
- SetErrorCode(__HResults.COR_E_WAITHANDLECANNOTBEOPENED);
- }
-
- protected WaitHandleCannotBeOpenedException(SerializationInfo info, StreamingContext context) : base (info, context)
- {
- }
- }
-}
-