Warnings cleanup
[mono.git] / mcs / class / corlib / System.Threading / Thread.cs
index bbf713df83d3c5ed227e0efcf0cc0e31743deabd..a1e44a48687c96ef299957aa37fc8404f37c9795 100644 (file)
@@ -54,6 +54,7 @@ namespace System.Threading {
        public sealed class Thread : _Thread {
 #endif
 
+#pragma warning disable 169, 414, 649
                #region Sync with metadata/object-internals.h
                int lock_thread_id;
                // stores a thread handle
@@ -84,29 +85,35 @@ namespace System.Threading {
                int stack_size;
                object start_obj;
                private IntPtr appdomain_refs;
-               private bool interruption_requested;
+               private int interruption_requested;
                private IntPtr suspend_event;
                private IntPtr suspended_event;
                private IntPtr resume_event;
-               /* Don't lock on synch_lock in managed code, since it can result in deadlocks */
-               private object synch_lock = new Object();
+               private IntPtr synch_cs;
                private IntPtr serialized_culture_info;
                private int serialized_culture_info_len;
                private IntPtr serialized_ui_culture_info;
                private int serialized_ui_culture_info_len;
                private ExecutionContext _ec;
+               private bool thread_dump_requested;
+               private IntPtr end_stack;
+               private bool thread_interrupt_requested;
+               private byte apartment_state = (byte)ApartmentState.Unknown;
+               volatile int critical_region_level;
+               private int small_id;
+               private IntPtr manage_callback;
+               private object pending_exception;
                /* 
                 * These fields are used to avoid having to increment corlib versions
                 * when a new field is added to the unmanaged MonoThread structure.
                 */
-               private IntPtr unused1;
                private IntPtr unused2;
                private IntPtr unused3;
                private IntPtr unused4;
                private IntPtr unused5;
                private IntPtr unused6;
-               private IntPtr unused7;
                #endregion
+#pragma warning restore 169, 414, 649
 
                // the name of local_slots is important as it's used by the runtime.
                [ThreadStatic] 
@@ -114,9 +121,15 @@ namespace System.Threading {
 
                // can be both a ThreadSart and a ParameterizedThreadStart
                private MulticastDelegate threadstart;
-               private string thread_name=null;
+               //private string thread_name=null;
+
+#if NET_2_0            
+               private static int _managed_id_counter;
+               private int managed_id;
+#endif         
                
                private IPrincipal _principal;
+               internal NumberFormatter _numberFormatter;
 
                public static Context CurrentContext {
                        [SecurityPermission (SecurityAction.LinkDemand, Infrastructure=true)]
@@ -235,6 +248,18 @@ namespace System.Threading {
                        slots [slot.slot] = data;
                }
 
+               internal NumberFormatter AcquireNumberFormatter() {
+                       NumberFormatter res = _numberFormatter;
+                       _numberFormatter = null;
+                       if (res == null)
+                               return new NumberFormatter (this);
+                       return res;
+               }
+
+               internal void ReleaseNumberFormatter (NumberFormatter formatter) {
+                       _numberFormatter = formatter;
+               }
+
                public static AppDomain GetDomain() {
                        return AppDomain.CurrentDomain;
                }
@@ -293,11 +318,16 @@ namespace System.Threading {
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
                private extern IntPtr Thread_internal (MulticastDelegate start);
 
+               [MethodImplAttribute(MethodImplOptions.InternalCall)]
+               private extern void Thread_init ();
+
                public Thread(ThreadStart start) {
                        if(start==null) {
                                throw new ArgumentNullException("Null ThreadStart");
                        }
                        threadstart=start;
+
+                       Thread_init ();
                }
 
 #if NET_2_0
@@ -305,16 +335,35 @@ namespace System.Threading {
 #endif
                public ApartmentState ApartmentState {
                        get {
-                               return(ApartmentState.Unknown);
+                               if ((ThreadState & ThreadState.Stopped) != 0)
+                                       throw new ThreadStateException ("Thread is dead; state can not be accessed.");
+
+                               return (ApartmentState)apartment_state;
                        }
-                       
-                       set {
-                               // FIXME: Implement setter.
+
+                       set     {
+#if NET_2_0
+                               TrySetApartmentState (value);
+#else
+                               /* Only throw this exception when
+                                * changing the state of another
+                                * thread.  See bug 324338
+                                */
+                               if ((this != CurrentThread) &&
+                                   (ThreadState & ThreadState.Unstarted) == 0)
+                                       throw new ThreadStateException ("Thread was in an invalid state for the operation being executed.");
+
+                               if (value != ApartmentState.STA && value != ApartmentState.MTA)
+                                       throw new ArgumentOutOfRangeException ("value is not a valid apartment state.");
+
+                               if ((ApartmentState)apartment_state == ApartmentState.Unknown)
+                                       apartment_state = (byte)value;
+#endif
                        }
                }
 
-               [MethodImplAttribute (MethodImplOptions.InternalCall)]
-               private static extern int current_lcid ();
+               //[MethodImplAttribute (MethodImplOptions.InternalCall)]
+               //private static extern int current_lcid ();
 
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
                private extern CultureInfo GetCachedCurrentCulture ();
@@ -346,7 +395,7 @@ namespace System.Threading {
                 * CurrentCulture, which will throw an exception, etc.
                 * Use a boolean to short-circuit this scenario.
                 */
-               private static bool in_currentculture=false;
+               private bool in_currentculture=false;
 
                static object culture_lock = new object ();
                
@@ -381,6 +430,8 @@ namespace System.Threading {
                                                //
                                                SetCachedCurrentCulture (culture);
                                                in_currentculture = false;
+                                               if (_numberFormatter != null)
+                                                       _numberFormatter.CurrentCulture = culture;
                                                return culture;
                                        }
                                }
@@ -399,6 +450,8 @@ namespace System.Threading {
                                        in_currentculture = false;
                                }
 
+                               if (_numberFormatter != null)
+                                       _numberFormatter.CurrentCulture = culture;
                                return culture;
                        }
                        
@@ -407,18 +460,35 @@ namespace System.Threading {
                                if (value == null)
                                        throw new ArgumentNullException ("value");
 
+                               CultureInfo culture = GetCachedCurrentCulture ();
+                               if (culture == value)
+                                       return;
+
                                value.CheckNeutral ();
                                in_currentculture = true;
                                try {
-                                       BinaryFormatter bf = new BinaryFormatter();
-                                       MemoryStream ms = new MemoryStream ();
-                                       bf.Serialize (ms, value);
-
                                        SetCachedCurrentCulture (value);
-                                       SetSerializedCurrentCulture (ms.GetBuffer ());
+
+                                       byte[] serialized_form = null;
+
+                                       if (value.IsReadOnly && value.cached_serialized_form != null) {
+                                               serialized_form = value.cached_serialized_form;
+                                       } else {
+                                               BinaryFormatter bf = new BinaryFormatter();
+                                               MemoryStream ms = new MemoryStream ();
+                                               bf.Serialize (ms, value);
+
+                                               serialized_form = ms.GetBuffer ();
+                                               if (value.IsReadOnly)
+                                                       value.cached_serialized_form = serialized_form;
+                                       }
+                                               
+                                       SetSerializedCurrentCulture (serialized_form);
                                } finally {
                                        in_currentculture = false;
                                }
+                               if (_numberFormatter != null)
+                                       _numberFormatter.CurrentCulture = value;
                        }
                }
 
@@ -478,13 +548,28 @@ namespace System.Threading {
                                if (value == null)
                                        throw new ArgumentNullException ("value");
 
-                               try {
-                                       BinaryFormatter bf = new BinaryFormatter();
-                                       MemoryStream ms = new MemoryStream ();
-                                       bf.Serialize (ms, value);
+                               CultureInfo culture = GetCachedCurrentUICulture ();
+                               if (culture == value)
+                                       return;
 
+                               try {
                                        SetCachedCurrentUICulture (value);
-                                       SetSerializedCurrentUICulture (ms.GetBuffer ());
+
+                                       byte[] serialized_form = null;
+
+                                       if (value.IsReadOnly && value.cached_serialized_form != null) {
+                                               serialized_form = value.cached_serialized_form;
+                                       } else {
+                                               BinaryFormatter bf = new BinaryFormatter();
+                                               MemoryStream ms = new MemoryStream ();
+                                               bf.Serialize (ms, value);
+
+                                               serialized_form = ms.GetBuffer ();
+                                               if (value.IsReadOnly)
+                                                       value.cached_serialized_form = serialized_form;
+                                       }
+                                               
+                                       SetSerializedCurrentUICulture (serialized_form);
                                } finally {
                                        in_currentculture = false;
                                }
@@ -522,7 +607,11 @@ namespace System.Threading {
 
                public bool IsBackground {
                        get {
-                               return (GetState () & ThreadState.Background) != 0;
+                               ThreadState thread_state = GetState ();
+                               if ((thread_state & ThreadState.Stopped) != 0)
+                                       throw new ThreadStateException ("Thread is dead; state can not be accessed.");
+
+                               return (thread_state & ThreadState.Background) != 0;
                        }
                        
                        set {
@@ -798,6 +887,10 @@ namespace System.Threading {
 #endif
 
 #if NET_2_0
+               private static int GetNewManagedId() {
+                       return Interlocked.Increment(ref _managed_id_counter);
+               }
+
                public Thread (ThreadStart start, int maxStackSize)
                {
                        if (start == null)
@@ -807,6 +900,7 @@ namespace System.Threading {
 
                        threadstart = start;
                        stack_size = maxStackSize;
+                       Thread_init ();
                }
 
                public Thread (ParameterizedThreadStart start)
@@ -815,6 +909,7 @@ namespace System.Threading {
                                throw new ArgumentNullException ("start");
 
                        threadstart = start;
+                       Thread_init ();
                }
 
                public Thread (ParameterizedThreadStart start, int maxStackSize)
@@ -826,9 +921,11 @@ namespace System.Threading {
 
                        threadstart = start;
                        stack_size = maxStackSize;
+                       Thread_init ();
                }
 
                [MonoTODO ("limited to CompressedStack support")]
+               // FIXME: We share the _ec object between appdomains
                public ExecutionContext ExecutionContext {
                        [ReliabilityContract (Consistency.WillNotCorruptState, Cer.MayFail)]
                        get {
@@ -839,78 +936,74 @@ namespace System.Threading {
                }
 
                public int ManagedThreadId {
-               [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
-                       get { return (int)thread_id; }
+                       [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
+                       get {
+                               if (managed_id == 0) {
+                                       int new_managed_id = GetNewManagedId ();
+                                       
+                                       Interlocked.CompareExchange (ref managed_id, new_managed_id, 0);
+                               }
+                               
+                               return managed_id;
+                       }
                }
 
-               [MonoTODO("Not implemented")]
                [ReliabilityContract (Consistency.WillNotCorruptState, Cer.MayFail)]
                public static void BeginCriticalRegion ()
                {
-                       throw new NotImplementedException ();
+                       CurrentThread.critical_region_level++;
                }
 
-               [MonoTODO("Not implemented")]
                [ReliabilityContract (Consistency.WillNotCorruptState, Cer.Success)]
                public static void EndCriticalRegion ()
                {
-                       throw new NotImplementedException ();
+                       CurrentThread.critical_region_level--;
                }
 
-               [MonoTODO("Not implemented")]
                [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
                public static void BeginThreadAffinity ()
                {
-                       throw new NotImplementedException ();
+                       // Managed and native threads are currently bound together.
                }
 
-               [MonoTODO("Not implemented")]
                [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
                public static void EndThreadAffinity ()
                {
-                       throw new NotImplementedException ();
+                       // Managed and native threads are currently bound together.
                }
-
-               //
-               // We disable warning 618, because we are accessing the
-               // empty property ApartmentState which produces an Obsolete
-               // message, but since its an empty routine needed for 1.x
-               // we use it.
-               //
-               // Maybe we should later turn these into internal methods for 1.x
-               // instead and have the property call these.
-               
                
                public ApartmentState GetApartmentState ()
                {
-                       return this.ApartmentState;
+                       return (ApartmentState)apartment_state;
                }
 
                public void SetApartmentState (ApartmentState state)
                {
-                       this.ApartmentState = state;
+                       if (!TrySetApartmentState (state))
+                               throw new InvalidOperationException ("Failed to set the specified COM apartment state.");
                }
 
-               [MonoTODO]
-               public bool TrySetApartmentState (ApartmentState state)
+               public bool TrySetApartmentState (ApartmentState state) 
                {
-                       try {
-                               this.ApartmentState = state;
-                               return true;
-                       }
-                       catch (ArgumentException) {
-                               throw;
-                       }
-                       catch {
+                       /* Only throw this exception when changing the
+                        * state of another thread.  See bug 324338
+                        */
+                       if ((this != CurrentThread) &&
+                           (ThreadState & ThreadState.Unstarted) == 0)
+                               throw new ThreadStateException ("Thread was in an invalid state for the operation being executed.");
+
+                       if ((ApartmentState)apartment_state != ApartmentState.Unknown)
                                return false;
-                       }
+
+                       apartment_state = (byte)state;
+
+                       return true;
                }
                
                [ComVisible (false)]
                public override int GetHashCode ()
                {
-                       // ??? overridden but not guaranteed to be unique ???
-                       return (int)thread_id;
+                       return ManagedThreadId;
                }
 
                public void Start (object parameter)