// Dick Porter (dick@ximian.com)
//
// (C) Ximian, Inc. http://www.ximian.com
-// Copyright (C) 2004 Novell (http://www.novell.com)
-//
-
-//
-// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+// Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
//
using System.Runtime.Remoting.Contexts;
+using System.Runtime.Serialization;
+using System.Runtime.Serialization.Formatters.Binary;
using System.Security.Permissions;
using System.Security.Principal;
using System.Globalization;
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.IO;
using System.Collections;
+using System.Security;
+
+#if NET_2_0
+using System.Runtime.ConstrainedExecution;
+#endif
+
+namespace System.Threading {
+
+ [ClassInterface (ClassInterfaceType.None)]
+#if NET_2_0
+ [ComVisible (true)]
+ [ComDefaultInterface (typeof (_Thread))]
+ public sealed class Thread : CriticalFinalizerObject, _Thread {
+#else
+ public sealed class Thread : _Thread {
+#endif
-namespace System.Threading
-{
- public sealed class Thread
- {
- #region Sync with object.h
+ #region Sync with metadata/object-internals.h
+ int lock_thread_id;
// stores a thread handle
private IntPtr system_thread_handle;
-
- private CultureInfo current_culture;
- private CultureInfo current_ui_culture;
+
+ /* Note this is an opaque object (an array), not a CultureInfo */
+ private object cached_culture_info;
+ private IntPtr unused0;
private bool threadpool_thread;
/* accessed only from unmanaged code */
private IntPtr name;
private object abort_exc;
internal object abort_state;
/* thread_id is only accessed from unmanaged code */
- private int thread_id;
+ private Int64 thread_id;
/* start_notify is used by the runtime to signal that Start()
* is ok to return
private IntPtr static_data;
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 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 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;
+ /*
+ * 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
- private ThreadStart threadstart;
+ // the name of local_slots is important as it's used by the runtime.
+ [ThreadStatic]
+ static object[] local_slots;
+
+ // can be both a ThreadSart and a ParameterizedThreadStart
+ private MulticastDelegate threadstart;
private string thread_name=null;
private IPrincipal _principal;
-
+
public static Context CurrentContext {
+ [SecurityPermission (SecurityAction.LinkDemand, Infrastructure=true)]
get {
return(AppDomain.InternalGetContext ());
}
}
return p;
}
+ [SecurityPermission (SecurityAction.Demand, ControlPrincipal = true)]
set {
- new SecurityPermission (SecurityPermissionFlag.ControlPrincipal).Demand ();
CurrentThread._principal = value;
}
}
private extern static Thread CurrentThread_internal();
public static Thread CurrentThread {
+#if NET_2_0
+ [ReliabilityContract (Consistency.WillNotCorruptState, Cer.MayFail)]
+#endif
get {
return(CurrentThread_internal());
}
internal static int CurrentThreadId {
get {
- return CurrentThread.thread_id;
+ return (int)(CurrentThread.thread_id);
}
}
- // Looks up the slot hash for the current thread
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- private extern static Hashtable SlotHash_lookup();
-
- // Stores the slot hash for the current thread
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- private extern static void SlotHash_store(Hashtable slothash);
-
- private static Hashtable GetTLSSlotHash() {
- Hashtable slothash=SlotHash_lookup();
- if(slothash==null) {
- // Not synchronised, because this is
- // thread specific anyway.
- slothash=new Hashtable();
- SlotHash_store(slothash);
- }
-
- return(slothash);
- }
-
- internal static object ResetDataStoreStatus () {
- Hashtable slothash=SlotHash_lookup();
- SlotHash_store(null);
- return slothash;
- }
-
- internal static void RestoreDataStoreStatus (object data) {
- SlotHash_store((Hashtable)data);
- }
-
- public static LocalDataStoreSlot AllocateDataSlot() {
- LocalDataStoreSlot slot = new LocalDataStoreSlot();
-
- return(slot);
- }
-
// Stores a hash keyed by strings of LocalDataStoreSlot objects
static Hashtable datastorehash;
-
+ private static object datastore_lock = new object ();
+
private static void InitDataStoreHash () {
- lock (typeof (Thread)) {
+ lock (datastore_lock) {
if (datastorehash == null) {
datastorehash = Hashtable.Synchronized(new Hashtable());
}
}
}
- public static LocalDataStoreSlot AllocateNamedDataSlot(string name) {
- lock (typeof (Thread)) {
+ public static LocalDataStoreSlot AllocateNamedDataSlot (string name) {
+ lock (datastore_lock) {
if (datastorehash == null)
InitDataStoreHash ();
- LocalDataStoreSlot slot = (LocalDataStoreSlot)datastorehash[name];
- if(slot!=null) {
+ LocalDataStoreSlot slot = (LocalDataStoreSlot)datastorehash [name];
+ if (slot != null) {
// This exception isnt documented (of
// course) but .net throws it
throw new ArgumentException("Named data slot already added");
}
- slot = new LocalDataStoreSlot();
+ slot = AllocateDataSlot ();
- datastorehash.Add(name, slot);
+ datastorehash.Add (name, slot);
- return(slot);
+ return slot;
}
}
- public static void FreeNamedDataSlot(string name) {
- lock (typeof (Thread)) {
+ public static void FreeNamedDataSlot (string name) {
+ lock (datastore_lock) {
if (datastorehash == null)
InitDataStoreHash ();
- LocalDataStoreSlot slot=(LocalDataStoreSlot)datastorehash[name];
+ LocalDataStoreSlot slot = (LocalDataStoreSlot)datastorehash [name];
- if(slot!=null) {
- datastorehash.Remove(slot);
+ if (slot != null) {
+ datastorehash.Remove (slot);
}
}
}
- public static object GetData(LocalDataStoreSlot slot) {
- Hashtable slothash=GetTLSSlotHash();
- return(slothash[slot]);
+ public static LocalDataStoreSlot AllocateDataSlot () {
+ return new LocalDataStoreSlot (true);
+ }
+
+ public static object GetData (LocalDataStoreSlot slot) {
+ object[] slots = local_slots;
+ if (slot == null)
+ throw new ArgumentNullException ("slot");
+ if (slots != null && slot.slot < slots.Length)
+ return slots [slot.slot];
+ return null;
+ }
+
+ public static void SetData (LocalDataStoreSlot slot, object data) {
+ object[] slots = local_slots;
+ if (slot == null)
+ throw new ArgumentNullException ("slot");
+ if (slots == null) {
+ slots = new object [slot.slot + 2];
+ local_slots = slots;
+ } else if (slot.slot >= slots.Length) {
+ object[] nslots = new object [slot.slot + 2];
+ slots.CopyTo (nslots, 0);
+ slots = nslots;
+ local_slots = slots;
+ }
+ slots [slot.slot] = data;
}
public static AppDomain GetDomain() {
[MethodImplAttribute(MethodImplOptions.InternalCall)]
public extern static int GetDomainID();
+ [MethodImplAttribute (MethodImplOptions.InternalCall)]
+ internal extern static void FreeLocalSlotValues (int slot, bool thread_local);
+
public static LocalDataStoreSlot GetNamedDataSlot(string name) {
- if (datastorehash == null)
- InitDataStoreHash ();
- LocalDataStoreSlot slot=(LocalDataStoreSlot)datastorehash[name];
+ lock (datastore_lock) {
+ if (datastorehash == null)
+ InitDataStoreHash ();
+ LocalDataStoreSlot slot=(LocalDataStoreSlot)datastorehash[name];
- if(slot==null) {
- slot=AllocateNamedDataSlot(name);
- }
+ if(slot==null) {
+ slot=AllocateNamedDataSlot(name);
+ }
- return(slot);
+ return(slot);
+ }
}
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private extern static void ResetAbort_internal();
- public static void ResetAbort()
+ [SecurityPermission (SecurityAction.Demand, ControlThread=true)]
+ public static void ResetAbort ()
{
- ResetAbort_internal();
- }
-
-
- public static void SetData(LocalDataStoreSlot slot,
- object data) {
- Hashtable slothash=GetTLSSlotHash();
-
- if(slothash.Contains(slot)) {
- slothash.Remove(slot);
- }
-
- slothash.Add(slot, data);
+ ResetAbort_internal ();
}
[MethodImplAttribute(MethodImplOptions.InternalCall)]
if((millisecondsTimeout<0) && (millisecondsTimeout != Timeout.Infinite)) {
throw new ArgumentException("Negative timeout");
}
- Thread thread=CurrentThread;
-
- thread.set_state(ThreadState.WaitSleepJoin);
-
Sleep_internal(millisecondsTimeout);
- thread.clr_state(ThreadState.WaitSleepJoin);
}
public static void Sleep(TimeSpan timeout) {
throw new ArgumentOutOfRangeException("Timeout out of range");
}
- Thread thread=CurrentThread;
-
- thread.set_state(ThreadState.WaitSleepJoin);
Sleep_internal(ms);
- thread.clr_state(ThreadState.WaitSleepJoin);
}
// Returns the system thread handle
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- private extern IntPtr Thread_internal(ThreadStart start);
+ private extern IntPtr Thread_internal (MulticastDelegate start);
public Thread(ThreadStart start) {
if(start==null) {
}
[MonoTODO]
+#if NET_2_0
+ [Obsolete ("Deprecated in favor of GetApartmentState, SetApartmentState and TrySetApartmentState.")]
+#endif
public ApartmentState ApartmentState {
get {
return(ApartmentState.Unknown);
[MethodImplAttribute (MethodImplOptions.InternalCall)]
private static extern int current_lcid ();
+ [MethodImplAttribute (MethodImplOptions.InternalCall)]
+ private extern CultureInfo GetCachedCurrentCulture ();
+
+ [MethodImplAttribute (MethodImplOptions.InternalCall)]
+ private extern byte[] GetSerializedCurrentCulture ();
+
+ [MethodImplAttribute (MethodImplOptions.InternalCall)]
+ private extern void SetCachedCurrentCulture (CultureInfo culture);
+
+ [MethodImplAttribute (MethodImplOptions.InternalCall)]
+ private extern void SetSerializedCurrentCulture (byte[] culture);
+
+ [MethodImplAttribute (MethodImplOptions.InternalCall)]
+ private extern CultureInfo GetCachedCurrentUICulture ();
+
+ [MethodImplAttribute (MethodImplOptions.InternalCall)]
+ private extern byte[] GetSerializedCurrentUICulture ();
+
+ [MethodImplAttribute (MethodImplOptions.InternalCall)]
+ private extern void SetCachedCurrentUICulture (CultureInfo culture);
+
+ [MethodImplAttribute (MethodImplOptions.InternalCall)]
+ private extern void SetSerializedCurrentUICulture (byte[] culture);
+
/* 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
* Use a boolean to short-circuit this scenario.
*/
private static bool in_currentculture=false;
+
+ static object culture_lock = new object ();
+ /*
+ * Thread objects are shared between appdomains, and CurrentCulture
+ * should always return an object in the calling appdomain. See bug
+ * http://bugzilla.ximian.com/show_bug.cgi?id=50049 for more info.
+ * This is hard to implement correctly and efficiently, so the current
+ * implementation is not perfect: changes made in one appdomain to the
+ * state of the current cultureinfo object are not visible to other
+ * appdomains.
+ */
public CultureInfo CurrentCulture {
get {
- if (current_culture == null) {
- lock (typeof (Thread)) {
- if(current_culture==null) {
- if(in_currentculture==true) {
- /* Bail out */
- current_culture = CultureInfo.InvariantCulture;
- } else {
- in_currentculture=true;
-
- current_culture = CultureInfo.ConstructCurrentCulture ();
- }
- }
-
- in_currentculture=false;
+ if (in_currentculture)
+ /* Bail out */
+ return CultureInfo.InvariantCulture;
+
+ CultureInfo culture = GetCachedCurrentCulture ();
+ if (culture != null)
+ return culture;
+
+ byte[] arr = GetSerializedCurrentCulture ();
+ if (arr == null) {
+ lock (culture_lock) {
+ in_currentculture=true;
+ culture = CultureInfo.ConstructCurrentCulture ();
+ //
+ // Don't serialize the culture in this case to avoid
+ // initializing the serialization infrastructure in the
+ // common case when the culture is not set explicitly.
+ //
+ SetCachedCurrentCulture (culture);
+ in_currentculture = false;
+ return culture;
}
}
-
- return(current_culture);
+
+ /*
+ * No cultureinfo object exists for this domain, so create one
+ * by deserializing the serialized form.
+ */
+ in_currentculture = true;
+ try {
+ BinaryFormatter bf = new BinaryFormatter ();
+ MemoryStream ms = new MemoryStream (arr);
+ culture = (CultureInfo)bf.Deserialize (ms);
+ SetCachedCurrentCulture (culture);
+ } finally {
+ in_currentculture = false;
+ }
+
+ return culture;
}
+ [SecurityPermission (SecurityAction.Demand, ControlThread=true)]
set {
- current_culture = value;
+ if (value == null)
+ throw new ArgumentNullException ("value");
+
+ value.CheckNeutral ();
+ in_currentculture = true;
+ try {
+ BinaryFormatter bf = new BinaryFormatter();
+ MemoryStream ms = new MemoryStream ();
+ bf.Serialize (ms, value);
+
+ SetCachedCurrentCulture (value);
+ SetSerializedCurrentCulture (ms.GetBuffer ());
+ } finally {
+ in_currentculture = false;
+ }
}
}
public CultureInfo CurrentUICulture {
get {
- if (current_ui_culture == null) {
- lock (this) {
- if(current_ui_culture==null) {
- /* We don't
- * distinguish
- * between
- * System and
- * UI cultures
- */
- current_ui_culture = CultureInfo.ConstructCurrentUICulture ();
- }
+ if (in_currentculture)
+ /* Bail out */
+ return CultureInfo.InvariantCulture;
+
+ CultureInfo culture = GetCachedCurrentUICulture ();
+ if (culture != null)
+ return culture;
+
+ byte[] arr = GetSerializedCurrentUICulture ();
+ if (arr == null) {
+ lock (culture_lock) {
+ in_currentculture=true;
+ /* We don't
+ * distinguish
+ * between
+ * System and
+ * UI cultures
+ */
+ culture = CultureInfo.ConstructCurrentUICulture ();
+ //
+ // Don't serialize the culture in this case to avoid
+ // initializing the serialization infrastructure in the
+ // common case when the culture is not set explicitly.
+ //
+ SetCachedCurrentUICulture (culture);
+ in_currentculture = false;
+ return culture;
}
}
-
- return(current_ui_culture);
+
+ /*
+ * No cultureinfo object exists for this domain, so create one
+ * by deserializing the serialized form.
+ */
+ in_currentculture = true;
+ try {
+ BinaryFormatter bf = new BinaryFormatter ();
+ MemoryStream ms = new MemoryStream (arr);
+ culture = (CultureInfo)bf.Deserialize (ms);
+ SetCachedCurrentUICulture (culture);
+ }
+ finally {
+ in_currentculture = false;
+ }
+
+ return culture;
}
set {
- current_ui_culture = value;
+ in_currentculture = true;
+
+ if (value == null)
+ throw new ArgumentNullException ("value");
+
+ try {
+ BinaryFormatter bf = new BinaryFormatter();
+ MemoryStream ms = new MemoryStream ();
+ bf.Serialize (ms, value);
+
+ SetCachedCurrentUICulture (value);
+ SetSerializedCurrentUICulture (ms.GetBuffer ());
+ } finally {
+ in_currentculture = false;
+ }
}
}
public bool IsAlive {
get {
- ThreadState curstate=state;
+ ThreadState curstate = GetState ();
if((curstate & ThreadState.Aborted) != 0 ||
(curstate & ThreadState.Stopped) != 0 ||
public bool IsBackground {
get {
- if((state & ThreadState.Background) != 0) {
- return(true);
- } else {
- return(false);
- }
+ return (GetState () & ThreadState.Background) != 0;
}
set {
- if(value==true) {
- set_state(ThreadState.Background);
+ if (value) {
+ SetState (ThreadState.Background);
} else {
- clr_state(ThreadState.Background);
+ ClrState (ThreadState.Background);
}
}
}
}
set {
- lock (this) {
- if(Name!=null) {
- throw new InvalidOperationException ("Thread.Name can only be set once.");
- }
-
- SetName_internal (value);
- }
+ SetName_internal (value);
}
}
public ThreadState ThreadState {
get {
- return(state);
+ return GetState ();
}
}
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private extern void Abort_internal (object stateInfo);
- public void Abort() {
+ [SecurityPermission (SecurityAction.Demand, ControlThread=true)]
+ public void Abort ()
+ {
Abort_internal (null);
}
- public void Abort(object stateInfo) {
- Abort_internal(stateInfo);
+ [SecurityPermission (SecurityAction.Demand, ControlThread=true)]
+ public void Abort (object stateInfo)
+ {
+ Abort_internal (stateInfo);
}
[MonoTODO]
- public void Interrupt() {
+ [SecurityPermission (SecurityAction.Demand, ControlThread=true)]
+ public void Interrupt ()
+ {
+ throw new NotImplementedException ();
}
// The current thread joins with 'this'. Set ms to 0 to block
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private extern bool Join_internal(int ms, IntPtr handle);
- public void Join() {
- if((state & ThreadState.Unstarted) != 0) {
- throw new ThreadStateException("Thread has not been started");
- }
-
- Thread thread=CurrentThread;
-
- thread.set_state(ThreadState.WaitSleepJoin);
+ public void Join()
+ {
Join_internal(Timeout.Infinite, system_thread_handle);
- thread.clr_state(ThreadState.WaitSleepJoin);
}
- public bool Join(int millisecondsTimeout) {
+ public bool Join(int millisecondsTimeout)
+ {
if (millisecondsTimeout != Timeout.Infinite && millisecondsTimeout < 0)
throw new ArgumentException ("Timeout less than zero", "millisecondsTimeout");
- if((state & ThreadState.Unstarted) != 0) {
- throw new ThreadStateException("Thread has not been started");
- }
-
- Thread thread=CurrentThread;
-
- thread.set_state(ThreadState.WaitSleepJoin);
- bool ret=Join_internal(millisecondsTimeout,
- system_thread_handle);
- thread.clr_state(ThreadState.WaitSleepJoin);
-
- return(ret);
+ return Join_internal(millisecondsTimeout, system_thread_handle);
}
- public bool Join(TimeSpan timeout) {
+ public bool Join(TimeSpan timeout)
+ {
// LAMESPEC: says to throw ArgumentException too
int ms=Convert.ToInt32(timeout.TotalMilliseconds);
if(ms < 0 || ms > Int32.MaxValue) {
throw new ArgumentOutOfRangeException("timeout out of range");
}
- if((state & ThreadState.Unstarted) != 0) {
- throw new ThreadStateException("Thread has not been started");
- }
-
- Thread thread=CurrentThread;
-
- thread.set_state(ThreadState.WaitSleepJoin);
- bool ret=Join_internal(ms, system_thread_handle);
- thread.clr_state(ThreadState.WaitSleepJoin);
-
- return(ret);
+ return Join_internal(ms, system_thread_handle);
}
#if NET_1_1
- [MonoTODO ("seems required for multi-processors systems like Itanium")]
- public static void MemoryBarrier ()
- {
- throw new NotImplementedException ();
- }
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ public extern static void MemoryBarrier ();
#endif
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private extern void Resume_internal();
+#if NET_2_0
+ [Obsolete ("")]
+#endif
+ [SecurityPermission (SecurityAction.Demand, ControlThread=true)]
public void Resume ()
{
- if ((state & ThreadState.Unstarted) != 0 || !IsAlive ||
- ((state & ThreadState.Suspended) == 0 && (state & ThreadState.SuspendRequested) == 0))
- {
- throw new ThreadStateException("Thread has not been started, or is dead");
- }
-
Resume_internal ();
}
[MonoTODO]
+#if NET_2_0
+ [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
+#endif
public static void SpinWait (int iterations)
{
throw new NotImplementedException ();
}
- // Launches the thread
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- private extern void Start_internal(IntPtr handle);
-
public void Start() {
- lock(this) {
- if((state & ThreadState.Unstarted) == 0) {
- throw new ThreadStateException("Thread has already been started");
- }
-
-
- // Thread_internal creates the new thread, but
- // blocks it until Start() is called later.
- system_thread_handle=Thread_internal(threadstart);
-
- if (system_thread_handle == (IntPtr) 0) {
- throw new SystemException ("Thread creation failed");
- }
-
- // Launch this thread
- Start_internal(system_thread_handle);
+ // propagate informations from the original thread to the new thread
+#if NET_2_0
+ if (!ExecutionContext.IsFlowSuppressed ())
+ _ec = ExecutionContext.Capture ();
+#else
+ // before 2.0 this was only used for security (mostly CAS) so we
+ // do this only if the security manager is active
+ if (SecurityManager.SecurityEnabled)
+ _ec = ExecutionContext.Capture ();
+#endif
+ if (CurrentThread._principal != null)
+ _principal = CurrentThread._principal;
- // Mark the thread state as Running
- // (which is all bits
- // cleared). Therefore just remove the
- // Unstarted bit
- clr_state(ThreadState.Unstarted);
- }
+ // Thread_internal creates and starts the new thread,
+ if (Thread_internal(threadstart) == (IntPtr) 0)
+ throw new SystemException ("Thread creation failed.");
}
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private extern void Suspend_internal();
- public void Suspend() {
- if((state & ThreadState.Unstarted) != 0 || !IsAlive) {
- throw new ThreadStateException("Thread has not been started, or is dead");
- }
+#if NET_2_0
+ [Obsolete ("")]
+#endif
+ [SecurityPermission (SecurityAction.Demand, ControlThread=true)]
+ public void Suspend ()
+ {
Suspend_internal ();
}
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private extern void Thread_free_internal(IntPtr handle);
+#if NET_2_0
+ [ReliabilityContract (Consistency.WillNotCorruptState, Cer.Success)]
+#endif
~Thread() {
// Free up the handle
if (system_thread_handle != (IntPtr) 0)
Thread_free_internal(system_thread_handle);
}
- private void set_state(ThreadState set) {
- lock(this) {
- state |= set;
- }
- }
- private void clr_state(ThreadState clr) {
- lock(this) {
- state &= ~clr;
- }
- }
+ [MethodImplAttribute (MethodImplOptions.InternalCall)]
+ extern private void SetState (ThreadState set);
+
+ [MethodImplAttribute (MethodImplOptions.InternalCall)]
+ extern private void ClrState (ThreadState clr);
+
+ [MethodImplAttribute (MethodImplOptions.InternalCall)]
+ extern private ThreadState GetState ();
#if NET_1_1
[CLSCompliant (false)]
[MethodImplAttribute (MethodImplOptions.InternalCall)]
- extern public static byte VolatileRead (ref UIntPtr address);
+ extern public static UIntPtr VolatileRead (ref UIntPtr address);
[MethodImplAttribute (MethodImplOptions.InternalCall)]
extern public static void VolatileWrite (ref byte address, byte value);
extern public static void VolatileWrite (ref UIntPtr address, UIntPtr value);
#endif
+
+#if NET_2_0
+ public Thread (ThreadStart start, int maxStackSize)
+ {
+ if (start == null)
+ throw new ArgumentNullException ("start");
+ if (maxStackSize < 131072)
+ throw new ArgumentException ("< 128 kb", "maxStackSize");
+
+ threadstart = start;
+ stack_size = maxStackSize;
+ }
+
+ public Thread (ParameterizedThreadStart start)
+ {
+ if (start == null)
+ throw new ArgumentNullException ("start");
+
+ threadstart = start;
+ }
+
+ public Thread (ParameterizedThreadStart start, int maxStackSize)
+ {
+ if (start == null)
+ throw new ArgumentNullException ("start");
+ if (maxStackSize < 131072)
+ throw new ArgumentException ("< 128 kb", "maxStackSize");
+
+ threadstart = start;
+ stack_size = maxStackSize;
+ }
+
+ [MonoTODO ("limited to CompressedStack support")]
+ public ExecutionContext ExecutionContext {
+ [ReliabilityContract (Consistency.WillNotCorruptState, Cer.MayFail)]
+ get {
+ if (_ec == null)
+ _ec = new ExecutionContext ();
+ return _ec;
+ }
+ }
+
+ public int ManagedThreadId {
+ [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
+ get { return (int)thread_id; }
+ }
+
+ [MonoTODO]
+ [ReliabilityContract (Consistency.WillNotCorruptState, Cer.MayFail)]
+ public static void BeginCriticalRegion ()
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ [ReliabilityContract (Consistency.WillNotCorruptState, Cer.Success)]
+ public static void EndCriticalRegion ()
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
+ public static void BeginThreadAffinity ()
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
+ public static void EndThreadAffinity ()
+ {
+ throw new NotImplementedException ();
+ }
+
+ //
+ // 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;
+ }
+
+ [MonoTODO]
+ public void SetApartmentState (ApartmentState state)
+ {
+ this.ApartmentState = state;
+ }
+
+ [MonoTODO]
+ public bool TrySetApartmentState (ApartmentState state)
+ {
+ try {
+ this.ApartmentState = state;
+ return true;
+ }
+ catch (ArgumentException) {
+ throw;
+ }
+ catch {
+ return false;
+ }
+ }
+ [ComVisible (false)]
+ public override int GetHashCode ()
+ {
+ // ??? overridden but not guaranteed to be unique ???
+ return (int)thread_id;
+ }
+
+ public void Start (object parameter)
+ {
+ start_obj = parameter;
+ Start ();
+ }
+#else
+ internal ExecutionContext ExecutionContext {
+ get {
+ if (_ec == null)
+ _ec = new ExecutionContext ();
+ return _ec;
+ }
+ }
+#endif
+
+ // NOTE: This method doesn't show in the class library status page because
+ // it cannot be "found" with the StrongNameIdentityPermission for ECMA key.
+ // But it's there!
+ [SecurityPermission (SecurityAction.LinkDemand, UnmanagedCode = true)]
+ [StrongNameIdentityPermission (SecurityAction.LinkDemand, PublicKey="00000000000000000400000000000000")]
+#if NET_2_0
+ [Obsolete ("see CompressedStack class")]
+#endif
+#if NET_1_1
+ public
+#else
+ internal
+#endif
+ CompressedStack GetCompressedStack ()
+ {
+ // Note: returns null if no CompressedStack has been set.
+ // However CompressedStack.GetCompressedStack returns an
+ // (empty?) CompressedStack instance.
+ CompressedStack cs = ExecutionContext.SecurityContext.CompressedStack;
+ return ((cs == null) || cs.IsEmpty ()) ? null : cs.CreateCopy ();
+ }
+
+ // NOTE: This method doesn't show in the class library status page because
+ // it cannot be "found" with the StrongNameIdentityPermission for ECMA key.
+ // But it's there!
+ [SecurityPermission (SecurityAction.LinkDemand, UnmanagedCode = true)]
+ [StrongNameIdentityPermission (SecurityAction.LinkDemand, PublicKey="00000000000000000400000000000000")]
+#if NET_2_0
+ [Obsolete ("see CompressedStack class")]
+#endif
+#if NET_1_1
+ public
+#else
+ internal
+#endif
+ void SetCompressedStack (CompressedStack stack)
+ {
+ ExecutionContext.SecurityContext.CompressedStack = stack;
+ }
+
+#if NET_1_1
+ void _Thread.GetIDsOfNames ([In] ref Guid riid, IntPtr rgszNames, uint cNames, uint lcid, IntPtr rgDispId)
+ {
+ throw new NotImplementedException ();
+ }
+
+ void _Thread.GetTypeInfo (uint iTInfo, uint lcid, IntPtr ppTInfo)
+ {
+ throw new NotImplementedException ();
+ }
+
+ void _Thread.GetTypeInfoCount (out uint pcTInfo)
+ {
+ throw new NotImplementedException ();
+ }
+
+ void _Thread.Invoke (uint dispIdMember, [In] ref Guid riid, uint lcid, short wFlags, IntPtr pDispParams,
+ IntPtr pVarResult, IntPtr pExcepInfo, IntPtr puArgErr)
+ {
+ throw new NotImplementedException ();
+ }
+#endif
}
}