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