2 // System.Threading.Thread.cs
5 // Dick Porter (dick@ximian.com)
7 // (C) Ximian, Inc. http://www.ximian.com
8 // Copyright (C) 2004 Novell (http://www.novell.com)
12 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 using System.Runtime.Remoting.Contexts;
35 using System.Security.Permissions;
36 using System.Security.Principal;
37 using System.Globalization;
38 using System.Runtime.CompilerServices;
39 using System.Collections;
41 namespace System.Threading
43 public sealed class Thread
45 #region Sync with object.h
46 // stores a thread handle
47 private IntPtr system_thread_handle;
49 private CultureInfo current_culture;
50 private CultureInfo current_ui_culture;
51 private bool threadpool_thread;
52 /* accessed only from unmanaged code */
55 private ThreadState state = ThreadState.Unstarted;
56 private object abort_exc;
57 internal object abort_state;
58 /* thread_id is only accessed from unmanaged code */
59 private int thread_id;
61 /* start_notify is used by the runtime to signal that Start()
64 private IntPtr start_notify;
65 private IntPtr stack_ptr;
66 private IntPtr static_data;
67 private IntPtr jit_data;
68 private IntPtr lock_data;
69 private IntPtr appdomain_refs;
70 private bool interruption_requested;
71 private IntPtr suspend_event;
72 private IntPtr resume_event;
73 private object synch_lock = new Object();
76 private ThreadStart threadstart;
77 private string thread_name=null;
79 private IPrincipal _principal;
81 public static Context CurrentContext {
83 return(AppDomain.InternalGetContext ());
87 public static IPrincipal CurrentPrincipal {
90 Thread th = CurrentThread;
94 p = GetDomain ().DefaultPrincipal;
101 new SecurityPermission (SecurityPermissionFlag.ControlPrincipal).Demand ();
102 CurrentThread._principal = value;
106 // Looks up the object associated with the current thread
107 [MethodImplAttribute(MethodImplOptions.InternalCall)]
108 private extern static Thread CurrentThread_internal();
110 public static Thread CurrentThread {
112 return(CurrentThread_internal());
116 internal static int CurrentThreadId {
118 return CurrentThread.thread_id;
122 // Looks up the slot hash for the current thread
123 [MethodImplAttribute(MethodImplOptions.InternalCall)]
124 private extern static Hashtable SlotHash_lookup();
126 // Stores the slot hash for the current thread
127 [MethodImplAttribute(MethodImplOptions.InternalCall)]
128 private extern static void SlotHash_store(Hashtable slothash);
130 private static Hashtable GetTLSSlotHash() {
131 Hashtable slothash=SlotHash_lookup();
133 // Not synchronised, because this is
134 // thread specific anyway.
135 slothash=new Hashtable();
136 SlotHash_store(slothash);
142 internal static object ResetDataStoreStatus () {
143 Hashtable slothash=SlotHash_lookup();
144 SlotHash_store(null);
148 internal static void RestoreDataStoreStatus (object data) {
149 SlotHash_store((Hashtable)data);
152 public static LocalDataStoreSlot AllocateDataSlot() {
153 LocalDataStoreSlot slot = new LocalDataStoreSlot();
158 // Stores a hash keyed by strings of LocalDataStoreSlot objects
159 static Hashtable datastorehash;
160 private static object datastore_lock = new object ();
162 private static void InitDataStoreHash () {
163 lock (datastore_lock) {
164 if (datastorehash == null) {
165 datastorehash = Hashtable.Synchronized(new Hashtable());
170 public static LocalDataStoreSlot AllocateNamedDataSlot(string name) {
171 lock (datastore_lock) {
172 if (datastorehash == null)
173 InitDataStoreHash ();
174 LocalDataStoreSlot slot = (LocalDataStoreSlot)datastorehash[name];
176 // This exception isnt documented (of
177 // course) but .net throws it
178 throw new ArgumentException("Named data slot already added");
181 slot = new LocalDataStoreSlot();
183 datastorehash.Add(name, slot);
189 public static void FreeNamedDataSlot(string name) {
190 lock (datastore_lock) {
191 if (datastorehash == null)
192 InitDataStoreHash ();
193 LocalDataStoreSlot slot=(LocalDataStoreSlot)datastorehash[name];
196 datastorehash.Remove(slot);
201 public static object GetData(LocalDataStoreSlot slot) {
202 Hashtable slothash=GetTLSSlotHash();
203 return(slothash[slot]);
206 public static AppDomain GetDomain() {
207 return AppDomain.CurrentDomain;
210 [MethodImplAttribute(MethodImplOptions.InternalCall)]
211 public extern static int GetDomainID();
213 public static LocalDataStoreSlot GetNamedDataSlot(string name) {
214 lock (datastore_lock) {
215 if (datastorehash == null)
216 InitDataStoreHash ();
217 LocalDataStoreSlot slot=(LocalDataStoreSlot)datastorehash[name];
220 slot=AllocateNamedDataSlot(name);
227 [MethodImplAttribute(MethodImplOptions.InternalCall)]
228 private extern static void ResetAbort_internal();
230 public static void ResetAbort()
232 ResetAbort_internal();
236 public static void SetData(LocalDataStoreSlot slot,
238 Hashtable slothash=GetTLSSlotHash();
240 if(slothash.Contains(slot)) {
241 slothash.Remove(slot);
244 slothash.Add(slot, data);
247 [MethodImplAttribute(MethodImplOptions.InternalCall)]
248 private extern static void Sleep_internal(int ms);
250 public static void Sleep(int millisecondsTimeout) {
251 if((millisecondsTimeout<0) && (millisecondsTimeout != Timeout.Infinite)) {
252 throw new ArgumentException("Negative timeout");
254 Thread thread=CurrentThread;
255 Sleep_internal(millisecondsTimeout);
258 public static void Sleep(TimeSpan timeout) {
259 // LAMESPEC: says to throw ArgumentException too
260 int ms=Convert.ToInt32(timeout.TotalMilliseconds);
262 if(ms < 0 || ms > Int32.MaxValue) {
263 throw new ArgumentOutOfRangeException("Timeout out of range");
266 Thread thread=CurrentThread;
270 // Returns the system thread handle
271 [MethodImplAttribute(MethodImplOptions.InternalCall)]
272 private extern IntPtr Thread_internal(ThreadStart start);
274 public Thread(ThreadStart start) {
276 throw new ArgumentNullException("Null ThreadStart");
282 public ApartmentState ApartmentState {
284 return(ApartmentState.Unknown);
291 [MethodImplAttribute (MethodImplOptions.InternalCall)]
292 private static extern int current_lcid ();
294 /* If the current_lcid() isn't known by CultureInfo,
295 * it will throw an exception which may cause
296 * String.Concat to try and recursively look up the
297 * CurrentCulture, which will throw an exception, etc.
298 * Use a boolean to short-circuit this scenario.
300 private static bool in_currentculture=false;
302 public CultureInfo CurrentCulture {
304 if (current_culture == null) {
305 lock (typeof (Thread)) {
306 if(current_culture==null) {
307 if(in_currentculture==true) {
309 current_culture = CultureInfo.InvariantCulture;
311 in_currentculture=true;
313 current_culture = CultureInfo.ConstructCurrentCulture ();
317 in_currentculture=false;
321 return(current_culture);
325 current_culture = value;
329 public CultureInfo CurrentUICulture {
331 if (current_ui_culture == null) {
333 if(current_ui_culture==null) {
340 current_ui_culture = CultureInfo.ConstructCurrentUICulture ();
345 return(current_ui_culture);
349 current_ui_culture = value;
353 public bool IsThreadPoolThread {
355 return IsThreadPoolThreadInternal;
359 internal bool IsThreadPoolThreadInternal {
361 return threadpool_thread;
364 threadpool_thread = value;
368 public bool IsAlive {
370 ThreadState curstate=state;
372 if((curstate & ThreadState.Aborted) != 0 ||
373 (curstate & ThreadState.Stopped) != 0 ||
374 (curstate & ThreadState.Unstarted) != 0) {
382 public bool IsBackground {
384 if((state & ThreadState.Background) != 0) {
393 set_state(ThreadState.Background);
395 clr_state(ThreadState.Background);
400 [MethodImplAttribute(MethodImplOptions.InternalCall)]
401 private extern string GetName_internal ();
403 [MethodImplAttribute(MethodImplOptions.InternalCall)]
404 private extern void SetName_internal (String name);
407 * The thread name must be shared by appdomains, so it is stored in
413 return GetName_internal ();
419 throw new InvalidOperationException ("Thread.Name can only be set once.");
422 SetName_internal (value);
428 public ThreadPriority Priority {
430 return(ThreadPriority.Lowest);
437 public ThreadState ThreadState {
443 [MethodImplAttribute(MethodImplOptions.InternalCall)]
444 private extern void Abort_internal (object stateInfo);
446 public void Abort() {
447 Abort_internal (null);
450 public void Abort(object stateInfo) {
451 Abort_internal(stateInfo);
456 public void Interrupt() {
459 // The current thread joins with 'this'. Set ms to 0 to block
460 // until this actually exits.
461 [MethodImplAttribute(MethodImplOptions.InternalCall)]
462 private extern bool Join_internal(int ms, IntPtr handle);
465 if((state & ThreadState.Unstarted) != 0) {
466 throw new ThreadStateException("Thread has not been started");
469 Thread thread=CurrentThread;
471 Join_internal(Timeout.Infinite, system_thread_handle);
474 public bool Join(int millisecondsTimeout) {
475 if (millisecondsTimeout != Timeout.Infinite && millisecondsTimeout < 0)
476 throw new ArgumentException ("Timeout less than zero", "millisecondsTimeout");
478 if((state & ThreadState.Unstarted) != 0) {
479 throw new ThreadStateException("Thread has not been started");
482 Thread thread=CurrentThread;
483 return Join_internal(millisecondsTimeout, system_thread_handle);
486 public bool Join(TimeSpan timeout) {
487 // LAMESPEC: says to throw ArgumentException too
488 int ms=Convert.ToInt32(timeout.TotalMilliseconds);
490 if(ms < 0 || ms > Int32.MaxValue) {
491 throw new ArgumentOutOfRangeException("timeout out of range");
493 if((state & ThreadState.Unstarted) != 0) {
494 throw new ThreadStateException("Thread has not been started");
497 Thread thread=CurrentThread;
498 return Join_internal(ms, system_thread_handle);
502 [MonoTODO ("seems required for multi-processors systems like Itanium")]
503 public static void MemoryBarrier ()
505 throw new NotImplementedException ();
508 [MethodImplAttribute(MethodImplOptions.InternalCall)]
509 private extern void Resume_internal();
511 public void Resume ()
513 if ((state & ThreadState.Unstarted) != 0 || !IsAlive ||
514 ((state & ThreadState.Suspended) == 0 && (state & ThreadState.SuspendRequested) == 0))
516 throw new ThreadStateException("Thread has not been started, or is dead");
523 public static void SpinWait (int iterations)
525 throw new NotImplementedException ();
528 // Launches the thread
529 [MethodImplAttribute(MethodImplOptions.InternalCall)]
530 private extern void Start_internal(IntPtr handle);
532 public void Start() {
534 if((state & ThreadState.Unstarted) == 0) {
535 throw new ThreadStateException("Thread has already been started");
539 // Thread_internal creates the new thread, but
540 // blocks it until Start() is called later.
541 system_thread_handle=Thread_internal(threadstart);
543 if (system_thread_handle == (IntPtr) 0) {
544 throw new SystemException ("Thread creation failed");
547 // Launch this thread
548 Start_internal(system_thread_handle);
550 // Mark the thread state as Running
551 // (which is all bits
552 // cleared). Therefore just remove the
554 clr_state(ThreadState.Unstarted);
558 [MethodImplAttribute(MethodImplOptions.InternalCall)]
559 private extern void Suspend_internal();
561 public void Suspend() {
562 if((state & ThreadState.Unstarted) != 0 || !IsAlive) {
563 throw new ThreadStateException("Thread has not been started, or is dead");
568 // Closes the system thread handle
569 [MethodImplAttribute(MethodImplOptions.InternalCall)]
570 private extern void Thread_free_internal(IntPtr handle);
573 // Free up the handle
574 if (system_thread_handle != (IntPtr) 0)
575 Thread_free_internal(system_thread_handle);
578 private void set_state(ThreadState set) {
583 private void clr_state(ThreadState clr) {
591 [MethodImplAttribute (MethodImplOptions.InternalCall)]
592 extern public static byte VolatileRead (ref byte address);
594 [MethodImplAttribute (MethodImplOptions.InternalCall)]
595 extern public static double VolatileRead (ref double address);
597 [MethodImplAttribute (MethodImplOptions.InternalCall)]
598 extern public static short VolatileRead (ref short address);
600 [MethodImplAttribute (MethodImplOptions.InternalCall)]
601 extern public static int VolatileRead (ref int address);
603 [MethodImplAttribute (MethodImplOptions.InternalCall)]
604 extern public static long VolatileRead (ref long address);
606 [MethodImplAttribute (MethodImplOptions.InternalCall)]
607 extern public static IntPtr VolatileRead (ref IntPtr address);
609 [MethodImplAttribute (MethodImplOptions.InternalCall)]
610 extern public static object VolatileRead (ref object address);
612 [CLSCompliant(false)]
613 [MethodImplAttribute (MethodImplOptions.InternalCall)]
614 extern public static sbyte VolatileRead (ref sbyte address);
616 [MethodImplAttribute (MethodImplOptions.InternalCall)]
617 extern public static float VolatileRead (ref float address);
619 [CLSCompliant (false)]
620 [MethodImplAttribute (MethodImplOptions.InternalCall)]
621 extern public static ushort VolatileRead (ref ushort address);
623 [CLSCompliant (false)]
624 [MethodImplAttribute (MethodImplOptions.InternalCall)]
625 extern public static uint VolatileRead (ref uint address);
627 [CLSCompliant (false)]
628 [MethodImplAttribute (MethodImplOptions.InternalCall)]
629 extern public static ulong VolatileRead (ref ulong address);
631 [CLSCompliant (false)]
632 [MethodImplAttribute (MethodImplOptions.InternalCall)]
633 extern public static UIntPtr VolatileRead (ref UIntPtr address);
635 [MethodImplAttribute (MethodImplOptions.InternalCall)]
636 extern public static void VolatileWrite (ref byte address, byte value);
638 [MethodImplAttribute (MethodImplOptions.InternalCall)]
639 extern public static void VolatileWrite (ref double address, double value);
641 [MethodImplAttribute (MethodImplOptions.InternalCall)]
642 extern public static void VolatileWrite (ref short address, short value);
644 [MethodImplAttribute (MethodImplOptions.InternalCall)]
645 extern public static void VolatileWrite (ref int address, int value);
647 [MethodImplAttribute (MethodImplOptions.InternalCall)]
648 extern public static void VolatileWrite (ref long address, long value);
650 [MethodImplAttribute (MethodImplOptions.InternalCall)]
651 extern public static void VolatileWrite (ref IntPtr address, IntPtr value);
653 [MethodImplAttribute (MethodImplOptions.InternalCall)]
654 extern public static void VolatileWrite (ref object address, object value);
656 [CLSCompliant(false)]
657 [MethodImplAttribute (MethodImplOptions.InternalCall)]
658 extern public static void VolatileWrite (ref sbyte address, sbyte value);
660 [MethodImplAttribute (MethodImplOptions.InternalCall)]
661 extern public static void VolatileWrite (ref float address, float value);
663 [CLSCompliant (false)]
664 [MethodImplAttribute (MethodImplOptions.InternalCall)]
665 extern public static void VolatileWrite (ref ushort address, ushort value);
667 [CLSCompliant (false)]
668 [MethodImplAttribute (MethodImplOptions.InternalCall)]
669 extern public static void VolatileWrite (ref uint address, uint value);
671 [CLSCompliant (false)]
672 [MethodImplAttribute (MethodImplOptions.InternalCall)]
673 extern public static void VolatileWrite (ref ulong address, ulong value);
675 [CLSCompliant (false)]
676 [MethodImplAttribute (MethodImplOptions.InternalCall)]
677 extern public static void VolatileWrite (ref UIntPtr address, UIntPtr value);