[mono/mono] [5 commits] e4997931: [bcl]Set the culture of the thread local NumberFormatter everytime.

"Rodrigo Kumpera ([email protected])" <[email protected]> Mon, 18 Nov 2013 23:29:45 +0000
Newsgroups gmane.comp.gnome.mono.patches
Message-ID <000001426d8c5fd9-3cd5be8d-3b63-442b-baa8-b095af9b88bb-000000@email.amazonses.com>
   Branch: refs/heads/master
     Home: https://github.com/mono/mono
  Compare: https://github.com/mono/mono/compare/57091eda02a9...349cb638ff55

   Commit: e49979312508bc7db79c63f558dd0cf5dafa7290
   Author: Rodrigo Kumpera <[email protected]> (kumpera)
     Date: 2013-11-18 23:13:02 GMT
      URL: https://github.com/mono/mono/commit/e49979312508bc7db79c63f558dd0cf5dafa7290

[bcl]Set the culture of the thread local NumberFormatter everytime.

the problem of changing the culture when a new value is set in the current thread
is that is doesn't work well with CultureInfo.DefaultThreadCurrentCulture.

Changed paths:
  M mcs/class/corlib/System.Threading/Thread.cs
  M mcs/class/corlib/System/NumberFormatter.cs

Modified: mcs/class/corlib/System.Threading/Thread.cs
===================================================================
@@ -474,7 +474,6 @@ public static void Sleep (TimeSpan timeout)
 					return culture;
 
 				current_culture = culture = CultureInfo.ConstructCurrentCulture ();
-				NumberFormatter.SetThreadCurrentCulture (culture);
 				return culture;
 			}
 			
@@ -485,7 +484,6 @@ public static void Sleep (TimeSpan timeout)
 
 				value.CheckNeutral ();
 				current_culture = value;
-				NumberFormatter.SetThreadCurrentCulture (value);
 			}
 		}
 

Modified: mcs/class/corlib/System/NumberFormatter.cs
===================================================================
@@ -783,6 +783,7 @@ private static NumberFormatter GetInstance()
 			threadNumberFormatter = null;
 			if (res == null)
 				return new NumberFormatter (Thread.CurrentThread);
+			res.CurrentCulture = Thread.CurrentThread.CurrentCulture;
 			return res;
 		}
 
@@ -791,12 +792,6 @@ private void Release()
 			threadNumberFormatter = this;
 		}
 
-		internal static void SetThreadCurrentCulture (CultureInfo culture)
-		{
-			if (threadNumberFormatter != null)
-				threadNumberFormatter.CurrentCulture = culture;
-		}
-
 		public static string NumberToString (string format, sbyte value, IFormatProvider fp)
 		{
 			NumberFormatter inst = GetInstance();

   Commit: b1b2a0a8fb81f8f1cb8d5fdde34b551f78f5eb30
   Author: Rodrigo Kumpera <[email protected]> (kumpera)
     Date: 2013-11-18 23:13:02 GMT
      URL: https://github.com/mono/mono/commit/b1b2a0a8fb81f8f1cb8d5fdde34b551f78f5eb30

[bcl]Memoize the default culture so it can be reused across threads.

Changed paths:
  M mcs/class/corlib/System.Globalization/CultureInfo.cs

Modified: mcs/class/corlib/System.Globalization/CultureInfo.cs
===================================================================
@@ -45,6 +45,7 @@ public class CultureInfo : ICloneable, IFormatProvider
 		static volatile CultureInfo invariant_culture_info = new CultureInfo (InvariantCultureId, false, true);
 		static object shared_table_lock = new object ();
 		internal static int BootstrapCultureID;
+		static CultureInfo default_current_culture;
 
 #pragma warning disable 169, 649
 		bool m_isReadOnly;
@@ -124,10 +125,13 @@ public class CultureInfo : ICloneable, IFormatProvider
 
 		internal static CultureInfo ConstructCurrentCulture ()
 		{
+			if (default_current_culture != null)
+				return default_current_culture;
 			CultureInfo ci = new CultureInfo ();
 			if (!ConstructInternalLocaleFromCurrentLocale (ci))
 				ci = InvariantCulture;
 			BootstrapCultureID = ci.cultureID;
+			default_current_culture = ci;
 			return ci;
 		}
 

   Commit: 5b8f9ad666190001e480d2bb9fb70ce63bd24130
   Author: Rodrigo Kumpera <[email protected]> (kumpera)
     Date: 2013-11-18 23:13:02 GMT
      URL: https://github.com/mono/mono/commit/5b8f9ad666190001e480d2bb9fb70ce63bd24130

[bcl] Implement CultureInfo.DefaultThreadCurrentCulture.

The way DefaultThreadCurrentCulture is to be implemented is that its current value
will always be used by a thread that didn't set a value for its culture.

This means we can't cache DefaultThreadCurrentCulture value as it's allowed to
change and threads must always show the latest value.

Changed paths:
  M mcs/class/corlib/System.Globalization/CultureInfo.cs
  M mcs/class/corlib/System.Threading/Thread.cs

Modified: mcs/class/corlib/System.Globalization/CultureInfo.cs
===================================================================
@@ -1013,13 +1013,12 @@ static Calendar CreateCalendar (int calendarType)
 		}
 		
 #if NET_4_5
