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;
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 if (datastorehash == null)
118 InitDataStoreHash ();
119 LocalDataStoreSlot slot = (LocalDataStoreSlot)datastorehash[name];
121 // This exception isnt documented (of
122 // course) but .net throws it
123 throw new ArgumentException("Named data slot already added");
126 slot = new LocalDataStoreSlot();
128 datastorehash.Add(name, slot);
133 public static void FreeNamedDataSlot(string name) {
134 if (datastorehash == null)
135 InitDataStoreHash ();
136 LocalDataStoreSlot slot=(LocalDataStoreSlot)datastorehash[name];
139 datastorehash.Remove(slot);
143 public static object GetData(LocalDataStoreSlot slot) {
144 Hashtable slothash=GetTLSSlotHash();
145 return(slothash[slot]);
148 public static AppDomain GetDomain() {
149 return AppDomain.CurrentDomain;
152 [MethodImplAttribute(MethodImplOptions.InternalCall)]
153 public extern static int GetDomainID();
155 public static LocalDataStoreSlot GetNamedDataSlot(string name) {
156 if (datastorehash == null)
157 InitDataStoreHash ();
158 LocalDataStoreSlot slot=(LocalDataStoreSlot)datastorehash[name];
161 slot=AllocateNamedDataSlot(name);
167 [MethodImplAttribute(MethodImplOptions.InternalCall)]
168 private extern static void ResetAbort_internal();
170 public static void ResetAbort()
172 Thread thread=CurrentThread;
174 thread.clr_state(ThreadState.AbortRequested);
175 ResetAbort_internal();
179 public static void SetData(LocalDataStoreSlot slot,
181 Hashtable slothash=GetTLSSlotHash();
183 if(slothash.Contains(slot)) {
184 slothash.Remove(slot);
187 slothash.Add(slot, data);
190 [MethodImplAttribute(MethodImplOptions.InternalCall)]
191 private extern static void Sleep_internal(int ms);
193 public static void Sleep(int millisecondsTimeout) {
194 if((millisecondsTimeout<0) && (millisecondsTimeout != Timeout.Infinite)) {
195 throw new ArgumentException("Negative timeout");
197 Thread thread=CurrentThread;
199 thread.set_state(ThreadState.WaitSleepJoin);
201 Sleep_internal(millisecondsTimeout);
202 thread.clr_state(ThreadState.WaitSleepJoin);
205 public static void Sleep(TimeSpan timeout) {
206 // LAMESPEC: says to throw ArgumentException too
207 int ms=Convert.ToInt32(timeout.TotalMilliseconds);
209 if(ms < 0 || ms > Int32.MaxValue) {
210 throw new ArgumentOutOfRangeException("Timeout out of range");
213 Thread thread=CurrentThread;
215 thread.set_state(ThreadState.WaitSleepJoin);
217 thread.clr_state(ThreadState.WaitSleepJoin);
220 // Returns the system thread handle
221 [MethodImplAttribute(MethodImplOptions.InternalCall)]
222 private extern IntPtr Thread_internal(ThreadStart start);
224 public Thread(ThreadStart start) {
226 throw new ArgumentNullException("Null ThreadStart");
230 // This is a two-stage thread launch. Thread_internal
231 // creates the new thread, but blocks it until
232 // Start() is called later.
233 system_thread_handle=Thread_internal(start);
235 // Should throw an exception here if
236 // Thread_internal returns NULL
237 if(system_thread_handle==(IntPtr)0) {
238 throw new SystemException("Thread creation failed");
243 public ApartmentState ApartmentState {
246 return(ApartmentState.Unknown);
254 public CultureInfo CurrentCulture {
256 if (current_culture == null)
257 current_culture = CultureInfo.InvariantCulture;
258 return current_culture;
262 current_culture = value;
267 public CultureInfo CurrentUICulture {
270 return(CurrentCulture);
275 CurrentCulture=value;
279 public bool IsThreadPoolThread {
281 return IsThreadPoolThreadInternal;
285 internal bool IsThreadPoolThreadInternal {
287 return threadpool_thread;
290 threadpool_thread = value;
294 public bool IsAlive {
296 ThreadState curstate=state;
298 if((curstate & ThreadState.Aborted) != 0 ||
299 (curstate & ThreadState.Stopped) != 0 ||
300 (curstate & ThreadState.Unstarted) != 0) {
308 public bool IsBackground {
310 if((state & ThreadState.Background) != 0) {
319 set_state(ThreadState.Background);
321 clr_state(ThreadState.Background);
337 public ThreadPriority Priority {
340 return(ThreadPriority.Lowest);
347 public ThreadState ThreadState {
353 [MethodImplAttribute(MethodImplOptions.InternalCall)]
354 private extern void Abort_internal (object stateInfo);
356 public void Abort() {
357 set_state(ThreadState.AbortRequested);
358 Abort_internal (null);
361 public void Abort(object stateInfo) {
362 set_state(ThreadState.AbortRequested);
363 Abort_internal(stateInfo);
368 public void Interrupt() {
372 // The current thread joins with 'this'. Set ms to 0 to block
373 // until this actually exits.
374 [MethodImplAttribute(MethodImplOptions.InternalCall)]
375 private extern bool Join_internal(int ms, IntPtr handle);
378 if((state & ThreadState.Unstarted) != 0) {
379 throw new ThreadStateException("Thread has not been started");
382 Thread thread=CurrentThread;
384 thread.set_state(ThreadState.WaitSleepJoin);
385 Join_internal(Timeout.Infinite, system_thread_handle);
386 thread.clr_state(ThreadState.WaitSleepJoin);
389 public bool Join(int millisecondsTimeout) {
390 if (millisecondsTimeout != Timeout.Infinite && millisecondsTimeout < 0)
391 throw new ArgumentException ("Timeout less than zero", "millisecondsTimeout");
393 if((state & ThreadState.Unstarted) != 0) {
394 throw new ThreadStateException("Thread has not been started");
397 Thread thread=CurrentThread;
399 thread.set_state(ThreadState.WaitSleepJoin);
400 bool ret=Join_internal(millisecondsTimeout,
401 system_thread_handle);
402 thread.clr_state(ThreadState.WaitSleepJoin);
407 public bool Join(TimeSpan timeout) {
408 // LAMESPEC: says to throw ArgumentException too
409 int ms=Convert.ToInt32(timeout.TotalMilliseconds);
411 if(ms < 0 || ms > Int32.MaxValue) {
412 throw new ArgumentOutOfRangeException("timeout out of range");
414 if((state & ThreadState.Unstarted) != 0) {
415 throw new ThreadStateException("Thread has not been started");
418 Thread thread=CurrentThread;
420 thread.set_state(ThreadState.WaitSleepJoin);
421 bool ret=Join_internal(ms, system_thread_handle);
422 thread.clr_state(ThreadState.WaitSleepJoin);
428 public void Resume() {
429 throw new NotImplementedException ();
432 // Launches the thread
433 [MethodImplAttribute(MethodImplOptions.InternalCall)]
434 private extern void Start_internal(IntPtr handle);
436 public void Start() {
438 if((state & ThreadState.Unstarted) == 0) {
439 throw new ThreadStateException("Thread has already been started");
442 // Launch this thread
443 Start_internal(system_thread_handle);
445 // Mark the thread state as Running
446 // (which is all bits
447 // cleared). Therefore just remove the
449 clr_state(ThreadState.Unstarted);
454 public void Suspend() {
455 if((state & ThreadState.Unstarted) != 0 || !IsAlive) {
456 throw new ThreadStateException("Thread has not been started, or is dead");
459 set_state(ThreadState.SuspendRequested);
460 // FIXME - somehow let the interpreter know that
461 // this thread should now suspend
462 Console.WriteLine ("WARNING: Thread.Suspend () partially implemented");
465 // Closes the system thread handle
466 [MethodImplAttribute(MethodImplOptions.InternalCall)]
467 private extern void Thread_free_internal(IntPtr handle);
470 // Free up the handle
471 Thread_free_internal(system_thread_handle);
474 private void set_state(ThreadState set) {
479 private void clr_state(ThreadState clr) {