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