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
*/
private IntPtr start_notify;
private IntPtr stack_ptr;
- private IntPtr static_data;
+ private UIntPtr static_data; /* GC-tracked */
private IntPtr jit_data;
private IntPtr lock_data;
Context current_appcontext;
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]
// 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)]
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;
}
[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 ();
}
- [MonoTODO]
#if NET_2_0
[Obsolete ("Deprecated in favor of GetApartmentState, SetApartmentState and TrySetApartmentState.")]
#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 {
+
+ 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 ();
* 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 ();
//
SetCachedCurrentCulture (culture);
in_currentculture = false;
+ if (_numberFormatter != null)
+ _numberFormatter.CurrentCulture = culture;
return culture;
}
}
in_currentculture = false;
}
+ if (_numberFormatter != null)
+ _numberFormatter.CurrentCulture = culture;
return culture;
}
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;
}
}
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;
}
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 {
}
}
- [MonoTODO]
public ThreadPriority Priority {
get {
return(ThreadPriority.Lowest);
}
set {
+ // FIXME: Implement setter.
}
}
#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)
threadstart = start;
stack_size = maxStackSize;
+ Thread_init ();
}
public Thread (ParameterizedThreadStart start)
throw new ArgumentNullException ("start");
threadstart = start;
+ Thread_init ();
}
public Thread (ParameterizedThreadStart start, int maxStackSize)
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 {
}
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]
[ReliabilityContract (Consistency.WillNotCorruptState, Cer.MayFail)]
public static void BeginCriticalRegion ()
{
- throw new NotImplementedException ();
+ CurrentThread.critical_region_level++;
}
- [MonoTODO]
[ReliabilityContract (Consistency.WillNotCorruptState, Cer.Success)]
public static void EndCriticalRegion ()
{
- throw new NotImplementedException ();
+ CurrentThread.critical_region_level--;
}
- [MonoTODO]
[ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
public static void BeginThreadAffinity ()
{
- throw new NotImplementedException ();
+ // Managed and native threads are currently bound together.
}
- [MonoTODO]
[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.
-
- [MonoTODO]
public ApartmentState GetApartmentState ()
{
- return this.ApartmentState;
+ return (ApartmentState)apartment_state;
}
- [MonoTODO]
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)