[Mono-dev] patches for RegionInfo support

Kornél Pál kornelpal at hotmail.com
Mon Aug 22 05:36:49 EDT 2005


Hi,

You are misinterpreting CurrentRegion.
CurrentRegion is no way related to CurrentCulture.

RegionInfo.CurrentRegion:
http://msdn2.microsoft.com/library/7kcxkdc9(en-us,vs.80).aspx

The documentation describes the actual behaviour of CurrentRegion (I have
done some tests):

The value is AppDomain scoped (in other words stored in a static filed). A
single instance is constructed at the first call to CurrentRegion then a
cached value is retruned. On Windows this is based on the value selected in
"Regional and Language Options". This is per-user setting on Windows and can
be retrieved using GetUserDefaultLCID. You can change however this setting
(on Windows) without rebooting so the value may change. But it will have no
effect to CurrentRegion if it's already cached unless you call
CultureInfo.ClearCachedData.

And CurrentRegion is read-only.

CultureInfo.ClearCachedData:
http://msdn2.microsoft.com/library/65x0h0wh(en-us,vs.80).aspx:

It simply clears (or reinitializes) the cached values of
CultureInfo.CurrentCulture, CultureInfo.CurrentUICulture,
RegionInfo.CurrentRegion and TimeZone.CurrentTimeZone.

Note that TimeZone.CurrentTimeZone reset is not documented but is can simply
tested by changing time zone in Control Panel the calling
CultureInfo.ClearCachedData. CurrentTimeZone is cached just like
CurrentRegion and can be changed without restart as well.

CultureInfo.CurrentCulture and CultureInfo.CurrentUICulture are not changed
on existing threads (documented and I tested as well) but the updated values
will be used for new threads. This reveals that MS.NET is caching the
default values (as they know how Windows select default thread locale:) and
associates them to new threads rather than using GetThreadLocale for example
on new threads.

As such CultureInfo.ClearCachedData seems to deal only with static fields
but it is an instance method.:)

At the beginning I said that "CurrentRegion is no way related to
CurrentCulture.". This is true but I don't know other OS' internals
regarding RegionInfo so using CultureInfo may be required but CurrentRegion
is an AppDomain scope cached value that will be refreshed only when calling
ClearCachedData. So CurrentCulture should not be used as it can be changed
but the default value for CurrentCulture can be used if it's required.

Kornél

----- Original Message -----
From: "Atsushi Eno" <atsushi at ximian.com>
To: <mono-devel-list at lists.ximian.com>
Sent: Monday, August 22, 2005 3:42 AM
Subject: Re: [Mono-dev] patches for RegionInfo support


