Add EventWaitHandle creation extension method that takes an ACL (dotnet/corefx#42213)
authorCarlos Sanchez Lopez <1175054+carlossanlop@users.noreply.github.com>
Fri, 8 Nov 2019 03:37:03 +0000 (19:37 -0800)
committerGitHub <noreply@github.com>
Fri, 8 Nov 2019 03:37:03 +0000 (19:37 -0800)
* Add EventWaitHandle creation extension method that takes an ACL

* Call OpenExisting, add basic unit tests, move MAX_PATH in csproj for all Windows platforms, ensure same exceptions are thrown in both netcore and netfx.

* Address suggestions: using for the created handle, simplify try finally, merge methods, remove an unnecessary Debug.Assert

* simplify using, reorganize PInvokes a bit, let VS format resx as it expects it, remove BOM from csproj

* Add more unit tests

* Save basic access rights in a constant, generate name randomly

* Use FullControl (EVENT_ALL_ACCESS); update unit tests to use EventWaitHandleRights

* Apply suggestion of creating an EWH, then replacing its SWH.

* Remove using causing chaos, add more unit tests, remove null string unit test.

* spacing

* Address comments

* Remove unnecessary checks/exceptions, update unit tests

* Fix netfx x86 ut failure - different exception for mode validation.

* Small documentation fix

* Remove documentation for exception thrown with null security

* more documentation fixes

* New file for unit tests

* Dispose and remove windows only attributes in tests

* suggestion to not use var

* Remove duplicate resx after merge

* Readd cs files lost during merge

* Remove resx modification since it was untouched for this PR

* Address test comments

Commit migrated from https://github.com/dotnet/corefx/commit/14b0893b7aa8099711cceb908b42f6d5cbb9cd5c

src/libraries/System.Threading.AccessControl/ref/System.Threading.AccessControl.cs
src/libraries/System.Threading.AccessControl/src/System.Threading.AccessControl.csproj
src/libraries/System.Threading.AccessControl/src/System/Threading/EventWaitHandleAcl.cs [new file with mode: 0644]
src/libraries/System.Threading.AccessControl/src/System/Threading/EventWaitHandleAcl.net46.cs [new file with mode: 0644]
src/libraries/System.Threading.AccessControl/tests/EventWaitHandleAclTests.cs [new file with mode: 0644]
src/libraries/System.Threading.AccessControl/tests/MutexAclTests.cs
src/libraries/System.Threading.AccessControl/tests/SemaphoreAclTests.cs
src/libraries/System.Threading.AccessControl/tests/System.Threading.AccessControl.Tests.csproj

index 0298eb4..a4b5d31 100644 (file)
@@ -147,6 +147,10 @@ namespace System.Threading
         public static void SetAccessControl(this System.Threading.Mutex mutex, System.Security.AccessControl.MutexSecurity mutexSecurity) { }
         public static void SetAccessControl(this System.Threading.Semaphore semaphore, System.Security.AccessControl.SemaphoreSecurity semaphoreSecurity) { }
     }
