From 65fc6e978fc21a05878b59ffc016613d9e34bcf6 Mon Sep 17 00:00:00 2001 From: Anirudh Agnihotry Date: Fri, 8 Jun 2018 14:51:10 -0700 Subject: [PATCH] Moved Mutex.cs From src to shared (#18320) * Moved Mutex.cs to shared * Reduced #ifdef in mutex.cs * Moved windows specific Implementation and renamed mincore to kernal32 * safeWaitHandle changed to _waitHandle * moved using statement out of buffer namespace --- .../System.Private.CoreLib.csproj | 1 - .../Interop/Windows/Kernel32/Interop.Constants.cs | 13 +++ .../Interop/Windows/Kernel32/Interop.Mutex.cs | 24 +++++ .../shared/System.Private.CoreLib.Shared.projitems | 4 + .../System/Threading/Mutex.Windows.cs} | 106 +++++---------------- .../shared/System/Threading/Mutex.cs | 64 +++++++++++++ .../src/Microsoft/Win32/Win32Native.cs | 12 --- src/System.Private.CoreLib/src/System/Buffer.cs | 32 +++---- .../src/System/Threading/EventWaitHandle.cs | 4 +- .../src/System/Threading/WaitHandle.cs | 40 ++++---- src/vm/mscorlib.h | 2 +- 11 files changed, 165 insertions(+), 137 deletions(-) create mode 100644 src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.Constants.cs create mode 100644 src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.Mutex.cs rename src/System.Private.CoreLib/{src/System/Threading/Mutex.cs => shared/System/Threading/Mutex.Windows.cs} (62%) create mode 100644 src/System.Private.CoreLib/shared/System/Threading/Mutex.cs diff --git a/src/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/System.Private.CoreLib/System.Private.CoreLib.csproj index 15b17cb..f56a100 100644 --- a/src/System.Private.CoreLib/System.Private.CoreLib.csproj +++ b/src/System.Private.CoreLib/System.Private.CoreLib.csproj @@ -460,7 +460,6 @@ - diff --git a/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.Constants.cs b/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.Constants.cs new file mode 100644 index 0000000..8437f4b --- /dev/null +++ b/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.Constants.cs @@ -0,0 +1,13 @@ +// 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. + +internal static partial class Interop +{ + internal static partial class Kernel32 + { + internal const int MAXIMUM_ALLOWED = 0x02000000; + internal const int SYNCHRONIZE = 0x00100000; + internal const int MUTEX_MODIFY_STATE = 0x00000001; + } +} diff --git a/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.Mutex.cs b/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.Mutex.cs new file mode 100644 index 0000000..f858514 --- /dev/null +++ b/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.Mutex.cs @@ -0,0 +1,24 @@ +// 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 + { + internal const uint CREATE_MUTEX_INITIAL_OWNER = 0x1; + + [DllImport(Interop.Libraries.Kernel32, SetLastError = true, CharSet = CharSet.Unicode)] + internal static extern SafeWaitHandle OpenMutex(uint desiredAccess, bool inheritHandle, string name); + + [DllImport(Interop.Libraries.Kernel32, SetLastError = true, CharSet = CharSet.Unicode)] + internal static extern SafeWaitHandle CreateMutexEx(IntPtr lpMutexAttributes, string name, uint flags, uint desiredAccess); + + [DllImport(Interop.Libraries.Kernel32, SetLastError = true)] + internal static extern bool ReleaseMutex(SafeWaitHandle handle); + } +} 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 98f9d1e..d1c7b26 100644 --- a/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems +++ b/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems @@ -568,6 +568,7 @@ + @@ -787,9 +788,12 @@ + + + diff --git a/src/System.Private.CoreLib/src/System/Threading/Mutex.cs b/src/System.Private.CoreLib/shared/System/Threading/Mutex.Windows.cs similarity index 62% rename from src/System.Private.CoreLib/src/System/Threading/Mutex.cs rename to src/System.Private.CoreLib/shared/System/Threading/Mutex.Windows.cs index 86981b5..e3fa7b7 100644 --- a/src/System.Private.CoreLib/src/System/Threading/Mutex.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Mutex.Windows.cs @@ -2,7 +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. - using System.IO; using Microsoft.Win32; using Microsoft.Win32.SafeHandles; @@ -14,98 +13,30 @@ namespace System.Threading /// /// Synchronization primitive that can also be used for interprocess synchronization /// - public sealed class Mutex : WaitHandle + public sealed partial class Mutex : WaitHandle { private const uint AccessRights = - (uint)Win32Native.MAXIMUM_ALLOWED | Win32Native.SYNCHRONIZE | Win32Native.MUTEX_MODIFY_STATE; + (uint)Interop.Kernel32.MAXIMUM_ALLOWED | Interop.Kernel32.SYNCHRONIZE | Interop.Kernel32.MUTEX_MODIFY_STATE; #if PLATFORM_UNIX // Maximum file name length on tmpfs file system. private const int WaitHandleNameMax = 255; #endif - public Mutex(bool initiallyOwned, string name, out bool createdNew) - { -#if !PLATFORM_UNIX - VerifyNameForCreate(name); -#endif - CreateMutexCore(initiallyOwned, name, out createdNew); - } - - public Mutex(bool initiallyOwned, string name) - { -#if !PLATFORM_UNIX - VerifyNameForCreate(name); -#endif - CreateMutexCore(initiallyOwned, name, out _); - } - - public Mutex(bool initiallyOwned) - { - CreateMutexCore(initiallyOwned, null, out _); - } - - public Mutex() - { - CreateMutexCore(false, null, out _); - } - - private Mutex(SafeWaitHandle handle) - { - SafeWaitHandle = handle; - } - - public static Mutex OpenExisting(string name) - { - switch (OpenExistingWorker(name, out Mutex result)) - { - case OpenExistingResult.NameNotFound: - throw new WaitHandleCannotBeOpenedException(); - - case OpenExistingResult.NameInvalid: - throw new WaitHandleCannotBeOpenedException(SR.Format(SR.Threading_WaitHandleCannotBeOpenedException_InvalidHandle, name)); - - case OpenExistingResult.PathNotFound: - throw Win32Marshal.GetExceptionForWin32Error(Interop.Errors.ERROR_PATH_NOT_FOUND, name); - - default: - return result; - } - } - - public static bool TryOpenExisting(string name, out Mutex result) => - OpenExistingWorker(name, out result) == OpenExistingResult.Success; - - // Note: To call ReleaseMutex, you must have an ACL granting you - // MUTEX_MODIFY_STATE rights (0x0001). The other interesting value - // in a Mutex's ACL is MUTEX_ALL_ACCESS (0x1F0001). - public void ReleaseMutex() - { - if (!Win32Native.ReleaseMutex(safeWaitHandle)) - { - throw new ApplicationException(SR.Arg_SynchronizationLockException); - } - } - -#if !PLATFORM_UNIX private static void VerifyNameForCreate(string name) { +#if PLATFORM_WINDOWS if (name != null && (Interop.Kernel32.MAX_PATH < name.Length)) { throw new ArgumentException(SR.Format(SR.Argument_WaitHandleNameTooLong, name, Interop.Kernel32.MAX_PATH), nameof(name)); } - } #endif + } private void CreateMutexCore(bool initiallyOwned, string name, out bool createdNew) { -#if !PLATFORM_UNIX - Debug.Assert(name == null || name.Length <= Interop.Kernel32.MAX_PATH); -#endif - - uint mutexFlags = initiallyOwned ? Win32Native.CREATE_MUTEX_INITIAL_OWNER : 0; - - SafeWaitHandle mutexHandle = Win32Native.CreateMutexEx(null, name, mutexFlags, AccessRights); + uint mutexFlags = initiallyOwned ? Interop.Kernel32.CREATE_MUTEX_INITIAL_OWNER : 0; + SafeWaitHandle mutexHandle = Interop.Kernel32.CreateMutexEx(IntPtr.Zero, name, mutexFlags, AccessRights); int errorCode = Marshal.GetLastWin32Error(); if (mutexHandle.IsInvalid) @@ -118,6 +49,7 @@ namespace System.Threading #endif if (errorCode == Interop.Errors.ERROR_INVALID_HANDLE) throw new WaitHandleCannotBeOpenedException(SR.Format(SR.Threading_WaitHandleCannotBeOpenedException_InvalidHandle, name)); + throw Win32Marshal.GetExceptionForWin32Error(errorCode, name); } @@ -137,23 +69,19 @@ namespace System.Threading throw new ArgumentException(SR.Argument_EmptyName, nameof(name)); } -#if !PLATFORM_UNIX VerifyNameForCreate(name); -#endif - result = null; // To allow users to view & edit the ACL's, call OpenMutex // with parameters to allow us to view & edit the ACL. This will - // fail if we don't have permission to view or edit the ACL's. + // fail if we don't have permission to view or edit the ACL's. // If that happens, ask for less permissions. - SafeWaitHandle myHandle = Win32Native.OpenMutex(AccessRights, false, name); + SafeWaitHandle myHandle = Interop.Kernel32.OpenMutex(AccessRights, false, name); if (myHandle.IsInvalid) { int errorCode = Marshal.GetLastWin32Error(); - #if PLATFORM_UNIX - if (name != null && errorCode == Interop.Errors.ERROR_FILENAME_EXCED_RANGE) + if (errorCode == Interop.Errors.ERROR_FILENAME_EXCED_RANGE) { // On Unix, length validation is done by CoreCLR's PAL after converting to utf-8 throw new ArgumentException(SR.Format(SR.Argument_WaitHandleNameTooLong, name, WaitHandleNameMax), nameof(name)); @@ -163,7 +91,7 @@ namespace System.Threading return OpenExistingResult.NameNotFound; if (Interop.Errors.ERROR_PATH_NOT_FOUND == errorCode) return OpenExistingResult.PathNotFound; - if (null != name && Interop.Errors.ERROR_INVALID_HANDLE == errorCode) + if (Interop.Errors.ERROR_INVALID_HANDLE == errorCode) return OpenExistingResult.NameInvalid; // this is for passed through Win32Native Errors @@ -171,8 +99,18 @@ namespace System.Threading } result = new Mutex(myHandle); - return OpenExistingResult.Success; } + + // Note: To call ReleaseMutex, you must have an ACL granting you + // MUTEX_MODIFY_STATE rights (0x0001). The other interesting value + // in a Mutex's ACL is MUTEX_ALL_ACCESS (0x1F0001). + public void ReleaseMutex() + { + if (!Interop.Kernel32.ReleaseMutex(_waitHandle)) + { + throw new ApplicationException(SR.Arg_SynchronizationLockException); + } + } } } diff --git a/src/System.Private.CoreLib/shared/System/Threading/Mutex.cs b/src/System.Private.CoreLib/shared/System/Threading/Mutex.cs new file mode 100644 index 0000000..bcc4ac7 --- /dev/null +++ b/src/System.Private.CoreLib/shared/System/Threading/Mutex.cs @@ -0,0 +1,64 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.IO; +using Microsoft.Win32; +using Microsoft.Win32.SafeHandles; +using System.Runtime.InteropServices; +using System.Diagnostics; + +namespace System.Threading +{ + /// + /// Synchronization primitive that can also be used for interprocess synchronization + /// + public sealed partial class Mutex : WaitHandle + { + public Mutex(bool initiallyOwned, string name, out bool createdNew) + { + VerifyNameForCreate(name); + CreateMutexCore(initiallyOwned, name, out createdNew); + } + + public Mutex(bool initiallyOwned, string name) + { + VerifyNameForCreate(name); + CreateMutexCore(initiallyOwned, name, out _); + } + + public Mutex(bool initiallyOwned) + { + CreateMutexCore(initiallyOwned, null, out _); + } + + public Mutex() + { + CreateMutexCore(false, null, out _); + } + + private Mutex(SafeWaitHandle handle) + { + SafeWaitHandle = handle; + } + + public static Mutex OpenExisting(string name) + { + switch (OpenExistingWorker(name, out Mutex 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 DirectoryNotFoundException(SR.Format(SR.IO_PathNotFound_Path, name)); + + default: + return result; + } + } + + public static bool TryOpenExisting(string name, out Mutex result) => + OpenExistingWorker(name, out result) == OpenExistingResult.Success; + } +} diff --git a/src/System.Private.CoreLib/src/Microsoft/Win32/Win32Native.cs b/src/System.Private.CoreLib/src/Microsoft/Win32/Win32Native.cs index 9a2678f..61dd2b3 100644 --- a/src/System.Private.CoreLib/src/Microsoft/Win32/Win32Native.cs +++ b/src/System.Private.CoreLib/src/Microsoft/Win32/Win32Native.cs @@ -173,9 +173,6 @@ namespace Microsoft.Win32 internal const uint CREATE_EVENT_MANUAL_RESET = 0x1; internal const uint CREATE_EVENT_INITIAL_SET = 0x2; - // CreateMutexEx: flags - internal const uint CREATE_MUTEX_INITIAL_OWNER = 0x1; - internal const int LMEM_FIXED = 0x0000; internal const int LMEM_ZEROINIT = 0x0040; internal const int LPTR = (LMEM_FIXED | LMEM_ZEROINIT); @@ -309,15 +306,6 @@ namespace Microsoft.Win32 [DllImport(Interop.Libraries.Kernel32, SetLastError = true, CharSet = CharSet.Auto, BestFitMapping = false)] internal static extern SafeWaitHandle OpenEvent(uint desiredAccess, bool inheritHandle, string name); - [DllImport(Interop.Libraries.Kernel32, SetLastError = true, CharSet = CharSet.Auto, BestFitMapping = false)] - internal static extern SafeWaitHandle CreateMutexEx(SECURITY_ATTRIBUTES lpSecurityAttributes, string name, uint flags, uint desiredAccess); - - [DllImport(Interop.Libraries.Kernel32, SetLastError = true, CharSet = CharSet.Auto, BestFitMapping = false)] - internal static extern SafeWaitHandle OpenMutex(uint desiredAccess, bool inheritHandle, string name); - - [DllImport(Interop.Libraries.Kernel32, SetLastError = true)] - internal static extern bool ReleaseMutex(SafeWaitHandle handle); - [DllImport(Interop.Libraries.Kernel32, SetLastError = true)] internal static extern bool CloseHandle(IntPtr handle); diff --git a/src/System.Private.CoreLib/src/System/Buffer.cs b/src/System.Private.CoreLib/src/System/Buffer.cs index 43372ca..8245aa9 100644 --- a/src/System.Private.CoreLib/src/System/Buffer.cs +++ b/src/System.Private.CoreLib/src/System/Buffer.cs @@ -6,28 +6,26 @@ #define HAS_CUSTOM_BLOCKS #endif -namespace System -{ - //Only contains static methods. Does not require serialization - - using System; - using System.Runtime.CompilerServices; - using System.Runtime.ConstrainedExecution; - using System.Runtime.InteropServices; - using System.Runtime.Versioning; - using System.Diagnostics; - using System.Security; - using System.Runtime; - using Internal.Runtime.CompilerServices; +using System; +using System.Runtime.CompilerServices; +using System.Runtime.ConstrainedExecution; +using System.Runtime.InteropServices; +using System.Runtime.Versioning; +using System.Diagnostics; +using System.Security; +using System.Runtime; +using Internal.Runtime.CompilerServices; #if BIT64 - using nint = System.Int64; - using nuint = System.UInt64; +using nint = System.Int64; +using nuint = System.UInt64; #else // BIT64 - using nint = System.Int32; - using nuint = System.UInt32; +using nint = System.Int32; +using nuint = System.UInt32; #endif // BIT64 +namespace System +{ public static class Buffer { // Copies from one primitive array to another primitive array without diff --git a/src/System.Private.CoreLib/src/System/Threading/EventWaitHandle.cs b/src/System.Private.CoreLib/src/System/Threading/EventWaitHandle.cs index c2ffb8c..4a02876 100644 --- a/src/System.Private.CoreLib/src/System/Threading/EventWaitHandle.cs +++ b/src/System.Private.CoreLib/src/System/Threading/EventWaitHandle.cs @@ -213,14 +213,14 @@ namespace System.Threading } public bool Reset() { - bool res = Win32Native.ResetEvent(safeWaitHandle); + bool res = Win32Native.ResetEvent(_waitHandle); if (!res) throw Win32Marshal.GetExceptionForLastWin32Error(); return res; } public bool Set() { - bool res = Win32Native.SetEvent(safeWaitHandle); + bool res = Win32Native.SetEvent(_waitHandle); if (!res) throw Win32Marshal.GetExceptionForLastWin32Error(); diff --git a/src/System.Private.CoreLib/src/System/Threading/WaitHandle.cs b/src/System.Private.CoreLib/src/System/Threading/WaitHandle.cs index 2de388d..aa8f8c2 100644 --- a/src/System.Private.CoreLib/src/System/Threading/WaitHandle.cs +++ b/src/System.Private.CoreLib/src/System/Threading/WaitHandle.cs @@ -34,7 +34,7 @@ namespace System.Threading private IntPtr waitHandle; // !!! DO NOT MOVE THIS FIELD. (See defn of WAITHANDLEREF in object.h - has hard-coded access to this field.) #pragma warning restore 414 - internal volatile SafeWaitHandle safeWaitHandle; + internal volatile SafeWaitHandle _waitHandle; internal bool hasThreadAffinity; @@ -63,7 +63,7 @@ namespace System.Threading private void Init() { - safeWaitHandle = null; + _waitHandle = null; waitHandle = InvalidHandle; hasThreadAffinity = false; } @@ -72,7 +72,7 @@ namespace System.Threading [Obsolete("Use the SafeWaitHandle property instead.")] public virtual IntPtr Handle { - get { return safeWaitHandle == null ? InvalidHandle : safeWaitHandle.DangerousGetHandle(); } + get { return _waitHandle == null ? InvalidHandle : _waitHandle.DangerousGetHandle(); } set { if (value == InvalidHandle) @@ -83,15 +83,15 @@ namespace System.Threading // ideally do these things: // *) Expose a settable SafeHandle property on WaitHandle. // *) Expose a settable OwnsHandle property on SafeHandle. - if (safeWaitHandle != null) + if (_waitHandle != null) { - safeWaitHandle.SetHandleAsInvalid(); - safeWaitHandle = null; + _waitHandle.SetHandleAsInvalid(); + _waitHandle = null; } } else { - safeWaitHandle = new SafeWaitHandle(value, true); + _waitHandle = new SafeWaitHandle(value, true); } waitHandle = value; } @@ -101,11 +101,11 @@ namespace System.Threading { get { - if (safeWaitHandle == null) + if (_waitHandle == null) { - safeWaitHandle = new SafeWaitHandle(InvalidHandle, false); + _waitHandle = new SafeWaitHandle(InvalidHandle, false); } - return safeWaitHandle; + return _waitHandle; } set @@ -120,13 +120,13 @@ namespace System.Threading { if (value == null) { - safeWaitHandle = null; + _waitHandle = null; waitHandle = InvalidHandle; } else { - safeWaitHandle = value; - waitHandle = safeWaitHandle.DangerousGetHandle(); + _waitHandle = value; + waitHandle = _waitHandle.DangerousGetHandle(); } } } @@ -143,7 +143,7 @@ namespace System.Threading // don't need to do a linktime check here. internal void SetHandleInternal(SafeWaitHandle handle) { - safeWaitHandle = handle; + _waitHandle = handle; waitHandle = handle.DangerousGetHandle(); } @@ -185,7 +185,7 @@ namespace System.Threading [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "Reviewed for thread-safety.")] private bool WaitOne(long timeout, bool exitContext) { - return InternalWaitOne(safeWaitHandle, timeout, hasThreadAffinity, exitContext); + return InternalWaitOne(_waitHandle, timeout, hasThreadAffinity, exitContext); } internal static bool InternalWaitOne(SafeHandle waitableSafeHandle, long millisecondsTimeout, bool hasThreadAffinity, bool exitContext) @@ -207,13 +207,13 @@ namespace System.Threading { // version of waitone without fast application switch (FAS) support // This is required to support the Wait which FAS needs (otherwise recursive dependency comes in) - if (safeWaitHandle == null) + if (_waitHandle == null) { throw new ObjectDisposedException(null, SR.ObjectDisposed_Generic); } long timeout = -1; - int ret = WaitOneNative(safeWaitHandle, (uint)timeout, hasThreadAffinity, false); + int ret = WaitOneNative(_waitHandle, (uint)timeout, hasThreadAffinity, false); if (ret == WAIT_ABANDONED) { ThrowAbandonedMutexException(); @@ -467,7 +467,7 @@ namespace System.Threading } //NOTE: This API is not supporting Pause/Resume as it's not exposed in CoreCLR (not in WP or SL) - int ret = SignalAndWaitOne(toSignal.safeWaitHandle, toWaitOn.safeWaitHandle, millisecondsTimeout, + int ret = SignalAndWaitOne(toSignal._waitHandle, toWaitOn._waitHandle, millisecondsTimeout, toWaitOn.hasThreadAffinity, exitContext); if (WAIT_ABANDONED == ret) @@ -508,9 +508,9 @@ namespace System.Threading protected virtual void Dispose(bool explicitDisposing) { - if (safeWaitHandle != null) + if (_waitHandle != null) { - safeWaitHandle.Close(); + _waitHandle.Close(); } } diff --git a/src/vm/mscorlib.h b/src/vm/mscorlib.h index 52dee0c..f66931a 100644 --- a/src/vm/mscorlib.h +++ b/src/vm/mscorlib.h @@ -982,7 +982,7 @@ DEFINE_FIELD_U(m_handle, WeakReferenceObject, m_Handle) DEFINE_CLASS(WEAKREFERENCE, System, WeakReference) DEFINE_CLASS_U(Threading, WaitHandle, WaitHandleBase) -DEFINE_FIELD_U(safeWaitHandle, WaitHandleBase, m_safeHandle) +DEFINE_FIELD_U(_waitHandle, WaitHandleBase, m_safeHandle) DEFINE_FIELD_U(waitHandle, WaitHandleBase, m_handle) DEFINE_FIELD_U(hasThreadAffinity, WaitHandleBase, m_hasThreadAffinity) -- 2.7.4