> Oops, the corlib patch was wrong. Reattached ones should work fine.
>
> Atsushi Eno
>
> Atsushi Eno wrote:
>> Hola,
>>
>> Paolo Molaro wrote:
>>> On 08/17/05 Atsushi Eno wrote:
>>>> I mostly copied those icall code from CurrentCulture support,
>>>> but one thing I don't understand is NUM_CACHED_CULTURES ... why
>>>> it is set as 4? Is it safe to guess NUM_CACHED_REGIONS 4 as well?
>>>
>>> I would store a single copy, ie not an array of objects, since nobody
>>> uses this stuff.
>>
>> Yeah, agreed.
>>
>>>> +        static object region_lock = new object ();
>>>> +
>>>> +        internal RegionInfo CurrentRegion {
>>>
>>> Make this static so it can be called only on the current thread and
>>> remove the locking.
>>
>> Am mazed... is there any reason that RegionInfo is different from
>> CultureInfo here (other than that CurrentCulture is exposed as
>> nonstatic)?  Anyways I attached the patch that fixes above.
>> If there seems no further problem, I'll commit it later.
>>
>> Atsushi Eno
>
>


--------------------------------------------------------------------------------


> Index: threads.c
> ===================================================================
> --- threads.c (revision 48630)
> +++ threads.c (working copy)
> @@ -823,6 +823,43 @@
>  mono_monitor_exit (this->synch_lock);
> }
>
> +MonoObject*
> +ves_icall_System_Threading_Thread_GetCachedCurrentRegion (MonoThread
> *this)
> +{
> + MonoObject *res;
> + MonoDomain *domain;
> + int i;
> +
> + /* No need to lock here */
> + if (this->region_info) {
> + domain = mono_domain_get ();
> + res = this->region_info;
> + if (res && res->vtable->domain == domain)
> + return res;
> + }
> +
> + return NULL;
> +}
> +
> +void
> +ves_icall_System_Threading_Thread_SetCachedCurrentRegion (MonoThread
> *this, MonoObject *region)
> +{
> + int i;
> + MonoDomain *domain = mono_domain_get ();
> +
> + mono_monitor_enter (this->synch_lock);
> +
> + if (this->region_info) {
> + if (this->region_info->vtable->domain == domain)
> + /* Replace */
> + this->region_info = region;
> + }
> + else
> + /* Free entry */
> + this->region_info = region;
> + mono_monitor_exit (this->synch_lock);
> +}
> +
> /* the jit may read the compiled code of this function */
> MonoThread *
> mono_thread_current (void)
> Index: object-internals.h
> ===================================================================
> --- object-internals.h (revision 48630)
> +++ object-internals.h (working copy)
> @@ -223,6 +223,7 @@
>  HANDLE     handle;
>  MonoObject **culture_info;
>  MonoObject **ui_culture_info;
> + MonoObject *region_info;
>  MonoBoolean threadpool_thread;
>  gunichar2  *name;
>  guint32     name_len;
> Index: threads-types.h
> ===================================================================
> --- threads-types.h (revision 48630)
> +++ threads-types.h (working copy)
> @@ -48,6 +48,8 @@
> extern MonoArray*
> ves_icall_System_Threading_Thread_GetSerializedCurrentUICulture
> (MonoThread *this_obj);
> extern void ves_icall_System_Threading_Thread_SetCachedCurrentUICulture
> (MonoThread *this_obj, MonoObject *culture);
> void ves_icall_System_Threading_Thread_SetSerializedCurrentUICulture
> (MonoThread *this_obj, MonoArray *arr);
> +extern MonoObject*
> ves_icall_System_Threading_Thread_GetCachedCurrentRegion (MonoThread
> *this_obj);
> +extern void ves_icall_System_Threading_Thread_SetCachedCurrentRegion
> (MonoThread *this_obj, MonoObject *culture);
> extern HANDLE
> ves_icall_System_Threading_Mutex_CreateMutex_internal(MonoBoolean owned,
> MonoString *name, MonoBoolean *created);
> extern void ves_icall_System_Threading_Mutex_ReleaseMutex_internal (HANDLE
> handle );
> extern HANDLE ves_icall_System_Threading_Events_CreateEvent_internal
> (MonoBoolean manual, MonoBoolean initial, MonoString *name);
> Index: icall.c
> ===================================================================
> --- icall.c (revision 48630)
> +++ icall.c (working copy)
> @@ -6884,6 +6884,7 @@
>  {"ClrState", ves_icall_System_Threading_Thread_ClrState},
>  {"CurrentThread_internal", mono_thread_current},
>  {"GetCachedCurrentCulture",
> ves_icall_System_Threading_Thread_GetCachedCurrentCulture},
> + {"GetCachedCurrentRegion",
> ves_icall_System_Threading_Thread_GetCachedCurrentRegion},
>  {"GetCachedCurrentUICulture",
> ves_icall_System_Threading_Thread_GetCachedCurrentUICulture},
>  {"GetDomainID", ves_icall_System_Threading_Thread_GetDomainID},
>  {"GetName_internal", ves_icall_System_Threading_Thread_GetName_internal},
> @@ -6894,6 +6895,7 @@
>  {"ResetAbort_internal()", ves_icall_System_Threading_Thread_ResetAbort},
>  {"Resume_internal()", ves_icall_System_Threading_Thread_Resume},
>  {"SetCachedCurrentCulture",
> ves_icall_System_Threading_Thread_SetCachedCurrentCulture},
> + {"SetCachedCurrentRegion",
> ves_icall_System_Threading_Thread_SetCachedCurrentRegion},
>  {"SetCachedCurrentUICulture",
> ves_icall_System_Threading_Thread_SetCachedCurrentUICulture},
>  {"SetName_internal", ves_icall_System_Threading_Thread_SetName_internal},
>  {"SetSerializedCurrentCulture",
> ves_icall_System_Threading_Thread_SetSerializedCurrentCulture},
>


