From 970ecb4642bbfbee6f14c94a3709ba99779d43c5 Mon Sep 17 00:00:00 2001 From: Anipik Date: Tue, 26 Jun 2018 18:07:33 -0700 Subject: [PATCH 1/9] Moving SafeWaitHandle to shared --- .../System.Private.CoreLib.csproj | 3 +-- .../Windows/Kernel32/Interop.CloseHandle.cs | 1 - .../Win32/SafeHandles/SafeWaitHandle.cs | 20 +++++++------------ .../System.Private.CoreLib.Shared.projitems | 3 ++- 4 files changed, 10 insertions(+), 17 deletions(-) rename src/System.Private.CoreLib/{src => shared}/Microsoft/Win32/SafeHandles/SafeWaitHandle.cs (67%) diff --git a/src/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/System.Private.CoreLib/System.Private.CoreLib.csproj index 9e8d9f7fe732..032e790c12d4 100644 --- a/src/System.Private.CoreLib/System.Private.CoreLib.csproj +++ b/src/System.Private.CoreLib/System.Private.CoreLib.csproj @@ -1,4 +1,4 @@ - + @@ -488,7 +488,6 @@ - diff --git a/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.CloseHandle.cs b/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.CloseHandle.cs index 96ed922a846d..ff41f939f1c6 100644 --- a/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.CloseHandle.cs +++ b/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.CloseHandle.cs @@ -10,7 +10,6 @@ internal partial class Interop internal partial class Kernel32 { [DllImport(Libraries.Kernel32, SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool CloseHandle(IntPtr handle); } } diff --git a/src/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeWaitHandle.cs b/src/System.Private.CoreLib/shared/Microsoft/Win32/SafeHandles/SafeWaitHandle.cs similarity index 67% rename from src/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeWaitHandle.cs rename to src/System.Private.CoreLib/shared/Microsoft/Win32/SafeHandles/SafeWaitHandle.cs index 1141e6d027ff..9d608c953011 100644 --- a/src/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeWaitHandle.cs +++ b/src/System.Private.CoreLib/shared/Microsoft/Win32/SafeHandles/SafeWaitHandle.cs @@ -2,21 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -/*============================================================ -** -** -** -** A wrapper for Win32 events (mutexes, auto reset events, and -** manual reset events). Used by WaitHandle. -** -** -===========================================================*/ - using System; using System.Security; using System.Runtime.InteropServices; using System.Runtime.CompilerServices; -using System.Runtime.ConstrainedExecution; using System.Runtime.Versioning; using Microsoft.Win32; using System.Threading; @@ -35,9 +24,14 @@ public SafeWaitHandle(IntPtr existingHandle, bool ownsHandle) : base(ownsHandle) SetHandle(existingHandle); } - override protected bool ReleaseHandle() + protected override bool ReleaseHandle() { - return Win32Native.CloseHandle(handle); +#if !CORECLR && !PLATFORM_WINDOWS + WaitSubsystem.DeleteHandle(handle); + return true; +#else + return Interop.Kernel32.CloseHandle(handle); +#endif } } } diff --git a/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems b/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems index da36623eaff7..e7417738c5ad 100644 --- a/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems +++ b/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems @@ -1,4 +1,4 @@ - + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) @@ -26,6 +26,7 @@ + From c317c4a6846a7cde6c3c3e7a9f50d71b702e93cf Mon Sep 17 00:00:00 2001 From: Anipik Date: Tue, 26 Jun 2018 18:11:05 -0700 Subject: [PATCH 2/9] Moved CancellationToken to shared --- .../System.Private.CoreLib.csproj | 3 +- .../System.Private.CoreLib.Shared.projitems | 3 +- .../System/Threading/CancellationToken.cs | 47 ++++++++++++++----- .../src/Microsoft/Win32/Win32Native.cs | 2 - 4 files changed, 38 insertions(+), 17 deletions(-) rename src/System.Private.CoreLib/{src => shared}/System/Threading/CancellationToken.cs (89%) diff --git a/src/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/System.Private.CoreLib/System.Private.CoreLib.csproj index 032e790c12d4..7f4b167317ca 100644 --- a/src/System.Private.CoreLib/System.Private.CoreLib.csproj +++ b/src/System.Private.CoreLib/System.Private.CoreLib.csproj @@ -1,4 +1,4 @@ - + @@ -402,7 +402,6 @@ - diff --git a/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems b/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems index e7417738c5ad..0ffc92a10230 100644 --- a/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems +++ b/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems @@ -1,4 +1,4 @@ - + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) @@ -581,6 +581,7 @@ + diff --git a/src/System.Private.CoreLib/src/System/Threading/CancellationToken.cs b/src/System.Private.CoreLib/shared/System/Threading/CancellationToken.cs similarity index 89% rename from src/System.Private.CoreLib/src/System/Threading/CancellationToken.cs rename to src/System.Private.CoreLib/shared/System/Threading/CancellationToken.cs index cffaf22cd48d..68e6971a5426 100644 --- a/src/System.Private.CoreLib/src/System/Threading/CancellationToken.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/CancellationToken.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Runtime.CompilerServices; namespace System.Threading { @@ -29,14 +30,14 @@ namespace System.Threading [DebuggerDisplay("IsCancellationRequested = {IsCancellationRequested}")] public readonly struct CancellationToken { - private readonly static Action s_actionToActionObjShunt = obj => ((Action)obj)(); - // The backing TokenSource. // if null, it implicitly represents the same thing as new CancellationToken(false). // When required, it will be instantiated to reflect this. private readonly CancellationTokenSource _source; //!! warning. If more fields are added, the assumptions in CreateLinkedToken may no longer be valid + private readonly static Action s_actionToActionObjShunt = obj => ((Action)obj)(); + /// /// Returns an empty CancellationToken value. /// @@ -136,7 +137,7 @@ public CancellationTokenRegistration Register(Action callback) => Register( s_actionToActionObjShunt, callback ?? throw new ArgumentNullException(nameof(callback)), - useSyncContext: false, + useSynchronizationContext: false, useExecutionContext: true); /// @@ -189,7 +190,7 @@ public CancellationTokenRegistration Register(Action callback, bool useSynchroni /// be used to unregister the callback. /// is null. public CancellationTokenRegistration Register(Action callback, object state) => - Register(callback, state, useSyncContext: false, useExecutionContext: true); + Register(callback, state, useSynchronizationContext: false, useExecutionContext: true); /// /// Registers a delegate that will be called when this @@ -222,19 +223,43 @@ public CancellationTokenRegistration Register(Action callback, object st // helper for internal registration needs that don't require an EC capture (e.g. creating linked token sources, or registering unstarted TPL tasks) // has a handy signature, and skips capturing execution context. internal CancellationTokenRegistration InternalRegisterWithoutEC(Action callback, object state) => - Register(callback, state, useSyncContext: false, useExecutionContext: false); + Register(callback, state, useSynchronizationContext: false, useExecutionContext: false); - // the real work.. - private CancellationTokenRegistration Register(Action callback, object state, bool useSyncContext, bool useExecutionContext) + /// + /// Registers a delegate that will be called when this + /// CancellationToken is canceled. + /// + /// + /// + /// If this token is already in the canceled state, the + /// delegate will be run immediately and synchronously. Any exception the delegate generates will be + /// propagated out of this method call. + /// + /// + /// The delegate to be executed when the CancellationToken is canceled. + /// The state to pass to the when the delegate is invoked. This may be null. + /// A Boolean value that indicates whether to capture + /// the current SynchronizationContext and use it + /// when invoking the . + /// The instance that can + /// be used to unregister the callback. + /// is null. + /// The associated CancellationTokenSource has been disposed. +#if CORECLR + private +#else + [MethodImpl(MethodImplOptions.NoInlining)] + public +#endif + CancellationTokenRegistration Register(Action callback, object state, bool useSynchronizationContext, bool useExecutionContext) { if (callback == null) - { throw new ArgumentNullException(nameof(callback)); - } CancellationTokenSource source = _source; return source != null ? - source.InternalRegister(callback, state, useSyncContext ? SynchronizationContext.Current : null, useExecutionContext ? ExecutionContext.Capture() : null) : + source.InternalRegister(callback, state, useSynchronizationContext ? SynchronizationContext.Current : null, useExecutionContext ? ExecutionContext.Capture() : null) : default; // Nothing to do for tokens than can never reach the canceled state. Give back a dummy registration. } @@ -305,9 +330,7 @@ private CancellationTokenRegistration Register(Action callback, object s public void ThrowIfCancellationRequested() { if (IsCancellationRequested) - { ThrowOperationCanceledException(); - } } // Throws an OCE; separated out to enable better inlining of ThrowIfCancellationRequested diff --git a/src/System.Private.CoreLib/src/Microsoft/Win32/Win32Native.cs b/src/System.Private.CoreLib/src/Microsoft/Win32/Win32Native.cs index a53ec792295a..d1a92a3e0f79 100644 --- a/src/System.Private.CoreLib/src/Microsoft/Win32/Win32Native.cs +++ b/src/System.Private.CoreLib/src/Microsoft/Win32/Win32Native.cs @@ -276,8 +276,6 @@ internal static bool GlobalMemoryStatusEx(ref MEMORYSTATUSEX buffer) internal static extern uint SysStringByteLen(IntPtr bstr); #endif - [DllImport(Interop.Libraries.Kernel32, SetLastError = true)] - internal static extern bool CloseHandle(IntPtr handle); [DllImport(Interop.Libraries.Kernel32, SetLastError = true)] internal static extern unsafe int WriteFile(SafeFileHandle handle, byte* bytes, int numBytesToWrite, out int numBytesWritten, IntPtr mustBeZero); From b7712eac1417b806149c1368a1c16f96e6b51f1f Mon Sep 17 00:00:00 2001 From: Anipik Date: Tue, 26 Jun 2018 18:11:25 -0700 Subject: [PATCH 3/9] _ remoev from variable names --- .../src/System/Threading/CancellationTokenSource.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/System.Private.CoreLib/src/System/Threading/CancellationTokenSource.cs b/src/System.Private.CoreLib/src/System/Threading/CancellationTokenSource.cs index d3c811348064..7f41d250b668 100644 --- a/src/System.Private.CoreLib/src/System/Threading/CancellationTokenSource.cs +++ b/src/System.Private.CoreLib/src/System/Threading/CancellationTokenSource.cs @@ -725,8 +725,6 @@ public static CancellationTokenSource CreateLinkedTokenSource(params Cancellatio } } - - /// /// Wait for a single callback to complete (or, more specifically, to not be running). /// It is ok to call this method if the callback has already finished. @@ -790,17 +788,17 @@ private sealed class LinkedNCancellationTokenSource : CancellationTokenSource { internal static readonly Action s_linkedTokenCancelDelegate = s => ((CancellationTokenSource)s).NotifyCancellation(throwOnFirstException: false); // skip ThrowIfDisposed() check in Cancel() - private CancellationTokenRegistration[] m_linkingRegistrations; + private CancellationTokenRegistration[] _linkingRegistrations; internal LinkedNCancellationTokenSource(params CancellationToken[] tokens) { - m_linkingRegistrations = new CancellationTokenRegistration[tokens.Length]; + _linkingRegistrations = new CancellationTokenRegistration[tokens.Length]; for (int i = 0; i < tokens.Length; i++) { if (tokens[i].CanBeCanceled) { - m_linkingRegistrations[i] = tokens[i].InternalRegisterWithoutEC(s_linkedTokenCancelDelegate, this); + _linkingRegistrations[i] = tokens[i].InternalRegisterWithoutEC(s_linkedTokenCancelDelegate, this); } // Empty slots in the array will be default(CancellationTokenRegistration), which are nops to Dispose. // Based on usage patterns, such occurrences should also be rare, such that it's not worth resizing @@ -815,10 +813,10 @@ protected override void Dispose(bool disposing) return; } - CancellationTokenRegistration[] linkingRegistrations = m_linkingRegistrations; + CancellationTokenRegistration[] linkingRegistrations = _linkingRegistrations; if (linkingRegistrations != null) { - m_linkingRegistrations = null; // release for GC once we're done enumerating + _linkingRegistrations = null; // release for GC once we're done enumerating for (int i = 0; i < linkingRegistrations.Length; i++) { linkingRegistrations[i].Dispose(); From b4cbe54c03a2cc685dcfd10650830864435c77cc Mon Sep 17 00:00:00 2001 From: Anipik Date: Tue, 26 Jun 2018 18:11:56 -0700 Subject: [PATCH 4/9] Default change to Default(Token) and minor changes --- .../src/System/Threading/SemaphoreSlim.cs | 41 ++++++------------- 1 file changed, 13 insertions(+), 28 deletions(-) diff --git a/src/System.Private.CoreLib/src/System/Threading/SemaphoreSlim.cs b/src/System.Private.CoreLib/src/System/Threading/SemaphoreSlim.cs index 9001fcd499d0..968e505e96d2 100644 --- a/src/System.Private.CoreLib/src/System/Threading/SemaphoreSlim.cs +++ b/src/System.Private.CoreLib/src/System/Threading/SemaphoreSlim.cs @@ -2,15 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -// -// -// -// A lightweight semahore class that contains the basic semaphore functions plus some useful functions like interrupt -// and wait handle exposing to allow waiting on multiple semaphores. -// -// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - using System; using System.Collections.Generic; @@ -19,8 +10,6 @@ using System.Runtime.InteropServices; using System.Threading.Tasks; -// The class will be part of the current System.Threading namespace - namespace System.Threading { /// @@ -55,7 +44,7 @@ public class SemaphoreSlim : IDisposable // The number of synchronously waiting threads, it is set to zero in the constructor and increments before blocking the // threading and decrements it back after that. It is used as flag for the release call to know if there are // waiting threads in the monitor or not. - private int m_waitCount; + private volatile int m_waitCount; /// /// This is used to help prevent waking more waiters than necessary. It's not perfect and sometimes more waiters than @@ -77,11 +66,11 @@ public class SemaphoreSlim : IDisposable private TaskNode m_asyncTail; // A pre-completed task with Result==true - private readonly static Task s_trueTask = - new Task(false, true, (TaskCreationOptions)InternalTaskOptions.DoNotDispose, default); + private static readonly Task s_trueTask = + new Task(false, true, (TaskCreationOptions)InternalTaskOptions.DoNotDispose, default(CancellationToken)); // A pre-completed task with Result==false private readonly static Task s_falseTask = - new Task(false, false, (TaskCreationOptions)InternalTaskOptions.DoNotDispose, default); + new Task(false, false, (TaskCreationOptions)InternalTaskOptions.DoNotDispose, default(CancellationToken)); // No maximum constant private const int NO_MAXIMUM = int.MaxValue; @@ -97,8 +86,6 @@ void IThreadPoolWorkItem.ExecuteWorkItem() bool setSuccessfully = TrySetResult(true); Debug.Assert(setSuccessfully, "Should have been able to complete task"); } - - void IThreadPoolWorkItem.MarkAborted(ThreadAbortException tae) { /* nop */ } } #endregion @@ -238,7 +225,7 @@ public void Wait(CancellationToken cancellationToken) /// otherwise, false. /// is a negative /// number other than -1 milliseconds, which represents an infinite time-out -or- timeout is greater - /// than . + /// than . public bool Wait(TimeSpan timeout) { // Validate the timeout @@ -267,7 +254,7 @@ public bool Wait(TimeSpan timeout) /// otherwise, false. /// is a negative /// number other than -1 milliseconds, which represents an infinite time-out -or- timeout is greater - /// than . + /// than . /// was canceled. public bool Wait(TimeSpan timeout, CancellationToken cancellationToken) { @@ -487,7 +474,6 @@ private bool WaitUntilCountOrTimeout(int millisecondsTimeout, uint startTime, Ca return false; } } - // ** the actual wait ** bool waitSuccessful = Monitor.Wait(m_lockObj, remainingWaitMilliseconds); @@ -517,7 +503,7 @@ private bool WaitUntilCountOrTimeout(int millisecondsTimeout, uint startTime, Ca /// A task that will complete when the semaphore has been entered. public Task WaitAsync() { - return WaitAsync(Timeout.Infinite, default); + return WaitAsync(Timeout.Infinite, default(CancellationToken)); } /// @@ -554,7 +540,7 @@ public Task WaitAsync(CancellationToken cancellationToken) /// public Task WaitAsync(int millisecondsTimeout) { - return WaitAsync(millisecondsTimeout, default); + return WaitAsync(millisecondsTimeout, default(CancellationToken)); } /// @@ -578,11 +564,11 @@ public Task WaitAsync(int millisecondsTimeout) /// /// /// is a negative number other than -1 milliseconds, which represents - /// an infinite time-out -or- timeout is greater than . + /// an infinite timeout is greater than . /// public Task WaitAsync(TimeSpan timeout) { - return WaitAsync(timeout, default); + return WaitAsync(timeout, default(CancellationToken)); } /// @@ -599,7 +585,7 @@ public Task WaitAsync(TimeSpan timeout) /// /// /// is a negative number other than -1 milliseconds, which represents - /// an infinite time-out -or- timeout is greater than . + /// an infinite time-out -or- timeout is greater than . /// public Task WaitAsync(TimeSpan timeout, CancellationToken cancellationToken) { @@ -743,7 +729,7 @@ private async Task WaitUntilCountOrTimeoutAsync(TaskNode asyncWaiter, int // completes due to the asyncWaiter completing, so we use our own token that we can explicitly // cancel, and we chain the caller's supplied token into it. using (var cts = cancellationToken.CanBeCanceled ? - CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, default) : + CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, default(CancellationToken)) : new CancellationTokenSource()) { var waitCompleted = Task.WhenAny(asyncWaiter, Task.Delay(millisecondsTimeout, cts.Token)); @@ -920,7 +906,7 @@ protected virtual void Dispose(bool disposing) { if (m_waitHandle != null) { - m_waitHandle.Close(); + m_waitHandle.Dispose(); m_waitHandle = null; } m_lockObj = null; @@ -956,7 +942,6 @@ private void CheckDispose() throw new ObjectDisposedException(null, SR.SemaphoreSlim_Disposed); } } - #endregion } } From a0f74468b7a9cc7f2ded45fdab2bb35fdaad36ba Mon Sep 17 00:00:00 2001 From: Anipik Date: Tue, 26 Jun 2018 19:02:38 -0700 Subject: [PATCH 5/9] Fixing coreclr unix build --- .../shared/System.Private.CoreLib.Shared.projitems | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems b/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems index 0ffc92a10230..47a73896fbcc 100644 --- a/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems +++ b/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems @@ -726,7 +726,6 @@ - @@ -812,6 +811,7 @@ + From 65731891ee3f2ff2b5c61f5cbb8e77c242782e8b Mon Sep 17 00:00:00 2001 From: Anipik Date: Tue, 26 Jun 2018 19:43:15 -0700 Subject: [PATCH 6/9] moving semaphoreSlim to shared --- .../System.Private.CoreLib.csproj | 1 - .../System.Private.CoreLib.Shared.projitems | 3 +- .../System/Threading/SemaphoreSlim.cs | 51 +++++++++---------- 3 files changed, 26 insertions(+), 29 deletions(-) rename src/System.Private.CoreLib/{src => shared}/System/Threading/SemaphoreSlim.cs (96%) diff --git a/src/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/System.Private.CoreLib/System.Private.CoreLib.csproj index 7f4b167317ca..986d273addc1 100644 --- a/src/System.Private.CoreLib/System.Private.CoreLib.csproj +++ b/src/System.Private.CoreLib/System.Private.CoreLib.csproj @@ -398,7 +398,6 @@ - diff --git a/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems b/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems index 47a73896fbcc..4a87e8d590e4 100644 --- a/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems +++ b/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems @@ -1,4 +1,4 @@ - + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) @@ -596,6 +596,7 @@ + diff --git a/src/System.Private.CoreLib/src/System/Threading/SemaphoreSlim.cs b/src/System.Private.CoreLib/shared/System/Threading/SemaphoreSlim.cs similarity index 96% rename from src/System.Private.CoreLib/src/System/Threading/SemaphoreSlim.cs rename to src/System.Private.CoreLib/shared/System/Threading/SemaphoreSlim.cs index 968e505e96d2..7dc5cfa95d0c 100644 --- a/src/System.Private.CoreLib/src/System/Threading/SemaphoreSlim.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/SemaphoreSlim.cs @@ -6,7 +6,6 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using System.Security; using System.Runtime.InteropServices; using System.Threading.Tasks; @@ -67,10 +66,10 @@ public class SemaphoreSlim : IDisposable // A pre-completed task with Result==true private static readonly Task s_trueTask = - new Task(false, true, (TaskCreationOptions)InternalTaskOptions.DoNotDispose, default(CancellationToken)); + new Task(false, true, (TaskCreationOptions)InternalTaskOptions.DoNotDispose, default); // A pre-completed task with Result==false private readonly static Task s_falseTask = - new Task(false, false, (TaskCreationOptions)InternalTaskOptions.DoNotDispose, default(CancellationToken)); + new Task(false, false, (TaskCreationOptions)InternalTaskOptions.DoNotDispose, default); // No maximum constant private const int NO_MAXIMUM = int.MaxValue; @@ -86,6 +85,8 @@ void IThreadPoolWorkItem.ExecuteWorkItem() bool setSuccessfully = TrySetResult(true); Debug.Assert(setSuccessfully, "Should have been able to complete task"); } + + void IThreadPoolWorkItem.MarkAborted(ThreadAbortException tae) { /* nop */ } } #endregion @@ -335,28 +336,24 @@ public bool Wait(int millisecondsTimeout, CancellationToken cancellationToken) try { // Perf: first spin wait for the count to be positive. - // This additional amount of spinwaiting in addition - // to Monitor.Enter()’s spinwaiting has shown measurable perf gains in test scenarios. - if (m_currentCount == 0) + // This additional amount of spinwaiting in addition + // to Monitor.Enter()’s spinwaiting has shown measurable perf gains in test scenarios. + // Monitor.Enter followed by Monitor.Wait is much more expensive than waiting on an event as it involves another + // spin, contention, etc. The usual number of spin iterations that would otherwise be used here is increased to + // lessen that extra expense of doing a proper wait. + var spinner = new SpinWait(); +#if CORECLR + int spinCount = SpinWait.SpinCountforSpinBeforeWait * 4; + while (m_currentCount == 0 && spinner.Count < spinCount) { - // Monitor.Enter followed by Monitor.Wait is much more expensive than waiting on an event as it involves another - // spin, contention, etc. The usual number of spin iterations that would otherwise be used here is increased to - // lessen that extra expense of doing a proper wait. - int spinCount = SpinWait.SpinCountforSpinBeforeWait * 4; - const int Sleep1Threshold = SpinWait.Sleep1ThresholdForSpinBeforeWait * 4; - - var spinner = new SpinWait(); - while (spinner.Count < spinCount) - { - spinner.SpinOnce(Sleep1Threshold); - - if (m_currentCount != 0) - { - break; - } - } + spinner.SpinOnce(SpinWait.Sleep1ThresholdForSpinBeforeWait * 4); } - +#else + while (m_currentCount == 0 && !spinner.NextSpinWillYield) + { + spinner.SpinOnce(); + } +#endif // entering the lock and incrementing waiters must not suffer a thread-abort, else we cannot // clean up m_waitCount correctly, which may lead to deadlock due to non-woken waiters. try { } @@ -503,7 +500,7 @@ private bool WaitUntilCountOrTimeout(int millisecondsTimeout, uint startTime, Ca /// A task that will complete when the semaphore has been entered. public Task WaitAsync() { - return WaitAsync(Timeout.Infinite, default(CancellationToken)); + return WaitAsync(Timeout.Infinite, default); } /// @@ -540,7 +537,7 @@ public Task WaitAsync(CancellationToken cancellationToken) /// public Task WaitAsync(int millisecondsTimeout) { - return WaitAsync(millisecondsTimeout, default(CancellationToken)); + return WaitAsync(millisecondsTimeout, default); } /// @@ -568,7 +565,7 @@ public Task WaitAsync(int millisecondsTimeout) /// public Task WaitAsync(TimeSpan timeout) { - return WaitAsync(timeout, default(CancellationToken)); + return WaitAsync(timeout, default); } /// @@ -729,7 +726,7 @@ private async Task WaitUntilCountOrTimeoutAsync(TaskNode asyncWaiter, int // completes due to the asyncWaiter completing, so we use our own token that we can explicitly // cancel, and we chain the caller's supplied token into it. using (var cts = cancellationToken.CanBeCanceled ? - CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, default(CancellationToken)) : + CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, default) : new CancellationTokenSource()) { var waitCompleted = Task.WhenAny(asyncWaiter, Task.Delay(millisecondsTimeout, cts.Token)); From f7e626d8caee418c966739f1f6ed38e1b0e8a72c Mon Sep 17 00:00:00 2001 From: Anipik Date: Tue, 26 Jun 2018 19:43:33 -0700 Subject: [PATCH 7/9] splitting safeWaitHandle to .windows and .unix --- .../SafeHandles/SafeWaitHandle.Windows.cs | 11 +++++++++++ .../Win32/SafeHandles/SafeWaitHandle.cs | 18 +----------------- .../System.Private.CoreLib.Shared.projitems | 3 ++- 3 files changed, 14 insertions(+), 18 deletions(-) create mode 100644 src/System.Private.CoreLib/shared/Microsoft/Win32/SafeHandles/SafeWaitHandle.Windows.cs diff --git a/src/System.Private.CoreLib/shared/Microsoft/Win32/SafeHandles/SafeWaitHandle.Windows.cs b/src/System.Private.CoreLib/shared/Microsoft/Win32/SafeHandles/SafeWaitHandle.Windows.cs new file mode 100644 index 000000000000..66f17f0af709 --- /dev/null +++ b/src/System.Private.CoreLib/shared/Microsoft/Win32/SafeHandles/SafeWaitHandle.Windows.cs @@ -0,0 +1,11 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Win32.SafeHandles +{ + public sealed partial class SafeWaitHandle : SafeHandleZeroOrMinusOneIsInvalid + { + protected override bool ReleaseHandle() => Interop.Kernel32.CloseHandle(handle); + } +} diff --git a/src/System.Private.CoreLib/shared/Microsoft/Win32/SafeHandles/SafeWaitHandle.cs b/src/System.Private.CoreLib/shared/Microsoft/Win32/SafeHandles/SafeWaitHandle.cs index 9d608c953011..edb0cdfcafe7 100644 --- a/src/System.Private.CoreLib/shared/Microsoft/Win32/SafeHandles/SafeWaitHandle.cs +++ b/src/System.Private.CoreLib/shared/Microsoft/Win32/SafeHandles/SafeWaitHandle.cs @@ -3,16 +3,10 @@ // See the LICENSE file in the project root for more information. using System; -using System.Security; -using System.Runtime.InteropServices; -using System.Runtime.CompilerServices; -using System.Runtime.Versioning; -using Microsoft.Win32; -using System.Threading; namespace Microsoft.Win32.SafeHandles { - public sealed class SafeWaitHandle : SafeHandleZeroOrMinusOneIsInvalid + public sealed partial class SafeWaitHandle : SafeHandleZeroOrMinusOneIsInvalid { // Called by P/Invoke marshaler private SafeWaitHandle() : base(true) @@ -23,15 +17,5 @@ public SafeWaitHandle(IntPtr existingHandle, bool ownsHandle) : base(ownsHandle) { SetHandle(existingHandle); } - - protected override bool ReleaseHandle() - { -#if !CORECLR && !PLATFORM_WINDOWS - WaitSubsystem.DeleteHandle(handle); - return true; -#else - return Interop.Kernel32.CloseHandle(handle); -#endif - } } } diff --git a/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems b/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems index 4a87e8d590e4..59a3074ab8b7 100644 --- a/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems +++ b/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems @@ -1,4 +1,4 @@ - + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) @@ -812,6 +812,7 @@ + From 4def88608a53522fae57d0988d830251fec76eb3 Mon Sep 17 00:00:00 2001 From: Anipik Date: Tue, 26 Jun 2018 20:42:59 -0700 Subject: [PATCH 8/9] Change reverted --- .../shared/System/Threading/SemaphoreSlim.cs | 38 ++++++++++--------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/src/System.Private.CoreLib/shared/System/Threading/SemaphoreSlim.cs b/src/System.Private.CoreLib/shared/System/Threading/SemaphoreSlim.cs index 7dc5cfa95d0c..1dffb137aac5 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/SemaphoreSlim.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/SemaphoreSlim.cs @@ -43,7 +43,7 @@ public class SemaphoreSlim : IDisposable // The number of synchronously waiting threads, it is set to zero in the constructor and increments before blocking the // threading and decrements it back after that. It is used as flag for the release call to know if there are // waiting threads in the monitor or not. - private volatile int m_waitCount; + private int m_waitCount; /// /// This is used to help prevent waking more waiters than necessary. It's not perfect and sometimes more waiters than @@ -85,8 +85,9 @@ void IThreadPoolWorkItem.ExecuteWorkItem() bool setSuccessfully = TrySetResult(true); Debug.Assert(setSuccessfully, "Should have been able to complete task"); } - +#if CORECLR void IThreadPoolWorkItem.MarkAborted(ThreadAbortException tae) { /* nop */ } +#endif } #endregion @@ -338,22 +339,25 @@ public bool Wait(int millisecondsTimeout, CancellationToken cancellationToken) // Perf: first spin wait for the count to be positive. // This additional amount of spinwaiting in addition // to Monitor.Enter()’s spinwaiting has shown measurable perf gains in test scenarios. - // Monitor.Enter followed by Monitor.Wait is much more expensive than waiting on an event as it involves another - // spin, contention, etc. The usual number of spin iterations that would otherwise be used here is increased to - // lessen that extra expense of doing a proper wait. - var spinner = new SpinWait(); -#if CORECLR - int spinCount = SpinWait.SpinCountforSpinBeforeWait * 4; - while (m_currentCount == 0 && spinner.Count < spinCount) + if (m_currentCount == 0) { - spinner.SpinOnce(SpinWait.Sleep1ThresholdForSpinBeforeWait * 4); + // Monitor.Enter followed by Monitor.Wait is much more expensive than waiting on an event as it involves another + // spin, contention, etc. The usual number of spin iterations that would otherwise be used here is increased to + // lessen that extra expense of doing a proper wait. + int spinCount = SpinWait.SpinCountforSpinBeforeWait * 4; + const int Sleep1Threshold = SpinWait.Sleep1ThresholdForSpinBeforeWait * 4; + + var spinner = new SpinWait(); + while (spinner.Count < spinCount) + { + spinner.SpinOnce(Sleep1Threshold); + + if (m_currentCount != 0) + { + break; + } + } } -#else - while (m_currentCount == 0 && !spinner.NextSpinWillYield) - { - spinner.SpinOnce(); - } -#endif // entering the lock and incrementing waiters must not suffer a thread-abort, else we cannot // clean up m_waitCount correctly, which may lead to deadlock due to non-woken waiters. try { } @@ -912,8 +916,6 @@ protected virtual void Dispose(bool disposing) } } - - /// /// Private helper method to wake up waiters when a cancellationToken gets canceled. /// From 29da5692e8294b195b750eab9bc4c30d159a6ec6 Mon Sep 17 00:00:00 2001 From: Anipik Date: Tue, 26 Jun 2018 23:12:30 -0700 Subject: [PATCH 9/9] Comment corrected --- .../shared/System/Threading/SemaphoreSlim.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System.Private.CoreLib/shared/System/Threading/SemaphoreSlim.cs b/src/System.Private.CoreLib/shared/System/Threading/SemaphoreSlim.cs index 1dffb137aac5..6dca573ef991 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/SemaphoreSlim.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/SemaphoreSlim.cs @@ -565,7 +565,7 @@ public Task WaitAsync(int millisecondsTimeout) /// /// /// is a negative number other than -1 milliseconds, which represents - /// an infinite timeout is greater than . + /// an infinite time-out -or- timeout is greater than . /// public Task WaitAsync(TimeSpan timeout) {