Tue Sep 10 12:12:51 CEST 2002 Paolo Molaro <lupus@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 = false;
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                 [MonoTODO]
32                 public static Context CurrentContext {
33                         get {
34                                 // FIXME -
35                                 // System.Runtime.Remoting.Context not
36                                 // yet implemented
37                                 return(null);
38                         }
39                 }
40
41                 [MonoTODO]
42                 public static IPrincipal CurrentPrincipal {
43                         get {
44                                 // FIXME -
45                                 // System.Security.Principal.IPrincipal
46                                 // not yet implemented
47                                 return(null);
48                         }
49                         
50                         set {
51                         }
52                 }
53
54                 // Looks up the object associated with the current thread
55                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
56                 private extern static Thread CurrentThread_internal();
57                 
58                 public static Thread CurrentThread {
59                         get {
60                                 return(CurrentThread_internal());
61                         }
62                 }
63
64                 // Looks up the slot hash for the current thread
65                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
66                 private extern static Hashtable SlotHash_lookup();
67
68                 // Stores the slot hash for the current thread
69                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
70                 private extern static void SlotHash_store(Hashtable slothash);
71
72                 private static Hashtable GetTLSSlotHash() {
73                         Hashtable slothash=SlotHash_lookup();
74                         if(slothash==null) {
75                                 // Not synchronised, because this is
76                                 // thread specific anyway.
77                                 slothash=new Hashtable();
78                                 SlotHash_store(slothash);
79                         }
80
81                         return(slothash);
82                 }
83
84                 public static LocalDataStoreSlot AllocateDataSlot() {
85                         LocalDataStoreSlot slot = new LocalDataStoreSlot();
86
87                         return(slot);
88                 }
89
90                 // Stores a hash keyed by strings of LocalDataStoreSlot objects
91                 static Hashtable datastorehash = Hashtable.Synchronized(new Hashtable());
92                 
93                 public static LocalDataStoreSlot AllocateNamedDataSlot(string name) {
94                         LocalDataStoreSlot slot = (LocalDataStoreSlot)datastorehash[name];
95                         if(slot!=null) {
96                                 // This exception isnt documented (of
97                                 // course) but .net throws it
98                                 throw new ArgumentException("Named data slot already added");
99                         }
100                         
101                         slot = new LocalDataStoreSlot();
102
103                         datastorehash.Add(name, slot);
104                         
105                         return(slot);
106                 }
107
108                 public static void FreeNamedDataSlot(string name) {
109                         LocalDataStoreSlot slot=(LocalDataStoreSlot)datastorehash[name];
110
111                         if(slot!=null) {
112                                 datastorehash.Remove(slot);
113                         }
114                 }
115
116                 public static object GetData(LocalDataStoreSlot slot) {
117                         Hashtable slothash=GetTLSSlotHash();
118                         return(slothash[slot]);
119                 }
120
121                 [MonoTODO]
122                 public static AppDomain GetDomain() {
123                         // FIXME
124                         return(null);
125                 }
126
127                 [MonoTODO]
128                 public static int GetDomainID() {
129                         // FIXME
130                         return(0);
131                 }
132
133                 public static LocalDataStoreSlot GetNamedDataSlot(string name) {
134                         LocalDataStoreSlot slot=(LocalDataStoreSlot)datastorehash[name];
135
136                         if(slot==null) {
137                                 slot=AllocateNamedDataSlot(name);
138                         }
139                         
140                         return(slot);
141                 }
142                 
143                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
144                 public extern static void ResetAbort();
145
146                 public static void SetData(LocalDataStoreSlot slot,
147                                            object data) {
148                         Hashtable slothash=GetTLSSlotHash();
149
150                         if(slothash[slot]!=null) {
151                                 slothash.Remove(slot);
152                         }
153                         
154                         slothash.Add(slot, data);
155                 }
156
157                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
158                 private extern static void Sleep_internal(int ms);
159
160                 public static void Sleep(int millisecondsTimeout) {
161                         if(millisecondsTimeout<0) {
162                                 throw new ArgumentException("Negative timeout");
163                         }
164                         Thread thread=CurrentThread;
165                                 
166                         thread.set_state(ThreadState.WaitSleepJoin);
167                                 
168                         Sleep_internal(millisecondsTimeout);
169                         thread.clr_state(ThreadState.WaitSleepJoin);
170                 }
171
172                 public static void Sleep(TimeSpan timeout) {
173                         // LAMESPEC: says to throw ArgumentException too
174                         if(timeout.Milliseconds < 0 || timeout.Milliseconds > Int32.MaxValue) {
175                                 throw new ArgumentOutOfRangeException("Timeout out of range");
176                         }
177
178                         Thread thread=CurrentThread;
179                                 
180                         thread.set_state(ThreadState.WaitSleepJoin);
181                         Sleep_internal(timeout.Milliseconds);
182                         thread.clr_state(ThreadState.WaitSleepJoin);
183                 }
184
185                 // Returns the system thread handle
186                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
187                 private extern IntPtr Thread_internal(ThreadStart start);
188
189                 public Thread(ThreadStart start) {
190                         if(start==null) {
191                                 throw new ArgumentNullException("Null ThreadStart");
192                         }
193
194                         // This is a two-stage thread launch.  Thread_internal
195                         // creates the new thread, but blocks it until
196                         // Start() is called later.
197                         system_thread_handle=Thread_internal(start);
198
199                         // Should throw an exception here if
200                         // Thread_internal returns NULL
201                 }
202
203                 [MonoTODO]
204                 public ApartmentState ApartmentState {
205                         get {
206                                 // FIXME
207                                 return(ApartmentState.Unknown);
208                         }
209                         
210                         set {
211                         }
212                 }
213
214                 [MonoTODO]
215                 public CultureInfo CurrentCulture {
216                         get {
217                                 if (current_culture == null)
218                                         current_culture = new CultureInfo ("");
219                                 return current_culture;
220                         }
221                         
222                         set {
223                                 current_culture = value;
224                         }
225                 }
226
227                 [MonoTODO]
228                 public CultureInfo CurrentUICulture {
229                         get {
230                                 // FIXME
231                                 return(CurrentCulture);
232                         }
233                         
234                         set {
235                                 // FIXME
236                                 CurrentCulture=value;
237                         }
238                 }
239
240                 public bool IsThreadPoolThread {
241                         get {
242                                 return IsThreadPoolThreadInternal;
243                         }
244                 }
245
246                 internal bool IsThreadPoolThreadInternal {
247                         get {
248                                 return threadpool_thread;
249                         }
250                         set {
251                                 threadpool_thread = value;
252                         }
253                 }
254
255                 public bool IsAlive {
256                         get {
257                                 // LAMESPEC: is a Stopped or Suspended
258                                 // thread dead?
259                                 ThreadState curstate=state;
260                                 
261                                 if((curstate & ThreadState.Aborted) != 0 ||
262                                    (curstate & ThreadState.AbortRequested) != 0 ||
263                                    (curstate & ThreadState.Unstarted) != 0) {
264                                         return(false);
265                                 } else {
266                                         return(true);
267                                 }
268                         }
269                 }
270
271                 public bool IsBackground {
272                         get {
273                                 if((state & ThreadState.Background) != 0) {
274                                         return(true);
275                                 } else {
276                                         return(false);
277                                 }
278                         }
279                         
280                         set {
281                                 if(value==true) {
282                                         set_state(ThreadState.Background);
283                                 } else {
284                                         clr_state(ThreadState.Background);
285                                 }
286                         }
287                 }
288
289                 private string thread_name=null;
290                 
291                 public string Name {
292                         get {
293                                 return(thread_name);
294                         }
295                         
296                         set {
297                                 thread_name=value;
298                         }
299                 }
300
301                 [MonoTODO]
302                 public ThreadPriority Priority {
303                         get {
304                                 // FIXME
305                                 return(ThreadPriority.Lowest);
306                         }
307                         
308                         set {
309                         }
310                 }
311
312                 public ThreadState ThreadState {
313                         get {
314                                 return(state);
315                         }
316                 }
317
318                 public void Abort() {
319                         Abort (null);
320                 }
321
322                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
323                 public extern void Abort (object stateInfo);
324
325                 [MonoTODO]
326                 public void Interrupt() {
327                         // FIXME
328                 }
329
330                 // The current thread joins with 'this'. Set ms to 0 to block
331                 // until this actually exits.
332                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
333                 private extern bool Join_internal(int ms, IntPtr handle);
334                 
335                 public void Join() {
336                         if((state & ThreadState.Unstarted) != 0) {
337                                 throw new ThreadStateException("Thread has not been started");
338                         }
339                         
340                         Thread thread=CurrentThread;
341                                 
342                         thread.set_state(ThreadState.WaitSleepJoin);
343                         Join_internal(Timeout.Infinite, system_thread_handle);
344                         thread.clr_state(ThreadState.WaitSleepJoin);
345                 }
346
347                 public bool Join(int millisecondsTimeout) {
348                         if(millisecondsTimeout<0) {
349                                 throw new ArgumentException("Timeout less than zero");
350                         }
351                         if((state & ThreadState.Unstarted) != 0) {
352                                 throw new ThreadStateException("Thread has not been started");
353                         }
354
355                         Thread thread=CurrentThread;
356                                 
357                         thread.set_state(ThreadState.WaitSleepJoin);
358                         bool ret=Join_internal(millisecondsTimeout,
359                                                system_thread_handle);
360                         thread.clr_state(ThreadState.WaitSleepJoin);
361
362                         return(ret);
363                 }
364
365                 public bool Join(TimeSpan timeout) {
366                         // LAMESPEC: says to throw ArgumentException too
367                         if(timeout.Milliseconds < 0 || timeout.Milliseconds > Int32.MaxValue) {
368                                 throw new ArgumentOutOfRangeException("timeout out of range");
369                         }
370                         if((state & ThreadState.Unstarted) != 0) {
371                                 throw new ThreadStateException("Thread has not been started");
372                         }
373
374                         Thread thread=CurrentThread;
375
376                         thread.set_state(ThreadState.WaitSleepJoin);
377                         bool ret=Join_internal(timeout.Milliseconds,
378                                                system_thread_handle);
379                         thread.clr_state(ThreadState.WaitSleepJoin);
380
381                         return(ret);
382                 }
383
384                 [MonoTODO]
385                 public void Resume() {
386                         // FIXME
387                 }
388
389                 // Launches the thread
390                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
391                 private extern void Start_internal(IntPtr handle);
392                 
393                 public void Start() {
394                         if((state & ThreadState.Unstarted) == 0) {
395                                 throw new ThreadStateException("Thread has already been started");
396                         }
397
398                         // Mark the thread state as Running (which is
399                         // all bits cleared). Therefore just remove
400                         // the Unstarted bit
401                         clr_state(ThreadState.Unstarted);
402                                 
403                         // Launch this thread
404                         Start_internal(system_thread_handle);
405                 }
406
407                 [MonoTODO]
408                 public void Suspend() {
409                         if((state & ThreadState.Unstarted) != 0 || !IsAlive) {
410                                 throw new ThreadStateException("Thread has not been started, or is dead");
411                         }
412
413                         set_state(ThreadState.SuspendRequested);
414                         // FIXME - somehow let the interpreter know that
415                         // this thread should now suspend
416                 }
417
418                 // Closes the system thread handle
419                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
420                 private extern void Thread_free_internal(IntPtr handle);
421
422                 ~Thread() {
423                         // Free up the handle
424                         Thread_free_internal(system_thread_handle);
425                 }
426
427                 private void set_state(ThreadState set) {
428                         lock(this) {
429                                 state |= set;
430                         }
431                 }
432                 private void clr_state(ThreadState clr) {
433                         lock(this) {
434                                 state &= ~clr;
435                         }
436                 }
437         }
438 }