diff options
Diffstat (limited to 'src/mscorlib/src/System/Threading/SemaphoreSlim.cs')
-rw-r--r-- | src/mscorlib/src/System/Threading/SemaphoreSlim.cs | 50 |
1 files changed, 22 insertions, 28 deletions
diff --git a/src/mscorlib/src/System/Threading/SemaphoreSlim.cs b/src/mscorlib/src/System/Threading/SemaphoreSlim.cs index c2dcbb3451..92d760d77d 100644 --- a/src/mscorlib/src/System/Threading/SemaphoreSlim.cs +++ b/src/mscorlib/src/System/Threading/SemaphoreSlim.cs @@ -40,7 +40,6 @@ namespace System.Threading /// </para> /// </remarks> [ComVisible(false)] - [HostProtection(Synchronization = true, ExternalThreading = true)] [DebuggerDisplay("Current Count = {m_currentCount}")] public class SemaphoreSlim : IDisposable { @@ -89,14 +88,12 @@ namespace System.Threading internal TaskNode Prev, Next; internal TaskNode() : base() {} - [SecurityCritical] void IThreadPoolWorkItem.ExecuteWorkItem() { bool setSuccessfully = TrySetResult(true); - Contract.Assert(setSuccessfully, "Should have been able to complete task"); + Debug.Assert(setSuccessfully, "Should have been able to complete task"); } - [SecurityCritical] void IThreadPoolWorkItem.MarkAborted(ThreadAbortException tae) { /* nop */ } } #endregion @@ -182,13 +179,13 @@ namespace System.Threading if (initialCount < 0 || initialCount > maxCount) { throw new ArgumentOutOfRangeException( - "initialCount", initialCount, GetResourceString("SemaphoreSlim_ctor_InitialCountWrong")); + nameof(initialCount), initialCount, GetResourceString("SemaphoreSlim_ctor_InitialCountWrong")); } //validate input if (maxCount <= 0) { - throw new ArgumentOutOfRangeException("maxCount", maxCount, GetResourceString("SemaphoreSlim_ctor_MaxCountWrong")); + throw new ArgumentOutOfRangeException(nameof(maxCount), maxCount, GetResourceString("SemaphoreSlim_ctor_MaxCountWrong")); } m_maxCount = maxCount; @@ -245,7 +242,7 @@ namespace System.Threading if (totalMilliseconds < -1 || totalMilliseconds > Int32.MaxValue) { throw new System.ArgumentOutOfRangeException( - "timeout", timeout, GetResourceString("SemaphoreSlim_Wait_TimeoutWrong")); + nameof(timeout), timeout, GetResourceString("SemaphoreSlim_Wait_TimeoutWrong")); } // Call wait with the timeout milliseconds @@ -275,7 +272,7 @@ namespace System.Threading if (totalMilliseconds < -1 || totalMilliseconds > Int32.MaxValue) { throw new System.ArgumentOutOfRangeException( - "timeout", timeout, GetResourceString("SemaphoreSlim_Wait_TimeoutWrong")); + nameof(timeout), timeout, GetResourceString("SemaphoreSlim_Wait_TimeoutWrong")); } // Call wait with the timeout milliseconds @@ -372,7 +369,7 @@ namespace System.Threading // then block on (once we've released the lock). if (m_asyncHead != null) { - Contract.Assert(m_asyncTail != null, "tail should not be null if head isn't"); + Debug.Assert(m_asyncTail != null, "tail should not be null if head isn't"); asyncWaitTask = WaitAsync(millisecondsTimeout, cancellationToken); } // There are no async waiters, so we can proceed with normal synchronous waiting. @@ -404,7 +401,7 @@ namespace System.Threading // defer to synchronous waiters in priority, which means that if it's possible an asynchronous // waiter didn't get released because a synchronous waiter was present, we need to ensure // that synchronous waiter succeeds so that they have a chance to release. - Contract.Assert(!waitSuccessful || m_currentCount > 0, + Debug.Assert(!waitSuccessful || m_currentCount > 0, "If the wait was successful, there should be count available."); if (m_currentCount > 0) { @@ -579,7 +576,7 @@ namespace System.Threading if (totalMilliseconds < -1 || totalMilliseconds > Int32.MaxValue) { throw new System.ArgumentOutOfRangeException( - "timeout", timeout, GetResourceString("SemaphoreSlim_Wait_TimeoutWrong")); + nameof(timeout), timeout, GetResourceString("SemaphoreSlim_Wait_TimeoutWrong")); } // Call wait with the timeout milliseconds @@ -638,7 +635,7 @@ namespace System.Threading // the semaphore or when the timeout expired or cancellation was requested. else { - Contract.Assert(m_currentCount == 0, "m_currentCount should never be negative"); + Debug.Assert(m_currentCount == 0, "m_currentCount should never be negative"); var asyncWaiter = CreateAndAddAsyncWaiter(); return (millisecondsTimeout == Timeout.Infinite && !cancellationToken.CanBeCanceled) ? asyncWaiter : @@ -651,7 +648,7 @@ namespace System.Threading /// <returns>The created task.</returns> private TaskNode CreateAndAddAsyncWaiter() { - Contract.Assert(Monitor.IsEntered(m_lockObj), "Requires the lock be held"); + Debug.Assert(Monitor.IsEntered(m_lockObj), "Requires the lock be held"); // Create the task var task = new TaskNode(); @@ -659,13 +656,13 @@ namespace System.Threading // Add it to the linked list if (m_asyncHead == null) { - Contract.Assert(m_asyncTail == null, "If head is null, so too should be tail"); + Debug.Assert(m_asyncTail == null, "If head is null, so too should be tail"); m_asyncHead = task; m_asyncTail = task; } else { - Contract.Assert(m_asyncTail != null, "If head is not null, neither should be tail"); + Debug.Assert(m_asyncTail != null, "If head is not null, neither should be tail"); m_asyncTail.Next = task; task.Prev = m_asyncTail; m_asyncTail = task; @@ -681,7 +678,7 @@ namespace System.Threading private bool RemoveAsyncWaiter(TaskNode task) { Contract.Requires(task != null, "Expected non-null task"); - Contract.Assert(Monitor.IsEntered(m_lockObj), "Requires the lock be held"); + Debug.Assert(Monitor.IsEntered(m_lockObj), "Requires the lock be held"); // Is the task in the list? To be in the list, either it's the head or it has a predecessor that's in the list. bool wasInList = m_asyncHead == task || task.Prev != null; @@ -691,7 +688,7 @@ namespace System.Threading if (task.Prev != null) task.Prev.Next = task.Next; if (m_asyncHead == task) m_asyncHead = task.Next; if (m_asyncTail == task) m_asyncTail = task.Prev; - Contract.Assert((m_asyncHead == null) == (m_asyncTail == null), "Head is null iff tail is null"); + Debug.Assert((m_asyncHead == null) == (m_asyncTail == null), "Head is null iff tail is null"); // Make sure not to leak task.Next = task.Prev = null; @@ -706,8 +703,8 @@ namespace System.Threading /// <returns>The task to return to the caller.</returns> private async Task<bool> WaitUntilCountOrTimeoutAsync(TaskNode asyncWaiter, int millisecondsTimeout, CancellationToken cancellationToken) { - Contract.Assert(asyncWaiter != null, "Waiter should have been constructed"); - Contract.Assert(Monitor.IsEntered(m_lockObj), "Requires the lock be held"); + Debug.Assert(asyncWaiter != null, "Waiter should have been constructed"); + Debug.Assert(Monitor.IsEntered(m_lockObj), "Requires the lock be held"); // Wait until either the task is completed, timeout occurs, or cancellation is requested. // We need to ensure that the Task.Delay task is appropriately cleaned up if the await @@ -776,7 +773,7 @@ namespace System.Threading if (releaseCount < 1) { throw new ArgumentOutOfRangeException( - "releaseCount", releaseCount, GetResourceString("SemaphoreSlim_Release_CountWrong")); + nameof(releaseCount), releaseCount, GetResourceString("SemaphoreSlim_Release_CountWrong")); } int returnCount; @@ -797,14 +794,12 @@ namespace System.Threading // Signal to any synchronous waiters int waitCount = m_waitCount; - if (currentCount == 1 || waitCount == 1) + + int waitersToNotify = Math.Min(releaseCount, waitCount); + for (int i = 0; i < waitersToNotify; i++) { Monitor.Pulse(m_lockObj); } - else if (waitCount > 1) - { - Monitor.PulseAll(m_lockObj); - } // Now signal to any asynchronous waiters, if there are any. While we've already // signaled the synchronous waiters, we still hold the lock, and thus @@ -814,7 +809,7 @@ namespace System.Threading // waits are canceled, but the wait code path will handle that. if (m_asyncHead != null) { - Contract.Assert(m_asyncTail != null, "tail should not be null if head isn't null"); + Debug.Assert(m_asyncTail != null, "tail should not be null if head isn't null"); int maxAsyncToRelease = currentCount - waitCount; while (maxAsyncToRelease > 0 && m_asyncHead != null) { @@ -844,7 +839,6 @@ namespace System.Threading /// Queues a waiter task to the ThreadPool. We use this small helper method so that /// the larger Release(count) method does not need to be SecuritySafeCritical. /// </summary> - [SecuritySafeCritical] // for ThreadPool.UnsafeQueueCustomWorkItem private static void QueueWaiterTask(TaskNode waiterTask) { ThreadPool.UnsafeQueueCustomWorkItem(waiterTask, forceGlobal: false); @@ -898,7 +892,7 @@ namespace System.Threading private static void CancellationTokenCanceledEventHandler(object obj) { SemaphoreSlim semaphore = obj as SemaphoreSlim; - Contract.Assert(semaphore != null, "Expected a SemaphoreSlim"); + Debug.Assert(semaphore != null, "Expected a SemaphoreSlim"); lock (semaphore.m_lockObj) { Monitor.PulseAll(semaphore.m_lockObj); //wake up all waiters. |