Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
7573706
Add EventWaitHandle creation extension method that takes an ACL
carlossanlop Oct 30, 2019
9b0c0c0
Call OpenExisting, add basic unit tests, move MAX_PATH in csproj for …
carlossanlop Oct 30, 2019
2984404
Address suggestions: using for the created handle, simplify try final…
carlossanlop Oct 31, 2019
ff6391e
simplify using, reorganize PInvokes a bit, let VS format resx as it e…
carlossanlop Oct 31, 2019
b518de9
Add more unit tests
carlossanlop Oct 31, 2019
240bbc7
Save basic access rights in a constant, generate name randomly
carlossanlop Oct 31, 2019
ce079a5
Use FullControl (EVENT_ALL_ACCESS); update unit tests to use EventWai…
carlossanlop Nov 1, 2019
e0cf7cc
Apply suggestion of creating an EWH, then replacing its SWH.
carlossanlop Nov 1, 2019
09f5a7b
Remove using causing chaos, add more unit tests, remove null string u…
carlossanlop Nov 1, 2019
7fb95e3
spacing
carlossanlop Nov 1, 2019
66b1d7a
Address comments
carlossanlop Nov 1, 2019
42adc30
Remove unnecessary checks/exceptions, update unit tests
carlossanlop Nov 1, 2019
6b6daa2
Fix netfx x86 ut failure - different exception for mode validation.
carlossanlop Nov 4, 2019
166da5c
Small documentation fix
carlossanlop Nov 4, 2019
f49035e
Remove documentation for exception thrown with null security
carlossanlop Nov 4, 2019
0b0a5b6
more documentation fixes
carlossanlop Nov 4, 2019
aba8320
New file for unit tests
carlossanlop Nov 5, 2019
95af0e1
Dispose and remove windows only attributes in tests
carlossanlop Nov 5, 2019
be24175
suggestion to not use var
carlossanlop Nov 5, 2019
0e4eb4c
Remove duplicate resx after merge
carlossanlop Nov 8, 2019
3d62b9a
Readd cs files lost during merge
carlossanlop Nov 8, 2019
0cf8663
Remove resx modification since it was untouched for this PR
carlossanlop Nov 8, 2019
bd2680f
Address test comments
carlossanlop Nov 8, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

#nullable enable
using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;
Expand All @@ -13,16 +14,16 @@ internal static partial class Kernel32
internal const uint CREATE_EVENT_INITIAL_SET = 0x2;
internal const uint CREATE_EVENT_MANUAL_RESET = 0x1;

[DllImport(Interop.Libraries.Kernel32, SetLastError = true)]
[DllImport(Libraries.Kernel32, SetLastError = true)]
internal static extern bool SetEvent(SafeWaitHandle handle);

[DllImport(Interop.Libraries.Kernel32, SetLastError = true)]
[DllImport(Libraries.Kernel32, SetLastError = true)]
internal static extern bool ResetEvent(SafeWaitHandle handle);

[DllImport(Interop.Libraries.Kernel32, EntryPoint = "CreateEventExW", SetLastError = true, CharSet = CharSet.Unicode)]
[DllImport(Libraries.Kernel32, EntryPoint = "CreateEventExW", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern SafeWaitHandle CreateEventEx(IntPtr lpSecurityAttributes, string? name, uint flags, uint desiredAccess);

[DllImport(Interop.Libraries.Kernel32, EntryPoint = "OpenEventW", SetLastError = true, CharSet = CharSet.Unicode)]
[DllImport(Libraries.Kernel32, EntryPoint = "OpenEventW", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern SafeWaitHandle OpenEvent(uint desiredAccess, bool inheritHandle, string name);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,10 @@ public static void SetAccessControl(this System.Threading.EventWaitHandle handle
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; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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" />
Expand All @@ -22,13 +23,15 @@
<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" />
</ItemGroup>
<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" />
Expand Down
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
Loading