2002-10-25 Zoltan Varga <vargaz@freemail.hu>
[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                 public static AppDomain GetDomain() {
122                         return AppDomain.CurrentDomain;
123                 }
124
125                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
126                 public extern static int GetDomainID();
127
128                 public static LocalDataStoreSlot GetNamedDataSlot(string name) {
129                         LocalDataStoreSlot slot=(LocalDataStoreSlot)datastorehash[name];
130
131                         if(slot==null) {
132                                 slot=AllocateNamedDataSlot(name);
133                         }
134                         
135                         return(slot);
136                 }
137                 
138                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
139                 public extern static void ResetAbort();
140
141                 public static void SetData(LocalDataStoreSlot slot,
142                                            object data) {
143                         Hashtable slothash=GetTLSSlotHash();
144
145                         if(slothash[slot]!=null) {
146                                 slothash.Remove(slot);
147                         }
148                         
149                         slothash.Add(slot, data);
150                 }
151
152                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
153                 private extern static void Sleep_internal(int ms);
154
155                 public static void Sleep(int millisecondsTimeout) {
156                         if(millisecondsTimeout<0) {
157                                 throw new ArgumentException("Negative timeout");
158                         }
159                         Thread thread=CurrentThread;
160                                 
161                         thread.set_state(ThreadState.WaitSleepJoin);
162                                 
163                         Sleep_internal(millisecondsTimeout);
164                         thread.clr_state(ThreadState.WaitSleepJoin);
165                 }
166
167                 public static void Sleep(TimeSpan timeout) {
168                         // LAMESPEC: says to throw ArgumentException too
169                         if(timeout.Milliseconds < 0 || timeout.Milliseconds > Int32.MaxValue) {
170                                 throw new ArgumentOutOfRangeException("Timeout out of range");
171                         }
172
173                         Thread thread=CurrentThread;
174                                 
175                         thread.set_state(ThreadState.WaitSleepJoin);
176                         Sleep_internal(timeout.Milliseconds);
177                         thread.clr_state(ThreadState.WaitSleepJoin);
178                 }
179
180                 // Returns the system thread handle
181                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
182                 private extern IntPtr Thread_internal(ThreadStart start);
183
184                 public Thread(ThreadStart start) {
185                         if(start==null) {
186                                 throw new ArgumentNullException("Null ThreadStart");
187                         }
188
189                         // This is a two-stage thread launch.  Thread_internal
190                         // creates the new thread, but blocks it until
191                         // Start() is called later.
192                         system_thread_handle=Thread_internal(start);
193
194                         // Should throw an exception here if
195                         // Thread_internal returns NULL
196                 }
197
198                 [MonoTODO]
199                 public ApartmentState ApartmentState {
200                         get {
201                                 // FIXME
202                                 return(ApartmentState.Unknown);
203                         }
204                         
205                         set {
206                         }
207                 }
208
209                 [MonoTODO]
210                 public CultureInfo CurrentCulture {
211                         get {
212                                 if (current_culture == null)
213                                         current_culture = new CultureInfo ("");
214                                 return current_culture;
215                         }
216                         
217                         set {
218                                 current_culture = value;
219                         }
220                 }
221
222                 [MonoTODO]
223                 public CultureInfo CurrentUICulture {
224                         get {
225                                 // FIXME
226                                 return(CurrentCulture);
227                         }
228                         
229                         set {
230                                 // FIXME
231                                 CurrentCulture=value;
232                         }
233                 }
234
235                 public bool IsThreadPoolThread {
236                         get {
237                                 return IsThreadPoolThreadInternal;
238                         }
239                 }
240
241                 internal bool IsThreadPoolThreadInternal {
242                         get {
243                                 return threadpool_thread;
244                         }
245                         set {
246                                 threadpool_thread = value;
247                         }
248                 }
249
250                 public bool IsAlive {
251                         get {
252                                 // LAMESPEC: is a Stopped or Suspended
253                                 // thread dead?
254                                 ThreadState curstate=state;
255                                 
256                                 if((curstate & ThreadState.Aborted) != 0 ||
257                                    (curstate & ThreadState.AbortRequested) != 0 ||
258                                    (curstate & ThreadState.Unstarted) != 0) {
259                                         return(false);
260                                 } else {
261                                         return(true);
262                                 }
263                         }
264                 }
265
266                 public bool IsBackground {
267                         get {
268                                 if((state & ThreadState.Background) != 0) {
269                                         return(true);
270                                 } else {
271                                         return(false);
272                                 }
273                         }
274                         
275                         set {
276                                 if(value==true) {
277                                         set_state(ThreadState.Background);
278                                 } else {
279                                         clr_state(ThreadState.Background);
280                                 }
281                         }
282                 }
283
284                 private string thread_name=null;
285                 
286                 public string Name {
287                         get {
288                                 return(thread_name);
289                         }
290                         
291                         set {
292                                 thread_name=value;
293                         }
294                 }
295
296                 [MonoTODO]
297                 public ThreadPriority Priority {
298                         get {
299                                 // FIXME
300                                 return(ThreadPriority.Lowest);
301                         }
302                         
303                         set {
304                         }
305                 }
306
307                 public ThreadState ThreadState {
308                         get {
309                                 return(state);
310                         }
311                 }
312
313                 public void Abort() {
314                         Abort (null);
315                 }
316
317                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
318                 public extern void Abort (object stateInfo);
319
320                 [MonoTODO]
321                 public void Interrupt() {
322                         // FIXME
323                 }
324
325                 // The current thread joins with 'this'. Set ms to 0 to block
326                 // until this actually exits.
327                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
328                 private extern bool Join_internal(int ms, IntPtr handle);
329                 
330                 public void Join() {
331                         if((state & ThreadState.Unstarted) != 0) {
332                                 throw new ThreadStateException("Thread has not been started");
333                         }
334                         
335                         Thread thread=CurrentThread;
336                                 
337                         thread.set_state(ThreadState.WaitSleepJoin);
338                         Join_internal(Timeout.Infinite, system_thread_handle);
339                         thread.clr_state(ThreadState.WaitSleepJoin);
340                 }
341
342                 public bool Join(int millisecondsTimeout) {
343                         if(millisecondsTimeout<0) {
344                                 throw new ArgumentException("Timeout less than zero");
345                         }
346                         if((state & ThreadState.Unstarted) != 0) {
347                                 throw new ThreadStateException("Thread has not been started");
348                         }
349
350                         Thread thread=CurrentThread;
351                                 
352                         thread.set_state(ThreadState.WaitSleepJoin);
353                         bool ret=Join_internal(millisecondsTimeout,
354                                                system_thread_handle);
355                         thread.clr_state(ThreadState.WaitSleepJoin);
356
357                         return(ret);
358                 }
359
360                 public bool Join(TimeSpan timeout) {
361                         // LAMESPEC: says to throw ArgumentException too
362                         if(timeout.Milliseconds < 0 || timeout.Milliseconds > Int32.MaxValue) {
363                                 throw new ArgumentOutOfRangeException("timeout out of range");
364                         }
365                         if((state & ThreadState.Unstarted) != 0) {
366                                 throw new ThreadStateException("Thread has not been started");
367                         }
368
369                         Thread thread=CurrentThread;
370
371                         thread.set_state(ThreadState.WaitSleepJoin);
372                         bool ret=Join_internal(timeout.Milliseconds,
373                                                system_thread_handle);
374                         thread.clr_state(ThreadState.WaitSleepJoin);
375
376                         return(ret);
377                 }
378
379                 [MonoTODO]
380                 public void Resume() {
381                         // FIXME
382                 }
383
384                 // Launches the thread
385                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
386                 private extern void Start_internal(IntPtr handle);
387                 
388                 public void Start() {
389                         if((state & ThreadState.Unstarted) == 0) {
390                                 throw new ThreadStateException("Thread has already been started");
391                         }
392
393                         // Mark the thread state as Running (which is
394                         // all bits cleared). Therefore just remove
395                         // the Unstarted bit
396                         clr_state(ThreadState.Unstarted);
397                                 
398                         // Launch this thread
399                         Start_internal(system_thread_handle);
400                 }
401
402                 [MonoTODO]
403                 public void Suspend() {
404                         if((state & ThreadState.Unstarted) != 0 || !IsAlive) {
405                                 throw new ThreadStateException("Thread has not been started, or is dead");
406                         }
407
408                         set_state(ThreadState.SuspendRequested);
409                         // FIXME - somehow let the interpreter know that
410                         // this thread should now suspend
411                 }
412
413                 // Closes the system thread handle
414                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
415                 private extern void Thread_free_internal(IntPtr handle);
416
417                 ~Thread() {
418                         // Free up the handle
419                         Thread_free_internal(system_thread_handle);
420                 }
421
422                 private void set_state(ThreadState set) {
423                         lock(this) {
424                                 state |= set;
425                         }
426                 }
427                 private void clr_state(ThreadState clr) {
428                         lock(this) {
429                                 state &= ~clr;
430                         }
431                 }
432         }
433 }