PageRenderTime 43ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/mcs/class/referencesource/System/sys/system/threading/semaphore.cs

https://github.com/pruiz/mono
C# | 410 lines | 348 code | 45 blank | 17 comment | 70 complexity | 59ca631096b516eb93778d2b72f8f550 MD5 | raw file
Possible License(s): LGPL-2.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0
  1. #if MONO
  2. #undef FEATURE_PAL
  3. #endif
  4. // ==++==
  5. //
  6. // Copyright (c) Microsoft Corporation. All rights reserved.
  7. //
  8. // ==--==
  9. namespace System.Threading
  10. {
  11. using System.IO;
  12. using System.IO.Ports; // For InternalResources class
  13. using Microsoft.Win32;
  14. using Microsoft.Win32.SafeHandles;
  15. // CoreSys build problem - we're using mscorlib's implementation assembly instead of one from asmmeta. There's a conflicting NativeMethods type.
  16. using Marshal = System.Runtime.InteropServices.Marshal;
  17. using ComVisibleAttribute = System.Runtime.InteropServices.ComVisibleAttribute;
  18. using System.Threading;
  19. using System.Security;
  20. using System.Security.Permissions;
  21. #if !FEATURE_PAL && !FEATURE_NETCORE
  22. using System.Security.AccessControl;
  23. #endif
  24. using System.Runtime.Versioning;
  25. using System.Runtime.ConstrainedExecution;
  26. using System.Runtime.CompilerServices;
  27. [HostProtection(Synchronization=true, ExternalThreading=true)]
  28. [ComVisibleAttribute(false)]
  29. public sealed class Semaphore: WaitHandle
  30. {
  31. private const int MAX_PATH = 260;
  32. // creates a nameless semaphore object
  33. // Win32 only takes maximum count of Int32.MaxValue
  34. [SecuritySafeCritical]
  35. #if !FEATURE_NETCORE
  36. [ResourceExposure(ResourceScope.None)]
  37. [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
  38. #endif // !FEATURE_NETCORE
  39. public Semaphore(int initialCount, int maximumCount) : this(initialCount,maximumCount,null){}
  40. #if FEATURE_NETCORE
  41. [SecurityCritical]
  42. #else
  43. [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
  44. [ResourceExposure(ResourceScope.Machine)]
  45. [ResourceConsumption(ResourceScope.Machine)]
  46. #endif
  47. public Semaphore(int initialCount, int maximumCount, string name)
  48. {
  49. if (initialCount < 0)
  50. {
  51. throw new ArgumentOutOfRangeException("initialCount", SR.GetString(SR.ArgumentOutOfRange_NeedNonNegNumRequired));
  52. }
  53. if (maximumCount < 1)
  54. {
  55. throw new ArgumentOutOfRangeException("maximumCount", SR.GetString(SR.ArgumentOutOfRange_NeedPosNum));
  56. }
  57. if (initialCount > maximumCount)
  58. {
  59. throw new ArgumentException(SR.GetString(SR.Argument_SemaphoreInitialMaximum));
  60. }
  61. if(null != name && MAX_PATH < name.Length)
  62. {
  63. throw new ArgumentException(SR.GetString(SR.Argument_WaitHandleNameTooLong));
  64. }
  65. #if MONO
  66. int errorCode;
  67. var myHandle = new SafeWaitHandle (CreateSemaphore_internal (initialCount, maximumCount, name, out errorCode), true);
  68. #else
  69. SafeWaitHandle myHandle = SafeNativeMethods.CreateSemaphore(null, initialCount, maximumCount, name);
  70. #endif
  71. if (myHandle.IsInvalid)
  72. {
  73. #if !MONO
  74. int errorCode = Marshal.GetLastWin32Error();
  75. #endif
  76. if(null != name && 0 != name.Length && NativeMethods.ERROR_INVALID_HANDLE == errorCode)
  77. throw new WaitHandleCannotBeOpenedException(SR.GetString(SR.WaitHandleCannotBeOpenedException_InvalidHandle,name));
  78. #if MONO
  79. InternalResources.WinIOError(errorCode, "");
  80. #else
  81. InternalResources.WinIOError();
  82. #endif
  83. }
  84. this.SafeWaitHandle = myHandle;
  85. }
  86. #if FEATURE_NETCORE
  87. [SecurityCritical]
  88. #else
  89. [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
  90. [ResourceExposure(ResourceScope.Machine)]
  91. [ResourceConsumption(ResourceScope.Machine)]
  92. #endif
  93. public Semaphore(int initialCount, int maximumCount, string name, out bool createdNew)
  94. #if !FEATURE_PAL && !FEATURE_NETCORE
  95. : this(initialCount, maximumCount, name, out createdNew, null)
  96. {
  97. }
  98. [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
  99. [ResourceExposure(ResourceScope.Machine)]
  100. [ResourceConsumption(ResourceScope.Machine)]
  101. public unsafe Semaphore(int initialCount, int maximumCount, string name, out bool createdNew, SemaphoreSecurity semaphoreSecurity)
  102. #endif
  103. {
  104. if (initialCount < 0)
  105. {
  106. throw new ArgumentOutOfRangeException("initialCount", SR.GetString(SR.ArgumentOutOfRange_NeedNonNegNumRequired));
  107. }
  108. if (maximumCount < 1)
  109. {
  110. throw new ArgumentOutOfRangeException("maximumCount", SR.GetString(SR.ArgumentOutOfRange_NeedNonNegNumRequired));
  111. }
  112. if (initialCount > maximumCount)
  113. {
  114. throw new ArgumentException(SR.GetString(SR.Argument_SemaphoreInitialMaximum));
  115. }
  116. if(null != name && MAX_PATH < name.Length)
  117. {
  118. throw new ArgumentException(SR.GetString(SR.Argument_WaitHandleNameTooLong));
  119. }
  120. SafeWaitHandle myHandle;
  121. #if MONO
  122. int errorCode;
  123. myHandle = new SafeWaitHandle (CreateSemaphore_internal (initialCount, maximumCount, name, out errorCode), true);
  124. #else
  125. #if !FEATURE_PAL && !FEATURE_NETCORE
  126. // For ACL's, get the security descriptor from the SemaphoreSecurity.
  127. if (semaphoreSecurity != null) {
  128. NativeMethods.SECURITY_ATTRIBUTES secAttrs = null;
  129. secAttrs = new NativeMethods.SECURITY_ATTRIBUTES();
  130. secAttrs.nLength = (int)Marshal.SizeOf(secAttrs);
  131. byte[] sd = semaphoreSecurity.GetSecurityDescriptorBinaryForm();
  132. fixed(byte* pSecDescriptor = sd) {
  133. secAttrs.lpSecurityDescriptor = new SafeLocalMemHandle((IntPtr) pSecDescriptor, false);
  134. myHandle = SafeNativeMethods.CreateSemaphore(secAttrs, initialCount, maximumCount, name);
  135. }
  136. }
  137. else {
  138. #endif
  139. myHandle = SafeNativeMethods.CreateSemaphore(null, initialCount, maximumCount, name);
  140. #if !FEATURE_PAL && !FEATURE_NETCORE
  141. }
  142. #endif
  143. int errorCode = Marshal.GetLastWin32Error();
  144. #endif
  145. if (myHandle.IsInvalid)
  146. {
  147. if(null != name && 0 != name.Length && NativeMethods.ERROR_INVALID_HANDLE == errorCode)
  148. throw new WaitHandleCannotBeOpenedException(SR.GetString(SR.WaitHandleCannotBeOpenedException_InvalidHandle,name));
  149. #if MONO
  150. InternalResources.WinIOError(errorCode, "");
  151. #else
  152. InternalResources.WinIOError();
  153. #endif
  154. }
  155. createdNew = errorCode != NativeMethods.ERROR_ALREADY_EXISTS;
  156. this.SafeWaitHandle = myHandle;
  157. }
  158. #if FEATURE_NETCORE
  159. [SecurityCritical]
  160. #else
  161. [ResourceExposure(ResourceScope.Machine)]
  162. [ResourceConsumption(ResourceScope.Machine)]
  163. #endif
  164. private Semaphore(SafeWaitHandle handle)
  165. {
  166. this.SafeWaitHandle = handle;
  167. }
  168. #if FEATURE_NETCORE
  169. [SecurityCritical]
  170. #else
  171. [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
  172. [ResourceExposure(ResourceScope.Machine)]
  173. [ResourceConsumption(ResourceScope.Machine)]
  174. #endif
  175. public static Semaphore OpenExisting(string name)
  176. {
  177. #if !FEATURE_PAL && !FEATURE_NETCORE
  178. return OpenExisting(name, SemaphoreRights.Modify | SemaphoreRights.Synchronize);
  179. }
  180. [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
  181. [ResourceExposure(ResourceScope.Machine)]
  182. [ResourceConsumption(ResourceScope.Machine)]
  183. public static Semaphore OpenExisting(string name, SemaphoreRights rights)
  184. {
  185. Semaphore result;
  186. switch (OpenExistingWorker(name, rights, out result))
  187. #else //FEATURE_PAL || FEATURE_NETCORE
  188. Semaphore result;
  189. switch (OpenExistingWorker(name, out result))
  190. #endif //FEATURE_PAL || FEATURE_NETCORE
  191. {
  192. case OpenExistingResult.NameNotFound:
  193. throw new WaitHandleCannotBeOpenedException();
  194. case OpenExistingResult.NameInvalid:
  195. throw new WaitHandleCannotBeOpenedException(SR.GetString(SR.WaitHandleCannotBeOpenedException_InvalidHandle, name));
  196. case OpenExistingResult.PathNotFound:
  197. InternalResources.WinIOError(NativeMethods.ERROR_PATH_NOT_FOUND, string.Empty);
  198. return result; //never executes
  199. default:
  200. return result;
  201. }
  202. }
  203. #if FEATURE_NETCORE
  204. [SecurityCritical]
  205. #else
  206. [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
  207. [ResourceExposure(ResourceScope.Machine)]
  208. [ResourceConsumption(ResourceScope.Machine)]
  209. #endif
  210. public static bool TryOpenExisting(string name, out Semaphore result)
  211. {
  212. #if !FEATURE_PAL && !FEATURE_NETCORE
  213. return OpenExistingWorker(name, SemaphoreRights.Modify | SemaphoreRights.Synchronize, out result) == OpenExistingResult.Success;
  214. #else
  215. return OpenExistingWorker(name, out result) == OpenExistingResult.Success;
  216. #endif
  217. }
  218. #if !FEATURE_PAL && !FEATURE_NETCORE
  219. [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
  220. [ResourceExposure(ResourceScope.Machine)]
  221. [ResourceConsumption(ResourceScope.Machine)]
  222. public static bool TryOpenExisting(string name, SemaphoreRights rights, out Semaphore result)
  223. {
  224. return OpenExistingWorker(name, rights, out result) == OpenExistingResult.Success;
  225. }
  226. #endif
  227. // This exists in WaitHandle, but is oddly ifdefed for some reason...
  228. #if MONO
  229. new
  230. #endif
  231. private enum OpenExistingResult
  232. {
  233. Success,
  234. NameNotFound,
  235. PathNotFound,
  236. NameInvalid
  237. }
  238. #if FEATURE_NETCORE
  239. [SecurityCritical]
  240. #else
  241. [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
  242. [ResourceExposure(ResourceScope.Machine)]
  243. [ResourceConsumption(ResourceScope.Machine)]
  244. #endif
  245. private static OpenExistingResult OpenExistingWorker(
  246. string name,
  247. #if !FEATURE_PAL && !FEATURE_NETCORE
  248. SemaphoreRights rights,
  249. #endif
  250. out Semaphore result)
  251. {
  252. if (name == null)
  253. {
  254. throw new ArgumentNullException("name");
  255. }
  256. if(name.Length == 0)
  257. {
  258. throw new ArgumentException(SR.GetString(SR.InvalidNullEmptyArgument, "name"), "name");
  259. }
  260. if(null != name && MAX_PATH < name.Length)
  261. {
  262. throw new ArgumentException(SR.GetString(SR.Argument_WaitHandleNameTooLong));
  263. }
  264. result = null;
  265. #if MOBILE
  266. throw new NotSupportedException ();
  267. #else
  268. #if MONO
  269. int errorCode;
  270. var myHandle = new SafeWaitHandle (OpenSemaphore_internal (name, rights, out errorCode), true);
  271. #else
  272. //Pass false to OpenSemaphore to prevent inheritedHandles
  273. #if FEATURE_PAL || FEATURE_NETCORE
  274. const int SYNCHRONIZE = 0x00100000;
  275. const int SEMAPHORE_MODIFY_STATE = 0x00000002;
  276. SafeWaitHandle myHandle = SafeNativeMethods.OpenSemaphore(SEMAPHORE_MODIFY_STATE | SYNCHRONIZE, false, name);
  277. #else
  278. SafeWaitHandle myHandle = SafeNativeMethods.OpenSemaphore((int) rights, false, name);
  279. #endif
  280. #endif
  281. if (myHandle.IsInvalid)
  282. {
  283. #if !MONO
  284. int errorCode = Marshal.GetLastWin32Error();
  285. #endif
  286. if (NativeMethods.ERROR_FILE_NOT_FOUND == errorCode || NativeMethods.ERROR_INVALID_NAME == errorCode)
  287. return OpenExistingResult.NameNotFound;
  288. if (NativeMethods.ERROR_PATH_NOT_FOUND == errorCode)
  289. return OpenExistingResult.PathNotFound;
  290. if (null != name && 0 != name.Length && NativeMethods.ERROR_INVALID_HANDLE == errorCode)
  291. return OpenExistingResult.NameInvalid;
  292. //this is for passed through NativeMethods Errors
  293. #if MONO
  294. InternalResources.WinIOError(errorCode, "");
  295. #else
  296. InternalResources.WinIOError();
  297. #endif
  298. }
  299. result = new Semaphore(myHandle);
  300. return OpenExistingResult.Success;
  301. #endif
  302. }
  303. // increase the count on a semaphore, returns previous count
  304. #if !FEATURE_NETCORE
  305. [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  306. [PrePrepareMethod]
  307. #endif
  308. public int Release()
  309. {
  310. return Release(1);
  311. }
  312. // increase the count on a semaphore, returns previous count
  313. #if FEATURE_NETCORE
  314. [SecuritySafeCritical]
  315. #else
  316. [ResourceExposure(ResourceScope.None)]
  317. [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
  318. [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  319. #endif
  320. public int Release(int releaseCount)
  321. {
  322. if (releaseCount < 1)
  323. {
  324. throw new ArgumentOutOfRangeException("releaseCount", SR.GetString(SR.ArgumentOutOfRange_NeedNonNegNumRequired));
  325. }
  326. int previousCount;
  327. //If ReleaseSempahore returns false when the specified value would cause
  328. // the semaphore's count to exceed the maximum count set when Semaphore was created
  329. //Non-Zero return
  330. #if MONO
  331. if (!ReleaseSemaphore_internal(SafeWaitHandle.DangerousGetHandle(), releaseCount, out previousCount))
  332. #else
  333. if (!SafeNativeMethods.ReleaseSemaphore(SafeWaitHandle, releaseCount, out previousCount))
  334. #endif
  335. {
  336. throw new SemaphoreFullException();
  337. }
  338. return previousCount;
  339. }
  340. #if !FEATURE_PAL && !FEATURE_NETCORE
  341. [ResourceExposure(ResourceScope.None)]
  342. [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
  343. public SemaphoreSecurity GetAccessControl() {
  344. return new SemaphoreSecurity(SafeWaitHandle, AccessControlSections.Access | AccessControlSections.Owner | AccessControlSections.Group);
  345. }
  346. [ResourceExposure(ResourceScope.Machine)]
  347. [ResourceConsumption(ResourceScope.Machine)]
  348. public void SetAccessControl(SemaphoreSecurity semaphoreSecurity) {
  349. if (semaphoreSecurity == null)
  350. throw new ArgumentNullException("semaphoreSecurity");
  351. semaphoreSecurity.Persist(SafeWaitHandle);
  352. }
  353. #endif
  354. #if MONO
  355. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  356. internal static extern IntPtr CreateSemaphore_internal (
  357. int initialCount, int maximumCount, string name, out int errorCode);
  358. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  359. internal static extern bool ReleaseSemaphore_internal (
  360. IntPtr handle, int releaseCount, out int previousCount);
  361. [MethodImplAttribute (MethodImplOptions.InternalCall)]
  362. private static extern IntPtr OpenSemaphore_internal (string name, SemaphoreRights rights, out int errorCode);
  363. #endif
  364. }
  365. }