Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/corert.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Kotas <jkotas@microsoft.com>2015-12-03 04:17:53 +0300
committerJan Kotas <jkotas@microsoft.com>2015-12-03 05:15:24 +0300
commit530d048456d111fa8b4d5b2be4f15e13365c8c9c (patch)
tree969b0e1f6bb54c59c81f3421bfce2dabbb8e9ab3 /src/Common
parentfe9c7754c926b6914edb842f55c12945eeb94f36 (diff)
Move System.Private.Threading implementation files from Common
These files are very System.Threading specific, not shared by any projects and unlikely to be ever shared in future
Diffstat (limited to 'src/Common')
-rw-r--r--src/Common/src/System/Collections/Concurrent/LowLevelConcurrentQueue.cs614
-rw-r--r--src/Common/src/System/Threading/Barrier.cs943
-rw-r--r--src/Common/src/System/Threading/CDSsyncETWBCLProvider.cs117
-rw-r--r--src/Common/src/System/Threading/CountdownEvent.cs585
-rw-r--r--src/Common/src/System/Threading/Progress.cs104
-rw-r--r--src/Common/src/System/Threading/ReaderWriterLockSlim.cs1294
-rw-r--r--src/Common/src/System/Threading/TimeoutHelper.cs53
7 files changed, 0 insertions, 3710 deletions
diff --git a/src/Common/src/System/Collections/Concurrent/LowLevelConcurrentQueue.cs b/src/Common/src/System/Collections/Concurrent/LowLevelConcurrentQueue.cs
deleted file mode 100644
index 3cc531e92..000000000
--- a/src/Common/src/System/Collections/Concurrent/LowLevelConcurrentQueue.cs
+++ /dev/null
@@ -1,614 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-#pragma warning disable 0420
-
-// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
-//
-// A lock-free, concurrent queue primitive, and its associated debugger view type.
-//
-// This is a stripped-down version of ConcurrentQueue, for use from within the System.Threading
-// surface to eliminate a dependency on System.Collections.Concurrent.
-// Please try to keep this in sync with the public ConcurrentQueue implementation.
-//
-// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Runtime.InteropServices;
-using System.Security;
-using System.Threading;
-
-namespace System.Collections.Concurrent
-{
- /// <summary>
- /// Represents a thread-safe first-in, first-out collection of objects.
- /// </summary>
- /// <typeparam name="T">Specifies the type of elements in the queue.</typeparam>
- /// <remarks>
- /// All public and protected members of <see cref="ConcurrentQueue{T}"/> are thread-safe and may be used
- /// concurrently from multiple threads.
- /// </remarks>
- internal class LowLevelConcurrentQueue<T> /*: IProducerConsumerCollection<T>*/ : IEnumerable<T>
- {
- //fields of ConcurrentQueue
- private volatile Segment _head;
-
- private volatile Segment _tail;
-
- private const int SEGMENT_SIZE = 32;
-
- //number of snapshot takers, GetEnumerator(), ToList() and ToArray() operations take snapshot.
- internal volatile int m_numSnapshotTakers = 0;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="ConcurrentQueue{T}"/> class.
- /// </summary>
- public LowLevelConcurrentQueue()
- {
- _head = _tail = new Segment(0, this);
- }
-
- /// <summary>
- /// Returns an enumerator that iterates through a collection.
- /// </summary>
- /// <returns>An <see cref="T:System.Collections.IEnumerator"/> that can be used to iterate through the collection.</returns>
- IEnumerator IEnumerable.GetEnumerator()
- {
- return ((IEnumerable<T>)this).GetEnumerator();
- }
-
- /// <summary>
- /// Gets a value that indicates whether the <see cref="ConcurrentQueue{T}"/> is empty.
- /// </summary>
- /// <value>true if the <see cref="ConcurrentQueue{T}"/> is empty; otherwise, false.</value>
- /// <remarks>
- /// For determining whether the collection contains any items, use of this property is recommended
- /// rather than retrieving the number of items from the <see cref="Count"/> property and comparing it
- /// to 0. However, as this collection is intended to be accessed concurrently, it may be the case
- /// that another thread will modify the collection after <see cref="IsEmpty"/> returns, thus invalidating
- /// the result.
- /// </remarks>
- public bool IsEmpty
- {
- get
- {
- Segment head = _head;
- if (!head.IsEmpty)
- //fast route 1:
- //if current head is not empty, then queue is not empty
- return false;
- else if (head.Next == null)
- //fast route 2:
- //if current head is empty and it's the last segment
- //then queue is empty
- return true;
- else
- //slow route:
- //current head is empty and it is NOT the last segment,
- //it means another thread is growing new segment
- {
- SpinWait spin = new SpinWait();
- while (head.IsEmpty)
- {
- if (head.Next == null)
- return true;
-
- spin.SpinOnce();
- head = _head;
- }
- return false;
- }
- }
- }
-
- /// <summary>
- /// Store the position of the current head and tail positions.
- /// </summary>
- /// <param name="head">return the head segment</param>
- /// <param name="tail">return the tail segment</param>
- /// <param name="headLow">return the head offset, value range [0, SEGMENT_SIZE]</param>
- /// <param name="tailHigh">return the tail offset, value range [-1, SEGMENT_SIZE-1]</param>
- private void GetHeadTailPositions(out Segment head, out Segment tail,
- out int headLow, out int tailHigh)
- {
- head = _head;
- tail = _tail;
- headLow = head.Low;
- tailHigh = tail.High;
- SpinWait spin = new SpinWait();
-
- //we loop until the observed values are stable and sensible.
- //This ensures that any update order by other methods can be tolerated.
- while (
- //if head and tail changed, retry
- head != _head || tail != _tail
- //if low and high pointers, retry
- || headLow != head.Low || tailHigh != tail.High
- //if head jumps ahead of tail because of concurrent grow and dequeue, retry
- || head.m_index > tail.m_index)
- {
- spin.SpinOnce();
- head = _head;
- tail = _tail;
- headLow = head.Low;
- tailHigh = tail.High;
- }
- }
-
-
- /// <summary>
- /// Gets the number of elements contained in the <see cref="ConcurrentQueue{T}"/>.
- /// </summary>
- /// <value>The number of elements contained in the <see cref="ConcurrentQueue{T}"/>.</value>
- /// <remarks>
- /// For determining whether the collection contains any items, use of the <see cref="IsEmpty"/>
- /// property is recommended rather than retrieving the number of items from the <see cref="Count"/>
- /// property and comparing it to 0.
- /// </remarks>
- public int Count
- {
- get
- {
- //store head and tail positions in buffer,
- Segment head, tail;
- int headLow, tailHigh;
- GetHeadTailPositions(out head, out tail, out headLow, out tailHigh);
-
- if (head == tail)
- {
- return tailHigh - headLow + 1;
- }
-
- //head segment
- int count = SEGMENT_SIZE - headLow;
-
- //middle segment(s), if any, are full.
- //We don't deal with overflow to be consistent with the behavior of generic types in CLR.
- count += SEGMENT_SIZE * ((int)(tail.m_index - head.m_index - 1));
-
- //tail segment
- count += tailHigh + 1;
-
- return count;
- }
- }
-
- /// <summary>
- /// Returns an enumerator that iterates through the <see
- /// cref="ConcurrentQueue{T}"/>.
- /// </summary>
- /// <returns>An enumerator for the contents of the <see
- /// cref="ConcurrentQueue{T}"/>.</returns>
- /// <remarks>
- /// The enumeration represents a moment-in-time snapshot of the contents
- /// of the queue. It does not reflect any updates to the collection after
- /// <see cref="GetEnumerator"/> was called. The enumerator is safe to use
- /// concurrently with reads from and writes to the queue.
- /// </remarks>
- public IEnumerator<T> GetEnumerator()
- {
- // Increments the number of active snapshot takers. This increment must happen before the snapshot is
- // taken. At the same time, Decrement must happen after the enumeration is over. Only in this way, can it
- // eliminate race condition when Segment.TryRemove() checks whether m_numSnapshotTakers == 0.
- Interlocked.Increment(ref m_numSnapshotTakers);
-
- // Takes a snapshot of the queue.
- // A design flaw here: if a Thread.Abort() happens, we cannot decrement m_numSnapshotTakers. But we cannot
- // wrap the following with a try/finally block, otherwise the decrement will happen before the yield return
- // statements in the GetEnumerator (head, tail, headLow, tailHigh) method.
- Segment head, tail;
- int headLow, tailHigh;
- GetHeadTailPositions(out head, out tail, out headLow, out tailHigh);
-
- //If we put yield-return here, the iterator will be lazily evaluated. As a result a snapshot of
- // the queue is not taken when GetEnumerator is initialized but when MoveNext() is first called.
- // This is inconsistent with existing generic collections. In order to prevent it, we capture the
- // value of m_head in a buffer and call out to a helper method.
- //The old way of doing this was to return the ToList().GetEnumerator(), but ToList() was an
- // unnecessary perfomance hit.
- return GetEnumerator(head, tail, headLow, tailHigh);
- }
-
- /// <summary>
- /// Helper method of GetEnumerator to seperate out yield return statement, and prevent lazy evaluation.
- /// </summary>
- private IEnumerator<T> GetEnumerator(Segment head, Segment tail, int headLow, int tailHigh)
- {
- try
- {
- SpinWait spin = new SpinWait();
-
- if (head == tail)
- {
- for (int i = headLow; i <= tailHigh; i++)
- {
- // If the position is reserved by an Enqueue operation, but the value is not written into,
- // spin until the value is available.
- spin.Reset();
- while (!head.m_state[i].m_value)
- {
- spin.SpinOnce();
- }
- yield return head.m_array[i];
- }
- }
- else
- {
- //iterate on head segment
- for (int i = headLow; i < SEGMENT_SIZE; i++)
- {
- // If the position is reserved by an Enqueue operation, but the value is not written into,
- // spin until the value is available.
- spin.Reset();
- while (!head.m_state[i].m_value)
- {
- spin.SpinOnce();
- }
- yield return head.m_array[i];
- }
- //iterate on middle segments
- Segment curr = head.Next;
- while (curr != tail)
- {
- for (int i = 0; i < SEGMENT_SIZE; i++)
- {
- // If the position is reserved by an Enqueue operation, but the value is not written into,
- // spin until the value is available.
- spin.Reset();
- while (!curr.m_state[i].m_value)
- {
- spin.SpinOnce();
- }
- yield return curr.m_array[i];
- }
- curr = curr.Next;
- }
-
- //iterate on tail segment
- for (int i = 0; i <= tailHigh; i++)
- {
- // If the position is reserved by an Enqueue operation, but the value is not written into,
- // spin until the value is available.
- spin.Reset();
- while (!tail.m_state[i].m_value)
- {
- spin.SpinOnce();
- }
- yield return tail.m_array[i];
- }
- }
- }
- finally
- {
- // This Decrement must happen after the enumeration is over.
- Interlocked.Decrement(ref m_numSnapshotTakers);
- }
- }
-
- /// <summary>
- /// Adds an object to the end of the <see cref="ConcurrentQueue{T}"/>.
- /// </summary>
- /// <param name="item">The object to add to the end of the <see
- /// cref="ConcurrentQueue{T}"/>. The value can be a null reference
- /// (Nothing in Visual Basic) for reference types.
- /// </param>
- public void Enqueue(T item)
- {
- SpinWait spin = new SpinWait();
- while (true)
- {
- Segment tail = _tail;
- if (tail.TryAppend(item))
- return;
- spin.SpinOnce();
- }
- }
-
-
- /// <summary>
- /// Attempts to remove and return the object at the beginning of the <see
- /// cref="ConcurrentQueue{T}"/>.
- /// </summary>
- /// <param name="result">
- /// When this method returns, if the operation was successful, <paramref name="result"/> contains the
- /// object removed. If no object was available to be removed, the value is unspecified.
- /// </param>
- /// <returns>true if an element was removed and returned from the beggining of the <see
- /// cref="ConcurrentQueue{T}"/>
- /// succesfully; otherwise, false.</returns>
- public bool TryDequeue(out T result)
- {
- while (!IsEmpty)
- {
- Segment head = _head;
- if (head.TryRemove(out result))
- return true;
- //since method IsEmpty spins, we don't need to spin in the while loop
- }
- result = default(T);
- return false;
- }
-
- /// <summary>
- /// private class for ConcurrentQueue.
- /// a queue is a linked list of small arrays, each node is called a segment.
- /// A segment contains an array, a pointer to the next segment, and m_low, m_high indices recording
- /// the first and last valid elements of the array.
- /// </summary>
- private class Segment
- {
- //we define two volatile arrays: m_array and m_state. Note that the accesses to the array items
- //do not get volatile treatment. But we don't need to worry about loading adjacent elements or
- //store/load on adjacent elements would suffer reordering.
- // - Two stores: these are at risk, but CLRv2 memory model guarantees store-release hence we are safe.
- // - Two loads: because one item from two volatile arrays are accessed, the loads of the array references
- // are sufficient to prevent reordering of the loads of the elements.
- internal volatile T[] m_array;
-
- // For each entry in m_array, the corresponding entry in m_state indicates whether this position contains
- // a valid value. m_state is initially all false.
- internal volatile VolatileBool[] m_state;
-
- //pointer to the next segment. null if the current segment is the last segment
- private volatile Segment _next;
-
- //We use this zero based index to track how many segments have been created for the queue, and
- //to compute how many active segments are there currently.
- // * The number of currently active segments is : m_tail.m_index - m_head.m_index + 1;
- // * m_index is incremented with every Segment.Grow operation. We use Int64 type, and we can safely
- // assume that it never overflows. To overflow, we need to do 2^63 increments, even at a rate of 4
- // billion (2^32) increments per second, it takes 2^31 seconds, which is about 64 years.
- internal readonly long m_index;
-
- //indices of where the first and last valid values
- // - m_low points to the position of the next element to pop from this segment, range [0, infinity)
- // m_low >= SEGMENT_SIZE implies the segment is disposable
- // - m_high points to the position of the latest pushed element, range [-1, infinity)
- // m_high == -1 implies the segment is new and empty
- // m_high >= SEGMENT_SIZE-1 means this segment is ready to grow.
- // and the thread who sets m_high to SEGMENT_SIZE-1 is responsible to grow the segment
- // - Math.Min(m_low, SEGMENT_SIZE) > Math.Min(m_high, SEGMENT_SIZE-1) implies segment is empty
- // - initially m_low =0 and m_high=-1;
- private volatile int _low;
- private volatile int _high;
-
- private volatile LowLevelConcurrentQueue<T> _source;
-
- /// <summary>
- /// Create and initialize a segment with the specified index.
- /// </summary>
- internal Segment(long index, LowLevelConcurrentQueue<T> source)
- {
- m_array = new T[SEGMENT_SIZE];
- m_state = new VolatileBool[SEGMENT_SIZE]; //all initialized to false
- _high = -1;
- Debug.Assert(index >= 0);
- m_index = index;
- _source = source;
- }
-
- /// <summary>
- /// return the next segment
- /// </summary>
- internal Segment Next
- {
- get { return _next; }
- }
-
-
- /// <summary>
- /// return true if the current segment is empty (doesn't have any element available to dequeue,
- /// false otherwise
- /// </summary>
- internal bool IsEmpty
- {
- get { return (Low > High); }
- }
-
- /// <summary>
- /// Add an element to the tail of the current segment
- /// exclusively called by ConcurrentQueue.InitializedFromCollection
- /// InitializeFromCollection is responsible to guaratee that there is no index overflow,
- /// and there is no contention
- /// </summary>
- /// <param name="value"></param>
- internal void UnsafeAdd(T value)
- {
- Debug.Assert(_high < SEGMENT_SIZE - 1);
- _high++;
- m_array[_high] = value;
- m_state[_high].m_value = true;
- }
-
- /// <summary>
- /// Create a new segment and append to the current one
- /// Does not update the m_tail pointer
- /// exclusively called by ConcurrentQueue.InitializedFromCollection
- /// InitializeFromCollection is responsible to guaratee that there is no index overflow,
- /// and there is no contention
- /// </summary>
- /// <returns>the reference to the new Segment</returns>
- internal Segment UnsafeGrow()
- {
- Debug.Assert(_high >= SEGMENT_SIZE - 1);
- Segment newSegment = new Segment(m_index + 1, _source); //m_index is Int64, we don't need to worry about overflow
- _next = newSegment;
- return newSegment;
- }
-
- /// <summary>
- /// Create a new segment and append to the current one
- /// Update the m_tail pointer
- /// This method is called when there is no contention
- /// </summary>
- internal void Grow()
- {
- //no CAS is needed, since there is no contention (other threads are blocked, busy waiting)
- Segment newSegment = new Segment(m_index + 1, _source); //m_index is Int64, we don't need to worry about overflow
- _next = newSegment;
- Debug.Assert(_source._tail == this);
- _source._tail = _next;
- }
-
-
- /// <summary>
- /// Try to append an element at the end of this segment.
- /// </summary>
- /// <param name="value">the element to append</param>
- /// <param name="tail">The tail.</param>
- /// <returns>true if the element is appended, false if the current segment is full</returns>
- /// <remarks>if appending the specified element succeeds, and after which the segment is full,
- /// then grow the segment</remarks>
- internal bool TryAppend(T value)
- {
- //quickly check if m_high is already over the boundary, if so, bail out
- if (_high >= SEGMENT_SIZE - 1)
- {
- return false;
- }
-
- //Now we will use a CAS to increment m_high, and store the result in newhigh.
- //Depending on how many free spots left in this segment and how many threads are doing this Increment
- //at this time, the returning "newhigh" can be
- // 1) < SEGMENT_SIZE - 1 : we took a spot in this segment, and not the last one, just insert the value
- // 2) == SEGMENT_SIZE - 1 : we took the last spot, insert the value AND grow the segment
- // 3) > SEGMENT_SIZE - 1 : we failed to reserve a spot in this segment, we return false to
- // Queue.Enqueue method, telling it to try again in the next segment.
-
- int newhigh = SEGMENT_SIZE; //initial value set to be over the boundary
-
- //We need do Interlocked.Increment and value/state update in a finally block to ensure that they run
- //without interuption. This is to prevent anything from happening between them, and another dequeue
- //thread maybe spinning forever to wait for m_state[] to be true;
- try
- { }
- finally
- {
- newhigh = Interlocked.Increment(ref _high);
- if (newhigh <= SEGMENT_SIZE - 1)
- {
- m_array[newhigh] = value;
- m_state[newhigh].m_value = true;
- }
-
- //if this thread takes up the last slot in the segment, then this thread is responsible
- //to grow a new segment. Calling Grow must be in the finally block too for reliability reason:
- //if thread abort during Grow, other threads will be left busy spinning forever.
- if (newhigh == SEGMENT_SIZE - 1)
- {
- Grow();
- }
- }
-
- //if newhigh <= SEGMENT_SIZE-1, it means the current thread successfully takes up a spot
- return newhigh <= SEGMENT_SIZE - 1;
- }
-
-
- /// <summary>
- /// try to remove an element from the head of current segment
- /// </summary>
- /// <param name="result">The result.</param>
- /// <param name="head">The head.</param>
- /// <returns>return false only if the current segment is empty</returns>
- internal bool TryRemove(out T result)
- {
- SpinWait spin = new SpinWait();
- int lowLocal = Low, highLocal = High;
- while (lowLocal <= highLocal)
- {
- //try to update m_low
- if (Interlocked.CompareExchange(ref _low, lowLocal + 1, lowLocal) == lowLocal)
- {
- //if the specified value is not available (this spot is taken by a push operation,
- // but the value is not written into yet), then spin
- SpinWait spinLocal = new SpinWait();
- while (!m_state[lowLocal].m_value)
- {
- spinLocal.SpinOnce();
- }
- result = m_array[lowLocal];
-
- // If there is no other thread taking snapshot (GetEnumerator(), ToList(), etc), reset the deleted entry to null.
- // It is ok if after this conditional check m_numSnapshotTakers becomes > 0, because new snapshots won't include
- // the deleted entry at m_array[lowLocal].
- if (_source.m_numSnapshotTakers <= 0)
- {
- m_array[lowLocal] = default(T); //release the reference to the object.
- }
-
- //if the current thread sets m_low to SEGMENT_SIZE, which means the current segment becomes
- //disposable, then this thread is responsible to dispose this segment, and reset m_head
- if (lowLocal + 1 >= SEGMENT_SIZE)
- {
- // Invariant: we only dispose the current m_head, not any other segment
- // In usual situation, disposing a segment is simply seting m_head to m_head.m_next
- // But there is one special case, where m_head and m_tail points to the same and ONLY
- //segment of the queue: Another thread A is doing Enqueue and finds that it needs to grow,
- //while the *current* thread is doing *this* Dequeue operation, and finds that it needs to
- //dispose the current (and ONLY) segment. Then we need to wait till thread A finishes its
- //Grow operation, this is the reason of having the following while loop
- spinLocal = new SpinWait();
- while (_next == null)
- {
- spinLocal.SpinOnce();
- }
- Debug.Assert(_source._head == this);
- _source._head = _next;
- }
- return true;
- }
- else
- {
- //CAS failed due to contention: spin briefly and retry
- spin.SpinOnce();
- lowLocal = Low; highLocal = High;
- }
- }//end of while
- result = default(T);
- return false;
- }
-
- /// <summary>
- /// return the position of the head of the current segment
- /// Value range [0, SEGMENT_SIZE], if it's SEGMENT_SIZE, it means this segment is exhausted and thus empty
- /// </summary>
- internal int Low
- {
- get
- {
- return Math.Min(_low, SEGMENT_SIZE);
- }
- }
-
- /// <summary>
- /// return the logical position of the tail of the current segment
- /// Value range [-1, SEGMENT_SIZE-1]. When it's -1, it means this is a new segment and has no elemnet yet
- /// </summary>
- internal int High
- {
- get
- {
- //if m_high > SEGMENT_SIZE, it means it's out of range, we should return
- //SEGMENT_SIZE-1 as the logical position
- return Math.Min(_high, SEGMENT_SIZE - 1);
- }
- }
- }
- }//end of class Segment
-
- /// <summary>
- /// A wrapper struct for volatile bool, please note the copy of the struct it self will not be volatile
- /// for example this statement will not include in volatilness operation volatileBool1 = volatileBool2 the jit will copy the struct and will ignore the volatile
- /// </summary>
- internal struct VolatileBool
- {
- public VolatileBool(bool value)
- {
- m_value = value;
- }
- public volatile bool m_value;
- }
-}
diff --git a/src/Common/src/System/Threading/Barrier.cs b/src/Common/src/System/Threading/Barrier.cs
deleted file mode 100644
index 77c171f3a..000000000
--- a/src/Common/src/System/Threading/Barrier.cs
+++ /dev/null
@@ -1,943 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-
-// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
-//
-// A barrier allows multiple tasks to cooperatively work on some algorithm in parallel.
-// A group of tasks cooperate by moving through a series of phases, where each in the group signals it has arrived at
-// the barrier in a given phase and implicitly waits for all others to arrive.
-// The same barrier can be used for multiple phases.
-//
-// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Runtime.InteropServices;
-using System.Threading;
-using System.Security;
-
-namespace System.Threading
-{
- /// <summary>
- /// The exception that is thrown when the post-phase action of a <see cref="Barrier"/> fails.
- /// </summary>
- public class BarrierPostPhaseException : Exception
- {
- /// <summary>
- /// Initializes a new instance of the <see cref="BarrierPostPhaseException"/> class.
- /// </summary>
- public BarrierPostPhaseException()
- : this((string)null)
- {
- }
-
- /// <summary>
- /// Initializes a new instance of the <see cref="BarrierPostPhaseException"/> class with the specified inner exception.
- /// </summary>
- /// <param name="innerException">The exception that is the cause of the current exception.</param>
- public BarrierPostPhaseException(Exception innerException)
- : this(null, innerException)
- {
- }
-
- /// <summary>
- /// Initializes a new instance of the <see cref="BarrierPostPhaseException"/> class with a specified error message.
- /// </summary>
- /// <param name="message">A string that describes the exception.</param>
- public BarrierPostPhaseException(string message)
- : this(message, null)
- {
- }
-
- /// <summary>
- /// Initializes a new instance of the <see cref="BarrierPostPhaseException"/> class with a specified error message and inner exception.
- /// </summary>
- /// <param name="message">A string that describes the exception.</param>
- /// <param name="innerException">The exception that is the cause of the current exception.</param>
- public BarrierPostPhaseException(string message, Exception innerException)
- : base(message == null ? SR.BarrierPostPhaseException : message, innerException)
- {
- }
- }
-
-
- /// <summary>
- /// Enables multiple tasks to cooperatively work on an algorithm in parallel through multiple phases.
- /// </summary>
- /// <remarks>
- /// <para>
- /// A group of tasks cooperate by moving through a series of phases, where each in the group signals it
- /// has arrived at the <see cref="Barrier"/> in a given phase and implicitly waits for all others to
- /// arrive. The same <see cref="Barrier"/> can be used for multiple phases.
- /// </para>
- /// <para>
- /// All public and protected members of <see cref="Barrier"/> 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="Barrier"/> have
- /// completed.
- /// </para>
- /// </remarks>
- [ComVisible(false)]
- [DebuggerDisplay("Participant Count={ParticipantCount},Participants Remaining={ParticipantsRemaining}")]
- public class Barrier : IDisposable
- {
- //This variable holds the basic barrier variables:
- // 1- The current particiants count
- // 2- The total participants count
- // 3- The sense flag (true if the cuurrent phase is even, false otherwise)
- // The first 15 bits are for the total count which means the maximum participants for the barrier is about 32K
- // The 16th bit is dummy
- // The next 15th bit for the current
- // And the last highest bit is for the sense
- private volatile int _currentTotalCount;
-
- // Bitmask to extract the current count
- private const int CURRENT_MASK = 0x7FFF0000;
-
- // Bitmask to extract the total count
- private const int TOTAL_MASK = 0x00007FFF;
-
- // Bitmask to extratc the sense flag
- private const int SENSE_MASK = unchecked((int)0x80000000);
-
- // The maximum participants the barrier can operate = 32767 ( 2 power 15 - 1 )
- private const int MAX_PARTICIPANTS = TOTAL_MASK;
-
-
- // The current barrier phase
- // We don't need to worry about overflow, the max value is 2^63-1; If it starts from 0 at a
- // rate of 4 billion increments per second, it will takes about 64 years to overflow.
- private long _currentPhase;
-
-
- // dispose flag
- private bool _disposed;
-
- // Odd phases event
- private ManualResetEventSlim _oddEvent;
-
- // Even phases event
- private ManualResetEventSlim _evenEvent;
-
- // The execution context of the creator thread
- private ExecutionContext _ownerThreadContext;
-
- // The EC callback that invokes the post phase action
- [SecurityCritical]
- private static ContextCallback s_invokePostPhaseAction;
-
- // Post phase action after each phase
- private Action<Barrier> _postPhaseAction;
-
- // In case the post phase action throws an exception, wraps it in BarrierPostPhaseException
- private Exception _exception;
-
- // This is the ManagedThreadID of the postPhaseAction caller thread, this is used to determine if the SignalAndWait, Dispose or Add/RemoveParticipant caller thread is
- // the same thread as the postPhaseAction thread which means this method was called from the postPhaseAction which is illegal.
- // This value is captured before calling the action and reset back to zero after it.
- private int _actionCallerID;
-
- #region Properties
-
- /// <summary>
- /// Gets the number of participants in the barrier that haven’t yet signaled
- /// in the current phase.
- /// </summary>
- /// <remarks>
- /// This could be 0 during a post-phase action delegate execution or if the
- /// ParticipantCount is 0.
- /// </remarks>
- public int ParticipantsRemaining
- {
- get
- {
- int currentTotal = _currentTotalCount;
- int total = (int)(currentTotal & TOTAL_MASK);
- int current = (int)((currentTotal & CURRENT_MASK) >> 16);
- return total - current;
- }
- }
-
- /// <summary>
- /// Gets the total number of participants in the barrier.
- /// </summary>
- public int ParticipantCount
- {
- get { return (int)(_currentTotalCount & TOTAL_MASK); }
- }
-
- /// <summary>
- /// Gets the number of the barrier's current phase.
- /// </summary>
- public long CurrentPhaseNumber
- {
- // use the new Volatile.Read/Write method because it is cheaper than Interlocked.Read on AMD64 architecture
- get { return Volatile.Read(ref _currentPhase); }
-
- internal set { Volatile.Write(ref _currentPhase, value); }
- }
-
- #endregion
-
- /// <summary>
- /// Initializes a new instance of the <see cref="Barrier"/> class.
- /// </summary>
- /// <param name="participantCount">The number of participating threads.</param>
- /// <exception cref="ArgumentOutOfRangeException"> <paramref name="participantCount"/> is less than 0
- /// or greater than <see cref="T:System.Int16.MaxValue"/>.</exception>
- public Barrier(int participantCount)
- : this(participantCount, null)
- {
- }
-
- /// <summary>
- /// Initializes a new instance of the <see cref="Barrier"/> class.
- /// </summary>
- /// <param name="participantCount">The number of participating threads.</param>
- /// <param name="postPhaseAction">The <see cref="T:System.Action`1"/> to be executed after each
- /// phase.</param>
- /// <exception cref="T:System.ArgumentOutOfRangeException"> <paramref name="participantCount"/> is less than 0
- /// or greater than <see cref="T:System.Int32.MaxValue"/>.</exception>
- /// <remarks>
- /// The <paramref name="postPhaseAction"/> delegate will be executed after
- /// all participants have arrived at the barrier in one phase. The participants
- /// will not be released to the next phase until the postPhaseAction delegate
- /// has completed execution.
- /// </remarks>
- public Barrier(int participantCount, Action<Barrier> postPhaseAction)
- {
- // the count must be non negative value
- if (participantCount < 0 || participantCount > MAX_PARTICIPANTS)
- {
- throw new ArgumentOutOfRangeException("participantCount", participantCount, SR.Barrier_ctor_ArgumentOutOfRange);
- }
- _currentTotalCount = (int)participantCount;
- _postPhaseAction = postPhaseAction;
-
- //Lazily initialize the events
- _oddEvent = new ManualResetEventSlim(true);
- _evenEvent = new ManualResetEventSlim(false);
-
- // Capture the context if the post phase action is not null
- if (postPhaseAction != null)
- {
- _ownerThreadContext = ExecutionContext.Capture();
- }
-
- _actionCallerID = 0;
- }
-
- /// <summary>
- /// Extract the three variables current, total and sense from a given big variable
- /// </summary>
- /// <param name="currentTotal">The integer variable that contains the other three variables</param>
- /// <param name="current">The current cparticipant count</param>
- /// <param name="total">The total participants count</param>
- /// <param name="sense">The sense flag</param>
- private void GetCurrentTotal(int currentTotal, out int current, out int total, out bool sense)
- {
- total = (int)(currentTotal & TOTAL_MASK);
- current = (int)((currentTotal & CURRENT_MASK) >> 16);
- sense = (currentTotal & SENSE_MASK) == 0 ? true : false;
- }
-
- /// <summary>
- /// Write the three variables current. total and the sense to the m_currentTotal
- /// </summary>
- /// <param name="currentTotal">The old current total to compare</param>
- /// <param name="current">The current cparticipant count</param>
- /// <param name="total">The total participants count</param>
- /// <param name="sense">The sense flag</param>
- /// <returns>True if the CAS succeeded, false otherwise</returns>
- private bool SetCurrentTotal(int currentTotal, int current, int total, bool sense)
- {
- int newCurrentTotal = (current << 16) | total;
-
- if (!sense)
- {
- newCurrentTotal |= SENSE_MASK;
- }
-
-#pragma warning disable 0420
- return Interlocked.CompareExchange(ref _currentTotalCount, newCurrentTotal, currentTotal) == currentTotal;
-#pragma warning restore 0420
- }
-
- /// <summary>
- /// Notifies the <see cref="Barrier"/> that there will be an additional participant.
- /// </summary>
- /// <returns>The phase number of the barrier in which the new participants will first
- /// participate.</returns>
- /// <exception cref="T:System.InvalidOperationException">
- /// Adding a participant would cause the barrier's participant count to
- /// exceed <see cref="T:System.Int16.MaxValue"/>.
- /// </exception>
- /// <exception cref="T:System.InvalidOperationException">
- /// The method was invoked from within a post-phase action.
- /// </exception>
- /// <exception cref="T:System.ObjectDisposedException">The current instance has already been
- /// disposed.</exception>
- public long AddParticipant()
- {
- try
- {
- return AddParticipants(1);
- }
- catch (ArgumentOutOfRangeException)
- {
- throw new InvalidOperationException(SR.Barrier_AddParticipants_Overflow_ArgumentOutOfRange);
- }
- }
-
- /// <summary>
- /// Notifies the <see cref="Barrier"/> that there will be additional participants.
- /// </summary>
- /// <param name="participantCount">The number of additional participants to add to the
- /// barrier.</param>
- /// <returns>The phase number of the barrier in which the new participants will first
- /// participate.</returns>
- /// <exception cref="T:System.ArgumentOutOfRangeException"><paramref name="participantCount"/> is less than
- /// 0.</exception>
- /// <exception cref="T:System.ArgumentOutOfRangeException">Adding <paramref name="participantCount"/> participants would cause the
- /// barrier's participant count to exceed <see cref="T:System.Int16.MaxValue"/>.</exception>
- /// <exception cref="T:System.InvalidOperationException">
- /// The method was invoked from within a post-phase action.
- /// </exception>
- /// <exception cref="T:System.ObjectDisposedException">The current instance has already been
- /// disposed.</exception>
- public long AddParticipants(int participantCount)
- {
- // check dispose
- ThrowIfDisposed();
-
- if (participantCount < 1)
- {
- throw new ArgumentOutOfRangeException("participantCount", participantCount,
- SR.Barrier_AddParticipants_NonPositive_ArgumentOutOfRange);
- }
- else if (participantCount > MAX_PARTICIPANTS) //overflow
- {
- throw new ArgumentOutOfRangeException("participantCount",
- SR.Barrier_AddParticipants_Overflow_ArgumentOutOfRange);
- }
-
- // in case of this is called from the PHA
- if (_actionCallerID != 0 && Environment.CurrentManagedThreadId == _actionCallerID)
- {
- throw new InvalidOperationException(SR.Barrier_InvalidOperation_CalledFromPHA);
- }
-
- SpinWait spinner = new SpinWait();
- long newPhase = 0;
- while (true)
- {
- int currentTotal = _currentTotalCount;
- int total;
- int current;
- bool sense;
- GetCurrentTotal(currentTotal, out current, out total, out sense);
- if (participantCount + total > MAX_PARTICIPANTS) //overflow
- {
- throw new ArgumentOutOfRangeException("participantCount",
- SR.Barrier_AddParticipants_Overflow_ArgumentOutOfRange);
- }
-
- if (SetCurrentTotal(currentTotal, current, total + participantCount, sense))
- {
- // Calculating the first phase for that participant, if the current phase already finished return the nextphase else return the current phase
- // To know that the current phase is the sense doesn't match the
- // phase odd even, so that means it didn't yet change the phase count, so currentPhase +1 is returned, otherwise currentPhase is returned
- long currPhase = CurrentPhaseNumber;
- newPhase = (sense != (currPhase % 2 == 0)) ? currPhase + 1 : currPhase;
-
- // If this participant is going to join the next phase, which means the postPhaseAction is being running, this participants must wait until this done
- // and its event is reset.
- // Without that, if the postPhaseAction takes long time, this means the event ehich the current participant is goint to wait on is still set
- // (FinishPPhase didn't reset it yet) so it should wait until it reset
- if (newPhase != currPhase)
- {
- // Wait on the opposite event
- if (sense)
- {
- _oddEvent.Wait();
- }
- else
- {
- _evenEvent.Wait();
- }
- }
-
- //This else to fix the racing where the current phase has been finished, m_currentPhase has been updated but the events have not been set/reset yet
- // otherwise when this participant calls SignalAndWait it will wait on a set event however all other participants have not arrived yet.
- else
- {
- if (sense && _evenEvent.IsSet)
- _evenEvent.Reset();
- else if (!sense && _oddEvent.IsSet)
- _oddEvent.Reset();
- }
- break;
- }
- spinner.SpinOnce();
- }
- return newPhase;
- }
-
- /// <summary>
- /// Notifies the <see cref="Barrier"/> that there will be one less participant.
- /// </summary>
- /// <exception cref="T:System.InvalidOperationException">The barrier already has 0
- /// participants.</exception>
- /// <exception cref="T:System.InvalidOperationException">
- /// The method was invoked from within a post-phase action.
- /// </exception>
- /// <exception cref="T:System.ObjectDisposedException">The current instance has already been
- /// disposed.</exception>
- public void RemoveParticipant()
- {
- RemoveParticipants(1);
- }
-
- /// <summary>
- /// Notifies the <see cref="Barrier"/> that there will be fewer participants.
- /// </summary>
- /// <param name="participantCount">The number of additional participants to remove from the barrier.</param>
- /// <exception cref="T:System.ArgumentOutOfRangeException"><paramref name="participantCount"/> is less than
- /// 0.</exception>
- /// <exception cref="T:System.InvalidOperationException">The barrier already has 0 participants.</exception>
- /// <exception cref="T:System.InvalidOperationException">
- /// The method was invoked from within a post-phase action.
- /// </exception>
- /// <exception cref="T:System.ObjectDisposedException">The current instance has already been
- /// disposed.</exception>
- public void RemoveParticipants(int participantCount)
- {
- // check dispose
- ThrowIfDisposed();
-
- // Validate input
- if (participantCount < 1)
- {
- throw new ArgumentOutOfRangeException("participantCount", participantCount,
- SR.Barrier_RemoveParticipants_NonPositive_ArgumentOutOfRange);
- }
-
- // in case of this is called from the PHA
- if (_actionCallerID != 0 && Environment.CurrentManagedThreadId == _actionCallerID)
- {
- throw new InvalidOperationException(SR.Barrier_InvalidOperation_CalledFromPHA);
- }
-
- SpinWait spinner = new SpinWait();
- while (true)
- {
- int currentTotal = _currentTotalCount;
- int total;
- int current;
- bool sense;
- GetCurrentTotal(currentTotal, out current, out total, out sense);
-
- if (total < participantCount)
- {
- throw new ArgumentOutOfRangeException("participantCount",
- SR.Barrier_RemoveParticipants_ArgumentOutOfRange);
- }
- if (total - participantCount < current)
- {
- throw new InvalidOperationException(SR.Barrier_RemoveParticipants_InvalidOperation);
- }
- // If the remaining participats = current participants, then finish the current phase
- int remaingParticipants = total - participantCount;
- if (remaingParticipants > 0 && current == remaingParticipants)
- {
- if (SetCurrentTotal(currentTotal, 0, total - participantCount, !sense))
- {
- FinishPhase(sense);
- break;
- }
- }
- else
- {
- if (SetCurrentTotal(currentTotal, current, total - participantCount, sense))
- {
- break;
- }
- }
- spinner.SpinOnce();
- }
- }
-
- /// <summary>
- /// Signals that a participant has reached the <see cref="Barrier"/> and waits for all other
- /// participants to reach the barrier as well.
- /// </summary>
- /// <exception cref="T:System.InvalidOperationException">
- /// The method was invoked from within a post-phase action, the barrier currently has 0 participants,
- /// or the barrier is being used by more threads than are registered as participants.
- /// </exception>
- /// <exception cref="T:System.ObjectDisposedException">The current instance has already been
- /// disposed.</exception>
- public void SignalAndWait()
- {
- SignalAndWait(new CancellationToken());
- }
-
- /// <summary>
- /// Signals that a participant has reached the <see cref="Barrier"/> and waits for all other
- /// participants to reach the barrier, while observing a <see
- /// cref="T:System.Threading.CancellationToken"/>.
- /// </summary>
- /// <param name="cancellationToken">The <see cref="T:System.Threading.CancellationToken"/> to
- /// observe.</param>
- /// <exception cref="T:System.InvalidOperationException">
- /// The method was invoked from within a post-phase action, the barrier currently has 0 participants,
- /// or the barrier is being used by more threads than are registered as participants.
- /// </exception>
- /// <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 SignalAndWait(CancellationToken cancellationToken)
- {
-#if DEBUG
- bool result =
-#endif
- SignalAndWait(Timeout.Infinite, cancellationToken);
-#if DEBUG
- Debug.Assert(result);
-#endif
- }
-
- /// <summary>
- /// Signals that a participant has reached the <see cref="Barrier"/> and waits for all other
- /// participants to reach the barrier as well, 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 all other participants reached the barrier; 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 it is greater than
- /// <see cref="T:System.Int32.MaxValue"/>.</exception>
- /// <exception cref="T:System.InvalidOperationException">
- /// The method was invoked from within a post-phase action, the barrier currently has 0 participants,
- /// or the barrier is being used by more threads than are registered as participants.
- /// </exception>
- /// <exception cref="T:System.ObjectDisposedException">The current instance has already been
- /// disposed.</exception>
- public Boolean SignalAndWait(TimeSpan timeout)
- {
- return SignalAndWait(timeout, new CancellationToken());
- }
-
- /// <summary>
- /// Signals that a participant has reached the <see cref="Barrier"/> and waits for all other
- /// participants to reach the barrier as well, 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 all other participants reached the barrier; 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.</exception>
- /// <exception cref="T:System.InvalidOperationException">
- /// The method was invoked from within a post-phase action, the barrier currently has 0 participants,
- /// or the barrier is being used by more threads than are registered as participants.
- /// </exception>
- /// <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 Boolean SignalAndWait(TimeSpan timeout, CancellationToken cancellationToken)
- {
- Int64 totalMilliseconds = (Int64)timeout.TotalMilliseconds;
- if (totalMilliseconds < -1 || totalMilliseconds > int.MaxValue)
- {
- throw new System.ArgumentOutOfRangeException("timeout", timeout,
- SR.Barrier_SignalAndWait_ArgumentOutOfRange);
- }
- return SignalAndWait((int)timeout.TotalMilliseconds, cancellationToken);
- }
-
- /// <summary>
- /// Signals that a participant has reached the <see cref="Barrier"/> and waits for all other
- /// participants to reach the barrier as well, 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 all other participants reached the barrier; otherwise, false.</returns>
- /// <exception cref="T:System.ArgumentOutOfRangeException"><paramref name="millisecondsTimeout"/> is a
- /// negative number other than -1, which represents an infinite time-out.</exception>
- /// <exception cref="T:System.InvalidOperationException">
- /// The method was invoked from within a post-phase action, the barrier currently has 0 participants,
- /// or the barrier is being used by more threads than are registered as participants.
- /// </exception>
- /// <exception cref="T:System.ObjectDisposedException">The current instance has already been
- /// disposed.</exception>
- public bool SignalAndWait(int millisecondsTimeout)
- {
- return SignalAndWait(millisecondsTimeout, new CancellationToken());
- }
-
- /// <summary>
- /// Signals that a participant has reached the barrier and waits for all other participants to reach
- /// the barrier as well, 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 all other participants reached the barrier; otherwise, false.</returns>
- /// <exception cref="T:System.ArgumentOutOfRangeException"><paramref name="millisecondsTimeout"/> is a
- /// negative number other than -1, which represents an infinite time-out.</exception>
- /// <exception cref="T:System.InvalidOperationException">
- /// The method was invoked from within a post-phase action, the barrier currently has 0 participants,
- /// or the barrier is being used by more threads than are registered as participants.
- /// </exception>
- /// <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 bool SignalAndWait(int millisecondsTimeout, CancellationToken cancellationToken)
- {
- ThrowIfDisposed();
- cancellationToken.ThrowIfCancellationRequested();
-
- if (millisecondsTimeout < -1)
- {
- throw new System.ArgumentOutOfRangeException("millisecondsTimeout", millisecondsTimeout,
- SR.Barrier_SignalAndWait_ArgumentOutOfRange);
- }
-
- // in case of this is called from the PHA
- if (_actionCallerID != 0 && Environment.CurrentManagedThreadId == _actionCallerID)
- {
- throw new InvalidOperationException(SR.Barrier_InvalidOperation_CalledFromPHA);
- }
-
- // local variables to extract the basic barrier variable and update them
- // The are declared here instead of inside the loop body because the will be used outside the loop
- bool sense; // The sense of the barrier *before* the phase associated with this SignalAndWait call completes
- int total;
- int current;
- int currentTotal;
- long phase;
- SpinWait spinner = new SpinWait();
- while (true)
- {
- currentTotal = _currentTotalCount;
- GetCurrentTotal(currentTotal, out current, out total, out sense);
- phase = CurrentPhaseNumber;
- // throw if zero participants
- if (total == 0)
- {
- throw new InvalidOperationException(SR.Barrier_SignalAndWait_InvalidOperation_ZeroTotal);
- }
- // Try to detect if the number of threads for this phase exceeded the total number of participants or not
- // This can be detected if the current is zero which means all participants for that phase has arrived and the phase number is not changed yet
- if (current == 0 && sense != (CurrentPhaseNumber % 2 == 0))
- {
- throw new InvalidOperationException(SR.Barrier_SignalAndWait_InvalidOperation_ThreadsExceeded);
- }
- //This is the last thread, finish the phase
- if (current + 1 == total)
- {
- if (SetCurrentTotal(currentTotal, 0, total, !sense))
- {
- if (CdsSyncEtwBCLProvider.Log.IsEnabled())
- {
- CdsSyncEtwBCLProvider.Log.Barrier_PhaseFinished(sense, CurrentPhaseNumber);
- }
- FinishPhase(sense);
- return true;
- }
- }
- else if (SetCurrentTotal(currentTotal, current + 1, total, sense))
- {
- break;
- }
-
- spinner.SpinOnce();
- }
-
- // ** Perform the real wait **
- // select the correct event to wait on, based on the current sense.
- ManualResetEventSlim eventToWaitOn = (sense) ? _evenEvent : _oddEvent;
-
- bool waitWasCanceled = false;
- bool waitResult = false;
- try
- {
- waitResult = DiscontinuousWait(eventToWaitOn, millisecondsTimeout, cancellationToken, phase);
- }
- catch (OperationCanceledException)
- {
- waitWasCanceled = true;
- }
- catch (ObjectDisposedException)// in case a race happen where one of the thread returned from SignalAndWait and the current thread calls Wait on a disposed event
- {
- // make sure the current phase for this thread is already finished, otherwise propagate the exception
- if (phase < CurrentPhaseNumber)
- waitResult = true;
- else
- throw;
- }
-
-
-
- if (!waitResult)
- {
- //reset the spinLock to prepare it for the next loop
- spinner.Reset();
-
- //If the wait timeout expired and all other thread didn't reach the barrier yet, update the current count back
- while (true)
- {
- bool newSense;
- currentTotal = _currentTotalCount;
- GetCurrentTotal(currentTotal, out current, out total, out newSense);
- // If the timeout expired and the phase has just finished, return true and this is considered as succeeded SignalAndWait
- //otherwise the timeout expired and the current phase has not been finished yet, return false
- //The phase is finished if the phase member variable is changed (incremented) or the sense has been changed
- // we have to use the statements in the comparison below for two cases:
- // 1- The sense is changed but the last thread didn't update the phase yet
- // 2- The phase is already incremented but the sense flipped twice due to the termination of the next phase
- if (phase < CurrentPhaseNumber || sense != newSense)
- {
- // The current phase has been finished, but we shouldn't return before the events are set/reset otherwise this thread could start
- // next phase and the appropriate event has not reset yet which could make it return immediately from the next phase SignalAndWait
- // before waiting other threads
- WaitCurrentPhase(eventToWaitOn, phase);
- Debug.Assert(phase < CurrentPhaseNumber);
- break;
- }
- //The phase has not been finished yet, try to update the current count.
- if (SetCurrentTotal(currentTotal, current - 1, total, sense))
- {
- //if here, then the attempt to backout was successful.
- //throw (a fresh) oce if cancellation woke the wait
- //or return false if it was the timeout that woke the wait.
- //
- if (waitWasCanceled)
- throw new OperationCanceledException(SR.Common_OperationCanceled, cancellationToken);
- else
- return false;
- }
- spinner.SpinOnce();
- }
- }
-
- if (_exception != null)
- throw new BarrierPostPhaseException(_exception);
-
- return true;
- }
-
- /// <summary>
- /// Finish the phase by invoking the post phase action, and setting the event, this must be called by the
- /// last arrival thread
- /// </summary>
- /// <param name="observedSense">The current phase sense</param>
- [SecuritySafeCritical]
- private void FinishPhase(bool observedSense)
- {
- // Execute the PHA in try/finally block to reset the variables back in case of it threw an exception
- if (_postPhaseAction != null)
- {
- try
- {
- // Capture the caller thread ID to check if the Add/RemoveParticipant(s) is called from the PHA
- _actionCallerID = Environment.CurrentManagedThreadId;
- if (_ownerThreadContext != null)
- {
- var currentContext = _ownerThreadContext;
-
- ContextCallback handler = s_invokePostPhaseAction;
- if (handler == null)
- {
- s_invokePostPhaseAction = handler = InvokePostPhaseAction;
- }
- ExecutionContext.Run(_ownerThreadContext, handler, this);
- }
- else
- {
- _postPhaseAction(this);
- }
-
- _exception = null; // reset the exception if it was set previously
- }
- catch (Exception ex)
- {
- _exception = ex;
- }
- finally
- {
- _actionCallerID = 0;
- SetResetEvents(observedSense);
- if (_exception != null)
- throw new BarrierPostPhaseException(_exception);
- }
- }
- else
- {
- SetResetEvents(observedSense);
- }
- }
-
- /// <summary>
- /// Helper method to call the post phase action
- /// </summary>
- /// <param name="obj"></param>
- [SecurityCritical]
- private static void InvokePostPhaseAction(object obj)
- {
- var thisBarrier = (Barrier)obj;
- thisBarrier._postPhaseAction(thisBarrier);
- }
-
- /// <summary>
- /// Sets the current phase event and reset the next phase event
- /// </summary>
- /// <param name="observedSense">The current phase sense</param>
- private void SetResetEvents(bool observedSense)
- {
- // Increment the phase count using Volatile class because m_currentPhase is 64 bit long type, that could cause torn write on 32 bit machines
- CurrentPhaseNumber = CurrentPhaseNumber + 1;
- if (observedSense)
- {
- _oddEvent.Reset();
- _evenEvent.Set();
- }
- else
- {
- _evenEvent.Reset();
- _oddEvent.Set();
- }
- }
-
- /// <summary>
- /// Wait until the current phase finishes completely by spinning until either the event is set,
- /// or the phase count is incremented more than one time
- /// </summary>
- /// <param name="currentPhaseEvent">The current phase event</param>
- /// <param name="observedPhase">The current phase for that thread</param>
- private void WaitCurrentPhase(ManualResetEventSlim currentPhaseEvent, long observedPhase)
- {
- //spin until either of these two conditions succeeds
- //1- The event is set
- //2- the phase count is incremented more than one time, this means the next phase is finished as well,
- //but the event will be reset again, so we check the phase count instead
- SpinWait spinner = new SpinWait();
- while (!currentPhaseEvent.IsSet && CurrentPhaseNumber - observedPhase <= 1)
- {
- spinner.SpinOnce();
- }
- }
-
- /// <summary>
- /// The reason of discontinuous waiting instead of direct waiting on the event is to avoid the race where the sense is
- /// changed twice because the next phase is finished (due to either RemoveParticipant is called or another thread joined
- /// the next phase instead of the current thread) so the current thread will be stuck on the event because it is reset back
- /// The maxwait and the shift numbers are arbitrarily choosen, there were no references picking them
- /// </summary>
- /// <param name="currentPhaseEvent">The current phase event</param>
- /// <param name="totalTimeout">wait timeout in milliseconds</param>
- /// <param name="token">cancellation token passed to SignalAndWait</param>
- /// <param name="observedPhase">The current phase number for this thread</param>
- /// <returns>True if the event is set or the phasenumber changed, false if the timeout expired</returns>
- private bool DiscontinuousWait(ManualResetEventSlim currentPhaseEvent, int totalTimeout, CancellationToken token, long observedPhase)
- {
- int maxWait = 100; // 100 ms
- int waitTimeCeiling = 10000; // 10 seconds
- while (observedPhase == CurrentPhaseNumber)
- {
- // the next wait time, the min of the maxWait and the totalTimeout
- int waitTime = totalTimeout == Timeout.Infinite ? maxWait : Math.Min(maxWait, totalTimeout);
-
- if (currentPhaseEvent.Wait(waitTime, token))
- return true;
-
- //update the total wait time
- if (totalTimeout != Timeout.Infinite)
- {
- totalTimeout -= waitTime;
- if (totalTimeout <= 0)
- return false;
- }
-
- //if the maxwait exceeded 10 seconds then we will stop increasing the maxWait time and keep it 10 seconds, otherwise keep doubling it
- maxWait = maxWait >= waitTimeCeiling ? waitTimeCeiling : Math.Min(maxWait << 1, waitTimeCeiling);
- }
-
- //if we exited the loop because the observed phase doesn't match the current phase, then we have to spin to mske sure
- //the event is set or the next phase is finished
- WaitCurrentPhase(currentPhaseEvent, observedPhase);
-
- return true;
- }
-
- /// <summary>
- /// Releases all resources used by the current instance of <see cref="Barrier"/>.
- /// </summary>
- /// <exception cref="T:System.InvalidOperationException">
- /// The method was invoked from within a post-phase action.
- /// </exception>
- /// <remarks>
- /// Unlike most of the members of <see cref="Barrier"/>, Dispose is not thread-safe and may not be
- /// used concurrently with other members of this instance.
- /// </remarks>
- public void Dispose()
- {
- // in case of this is called from the PHA
- if (_actionCallerID != 0 && Environment.CurrentManagedThreadId == _actionCallerID)
- {
- throw new InvalidOperationException(SR.Barrier_InvalidOperation_CalledFromPHA);
- }
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- /// <summary>
- /// When overridden in a derived class, releases the unmanaged resources used by the
- /// <see cref="Barrier"/>, 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="Barrier"/>, 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 (!_disposed)
- {
- if (disposing)
- {
- _oddEvent.Dispose();
- _evenEvent.Dispose();
- }
- _disposed = true;
- }
- }
-
- /// <summary>
- /// Throw ObjectDisposedException if the barrier is disposed
- /// </summary>
- private void ThrowIfDisposed()
- {
- if (_disposed)
- {
- throw new ObjectDisposedException("Barrier", SR.Barrier_Dispose);
- }
- }
- }
-}
diff --git a/src/Common/src/System/Threading/CDSsyncETWBCLProvider.cs b/src/Common/src/System/Threading/CDSsyncETWBCLProvider.cs
deleted file mode 100644
index b42450aaa..000000000
--- a/src/Common/src/System/Threading/CDSsyncETWBCLProvider.cs
+++ /dev/null
@@ -1,117 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-
-// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
-//
-// A helper class for firing ETW events related to the Coordination Data Structure
-// sync primitives. This provider is used by CDS sync primitives in both mscorlib.dll
-// and system.dll. The purpose of sharing the provider class is to be able to enable
-// ETW tracing on all CDS sync types with a single ETW provider GUID, and to minimize
-// the number of providers in use.
-//
-// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-
-using System;
-using System.Collections.Generic;
-using System.Text;
-using System.Security;
-using System.Diagnostics.Tracing;
-
-namespace System.Threading
-{
- /// <summary>Provides an event source for tracing CDS synchronization information.</summary>
- [EventSource(
- Name = "System.Threading.SynchronizationEventSource",
- Guid = "EC631D38-466B-4290-9306-834971BA0217"
- //TODO:(TFS455853):Add support for reading localized string in the EventSource il2il transform
- //,LocalizationResources = "mscorlib"
- )]
- internal sealed class CdsSyncEtwBCLProvider : EventSource
- {
- /// <summary>
- /// Defines the singleton instance for the CDS Sync ETW provider.
- /// The CDS Sync Event provider GUID is {EC631D38-466B-4290-9306-834971BA0217}.
- /// </summary>
- public static CdsSyncEtwBCLProvider Log = new CdsSyncEtwBCLProvider();
- /// <summary>Prevent external instantiation. All logging should go through the Log instance.</summary>
- private CdsSyncEtwBCLProvider() { }
-
- /// <summary>Enabled for all keywords.</summary>
- private const EventKeywords ALL_KEYWORDS = (EventKeywords)(-1);
-
- //-----------------------------------------------------------------------------------
- //
- // CDS Synchronization Event IDs (must be unique)
- //
-
- private const int SPINLOCK_FASTPATHFAILED_ID = 1;
- private const int SPINWAIT_NEXTSPINWILLYIELD_ID = 2;
- private const int BARRIER_PHASEFINISHED_ID = 3;
-
- /////////////////////////////////////////////////////////////////////////////////////
- //
- // SpinLock Events
- //
-
- [Event(SPINLOCK_FASTPATHFAILED_ID, Level = EventLevel.Warning)]
- public void SpinLock_FastPathFailed(int ownerID)
- {
- if (IsEnabled(EventLevel.Warning, ALL_KEYWORDS))
- {
- WriteEvent(SPINLOCK_FASTPATHFAILED_ID, ownerID);
- }
- }
-
- /////////////////////////////////////////////////////////////////////////////////////
- //
- // SpinWait Events
- //
-
- [Event(SPINWAIT_NEXTSPINWILLYIELD_ID, Level = EventLevel.Informational)]
- public void SpinWait_NextSpinWillYield()
- {
- if (IsEnabled(EventLevel.Informational, ALL_KEYWORDS))
- {
- WriteEvent(SPINWAIT_NEXTSPINWILLYIELD_ID);
- }
- }
-
-
- //
- // Events below this point are used by the CDS types in System.dll
- //
-
- /////////////////////////////////////////////////////////////////////////////////////
- //
- // Barrier Events
- //
-
- [SecuritySafeCritical]
- [Event(BARRIER_PHASEFINISHED_ID, Level = EventLevel.Verbose, Version = 1)]
- public void Barrier_PhaseFinished(bool currentSense, long phaseNum)
- {
- if (IsEnabled(EventLevel.Verbose, ALL_KEYWORDS))
- {
- // WriteEvent(BARRIER_PHASEFINISHED_ID, currentSense, phaseNum);
-
- // There is no explicit WriteEvent() overload matching this event's bool+long fields.
- // Therefore calling WriteEvent() would hit the "params" overload, which leads to an
- // object allocation every time this event is fired. To prevent that problem we will
- // call WriteEventCore(), which works with a stack based EventData array populated with
- // the event fields.
- unsafe
- {
- EventData* eventPayload = stackalloc EventData[2];
-
- Int32 senseAsInt32 = currentSense ? 1 : 0; // write out Boolean as Int32
- eventPayload[0].Size = sizeof(int);
- eventPayload[0].DataPointer = ((IntPtr)(&senseAsInt32));
- eventPayload[1].Size = sizeof(long);
- eventPayload[1].DataPointer = ((IntPtr)(&phaseNum));
-
- WriteEventCore(BARRIER_PHASEFINISHED_ID, 2, eventPayload);
- }
- }
- }
- }
-}
diff --git a/src/Common/src/System/Threading/CountdownEvent.cs b/src/Common/src/System/Threading/CountdownEvent.cs
deleted file mode 100644
index d27caa9f8..000000000
--- a/src/Common/src/System/Threading/CountdownEvent.cs
+++ /dev/null
@@ -1,585 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-
-// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
-//
-// A simple coordination data structure that we use for fork/join style parallelism.
-//
-// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-
-using System;
-using System.Diagnostics;
-using System.Runtime.InteropServices;
-using System.Threading;
-
-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>
- [ComVisible(false)]
- [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 _initialCount; // The original # of signals the latch was instantiated with.
- private volatile int _currentCount; // The # of outstanding signals before the latch transitions to a signaled state.
- private ManualResetEventSlim _event; // An event used to manage blocking and signaling.
- private volatile bool _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("initialCount");
- }
-
- _initialCount = initialCount;
- _currentCount = initialCount;
-
- // Allocate a thin event, which internally defers creation of an actual Win32 event.
- _event = new ManualResetEventSlim();
-
- // If the latch was created with a count of 0, then it's already in the signaled state.
- if (initialCount == 0)
- {
- _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 = _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 _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 (_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 _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)
- {
- _event.Dispose();
- _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(_event != null);
-
- if (_currentCount <= 0)
- {
- throw new InvalidOperationException(SR.CountdownEvent_Decrement_BelowZero);
- }
-#pragma warning disable 0420
- int newCount = Interlocked.Decrement(ref _currentCount);
-#pragma warning restore 0420
- if (newCount == 0)
- {
- _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(SR.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("signalCount");
- }
-
- ThrowIfDisposed();
- Debug.Assert(_event != null);
-
- int observedCount;
- SpinWait spin = new SpinWait();
- while (true)
- {
- observedCount = _currentCount;
-
- // If the latch is already signaled, we will fail.
- if (observedCount < signalCount)
- {
- throw new InvalidOperationException(SR.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 _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)
- {
- _event.Set();
- return true;
- }
-
- Debug.Assert(_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(SR.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("signalCount");
- }
-
- ThrowIfDisposed();
-
- // Loop around until we successfully increment the count.
- int observedCount;
- SpinWait spin = new SpinWait();
- while (true)
- {
- observedCount = _currentCount;
-
- if (observedCount <= 0)
- {
- return false;
- }
- else if (observedCount > (Int32.MaxValue - signalCount))
- {
- throw new InvalidOperationException(SR.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 _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(_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("count");
- }
-
- _currentCount = count;
- _initialCount = count;
-
- if (count == 0)
- {
- _event.Set();
- }
- else
- {
- _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("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("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("millisecondsTimeout");
- }
-
- ThrowIfDisposed();
- cancellationToken.ThrowIfCancellationRequested();
-
- bool returnValue = IsSet;
-
- // If not completed yet, wait on the event.
- if (!returnValue)
- {
- // ** the actual wait
- returnValue = _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 (_disposed)
- {
- throw new ObjectDisposedException("CountdownEvent");
- }
- }
- }
-}
diff --git a/src/Common/src/System/Threading/Progress.cs b/src/Common/src/System/Threading/Progress.cs
deleted file mode 100644
index 4b1f64f1c..000000000
--- a/src/Common/src/System/Threading/Progress.cs
+++ /dev/null
@@ -1,104 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-
-using System;
-using System.Threading;
-using System.Diagnostics;
-
-namespace System
-{
- /// <summary>
- /// Provides an IProgress{T} that invokes callbacks for each reported progress value.
- /// </summary>
- /// <typeparam name="T">Specifies the type of the progress report value.</typeparam>
- /// <remarks>
- /// Any handler provided to the constructor or event handlers registered with
- /// the <see cref="ProgressChanged"/> event are invoked through a
- /// <see cref="System.Threading.SynchronizationContext"/> instance captured
- /// when the instance is constructed. If there is no current SynchronizationContext
- /// at the time of construction, the callbacks will be invoked on the ThreadPool.
- /// </remarks>
- public class Progress<T> : IProgress<T>
- {
- /// <summary>The synchronization context captured upon construction. This will never be null.</summary>
- private readonly SynchronizationContext _synchronizationContext;
- /// <summary>The handler specified to the constructor. This may be null.</summary>
- private readonly Action<T> _handler;
- /// <summary>A cached delegate used to post invocation to the synchronization context.</summary>
- private readonly SendOrPostCallback _invokeHandlers;
-
- /// <summary>Initializes the <see cref="Progress{T}"/>.</summary>
- public Progress()
- {
- // Capture the current synchronization context.
- // If there is no current context, we use a default instance targeting the ThreadPool.
- _synchronizationContext = SynchronizationContext.Current ?? ProgressStatics.DefaultContext;
- Debug.Assert(_synchronizationContext != null);
- _invokeHandlers = new SendOrPostCallback(InvokeHandlers);
- }
-
- /// <summary>Initializes the <see cref="Progress{T}"/> with the specified callback.</summary>
- /// <param name="handler">
- /// A handler to invoke for each reported progress value. This handler will be invoked
- /// in addition to any delegates registered with the <see cref="ProgressChanged"/> event.
- /// Depending on the <see cref="System.Threading.SynchronizationContext"/> instance captured by
- /// the <see cref="Progress"/> at construction, it's possible that this handler instance
- /// could be invoked concurrently with itself.
- /// </param>
- /// <exception cref="System.ArgumentNullException">The <paramref name="handler"/> is null (Nothing in Visual Basic).</exception>
- public Progress(Action<T> handler) : this()
- {
- if (handler == null) throw new ArgumentNullException("handler");
- _handler = handler;
- }
-
- /// <summary>Raised for each reported progress value.</summary>
- /// <remarks>
- /// Handlers registered with this event will be invoked on the
- /// <see cref="System.Threading.SynchronizationContext"/> captured when the instance was constructed.
- /// </remarks>
- public event EventHandler<T> ProgressChanged;
-
- /// <summary>Reports a progress change.</summary>
- /// <param name="value">The value of the updated progress.</param>
- protected virtual void OnReport(T value)
- {
- // If there's no handler, don't bother going through the sync context.
- // Inside the callback, we'll need to check again, in case
- // an event handler is removed between now and then.
- Action<T> handler = _handler;
- EventHandler<T> changedEvent = ProgressChanged;
- if (handler != null || changedEvent != null)
- {
- // Post the processing to the sync context.
- // (If T is a value type, it will get boxed here.)
- _synchronizationContext.Post(_invokeHandlers, value);
- }
- }
-
- /// <summary>Reports a progress change.</summary>
- /// <param name="value">The value of the updated progress.</param>
- void IProgress<T>.Report(T value) { OnReport(value); }
-
- /// <summary>Invokes the action and event callbacks.</summary>
- /// <param name="state">The progress value.</param>
- private void InvokeHandlers(object state)
- {
- T value = (T)state;
-
- Action<T> handler = _handler;
- EventHandler<T> changedEvent = ProgressChanged;
-
- if (handler != null) handler(value);
- if (changedEvent != null) changedEvent(this, value);
- }
- }
-
- /// <summary>Holds static values for <see cref="Progress{T}"/>.</summary>
- /// <remarks>This avoids one static instance per type T.</remarks>
- internal static class ProgressStatics
- {
- /// <summary>A default synchronization context that targets the ThreadPool.</summary>
- internal static readonly SynchronizationContext DefaultContext = new SynchronizationContext();
- }
-}
diff --git a/src/Common/src/System/Threading/ReaderWriterLockSlim.cs b/src/Common/src/System/Threading/ReaderWriterLockSlim.cs
deleted file mode 100644
index b5c761e18..000000000
--- a/src/Common/src/System/Threading/ReaderWriterLockSlim.cs
+++ /dev/null
@@ -1,1294 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-
-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 specifiation for myLock: This lock protects exactly the local fields associted
- // instance of ReaderWriterLockSlim. It does NOT protect the memory associted with the
- // the events that hang off this lock (eg writeEvent, readEvent upgradeEvent).
- private int _myLock;
-
- //The variables controlling spinning behaviior 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 aquire a write lock go here.
- private EventWaitHandle _readEvent; // threads waiting to aquire 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 it's 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("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("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 struucture).
- 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);
- 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);
-
- //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);
- //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);
- 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)
- {
-#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 aboutto throw for some reason. Exit myLock.
- 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()
- {
- bool setUpgradeEvent = false;
- bool setReadEvent = false;
- 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 droppping 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 if (readercount >= 0)
- {
- if (_numReadWaiters != 0 || _numUpgradeWaiters != 0)
- {
- if (_numReadWaiters != 0)
- setReadEvent = true;
-
- if (_numUpgradeWaiters != 0 && _upgradeLockOwnerId == -1)
- {
- setUpgradeEvent = true;
- }
-
- 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.
- }
- else
- ExitMyLock();
- }
- else
- ExitMyLock();
- }
-
- 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)
- {
- Helpers.Spin(LockSpinCycles * (i + 1)); // Wait a few dozen instructions to let another processor release lock.
- }
- else if (i < (LockSpinCount + LockSleep0Count))
- {
- Helpers.Sleep(0); // Give up my quantum.
- }
- else
- {
- Helpers.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 backoff
- if ((SpinCount < 5) && (Environment.ProcessorCount > 1))
- {
- Helpers.Spin(LockSpinCycles * SpinCount);
- }
- else if (SpinCount < MaxSpinCount - 3)
- {
- Helpers.Sleep(0);
- }
- else
- {
- Helpers.Sleep(1);
- }
- }
-
- public void Dispose()
- {
- Dispose(true);
- }
-
- private void Dispose(bool disposing)
- {
- if (disposing)
- {
- if (_fDisposed)
- throw new ObjectDisposedException(null);
-
- 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/Common/src/System/Threading/TimeoutHelper.cs b/src/Common/src/System/Threading/TimeoutHelper.cs
deleted file mode 100644
index 598641437..000000000
--- a/src/Common/src/System/Threading/TimeoutHelper.cs
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-
-using System.Diagnostics;
-
-namespace System.Threading
-{
- /// <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;
- }
- }
-}