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
;
42 using System
.Runtime
.ConstrainedExecution
;
43 using System
.Runtime
.InteropServices
;
46 namespace System
.Threading
48 public sealed class Thread
50 #region Sync with object.h
51 // stores a thread handle
52 private IntPtr system_thread_handle
;
54 private CultureInfo current_culture
;
55 private CultureInfo current_ui_culture
;
56 private bool threadpool_thread
;
57 /* accessed only from unmanaged code */
60 private ThreadState state
= ThreadState
.Unstarted
;
61 private object abort_exc
;
62 internal object abort_state
;
63 /* thread_id is only accessed from unmanaged code */
64 private int thread_id
;
66 /* start_notify is used by the runtime to signal that Start()
69 private IntPtr start_notify
;
70 private IntPtr stack_ptr
;
71 private IntPtr static_data
;
72 private IntPtr jit_data
;
73 private IntPtr lock_data
;
74 private IntPtr appdomain_refs
;
75 private bool interruption_requested
;
76 private IntPtr suspend_event
;
77 private IntPtr resume_event
;
78 private object synch_lock
= new Object();
81 private ThreadStart threadstart
;
82 private string thread_name
=null;
84 private IPrincipal _principal
;
86 public static Context CurrentContext
{
88 return(AppDomain
.InternalGetContext ());
92 public static IPrincipal CurrentPrincipal
{
95 Thread th
= CurrentThread
;
99 p
= GetDomain ().DefaultPrincipal
;
105 [SecurityPermission (SecurityAction
.Demand
, Flags
=SecurityPermissionFlag
.ControlPolicy
)]
107 CurrentThread
._principal
= value;
111 // Looks up the object associated with the current thread
112 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
113 private extern static Thread
CurrentThread_internal();
115 public static Thread CurrentThread
{
117 [ReliabilityContract (Consistency
.WillNotCorruptState
, CER
.MayFail
)]
120 return(CurrentThread_internal());
124 internal static int CurrentThreadId
{
126 return CurrentThread
.thread_id
;
130 // Looks up the slot hash for the current thread
131 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
132 private extern static Hashtable
SlotHash_lookup();
134 // Stores the slot hash for the current thread
135 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
136 private extern static void SlotHash_store(Hashtable slothash
);
138 private static Hashtable
GetTLSSlotHash() {
139 Hashtable slothash
=SlotHash_lookup();
141 // Not synchronised, because this is
142 // thread specific anyway.
143 slothash
=new Hashtable();
144 SlotHash_store(slothash
);
150 internal static object ResetDataStoreStatus () {
151 Hashtable slothash
=SlotHash_lookup();
152 SlotHash_store(null);
156 internal static void RestoreDataStoreStatus (object data
) {
157 SlotHash_store((Hashtable
)data
);
160 public static LocalDataStoreSlot
AllocateDataSlot() {
161 LocalDataStoreSlot slot
= new LocalDataStoreSlot();
166 // Stores a hash keyed by strings of LocalDataStoreSlot objects
167 static Hashtable datastorehash
;
168 private static object datastore_lock
= new object ();
170 private static void InitDataStoreHash () {
171 lock (datastore_lock
) {
172 if (datastorehash
== null) {
173 datastorehash
= Hashtable
.Synchronized(new Hashtable());
178 public static LocalDataStoreSlot
AllocateNamedDataSlot(string name
) {
179 lock (datastore_lock
) {
180 if (datastorehash
== null)
181 InitDataStoreHash ();
182 LocalDataStoreSlot slot
= (LocalDataStoreSlot
)datastorehash
[name
];
184 // This exception isnt documented (of
185 // course) but .net throws it
186 throw new ArgumentException("Named data slot already added");
189 slot
= new LocalDataStoreSlot();
191 datastorehash
.Add(name
, slot
);
197 public static void FreeNamedDataSlot(string name
) {
198 lock (datastore_lock
) {
199 if (datastorehash
== null)
200 InitDataStoreHash ();
201 LocalDataStoreSlot slot
=(LocalDataStoreSlot
)datastorehash
[name
];
204 datastorehash
.Remove(slot
);
209 public static object GetData(LocalDataStoreSlot slot
) {
210 Hashtable slothash
=GetTLSSlotHash();
211 return(slothash
[slot
]);
214 public static AppDomain
GetDomain() {
215 return AppDomain
.CurrentDomain
;
218 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
219 public extern static int GetDomainID();
221 public static LocalDataStoreSlot
GetNamedDataSlot(string name
) {
222 lock (datastore_lock
) {
223 if (datastorehash
== null)
224 InitDataStoreHash ();
225 LocalDataStoreSlot slot
=(LocalDataStoreSlot
)datastorehash
[name
];
228 slot
=AllocateNamedDataSlot(name
);
235 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
236 private extern static void ResetAbort_internal();
238 public static void ResetAbort()
240 ResetAbort_internal();
244 public static void SetData(LocalDataStoreSlot slot
,
246 Hashtable slothash
=GetTLSSlotHash();
248 if(slothash
.Contains(slot
)) {
249 slothash
.Remove(slot
);
252 slothash
.Add(slot
, data
);
255 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
256 private extern static void Sleep_internal(int ms
);
258 public static void Sleep(int millisecondsTimeout
) {
259 if((millisecondsTimeout
<0) && (millisecondsTimeout
!= Timeout
.Infinite
)) {
260 throw new ArgumentException("Negative timeout");
262 Thread thread
=CurrentThread
;
263 Sleep_internal(millisecondsTimeout
);
266 public static void Sleep(TimeSpan timeout
) {
267 // LAMESPEC: says to throw ArgumentException too
268 int ms
=Convert
.ToInt32(timeout
.TotalMilliseconds
);
270 if(ms
< 0 || ms
> Int32
.MaxValue
) {
271 throw new ArgumentOutOfRangeException("Timeout out of range");
274 Thread thread
=CurrentThread
;
278 // Returns the system thread handle
279 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
280 private extern IntPtr
Thread_internal(ThreadStart start
);
282 public Thread(ThreadStart start
) {
284 throw new ArgumentNullException("Null ThreadStart");
293 public ApartmentState ApartmentState
{
295 return(ApartmentState
.Unknown
);
302 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
303 private static extern int current_lcid ();
305 /* If the current_lcid() isn't known by CultureInfo,
306 * it will throw an exception which may cause
307 * String.Concat to try and recursively look up the
308 * CurrentCulture, which will throw an exception, etc.
309 * Use a boolean to short-circuit this scenario.
311 private static bool in_currentculture
=false;
313 public CultureInfo CurrentCulture
{
315 if (current_culture
== null) {
316 lock (typeof (Thread
)) {
317 if(current_culture
==null) {
318 if(in_currentculture
==true) {
320 current_culture
= CultureInfo
.InvariantCulture
;
322 in_currentculture
=true;
324 current_culture
= CultureInfo
.ConstructCurrentCulture ();
328 in_currentculture
=false;
332 return(current_culture
);
336 current_culture
= value;
340 public CultureInfo CurrentUICulture
{
342 if (current_ui_culture
== null) {
344 if(current_ui_culture
==null) {
351 current_ui_culture
= CultureInfo
.ConstructCurrentUICulture ();
356 return(current_ui_culture
);
360 current_ui_culture
= value;
364 public bool IsThreadPoolThread
{
366 return IsThreadPoolThreadInternal
;
370 internal bool IsThreadPoolThreadInternal
{
372 return threadpool_thread
;
375 threadpool_thread
= value;
379 public bool IsAlive
{
381 ThreadState curstate
=state
;
383 if((curstate
& ThreadState
.Aborted
) != 0 ||
384 (curstate
& ThreadState
.Stopped
) != 0 ||
385 (curstate
& ThreadState
.Unstarted
) != 0) {
393 public bool IsBackground
{
395 if((state
& ThreadState
.Background
) != 0) {
404 set_state(ThreadState
.Background
);
406 clr_state(ThreadState
.Background
);
411 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
412 private extern string GetName_internal ();
414 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
415 private extern void SetName_internal (String name
);
418 * The thread name must be shared by appdomains, so it is stored in
424 return GetName_internal ();
430 throw new InvalidOperationException ("Thread.Name can only be set once.");
433 SetName_internal (value);
439 public ThreadPriority Priority
{
441 return(ThreadPriority
.Lowest
);
448 public ThreadState ThreadState
{
454 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
455 private extern void Abort_internal (object stateInfo
);
457 public void Abort() {
458 Abort_internal (null);
461 public void Abort(object stateInfo
) {
462 Abort_internal(stateInfo
);
467 public void Interrupt() {
470 // The current thread joins with 'this'. Set ms to 0 to block
471 // until this actually exits.
472 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
473 private extern bool Join_internal(int ms
, IntPtr handle
);
476 if((state
& ThreadState
.Unstarted
) != 0) {
477 throw new ThreadStateException("Thread has not been started");
480 Thread thread
=CurrentThread
;
482 Join_internal(Timeout
.Infinite
, system_thread_handle
);
485 public bool Join(int millisecondsTimeout
) {
486 if (millisecondsTimeout
!= Timeout
.Infinite
&& millisecondsTimeout
< 0)
487 throw new ArgumentException ("Timeout less than zero", "millisecondsTimeout");
489 if((state
& ThreadState
.Unstarted
) != 0) {
490 throw new ThreadStateException("Thread has not been started");
493 Thread thread
=CurrentThread
;
494 return Join_internal(millisecondsTimeout
, system_thread_handle
);
497 public bool Join(TimeSpan timeout
) {
498 // LAMESPEC: says to throw ArgumentException too
499 int ms
=Convert
.ToInt32(timeout
.TotalMilliseconds
);
501 if(ms
< 0 || ms
> Int32
.MaxValue
) {
502 throw new ArgumentOutOfRangeException("timeout out of range");
504 if((state
& ThreadState
.Unstarted
) != 0) {
505 throw new ThreadStateException("Thread has not been started");
508 Thread thread
=CurrentThread
;
509 return Join_internal(ms
, system_thread_handle
);
513 [MonoTODO ("seems required for multi-processors systems like Itanium")]
514 public static void MemoryBarrier ()
516 throw new NotImplementedException ();
519 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
520 private extern void Resume_internal();
525 public void Resume ()
527 if ((state
& ThreadState
.Unstarted
) != 0 || !IsAlive
||
528 ((state
& ThreadState
.Suspended
) == 0 && (state
& ThreadState
.SuspendRequested
) == 0))
530 throw new ThreadStateException("Thread has not been started, or is dead");
537 public static void SpinWait (int iterations
)
539 throw new NotImplementedException ();
542 // Launches the thread
543 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
544 private extern void Start_internal(IntPtr handle
);
546 public void Start() {
548 if((state
& ThreadState
.Unstarted
) == 0) {
549 throw new ThreadStateException("Thread has already been started");
553 // Thread_internal creates the new thread, but
554 // blocks it until Start() is called later.
555 system_thread_handle
=Thread_internal(threadstart
);
557 if (system_thread_handle
== (IntPtr
) 0) {
558 throw new SystemException ("Thread creation failed");
561 // Launch this thread
562 Start_internal(system_thread_handle
);
564 // Mark the thread state as Running
565 // (which is all bits
566 // cleared). Therefore just remove the
568 clr_state(ThreadState
.Unstarted
);
572 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
573 private extern void Suspend_internal();
578 public void Suspend() {
579 if((state
& ThreadState
.Unstarted
) != 0 || !IsAlive
) {
580 throw new ThreadStateException("Thread has not been started, or is dead");
585 // Closes the system thread handle
586 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
587 private extern void Thread_free_internal(IntPtr handle
);
590 // Free up the handle
591 if (system_thread_handle
!= (IntPtr
) 0)
592 Thread_free_internal(system_thread_handle
);
595 private void set_state(ThreadState
set) {
600 private void clr_state(ThreadState clr
) {
608 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
609 extern public static byte VolatileRead (ref byte address
);
611 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
612 extern public static double VolatileRead (ref double address
);
614 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
615 extern public static short VolatileRead (ref short address
);
617 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
618 extern public static int VolatileRead (ref int address
);
620 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
621 extern public static long VolatileRead (ref long address
);
623 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
624 extern public static IntPtr
VolatileRead (ref IntPtr address
);
626 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
627 extern public static object VolatileRead (ref object address
);
629 [CLSCompliant(false)]
630 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
631 extern public static sbyte VolatileRead (ref sbyte address
);
633 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
634 extern public static float VolatileRead (ref float address
);
636 [CLSCompliant (false)]
637 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
638 extern public static ushort VolatileRead (ref ushort address
);
640 [CLSCompliant (false)]
641 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
642 extern public static uint VolatileRead (ref uint address
);
644 [CLSCompliant (false)]
645 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
646 extern public static ulong VolatileRead (ref ulong address
);
648 [CLSCompliant (false)]
649 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
650 extern public static UIntPtr
VolatileRead (ref UIntPtr address
);
652 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
653 extern public static void VolatileWrite (ref byte address
, byte value);
655 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
656 extern public static void VolatileWrite (ref double address
, double value);
658 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
659 extern public static void VolatileWrite (ref short address
, short value);
661 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
662 extern public static void VolatileWrite (ref int address
, int value);
664 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
665 extern public static void VolatileWrite (ref long address
, long value);
667 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
668 extern public static void VolatileWrite (ref IntPtr address
, IntPtr
value);
670 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
671 extern public static void VolatileWrite (ref object address
, object value);
673 [CLSCompliant(false)]
674 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
675 extern public static void VolatileWrite (ref sbyte address
, sbyte value);
677 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
678 extern public static void VolatileWrite (ref float address
, float value);
680 [CLSCompliant (false)]
681 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
682 extern public static void VolatileWrite (ref ushort address
, ushort value);
684 [CLSCompliant (false)]
685 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
686 extern public static void VolatileWrite (ref uint address
, uint value);
688 [CLSCompliant (false)]
689 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
690 extern public static void VolatileWrite (ref ulong address
, ulong value);
692 [CLSCompliant (false)]
693 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
694 extern public static void VolatileWrite (ref UIntPtr address
, UIntPtr
value);
699 [MonoTODO ("stack size is ignored")]
700 public Thread (ThreadStart start
, int maxStackSize
)
703 throw new ArgumentNullException ("start");
704 if (maxStackSize
< 131072)
705 throw new ArgumentException ("< 128 kb", "maxStackSize");
711 public Thread (ParameterizedThreadStart start
)
714 throw new ArgumentNullException ("start");
716 throw new NotImplementedException ();
720 public Thread (ParameterizedThreadStart start
, int maxStackSize
)
723 throw new ArgumentNullException ("start");
724 if (maxStackSize
< 131072)
725 throw new ArgumentException ("< 128 kb", "maxStackSize");
727 throw new NotImplementedException ();
731 public ExecutionContext ExecutionContext
{
732 [ReliabilityContract (Consistency
.WillNotCorruptState
, CER
.MayFail
)]
733 get { throw new NotImplementedException (); }
736 public int ManagedThreadId
{
737 get { return thread_id; }
741 [ReliabilityContract (Consistency
.WillNotCorruptState
, CER
.MayFail
)]
742 public static void BeginCriticalRegion ()
744 throw new NotImplementedException ();
748 [ReliabilityContract (Consistency
.WillNotCorruptState
, CER
.Success
)]
749 public static void EndCriticalRegion ()
751 throw new NotImplementedException ();
755 public static void BeginThreadAffinity ()
757 throw new NotImplementedException ();
761 public static void EndThreadAffinity ()
763 throw new NotImplementedException ();
767 public ApartmentState
GetApartmentState ()
769 return this.ApartmentState
;
773 public void SetApartmentState (ApartmentState state
)
775 this.ApartmentState
= state
;
779 public bool TrySetApartmentState (ApartmentState state
)
782 this.ApartmentState
= state
;
785 catch (ArgumentException
) {
794 public CompressedStack
GetCompressedStack ()
796 throw new NotImplementedException ();
800 public void SetCompressedStack (CompressedStack stack
)
802 throw new NotImplementedException ();
806 public override int GetHashCode ()
808 // ??? overridden but not guaranteed to be unique ???
813 public void Start (object parameter
)
815 throw new NotImplementedException ();