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;
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;
37 private IntPtr jit_data;
38 private IntPtr lock_data;
40 private ThreadStart threadstart;
41 private string thread_name=null;
44 public static Context CurrentContext {
46 return(AppDomain.InternalGetContext ());
51 public static IPrincipal CurrentPrincipal {
54 // System.Security.Principal.IPrincipal
55 // not yet implemented
63 // Looks up the object associated with the current thread
64 [MethodImplAttribute(MethodImplOptions.InternalCall)]
65 private extern static Thread CurrentThread_internal();
67 public static Thread CurrentThread {
69 return(CurrentThread_internal());
73 internal static int CurrentThreadId {
75 return CurrentThread.thread_id;
79 // Looks up the slot hash for the current thread
80 [MethodImplAttribute(MethodImplOptions.InternalCall)]
81 private extern static Hashtable SlotHash_lookup();
83 // Stores the slot hash for the current thread
84 [MethodImplAttribute(MethodImplOptions.InternalCall)]
85 private extern static void SlotHash_store(Hashtable slothash);
87 private static Hashtable GetTLSSlotHash() {
88 Hashtable slothash=SlotHash_lookup();
90 // Not synchronised, because this is
91 // thread specific anyway.
92 slothash=new Hashtable();
93 SlotHash_store(slothash);
99 public static LocalDataStoreSlot AllocateDataSlot() {
100 LocalDataStoreSlot slot = new LocalDataStoreSlot();
105 // Stores a hash keyed by strings of LocalDataStoreSlot objects
106 static Hashtable datastorehash;
108 private static void InitDataStoreHash () {
109 lock (typeof (Thread)) {
110 if (datastorehash == null) {
111 datastorehash = Hashtable.Synchronized(new Hashtable());
116 public static LocalDataStoreSlot AllocateNamedDataSlot(string name) {
117 lock (typeof (Thread)) {
118 if (datastorehash == null)
119 InitDataStoreHash ();
120 LocalDataStoreSlot slot = (LocalDataStoreSlot)datastorehash[name];
122 // This exception isnt documented (of
123 // course) but .net throws it
124 throw new ArgumentException("Named data slot already added");
127 slot = new LocalDataStoreSlot();
129 datastorehash.Add(name, slot);
135 public static void FreeNamedDataSlot(string name) {
136 lock (typeof (Thread)) {
137 if (datastorehash == null)
138 InitDataStoreHash ();
139 LocalDataStoreSlot slot=(LocalDataStoreSlot)datastorehash[name];
142 datastorehash.Remove(slot);
147 public static object GetData(LocalDataStoreSlot slot) {
148 Hashtable slothash=GetTLSSlotHash();
149 return(slothash[slot]);
152 public static AppDomain GetDomain() {
153 return AppDomain.CurrentDomain;
156 [MethodImplAttribute(MethodImplOptions.InternalCall)]
157 public extern static int GetDomainID();
159 public static LocalDataStoreSlot GetNamedDataSlot(string name) {
160 if (datastorehash == null)
161 InitDataStoreHash ();
162 LocalDataStoreSlot slot=(LocalDataStoreSlot)datastorehash[name];
165 slot=AllocateNamedDataSlot(name);
171 [MethodImplAttribute(MethodImplOptions.InternalCall)]
172 private extern static void ResetAbort_internal();
174 public static void ResetAbort()
176 Thread thread=CurrentThread;
178 thread.clr_state(ThreadState.AbortRequested);
179 ResetAbort_internal();
183 public static void SetData(LocalDataStoreSlot slot,
185 Hashtable slothash=GetTLSSlotHash();
187 if(slothash.Contains(slot)) {
188 slothash.Remove(slot);
191 slothash.Add(slot, data);
194 [MethodImplAttribute(MethodImplOptions.InternalCall)]
195 private extern static void Sleep_internal(int ms);
197 public static void Sleep(int millisecondsTimeout) {
198 if((millisecondsTimeout<0) && (millisecondsTimeout != Timeout.Infinite)) {
199 throw new ArgumentException("Negative timeout");
201 Thread thread=CurrentThread;
203 thread.set_state(ThreadState.WaitSleepJoin);
205 Sleep_internal(millisecondsTimeout);
206 thread.clr_state(ThreadState.WaitSleepJoin);
209 public static void Sleep(TimeSpan timeout) {
210 // LAMESPEC: says to throw ArgumentException too
211 int ms=Convert.ToInt32(timeout.TotalMilliseconds);
213 if(ms < 0 || ms > Int32.MaxValue) {
214 throw new ArgumentOutOfRangeException("Timeout out of range");
217 Thread thread=CurrentThread;
219 thread.set_state(ThreadState.WaitSleepJoin);
221 thread.clr_state(ThreadState.WaitSleepJoin);
224 // Returns the system thread handle
225 [MethodImplAttribute(MethodImplOptions.InternalCall)]
226 private extern IntPtr Thread_internal(ThreadStart start);
228 public Thread(ThreadStart start) {
230 throw new ArgumentNullException("Null ThreadStart");
234 // This is a two-stage thread launch. Thread_internal
235 // creates the new thread, but blocks it until
236 // Start() is called later.
237 system_thread_handle=Thread_internal(start);
239 // Should throw an exception here if
240 // Thread_internal returns NULL
241 if(system_thread_handle==(IntPtr)0) {
242 throw new SystemException("Thread creation failed");
247 public ApartmentState ApartmentState {
250 return(ApartmentState.Unknown);
258 public CultureInfo CurrentCulture {
260 if (current_culture == null)
261 current_culture = CultureInfo.InvariantCulture;
262 return current_culture;
266 current_culture = value;
271 public CultureInfo CurrentUICulture {
274 return(CurrentCulture);
279 CurrentCulture=value;
283 public bool IsThreadPoolThread {
285 return IsThreadPoolThreadInternal;
289 internal bool IsThreadPoolThreadInternal {
291 return threadpool_thread;
294 threadpool_thread = value;
298 public bool IsAlive {
300 ThreadState curstate=state;
302 if((curstate & ThreadState.Aborted) != 0 ||
303 (curstate & ThreadState.Stopped) != 0 ||
304 (curstate & ThreadState.Unstarted) != 0) {
312 public bool IsBackground {
314 if((state & ThreadState.Background) != 0) {
323 set_state(ThreadState.Background);
325 clr_state(ThreadState.Background);
341 public ThreadPriority Priority {
344 return(ThreadPriority.Lowest);
351 public ThreadState ThreadState {
357 [MethodImplAttribute(MethodImplOptions.InternalCall)]
358 private extern void Abort_internal (object stateInfo);
360 public void Abort() {
361 set_state(ThreadState.AbortRequested);
362 Abort_internal (null);
365 public void Abort(object stateInfo) {
366 set_state(ThreadState.AbortRequested);
367 Abort_internal(stateInfo);
372 public void Interrupt() {
376 // The current thread joins with 'this'. Set ms to 0 to block
377 // until this actually exits.
378 [MethodImplAttribute(MethodImplOptions.InternalCall)]
379 private extern bool Join_internal(int ms, IntPtr handle);
382 if((state & ThreadState.Unstarted) != 0) {
383 throw new ThreadStateException("Thread has not been started");
386 Thread thread=CurrentThread;
388 thread.set_state(ThreadState.WaitSleepJoin);
389 Join_internal(Timeout.Infinite, system_thread_handle);
390 thread.clr_state(ThreadState.WaitSleepJoin);
393 public bool Join(int millisecondsTimeout) {
394 if (millisecondsTimeout != Timeout.Infinite && millisecondsTimeout < 0)
395 throw new ArgumentException ("Timeout less than zero", "millisecondsTimeout");
397 if((state & ThreadState.Unstarted) != 0) {
398 throw new ThreadStateException("Thread has not been started");
401 Thread thread=CurrentThread;
403 thread.set_state(ThreadState.WaitSleepJoin);
404 bool ret=Join_internal(millisecondsTimeout,
405 system_thread_handle);
406 thread.clr_state(ThreadState.WaitSleepJoin);
411 public bool Join(TimeSpan timeout) {
412 // LAMESPEC: says to throw ArgumentException too
413 int ms=Convert.ToInt32(timeout.TotalMilliseconds);
415 if(ms < 0 || ms > Int32.MaxValue) {
416 throw new ArgumentOutOfRangeException("timeout out of range");
418 if((state & ThreadState.Unstarted) != 0) {
419 throw new ThreadStateException("Thread has not been started");
422 Thread thread=CurrentThread;
424 thread.set_state(ThreadState.WaitSleepJoin);
425 bool ret=Join_internal(ms, system_thread_handle);
426 thread.clr_state(ThreadState.WaitSleepJoin);
432 public void Resume() {
433 throw new NotImplementedException ();
436 // Launches the thread
437 [MethodImplAttribute(MethodImplOptions.InternalCall)]
438 private extern void Start_internal(IntPtr handle);
440 public void Start() {
442 if((state & ThreadState.Unstarted) == 0) {
443 throw new ThreadStateException("Thread has already been started");
446 // Launch this thread
447 Start_internal(system_thread_handle);
449 // Mark the thread state as Running
450 // (which is all bits
451 // cleared). Therefore just remove the
453 clr_state(ThreadState.Unstarted);
458 public void Suspend() {
459 if((state & ThreadState.Unstarted) != 0 || !IsAlive) {
460 throw new ThreadStateException("Thread has not been started, or is dead");
463 set_state(ThreadState.SuspendRequested);
464 // FIXME - somehow let the interpreter know that
465 // this thread should now suspend
466 Console.WriteLine ("WARNING: Thread.Suspend () partially implemented");
469 // Closes the system thread handle
470 [MethodImplAttribute(MethodImplOptions.InternalCall)]
471 private extern void Thread_free_internal(IntPtr handle);
474 // Free up the handle
475 Thread_free_internal(system_thread_handle);
478 private void set_state(ThreadState set) {
483 private void clr_state(ThreadState clr) {