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