-		[MonoTODO]
 		public static CultureInfo DefaultThreadCurrentCulture {
 			get {
-				throw new NotImplementedException ();
+				return Thread.default_culture;
 			}
 			set {
-				throw new NotImplementedException ();
+				Thread.default_culture = value;
 			}
 		}
 		

Modified: mcs/class/corlib/System.Threading/Thread.cs
===================================================================
@@ -137,6 +137,7 @@ public sealed class Thread : CriticalFinalizerObject, _Thread {
 
 		IPrincipal principal;
 		int principal_version;
+		bool current_culture_set;
 		CultureInfo current_culture;
 		CultureInfo current_ui_culture;
 
@@ -156,6 +157,8 @@ public sealed class Thread : CriticalFinalizerObject, _Thread {
 
 		static NamedDataSlot namedDataSlot;		
 
+		static internal CultureInfo default_culture;
+
 		// can be both a ThreadStart and a ParameterizedThreadStart
 		private MulticastDelegate threadstart;
 		//private string thread_name=null;
@@ -470,9 +473,12 @@ public static void Sleep (TimeSpan timeout)
 		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 ();
 				return culture;
 			}
@@ -484,6 +490,7 @@ public static void Sleep (TimeSpan timeout)
 
 				value.CheckNeutral ();
 				current_culture = value;
+				current_culture_set = true;
 			}
 		}
 

   Commit: 703eb849113b9b615783ce87c646c2493e691598
   Author: Rodrigo Kumpera <[email protected]> (kumpera)
     Date: 2013-11-18 23:13:03 GMT
      URL: https://github.com/mono/mono/commit/703eb849113b9b615783ce87c646c2493e691598

[bcl]Add test for CultureInfo.DefaultThreadCurrentCulture

Changed paths:
  M mcs/class/corlib/Test/System.Globalization/CultureInfoTest.cs

Modified: mcs/class/corlib/Test/System.Globalization/CultureInfoTest.cs
===================================================================
@@ -599,5 +599,119 @@ public void CultureNotFound ()
 			// https://bugzilla.xamarin.com/show_bug.cgi?id=3471
 			new CultureInfo ("en-HK");
 		}
