2003-11-12 Miguel de Icaza <miguel@ximian.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 //
9
10 using System.Runtime.Remoting.Contexts;
11 using System.Security.Principal;
12 using System.Globalization;
13 using System.Runtime.CompilerServices;
14 using System.Collections;
15
16 namespace System.Threading
17 {
18         public sealed class Thread
19         {
20                 // stores a thread handle
21                 private IntPtr system_thread_handle;
22                 
23                 private CultureInfo current_culture;
24                 private bool threadpool_thread;
25                 private ThreadState state = ThreadState.Unstarted;
26                 private object abort_exc;
27                 internal object abort_state;
28                 /* thread_id is only accessed from unmanaged code */
29                 private int thread_id;
30                 
31                 /* start_notify is used by the runtime to signal that Start()
32                  * is ok to return
33                  */
34                 private IntPtr start_notify;
35                 private IntPtr stack_ptr;
36                 private IntPtr static_data;
37                 private IntPtr jit_data;
38                 private IntPtr lock_data;
39                 
40                 private ThreadStart threadstart;
41                 private string thread_name=null;
42                 
43                 
44                 public static Context CurrentContext {
45                         get {
46                                 return(AppDomain.InternalGetContext ());
47                         }
48                 }
49
50                 [MonoTODO]
51                 public static IPrincipal CurrentPrincipal {
52                         get {
53                                 // FIXME -
54                                 // System.Security.Principal.IPrincipal
55                                 // not yet implemented
56                                 return(null);
57                         }
58                         
59                         set {
60                         }
61                 }
62
63                 // Looks up the object associated with the current thread
64                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
65                 private extern static Thread CurrentThread_internal();
66                 
67                 public static Thread CurrentThread {
68                         get {
69                                 return(CurrentThread_internal());
70                         }
71                 }
72
73                 internal static int CurrentThreadId {
74                         get {
75                                 return CurrentThread.thread_id;
76                         }
77                 }
78
79                 // Looks up the slot hash for the current thread
80                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
81                 private extern static Hashtable SlotHash_lookup();
82
83                 // Stores the slot hash for the current thread
84                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
85                 private extern static void SlotHash_store(Hashtable slothash);
86
87                 private static Hashtable GetTLSSlotHash() {
88                         Hashtable slothash=SlotHash_lookup();
89                         if(slothash==null) {
90                                 // Not synchronised, because this is
91                                 // thread specific anyway.
92                                 slothash=new Hashtable();
93                                 SlotHash_store(slothash);
94                         }
95
96                         return(slothash);
97                 }
98                 
99                 internal static object ResetDataStoreStatus () {
100                         Hashtable slothash=SlotHash_lookup();
101                         SlotHash_store(null);
102                         return slothash;
103                 }
104
105                 internal static void RestoreDataStoreStatus (object data) {
106                         SlotHash_store((Hashtable)data);
107                 }
108
109                 public static LocalDataStoreSlot AllocateDataSlot() {
110                         LocalDataStoreSlot slot = new LocalDataStoreSlot();
111
112                         return(slot);
113                 }
114
115                 // Stores a hash keyed by strings of LocalDataStoreSlot objects
116                 static Hashtable datastorehash;
117
118                 private static void InitDataStoreHash () {
119                         lock (typeof (Thread)) {
120                                 if (datastorehash == null) {
121                                         datastorehash = Hashtable.Synchronized(new Hashtable());
122                                 }
123                         }
124                 }
125                 
126                 public static LocalDataStoreSlot AllocateNamedDataSlot(string name) {
127                         lock (typeof (Thread)) {
128                                 if (datastorehash == null)
129                                         InitDataStoreHash ();
130                                 LocalDataStoreSlot slot = (LocalDataStoreSlot)datastorehash[name];
131                                 if(slot!=null) {
132                                         // This exception isnt documented (of
133                                         // course) but .net throws it
134                                         throw new ArgumentException("Named data slot already added");
135                                 }
136                         
137                                 slot = new LocalDataStoreSlot();
138
139                                 datastorehash.Add(name, slot);
140
141                                 return(slot);
142                         }
143                 }
144
145                 public static void FreeNamedDataSlot(string name) {
146                         lock (typeof (Thread)) {
147                                 if (datastorehash == null)
148                                         InitDataStoreHash ();
149                                 LocalDataStoreSlot slot=(LocalDataStoreSlot)datastorehash[name];
150
151                                 if(slot!=null) {
152                                         datastorehash.Remove(slot);
153                                 }
154                         }
155                 }
156
157                 public static object GetData(LocalDataStoreSlot slot) {
158                         Hashtable slothash=GetTLSSlotHash();
159                         return(slothash[slot]);
160                 }
161
162                 public static AppDomain GetDomain() {
163                         return AppDomain.CurrentDomain;
164                 }
165
166                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
167                 public extern static int GetDomainID();
168
169                 public static LocalDataStoreSlot GetNamedDataSlot(string name) {
170                         if (datastorehash == null)
171                                 InitDataStoreHash ();
172                         LocalDataStoreSlot slot=(LocalDataStoreSlot)datastorehash[name];
173
174                         if(slot==null) {
175                                 slot=AllocateNamedDataSlot(name);
176                         }
177                         
178                         return(slot);
179                 }
180                 
181                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
182                 private extern static void ResetAbort_internal();
183
184                 public static void ResetAbort()
185                 {
186                         Thread thread=CurrentThread;
187
188                         thread.clr_state(ThreadState.AbortRequested);
189                         ResetAbort_internal();
190                 }
191                 
192
193                 public static void SetData(LocalDataStoreSlot slot,
194                                            object data) {
195                         Hashtable slothash=GetTLSSlotHash();
196
197                         if(slothash.Contains(slot)) {
198                                 slothash.Remove(slot);
199                         }
200                         
201                         slothash.Add(slot, data);
202                 }
203
204                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
205                 private extern static void Sleep_internal(int ms);
206
207                 public static void Sleep(int millisecondsTimeout) {
208                         if((millisecondsTimeout<0) && (millisecondsTimeout != Timeout.Infinite)) {
209                                 throw new ArgumentException("Negative timeout");
210                         }
211                         Thread thread=CurrentThread;
212                                 
213                         thread.set_state(ThreadState.WaitSleepJoin);
214                                 
215                         Sleep_internal(millisecondsTimeout);
216                         thread.clr_state(ThreadState.WaitSleepJoin);
217                 }
218
219                 public static void Sleep(TimeSpan timeout) {
220                         // LAMESPEC: says to throw ArgumentException too
221                         int ms=Convert.ToInt32(timeout.TotalMilliseconds);
222                         
223                         if(ms < 0 || ms > Int32.MaxValue) {
224                                 throw new ArgumentOutOfRangeException("Timeout out of range");
225                         }
226
227                         Thread thread=CurrentThread;
228                                 
229                         thread.set_state(ThreadState.WaitSleepJoin);
230                         Sleep_internal(ms);
231                         thread.clr_state(ThreadState.WaitSleepJoin);
232                 }
233
234                 // Returns the system thread handle
235                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
236                 private extern IntPtr Thread_internal(ThreadStart start);
237
238                 public Thread(ThreadStart start) {
239                         if(start==null) {
240                                 throw new ArgumentNullException("Null ThreadStart");
241                         }
242                         threadstart=start;
243
244                         // This is a two-stage thread launch.  Thread_internal
245                         // creates the new thread, but blocks it until
246                         // Start() is called later.
247                         system_thread_handle=Thread_internal(start);
248
249                         // Should throw an exception here if
250                         // Thread_internal returns NULL
251                         if(system_thread_handle==(IntPtr)0) {
252                                 throw new SystemException("Thread creation failed");
253                         }
254                 }
255
256                 [MonoTODO]
257                 public ApartmentState ApartmentState {
258                         get {
259                                 // FIXME
260                                 return(ApartmentState.Unknown);
261                         }
262                         
263                         set {
264                         }
265                 }
266
267                 [MonoTODO]
268                 public CultureInfo CurrentCulture {
269                         get {
270                                 if (current_culture == null)
271                                         current_culture = CultureInfo.InvariantCulture;
272                                 return current_culture;
273                         }
274                         
275                         set {
276                                 current_culture = value;
277                         }
278                 }
279
280                 [MonoTODO]
281                 public CultureInfo CurrentUICulture {
282                         get {
283                                 // FIXME
284                                 return(CurrentCulture);
285                         }
286                         
287                         set {
288                                 // FIXME
289                                 CurrentCulture=value;
290                         }
291                 }
292
293                 public bool IsThreadPoolThread {
294                         get {
295                                 return IsThreadPoolThreadInternal;
296                         }
297                 }
298
299                 internal bool IsThreadPoolThreadInternal {
300                         get {
301                                 return threadpool_thread;
302                         }
303                         set {
304                                 threadpool_thread = value;
305                         }
306                 }
307
308                 public bool IsAlive {
309                         get {
310                                 ThreadState curstate=state;
311                                 
312                                 if((curstate & ThreadState.Aborted) != 0 ||
313                                    (curstate & ThreadState.Stopped) != 0 ||
314                                    (curstate & ThreadState.Unstarted) != 0) {
315                                         return(false);
316                                 } else {
317                                         return(true);
318                                 }
319                         }
320                 }
321
322                 public bool IsBackground {
323                         get {
324                                 if((state & ThreadState.Background) != 0) {
325                                         return(true);
326                                 } else {
327                                         return(false);
328                                 }
329                         }
330                         
331                         set {
332                                 if(value==true) {
333                                         set_state(ThreadState.Background);
334                                 } else {
335                                         clr_state(ThreadState.Background);
336                                 }
337                         }
338                 }
339
340                 public string Name {
341                         get {
342                                 return(thread_name);
343                         }
344                         
345                         set {
346                                 thread_name=value;
347                         }
348                 }
349
350                 [MonoTODO]
351                 public ThreadPriority Priority {
352                         get {
353                                 // FIXME
354                                 return(ThreadPriority.Lowest);
355                         }
356                         
357                         set {
358                         }
359                 }
360
361                 public ThreadState ThreadState {
362                         get {
363                                 return(state);
364                         }
365                 }
366
367                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
368                 private extern void Abort_internal (object stateInfo);
369
370                 public void Abort() {
371                         set_state(ThreadState.AbortRequested);
372                         Abort_internal (null);
373                 }
374
375                 public void Abort(object stateInfo) {
376                         set_state(ThreadState.AbortRequested);
377                         Abort_internal(stateInfo);
378                 }
379                 
380
381                 [MonoTODO]
382                 public void Interrupt() {
383                         // FIXME
384                 }
385
386                 // The current thread joins with 'this'. Set ms to 0 to block
387                 // until this actually exits.
388                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
389                 private extern bool Join_internal(int ms, IntPtr handle);
390                 
391                 public void Join() {
392                         if((state & ThreadState.Unstarted) != 0) {
393                                 throw new ThreadStateException("Thread has not been started");
394                         }
395                         
396                         Thread thread=CurrentThread;
397                                 
398                         thread.set_state(ThreadState.WaitSleepJoin);
399                         Join_internal(Timeout.Infinite, system_thread_handle);
400                         thread.clr_state(ThreadState.WaitSleepJoin);
401                 }
402
403                 public bool Join(int millisecondsTimeout) {
404                         if (millisecondsTimeout != Timeout.Infinite && millisecondsTimeout < 0)
405                                 throw new ArgumentException ("Timeout less than zero", "millisecondsTimeout");
406
407                         if((state & ThreadState.Unstarted) != 0) {
408                                 throw new ThreadStateException("Thread has not been started");
409                         }
410
411                         Thread thread=CurrentThread;
412                                 
413                         thread.set_state(ThreadState.WaitSleepJoin);
414                         bool ret=Join_internal(millisecondsTimeout,
415                                                system_thread_handle);
416                         thread.clr_state(ThreadState.WaitSleepJoin);
417
418                         return(ret);
419                 }
420
421                 public bool Join(TimeSpan timeout) {
422                         // LAMESPEC: says to throw ArgumentException too
423                         int ms=Convert.ToInt32(timeout.TotalMilliseconds);
424                         
425                         if(ms < 0 || ms > Int32.MaxValue) {
426                                 throw new ArgumentOutOfRangeException("timeout out of range");
427                         }
428                         if((state & ThreadState.Unstarted) != 0) {
429                                 throw new ThreadStateException("Thread has not been started");
430                         }
431
432                         Thread thread=CurrentThread;
433
434                         thread.set_state(ThreadState.WaitSleepJoin);
435                         bool ret=Join_internal(ms, system_thread_handle);
436                         thread.clr_state(ThreadState.WaitSleepJoin);
437
438                         return(ret);
439                 }
440
441                 [MonoTODO]
442                 public void Resume() {
443                         throw new NotImplementedException ();
444                 }
445
446                 // Launches the thread
447                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
448                 private extern void Start_internal(IntPtr handle);
449                 
450                 public void Start() {
451                         lock(this) {
452                                 if((state & ThreadState.Unstarted) == 0) {
453                                         throw new ThreadStateException("Thread has already been started");
454                                 }
455                                 
456                                 // Launch this thread
457                                 Start_internal(system_thread_handle);
458
459                                 // Mark the thread state as Running
460                                 // (which is all bits
461                                 // cleared). Therefore just remove the
462                                 // Unstarted bit
463                                 clr_state(ThreadState.Unstarted);
464                         }
465                 }
466
467                 [MonoTODO]
468                 public void Suspend() {
469                         if((state & ThreadState.Unstarted) != 0 || !IsAlive) {
470                                 throw new ThreadStateException("Thread has not been started, or is dead");
471                         }
472
473                         set_state(ThreadState.SuspendRequested);
474                         // FIXME - somehow let the interpreter know that
475                         // this thread should now suspend
476                         Console.WriteLine ("WARNING: Thread.Suspend () partially implemented");
477                 }
478
479                 // Closes the system thread handle
480                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
481                 private extern void Thread_free_internal(IntPtr handle);
482
483                 ~Thread() {
484                         // Free up the handle
485                         Thread_free_internal(system_thread_handle);
486                 }
487
488                 private void set_state(ThreadState set) {
489                         lock(this) {
490                                 state |= set;
491                         }
492                 }
493                 private void clr_state(ThreadState clr) {
494                         lock(this) {
495                                 state &= ~clr;
496                         }
497                 }
498
499 #if NET_1_1
500                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
501                 extern public static byte VolatileRead (ref byte address);
502                 
503                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
504                 extern public static double VolatileRead (ref double address);
505                 
506                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
507                 extern public static short VolatileRead (ref short address);
508                 
509                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
510                 extern public static int VolatileRead (ref int address);
511                 
512                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
513                 extern public static long VolatileRead (ref long address);
514                 
515                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
516                 extern public static IntPtr VolatileRead (ref IntPtr address);
517                 
518                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
519                 extern public static object VolatileRead (ref object address);
520
521                 [CLSCompliant(false)]
522                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
523                 extern public static sbyte VolatileRead (ref sbyte address);
524                 
525                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
526                 extern public static float VolatileRead (ref float address);
527
528                 [CLSCompliant (false)]
529                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
530                 extern public static ushort VolatileRead (ref ushort address);
531
532                 [CLSCompliant (false)]
533                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
534                 extern public static uint VolatileRead (ref uint address);
535
536                 [CLSCompliant (false)]
537                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
538                 extern public static ulong VolatileRead (ref ulong address);
539
540                 [CLSCompliant (false)]
541                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
542                 extern public static byte VolatileRead (ref UIntPtr address);
543
544                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
545                 extern public static void VolatileWrite (ref byte address, byte value);
546                 
547                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
548                 extern public static void VolatileWrite (ref double address, double value);
549                 
550                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
551                 extern public static void VolatileWrite (ref short address, short value);
552                 
553                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
554                 extern public static void VolatileWrite (ref int address, int value);
555                 
556                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
557                 extern public static void VolatileWrite (ref long address, long value);
558                 
559                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
560                 extern public static void VolatileWrite (ref IntPtr address, IntPtr value);
561                 
562                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
563                 extern public static void VolatileWrite (ref object address, object value);
564
565                 [CLSCompliant(false)]
566                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
567                 extern public static void VolatileWrite (ref sbyte address, sbyte value);
568                 
569                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
570                 extern public static void VolatileWrite (ref float address, float value);
571
572                 [CLSCompliant (false)]
573                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
574                 extern public static void VolatileWrite (ref ushort address, ushort value);
575
576                 [CLSCompliant (false)]
577                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
578                 extern public static void VolatileWrite (ref uint address, uint value);
579
580                 [CLSCompliant (false)]
581                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
582                 extern public static void VolatileWrite (ref ulong address, ulong value);
583
584                 [CLSCompliant (false)]
585                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
586                 extern public static void VolatileWrite (ref UIntPtr address, UIntPtr value);
587                 
588 #endif
589                 
590         }
591 }