2 // System.Threading.Thread.cs
5 // Dick Porter (dick@ximian.com)
7 // (C) Ximian, Inc. http://www.ximian.com
10 using System.Runtime.Remoting.Contexts;
11 using System.Security.Principal;
12 using System.Globalization;
13 using System.Runtime.CompilerServices;
14 using System.Collections;
16 namespace System.Threading
18 public sealed class Thread
20 // stores a thread handle
21 private IntPtr system_thread_handle;
23 private CultureInfo current_culture;
24 private bool threadpool_thread = false;
25 private ThreadState state = ThreadState.Unstarted;
26 private object abort_exc;
27 internal object abort_state;
28 /* thread_id is only accessed from unmanaged code */
29 private int thread_id;
31 /* start_notify is used by the runtime to signal that Start()
34 private IntPtr start_notify;
35 private IntPtr stack_ptr;
36 private IntPtr static_data;
38 public static Context CurrentContext {
40 return(AppDomain.InternalGetContext ());
45 public static IPrincipal CurrentPrincipal {
48 // System.Security.Principal.IPrincipal
49 // not yet implemented
57 // Looks up the object associated with the current thread
58 [MethodImplAttribute(MethodImplOptions.InternalCall)]
59 private extern static Thread CurrentThread_internal();
61 public static Thread CurrentThread {
63 return(CurrentThread_internal());
67 internal static int CurrentThreadId {
69 return CurrentThread.thread_id;
73 // Looks up the slot hash for the current thread
74 [MethodImplAttribute(MethodImplOptions.InternalCall)]
75 private extern static Hashtable SlotHash_lookup();
77 // Stores the slot hash for the current thread
78 [MethodImplAttribute(MethodImplOptions.InternalCall)]
79 private extern static void SlotHash_store(Hashtable slothash);
81 private static Hashtable GetTLSSlotHash() {
82 Hashtable slothash=SlotHash_lookup();
84 // Not synchronised, because this is
85 // thread specific anyway.
86 slothash=new Hashtable();
87 SlotHash_store(slothash);
93 public static LocalDataStoreSlot AllocateDataSlot() {
94 LocalDataStoreSlot slot = new LocalDataStoreSlot();
99 // Stores a hash keyed by strings of LocalDataStoreSlot objects
100 static Hashtable datastorehash;
102 private static void InitDataStoreHash () {
103 lock (typeof (Thread)) {
104 if (datastorehash == null) {
105 datastorehash = Hashtable.Synchronized(new Hashtable());
110 public static LocalDataStoreSlot AllocateNamedDataSlot(string name) {
111 if (datastorehash == null)
112 InitDataStoreHash ();
113 LocalDataStoreSlot slot = (LocalDataStoreSlot)datastorehash[name];
115 // This exception isnt documented (of
116 // course) but .net throws it
117 throw new ArgumentException("Named data slot already added");
120 slot = new LocalDataStoreSlot();
122 datastorehash.Add(name, slot);
127 public static void FreeNamedDataSlot(string name) {
128 if (datastorehash == null)
129 InitDataStoreHash ();
130 LocalDataStoreSlot slot=(LocalDataStoreSlot)datastorehash[name];
133 datastorehash.Remove(slot);
137 public static object GetData(LocalDataStoreSlot slot) {
138 Hashtable slothash=GetTLSSlotHash();
139 return(slothash[slot]);
142 public static AppDomain GetDomain() {
143 return AppDomain.CurrentDomain;
146 [MethodImplAttribute(MethodImplOptions.InternalCall)]
147 public extern static int GetDomainID();
149 public static LocalDataStoreSlot GetNamedDataSlot(string name) {
150 if (datastorehash == null)
151 InitDataStoreHash ();
152 LocalDataStoreSlot slot=(LocalDataStoreSlot)datastorehash[name];
155 slot=AllocateNamedDataSlot(name);
161 [MethodImplAttribute(MethodImplOptions.InternalCall)]
162 private extern static void ResetAbort_internal();
164 public static void ResetAbort()
166 Thread thread=CurrentThread;
168 thread.clr_state(ThreadState.AbortRequested);
169 ResetAbort_internal();
173 public static void SetData(LocalDataStoreSlot slot,
175 Hashtable slothash=GetTLSSlotHash();
177 if(slothash[slot]!=null) {
178 slothash.Remove(slot);
181 slothash.Add(slot, data);
184 [MethodImplAttribute(MethodImplOptions.InternalCall)]
185 private extern static void Sleep_internal(int ms);
187 public static void Sleep(int millisecondsTimeout) {
188 if((millisecondsTimeout<0) && (millisecondsTimeout != Timeout.Infinite)) {
189 throw new ArgumentException("Negative timeout");
191 Thread thread=CurrentThread;
193 thread.set_state(ThreadState.WaitSleepJoin);
195 Sleep_internal(millisecondsTimeout);
196 thread.clr_state(ThreadState.WaitSleepJoin);
199 public static void Sleep(TimeSpan timeout) {
200 // LAMESPEC: says to throw ArgumentException too
201 int ms=Convert.ToInt32(timeout.TotalMilliseconds);
203 if(ms < 0 || ms > Int32.MaxValue) {
204 throw new ArgumentOutOfRangeException("Timeout out of range");
207 Thread thread=CurrentThread;
209 thread.set_state(ThreadState.WaitSleepJoin);
211 thread.clr_state(ThreadState.WaitSleepJoin);
214 // Returns the system thread handle
215 [MethodImplAttribute(MethodImplOptions.InternalCall)]
216 private extern IntPtr Thread_internal(ThreadStart start);
218 private ThreadStart threadstart;
220 public Thread(ThreadStart start) {
222 throw new ArgumentNullException("Null ThreadStart");
226 // This is a two-stage thread launch. Thread_internal
227 // creates the new thread, but blocks it until
228 // Start() is called later.
229 system_thread_handle=Thread_internal(start);
231 // Should throw an exception here if
232 // Thread_internal returns NULL
236 public ApartmentState ApartmentState {
239 return(ApartmentState.Unknown);
247 public CultureInfo CurrentCulture {
249 if (current_culture == null)
250 current_culture = CultureInfo.InvariantCulture;
251 return current_culture;
255 current_culture = value;
260 public CultureInfo CurrentUICulture {
263 return(CurrentCulture);
268 CurrentCulture=value;
272 public bool IsThreadPoolThread {
274 return IsThreadPoolThreadInternal;
278 internal bool IsThreadPoolThreadInternal {
280 return threadpool_thread;
283 threadpool_thread = value;
287 public bool IsAlive {
289 ThreadState curstate=state;
291 if((curstate & ThreadState.Aborted) != 0 ||
292 (curstate & ThreadState.Stopped) != 0 ||
293 (curstate & ThreadState.Unstarted) != 0) {
301 public bool IsBackground {
303 if((state & ThreadState.Background) != 0) {
312 set_state(ThreadState.Background);
314 clr_state(ThreadState.Background);
319 private string thread_name=null;
332 public ThreadPriority Priority {
335 return(ThreadPriority.Lowest);
342 public ThreadState ThreadState {
348 [MethodImplAttribute(MethodImplOptions.InternalCall)]
349 private extern void Abort_internal (object stateInfo);
351 public void Abort() {
352 set_state(ThreadState.AbortRequested);
353 Abort_internal (null);
356 public void Abort(object stateInfo) {
357 set_state(ThreadState.AbortRequested);
358 Abort_internal(stateInfo);
363 public void Interrupt() {
367 // The current thread joins with 'this'. Set ms to 0 to block
368 // until this actually exits.
369 [MethodImplAttribute(MethodImplOptions.InternalCall)]
370 private extern bool Join_internal(int ms, IntPtr handle);
373 if((state & ThreadState.Unstarted) != 0) {
374 throw new ThreadStateException("Thread has not been started");
377 Thread thread=CurrentThread;
379 thread.set_state(ThreadState.WaitSleepJoin);
380 Join_internal(Timeout.Infinite, system_thread_handle);
381 thread.clr_state(ThreadState.WaitSleepJoin);
384 public bool Join(int millisecondsTimeout) {
385 if (millisecondsTimeout != Timeout.Infinite && millisecondsTimeout < 0)
386 throw new ArgumentException ("Timeout less than zero", "millisecondsTimeout");
388 if((state & ThreadState.Unstarted) != 0) {
389 throw new ThreadStateException("Thread has not been started");
392 Thread thread=CurrentThread;
394 thread.set_state(ThreadState.WaitSleepJoin);
395 bool ret=Join_internal(millisecondsTimeout,
396 system_thread_handle);
397 thread.clr_state(ThreadState.WaitSleepJoin);
402 public bool Join(TimeSpan timeout) {
403 // LAMESPEC: says to throw ArgumentException too
404 int ms=Convert.ToInt32(timeout.TotalMilliseconds);
406 if(ms < 0 || ms > Int32.MaxValue) {
407 throw new ArgumentOutOfRangeException("timeout out of range");
409 if((state & ThreadState.Unstarted) != 0) {
410 throw new ThreadStateException("Thread has not been started");
413 Thread thread=CurrentThread;
415 thread.set_state(ThreadState.WaitSleepJoin);
416 bool ret=Join_internal(ms, system_thread_handle);
417 thread.clr_state(ThreadState.WaitSleepJoin);
423 public void Resume() {
424 throw new NotImplementedException ();
427 // Launches the thread
428 [MethodImplAttribute(MethodImplOptions.InternalCall)]
429 private extern void Start_internal(IntPtr handle);
431 public void Start() {
433 if((state & ThreadState.Unstarted) == 0) {
434 throw new ThreadStateException("Thread has already been started");
437 // Launch this thread
438 Start_internal(system_thread_handle);
440 // Mark the thread state as Running
441 // (which is all bits
442 // cleared). Therefore just remove the
444 clr_state(ThreadState.Unstarted);
449 public void Suspend() {
450 if((state & ThreadState.Unstarted) != 0 || !IsAlive) {
451 throw new ThreadStateException("Thread has not been started, or is dead");
454 set_state(ThreadState.SuspendRequested);
455 // FIXME - somehow let the interpreter know that
456 // this thread should now suspend
457 Console.WriteLine ("WARNING: Thread.Suspend () partially implemented");
460 // Closes the system thread handle
461 [MethodImplAttribute(MethodImplOptions.InternalCall)]
462 private extern void Thread_free_internal(IntPtr handle);
465 // Free up the handle
466 Thread_free_internal(system_thread_handle);
469 private void set_state(ThreadState set) {
474 private void clr_state(ThreadState clr) {