From 7f3136c50f73f25cfd498e289762517b01c3e45e Mon Sep 17 00:00:00 2001 From: Anirudh Agnihotry Date: Thu, 21 Jun 2018 18:39:23 -0700 Subject: [PATCH] Moved Semaphore.cs and Semaphore.Windows.cs to shared (dotnet/coreclr#18597) * TryOpenexistingworker and createsemaphore moved to semaphore.windows.cs * Common code moved to verifyCounts and CreateMutexCore and then moved to semaphore.windows.cs * CreateSemaphore merged with CreateSemaphore core * Moving interop functions from win32Native to inteop.kernel32 * Moving the files to shared * Minor Formating Commit migrated from https://github.com/dotnet/coreclr/commit/84b6f1da3338df672347732a0ea5f7cf4a3e43cf --- .../System.Private.CoreLib.csproj | 1 - .../src/Microsoft/Win32/Win32Native.cs | 11 -- .../src/System/Threading/Semaphore.cs | 186 --------------------- .../Interop/Windows/Kernel32/Interop.Constants.cs | 1 + .../Interop/Windows/Kernel32/Interop.Semaphore.cs | 23 +++ .../src/System.Private.CoreLib.Shared.projitems | 3 + .../src/System/Threading/Semaphore.Windows.cs | 91 ++++++++++ .../src/System/Threading/Semaphore.cs | 75 +++++++++ 8 files changed, 193 insertions(+), 198 deletions(-) delete mode 100644 src/coreclr/src/System.Private.CoreLib/src/System/Threading/Semaphore.cs create mode 100644 src/libraries/System.Private.CoreLib/src/Interop/Windows/Kernel32/Interop.Semaphore.cs create mode 100644 src/libraries/System.Private.CoreLib/src/System/Threading/Semaphore.Windows.cs create mode 100644 src/libraries/System.Private.CoreLib/src/System/Threading/Semaphore.cs diff --git a/src/coreclr/src/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/coreclr/src/System.Private.CoreLib/System.Private.CoreLib.csproj index a97fa08..ccb3050 100644 --- a/src/coreclr/src/System.Private.CoreLib/System.Private.CoreLib.csproj +++ b/src/coreclr/src/System.Private.CoreLib/System.Private.CoreLib.csproj @@ -392,7 +392,6 @@ - diff --git a/src/coreclr/src/System.Private.CoreLib/src/Microsoft/Win32/Win32Native.cs b/src/coreclr/src/System.Private.CoreLib/src/Microsoft/Win32/Win32Native.cs index 61dd2b3..dcd4345 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/Microsoft/Win32/Win32Native.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/Microsoft/Win32/Win32Native.cs @@ -165,7 +165,6 @@ namespace Microsoft.Win32 // Note that you may need to specify the SYNCHRONIZE bit as well // to be able to open a synchronization primitive. - internal const int SEMAPHORE_MODIFY_STATE = 0x00000002; internal const int EVENT_MODIFY_STATE = 0x00000002; internal const int MUTEX_MODIFY_STATE = 0x00000001; @@ -312,16 +311,6 @@ namespace Microsoft.Win32 [DllImport(Interop.Libraries.Kernel32, SetLastError = true)] internal static extern unsafe int WriteFile(SafeFileHandle handle, byte* bytes, int numBytesToWrite, out int numBytesWritten, IntPtr mustBeZero); - [DllImport(Interop.Libraries.Kernel32, SetLastError = true, CharSet = CharSet.Auto, BestFitMapping = false)] - internal static extern SafeWaitHandle CreateSemaphoreEx(SECURITY_ATTRIBUTES lpSecurityAttributes, int initialCount, int maximumCount, string name, uint flags, uint desiredAccess); - - [DllImport(Interop.Libraries.Kernel32, SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool ReleaseSemaphore(SafeWaitHandle handle, int releaseCount, out int previousCount); - - [DllImport(Interop.Libraries.Kernel32, SetLastError = true, CharSet = CharSet.Auto, BestFitMapping = false)] - internal static extern SafeWaitHandle OpenSemaphore(uint desiredAccess, bool inheritHandle, string name); - internal static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1); // WinBase.h // Note, these are #defines used to extract handles, and are NOT handles. diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Threading/Semaphore.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Threading/Semaphore.cs deleted file mode 100644 index 2853485..0000000 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Threading/Semaphore.cs +++ /dev/null @@ -1,186 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using Microsoft.Win32; -using Microsoft.Win32.SafeHandles; -using System.Diagnostics; -using System.IO; -using System.Runtime.InteropServices; -using System.Security; - -namespace System.Threading -{ - public sealed partial class Semaphore : WaitHandle - { - private const uint AccessRights = - (uint)Win32Native.MAXIMUM_ALLOWED | Win32Native.SYNCHRONIZE | Win32Native.SEMAPHORE_MODIFY_STATE; - - public Semaphore(int initialCount, int maximumCount) : this(initialCount, maximumCount, null) { } - - public Semaphore(int initialCount, int maximumCount, string name) - { - if (initialCount < 0) - { - throw new ArgumentOutOfRangeException(nameof(initialCount), SR.ArgumentOutOfRange_NeedNonNegNum); - } - - if (maximumCount < 1) - { - throw new ArgumentOutOfRangeException(nameof(maximumCount), SR.ArgumentOutOfRange_NeedPosNum); - } - - if (initialCount > maximumCount) - { - throw new ArgumentException(SR.Argument_SemaphoreInitialMaximum); - } - - SafeWaitHandle myHandle = CreateSemaphore(initialCount, maximumCount, name); - - if (myHandle.IsInvalid) - { - int errorCode = Marshal.GetLastWin32Error(); - - if (null != name && 0 != name.Length && Interop.Errors.ERROR_INVALID_HANDLE == errorCode) - throw new WaitHandleCannotBeOpenedException( - SR.Format(SR.Threading_WaitHandleCannotBeOpenedException_InvalidHandle, name)); - - throw Win32Marshal.GetExceptionForLastWin32Error(); - } - this.SafeWaitHandle = myHandle; - } - - public Semaphore(int initialCount, int maximumCount, string name, out bool createdNew) - { - if (initialCount < 0) - { - throw new ArgumentOutOfRangeException(nameof(initialCount), SR.ArgumentOutOfRange_NeedNonNegNum); - } - - if (maximumCount < 1) - { - throw new ArgumentOutOfRangeException(nameof(maximumCount), SR.ArgumentOutOfRange_NeedNonNegNum); - } - - if (initialCount > maximumCount) - { - throw new ArgumentException(SR.Argument_SemaphoreInitialMaximum); - } - - SafeWaitHandle myHandle = CreateSemaphore(initialCount, maximumCount, name); - - int errorCode = Marshal.GetLastWin32Error(); - if (myHandle.IsInvalid) - { - if (null != name && 0 != name.Length && Interop.Errors.ERROR_INVALID_HANDLE == errorCode) - throw new WaitHandleCannotBeOpenedException( - SR.Format(SR.Threading_WaitHandleCannotBeOpenedException_InvalidHandle, name)); - throw Win32Marshal.GetExceptionForLastWin32Error(); - } - createdNew = errorCode != Interop.Errors.ERROR_ALREADY_EXISTS; - this.SafeWaitHandle = myHandle; - } - - private Semaphore(SafeWaitHandle handle) - { - this.SafeWaitHandle = handle; - } - - private static SafeWaitHandle CreateSemaphore(int initialCount, int maximumCount, string name) - { -#if !PLATFORM_WINDOWS - if (name != null) - { - throw new PlatformNotSupportedException(SR.PlatformNotSupported_NamedSynchronizationPrimitives); - } -#endif - - Debug.Assert(initialCount >= 0); - Debug.Assert(maximumCount >= 1); - Debug.Assert(initialCount <= maximumCount); - - return Win32Native.CreateSemaphoreEx(null, initialCount, maximumCount, name, 0, AccessRights); - } - - public static Semaphore OpenExisting(string name) - { - Semaphore result; - switch (OpenExistingWorker(name, out result)) - { - case OpenExistingResult.NameNotFound: - throw new WaitHandleCannotBeOpenedException(); - case OpenExistingResult.NameInvalid: - throw new WaitHandleCannotBeOpenedException(SR.Format(SR.Threading_WaitHandleCannotBeOpenedException_InvalidHandle, name)); - case OpenExistingResult.PathNotFound: - throw new IOException(Interop.Kernel32.GetMessage(Interop.Errors.ERROR_PATH_NOT_FOUND)); - default: - return result; - } - } - - public static bool TryOpenExisting(string name, out Semaphore result) - { - return OpenExistingWorker(name, out result) == OpenExistingResult.Success; - } - - private static OpenExistingResult OpenExistingWorker(string name, out Semaphore result) - { -#if PLATFORM_WINDOWS - if (name == null) - throw new ArgumentNullException(nameof(name)); - if (name.Length == 0) - throw new ArgumentException(SR.Argument_EmptyName, nameof(name)); - - //Pass false to OpenSemaphore to prevent inheritedHandles - SafeWaitHandle myHandle = Win32Native.OpenSemaphore(AccessRights, false, name); - - if (myHandle.IsInvalid) - { - result = null; - - int errorCode = Marshal.GetLastWin32Error(); - - if (Interop.Errors.ERROR_FILE_NOT_FOUND == errorCode || Interop.Errors.ERROR_INVALID_NAME == errorCode) - return OpenExistingResult.NameNotFound; - if (Interop.Errors.ERROR_PATH_NOT_FOUND == errorCode) - return OpenExistingResult.PathNotFound; - if (null != name && 0 != name.Length && Interop.Errors.ERROR_INVALID_HANDLE == errorCode) - return OpenExistingResult.NameInvalid; - //this is for passed through NativeMethods Errors - throw Win32Marshal.GetExceptionForLastWin32Error(); - } - - result = new Semaphore(myHandle); - return OpenExistingResult.Success; -#else - throw new PlatformNotSupportedException(SR.PlatformNotSupported_NamedSynchronizationPrimitives); -#endif - } - - public int Release() - { - return Release(1); - } - - // increase the count on a semaphore, returns previous count - public int Release(int releaseCount) - { - if (releaseCount < 1) - { - throw new ArgumentOutOfRangeException(nameof(releaseCount), SR.ArgumentOutOfRange_NeedNonNegNum); - } - - //If ReleaseSempahore returns false when the specified value would cause - // the semaphore's count to exceed the maximum count set when Semaphore was created - //Non-Zero return - - int previousCount; - if (!Win32Native.ReleaseSemaphore(SafeWaitHandle, releaseCount, out previousCount)) - { - throw new SemaphoreFullException(); - } - - return previousCount; - } - } -} diff --git a/src/libraries/System.Private.CoreLib/src/Interop/Windows/Kernel32/Interop.Constants.cs b/src/libraries/System.Private.CoreLib/src/Interop/Windows/Kernel32/Interop.Constants.cs index 8437f4b..59dace9 100644 --- a/src/libraries/System.Private.CoreLib/src/Interop/Windows/Kernel32/Interop.Constants.cs +++ b/src/libraries/System.Private.CoreLib/src/Interop/Windows/Kernel32/Interop.Constants.cs @@ -9,5 +9,6 @@ internal static partial class Interop internal const int MAXIMUM_ALLOWED = 0x02000000; internal const int SYNCHRONIZE = 0x00100000; internal const int MUTEX_MODIFY_STATE = 0x00000001; + internal const int SEMAPHORE_MODIFY_STATE = 0x00000002; } } diff --git a/src/libraries/System.Private.CoreLib/src/Interop/Windows/Kernel32/Interop.Semaphore.cs b/src/libraries/System.Private.CoreLib/src/Interop/Windows/Kernel32/Interop.Semaphore.cs new file mode 100644 index 0000000..6d1467b --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/Interop/Windows/Kernel32/Interop.Semaphore.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.Win32.SafeHandles; +using System; +using System.Runtime.InteropServices; + +internal static partial class Interop +{ + internal static partial class Kernel32 + { + [DllImport(Interop.Libraries.Kernel32, SetLastError = true, CharSet = CharSet.Unicode)] + internal static extern SafeWaitHandle OpenSemaphore(uint desiredAccess, bool inheritHandle, string name); + + [DllImport(Libraries.Kernel32, SetLastError = true, CharSet = CharSet.Unicode)] + internal static extern SafeWaitHandle CreateSemaphoreEx(IntPtr lpSecurityAttributes, int initialCount, int maximumCount, string name, uint flags, uint desiredAccess); + + [DllImport(Interop.Libraries.Kernel32, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool ReleaseSemaphore(SafeWaitHandle handle, int releaseCount, out int previousCount); + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index 7ee0321..eeef09b 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -591,6 +591,7 @@ + @@ -812,8 +813,10 @@ + + diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Semaphore.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Semaphore.Windows.cs new file mode 100644 index 0000000..f101564 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Semaphore.Windows.cs @@ -0,0 +1,91 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.Win32.SafeHandles; +using System.Diagnostics; +using System.IO; +using System.Runtime.InteropServices; + +namespace System.Threading +{ + public sealed partial class Semaphore + { + private const uint AccessRights = (uint)Interop.Kernel32.MAXIMUM_ALLOWED | Interop.Kernel32.SYNCHRONIZE | Interop.Kernel32.SEMAPHORE_MODIFY_STATE; + + private Semaphore(SafeWaitHandle handle) + { + SafeWaitHandle = handle; + } + + private void CreateSemaphoreCore(int initialCount, int maximumCount, string name, out bool createdNew) + { + Debug.Assert(initialCount >= 0); + Debug.Assert(maximumCount >= 1); + Debug.Assert(initialCount <= maximumCount); + +#if PLATFORM_UNIX + if (name != null) + throw new PlatformNotSupportedException(SR.PlatformNotSupported_NamedSynchronizationPrimitives); +#endif + SafeWaitHandle myHandle = Interop.Kernel32.CreateSemaphoreEx(IntPtr.Zero, initialCount, maximumCount, name, 0, AccessRights); + + int errorCode = Marshal.GetLastWin32Error(); + if (myHandle.IsInvalid) + { + if (name != null && name.Length != 0 && errorCode == Interop.Errors.ERROR_INVALID_HANDLE) + throw new WaitHandleCannotBeOpenedException( + SR.Format(SR.Threading_WaitHandleCannotBeOpenedException_InvalidHandle, name)); + + throw Win32Marshal.GetExceptionForLastWin32Error(); + } + createdNew = errorCode != Interop.Errors.ERROR_ALREADY_EXISTS; + this.SafeWaitHandle = myHandle; + } + + private static OpenExistingResult OpenExistingWorker(string name, out Semaphore result) + { +#if PLATFORM_WINDOWS + if (name == null) + throw new ArgumentNullException(nameof(name)); + if (name.Length == 0) + throw new ArgumentException(SR.Argument_EmptyName, nameof(name)); + + //Pass false to OpenSemaphore to prevent inheritedHandles + SafeWaitHandle myHandle = Interop.Kernel32.OpenSemaphore(AccessRights, false, name); + + if (myHandle.IsInvalid) + { + result = null; + int errorCode = Marshal.GetLastWin32Error(); + + if (errorCode == Interop.Errors.ERROR_FILE_NOT_FOUND || errorCode == Interop.Errors.ERROR_INVALID_NAME) + return OpenExistingResult.NameNotFound; + if (errorCode == Interop.Errors.ERROR_PATH_NOT_FOUND) + return OpenExistingResult.PathNotFound; + if (name != null && name.Length != 0 && errorCode == Interop.Errors.ERROR_INVALID_HANDLE) + return OpenExistingResult.NameInvalid; + //this is for passed through NativeMethods Errors + throw Win32Marshal.GetExceptionForLastWin32Error(); + } + + result = new Semaphore(myHandle); + return OpenExistingResult.Success; +#else + throw new PlatformNotSupportedException(SR.PlatformNotSupported_NamedSynchronizationPrimitives); +#endif + } + + private int ReleaseCore(int releaseCount) + { + // If ReleaseSempahore returns false when the specified value would cause + // the semaphore's count to exceed the maximum count set when Semaphore was created + // Non-Zero return + int previousCount; + if (!Interop.Kernel32.ReleaseSemaphore(SafeWaitHandle, releaseCount, out previousCount)) + throw new SemaphoreFullException(); + + return previousCount; + } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Semaphore.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Semaphore.cs new file mode 100644 index 0000000..8e4ad76 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Semaphore.cs @@ -0,0 +1,75 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.Win32; +using Microsoft.Win32.SafeHandles; +using System.IO; +using System.Runtime.InteropServices; + +namespace System.Threading +{ + public sealed partial class Semaphore : WaitHandle + { + // creates a nameless semaphore object + // Win32 only takes maximum count of Int32.MaxValue + public Semaphore(int initialCount, int maximumCount) : this(initialCount, maximumCount, null) { } + + public Semaphore(int initialCount, int maximumCount, string name) + { + VerifyCounts(initialCount, maximumCount); + + bool createdNew; + CreateSemaphoreCore(initialCount, maximumCount, name, out createdNew); + } + + public Semaphore(int initialCount, int maximumCount, string name, out bool createdNew) + { + VerifyCounts(initialCount, maximumCount); + + CreateSemaphoreCore(initialCount, maximumCount, name, out createdNew); + } + + private static void VerifyCounts(int initialCount, int maximumCount) + { + if (initialCount < 0) + throw new ArgumentOutOfRangeException(nameof(initialCount), SR.ArgumentOutOfRange_NeedNonNegNum); + + if (maximumCount < 1) + throw new ArgumentOutOfRangeException(nameof(maximumCount), SR.ArgumentOutOfRange_NeedPosNum); + + if (initialCount > maximumCount) + throw new ArgumentException(SR.Argument_SemaphoreInitialMaximum); + } + + public static Semaphore OpenExisting(string name) + { + Semaphore result; + switch (OpenExistingWorker(name, out result)) + { + case OpenExistingResult.NameNotFound: + throw new WaitHandleCannotBeOpenedException(); + case OpenExistingResult.NameInvalid: + throw new WaitHandleCannotBeOpenedException(SR.Format(SR.Threading_WaitHandleCannotBeOpenedException_InvalidHandle, name)); + case OpenExistingResult.PathNotFound: + throw new IOException(SR.Format(SR.IO_PathNotFound_Path, name)); + default: + return result; + } + } + + public static bool TryOpenExisting(string name, out Semaphore result) => + OpenExistingWorker(name, out result) == OpenExistingResult.Success; + + public int Release() => ReleaseCore(1); + + // increase the count on a semaphore, returns previous count + public int Release(int releaseCount) + { + if (releaseCount < 1) + throw new ArgumentOutOfRangeException(nameof(releaseCount), SR.ArgumentOutOfRange_NeedNonNegNum); + + return ReleaseCore(releaseCount); + } + } +} -- 2.7.4