+
+#if NET_4_5
+		CountdownEvent barrier = new CountdownEvent (3);
+		AutoResetEvent[] evt = new AutoResetEvent [] { new AutoResetEvent (false), new AutoResetEvent (false), new AutoResetEvent (false)};
+
+		CultureInfo[] initial_culture = new CultureInfo[3];
+		CultureInfo[] changed_culture = new CultureInfo[3];
+		CultureInfo[] changed_culture2 = new CultureInfo[3];
+		CultureInfo alternative_culture = new CultureInfo("pt-BR");
+
+		void StepAllPhases (int index)
+		{
+			initial_culture [index] = CultureInfo.CurrentCulture;
+			/*Phase 1 - we witness the original value */
+			barrier.Signal ();
+
+			/*Phase 2 - main thread changes culture */
+			evt [index].WaitOne ();
+
+			/*Phase 3 - we witness the new value */
+			changed_culture [index] = CultureInfo.CurrentCulture;
+			barrier.Signal ();
+
+			/* Phase 4 - main thread changes culture back */
+			evt [index].WaitOne ();
+
+			/*Phase 5 - we witness the new value */
+			changed_culture2 [index] = CultureInfo.CurrentCulture;
+			barrier.Signal ();
+		}
+
+		void ThreadWithoutChange () {
+			StepAllPhases (0);
+		}
+
+		void ThreadWithChange () {
+			Thread.CurrentThread.CurrentCulture = alternative_culture;
+			StepAllPhases (1);
+		}
+
+		void ThreadPoolWithoutChange () {
+			StepAllPhases (2);
+		}
+
+		[Test]
+		public void DefaultThreadCurrentCulture () {
+			var orig_culture = CultureInfo.CurrentCulture;
+			var new_culture = new CultureInfo("fr-FR");
+
+			Console.WriteLine (orig_culture.IsReadOnly);
+			/* Phase 0 - warm up */
+			new Thread (ThreadWithoutChange).Start ();
+			new Thread (ThreadWithChange).Start ();
+			Action x = ThreadPoolWithoutChange;
+			x.BeginInvoke (null, null);
+
+			/* Phase 1 - let everyone witness initial values */
+			initial_culture [0] = CultureInfo.CurrentCulture;
+			barrier.Wait ();
+			barrier.Reset ();
+
+			/* Phase 2 - change the default culture*/
+			CultureInfo.DefaultThreadCurrentCulture = new_culture;
+			evt [0].Set ();
+			evt [1].Set ();
+			evt [2].Set ();
+			/* Phase 3 - let everyone witness the new value */
+			changed_culture [0] = CultureInfo.CurrentCulture;
+			barrier.Wait ();
+			barrier.Reset ();
+
+			/* Phase 4 - revert the default culture back to null */
+			CultureInfo.DefaultThreadCurrentCulture = null;
+			evt [0].Set ();
+			evt [1].Set ();
+			evt [2].Set ();
+
+			/* Phase 5 - let everyone witness the new value */
+			changed_culture2 [0] = CultureInfo.CurrentCulture;
+			barrier.Wait ();
+			barrier.Reset ();
+
+			CultureInfo.DefaultThreadCurrentCulture = null;
+
+			Assert.AreEqual (orig_culture, initial_culture [0], "#2");
+			Assert.AreEqual (alternative_culture, initial_culture [1], "#3");
+			Assert.AreEqual (orig_culture, initial_culture [2], "#4");
+
+			Assert.AreEqual (new_culture, changed_culture [0], "#6");
+			Assert.AreEqual (alternative_culture, changed_culture [1], "#7");
+			Assert.AreEqual (new_culture, changed_culture [2], "#8");
+
+			Assert.AreEqual (orig_culture, changed_culture2 [0], "#10");
+			Assert.AreEqual (alternative_culture, changed_culture2 [1], "#11");
+			Assert.AreEqual (orig_culture, changed_culture2 [2], "#12");
+		}
+
+		[Test]
+		public void DefaultThreadCurrentCultureAndNumberFormaters () {
+			string us_str = null;
+			string br_str = null;
+			var thread = new Thread (() => {
+				CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("en-US");
+				us_str = 100000.ToString ("C");
+				CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("pt-BR");
+				br_str = 100000.ToString ("C");
+			});
+			thread.Start ();
+			thread.Join ();
+			CultureInfo.DefaultThreadCurrentCulture = null;
+			Assert.AreEqual ("$100,000.00", us_str, "#1");
+			Assert.AreEqual ("R$ 100.000,00", br_str, "#2");
+		}
+#endif
 	}
 }

   Commit: 349cb638ff55bab16fe3a8e36176330a30f2dee1
   Author: Rodrigo Kumpera <[email protected]> (kumpera)
     Date: 2013-11-18 23:13:03 GMT
      URL: https://github.com/mono/mono/commit/349cb638ff55bab16fe3a8e36176330a30f2dee1

 [bcl] Implement CultureInfo.DefaultThreadCurrentUICulture.

Changed paths:
  M mcs/class/corlib/System.Globalization/CultureInfo.cs
  M mcs/class/corlib/System.Threading/Thread.cs

Modified: mcs/class/corlib/System.Globalization/CultureInfo.cs
===================================================================
@@ -1025,10 +1025,10 @@ static Calendar CreateCalendar (int calendarType)
 		[MonoTODO]
 		public static CultureInfo DefaultThreadCurrentUICulture {
 			get {
-				throw new NotImplementedException ();
+				return Thread.default_ui_culture;
 			}
 			set {
-				throw new NotImplementedException ();
+				Thread.default_ui_culture = value;
 			}
 		}
 #endif

Modified: mcs/class/corlib/System.Threading/Thread.cs
===================================================================
@@ -138,6 +138,7 @@ public sealed class Thread : CriticalFinalizerObject, _Thread {
 		IPrincipal principal;
 		int principal_version;
 		bool current_culture_set;
+		bool current_ui_culture_set;
 		CultureInfo current_culture;
 		CultureInfo current_ui_culture;
 
@@ -158,6 +159,7 @@ public sealed class Thread : CriticalFinalizerObject, _Thread {
 		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;
@@ -497,9 +499,12 @@ public static void Sleep (TimeSpan timeout)
 		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;
 			}
@@ -508,6 +513,7 @@ public static void Sleep (TimeSpan timeout)
 				if (value == null)
 					throw new ArgumentNullException ("value");
 				current_ui_culture = value;
+				current_ui_culture_set = true;
 			}
 		}
 


_______________________________________________
Mono-patches maillist  -  [email protected]
http://lists.ximian.com/mailman/listinfo/mono-patches