WaitHandle.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  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. if (value == InvalidHandle)
  198. safe_wait_handle = new SafeWaitHandle (InvalidHandle, false);
  199. else
  200. safe_wait_handle = new SafeWaitHandle (value, true);
  201. }
  202. }
  203. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  204. private extern bool WaitOne_internal(IntPtr handle, int ms, bool exitContext);
  205. protected virtual void Dispose (bool explicitDisposing)
  206. {
  207. if (!disposed){
  208. disposed = true;
  209. //
  210. // This is only the case if the handle was never properly initialized
  211. // most likely a bug in the derived class
  212. //
  213. if (safe_wait_handle == null)
  214. return;
  215. lock (this){
  216. if (safe_wait_handle != null)
  217. safe_wait_handle.Dispose ();
  218. }
  219. }
  220. }
  221. public SafeWaitHandle SafeWaitHandle {
  222. [ReliabilityContract (Consistency.WillNotCorruptState, Cer.MayFail)]
  223. get {
  224. return safe_wait_handle;
  225. }
  226. [ReliabilityContract (Consistency.WillNotCorruptState, Cer.Success)]
  227. set {
  228. if (value == null)
  229. safe_wait_handle = new SafeWaitHandle (InvalidHandle, false);
  230. else
  231. safe_wait_handle = value;
  232. }
  233. }
  234. [MonoTODO]
  235. public static bool SignalAndWait (WaitHandle toSignal,
  236. WaitHandle toWaitOn)
  237. {
  238. throw new NotImplementedException ();
  239. }
  240. [MonoTODO]
  241. public static bool SignalAndWait (WaitHandle toSignal,
  242. WaitHandle toWaitOn,
  243. int millisecondsTimeout,
  244. bool exitContext)
  245. {
  246. throw new NotImplementedException ();
  247. }
  248. [MonoTODO]
  249. public static bool SignalAndWait (WaitHandle toSignal,
  250. WaitHandle toWaitOn,
  251. TimeSpan timeout,
  252. bool exitContext)
  253. {
  254. throw new NotImplementedException ();
  255. }
  256. public virtual bool WaitOne()
  257. {
  258. CheckDisposed ();
  259. bool release = false;
  260. try {
  261. safe_wait_handle.DangerousAddRef (ref release);
  262. return (WaitOne_internal(safe_wait_handle.DangerousGetHandle (), Timeout.Infinite, false));
  263. } finally {
  264. if (release)
  265. safe_wait_handle.DangerousRelease ();
  266. }
  267. }
  268. public virtual bool WaitOne(int millisecondsTimeout, bool exitContext)
  269. {
  270. CheckDisposed ();
  271. bool release = false;
  272. try {
  273. if (exitContext)
  274. SynchronizationAttribute.ExitContext ();
  275. safe_wait_handle.DangerousAddRef (ref release);
  276. return (WaitOne_internal(safe_wait_handle.DangerousGetHandle (), millisecondsTimeout, exitContext));
  277. } finally {
  278. if (exitContext)
  279. SynchronizationAttribute.EnterContext ();
  280. if (release)
  281. safe_wait_handle.DangerousRelease ();
  282. }
  283. }
  284. public virtual bool WaitOne(TimeSpan timeout, bool exitContext)
  285. {
  286. CheckDisposed ();
  287. long ms = (long) timeout.TotalMilliseconds;
  288. if (ms < -1 || ms > Int32.MaxValue)
  289. throw new ArgumentOutOfRangeException ("timeout");
  290. bool release = false;
  291. try {
  292. if (exitContext)
  293. SynchronizationAttribute.ExitContext ();
  294. safe_wait_handle.DangerousAddRef (ref release);
  295. return (WaitOne_internal(safe_wait_handle.DangerousGetHandle (), (int) ms, exitContext));
  296. }
  297. finally {
  298. if (exitContext)
  299. SynchronizationAttribute.EnterContext ();
  300. if (release)
  301. safe_wait_handle.DangerousRelease ();
  302. }
  303. }
  304. internal void CheckDisposed ()
  305. {
  306. if (disposed || safe_wait_handle == null)
  307. throw new ObjectDisposedException (GetType ().FullName);
  308. }
  309. #else
  310. private IntPtr os_handle = InvalidHandle;
  311. public virtual IntPtr Handle {
  312. get {
  313. return(os_handle);
  314. }
  315. [SecurityPermission (SecurityAction.LinkDemand, UnmanagedCode = true)]
  316. [SecurityPermission (SecurityAction.InheritanceDemand, UnmanagedCode = true)]
  317. set {
  318. os_handle=value;
  319. }
  320. }
  321. internal void CheckDisposed ()
  322. {
  323. if (disposed || os_handle == InvalidHandle)
  324. throw new ObjectDisposedException (GetType ().FullName);
  325. }
  326. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  327. private extern bool WaitOne_internal(IntPtr handle, int ms, bool exitContext);
  328. protected virtual void Dispose(bool explicitDisposing) {
  329. // Check to see if Dispose has already been called.
  330. if (!disposed) {
  331. disposed=true;
  332. if (os_handle == InvalidHandle)
  333. return;
  334. lock (this) {
  335. if (os_handle != InvalidHandle) {
  336. NativeEventCalls.CloseEvent_internal (os_handle);
  337. os_handle = InvalidHandle;
  338. }
  339. }
  340. }
  341. }
  342. public virtual bool WaitOne()
  343. {
  344. CheckDisposed ();
  345. return(WaitOne_internal(os_handle, Timeout.Infinite, false));
  346. }
  347. public virtual bool WaitOne(int millisecondsTimeout, bool exitContext)
  348. {
  349. CheckDisposed ();
  350. try {
  351. if (exitContext) SynchronizationAttribute.ExitContext ();
  352. return(WaitOne_internal(os_handle, millisecondsTimeout, exitContext));
  353. }
  354. finally {
  355. if (exitContext) SynchronizationAttribute.EnterContext ();
  356. }
  357. }
  358. public virtual bool WaitOne(TimeSpan timeout, bool exitContext)
  359. {
  360. CheckDisposed ();
  361. long ms = (long) timeout.TotalMilliseconds;
  362. if (ms < -1 || ms > Int32.MaxValue)
  363. throw new ArgumentOutOfRangeException ("timeout");
  364. try {
  365. if (exitContext) SynchronizationAttribute.ExitContext ();
  366. return (WaitOne_internal(os_handle, (int) ms, exitContext));
  367. }
  368. finally {
  369. if (exitContext) SynchronizationAttribute.EnterContext ();
  370. }
  371. }
  372. #endif
  373. protected static readonly IntPtr InvalidHandle = (IntPtr) (-1);
  374. bool disposed = false;
  375. void IDisposable.Dispose() {
  376. Dispose(true);
  377. // Take yourself off the Finalization queue
  378. GC.SuppressFinalize(this);
  379. }
  380. ~WaitHandle() {
  381. Dispose(false);
  382. }
  383. }
  384. }