Revert until we track down the RH9 bug
[mono.git] / mono / io-layer / threads.c
1 /*
2  * threads.c:  Thread handles
3  *
4  * Author:
5  *      Dick Porter (dick@ximian.com)
6  *
7  * (C) 2002 Ximian, Inc.
8  */
9
10 #include <config.h>
11 #if HAVE_BOEHM_GC
12 #include <mono/os/gc_wrapper.h>
13 #include "mono/utils/mono-hash.h"
14 #endif
15 #include <glib.h>
16 #include <string.h>
17 #include <pthread.h>
18 #include <signal.h>
19 #include <sched.h>
20 #include <sys/time.h>
21 #include <errno.h>
22
23 #include <mono/io-layer/wapi.h>
24 #include <mono/io-layer/wapi-private.h>
25 #include <mono/io-layer/timed-thread.h>
26 #include <mono/io-layer/handles-private.h>
27 #include <mono/io-layer/misc-private.h>
28 #include <mono/io-layer/mono-mutex.h>
29 #include <mono/io-layer/thread-private.h>
30 #include <mono/io-layer/mono-spinlock.h>
31
32 #undef DEBUG
33 #undef TLS_DEBUG
34 #undef TLS_PTHREAD_MUTEX
35
36
37 /* Hash threads with tids. I thought of using TLS for this, but that
38  * would have to set the data in the new thread, which is more hassle
39  */
40 static mono_once_t thread_hash_once = MONO_ONCE_INIT;
41 static mono_mutex_t thread_hash_mutex = MONO_MUTEX_INITIALIZER;
42 static GHashTable *thread_hash=NULL;
43
44 #if HAVE_BOEHM_GC
45 static MonoGHashTable *tls_gc_hash = NULL;
46 #endif
47
48 static void thread_close_private (gpointer handle);
49 static void thread_own (gpointer handle);
50
51 struct _WapiHandleOps _wapi_thread_ops = {
52         NULL,                           /* close_shared */
53         thread_close_private,           /* close_private */
54         NULL,                           /* signal */
55         thread_own,                     /* own */
56         NULL,                           /* is_owned */
57 };
58
59 static mono_once_t thread_ops_once=MONO_ONCE_INIT;
60
61 #ifdef WITH_INCLUDED_LIBGC
62 static void gc_init (void);
63 #endif
64
65 static void thread_ops_init (void)
66 {
67         _wapi_handle_register_capabilities (WAPI_HANDLE_THREAD,
68                                             WAPI_HANDLE_CAP_WAIT);
69
70 #ifdef WITH_INCLUDED_LIBGC
71         gc_init ();
72 #endif
73 }
74
75 static void thread_close_private (gpointer handle)
76 {
77         struct _WapiHandlePrivate_thread *thread_handle;
78         gboolean ok;
79         
80         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD, NULL,
81                                 (gpointer *)&thread_handle);
82         if(ok==FALSE) {
83                 g_warning (G_GNUC_PRETTY_FUNCTION
84                            ": error looking up thread handle %p", handle);
85                 return;
86         }
87         
88 #ifdef DEBUG
89         g_message(G_GNUC_PRETTY_FUNCTION
90                   ": closing thread handle %p with thread %p id %ld",
91                   handle, thread_handle->thread,
92                   thread_handle->thread->id);
93 #endif
94
95         if(thread_handle->thread!=NULL) {
96                 _wapi_timed_thread_destroy (thread_handle->thread);
97         }
98 }
99
100 static void thread_own (gpointer handle)
101 {
102         struct _WapiHandle_thread *thread_handle;
103         struct _WapiHandlePrivate_thread *thread_private_handle;
104         gboolean ok;
105         
106         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
107                                 (gpointer *)&thread_handle,
108                                 (gpointer *)&thread_private_handle);
109         if(ok==FALSE) {
110                 g_warning (G_GNUC_PRETTY_FUNCTION
111                            ": error looking up thread handle %p", handle);
112                 return;
113         }
114
115         if(thread_private_handle->joined==FALSE) {
116                 _wapi_timed_thread_join (thread_private_handle->thread, NULL,
117                                          NULL);
118                 thread_private_handle->joined=TRUE;
119         }
120 }
121
122 static void thread_exit(guint32 exitstatus, gpointer handle)
123 {
124         struct _WapiHandle_thread *thread_handle;
125         struct _WapiHandlePrivate_thread *thread_private_handle;
126         gboolean ok;
127         
128         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
129                                 (gpointer *)&thread_handle,
130                                 (gpointer *)&thread_private_handle);
131         if(ok==FALSE) {
132                 g_warning (G_GNUC_PRETTY_FUNCTION
133                            ": error looking up thread handle %p", handle);
134                 return;
135         }
136
137         _wapi_handle_lock_handle (handle);
138
139 #ifdef DEBUG
140         g_message (G_GNUC_PRETTY_FUNCTION
141                    ": Recording thread handle %p exit status", handle);
142 #endif
143         
144         thread_handle->exitstatus=exitstatus;
145         thread_handle->state=THREAD_STATE_EXITED;
146         _wapi_handle_set_signal_state (handle, TRUE, TRUE);
147
148         _wapi_handle_unlock_handle (handle);
149         
150 #ifdef DEBUG
151         g_message(G_GNUC_PRETTY_FUNCTION
152                   ": Recording thread handle %p id %ld status as %d",
153                   handle, thread_private_handle->thread->id, exitstatus);
154 #endif
155
156         /* Remove this thread from the hash */
157         mono_mutex_lock(&thread_hash_mutex);
158         g_hash_table_remove(thread_hash, &thread_private_handle->thread->id);
159         mono_mutex_unlock(&thread_hash_mutex);
160
161         /* The thread is no longer active, so unref it */
162         _wapi_handle_unref (handle);
163 }
164
165 static void thread_hash_init(void)
166 {
167         thread_hash=g_hash_table_new(g_int_hash, g_int_equal);
168 }
169
170 /**
171  * CreateThread:
172  * @security: Ignored for now.
173  * @stacksize: the size in bytes of the new thread's stack. Use 0 to
174  * default to the normal stack size. (Ignored for now).
175  * @start: The function that the new thread should start with
176  * @param: The parameter to give to @start.
177  * @create: If 0, the new thread is ready to run immediately.  If
178  * %CREATE_SUSPENDED, the new thread will be in the suspended state,
179  * requiring a ResumeThread() call to continue running.
180  * @tid: If non-NULL, the ID of the new thread is stored here.
181  *
182  * Creates a new threading handle.
183  *
184  * Return value: a new handle, or NULL
185  */
186 gpointer CreateThread(WapiSecurityAttributes *security G_GNUC_UNUSED, guint32 stacksize G_GNUC_UNUSED,
187                       WapiThreadStart start, gpointer param, guint32 create,
188                       guint32 *tid) 
189 {
190         struct _WapiHandle_thread *thread_handle;
191         struct _WapiHandlePrivate_thread *thread_private_handle;
192         pthread_attr_t attr;
193         gpointer handle;
194         gboolean ok;
195         int ret;
196         
197         mono_once(&thread_hash_once, thread_hash_init);
198         mono_once (&thread_ops_once, thread_ops_init);
199         
200         if(start==NULL) {
201                 return(NULL);
202         }
203         
204         handle=_wapi_handle_new (WAPI_HANDLE_THREAD);
205         if(handle==_WAPI_HANDLE_INVALID) {
206                 g_warning (G_GNUC_PRETTY_FUNCTION
207                            ": error creating thread handle");
208                 return(NULL);
209         }
210
211         _wapi_handle_lock_handle (handle);
212         
213         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
214                                 (gpointer *)&thread_handle,
215                                 (gpointer *)&thread_private_handle);
216         if(ok==FALSE) {
217                 g_warning (G_GNUC_PRETTY_FUNCTION
218                            ": error looking up thread handle %p", handle);
219                 _wapi_handle_unlock_handle (handle);
220                 return(NULL);
221         }
222
223         /* Hold a reference while the thread is active, because we use
224          * the handle to store thread exit information
225          */
226         _wapi_handle_ref (handle);
227
228         thread_handle->state=THREAD_STATE_START;
229         
230         /* Lock around the thread create, so that the new thread cant
231          * race us to look up the thread handle in GetCurrentThread()
232          */
233         mono_mutex_lock(&thread_hash_mutex);
234         
235         /* Set a 2M stack size.  This is the default on Linux, but BSD
236          * needs it.  (The original bug report from Martin Dvorak <md@9ll.cz>
237          * set the size to 2M-4k.  I don't know why it's short by 4k, so
238          * I'm leaving it as 2M until I'm told differently.)
239          */
240         pthread_attr_init(&attr);
241         pthread_attr_setstacksize(&attr, 1024*1024*2);
242
243         ret=_wapi_timed_thread_create(&thread_private_handle->thread, &attr,
244                                       create, start, thread_exit, param,
245                                       handle);
246         if(ret!=0) {
247 #ifdef DEBUG
248                 g_message(G_GNUC_PRETTY_FUNCTION ": Thread create error: %s",
249                           strerror(ret));
250 #endif
251                 mono_mutex_unlock(&thread_hash_mutex);
252                 _wapi_handle_unlock_handle (handle);
253                 _wapi_handle_unref (handle);
254                 
255                 /* And again, because of the reference we took above */
256                 _wapi_handle_unref (handle);
257                 return(NULL);
258         }
259
260         g_hash_table_insert(thread_hash, &thread_private_handle->thread->id,
261                             handle);
262         mono_mutex_unlock(&thread_hash_mutex);
263         
264 #ifdef DEBUG
265         g_message(G_GNUC_PRETTY_FUNCTION
266                   ": Started thread handle %p thread %p ID %ld", handle,
267                   thread_private_handle->thread,
268                   thread_private_handle->thread->id);
269 #endif
270         
271         if(tid!=NULL) {
272 #ifdef PTHREAD_POINTER_ID
273                 *tid=GPOINTER_TO_UINT(thread_private_handle->thread->id);
274 #else
275                 *tid=thread_private_handle->thread->id;
276 #endif
277         }
278
279         _wapi_handle_unlock_handle (handle);
280         
281         return(handle);
282 }
283
284 gpointer OpenThread (guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, guint32 tid)
285 {
286         gpointer ret=NULL;
287         
288         mono_once(&thread_hash_once, thread_hash_init);
289         mono_once (&thread_ops_once, thread_ops_init);
290         
291 #ifdef DEBUG
292         g_message (G_GNUC_PRETTY_FUNCTION ": looking up thread %d", tid);
293 #endif
294
295         mono_mutex_lock(&thread_hash_mutex);
296         
297         ret=g_hash_table_lookup(thread_hash, &tid);
298         mono_mutex_unlock(&thread_hash_mutex);
299         
300         if(ret!=NULL) {
301                 _wapi_handle_ref (ret);
302         }
303         
304 #ifdef DEBUG
305         g_message (G_GNUC_PRETTY_FUNCTION ": returning thread handle %p", ret);
306 #endif
307         
308         return(ret);
309 }
310
311 /**
312  * ExitThread:
313  * @exitcode: Sets the thread's exit code, which can be read from
314  * another thread with GetExitCodeThread().
315  *
316  * Terminates the calling thread.  A thread can also exit by returning
317  * from its start function. When the last thread in a process
318  * terminates, the process itself terminates.
319  */
320 void ExitThread(guint32 exitcode)
321 {
322         _wapi_timed_thread_exit(exitcode);
323 }
324
325 /**
326  * GetExitCodeThread:
327  * @handle: The thread handle to query
328  * @exitcode: The thread @handle exit code is stored here
329  *
330  * Finds the exit code of @handle, and stores it in @exitcode.  If the
331  * thread @handle is still running, the value stored is %STILL_ACTIVE.
332  *
333  * Return value: %TRUE, or %FALSE on error.
334  */
335 gboolean GetExitCodeThread(gpointer handle, guint32 *exitcode)
336 {
337         struct _WapiHandle_thread *thread_handle;
338         struct _WapiHandlePrivate_thread *thread_private_handle;
339         gboolean ok;
340         
341         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
342                                 (gpointer *)&thread_handle,
343                                 (gpointer *)&thread_private_handle);
344         if(ok==FALSE) {
345                 g_warning (G_GNUC_PRETTY_FUNCTION
346                            ": error looking up thread handle %p", handle);
347                 return(FALSE);
348         }
349         
350 #ifdef DEBUG
351         g_message(G_GNUC_PRETTY_FUNCTION
352                   ": Finding exit status for thread handle %p id %ld", handle,
353                   thread_private_handle->thread->id);
354 #endif
355
356         if(exitcode==NULL) {
357 #ifdef DEBUG
358                 g_message(G_GNUC_PRETTY_FUNCTION
359                           ": Nowhere to store exit code");
360 #endif
361                 return(FALSE);
362         }
363         
364         if(thread_handle->state!=THREAD_STATE_EXITED) {
365 #ifdef DEBUG
366                 g_message(G_GNUC_PRETTY_FUNCTION
367                           ": Thread still active (state %d, exited is %d)",
368                           thread_handle->state, THREAD_STATE_EXITED);
369 #endif
370                 *exitcode=STILL_ACTIVE;
371                 return(TRUE);
372         }
373         
374         *exitcode=thread_handle->exitstatus;
375         
376         return(TRUE);
377 }
378
379 /**
380  * GetCurrentThreadId:
381  *
382  * Looks up the thread ID of the current thread.  This ID can be
383  * passed to OpenThread() to create a new handle on this thread.
384  *
385  * Return value: the thread ID.
386  */
387 guint32 GetCurrentThreadId(void)
388 {
389         pthread_t tid=pthread_self();
390         
391 #ifdef PTHREAD_POINTER_ID
392         return(GPOINTER_TO_UINT(tid));
393 #else
394         return(tid);
395 #endif
396 }
397
398 static gpointer thread_attach(guint32 *tid)
399 {
400         struct _WapiHandle_thread *thread_handle;
401         struct _WapiHandlePrivate_thread *thread_private_handle;
402         gpointer handle;
403         gboolean ok;
404         int ret;
405
406         mono_once(&thread_hash_once, thread_hash_init);
407         mono_once (&thread_ops_once, thread_ops_init);
408
409         handle=_wapi_handle_new (WAPI_HANDLE_THREAD);
410         if(handle==_WAPI_HANDLE_INVALID) {
411                 g_warning (G_GNUC_PRETTY_FUNCTION
412                            ": error creating thread handle");
413                 return(NULL);
414         }
415
416         _wapi_handle_lock_handle (handle);
417
418         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
419                                 (gpointer *)&thread_handle,
420                                 (gpointer *)&thread_private_handle);
421         if(ok==FALSE) {
422                 g_warning (G_GNUC_PRETTY_FUNCTION
423                            ": error looking up thread handle %p", handle);
424                 _wapi_handle_unlock_handle (handle);
425                 return(NULL);
426         }
427
428         /* Hold a reference while the thread is active, because we use
429          * the handle to store thread exit information
430          */
431         _wapi_handle_ref (handle);
432
433         thread_handle->state=THREAD_STATE_START;
434
435         /* Lock around the thread create, so that the new thread cant
436          * race us to look up the thread handle in GetCurrentThread()
437          */
438         mono_mutex_lock(&thread_hash_mutex);
439
440         ret=_wapi_timed_thread_attach(&thread_private_handle->thread,
441                                       thread_exit, handle);
442         if(ret!=0) {
443 #ifdef DEBUG
444                 g_message(G_GNUC_PRETTY_FUNCTION ": Thread attach error: %s",
445                           strerror(ret));
446 #endif
447                 mono_mutex_unlock(&thread_hash_mutex);
448                 _wapi_handle_unlock_handle (handle);
449                 _wapi_handle_unref (handle);
450
451                 /* And again, because of the reference we took above */
452                 _wapi_handle_unref (handle);
453                 return(NULL);
454         }
455
456         g_hash_table_insert(thread_hash, &thread_private_handle->thread->id,
457                             handle);
458         mono_mutex_unlock(&thread_hash_mutex);
459
460 #ifdef DEBUG
461         g_message(G_GNUC_PRETTY_FUNCTION
462                   ": Attached thread handle %p thread %p ID %ld", handle,
463                   thread_private_handle->thread,
464                   thread_private_handle->thread->id);
465 #endif
466
467         if(tid!=NULL) {
468 #ifdef PTHREAD_POINTER_ID
469                 *tid=GPOINTER_TO_UINT(thread_private_handle->thread->id);
470 #else
471                 *tid=thread_private_handle->thread->id;
472 #endif
473         }
474
475         _wapi_handle_unlock_handle (handle);
476
477         return(handle);
478 }
479
480 /**
481  * GetCurrentThread:
482  *
483  * Looks up the handle associated with the current thread.  Under
484  * Windows this is a pseudohandle, and must be duplicated with
485  * DuplicateHandle() for some operations.
486  *
487  * Return value: The current thread handle, or %NULL on failure.
488  * (Unknown whether Windows has a possible failure here.  It may be
489  * necessary to implement the pseudohandle-constant behaviour).
490  */
491 gpointer GetCurrentThread(void)
492 {
493         gpointer ret=NULL;
494         guint32 tid;
495         
496         mono_once(&thread_hash_once, thread_hash_init);
497         mono_once (&thread_ops_once, thread_ops_init);
498         
499         tid=GetCurrentThreadId();
500         
501         mono_mutex_lock(&thread_hash_mutex);
502
503         ret=g_hash_table_lookup(thread_hash, &tid);
504         mono_mutex_unlock(&thread_hash_mutex);
505         
506         if (!ret) {
507                 ret = thread_attach (NULL);
508         }
509
510         return(ret);
511 }
512
513 /**
514  * ResumeThread:
515  * @handle: the thread handle to resume
516  *
517  * Decrements the suspend count of thread @handle. A thread can only
518  * run if its suspend count is zero.
519  *
520  * Return value: the previous suspend count, or 0xFFFFFFFF on error.
521  */
522 guint32 ResumeThread(gpointer handle)
523 {
524         struct _WapiHandle_thread *thread_handle;
525         struct _WapiHandlePrivate_thread *thread_private_handle;
526         gboolean ok;
527         
528         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
529                                 (gpointer *)&thread_handle,
530                                 (gpointer *)&thread_private_handle);
531         if(ok==FALSE) {
532                 g_warning (G_GNUC_PRETTY_FUNCTION
533                            ": error looking up thread handle %p", handle);
534                 return(0xFFFFFFFF);
535         }
536
537 #ifdef WITH_INCLUDED_LIBGC
538         if (thread_private_handle->thread->suspend_count <= 1)
539                 _wapi_timed_thread_resume (thread_private_handle->thread);
540         
541         return --thread_private_handle->thread->suspend_count;
542 #else
543         /* This is still a kludge that only copes with starting a
544          * thread that was suspended on create, so don't bother with
545          * the suspend count crap yet
546          */
547         _wapi_timed_thread_resume (thread_private_handle->thread);
548         return(0xFFFFFFFF);
549 #endif
550 }
551
552 /**
553  * SuspendThread:
554  * @handle: the thread handle to suspend
555  *
556  * Increments the suspend count of thread @handle. A thread can only
557  * run if its suspend count is zero.
558  *
559  * Return value: the previous suspend count, or 0xFFFFFFFF on error.
560  */
561 guint32 SuspendThread(gpointer handle)
562 {
563 #ifdef WITH_INCLUDED_LIBGC
564         struct _WapiHandle_thread *thread_handle;
565         struct _WapiHandlePrivate_thread *thread_private_handle;
566         gpointer current;
567         gboolean ok;
568
569         current = GetCurrentThread ();
570         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
571                                 (gpointer *)&thread_handle,
572                                 (gpointer *)&thread_private_handle);
573         if(ok==FALSE) {
574                 g_warning (G_GNUC_PRETTY_FUNCTION
575                            ": error looking up thread handle %p", handle);
576                 return(0xFFFFFFFF);
577         }
578
579         if (!thread_private_handle->thread->suspend_count) {
580                 if (handle == current)
581                         _wapi_timed_thread_suspend (thread_private_handle->thread);
582                 else {
583                         pthread_kill (thread_private_handle->thread->id, SIGPWR);
584                         sem_wait (&thread_private_handle->thread->suspended_sem);
585                 }
586         }
587
588         return thread_private_handle->thread->suspend_count++;
589 #else
590         return(0xFFFFFFFF);
591 #endif
592 }
593
594 /*
595  * We assume here that TLS_MINIMUM_AVAILABLE is less than
596  * PTHREAD_KEYS_MAX, allowing enough overhead for a few TLS keys for
597  * library usage.
598  *
599  * Currently TLS_MINIMUM_AVAILABLE is 64 and _POSIX_THREAD_KEYS_MAX
600  * (the minimum value for PTHREAD_KEYS_MAX) is 128, so we should be
601  * fine.
602  */
603
604 static pthread_key_t TLS_keys[TLS_MINIMUM_AVAILABLE];
605 static gboolean TLS_used[TLS_MINIMUM_AVAILABLE]={FALSE};
606 #ifdef TLS_PTHREAD_MUTEX
607 static mono_mutex_t TLS_mutex=MONO_MUTEX_INITIALIZER;
608 #else
609 static guint32 TLS_spinlock=0;
610 #endif
611
612 /**
613  * TlsAlloc:
614  *
615  * Allocates a Thread Local Storage (TLS) index.  Any thread in the
616  * same process can use this index to store and retrieve values that
617  * are local to that thread.
618  *
619  * Return value: The index value, or %TLS_OUT_OF_INDEXES if no index
620  * is available.
621  */
622 guint32 TlsAlloc(void)
623 {
624         guint32 i;
625         
626 #ifdef TLS_PTHREAD_MUTEX
627         mono_mutex_lock(&TLS_mutex);
628 #else
629         MONO_SPIN_LOCK (TLS_spinlock);
630 #endif
631         
632         for(i=0; i<TLS_MINIMUM_AVAILABLE; i++) {
633                 if(TLS_used[i]==FALSE) {
634                         TLS_used[i]=TRUE;
635                         pthread_key_create(&TLS_keys[i], NULL);
636
637 #ifdef TLS_PTHREAD_MUTEX
638                         mono_mutex_unlock(&TLS_mutex);
639 #else
640                         MONO_SPIN_UNLOCK (TLS_spinlock);
641 #endif
642         
643 #ifdef TLS_DEBUG
644                         g_message (G_GNUC_PRETTY_FUNCTION ": returning key %d",
645                                    i);
646 #endif
647                         
648                         return(i);
649                 }
650         }
651
652 #ifdef TLS_PTHREAD_MUTEX
653         mono_mutex_unlock(&TLS_mutex);
654 #else
655         MONO_SPIN_UNLOCK (TLS_spinlock);
656 #endif
657         
658 #ifdef TLS_DEBUG
659         g_message (G_GNUC_PRETTY_FUNCTION ": out of indices");
660 #endif
661                         
662         
663         return(TLS_OUT_OF_INDEXES);
664 }
665
666 #define MAKE_GC_ID(idx) (GUINT_TO_POINTER((idx)|(GetCurrentThreadId()<<8)))
667
668 /**
669  * TlsFree:
670  * @idx: The TLS index to free
671  *
672  * Releases a TLS index, making it available for reuse.  This call
673  * will delete any TLS data stored under index @idx in all threads.
674  *
675  * Return value: %TRUE on success, %FALSE otherwise.
676  */
677 gboolean TlsFree(guint32 idx)
678 {
679 #ifdef TLS_DEBUG
680         g_message (G_GNUC_PRETTY_FUNCTION ": freeing key %d", idx);
681 #endif
682
683 #ifdef TLS_PTHREAD_MUTEX
684         mono_mutex_lock(&TLS_mutex);
685 #else
686         MONO_SPIN_LOCK (TLS_spinlock);
687 #endif
688         
689         if(TLS_used[idx]==FALSE) {
690 #ifdef TLS_PTHREAD_MUTEX
691                 mono_mutex_unlock(&TLS_mutex);
692 #else
693                 MONO_SPIN_UNLOCK (TLS_spinlock);
694 #endif
695                 return(FALSE);
696         }
697         
698         TLS_used[idx]=FALSE;
699         pthread_key_delete(TLS_keys[idx]);
700         
701 #if HAVE_BOEHM_GC
702         mono_g_hash_table_remove (tls_gc_hash, MAKE_GC_ID (idx));
703 #endif
704
705 #ifdef TLS_PTHREAD_MUTEX
706         mono_mutex_unlock(&TLS_mutex);
707 #else
708         MONO_SPIN_UNLOCK (TLS_spinlock);
709 #endif
710         
711         return(TRUE);
712 }
713
714 /**
715  * TlsGetValue:
716  * @idx: The TLS index to retrieve
717  *
718  * Retrieves the TLS data stored under index @idx.
719  *
720  * Return value: The value stored in the TLS index @idx in the current
721  * thread, or %NULL on error.  As %NULL can be a valid return value,
722  * in this case GetLastError() returns %ERROR_SUCCESS.
723  */
724 gpointer TlsGetValue(guint32 idx)
725 {
726         gpointer ret;
727         
728 #ifdef TLS_DEBUG
729         g_message (G_GNUC_PRETTY_FUNCTION ": looking up key %d", idx);
730 #endif
731         
732         ret=pthread_getspecific(TLS_keys[idx]);
733
734 #ifdef TLS_DEBUG
735         g_message (G_GNUC_PRETTY_FUNCTION ": returning %p", ret);
736 #endif
737         
738         return(ret);
739 }
740
741 /**
742  * TlsSetValue:
743  * @idx: The TLS index to store
744  * @value: The value to store under index @idx
745  *
746  * Stores @value at TLS index @idx.
747  *
748  * Return value: %TRUE on success, %FALSE otherwise.
749  */
750 gboolean TlsSetValue(guint32 idx, gpointer value)
751 {
752         int ret;
753
754 #ifdef TLS_DEBUG
755         g_message (G_GNUC_PRETTY_FUNCTION ": setting key %d to %p", idx,
756                    value);
757 #endif
758         
759 #ifdef TLS_PTHREAD_MUTEX
760         mono_mutex_lock(&TLS_mutex);
761 #else
762         MONO_SPIN_LOCK (TLS_spinlock);
763 #endif
764         
765         if(TLS_used[idx]==FALSE) {
766 #ifdef TLS_DEBUG
767                 g_message (G_GNUC_PRETTY_FUNCTION ": key %d unused", idx);
768 #endif
769
770 #ifdef TLS_PTHREAD_MUTEX
771                 mono_mutex_unlock(&TLS_mutex);
772 #else
773                 MONO_SPIN_UNLOCK (TLS_spinlock);
774 #endif
775                 return(FALSE);
776         }
777         
778         ret=pthread_setspecific(TLS_keys[idx], value);
779         if(ret!=0) {
780 #ifdef TLS_DEBUG
781                 g_message (G_GNUC_PRETTY_FUNCTION
782                            ": pthread_setspecific error: %s", strerror (ret));
783 #endif
784
785 #ifdef TLS_PTHREAD_MUTEX
786                 mono_mutex_unlock(&TLS_mutex);
787 #else
788                 MONO_SPIN_UNLOCK (TLS_spinlock);
789 #endif
790                 return(FALSE);
791         }
792         
793 #if HAVE_BOEHM_GC
794         if (!tls_gc_hash)
795                 tls_gc_hash = mono_g_hash_table_new(g_direct_hash, g_direct_equal);
796         mono_g_hash_table_insert (tls_gc_hash, MAKE_GC_ID (idx), value);
797 #endif
798
799 #ifdef TLS_PTHREAD_MUTEX
800         mono_mutex_unlock(&TLS_mutex);
801 #else
802         MONO_SPIN_UNLOCK (TLS_spinlock);
803 #endif
804         
805         return(TRUE);
806 }
807
808 /**
809  * Sleep:
810  * @ms: The time in milliseconds to suspend for
811  *
812  * Suspends execution of the current thread for @ms milliseconds.  A
813  * value of zero causes the thread to relinquish its time slice.  A
814  * value of %INFINITE causes an infinite delay.
815  */
816 void Sleep(guint32 ms)
817 {
818         struct timespec req, rem;
819         div_t divvy;
820         int ret;
821         
822 #ifdef DEBUG
823         g_message(G_GNUC_PRETTY_FUNCTION ": Sleeping for %d ms", ms);
824 #endif
825
826         if(ms==0) {
827                 sched_yield();
828                 return;
829         }
830         
831         /* FIXME: check for INFINITE and sleep forever */
832         divvy=div((int)ms, 1000);
833         
834         req.tv_sec=divvy.quot;
835         req.tv_nsec=divvy.rem*1000000;
836         
837 again:
838         ret=nanosleep(&req, &rem);
839         if(ret==-1) {
840                 /* Sleep interrupted with rem time remaining */
841 #ifdef DEBUG
842                 guint32 rems=rem.tv_sec*1000 + rem.tv_nsec/1000000;
843                 
844                 g_message(G_GNUC_PRETTY_FUNCTION ": Still got %d ms to go",
845                           rems);
846 #endif
847                 req=rem;
848                 goto again;
849         }
850 }
851
852 /* FIXME: implement alertable */
853 void SleepEx(guint32 ms, gboolean alertable)
854 {
855         if(alertable==TRUE) {
856                 g_warning(G_GNUC_PRETTY_FUNCTION ": alertable not implemented");
857         }
858         
859         Sleep(ms);
860 }
861
862 #ifdef WITH_INCLUDED_LIBGC
863
864 static void GC_suspend_handler (int sig)
865 {
866         struct _WapiHandle_thread *thread_handle;
867         struct _WapiHandlePrivate_thread *thread_private_handle;
868         gpointer handle;
869         gboolean ok;
870
871         handle = GetCurrentThread ();
872         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
873                                 (gpointer *)&thread_handle,
874                                 (gpointer *)&thread_private_handle);
875         if(ok==FALSE) {
876                 g_warning (G_GNUC_PRETTY_FUNCTION
877                            ": error looking up thread handle %p", handle);
878                 return;
879         }
880
881         thread_private_handle->thread->stack_ptr = &ok;
882         sem_post (&thread_private_handle->thread->suspended_sem);
883
884         _wapi_timed_thread_suspend (thread_private_handle->thread);
885
886         thread_private_handle->thread->stack_ptr = NULL;
887 }
888
889 static void gc_init (void)
890 {
891         struct sigaction act;
892
893         act.sa_handler = GC_suspend_handler;
894         g_assert (sigaction (SIGPWR, &act, NULL) == 0);
895 }
896
897 void mono_wapi_push_thread_stack (gpointer handle, gpointer stack_ptr)
898 {
899         struct _WapiHandle_thread *thread_handle;
900         struct _WapiHandlePrivate_thread *thread_private_handle;
901         gboolean ok;
902
903         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
904                                 (gpointer *)&thread_handle,
905                                 (gpointer *)&thread_private_handle);
906         if(ok==FALSE) {
907                 g_warning (G_GNUC_PRETTY_FUNCTION
908                            ": error looking up thread handle %p", handle);
909                 return;
910         }
911
912         GC_push_all_stack (thread_private_handle->thread->stack_ptr, stack_ptr);
913 }
914
915 #endif /* WITH_INCLUDED_LIBGC */