--------------------------------------------------------------------------------


> Index: System.Globalization/RegionInfo.cs
> ===================================================================
> --- System.Globalization/RegionInfo.cs (revision 48630)
> +++ System.Globalization/RegionInfo.cs (working copy)
> @@ -29,28 +29,17 @@
> //
> using System.Globalization;
> using System.Runtime.CompilerServices;
> +using System.Threading;
>
> namespace System.Globalization
> {
>  [Serializable]
>  public class RegionInfo
>  {
> - static RegionInfo currentRegion;
> -
>  // This property is not synchronized with CurrentCulture, so
>  // we need to use bootstrap CurrentCulture LCID.
>  public static RegionInfo CurrentRegion {
> - get {
> - if (currentRegion == null) {
> - // make sure to fill BootstrapCultureID.
> - CultureInfo ci = CultureInfo.CurrentCulture;
> - // If current culture is invariant then region is not available.
> - if (ci == null || CultureInfo.BootstrapCultureID == 0x7F)
> - return null;
> - currentRegion = new RegionInfo (CultureInfo.BootstrapCultureID);
> - }
> - return currentRegion;
> - }
> + get { return Thread.CurrentRegion; }
>  }
>
>  int regionId;
> Index: System.Threading/Thread.cs
> ===================================================================
> --- System.Threading/Thread.cs (revision 48630)
> +++ System.Threading/Thread.cs (working copy)
> @@ -59,6 +59,7 @@
>
>  private IntPtr culture_info;
>  private IntPtr ui_culture_info;
> + private IntPtr region_info;
>  private bool threadpool_thread;
>  /* accessed only from unmanaged code */
>  private IntPtr name;
> @@ -317,6 +318,9 @@
>  private extern CultureInfo GetCachedCurrentUICulture ();
>
>  [MethodImplAttribute (MethodImplOptions.InternalCall)]
> + private static extern RegionInfo GetCachedCurrentRegion (Thread
> current);
> +
> + [MethodImplAttribute (MethodImplOptions.InternalCall)]
>  private extern byte[] GetSerializedCurrentUICulture ();
>
>  [MethodImplAttribute (MethodImplOptions.InternalCall)]
> @@ -325,6 +329,9 @@
>  [MethodImplAttribute (MethodImplOptions.InternalCall)]
>  private extern void SetSerializedCurrentUICulture (byte[] culture);
>
> + [MethodImplAttribute (MethodImplOptions.InternalCall)]
> + private static extern void SetCachedCurrentRegion (Thread current,
> RegionInfo region);
> +
>  /* If the current_lcid() isn't known by CultureInfo,
>  * it will throw an exception which may cause
>  * String.Concat to try and recursively look up the
> @@ -476,6 +483,23 @@
>  }
>  }
>
> + internal static RegionInfo CurrentRegion {
> + get {
> + RegionInfo region = GetCachedCurrentRegion (CurrentThread);
> + // unlike CurrentCulture, creating different
> + // instance between AppDomain should be OK.
> + if (region != null)
> + return region;
> +
> + // make sure that CurrentCulture exists.
> + CultureInfo current = CurrentThread.CurrentCulture;
> + region = new RegionInfo (
> + CultureInfo.BootstrapCultureID);
> + SetCachedCurrentRegion (CurrentThread, region);
> + return region;
> + }
> + }
> +
>  public bool IsThreadPoolThread {
>  get {
>  return IsThreadPoolThreadInternal;
>


--------------------------------------------------------------------------------


> _______________________________________________
> Mono-devel-list mailing list
> Mono-devel-list at lists.ximian.com
> http://lists.ximian.com/mailman/listinfo/mono-devel-list
>




More information about the Mono-devel-list mailing list