+    public static class EventWaitHandleAcl
+    {
+        public static System.Threading.EventWaitHandle Create(bool initialState, System.Threading.EventResetMode mode, string name, out bool createdNew, System.Security.AccessControl.EventWaitHandleSecurity eventSecurity) { throw null; }
+    }
     public static class MutexAcl
     {
         public static System.Threading.Mutex Create(bool initiallyOwned, string name, out bool createdNew, System.Security.AccessControl.MutexSecurity mutexSecurity) { throw null; }
index 23200dd..44aa39c 100644 (file)
@@ -13,6 +13,7 @@
     <Compile Include="$(CommonPath)\Interop\Windows\Interop.Errors.cs" Link="Common\Interop\Windows\Interop.Errors.cs" />
     <Compile Include="$(CommonPath)\CoreLib\Interop\Windows\Interop.BOOL.cs" Link="Common\CoreLib\Interop\Windows\Interop.BOOL.cs" />
     <Compile Include="$(CommonPath)\CoreLib\Interop\Windows\Interop.Libraries.cs" Link="Common\CoreLib\Interop\Windows\Interop.Libraries.cs" />
+    <Compile Include="$(CommonPath)\CoreLib\Interop\Windows\Kernel32\Interop.EventWaitHandle.cs" Link="Common\CoreLib\Interop\Windows\Kernel32\Interop.EventWaitHandle.cs" />
     <Compile Include="$(CommonPath)\CoreLib\Interop\Windows\Kernel32\Interop.Constants.cs" Link="Common\CoreLib\Interop\Windows\Kernel32\Interop.Constants.cs" />
     <Compile Include="$(CommonPath)\CoreLib\Interop\Windows\Kernel32\Interop.FormatMessage.cs" Link="Common\CoreLib\Interop\Windows\Kernel32\Interop.FormatMessage.cs" />
     <Compile Include="$(CommonPath)\CoreLib\Interop\Windows\Kernel32\Interop.Mutex.cs" Link="Common\CoreLib\Interop\Windows\Kernel32\Interop.Mutex.cs" />
@@ -22,6 +23,7 @@
     <Compile Include="System\Security\AccessControl\MutexSecurity.cs" />
     <Compile Include="System\Security\AccessControl\EventWaitHandleSecurity.cs" />
     <Compile Include="System\Security\AccessControl\SemaphoreSecurity.cs" />
+    <Compile Include="System\Threading\EventWaitHandleAcl.cs" />
     <Compile Include="System\Threading\MutexAcl.cs" />
     <Compile Include="System\Threading\SemaphoreAcl.cs" />
     <Compile Include="System\Threading\ThreadingAclExtensions.cs" />
@@ -29,6 +31,7 @@
   <ItemGroup Condition="'$(TargetsNetFx)' == 'true'">
     <Reference Include="mscorlib" />
     <Reference Include="System" />
+    <Compile Include="System\Threading\EventWaitHandleAcl.net46.cs" />
     <Compile Include="System\Threading\MutexAcl.net46.cs" />
     <Compile Include="System\Threading\SemaphoreAcl.net46.cs" />
     <Compile Include="System\Threading\ThreadingAclExtensions.net46.cs" />
diff --git a/src/libraries/System.Threading.AccessControl/src/System/Threading/EventWaitHandleAcl.cs b/src/libraries/System.Threading.AccessControl/src/System/Threading/EventWaitHandleAcl.cs
new file mode 100644 (file)
index 0000000..f6a15ff
--- /dev/null
@@ -0,0 +1,88 @@
+// 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 System.Runtime.InteropServices;
+using System.Security.AccessControl;
+using Microsoft.Win32.SafeHandles;
+
+namespace System.Threading
+{
+    public static class EventWaitHandleAcl
+    {
+        /// <summary>Gets or creates an <see cref="EventWaitHandle" /> instance, allowing a <see cref="EventWaitHandleSecurity " /> instance to be optionally specified to set it during the event creation.</summary>
+        /// <param name="initialState"><see langword="true" /> to set the initial state to signaled if the named event is created as a result of this call; <see langword="false" /> to set it to non-signaled.</param>
+        /// <param name="mode">One of the enum values that determines whether the event resets automatically or manually.</param>
+        /// <param name="name">The name, if the event is a system-wide synchronization event; otherwise, <see langword="null" /> or an empty string.</param>
+        /// <param name="createdNew">When this method returns, this argument is always set to <see langword="true" /> if a local event is created; that is, when <paramref name="name" /> is <see langword="null" /> or <see cref="string.Empty" />. If <paramref name="name" /> has a valid, non-empty value, this argument is set to <see langword="true" /> when the system event is created, or it is set to <see langword="false" /> if an existing system event is found with that name. This parameter is passed uninitialized.</param>
+        /// <param name="eventSecurity">The optional Windows access control security to apply.</param>
+        /// <returns>An object that represents a system event wait handle, if named, or a local event wait handle, if nameless.</returns>
+        /// <exception cref="ArgumentNullException">.NET Framework only: The <paramref name="name" /> length is beyond MAX_PATH (260 characters).</exception>
+        /// <exception cref="ArgumentOutOfRangeException">The <paramref name="mode" /> enum value was out of legal range.</exception>
+        /// <exception cref="DirectoryNotFoundException">Could not find a part of the path specified in <paramref name="name" />.</exception>
+        /// <exception cref="WaitHandleCannotBeOpenedException">A system-wide synchronization event with the provided <paramref name="name" /> was not found.
+        /// -or-
+        /// An <see cref="EventWaitHandle" /> with system-wide name <paramref name="name" /> cannot be created. An <see cref="EventWaitHandle" /> of a different type might have the same name.</exception>
+        /// <remarks>If a `name` is passed and the system event already exists, the existing event is returned. If `name` is `null` or <see cref="string.Empty" />, a new local event is always created.</remarks>
+        public static unsafe EventWaitHandle Create(bool initialState, EventResetMode mode, string name, out bool createdNew, EventWaitHandleSecurity eventSecurity)
+        {
+            if (eventSecurity == null)
+            {
+                return new EventWaitHandle(initialState, mode, name, out createdNew);
+            }
+
+            if (mode != EventResetMode.AutoReset && mode != EventResetMode.ManualReset)
+            {
+                throw new ArgumentOutOfRangeException(nameof(mode));
+            }
+
+            uint eventFlags = initialState ? Interop.Kernel32.CREATE_EVENT_INITIAL_SET : 0;
+            if (mode == EventResetMode.ManualReset)
+            {
+                eventFlags |= Interop.Kernel32.CREATE_EVENT_MANUAL_RESET;
+            }
+
+            fixed (byte* pSecurityDescriptor = eventSecurity.GetSecurityDescriptorBinaryForm())
+            {
+                var secAttrs = new Interop.Kernel32.SECURITY_ATTRIBUTES
+                {
+                    nLength = (uint)sizeof(Interop.Kernel32.SECURITY_ATTRIBUTES),
+                    lpSecurityDescriptor = (IntPtr)pSecurityDescriptor
+                };
+
+                SafeWaitHandle handle = Interop.Kernel32.CreateEventEx(
+                    (IntPtr)(&secAttrs),
+                    name,
+                    eventFlags,
+                    (uint)EventWaitHandleRights.FullControl);
+
+                ValidateHandle(handle, name, out createdNew);
+
+                EventWaitHandle ewh = new EventWaitHandle(initialState, mode);
+                SafeWaitHandle old = ewh.SafeWaitHandle;
+                ewh.SafeWaitHandle = handle;
+                old.Dispose();
+
+                return ewh;
+            }
+        }
+
+        private static void ValidateHandle(SafeWaitHandle handle, string name, out bool createdNew)
+        {
+            int errorCode = Marshal.GetLastWin32Error();
+
+            if (handle.IsInvalid)
+            {
+                handle.SetHandleAsInvalid();
+
+                if (!string.IsNullOrEmpty(name) && errorCode == Interop.Errors.ERROR_INVALID_HANDLE)
+                    throw new WaitHandleCannotBeOpenedException(SR.Format(SR.WaitHandleCannotBeOpenedException_InvalidHandle, name));
+
+                throw Win32Marshal.GetExceptionForWin32Error(errorCode, name);
+            }
+
+            createdNew = (errorCode != Interop.Errors.ERROR_ALREADY_EXISTS);
+        }
+    }
+}
diff --git a/src/libraries/System.Threading.AccessControl/src/System/Threading/EventWaitHandleAcl.net46.cs b/src/libraries/System.Threading.AccessControl/src/System/Threading/EventWaitHandleAcl.net46.cs
new file mode 100644 (file)
index 0000000..2b8e65d
--- /dev/null
@@ -0,0 +1,21 @@
+// 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.Security.AccessControl;
+
+namespace System.Threading
+{
+    public static class EventWaitHandleAcl
+    {
+        public static EventWaitHandle Create(
+            bool initialState,
+            EventResetMode mode,
+            string name,
+            out bool createdNew,
+            EventWaitHandleSecurity eventSecurity)
+        {
+            return new EventWaitHandle(initialState, mode, name, out createdNew, eventSecurity);
+        }
+    }
+}
diff --git a/src/libraries/System.Threading.AccessControl/tests/EventWaitHandleAclTests.cs b/src/libraries/System.Threading.AccessControl/tests/EventWaitHandleAclTests.cs
new file mode 100644 (file)
index 0000000..ca02c30
--- /dev/null
@@ -0,0 +1,247 @@
+// 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.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Security.AccessControl;
+using System.Security.Principal;
+using Xunit;
+
+namespace System.Threading.Tests
+{
+    public class EventWaitHandleAclTests : AclTests
+    {
+        [Fact]
+        public void EventWaitHandle_Create_NullSecurity()
+        {
+            CreateAndVerifyEventWaitHandle(
+                initialState: true,
+                mode: EventResetMode.AutoReset,
+                name: GetRandomName(),
+                expectedSecurity: null,
+                expectedCreatedNew: true).Dispose();
+        }
+
+        [Theory]
+        [InlineData(null)]
+        [InlineData("")]
+        public void EventWaitHandle_Create_NameMultipleNew(string name)
+        {
+            EventWaitHandleSecurity security = GetBasicEventWaitHandleSecurity();
+
+            using EventWaitHandle handle1 = CreateAndVerifyEventWaitHandle(
+                initialState: true,
+                mode: EventResetMode.AutoReset,
+                name,
+                security,
+                expectedCreatedNew: true);
+
+            using EventWaitHandle handle2 = CreateAndVerifyEventWaitHandle(
+                initialState: true,
+                mode: EventResetMode.AutoReset,
+                name,
+                security,
+                expectedCreatedNew: true);
+        }
+
+        [Fact]
+        public void EventWaitHandle_Create_CreateNewExisting()
+        {
+            string name = GetRandomName();
+            EventWaitHandleSecurity security = GetBasicEventWaitHandleSecurity();
+
+            using EventWaitHandle handle1 = CreateAndVerifyEventWaitHandle(
+                initialState: true,
+                mode: EventResetMode.AutoReset,
+                name,
+                security,
+                expectedCreatedNew: true);
+
+            using EventWaitHandle handle2 = CreateAndVerifyEventWaitHandle(
+                initialState: true,
+                mode: EventResetMode.AutoReset,
+                name,
+                security,
+                expectedCreatedNew: false);
+        }
+
+        [Fact]
+        public void EventWaitHandle_Create_GlobalPrefixNameNotFound()
+        {
+            string prefixedName = @"GLOBAL\" + GetRandomName();
+
+            Assert.Throws<DirectoryNotFoundException>(() =>
+            {
+                CreateEventWaitHandle(
+                    initialState: true,
+                    mode: EventResetMode.AutoReset,
+                    prefixedName,
+                    expectedSecurity: GetBasicEventWaitHandleSecurity(),
+                    expectedCreatedNew: true).Dispose();
+            });
+        }
+
+        // The documentation says MAX_PATH is the length limit for name, but it won't throw any errors:
+        // https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-createeventexw
+        // The .NET Core constructors for EventWaitHandle do not throw on name longer than MAX_LENGTH, so the extension method should match the behavior:
+        // https://source.dot.net/#System.Private.CoreLib/shared/System/Threading/EventWaitHandle.Windows.cs,20
+        // The .NET Framework constructor throws:
+        // https://referencesource.microsoft.com/#mscorlib/system/threading/eventwaithandle.cs,59
+        [Fact]
+        public void EventWaitHandle_Create_BeyondMaxPathLength()
+        {
+            string name = new string('x', Interop.Kernel32.MAX_PATH + 100);
+            EventWaitHandleSecurity security = GetBasicEventWaitHandleSecurity();
+            EventResetMode mode = EventResetMode.AutoReset;
+
+            if (PlatformDetection.IsFullFramework)
+            {
+                Assert.Throws<ArgumentException>(() =>
+                {
+                    CreateEventWaitHandle(
+                        initialState: true,
+                        mode,
+                        name,
+                        security,
+                        expectedCreatedNew: true).Dispose();
+                });
+            }
+            else
+            {
+                using EventWaitHandle created = CreateAndVerifyEventWaitHandle(
+                        initialState: true,
+                        mode,
+                        name,
+                        security,
+                        expectedCreatedNew: true);
+
+                using EventWaitHandle openedByName = EventWaitHandle.OpenExisting(name);
+                Assert.NotNull(openedByName);
+            }
+        }
+
+        [Theory]
+        [InlineData((EventResetMode)int.MinValue)]
+        [InlineData((EventResetMode)(-1))]
+        [InlineData((EventResetMode)2)]
+        [InlineData((EventResetMode)int.MaxValue)]
+        public void EventWaitHandle_Create_InvalidMode(EventResetMode mode)
+        {
+            if (PlatformDetection.IsFullFramework)
+            {
+                Assert.Throws<ArgumentException>(() =>
+                {
+                    CreateEventWaitHandle(
+                        initialState: true,
+                        mode,
+                        GetRandomName(),
+                        GetBasicEventWaitHandleSecurity(),
+                        expectedCreatedNew: true).Dispose();
+                });
+            }
+            else
+            {
+                Assert.Throws<ArgumentOutOfRangeException>("mode", () =>
+                {
+                    CreateEventWaitHandle(
+                        initialState: true,
+                        mode,
+                        GetRandomName(),
+                        GetBasicEventWaitHandleSecurity(),
+                        expectedCreatedNew: true).Dispose();
+                });
+            }
+        }
+
+        public static IEnumerable<object[]> EventWaitHandle_Create_SpecificParameters_MemberData() =>
+            from initialState in new[] { true, false }
+            from mode in new[] { EventResetMode.AutoReset, EventResetMode.ManualReset }
+            from rights in new[] { EventWaitHandleRights.FullControl, EventWaitHandleRights.Synchronize, EventWaitHandleRights.Modify, EventWaitHandleRights.Modify | EventWaitHandleRights.Synchronize }
+            from accessControl in new[] { AccessControlType.Allow, AccessControlType.Deny }
+            select new object[] { initialState, mode, rights, accessControl };
+
+        [Theory]
+        [MemberData(nameof(EventWaitHandle_Create_SpecificParameters_MemberData))]
+        public void EventWaitHandle_Create_SpecificParameters(bool initialState, EventResetMode mode, EventWaitHandleRights rights, AccessControlType accessControl)
+        {
+            EventWaitHandleSecurity security = GetEventWaitHandleSecurity(WellKnownSidType.BuiltinUsersSid, rights, accessControl);
+            CreateAndVerifyEventWaitHandle(
+                initialState,
+                mode,
+                GetRandomName(),
+                security,
+                expectedCreatedNew: true).Dispose();
+
+        }
+
+        private EventWaitHandleSecurity GetBasicEventWaitHandleSecurity()
+        {
+            return GetEventWaitHandleSecurity(
+                WellKnownSidType.BuiltinUsersSid,
+                EventWaitHandleRights.FullControl,
+                AccessControlType.Allow);
+        }
+
+        private EventWaitHandleSecurity GetEventWaitHandleSecurity(WellKnownSidType sid, EventWaitHandleRights rights, AccessControlType accessControl)
+        {
+            EventWaitHandleSecurity security = new EventWaitHandleSecurity();
+            SecurityIdentifier identity = new SecurityIdentifier(sid, null);
+            EventWaitHandleAccessRule accessRule = new EventWaitHandleAccessRule(identity, rights, accessControl);
+            security.AddAccessRule(accessRule);
+            return security;
+        }
+        private EventWaitHandle CreateEventWaitHandle(bool initialState, EventResetMode mode, string name, EventWaitHandleSecurity expectedSecurity, bool expectedCreatedNew)
+        {
+            EventWaitHandle handle = EventWaitHandleAcl.Create(initialState, mode, name, out bool createdNew, expectedSecurity);
+            Assert.NotNull(handle);
+            Assert.Equal(expectedCreatedNew, createdNew);
+            return handle;
+        }
+
+        private EventWaitHandle CreateAndVerifyEventWaitHandle(bool initialState, EventResetMode mode, string name, EventWaitHandleSecurity expectedSecurity, bool expectedCreatedNew)
+        {
+            EventWaitHandle eventHandle = CreateEventWaitHandle(initialState, mode, name, expectedSecurity, expectedCreatedNew);
+
+            if (expectedSecurity != null)
+            {
+                EventWaitHandleSecurity actualSecurity = eventHandle.GetAccessControl();
+                VerifyEventWaitHandleSecurity(expectedSecurity, actualSecurity);
+            }
+
+            return eventHandle;
+        }
+
+        private void VerifyEventWaitHandleSecurity(EventWaitHandleSecurity expectedSecurity, EventWaitHandleSecurity actualSecurity)
+        {
+            Assert.Equal(typeof(EventWaitHandleRights), expectedSecurity.AccessRightType);
+            Assert.Equal(typeof(EventWaitHandleRights), actualSecurity.AccessRightType);
+
+            List<EventWaitHandleAccessRule> expectedAccessRules = expectedSecurity.GetAccessRules(includeExplicit: true, includeInherited: false, typeof(SecurityIdentifier))
+                .Cast<EventWaitHandleAccessRule>().ToList();
+
+            List<EventWaitHandleAccessRule> actualAccessRules = actualSecurity.GetAccessRules(includeExplicit: true, includeInherited: false, typeof(SecurityIdentifier))
+                .Cast<EventWaitHandleAccessRule>().ToList();
+
+            Assert.Equal(expectedAccessRules.Count, actualAccessRules.Count);
+            if (expectedAccessRules.Count > 0)
+            {
+                Assert.All(expectedAccessRules, actualAccessRule =>
+                {
+                    int count = expectedAccessRules.Count(expectedAccessRule => AreAccessRulesEqual(expectedAccessRule, actualAccessRule));
+                    Assert.True(count > 0);
+                });
+            }
+        }
+
+        private bool AreAccessRulesEqual(EventWaitHandleAccessRule expectedRule, EventWaitHandleAccessRule actualRule)
+        {
+            return
+                expectedRule.AccessControlType     == actualRule.AccessControlType &&
+                expectedRule.EventWaitHandleRights == actualRule.EventWaitHandleRights &&
+                expectedRule.InheritanceFlags      == actualRule.InheritanceFlags &&
+                expectedRule.PropagationFlags      == actualRule.PropagationFlags;
+        }
+    }
+}
index f51f09e..2b5bf00 100644 (file)
@@ -23,7 +23,7 @@ namespace System.Threading.Tests
         [InlineData("")]
         public void Mutex_Create_NameMultipleNew(string name)
         {
-            var security = GetBasicMutexSecurity();
+            MutexSecurity security = GetBasicMutexSecurity();
 
             using Mutex mutex1 = CreateAndVerifyMutex(initiallyOwned: true, name, security, expectedCreatedNew: true);
             using Mutex mutex2 = CreateAndVerifyMutex(initiallyOwned: true, name, security, expectedCreatedNew: true);
@@ -33,7 +33,7 @@ namespace System.Threading.Tests
         public void Mutex_Create_CreateNewExisting()
         {
             string name = GetRandomName();
-            var security = GetBasicMutexSecurity();
+            MutexSecurity security = GetBasicMutexSecurity();
 
             using Mutex mutexNew      = CreateAndVerifyMutex(initiallyOwned: true, name, security, expectedCreatedNew: true);
             using Mutex mutexExisting = CreateAndVerifyMutex(initiallyOwned: true, name, security, expectedCreatedNew: false);
@@ -76,7 +76,7 @@ namespace System.Threading.Tests
         [InlineData(false, MutexRights.Modify, AccessControlType.Deny)]
         public void Mutex_Create_SpecificParameters(bool initiallyOwned, MutexRights rights, AccessControlType accessControl)
         {
-            var security = GetMutexSecurity(WellKnownSidType.BuiltinUsersSid, rights, accessControl);
+            MutexSecurity security = GetMutexSecurity(WellKnownSidType.BuiltinUsersSid, rights, accessControl);
             CreateAndVerifyMutex(initiallyOwned, GetRandomName(), security, expectedCreatedNew: true).Dispose();
 
         }
@@ -91,9 +91,9 @@ namespace System.Threading.Tests
 
         private MutexSecurity GetMutexSecurity(WellKnownSidType sid, MutexRights rights, AccessControlType accessControl)
         {
-            var security = new MutexSecurity();
+            MutexSecurity security = new MutexSecurity();
             SecurityIdentifier identity = new SecurityIdentifier(sid, null);
-            var accessRule = new MutexAccessRule(identity, rights, accessControl);
+            MutexAccessRule accessRule = new MutexAccessRule(identity, rights, accessControl);
             security.AddAccessRule(accessRule);
             return security;
         }
index 028cc31..970217f 100644 (file)
@@ -48,7 +48,7 @@ namespace System.Threading.Tests
         [InlineData("")]
         public void Semaphore_Create_NameMultipleNew(string name)
         {
-            var security = GetBasicSemaphoreSecurity();
+            SemaphoreSecurity security = GetBasicSemaphoreSecurity();
             bool expectedCreatedNew = true;
 
             using Semaphore semaphore1 = CreateAndVerifySemaphore(
@@ -70,7 +70,7 @@ namespace System.Threading.Tests
         public void Semaphore_Create_CreateNewExisting()
         {
             string name = GetRandomName();
-            var security = GetBasicSemaphoreSecurity();
+            SemaphoreSecurity security = GetBasicSemaphoreSecurity();
 
             using Semaphore SemaphoreNew = CreateAndVerifySemaphore(
                 DefaultInitialCount,
@@ -129,7 +129,7 @@ namespace System.Threading.Tests
         [InlineData(SemaphoreRights.Modify | SemaphoreRights.Synchronize, AccessControlType.Deny)]
         public void Semaphore_Create_SpecificSecurity(SemaphoreRights rights, AccessControlType accessControl)
         {
-            var security = GetSemaphoreSecurity(WellKnownSidType.BuiltinUsersSid, rights, accessControl);
+            SemaphoreSecurity security = GetSemaphoreSecurity(WellKnownSidType.BuiltinUsersSid, rights, accessControl);
 
             CreateAndVerifySemaphore(
                 DefaultInitialCount,
@@ -150,9 +150,9 @@ namespace System.Threading.Tests
 
         private SemaphoreSecurity GetSemaphoreSecurity(WellKnownSidType sid, SemaphoreRights rights, AccessControlType accessControl)
         {
-            var security = new SemaphoreSecurity();
+            SemaphoreSecurity security = new SemaphoreSecurity();
             SecurityIdentifier identity = new SecurityIdentifier(sid, null);
-            var accessRule = new SemaphoreAccessRule(identity, rights, accessControl);
+            SemaphoreAccessRule accessRule = new SemaphoreAccessRule(identity, rights, accessControl);
             security.AddAccessRule(accessRule);
             return security;
         }
index 478d1d8..3974171 100644 (file)
@@ -6,6 +6,7 @@
     <Compile Include="$(CommonPath)\CoreLib\Interop\Windows\Kernel32\Interop.Constants.cs" Link="Common\CoreLib\Interop\Windows\Kernel32\Interop.Constants.cs" />
     <Compile Include="$(CommonPath)\CoreLib\Interop\Windows\Kernel32\Interop.MAX_PATH.cs" Link="Common\CoreLib\Interop\Windows\Kernel32\Interop.MAX_PATH.cs" />
     <Compile Include="AclTests.cs" />
+    <Compile Include="EventWaitHandleAclTests.cs" />
     <Compile Include="MutexAclTests.cs" />
     <Compile Include="MutexSecurityTests.cs" />
     <Compile Include="SemaphoreAclTests.cs" />