/src/libraries/System.Threading.AccessControl/src/System/Threading/SemaphoreAcl.cs

https://github.com/dotnet/runtime · C# · 92 lines · 64 code · 14 blank · 14 comment · 10 complexity · d6e971a18210f8ed19fd0dcecc6241af MD5 · raw file

  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the MIT license.
  3. using System.IO;
  4. using System.Runtime.InteropServices;
  5. using System.Security.AccessControl;
  6. using Microsoft.Win32.SafeHandles;
  7. namespace System.Threading
  8. {
  9. public static class SemaphoreAcl
  10. {
  11. /// <summary>Gets or creates an <see cref="Semaphore" /> instance, allowing a <see cref="SemaphoreSecurity " /> instance to be optionally specified to set it during the event creation.</summary>
  12. /// <param name="initialCount">The initial number of requests for the semaphore that can be satisfied concurrently.</param>
  13. /// <param name="maximumCount">The maximum number of requests for the semaphore that can be satisfied concurrently.</param>
  14. /// <param name="name">Optional argument to create a system semaphore. Set to <see langword="null" /> or <see cref="string.Empty" /> to create a local semaphore.</param>
  15. /// <param name="createdNew">When this method returns, this argument is always set to <see langword="true" /> if a local semaphore 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 semaphore is created, or it is set to <see langword="false" /> if an existing system semaphore is found with that name. This parameter is passed uninitialized.</param>
  16. /// <param name="semaphoreSecurity">The optional semaphore access control security to apply.</param>
  17. /// <returns>An object that represents a system semaphore, if named, or a local semaphore, if nameless.</returns>
  18. /// <exception cref="ArgumentOutOfRangeException"><paramref name="initialCount" /> is a negative number.
  19. /// -or-
  20. /// <paramref name="maximumCount" /> is not a positive number.</exception>
  21. /// <exception cref="ArgumentException"><paramref name="initialCount" /> is greater than <paramref name="maximumCount" />.</exception>
  22. /// <exception cref="WaitHandleCannotBeOpenedException">A semaphore handle with the system-wide name '<paramref name="name" />' cannot be created. A semaphore handle of a different type might have the same name.</exception>
  23. public static unsafe Semaphore Create(int initialCount, int maximumCount, string? name, out bool createdNew, SemaphoreSecurity? semaphoreSecurity)
  24. {
  25. if (semaphoreSecurity == null)
  26. {
  27. return new Semaphore(initialCount, maximumCount, name, out createdNew);
  28. }
  29. if (initialCount < 0)
  30. {
  31. throw new ArgumentOutOfRangeException(nameof(initialCount), SR.ArgumentOutOfRange_NeedNonNegNum);
  32. }
  33. if (maximumCount < 1)
  34. {
  35. throw new ArgumentOutOfRangeException(nameof(maximumCount), SR.ArgumentOutOfRange_NeedPosNum);
  36. }
  37. if (initialCount > maximumCount)
  38. {
  39. throw new ArgumentException(SR.Argument_SemaphoreInitialMaximum);
  40. }
  41. fixed (byte* pSecurityDescriptor = semaphoreSecurity.GetSecurityDescriptorBinaryForm())
  42. {
  43. var secAttrs = new Interop.Kernel32.SECURITY_ATTRIBUTES
  44. {
  45. nLength = (uint)sizeof(Interop.Kernel32.SECURITY_ATTRIBUTES),
  46. lpSecurityDescriptor = (IntPtr)pSecurityDescriptor
  47. };
  48. SafeWaitHandle handle = Interop.Kernel32.CreateSemaphoreEx(
  49. (IntPtr)(&secAttrs),
  50. initialCount,
  51. maximumCount,
  52. name,
  53. 0, // This parameter is reserved and must be 0.
  54. (uint)SemaphoreRights.FullControl // Equivalent to SEMAPHORE_ALL_ACCESS
  55. );
  56. ValidateHandle(handle, name, out createdNew);
  57. Semaphore semaphore = new Semaphore(initialCount, maximumCount);
  58. SafeWaitHandle old = semaphore.SafeWaitHandle;
  59. semaphore.SafeWaitHandle = handle;
  60. old.Dispose();
  61. return semaphore;
  62. }
  63. }
  64. private static void ValidateHandle(SafeWaitHandle handle, string? name, out bool createdNew)
  65. {
  66. int errorCode = Marshal.GetLastWin32Error();
  67. if (handle.IsInvalid)
  68. {
  69. if (!string.IsNullOrEmpty(name) && errorCode == Interop.Errors.ERROR_INVALID_HANDLE)
  70. {
  71. throw new WaitHandleCannotBeOpenedException(SR.Format(SR.Threading_WaitHandleCannotBeOpenedException_InvalidHandle, name));
  72. }
  73. throw Win32Marshal.GetExceptionForLastWin32Error();
  74. }
  75. createdNew = errorCode != Interop.Errors.ERROR_ALREADY_EXISTS;
  76. }
  77. }
  78. }