2007-12-27 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mcs / class / corlib / System.Threading / Thread.cs
1 //
2 // System.Threading.Thread.cs
3 //
4 // Author:
5 //   Dick Porter (dick@ximian.com)
6 //
7 // (C) Ximian, Inc.  http://www.ximian.com
8 // Copyright (C) 2004-2006 Novell, Inc (http://www.novell.com)
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 // 
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 // 
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 //
29
30 using System.Runtime.Remoting.Contexts;
31 using System.Runtime.Serialization;
32 using System.Runtime.Serialization.Formatters.Binary;
33 using System.Security.Permissions;
34 using System.Security.Principal;
35 using System.Globalization;
36 using System.Runtime.CompilerServices;
37 using System.Runtime.InteropServices;
38 using System.IO;
39 using System.Collections;
40 using System.Security;
41
42 #if NET_2_0
43 using System.Runtime.ConstrainedExecution;
44 #endif
45
46 namespace System.Threading {
47
48         [ClassInterface (ClassInterfaceType.None)]
49 #if NET_2_0
50         [ComVisible (true)]
51         [ComDefaultInterface (typeof (_Thread))]
52         public sealed class Thread : CriticalFinalizerObject, _Thread {
53 #else
54         public sealed class Thread : _Thread {
55 #endif
56
57                 #region Sync with metadata/object-internals.h
58                 int lock_thread_id;
59                 // stores a thread handle
60                 private IntPtr system_thread_handle;
61
62                 /* Note this is an opaque object (an array), not a CultureInfo */
63                 private object cached_culture_info;
64                 private IntPtr unused0;
65                 private bool threadpool_thread;
66                 /* accessed only from unmanaged code */
67                 private IntPtr name;
68                 private int name_len; 
69                 private ThreadState state = ThreadState.Unstarted;
70                 private object abort_exc;
71                 internal object abort_state;
72                 /* thread_id is only accessed from unmanaged code */
73                 private Int64 thread_id;
74                 
75                 /* start_notify is used by the runtime to signal that Start()
76                  * is ok to return
77                  */
78                 private IntPtr start_notify;
79                 private IntPtr stack_ptr;
80                 private UIntPtr static_data; /* GC-tracked */
81                 private IntPtr jit_data;
82                 private IntPtr lock_data;
83                 Context current_appcontext;
84                 int stack_size;
85                 object start_obj;
86                 private IntPtr appdomain_refs;
87                 private bool interruption_requested;
88                 private IntPtr suspend_event;
89                 private IntPtr suspended_event;
90                 private IntPtr resume_event;
91                 private IntPtr synch_cs;
92                 private IntPtr serialized_culture_info;
93                 private int serialized_culture_info_len;
94                 private IntPtr serialized_ui_culture_info;
95                 private int serialized_ui_culture_info_len;
96                 private ExecutionContext _ec;
97                 private bool thread_dump_requested;
98                 private IntPtr end_stack;
99                 private bool thread_interrupt_requested;
100                 private byte apartment_state = (byte)ApartmentState.Unknown;
101                 /* 
102                  * These fields are used to avoid having to increment corlib versions
103                  * when a new field is added to the unmanaged MonoThread structure.
104                  */
105                 private IntPtr unused5;
106                 private IntPtr unused6;
107                 private IntPtr unused7;
108                 #endregion
109
110                 // the name of local_slots is important as it's used by the runtime.
111                 [ThreadStatic] 
112                 static object[] local_slots;
113
114                 // can be both a ThreadSart and a ParameterizedThreadStart
115                 private MulticastDelegate threadstart;
116                 private string thread_name=null;
117                 
118                 private static int _managed_id_counter;
119                 private int managed_id;
120                 
121                 private IPrincipal _principal;
122
123                 public static Context CurrentContext {
124                         [SecurityPermission (SecurityAction.LinkDemand, Infrastructure=true)]
125                         get {
126                                 return(AppDomain.InternalGetContext ());
127                         }
128                 }
129
130                 public static IPrincipal CurrentPrincipal {
131                         get {
132                                 IPrincipal p = null;
133                                 Thread th = CurrentThread;
134                                 lock (th) {
135                                         p = th._principal;
136                                         if (p == null) {
137                                                 p = GetDomain ().DefaultPrincipal;
138                                                 th._principal = p;
139                                         }
140                                 }
141                                 return p;
142                         }
143                         [SecurityPermission (SecurityAction.Demand, ControlPrincipal = true)]
144                         set {
145                                 CurrentThread._principal = value;
146                         }
147                 }
148
149                 // Looks up the object associated with the current thread
150                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
151                 private extern static Thread CurrentThread_internal();
152                 
153                 public static Thread CurrentThread {
154 #if NET_2_0
155                         [ReliabilityContract (Consistency.WillNotCorruptState, Cer.MayFail)]
156 #endif
157                         get {
158                                 return(CurrentThread_internal());
159                         }
160                 }
161
162                 internal static int CurrentThreadId {
163                         get {
164                                 return (int)(CurrentThread.thread_id);
165                         }
166                 }
167
168                 // Stores a hash keyed by strings of LocalDataStoreSlot objects
169                 static Hashtable datastorehash;
170                 private static object datastore_lock = new object ();
171                 
172                 private static void InitDataStoreHash () {
173                         lock (datastore_lock) {
174                                 if (datastorehash == null) {
175                                         datastorehash = Hashtable.Synchronized(new Hashtable());
176                                 }
177                         }
178                 }
179                 
180                 public static LocalDataStoreSlot AllocateNamedDataSlot (string name) {
181                         lock (datastore_lock) {
182                                 if (datastorehash == null)
183                                         InitDataStoreHash ();
184                                 LocalDataStoreSlot slot = (LocalDataStoreSlot)datastorehash [name];
185                                 if (slot != null) {
186                                         // This exception isnt documented (of
187                                         // course) but .net throws it
188                                         throw new ArgumentException("Named data slot already added");
189                                 }
190                         
191                                 slot = AllocateDataSlot ();
192
193                                 datastorehash.Add (name, slot);
194
195                                 return slot;
196                         }
197                 }
198
199                 public static void FreeNamedDataSlot (string name) {
200                         lock (datastore_lock) {
201                                 if (datastorehash == null)
202                                         InitDataStoreHash ();
203                                 LocalDataStoreSlot slot = (LocalDataStoreSlot)datastorehash [name];
204
205                                 if (slot != null) {
206                                         datastorehash.Remove (slot);
207                                 }
208                         }
209                 }
210
211                 public static LocalDataStoreSlot AllocateDataSlot () {
212                         return new LocalDataStoreSlot (true);
213                 }
214
215                 public static object GetData (LocalDataStoreSlot slot) {
216                         object[] slots = local_slots;
217                         if (slot == null)
218                                 throw new ArgumentNullException ("slot");
219                         if (slots != null && slot.slot < slots.Length)
220                                 return slots [slot.slot];
221                         return null;
222                 }
223
224                 public static void SetData (LocalDataStoreSlot slot, object data) {
225                         object[] slots = local_slots;
226                         if (slot == null)
227                                 throw new ArgumentNullException ("slot");
228                         if (slots == null) {
229                                 slots = new object [slot.slot + 2];
230                                 local_slots = slots;
231                         } else if (slot.slot >= slots.Length) {
232                                 object[] nslots = new object [slot.slot + 2];
233                                 slots.CopyTo (nslots, 0);
234                                 slots = nslots;
235                                 local_slots = slots;
236                         }
237                         slots [slot.slot] = data;
238                 }
239
240                 public static AppDomain GetDomain() {
241                         return AppDomain.CurrentDomain;
242                 }
243
244                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
245                 public extern static int GetDomainID();
246
247                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
248                 internal extern static void FreeLocalSlotValues (int slot, bool thread_local);
249
250                 public static LocalDataStoreSlot GetNamedDataSlot(string name) {
251                         lock (datastore_lock) {
252                                 if (datastorehash == null)
253                                         InitDataStoreHash ();
254                                 LocalDataStoreSlot slot=(LocalDataStoreSlot)datastorehash[name];
255
256                                 if(slot==null) {
257                                         slot=AllocateNamedDataSlot(name);
258                                 }
259                         
260                                 return(slot);
261                         }
262                 }
263                 
264                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
265                 private extern static void ResetAbort_internal();
266
267                 [SecurityPermission (SecurityAction.Demand, ControlThread=true)]
268                 public static void ResetAbort ()
269                 {
270                         ResetAbort_internal ();
271                 }
272
273                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
274                 private extern static void Sleep_internal(int ms);
275
276                 public static void Sleep(int millisecondsTimeout) {
277                         if((millisecondsTimeout<0) && (millisecondsTimeout != Timeout.Infinite)) {
278                                 throw new ArgumentException("Negative timeout");
279                         }
280                         Sleep_internal(millisecondsTimeout);
281                 }
282
283                 public static void Sleep(TimeSpan timeout) {
284                         // LAMESPEC: says to throw ArgumentException too
285                         int ms=Convert.ToInt32(timeout.TotalMilliseconds);
286                         
287                         if(ms < 0 || ms > Int32.MaxValue) {
288                                 throw new ArgumentOutOfRangeException("Timeout out of range");
289                         }
290
291                         Sleep_internal(ms);
292                 }
293
294                 // Returns the system thread handle
295                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
296                 private extern IntPtr Thread_internal (MulticastDelegate start);
297
298                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
299                 private extern void Thread_init ();
300
301                 private static int GetNewManagedId() {
302                         return Interlocked.Increment(ref _managed_id_counter);
303                 }
304
305                 public Thread(ThreadStart start) {
306                         if(start==null) {
307                                 throw new ArgumentNullException("Null ThreadStart");
308                         }
309                         threadstart=start;
310
311                         Thread_init ();
312                 }
313
314 #if NET_2_0
315                 [Obsolete ("Deprecated in favor of GetApartmentState, SetApartmentState and TrySetApartmentState.")]
316 #endif
317                 public ApartmentState ApartmentState {
318                         get {
319                                 if ((ThreadState & ThreadState.Stopped) != 0)
320                                         throw new ThreadStateException ("Thread is dead; state can not be accessed.");
321
322                                 return (ApartmentState)apartment_state;
323                         }
324
325                         set     {
326 #if NET_2_0
327                                 TrySetApartmentState (value);
328 #else
329                                 if ((ThreadState & ThreadState.Unstarted) == 0)
330                                         throw new ThreadStateException ("Thread was in an invalid state for the operation being executed.");
331
332                                 if (value != ApartmentState.STA && value != ApartmentState.MTA)
333                                         throw new ArgumentException ("value is not a valid apartment state.");
334
335                                 if ((ApartmentState)apartment_state == ApartmentState.Unknown)
336                                         apartment_state = (byte)value;
337 #endif
338                         }
339                 }
340
341                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
342                 private static extern int current_lcid ();
343
344                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
345                 private extern CultureInfo GetCachedCurrentCulture ();
346
347                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
348                 private extern byte[] GetSerializedCurrentCulture ();
349
350                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
351                 private extern void SetCachedCurrentCulture (CultureInfo culture);
352
353                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
354                 private extern void SetSerializedCurrentCulture (byte[] culture);
355
356                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
357                 private extern CultureInfo GetCachedCurrentUICulture ();
358
359                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
360                 private extern byte[] GetSerializedCurrentUICulture ();
361
362                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
363                 private extern void SetCachedCurrentUICulture (CultureInfo culture);
364
365                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
366                 private extern void SetSerializedCurrentUICulture (byte[] culture);
367
368                 /* If the current_lcid() isn't known by CultureInfo,
369                  * it will throw an exception which may cause
370                  * String.Concat to try and recursively look up the
371                  * CurrentCulture, which will throw an exception, etc.
372                  * Use a boolean to short-circuit this scenario.
373                  */
374                 private static bool in_currentculture=false;
375
376                 static object culture_lock = new object ();
377                 
378                 /*
379                  * Thread objects are shared between appdomains, and CurrentCulture
380                  * should always return an object in the calling appdomain. See bug
381                  * http://bugzilla.ximian.com/show_bug.cgi?id=50049 for more info.
382                  * This is hard to implement correctly and efficiently, so the current
383                  * implementation is not perfect: changes made in one appdomain to the 
384                  * state of the current cultureinfo object are not visible to other 
385                  * appdomains.
386                  */             
387                 public CultureInfo CurrentCulture {
388                         get {
389                                 if (in_currentculture)
390                                         /* Bail out */
391                                         return CultureInfo.InvariantCulture;
392
393                                 CultureInfo culture = GetCachedCurrentCulture ();
394                                 if (culture != null)
395                                         return culture;
396
397                                 byte[] arr = GetSerializedCurrentCulture ();
398                                 if (arr == null) {
399                                         lock (culture_lock) {
400                                                 in_currentculture=true;
401                                                 culture = CultureInfo.ConstructCurrentCulture ();
402                                                 //
403                                                 // Don't serialize the culture in this case to avoid
404                                                 // initializing the serialization infrastructure in the
405                                                 // common case when the culture is not set explicitly.
406                                                 //
407                                                 SetCachedCurrentCulture (culture);
408                                                 in_currentculture = false;
409                                                 return culture;
410                                         }
411                                 }
412
413                                 /*
414                                  * No cultureinfo object exists for this domain, so create one
415                                  * by deserializing the serialized form.
416                                  */
417                                 in_currentculture = true;
418                                 try {
419                                         BinaryFormatter bf = new BinaryFormatter ();
420                                         MemoryStream ms = new MemoryStream (arr);
421                                         culture = (CultureInfo)bf.Deserialize (ms);
422                                         SetCachedCurrentCulture (culture);
423                                 } finally {
424                                         in_currentculture = false;
425                                 }
426
427                                 return culture;
428                         }
429                         
430                         [SecurityPermission (SecurityAction.Demand, ControlThread=true)]
431                         set {
432                                 if (value == null)
433                                         throw new ArgumentNullException ("value");
434
435                                 value.CheckNeutral ();
436                                 in_currentculture = true;
437                                 try {
438                                         BinaryFormatter bf = new BinaryFormatter();
439                                         MemoryStream ms = new MemoryStream ();
440                                         bf.Serialize (ms, value);
441
442                                         SetCachedCurrentCulture (value);
443                                         SetSerializedCurrentCulture (ms.GetBuffer ());
444                                 } finally {
445                                         in_currentculture = false;
446                                 }
447                         }
448                 }
449
450                 public CultureInfo CurrentUICulture {
451                         get {
452                                 if (in_currentculture)
453                                         /* Bail out */
454                                         return CultureInfo.InvariantCulture;
455
456                                 CultureInfo culture = GetCachedCurrentUICulture ();
457                                 if (culture != null)
458                                         return culture;
459
460                                 byte[] arr = GetSerializedCurrentUICulture ();
461                                 if (arr == null) {
462                                         lock (culture_lock) {
463                                                 in_currentculture=true;
464                                                 /* We don't
465                                                  * distinguish
466                                                  * between
467                                                  * System and
468                                                  * UI cultures
469                                                  */
470                                                 culture = CultureInfo.ConstructCurrentUICulture ();
471                                                 //
472                                                 // Don't serialize the culture in this case to avoid
473                                                 // initializing the serialization infrastructure in the
474                                                 // common case when the culture is not set explicitly.
475                                                 //
476                                                 SetCachedCurrentUICulture (culture);
477                                                 in_currentculture = false;
478                                                 return culture;
479                                         }
480                                 }
481
482                                 /*
483                                  * No cultureinfo object exists for this domain, so create one
484                                  * by deserializing the serialized form.
485                                  */
486                                 in_currentculture = true;
487                                 try {
488                                         BinaryFormatter bf = new BinaryFormatter ();
489                                         MemoryStream ms = new MemoryStream (arr);
490                                         culture = (CultureInfo)bf.Deserialize (ms);
491                                         SetCachedCurrentUICulture (culture);
492                                 }
493                                 finally {
494                                         in_currentculture = false;
495                                 }
496
497                                 return culture;
498                         }
499                         
500                         set {
501                                 in_currentculture = true;
502                                 
503                                 if (value == null)
504                                         throw new ArgumentNullException ("value");
505
506                                 try {
507                                         BinaryFormatter bf = new BinaryFormatter();
508                                         MemoryStream ms = new MemoryStream ();
509                                         bf.Serialize (ms, value);
510
511                                         SetCachedCurrentUICulture (value);
512                                         SetSerializedCurrentUICulture (ms.GetBuffer ());
513                                 } finally {
514                                         in_currentculture = false;
515                                 }
516                         }
517                 }
518
519                 public bool IsThreadPoolThread {
520                         get {
521                                 return IsThreadPoolThreadInternal;
522                         }
523                 }
524
525                 internal bool IsThreadPoolThreadInternal {
526                         get {
527                                 return threadpool_thread;
528                         }
529                         set {
530                                 threadpool_thread = value;
531                         }
532                 }
533
534                 public bool IsAlive {
535                         get {
536                                 ThreadState curstate = GetState ();
537                                 
538                                 if((curstate & ThreadState.Aborted) != 0 ||
539                                    (curstate & ThreadState.Stopped) != 0 ||
540                                    (curstate & ThreadState.Unstarted) != 0) {
541                                         return(false);
542                                 } else {
543                                         return(true);
544                                 }
545                         }
546                 }
547
548                 public bool IsBackground {
549                         get {
550                                 ThreadState thread_state = GetState ();
551                                 if ((thread_state & ThreadState.Stopped) != 0)
552                                         throw new ThreadStateException ("Thread is dead; state can not be accessed.");
553
554                                 return (thread_state & ThreadState.Background) != 0;
555                         }
556                         
557                         set {
558                                 if (value) {
559                                         SetState (ThreadState.Background);
560                                 } else {
561                                         ClrState (ThreadState.Background);
562                                 }
563                         }
564                 }
565
566                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
567                 private extern string GetName_internal ();
568
569                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
570                 private extern void SetName_internal (String name);
571
572                 /* 
573                  * The thread name must be shared by appdomains, so it is stored in
574                  * unmanaged code.
575                  */
576
577                 public string Name {
578                         get {
579                                 return GetName_internal ();
580                         }
581                         
582                         set {
583                                 SetName_internal (value);
584                         }
585                 }
586
587                 public ThreadPriority Priority {
588                         get {
589                                 return(ThreadPriority.Lowest);
590                         }
591                         
592                         set {
593                                 // FIXME: Implement setter.
594                         }
595                 }
596
597                 public ThreadState ThreadState {
598                         get {
599                                 return GetState ();
600                         }
601                 }
602
603                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
604                 private extern void Abort_internal (object stateInfo);
605
606                 [SecurityPermission (SecurityAction.Demand, ControlThread=true)]
607                 public void Abort () 
608                 {
609                         Abort_internal (null);
610                 }
611
612                 [SecurityPermission (SecurityAction.Demand, ControlThread=true)]
613                 public void Abort (object stateInfo) 
614                 {
615                         Abort_internal (stateInfo);
616                 }
617                 
618                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
619                 private extern void Interrupt_internal ();
620                 
621                 [SecurityPermission (SecurityAction.Demand, ControlThread=true)]
622                 public void Interrupt ()
623                 {
624                         Interrupt_internal ();
625                 }
626
627                 // The current thread joins with 'this'. Set ms to 0 to block
628                 // until this actually exits.
629                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
630                 private extern bool Join_internal(int ms, IntPtr handle);
631                 
632                 public void Join()
633                 {
634                         Join_internal(Timeout.Infinite, system_thread_handle);
635                 }
636
637                 public bool Join(int millisecondsTimeout)
638                 {
639                         if (millisecondsTimeout != Timeout.Infinite && millisecondsTimeout < 0)
640                                 throw new ArgumentException ("Timeout less than zero", "millisecondsTimeout");
641
642                         return Join_internal(millisecondsTimeout, system_thread_handle);
643                 }
644
645                 public bool Join(TimeSpan timeout)
646                 {
647                         // LAMESPEC: says to throw ArgumentException too
648                         int ms=Convert.ToInt32(timeout.TotalMilliseconds);
649                         
650                         if(ms < 0 || ms > Int32.MaxValue) {
651                                 throw new ArgumentOutOfRangeException("timeout out of range");
652                         }
653                         return Join_internal(ms, system_thread_handle);
654                 }
655
656 #if NET_1_1
657                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
658                 public extern static void MemoryBarrier ();
659 #endif
660                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
661                 private extern void Resume_internal();
662
663 #if NET_2_0
664                 [Obsolete ("")]
665 #endif
666                 [SecurityPermission (SecurityAction.Demand, ControlThread=true)]
667                 public void Resume () 
668                 {
669                         Resume_internal ();
670                 }
671
672                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
673                 private extern static void SpinWait_internal (int iterations);
674
675
676 #if NET_2_0
677                 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
678 #endif
679                 public static void SpinWait (int iterations) 
680                 {
681                         SpinWait_internal (iterations);
682                 }
683
684                 public void Start() {
685                         // propagate informations from the original thread to the new thread
686 #if NET_2_0
687                         if (!ExecutionContext.IsFlowSuppressed ())
688                                 _ec = ExecutionContext.Capture ();
689 #else
690                         // before 2.0 this was only used for security (mostly CAS) so we
691                         // do this only if the security manager is active
692                         if (SecurityManager.SecurityEnabled)
693                                 _ec = ExecutionContext.Capture ();
694 #endif
695                         if (CurrentThread._principal != null)
696                                 _principal = CurrentThread._principal;
697
698                         // Thread_internal creates and starts the new thread, 
699                         if (Thread_internal(threadstart) == (IntPtr) 0)
700                                 throw new SystemException ("Thread creation failed.");
701                 }
702
703                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
704                 private extern void Suspend_internal();
705
706 #if NET_2_0
707                 [Obsolete ("")]
708 #endif
709                 [SecurityPermission (SecurityAction.Demand, ControlThread=true)]
710                 public void Suspend ()
711                 {
712                         Suspend_internal ();
713                 }
714
715                 // Closes the system thread handle
716                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
717                 private extern void Thread_free_internal(IntPtr handle);
718
719 #if NET_2_0
720                 [ReliabilityContract (Consistency.WillNotCorruptState, Cer.Success)]
721 #endif
722                 ~Thread() {
723                         // Free up the handle
724                         if (system_thread_handle != (IntPtr) 0)
725                                 Thread_free_internal(system_thread_handle);
726                 }
727
728                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
729                 extern private void SetState (ThreadState set);
730                 
731                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
732                 extern private void ClrState (ThreadState clr);
733                 
734                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
735                 extern private ThreadState GetState ();
736
737 #if NET_1_1
738                 
739                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
740                 extern public static byte VolatileRead (ref byte address);
741                 
742                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
743                 extern public static double VolatileRead (ref double address);
744                 
745                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
746                 extern public static short VolatileRead (ref short address);
747                 
748                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
749                 extern public static int VolatileRead (ref int address);
750                 
751                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
752                 extern public static long VolatileRead (ref long address);
753                 
754                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
755                 extern public static IntPtr VolatileRead (ref IntPtr address);
756                 
757                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
758                 extern public static object VolatileRead (ref object address);
759
760                 [CLSCompliant(false)]
761                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
762                 extern public static sbyte VolatileRead (ref sbyte address);
763                 
764                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
765                 extern public static float VolatileRead (ref float address);
766
767                 [CLSCompliant (false)]
768                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
769                 extern public static ushort VolatileRead (ref ushort address);
770
771                 [CLSCompliant (false)]
772                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
773                 extern public static uint VolatileRead (ref uint address);
774
775                 [CLSCompliant (false)]
776                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
777                 extern public static ulong VolatileRead (ref ulong address);
778
779                 [CLSCompliant (false)]
780                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
781                 extern public static UIntPtr VolatileRead (ref UIntPtr address);
782
783                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
784                 extern public static void VolatileWrite (ref byte address, byte value);
785                 
786                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
787                 extern public static void VolatileWrite (ref double address, double value);
788                 
789                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
790                 extern public static void VolatileWrite (ref short address, short value);
791                 
792                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
793                 extern public static void VolatileWrite (ref int address, int value);
794                 
795                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
796                 extern public static void VolatileWrite (ref long address, long value);
797                 
798                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
799                 extern public static void VolatileWrite (ref IntPtr address, IntPtr value);
800                 
801                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
802                 extern public static void VolatileWrite (ref object address, object value);
803
804                 [CLSCompliant(false)]
805                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
806                 extern public static void VolatileWrite (ref sbyte address, sbyte value);
807                 
808                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
809                 extern public static void VolatileWrite (ref float address, float value);
810
811                 [CLSCompliant (false)]
812                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
813                 extern public static void VolatileWrite (ref ushort address, ushort value);
814
815                 [CLSCompliant (false)]
816                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
817                 extern public static void VolatileWrite (ref uint address, uint value);
818
819                 [CLSCompliant (false)]
820                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
821                 extern public static void VolatileWrite (ref ulong address, ulong value);
822
823                 [CLSCompliant (false)]
824                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
825                 extern public static void VolatileWrite (ref UIntPtr address, UIntPtr value);
826                 
827 #endif
828
829 #if NET_2_0
830                 public Thread (ThreadStart start, int maxStackSize)
831                 {
832                         if (start == null)
833                                 throw new ArgumentNullException ("start");
834                         if (maxStackSize < 131072)
835                                 throw new ArgumentException ("< 128 kb", "maxStackSize");
836
837                         threadstart = start;
838                         stack_size = maxStackSize;
839                         Thread_init ();
840                 }
841
842                 public Thread (ParameterizedThreadStart start)
843                 {
844                         if (start == null)
845                                 throw new ArgumentNullException ("start");
846
847                         threadstart = start;
848                         Thread_init ();
849                 }
850
851                 public Thread (ParameterizedThreadStart start, int maxStackSize)
852                 {
853                         if (start == null)
854                                 throw new ArgumentNullException ("start");
855                         if (maxStackSize < 131072)
856                                 throw new ArgumentException ("< 128 kb", "maxStackSize");
857
858                         threadstart = start;
859                         stack_size = maxStackSize;
860                         Thread_init ();
861                 }
862
863                 [MonoTODO ("limited to CompressedStack support")]
864                 // FIXME: We share the _ec object between appdomains
865                 public ExecutionContext ExecutionContext {
866                         [ReliabilityContract (Consistency.WillNotCorruptState, Cer.MayFail)]
867                         get {
868                                 if (_ec == null)
869                                         _ec = new ExecutionContext ();
870                                 return _ec;
871                         }
872                 }
873
874                 public int ManagedThreadId {
875                         [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
876                         get {
877                                 if (managed_id == 0) {
878                                         int new_managed_id = GetNewManagedId ();
879                                         
880                                         Interlocked.CompareExchange (ref managed_id, new_managed_id, 0);
881                                 }
882                                 
883                                 return managed_id;
884                         }
885                 }
886
887                 [MonoTODO("Not implemented")]
888                 [ReliabilityContract (Consistency.WillNotCorruptState, Cer.MayFail)]
889                 public static void BeginCriticalRegion ()
890                 {
891                         throw new NotImplementedException ();
892                 }
893
894                 [MonoTODO("Not implemented")]
895                 [ReliabilityContract (Consistency.WillNotCorruptState, Cer.Success)]
896                 public static void EndCriticalRegion ()
897                 {
898                         throw new NotImplementedException ();
899                 }
900
901                 [MonoTODO("Not implemented")]
902                 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
903                 public static void BeginThreadAffinity ()
904                 {
905                         throw new NotImplementedException ();
906                 }
907
908                 [MonoTODO("Not implemented")]
909                 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
910                 public static void EndThreadAffinity ()
911                 {
912                         throw new NotImplementedException ();
913                 }
914                 
915                 public ApartmentState GetApartmentState ()
916                 {
917                         return (ApartmentState)apartment_state;
918                 }
919
920                 public void SetApartmentState (ApartmentState state)
921                 {
922                         if (!TrySetApartmentState (state))
923                                 throw new InvalidOperationException ("Failed to set the specified COM apartment state.");
924                 }
925
926                 public bool TrySetApartmentState (ApartmentState state) 
927                 {
928                         if ((ThreadState & ThreadState.Unstarted) == 0)
929                                 throw new ThreadStateException ("Thread was in an invalid state for the operation being executed.");
930
931                         if ((ApartmentState)apartment_state != ApartmentState.Unknown)
932                                 return false;
933
934                         apartment_state = (byte)state;
935
936                         return true;
937                 }
938                 
939                 [ComVisible (false)]
940                 public override int GetHashCode ()
941                 {
942                         return ManagedThreadId;
943                 }
944
945                 public void Start (object parameter)
946                 {
947                         start_obj = parameter;
948                         Start ();
949                 }
950 #else
951                 internal ExecutionContext ExecutionContext {
952                         get {
953                                 if (_ec == null)
954                                         _ec = new ExecutionContext ();
955                                 return _ec;
956                         }
957                 }
958 #endif
959
960                 // NOTE: This method doesn't show in the class library status page because
961                 // it cannot be "found" with the StrongNameIdentityPermission for ECMA key.
962                 // But it's there!
963                 [SecurityPermission (SecurityAction.LinkDemand, UnmanagedCode = true)]
964                 [StrongNameIdentityPermission (SecurityAction.LinkDemand, PublicKey="00000000000000000400000000000000")]
965 #if NET_2_0
966                 [Obsolete ("see CompressedStack class")]
967 #endif
968 #if NET_1_1
969                 public
970 #else
971                 internal
972 #endif
973                 CompressedStack GetCompressedStack ()
974                 {
975                         // Note: returns null if no CompressedStack has been set.
976                         // However CompressedStack.GetCompressedStack returns an 
977                         // (empty?) CompressedStack instance.
978                         CompressedStack cs = ExecutionContext.SecurityContext.CompressedStack;
979                         return ((cs == null) || cs.IsEmpty ()) ? null : cs.CreateCopy ();
980                 }
981
982                 // NOTE: This method doesn't show in the class library status page because
983                 // it cannot be "found" with the StrongNameIdentityPermission for ECMA key.
984                 // But it's there!
985                 [SecurityPermission (SecurityAction.LinkDemand, UnmanagedCode = true)]
986                 [StrongNameIdentityPermission (SecurityAction.LinkDemand, PublicKey="00000000000000000400000000000000")]
987 #if NET_2_0
988                 [Obsolete ("see CompressedStack class")]
989 #endif
990 #if NET_1_1
991                 public
992 #else
993                 internal
994 #endif
995                 void SetCompressedStack (CompressedStack stack)
996                 {
997                         ExecutionContext.SecurityContext.CompressedStack = stack;
998                 }
999
1000 #if NET_1_1
1001                 void _Thread.GetIDsOfNames ([In] ref Guid riid, IntPtr rgszNames, uint cNames, uint lcid, IntPtr rgDispId)
1002                 {
1003                         throw new NotImplementedException ();
1004                 }
1005
1006                 void _Thread.GetTypeInfo (uint iTInfo, uint lcid, IntPtr ppTInfo)
1007                 {
1008                         throw new NotImplementedException ();
1009                 }
1010
1011                 void _Thread.GetTypeInfoCount (out uint pcTInfo)
1012                 {
1013                         throw new NotImplementedException ();
1014                 }
1015
1016                 void _Thread.Invoke (uint dispIdMember, [In] ref Guid riid, uint lcid, short wFlags, IntPtr pDispParams,
1017                         IntPtr pVarResult, IntPtr pExcepInfo, IntPtr puArgErr)
1018                 {
1019                         throw new NotImplementedException ();
1020                 }
1021 #endif
1022         }
1023 }