WaitHandle.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. //
  2. // System.Threading.WaitHandle.cs
  3. //
  4. // Author:
  5. // Dick Porter ([email protected])
  6. // Gonzalo Paniagua Javier ([email protected]
  7. //
  8. // (C) 2002,2003 Ximian, Inc. (http://www.ximian.com)
  9. // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
  10. //
  11. // Permission is hereby granted, free of charge, to any person obtaining
  12. // a copy of this software and associated documentation files (the
  13. // "Software"), to deal in the Software without restriction, including
  14. // without limitation the rights to use, copy, modify, merge, publish,
  15. // distribute, sublicense, and/or sell copies of the Software, and to
  16. // permit persons to whom the Software is furnished to do so, subject to
  17. // the following conditions:
  18. //
  19. // The above copyright notice and this permission notice shall be
  20. // included in all copies or substantial portions of the Software.
  21. //
  22. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  23. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  24. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  25. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  26. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  27. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  28. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  29. //
  30. using System;
  31. using System.Reflection;
  32. using System.Runtime.CompilerServices;
  33. using System.Runtime.Remoting.Contexts;
  34. using System.Security.Permissions;
  35. #if NET_2_0
  36. using System.Runtime.InteropServices;
  37. using Microsoft.Win32.SafeHandles;
  38. using System.Runtime.ConstrainedExecution;
  39. #endif
  40. namespace System.Threading
  41. {
  42. #if NET_2_0
  43. [ComVisible (true)]
  44. #endif
  45. public abstract class WaitHandle : MarshalByRefObject, IDisposable
  46. {
  47. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  48. private static extern bool WaitAll_internal(WaitHandle[] handles, int ms, bool exitContext);
  49. static void CheckArray (WaitHandle [] handles, bool waitAll)
  50. {
  51. if (handles == null)
  52. throw new ArgumentNullException ("waitHandles");
  53. int length = handles.Length;
  54. if (length > 64)
  55. throw new NotSupportedException ("Too many handles");
  56. #if false
  57. //
  58. // Although we should thrown an exception if this is an STA thread,
  59. // Mono does not know anything about STA threads, and just makes
  60. // things like Paint.NET not even possible to work.
  61. //
  62. // See bug #78455 for the bug this is supposed to fix.
  63. //
  64. if (waitAll && length > 1 && IsSTAThread)
  65. throw new NotSupportedException ("WaitAll for multiple handles is not allowed on an STA thread.");
  66. #endif
  67. foreach (WaitHandle w in handles) {
  68. if (w == null)
  69. throw new ArgumentNullException ("waitHandles", "null handle");
  70. #if NET_2_0
  71. if (w.safe_wait_handle == null)
  72. throw new ArgumentException ("null element found", "waitHandle");
  73. #else
  74. if (w.os_handle == InvalidHandle)
  75. throw new ArgumentException ("null element found", "waitHandle");
  76. #endif
  77. }
  78. }
  79. static bool IsSTAThread {
  80. get {
  81. bool isSTA = Thread.CurrentThread.ApartmentState ==
  82. ApartmentState.STA;
  83. // FIXME: remove this check after Thread.ApartmentState
  84. // has been properly implemented.
  85. if (!isSTA) {
  86. Assembly asm = Assembly.GetEntryAssembly ();
  87. if (asm != null)
  88. isSTA = asm.EntryPoint.GetCustomAttributes (typeof (STAThreadAttribute), false).Length > 0;
  89. }
  90. return isSTA;
  91. }
  92. }
  93. public static bool WaitAll(WaitHandle[] waitHandles)
  94. {
  95. CheckArray (waitHandles, true);
  96. return(WaitAll_internal(waitHandles, Timeout.Infinite, false));
  97. }
  98. public static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext)
  99. {
  100. CheckArray (waitHandles, true);
  101. try {
  102. if (exitContext) SynchronizationAttribute.ExitContext ();
  103. return(WaitAll_internal(waitHandles, millisecondsTimeout, false));
  104. }
  105. finally {
  106. if (exitContext) SynchronizationAttribute.EnterContext ();
  107. }
  108. }
  109. public static bool WaitAll(WaitHandle[] waitHandles,
  110. TimeSpan timeout,
  111. bool exitContext)
  112. {
  113. CheckArray (waitHandles, true);
  114. long ms = (long) timeout.TotalMilliseconds;
  115. if (ms < -1 || ms > Int32.MaxValue)
  116. throw new ArgumentOutOfRangeException ("timeout");
  117. try {
  118. if (exitContext) SynchronizationAttribute.ExitContext ();
  119. return (WaitAll_internal (waitHandles, (int) ms, exitContext));
  120. }
  121. finally {
  122. if (exitContext) SynchronizationAttribute.EnterContext ();
  123. }
  124. }
  125. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  126. private static extern int WaitAny_internal(WaitHandle[] handles, int ms, bool exitContext);
  127. // LAMESPEC: Doesn't specify how to signal failures
  128. #if NET_2_0
  129. [ReliabilityContract (Consistency.WillNotCorruptState, Cer.MayFail)]
  130. #endif
  131. public static int WaitAny(WaitHandle[] waitHandles)
  132. {
  133. CheckArray (waitHandles, false);
  134. return(WaitAny_internal(waitHandles, Timeout.Infinite, false));
  135. }
  136. #if NET_2_0
  137. [ReliabilityContract (Consistency.WillNotCorruptState, Cer.MayFail)]
  138. #endif
  139. public static int WaitAny(WaitHandle[] waitHandles,
  140. int millisecondsTimeout,
  141. bool exitContext)
  142. {
  143. CheckArray (waitHandles, false);
  144. try {
  145. if (exitContext) SynchronizationAttribute.ExitContext ();
  146. return(WaitAny_internal(waitHandles, millisecondsTimeout, exitContext));
  147. }
  148. finally {
  149. if (exitContext) SynchronizationAttribute.EnterContext ();
  150. }
  151. }
  152. #if NET_2_0
  153. [ReliabilityContract (Consistency.WillNotCorruptState, Cer.MayFail)]
  154. #endif
  155. public static int WaitAny(WaitHandle[] waitHandles,
  156. TimeSpan timeout, bool exitContext)
  157. {
  158. CheckArray (waitHandles, false);
  159. long ms = (long) timeout.TotalMilliseconds;
  160. if (ms < -1 || ms > Int32.MaxValue)
  161. throw new ArgumentOutOfRangeException ("timeout");
  162. try {
  163. if (exitContext) SynchronizationAttribute.ExitContext ();
  164. return (WaitAny_internal(waitHandles, (int) ms, exitContext));
  165. }
  166. finally {
  167. if (exitContext) SynchronizationAttribute.EnterContext ();
  168. }
  169. }
  170. [MonoTODO]
  171. #if NET_2_0
  172. protected
  173. #else
  174. public
  175. #endif
  176. WaitHandle() {
  177. // FIXME
  178. }
  179. public virtual void Close() {
  180. Dispose(true);
  181. GC.SuppressFinalize (this);
  182. }
  183. public const int WaitTimeout = 258;
  184. #if NET_2_0
  185. //
  186. // In 2.0 we use SafeWaitHandles instead of IntPtrs
  187. //
  188. SafeWaitHandle safe_wait_handle;
  189. [Obsolete ("In the profiles > 2.x, use SafeHandle instead of Handle")]
  190. public virtual IntPtr Handle {
  191. get {
  192. return safe_wait_handle.DangerousGetHandle ();
  193. }
  194. [SecurityPermission (SecurityAction.LinkDemand, UnmanagedCode = true)]
  195. [SecurityPermission (SecurityAction.InheritanceDemand, UnmanagedCode = true)]
  196. set {
  197. //
  198. // Notice, from the 2.x documentation:
  199. // Assigning a new value to the Handle property, will not release
  200. // the previous handle, this could lead to a leak
  201. //
  202. safe_wait_handle = new SafeWaitHandle (value, false);
  203. }
  204. }
  205. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  206. private extern bool WaitOne_internal(IntPtr handle, int ms, bool exitContext);
  207. protected virtual void Dispose (bool explicitDisposing)
  208. {
  209. if (!disposed){
  210. disposed = true;
  211. //
  212. // This is only the case if the handle was never properly initialized
  213. // most likely a but in the derived class
  214. //
  215. if (safe_wait_handle == null)
  216. return;
  217. lock (this){
  218. if (safe_wait_handle != null)
  219. safe_wait_handle.Dispose ();
  220. }
  221. }
  222. }
  223. public SafeWaitHandle SafeWaitHandle {
  224. [ReliabilityContract (Consistency.WillNotCorruptState, Cer.MayFail)]
  225. get {
  226. return safe_wait_handle;
  227. }
  228. [ReliabilityContract (Consistency.WillNotCorruptState, Cer.Success)]
  229. set {
  230. if (safe_wait_handle != null)
  231. safe_wait_handle.Close ();
  232. safe_wait_handle = value;
  233. }
  234. }
  235. public static bool SignalAndWait (WaitHandle toSignal,
  236. WaitHandle toWaitOn)
  237. {
  238. throw new NotImplementedException ();
  239. }
  240. public static bool SignalAndWait (WaitHandle toSignal,
  241. WaitHandle toWaitOn,
  242. int millisecondsTimeout,
  243. bool exitContext)
  244. {
  245. throw new NotImplementedException ();
  246. }
  247. public static bool SignalAndWait (WaitHandle toSignal,
  248. WaitHandle toWaitOn,
  249. TimeSpan timeout,
  250. bool exitContext)
  251. {
  252. throw new NotImplementedException ();
  253. }
  254. public virtual bool WaitOne()
  255. {
  256. CheckDisposed ();
  257. bool release = false;
  258. try {
  259. safe_wait_handle.DangerousAddRef (ref release);
  260. return (WaitOne_internal(safe_wait_handle.DangerousGetHandle (), Timeout.Infinite, false));
  261. } finally {
  262. if (release)
  263. safe_wait_handle.DangerousRelease ();
  264. }
  265. }
  266. public virtual bool WaitOne(int millisecondsTimeout, bool exitContext)
  267. {
  268. CheckDisposed ();
  269. bool release = false;
  270. try {
  271. if (exitContext)
  272. SynchronizationAttribute.ExitContext ();
  273. safe_wait_handle.DangerousAddRef (ref release);
  274. return (WaitOne_internal(safe_wait_handle.DangerousGetHandle (), millisecondsTimeout, exitContext));
  275. } finally {
  276. if (exitContext)
  277. SynchronizationAttribute.EnterContext ();
  278. if (release)
  279. safe_wait_handle.DangerousRelease ();
  280. }
  281. }
  282. public virtual bool WaitOne(TimeSpan timeout, bool exitContext)
  283. {
  284. CheckDisposed ();
  285. long ms = (long) timeout.TotalMilliseconds;
  286. if (ms < -1 || ms > Int32.MaxValue)
  287. throw new ArgumentOutOfRangeException ("timeout");
  288. bool release = false;
  289. try {
  290. if (exitContext)
  291. SynchronizationAttribute.ExitContext ();
  292. safe_wait_handle.DangerousAddRef (ref release);
  293. return (WaitOne_internal(safe_wait_handle.DangerousGetHandle (), (int) ms, exitContext));
  294. }
  295. finally {
  296. if (exitContext)
  297. SynchronizationAttribute.EnterContext ();
  298. if (release)
  299. safe_wait_handle.DangerousRelease ();
  300. }
  301. }
  302. internal void CheckDisposed ()
  303. {
  304. if (disposed || safe_wait_handle == null)
  305. throw new ObjectDisposedException (GetType ().FullName);
  306. }
  307. #else
  308. private IntPtr os_handle = InvalidHandle;
  309. public virtual IntPtr Handle {
  310. get {
  311. return(os_handle);
  312. }
  313. [SecurityPermission (SecurityAction.LinkDemand, UnmanagedCode = true)]
  314. [SecurityPermission (SecurityAction.InheritanceDemand, UnmanagedCode = true)]
  315. set {
  316. os_handle=value;
  317. }
  318. }
  319. internal void CheckDisposed ()
  320. {
  321. if (disposed || os_handle == InvalidHandle)
  322. throw new ObjectDisposedException (GetType ().FullName);
  323. }
  324. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  325. private extern bool WaitOne_internal(IntPtr handle, int ms, bool exitContext);
  326. protected virtual void Dispose(bool explicitDisposing) {
  327. // Check to see if Dispose has already been called.
  328. if (!disposed) {
  329. disposed=true;
  330. if (os_handle == InvalidHandle)
  331. return;
  332. lock (this) {
  333. if (os_handle != InvalidHandle) {
  334. NativeEventCalls.CloseEvent_internal (os_handle);
  335. os_handle = InvalidHandle;
  336. }
  337. }
  338. }
  339. }
  340. public virtual bool WaitOne()
  341. {
  342. CheckDisposed ();
  343. return(WaitOne_internal(os_handle, Timeout.Infinite, false));
  344. }
  345. public virtual bool WaitOne(int millisecondsTimeout, bool exitContext)
  346. {
  347. CheckDisposed ();
  348. try {
  349. if (exitContext) SynchronizationAttribute.ExitContext ();
  350. return(WaitOne_internal(os_handle, millisecondsTimeout, exitContext));
  351. }
  352. finally {
  353. if (exitContext) SynchronizationAttribute.EnterContext ();
  354. }
  355. }
  356. public virtual bool WaitOne(TimeSpan timeout, bool exitContext)
  357. {
  358. CheckDisposed ();
  359. long ms = (long) timeout.TotalMilliseconds;
  360. if (ms < -1 || ms > Int32.MaxValue)
  361. throw new ArgumentOutOfRangeException ("timeout");
  362. try {
  363. if (exitContext) SynchronizationAttribute.ExitContext ();
  364. return (WaitOne_internal(os_handle, (int) ms, exitContext));
  365. }
  366. finally {
  367. if (exitContext) SynchronizationAttribute.EnterContext ();
  368. }
  369. }
  370. #endif
  371. protected static readonly IntPtr InvalidHandle = IntPtr.Zero;
  372. bool disposed = false;
  373. void IDisposable.Dispose() {
  374. Dispose(true);
  375. // Take yourself off the Finalization queue
  376. GC.SuppressFinalize(this);
  377. }
  378. ~WaitHandle() {
  379. Dispose(false);
  380. }
  381. }
  382. }