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