This commit was manufactured by cvs2svn to create branch 'mono-1-0'.
[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 Novell (http://www.novell.com)
9 //
10
11 //
12 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
13 //
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
21 // 
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
24 // 
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 //
33
34 using System.Runtime.Remoting.Contexts;
35 using System.Security.Permissions;
36 using System.Security.Principal;
37 using System.Globalization;
38 using System.Runtime.CompilerServices;
39 using System.Collections;
40
41 namespace System.Threading
42 {
43         public sealed class Thread
44         {
45                 #region Sync with object.h
46                 // stores a thread handle
47                 private IntPtr system_thread_handle;
48                 
49                 private CultureInfo current_culture;
50                 private CultureInfo current_ui_culture;
51                 private bool threadpool_thread;
52                 /* accessed only from unmanaged code */
53                 private IntPtr name;
54                 private int name_len; 
55                 private ThreadState state = ThreadState.Unstarted;
56                 private object abort_exc;
57                 internal object abort_state;
58                 /* thread_id is only accessed from unmanaged code */
59                 private int thread_id;
60                 
61                 /* start_notify is used by the runtime to signal that Start()
62                  * is ok to return
63                  */
64                 private IntPtr start_notify;
65                 private IntPtr stack_ptr;
66                 private IntPtr static_data;
67                 private IntPtr jit_data;
68                 private IntPtr lock_data;
69                 private IntPtr appdomain_refs;
70                 private bool interruption_requested;
71                 private IntPtr suspend_event;
72                 private IntPtr resume_event;
73                 private object synch_lock = new Object();
74                 #endregion
75
76                 private ThreadStart threadstart;
77                 private string thread_name=null;
78                 
79                 private IPrincipal _principal;
80                 
81                 public static Context CurrentContext {
82                         get {
83                                 return(AppDomain.InternalGetContext ());
84                         }
85                 }
86
87                 public static IPrincipal CurrentPrincipal {
88                         get {
89                                 IPrincipal p = null;
90                                 Thread th = CurrentThread;
91                                 lock (th) {
92                                         p = th._principal;
93                                         if (p == null) {
94                                                 p = GetDomain ().DefaultPrincipal;
95                                                 th._principal = p;
96                                         }
97                                 }
98                                 return p;
99                         }
100                         set {
101                                 new SecurityPermission (SecurityPermissionFlag.ControlPrincipal).Demand ();
102                                 CurrentThread._principal = value;
103                         }
104                 }
105
106                 // Looks up the object associated with the current thread
107                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
108                 private extern static Thread CurrentThread_internal();
109                 
110                 public static Thread CurrentThread {
111                         get {
112                                 return(CurrentThread_internal());
113                         }
114                 }
115
116                 internal static int CurrentThreadId {
117                         get {
118                                 return CurrentThread.thread_id;
119                         }
120                 }
121
122                 // Looks up the slot hash for the current thread
123                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
124                 private extern static Hashtable SlotHash_lookup();
125
126                 // Stores the slot hash for the current thread
127                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
128                 private extern static void SlotHash_store(Hashtable slothash);
129
130                 private static Hashtable GetTLSSlotHash() {
131                         Hashtable slothash=SlotHash_lookup();
132                         if(slothash==null) {
133                                 // Not synchronised, because this is
134                                 // thread specific anyway.
135                                 slothash=new Hashtable();
136                                 SlotHash_store(slothash);
137                         }
138
139                         return(slothash);
140                 }
141                 
142                 internal static object ResetDataStoreStatus () {
143                         Hashtable slothash=SlotHash_lookup();
144                         SlotHash_store(null);
145                         return slothash;
146                 }
147
148                 internal static void RestoreDataStoreStatus (object data) {
149                         SlotHash_store((Hashtable)data);
150                 }
151
152                 public static LocalDataStoreSlot AllocateDataSlot() {
153                         LocalDataStoreSlot slot = new LocalDataStoreSlot();
154
155                         return(slot);
156                 }
157
158                 // Stores a hash keyed by strings of LocalDataStoreSlot objects
159                 static Hashtable datastorehash;
160                 private static object datastore_lock = new object ();
161                 
162                 private static void InitDataStoreHash () {
163                         lock (datastore_lock) {
164                                 if (datastorehash == null) {
165                                         datastorehash = Hashtable.Synchronized(new Hashtable());
166                                 }
167                         }
168                 }
169                 
170                 public static LocalDataStoreSlot AllocateNamedDataSlot(string name) {
171                         lock (datastore_lock) {
172                                 if (datastorehash == null)
173                                         InitDataStoreHash ();
174                                 LocalDataStoreSlot slot = (LocalDataStoreSlot)datastorehash[name];
175                                 if(slot!=null) {
176                                         // This exception isnt documented (of
177                                         // course) but .net throws it
178                                         throw new ArgumentException("Named data slot already added");
179                                 }
180                         
181                                 slot = new LocalDataStoreSlot();
182
183                                 datastorehash.Add(name, slot);
184
185                                 return(slot);
186                         }
187                 }
188
189                 public static void FreeNamedDataSlot(string name) {
190                         lock (datastore_lock) {
191                                 if (datastorehash == null)
192                                         InitDataStoreHash ();
193                                 LocalDataStoreSlot slot=(LocalDataStoreSlot)datastorehash[name];
194
195                                 if(slot!=null) {
196                                         datastorehash.Remove(slot);
197                                 }
198                         }
199                 }
200
201                 public static object GetData(LocalDataStoreSlot slot) {
202                         Hashtable slothash=GetTLSSlotHash();
203                         return(slothash[slot]);
204                 }
205
206                 public static AppDomain GetDomain() {
207                         return AppDomain.CurrentDomain;
208                 }
209
210                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
211                 public extern static int GetDomainID();
212
213                 public static LocalDataStoreSlot GetNamedDataSlot(string name) {
214                         lock (datastore_lock) {
215                                 if (datastorehash == null)
216                                         InitDataStoreHash ();
217                                 LocalDataStoreSlot slot=(LocalDataStoreSlot)datastorehash[name];
218
219                                 if(slot==null) {
220                                         slot=AllocateNamedDataSlot(name);
221                                 }
222                         
223                                 return(slot);
224                         }
225                 }
226                 
227                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
228                 private extern static void ResetAbort_internal();
229
230                 public static void ResetAbort()
231                 {
232                         ResetAbort_internal();
233                 }
234                 
235
236                 public static void SetData(LocalDataStoreSlot slot,
237                                            object data) {
238                         Hashtable slothash=GetTLSSlotHash();
239
240                         if(slothash.Contains(slot)) {
241                                 slothash.Remove(slot);
242                         }
243                         
244                         slothash.Add(slot, data);
245                 }
246
247                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
248                 private extern static void Sleep_internal(int ms);
249
250                 public static void Sleep(int millisecondsTimeout) {
251                         if((millisecondsTimeout<0) && (millisecondsTimeout != Timeout.Infinite)) {
252                                 throw new ArgumentException("Negative timeout");
253                         }
254                         Thread thread=CurrentThread;
255                         Sleep_internal(millisecondsTimeout);
256                 }
257
258                 public static void Sleep(TimeSpan timeout) {
259                         // LAMESPEC: says to throw ArgumentException too
260                         int ms=Convert.ToInt32(timeout.TotalMilliseconds);
261                         
262                         if(ms < 0 || ms > Int32.MaxValue) {
263                                 throw new ArgumentOutOfRangeException("Timeout out of range");
264                         }
265
266                         Thread thread=CurrentThread;
267                         Sleep_internal(ms);
268                 }
269
270                 // Returns the system thread handle
271                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
272                 private extern IntPtr Thread_internal(ThreadStart start);
273
274                 public Thread(ThreadStart start) {
275                         if(start==null) {
276                                 throw new ArgumentNullException("Null ThreadStart");
277                         }
278                         threadstart=start;
279                 }
280
281                 [MonoTODO]
282                 public ApartmentState ApartmentState {
283                         get {
284                                 return(ApartmentState.Unknown);
285                         }
286                         
287                         set {
288                         }
289                 }
290
291                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
292                 private static extern int current_lcid ();
293
294                 /* If the current_lcid() isn't known by CultureInfo,
295                  * it will throw an exception which may cause
296                  * String.Concat to try and recursively look up the
297                  * CurrentCulture, which will throw an exception, etc.
298                  * Use a boolean to short-circuit this scenario.
299                  */
300                 private static bool in_currentculture=false;
301                 
302                 public CultureInfo CurrentCulture {
303                         get {
304                                 if (current_culture == null) {
305                                         lock (typeof (Thread)) {
306                                                 if(current_culture==null) {
307                                                         if(in_currentculture==true) {
308                                                                 /* Bail out */
309                                                                 current_culture = CultureInfo.InvariantCulture;
310                                                         } else {
311                                                                 in_currentculture=true;
312                                                         
313                                                                 current_culture = CultureInfo.ConstructCurrentCulture ();
314                                                         }
315                                                 }
316                                                 
317                                                 in_currentculture=false;
318                                         }
319                                 }
320                                 
321                                 return(current_culture);
322                         }
323                         
324                         set {
325                                 current_culture = value;
326                         }
327                 }
328
329                 public CultureInfo CurrentUICulture {
330                         get {
331                                 if (current_ui_culture == null) {
332                                         lock (synch_lock) {
333                                                 if(current_ui_culture==null) {
334                                                         /* We don't
335                                                          * distinguish
336                                                          * between
337                                                          * System and
338                                                          * UI cultures
339                                                          */
340                                                         current_ui_culture = CultureInfo.ConstructCurrentUICulture ();
341                                                 }
342                                         }
343                                 }
344                                 
345                                 return(current_ui_culture);
346                         }
347                         
348                         set {
349                                 current_ui_culture = value;
350                         }
351                 }
352
353                 public bool IsThreadPoolThread {
354                         get {
355                                 return IsThreadPoolThreadInternal;
356                         }
357                 }
358
359                 internal bool IsThreadPoolThreadInternal {
360                         get {
361                                 return threadpool_thread;
362                         }
363                         set {
364                                 threadpool_thread = value;
365                         }
366                 }
367
368                 public bool IsAlive {
369                         get {
370                                 ThreadState curstate=state;
371                                 
372                                 if((curstate & ThreadState.Aborted) != 0 ||
373                                    (curstate & ThreadState.Stopped) != 0 ||
374                                    (curstate & ThreadState.Unstarted) != 0) {
375                                         return(false);
376                                 } else {
377                                         return(true);
378                                 }
379                         }
380                 }
381
382                 public bool IsBackground {
383                         get {
384                                 if((state & ThreadState.Background) != 0) {
385                                         return(true);
386                                 } else {
387                                         return(false);
388                                 }
389                         }
390                         
391                         set {
392                                 if(value==true) {
393                                         set_state(ThreadState.Background);
394                                 } else {
395                                         clr_state(ThreadState.Background);
396                                 }
397                         }
398                 }
399
400                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
401                 private extern string GetName_internal ();
402
403                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
404                 private extern void SetName_internal (String name);
405
406                 /* 
407                  * The thread name must be shared by appdomains, so it is stored in
408                  * unmanaged code.
409                  */
410
411                 public string Name {
412                         get {
413                                 return GetName_internal ();
414                         }
415                         
416                         set {
417                                 lock (synch_lock) {
418                                         if(Name!=null) {
419                                                 throw new InvalidOperationException ("Thread.Name can only be set once.");
420                                         }
421                                 
422                                         SetName_internal (value);
423                                 }
424                         }
425                 }
426
427                 [MonoTODO]
428                 public ThreadPriority Priority {
429                         get {
430                                 return(ThreadPriority.Lowest);
431                         }
432                         
433                         set {
434                         }
435                 }
436
437                 public ThreadState ThreadState {
438                         get {
439                                 return(state);
440                         }
441                 }
442
443                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
444                 private extern void Abort_internal (object stateInfo);
445
446                 public void Abort() {
447                         Abort_internal (null);
448                 }
449
450                 public void Abort(object stateInfo) {
451                         Abort_internal(stateInfo);
452                 }
453                 
454
455                 [MonoTODO]
456                 public void Interrupt() {
457                 }
458
459                 // The current thread joins with 'this'. Set ms to 0 to block
460                 // until this actually exits.
461                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
462                 private extern bool Join_internal(int ms, IntPtr handle);
463                 
464                 public void Join() {
465                         if((state & ThreadState.Unstarted) != 0) {
466                                 throw new ThreadStateException("Thread has not been started");
467                         }
468                         
469                         Thread thread=CurrentThread;
470                                 
471                         Join_internal(Timeout.Infinite, system_thread_handle);
472                 }
473
474                 public bool Join(int millisecondsTimeout) {
475                         if (millisecondsTimeout != Timeout.Infinite && millisecondsTimeout < 0)
476                                 throw new ArgumentException ("Timeout less than zero", "millisecondsTimeout");
477
478                         if((state & ThreadState.Unstarted) != 0) {
479                                 throw new ThreadStateException("Thread has not been started");
480                         }
481
482                         Thread thread=CurrentThread;
483                         return Join_internal(millisecondsTimeout, system_thread_handle);
484                 }
485
486                 public bool Join(TimeSpan timeout) {
487                         // LAMESPEC: says to throw ArgumentException too
488                         int ms=Convert.ToInt32(timeout.TotalMilliseconds);
489                         
490                         if(ms < 0 || ms > Int32.MaxValue) {
491                                 throw new ArgumentOutOfRangeException("timeout out of range");
492                         }
493                         if((state & ThreadState.Unstarted) != 0) {
494                                 throw new ThreadStateException("Thread has not been started");
495                         }
496
497                         Thread thread=CurrentThread;
498                         return Join_internal(ms, system_thread_handle);
499                 }
500
501 #if NET_1_1
502                 [MonoTODO ("seems required for multi-processors systems like Itanium")]
503                 public static void MemoryBarrier ()
504                 {
505                         throw new NotImplementedException ();
506                 }
507 #endif
508                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
509                 private extern void Resume_internal();
510
511                 public void Resume () 
512                 {
513                         if ((state & ThreadState.Unstarted) != 0 || !IsAlive || 
514                                 ((state & ThreadState.Suspended) == 0 && (state & ThreadState.SuspendRequested) == 0)) 
515                         {
516                                 throw new ThreadStateException("Thread has not been started, or is dead");
517                         }
518                         
519                         Resume_internal ();
520                 }
521
522                 [MonoTODO]
523                 public static void SpinWait (int iterations) 
524                 {
525                         throw new NotImplementedException ();
526                 }
527
528                 // Launches the thread
529                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
530                 private extern void Start_internal(IntPtr handle);
531                 
532                 public void Start() {
533                         lock(synch_lock) {
534                                 if((state & ThreadState.Unstarted) == 0) {
535                                         throw new ThreadStateException("Thread has already been started");
536                                 }
537                                 
538
539                                 // Thread_internal creates the new thread, but
540                                 // blocks it until Start() is called later.
541                                 system_thread_handle=Thread_internal(threadstart);
542
543                                 if (system_thread_handle == (IntPtr) 0) {
544                                         throw new SystemException ("Thread creation failed");
545                                 }
546
547                                 // Launch this thread
548                                 Start_internal(system_thread_handle);
549
550                                 // Mark the thread state as Running
551                                 // (which is all bits
552                                 // cleared). Therefore just remove the
553                                 // Unstarted bit
554                                 clr_state(ThreadState.Unstarted);
555                         }
556                 }
557
558                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
559                 private extern void Suspend_internal();
560
561                 public void Suspend() {
562                         if((state & ThreadState.Unstarted) != 0 || !IsAlive) {
563                                 throw new ThreadStateException("Thread has not been started, or is dead");
564                         }
565                         Suspend_internal ();
566                 }
567
568                 // Closes the system thread handle
569                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
570                 private extern void Thread_free_internal(IntPtr handle);
571
572                 ~Thread() {
573                         // Free up the handle
574                         if (system_thread_handle != (IntPtr) 0)
575                                 Thread_free_internal(system_thread_handle);
576                 }
577
578                 private void set_state(ThreadState set) {
579                         lock(synch_lock) {
580                                 state |= set;
581                         }
582                 }
583                 private void clr_state(ThreadState clr) {
584                         lock(synch_lock) {
585                                 state &= ~clr;
586                         }
587                 }
588
589 #if NET_1_1
590                 
591                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
592                 extern public static byte VolatileRead (ref byte address);
593                 
594                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
595                 extern public static double VolatileRead (ref double address);
596                 
597                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
598                 extern public static short VolatileRead (ref short address);
599                 
600                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
601                 extern public static int VolatileRead (ref int address);
602                 
603                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
604                 extern public static long VolatileRead (ref long address);
605                 
606                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
607                 extern public static IntPtr VolatileRead (ref IntPtr address);
608                 
609                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
610                 extern public static object VolatileRead (ref object address);
611
612                 [CLSCompliant(false)]
613                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
614                 extern public static sbyte VolatileRead (ref sbyte address);
615                 
616                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
617                 extern public static float VolatileRead (ref float address);
618
619                 [CLSCompliant (false)]
620                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
621                 extern public static ushort VolatileRead (ref ushort address);
622
623                 [CLSCompliant (false)]
624                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
625                 extern public static uint VolatileRead (ref uint address);
626
627                 [CLSCompliant (false)]
628                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
629                 extern public static ulong VolatileRead (ref ulong address);
630
631                 [CLSCompliant (false)]
632                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
633                 extern public static UIntPtr VolatileRead (ref UIntPtr address);
634
635                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
636                 extern public static void VolatileWrite (ref byte address, byte value);
637                 
638                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
639                 extern public static void VolatileWrite (ref double address, double value);
640                 
641                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
642                 extern public static void VolatileWrite (ref short address, short value);
643                 
644                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
645                 extern public static void VolatileWrite (ref int address, int value);
646                 
647                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
648                 extern public static void VolatileWrite (ref long address, long value);
649                 
650                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
651                 extern public static void VolatileWrite (ref IntPtr address, IntPtr value);
652                 
653                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
654                 extern public static void VolatileWrite (ref object address, object value);
655
656                 [CLSCompliant(false)]
657                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
658                 extern public static void VolatileWrite (ref sbyte address, sbyte value);
659                 
660                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
661                 extern public static void VolatileWrite (ref float address, float value);
662
663                 [CLSCompliant (false)]
664                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
665                 extern public static void VolatileWrite (ref ushort address, ushort value);
666
667                 [CLSCompliant (false)]
668                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
669                 extern public static void VolatileWrite (ref uint address, uint value);
670
671                 [CLSCompliant (false)]
672                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
673                 extern public static void VolatileWrite (ref ulong address, ulong value);
674
675                 [CLSCompliant (false)]
676                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
677                 extern public static void VolatileWrite (ref UIntPtr address, UIntPtr value);
678                 
679 #endif
680                 
681         }
682 }