Merge pull request #1632 from alexanderkyte/bug24118
[mono.git] / mcs / class / corlib / System.Threading / Thread.cs
index 11f25a0ee8320f564f080802b7763c21d83c1866..4be83d2cd58c9807089f4146144911f26f85ccce 100644 (file)
@@ -43,7 +43,7 @@ using System.Runtime.ConstrainedExecution;
 
 namespace System.Threading {
        [StructLayout (LayoutKind.Sequential)]
-       internal class InternalThread : CriticalFinalizerObject {
+       sealed class InternalThread : CriticalFinalizerObject {
 #pragma warning disable 169, 414, 649
                #region Sync with metadata/object-internals.h
                int lock_thread_id;
@@ -137,6 +137,8 @@ namespace System.Threading {
 
                IPrincipal principal;
                int principal_version;
+               bool current_culture_set;
+               bool current_ui_culture_set;
                CultureInfo current_culture;
                CultureInfo current_ui_culture;
 
@@ -154,6 +156,11 @@ namespace System.Threading {
                [ThreadStatic]
                static ExecutionContext _ec;
 
+               static NamedDataSlot namedDataSlot;             
+
+               static internal CultureInfo default_culture;
+               static internal CultureInfo default_ui_culture;
+
                // can be both a ThreadStart and a ParameterizedThreadStart
                private MulticastDelegate threadstart;
                //private string thread_name=null;
@@ -325,50 +332,28 @@ namespace System.Threading {
                                return (int)(CurrentThread.internal_thread.thread_id);
                        }
                }
-
-               // Stores a hash keyed by strings of LocalDataStoreSlot objects
-               static Dictionary<string, LocalDataStoreSlot> datastorehash;
-               private static object datastore_lock = new object ();
                
-               private static void InitDataStoreHash () {
-                       lock (datastore_lock) {
-                               if (datastorehash == null) {
-                                       datastorehash = new Dictionary<string, LocalDataStoreSlot> ();
-                               }
+               static NamedDataSlot NamedDataSlot {
+                       get {
+                               if (namedDataSlot == null)
+                                       Interlocked.CompareExchange (ref namedDataSlot, new NamedDataSlot (), null);
+
+                               return namedDataSlot;
                        }
                }
                
-               public static LocalDataStoreSlot AllocateNamedDataSlot (string name) {
-                       lock (datastore_lock) {
-                               if (datastorehash == null)
-                                       InitDataStoreHash ();
-
-                               if (datastorehash.ContainsKey (name)) {
-                                       // This exception isnt documented (of
-                                       // course) but .net throws it
-                                       throw new ArgumentException("Named data slot already added");
-                               }
-                       
-                               var slot = AllocateDataSlot ();
-
-                               datastorehash.Add (name, slot);
-
-                               return slot;
-                       }
+               public static LocalDataStoreSlot AllocateNamedDataSlot (string name)
+               {
+                       return NamedDataSlot.Allocate (name);
                }
 
-               public static void FreeNamedDataSlot (string name) {
-                       lock (datastore_lock) {
-                               if (datastorehash == null)
-                                       InitDataStoreHash ();
-
-                               if (datastorehash.ContainsKey (name)) {
-                                       datastorehash.Remove (name);
-                               }
-                       }
+               public static void FreeNamedDataSlot (string name)
+               {
+                       NamedDataSlot.Free (name);
                }
 
-               public static LocalDataStoreSlot AllocateDataSlot () {
+               public static LocalDataStoreSlot AllocateDataSlot ()
+               {
                        return new LocalDataStoreSlot (true);
                }
 
@@ -400,18 +385,9 @@ namespace System.Threading {
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
                internal extern static void FreeLocalSlotValues (int slot, bool thread_local);
 
-               public static LocalDataStoreSlot GetNamedDataSlot(string name) {
-                       lock (datastore_lock) {
-                               if (datastorehash == null)
-                                       InitDataStoreHash ();
-
-                               LocalDataStoreSlot slot;
-                               if (!datastorehash.TryGetValue (name, out slot)) {
-                                       slot=AllocateNamedDataSlot(name);
-                               }
-                       
-                               return slot;
-                       }
+               public static LocalDataStoreSlot GetNamedDataSlot(string name)
+               {
+                       return NamedDataSlot.Get (name);
                }
                
                public static AppDomain GetDomain() {
@@ -430,12 +406,10 @@ namespace System.Threading {
                        ResetAbort_internal ();
                }
 
-#if NET_4_0
                [HostProtectionAttribute (SecurityAction.LinkDemand, Synchronization = true, ExternalThreading = true)]
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
                [ReliabilityContract (Consistency.WillNotCorruptState, Cer.Success)]
                public extern static bool Yield ();
-#endif
 
 
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
@@ -499,11 +473,13 @@ namespace System.Threading {
                public CultureInfo CurrentCulture {
                        get {
                                CultureInfo culture = current_culture;
-                               if (culture != null)
+                               if (current_culture_set && culture != null)
                                        return culture;
 
+                               if (default_culture != null)
+                                       return default_culture;
+
                                current_culture = culture = CultureInfo.ConstructCurrentCulture ();
-                               NumberFormatter.SetThreadCurrentCulture (culture);
                                return culture;
                        }
                        
@@ -514,16 +490,19 @@ namespace System.Threading {
 
                                value.CheckNeutral ();
                                current_culture = value;
-                               NumberFormatter.SetThreadCurrentCulture (value);
+                               current_culture_set = true;
                        }
                }
 
                public CultureInfo CurrentUICulture {
                        get {
                                CultureInfo culture = current_ui_culture;
-                               if (culture != null)
+                               if (current_ui_culture_set && culture != null)
                                        return culture;
 
+                               if (default_ui_culture != null)
+                                       return default_ui_culture;
+
                                current_ui_culture = culture = CultureInfo.ConstructCurrentUICulture ();
                                return culture;
                        }
@@ -532,6 +511,7 @@ namespace System.Threading {
                                if (value == null)
                                        throw new ArgumentNullException ("value");
                                current_ui_culture = value;
+                               current_ui_culture_set = true;
                        }
                }
 
@@ -605,11 +585,12 @@ namespace System.Threading {
 
                public ThreadPriority Priority {
                        get {
-                               return(ThreadPriority.Lowest);
+                               return (ThreadPriority)GetPriority (Internal);
                        }
                        
                        set {
-                               // FIXME: Implement setter.
+                               // FIXME: This doesn't do anything yet
+                               SetPriority (Internal, (int)value);
                        }
                }
 
@@ -622,6 +603,12 @@ namespace System.Threading {
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
                private extern static void Abort_internal (InternalThread thread, object stateInfo);
 
+               [MethodImplAttribute(MethodImplOptions.InternalCall)]
+               private extern static int GetPriority (InternalThread thread);
+
+               [MethodImplAttribute(MethodImplOptions.InternalCall)]
+               private extern static void SetPriority (InternalThread thread, int priority);
+
                [SecurityPermission (SecurityAction.Demand, ControlThread=true)]
                public void Abort () 
                {
@@ -701,31 +688,6 @@ namespace System.Threading {
                        }
                }
 
-#if MONOTOUCH
-               static ConstructorInfo nsautoreleasepool_ctor;
-               
-               IDisposable GetNSAutoreleasePool ()
-               {
-                       if (nsautoreleasepool_ctor == null) {
-                               Type t = Type.GetType ("MonoTouch.Foundation.NSAutoreleasePool, monotouch, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null");
-                               nsautoreleasepool_ctor = t.GetConstructor (Type.EmptyTypes);
-                       }
-                       return (IDisposable) nsautoreleasepool_ctor.Invoke (null);
-               }
-               
-               private void StartInternal ()
-               {
-                       using (var pool = GetNSAutoreleasePool ()) {
-                               current_thread = this;
-                       
-                               if (threadstart is ThreadStart) {
-                                       ((ThreadStart) threadstart) ();
-                               } else {
-                                       ((ParameterizedThreadStart) threadstart) (start_obj);
-                               }
-                       }
-               }
-#else
                private void StartInternal ()
                {
                        current_thread = this;
@@ -736,11 +698,10 @@ namespace System.Threading {
                                ((ParameterizedThreadStart) threadstart) (start_obj);
                        }
                }
-#endif
+
                public void Start() {
                        // propagate informations from the original thread to the new thread
-                       if (!ExecutionContext.IsFlowSuppressed ())
-                               ec_to_set = ExecutionContext.Capture ();
+                       ec_to_set = ExecutionContext.Capture (false, true);
                        Internal._serialized_principal = CurrentThread.Internal._serialized_principal;
 
                        // Thread_internal creates and starts the new thread, 
@@ -855,6 +816,8 @@ namespace System.Threading {
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
                extern public static void VolatileWrite (ref UIntPtr address, UIntPtr value);
                
+               [MethodImplAttribute (MethodImplOptions.InternalCall)]
+               extern static int SystemMaxStackStize ();
 
                static int CheckStackSize (int maxStackSize)
                {
@@ -869,12 +832,8 @@ namespace System.Threading {
                        if ((maxStackSize % page_size) != 0) // round up to a divisible of page size
                                maxStackSize = (maxStackSize / (page_size - 1)) * page_size;
 
-                       int default_stack_size = (IntPtr.Size / 4) * 1024 * 1024; // from wthreads.c
-
-                       if (maxStackSize > default_stack_size)
-                               return default_stack_size;
-
-                       return maxStackSize; 
+                       /* Respect the max stack size imposed by the system*/
+                       return Math.Min (maxStackSize, SystemMaxStackStize ());
                }
 
                public Thread (ThreadStart start, int maxStackSize)
@@ -903,7 +862,6 @@ namespace System.Threading {
                        Internal.stack_size = CheckStackSize (maxStackSize);
                }
 
-               [MonoTODO ("limited to CompressedStack support")]
                public ExecutionContext ExecutionContext {
                        [ReliabilityContract (Consistency.WillNotCorruptState, Cer.MayFail)]
                        get {
@@ -911,6 +869,35 @@ namespace System.Threading {
                                        _ec = new ExecutionContext ();
                                return _ec;
                        }
+                       internal set {
+                               _ec = value;
+                       }
+               }
+
+               internal bool HasExecutionContext {
+                       get {
+                               return _ec != null;
+                       }
+               }
+
+               internal void BranchExecutionContext (out ExecutionContext.Switcher switcher)
+               {
+                       if (_ec == null) {
+                               switcher =  new ExecutionContext.Switcher ();
+                       } else {
+                               switcher = new ExecutionContext.Switcher (_ec);
+                               _ec.CopyOnWrite = true;
+                       }
+               }
+
+               internal void RestoreExecutionContext (ref ExecutionContext.Switcher switcher)
+               {
+                       if (switcher.IsEmpty) {
+                               _ec = null;
+                               return;
+                       }
+
+                       switcher.Restore (_ec);
                }
 
                public int ManagedThreadId {
@@ -957,14 +944,11 @@ namespace System.Threading {
 
                public bool TrySetApartmentState (ApartmentState state) 
                {
-                       /* Only throw this exception when changing the
-                        * state of another thread.  See bug 324338
-                        */
-                       if ((this != CurrentThread) &&
-                           (ThreadState & ThreadState.Unstarted) == 0)
+                       if ((ThreadState & ThreadState.Unstarted) == 0)
                                throw new ThreadStateException ("Thread was in an invalid state for the operation being executed.");
 
-                       if ((ApartmentState)Internal.apartment_state != ApartmentState.Unknown)
+                       if ((ApartmentState)Internal.apartment_state != ApartmentState.Unknown && 
+                           (ApartmentState)Internal.apartment_state != state)
                                return false;
 
                        Internal.apartment_state = (byte)state;
@@ -1040,5 +1024,10 @@ namespace System.Threading {
                        throw new NotImplementedException ();
                }
 #endif
+
+               internal CultureInfo GetCurrentUICultureNoAppX ()
+               {
+                       return CultureInfo.CurrentUICulture;
+               }
        }
 }