X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2Fcorlib%2FSystem.Threading%2FWaitHandle.cs;h=81ee13c76d24e3fe77a088857dff8ba1085cde65;hb=83dccf8fe7cf27e92061daec886e235ce6c7c57b;hp=cc80b77bc412486f94669dd4468b81d053ac923b;hpb=f84f760a1c8a8c0ec6ae16b7f38d14a49d329ad7;p=mono.git diff --git a/mcs/class/corlib/System.Threading/WaitHandle.cs b/mcs/class/corlib/System.Threading/WaitHandle.cs index cc80b77bc41..81ee13c76d2 100644 --- a/mcs/class/corlib/System.Threading/WaitHandle.cs +++ b/mcs/class/corlib/System.Threading/WaitHandle.cs @@ -33,10 +33,20 @@ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Remoting.Contexts; using System.Security.Permissions; +using System.Runtime.InteropServices; +using Microsoft.Win32.SafeHandles; +using System.Runtime.ConstrainedExecution; namespace System.Threading { - public abstract class WaitHandle : MarshalByRefObject, IDisposable + [ComVisible (true)] + [StructLayout (LayoutKind.Sequential)] + public abstract class WaitHandle +#if MOONLIGHT + : IDisposable +#else + : MarshalByRefObject, IDisposable +#endif { [MethodImplAttribute(MethodImplOptions.InternalCall)] private static extern bool WaitAll_internal(WaitHandle[] handles, int ms, bool exitContext); @@ -50,20 +60,53 @@ namespace System.Threading if (length > 64) throw new NotSupportedException ("Too many handles"); - if (waitAll && length > 1 && - (Thread.CurrentThread.ApartmentState == ApartmentState.STA || - Assembly.GetEntryAssembly ().EntryPoint.GetCustomAttributes (typeof (STAThreadAttribute), false).Length == 1)) + if (handles.Length == 0) { + // MS throws different exceptions from the different methods. + if (waitAll) + throw new ArgumentNullException ("waitHandles"); + else + throw new ArgumentException (); + } + +#if false + // + // Although we should thrown an exception if this is an STA thread, + // Mono does not know anything about STA threads, and just makes + // things like Paint.NET not even possible to work. + // + // See bug #78455 for the bug this is supposed to fix. + // + if (waitAll && length > 1 && IsSTAThread) throw new NotSupportedException ("WaitAll for multiple handles is not allowed on an STA thread."); - +#endif foreach (WaitHandle w in handles) { if (w == null) throw new ArgumentNullException ("waitHandles", "null handle"); - if (w.os_handle == InvalidHandle) + if (w.safe_wait_handle == null) throw new ArgumentException ("null element found", "waitHandle"); + } } - +#if false + // usage of property is commented - see above + static bool IsSTAThread { + get { + bool isSTA = Thread.CurrentThread.ApartmentState == + ApartmentState.STA; + + // FIXME: remove this check after Thread.ApartmentState + // has been properly implemented. + if (!isSTA) { + Assembly asm = Assembly.GetEntryAssembly (); + if (asm != null) + isSTA = asm.EntryPoint.GetCustomAttributes (typeof (STAThreadAttribute), false).Length > 0; + } + + return isSTA; + } + } +#endif public static bool WaitAll(WaitHandle[] waitHandles) { CheckArray (waitHandles, true); @@ -73,8 +116,18 @@ namespace System.Threading public static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext) { CheckArray (waitHandles, true); + // check negative - except for -1 (which is Timeout.Infinite) + if (millisecondsTimeout < Timeout.Infinite) + throw new ArgumentOutOfRangeException ("millisecondsTimeout"); + try { - if (exitContext) SynchronizationAttribute.ExitContext (); + if (exitContext) { +#if MONOTOUCH + throw new NotSupportedException ("exitContext == true is not supported"); +#else + SynchronizationAttribute.ExitContext (); +#endif + } return(WaitAll_internal(waitHandles, millisecondsTimeout, false)); } finally { @@ -93,7 +146,13 @@ namespace System.Threading throw new ArgumentOutOfRangeException ("timeout"); try { - if (exitContext) SynchronizationAttribute.ExitContext (); + if (exitContext) { +#if MONOTOUCH + throw new NotSupportedException ("exitContext == true is not supported"); +#else + SynchronizationAttribute.ExitContext (); +#endif + } return (WaitAll_internal (waitHandles, (int) ms, exitContext)); } finally { @@ -105,19 +164,31 @@ namespace System.Threading private static extern int WaitAny_internal(WaitHandle[] handles, int ms, bool exitContext); // LAMESPEC: Doesn't specify how to signal failures + [ReliabilityContract (Consistency.WillNotCorruptState, Cer.MayFail)] public static int WaitAny(WaitHandle[] waitHandles) { CheckArray (waitHandles, false); return(WaitAny_internal(waitHandles, Timeout.Infinite, false)); } + [ReliabilityContract (Consistency.WillNotCorruptState, Cer.MayFail)] public static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext) { CheckArray (waitHandles, false); + // check negative - except for -1 (which is Timeout.Infinite) + if (millisecondsTimeout < Timeout.Infinite) + throw new ArgumentOutOfRangeException ("millisecondsTimeout"); + try { - if (exitContext) SynchronizationAttribute.ExitContext (); + if (exitContext) { +#if MONOTOUCH + throw new NotSupportedException ("exitContext == true is not supported"); +#else + SynchronizationAttribute.ExitContext (); +#endif + } return(WaitAny_internal(waitHandles, millisecondsTimeout, exitContext)); } finally { @@ -125,6 +196,19 @@ namespace System.Threading } } + [ReliabilityContract (Consistency.WillNotCorruptState, Cer.MayFail)] + public static int WaitAny(WaitHandle[] waitHandles, TimeSpan timeout) + { + return WaitAny (waitHandles, timeout, false); + } + + [ReliabilityContract (Consistency.WillNotCorruptState, Cer.MayFail)] + public static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout) + { + return WaitAny (waitHandles, millisecondsTimeout, false); + } + + [ReliabilityContract (Consistency.WillNotCorruptState, Cer.MayFail)] public static int WaitAny(WaitHandle[] waitHandles, TimeSpan timeout, bool exitContext) { @@ -135,7 +219,13 @@ namespace System.Threading throw new ArgumentOutOfRangeException ("timeout"); try { - if (exitContext) SynchronizationAttribute.ExitContext (); + if (exitContext) { +#if MONOTOUCH + throw new NotSupportedException ("exitContext == true is not supported"); +#else + SynchronizationAttribute.ExitContext (); +#endif + } return (WaitAny_internal(waitHandles, (int) ms, exitContext)); } finally { @@ -143,59 +233,174 @@ namespace System.Threading } } - [MonoTODO] - public WaitHandle() { + protected WaitHandle() + { // FIXME } + public virtual void Close () + { + Dispose(true); + } + +#if NET_4_0 || MOBILE || MOONLIGHT + public void Dispose () +#else + void IDisposable.Dispose () +#endif + { + Close (); + } + public const int WaitTimeout = 258; - private IntPtr os_handle = InvalidHandle; - + // + // In 2.0 we use SafeWaitHandles instead of IntPtrs + // + SafeWaitHandle safe_wait_handle; + + [Obsolete ("In the profiles > 2.x, use SafeHandle instead of Handle")] public virtual IntPtr Handle { get { - return(os_handle); + return safe_wait_handle.DangerousGetHandle (); } - + [SecurityPermission (SecurityAction.LinkDemand, UnmanagedCode = true)] [SecurityPermission (SecurityAction.InheritanceDemand, UnmanagedCode = true)] set { - os_handle=value; + if (value == InvalidHandle) + safe_wait_handle = new SafeWaitHandle (InvalidHandle, false); + else + safe_wait_handle = new SafeWaitHandle (value, true); } } + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + private extern bool WaitOne_internal(IntPtr handle, int ms, bool exitContext); - public virtual void Close() { - Dispose(true); - GC.SuppressFinalize (this); + protected virtual void Dispose (bool explicitDisposing) + { + if (!disposed){ + + // + // This is only the case if the handle was never properly initialized + // most likely a bug in the derived class + // + if (safe_wait_handle == null) + return; + + lock (this){ + if (disposed) + return; + + disposed = true; + if (safe_wait_handle != null) + safe_wait_handle.Dispose (); + } + } } - internal void CheckDisposed () + public SafeWaitHandle SafeWaitHandle { + [ReliabilityContract (Consistency.WillNotCorruptState, Cer.MayFail)] + get { + return safe_wait_handle; + } + + [ReliabilityContract (Consistency.WillNotCorruptState, Cer.Success)] + set { + if (value == null) + safe_wait_handle = new SafeWaitHandle (InvalidHandle, false); + else + safe_wait_handle = value; + } + } + + public static bool SignalAndWait (WaitHandle toSignal, + WaitHandle toWaitOn) { - if (disposed || os_handle == InvalidHandle) - throw new ObjectDisposedException (GetType ().FullName); + return SignalAndWait (toSignal, toWaitOn, -1, false); } + public static bool SignalAndWait (WaitHandle toSignal, + WaitHandle toWaitOn, + int millisecondsTimeout, + bool exitContext) + { + if (toSignal == null) + throw new ArgumentNullException ("toSignal"); + if (toWaitOn == null) + throw new ArgumentNullException ("toWaitOn"); + + if (millisecondsTimeout < -1) + throw new ArgumentOutOfRangeException ("millisecondsTimeout"); + + return SignalAndWait_Internal (toSignal.Handle, toWaitOn.Handle, millisecondsTimeout, exitContext); + } + + public static bool SignalAndWait (WaitHandle toSignal, + WaitHandle toWaitOn, + TimeSpan timeout, + bool exitContext) + { + double ms = timeout.TotalMilliseconds; + if (ms > Int32.MaxValue) + throw new ArgumentOutOfRangeException ("timeout"); + + return SignalAndWait (toSignal, toWaitOn, Convert.ToInt32 (ms), false); + } + [MethodImplAttribute(MethodImplOptions.InternalCall)] - private extern bool WaitOne_internal(IntPtr handle, int ms, bool exitContext); + static extern bool SignalAndWait_Internal (IntPtr toSignal, IntPtr toWaitOn, int ms, bool exitContext); public virtual bool WaitOne() { CheckDisposed (); - return(WaitOne_internal(os_handle, Timeout.Infinite, false)); + bool release = false; + try { + safe_wait_handle.DangerousAddRef (ref release); + return (WaitOne_internal(safe_wait_handle.DangerousGetHandle (), Timeout.Infinite, false)); + } finally { + if (release) + safe_wait_handle.DangerousRelease (); + } } public virtual bool WaitOne(int millisecondsTimeout, bool exitContext) { CheckDisposed (); + // check negative - except for -1 (which is Timeout.Infinite) + if (millisecondsTimeout < Timeout.Infinite) + throw new ArgumentOutOfRangeException ("millisecondsTimeout"); + + bool release = false; try { - if (exitContext) SynchronizationAttribute.ExitContext (); - return(WaitOne_internal(os_handle, millisecondsTimeout, exitContext)); - } - finally { - if (exitContext) SynchronizationAttribute.EnterContext (); + if (exitContext) { +#if MONOTOUCH + throw new NotSupportedException ("exitContext == true is not supported"); +#else + SynchronizationAttribute.ExitContext (); +#endif + } + safe_wait_handle.DangerousAddRef (ref release); + return (WaitOne_internal(safe_wait_handle.DangerousGetHandle (), millisecondsTimeout, exitContext)); + } finally { + if (exitContext) + SynchronizationAttribute.EnterContext (); + if (release) + safe_wait_handle.DangerousRelease (); } } + public virtual bool WaitOne (int millisecondsTimeout) + { + return WaitOne (millisecondsTimeout, false); + } + + public virtual bool WaitOne (TimeSpan timeout) + { + return WaitOne (timeout, false); + } + public virtual bool WaitOne(TimeSpan timeout, bool exitContext) { CheckDisposed (); @@ -203,43 +408,43 @@ namespace System.Threading if (ms < -1 || ms > Int32.MaxValue) throw new ArgumentOutOfRangeException ("timeout"); + bool release = false; try { - if (exitContext) SynchronizationAttribute.ExitContext (); - return (WaitOne_internal(os_handle, (int) ms, exitContext)); + if (exitContext) { +#if MONOTOUCH + throw new NotSupportedException ("exitContext == true is not supported"); +#else + SynchronizationAttribute.ExitContext (); +#endif + } + safe_wait_handle.DangerousAddRef (ref release); + return (WaitOne_internal(safe_wait_handle.DangerousGetHandle (), (int) ms, exitContext)); } finally { - if (exitContext) SynchronizationAttribute.EnterContext (); + if (exitContext) + SynchronizationAttribute.EnterContext (); + if (release) + safe_wait_handle.DangerousRelease (); } } - protected static readonly IntPtr InvalidHandle = IntPtr.Zero; - - bool disposed = false; - - void IDisposable.Dispose() { - Dispose(true); - // Take yourself off the Finalization queue - GC.SuppressFinalize(this); + internal void CheckDisposed () + { + if (disposed || safe_wait_handle == null) + throw new ObjectDisposedException (GetType ().FullName); } - - protected virtual void Dispose(bool explicitDisposing) { - // Check to see if Dispose has already been called. - if (!disposed) { - disposed=true; - if (os_handle == InvalidHandle) - return; - lock (this) { - if (os_handle != InvalidHandle) { - NativeEventCalls.CloseEvent_internal (os_handle); - os_handle = InvalidHandle; - } - } - } + public static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout) + { + return WaitAll (waitHandles, millisecondsTimeout, false); } - ~WaitHandle() { - Dispose(false); + public static bool WaitAll(WaitHandle[] waitHandles, TimeSpan timeout) + { + return WaitAll (waitHandles, timeout, false); } + + protected static readonly IntPtr InvalidHandle = (IntPtr) (-1); + bool disposed = false; } }