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