grammar updates
[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,
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         /* defaults of 2Mb for 32bits and 4Mb for 64bits */
242         if (stacksize == 0)
243                 stacksize = (SIZEOF_VOID_P / 2) * 1024 *1024;
244
245 #ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE
246         pthread_attr_setstacksize(&attr, stacksize);
247 #endif
248
249         ret=_wapi_timed_thread_create(&thread_private_handle->thread, &attr,
250                                       create, start, thread_exit, param,
251                                       handle);
252         if(ret!=0) {
253 #ifdef DEBUG
254                 g_message(G_GNUC_PRETTY_FUNCTION ": Thread create error: %s",
255                           strerror(ret));
256 #endif
257                 mono_mutex_unlock(&thread_hash_mutex);
258                 _wapi_handle_unlock_handle (handle);
259                 _wapi_handle_unref (handle);
260                 
261                 /* And again, because of the reference we took above */
262                 _wapi_handle_unref (handle);
263                 return(NULL);
264         }
265
266         g_hash_table_insert(thread_hash, &thread_private_handle->thread->id,
267                             handle);
268         mono_mutex_unlock(&thread_hash_mutex);
269         
270 #ifdef DEBUG
271         g_message(G_GNUC_PRETTY_FUNCTION
272                   ": Started thread handle %p thread %p ID %ld", handle,
273                   thread_private_handle->thread,
274                   thread_private_handle->thread->id);
275 #endif
276         
277         if(tid!=NULL) {
278 #ifdef PTHREAD_POINTER_ID
279                 *tid=GPOINTER_TO_UINT(thread_private_handle->thread->id);
280 #else
281                 *tid=thread_private_handle->thread->id;
282 #endif
283         }
284
285         _wapi_handle_unlock_handle (handle);
286         
287         return(handle);
288 }
289
290 gpointer OpenThread (guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, guint32 tid)
291 {
292         gpointer ret=NULL;
293         
294         mono_once(&thread_hash_once, thread_hash_init);
295         mono_once (&thread_ops_once, thread_ops_init);
296         
297 #ifdef DEBUG
298         g_message (G_GNUC_PRETTY_FUNCTION ": looking up thread %d", tid);
299 #endif
300
301         mono_mutex_lock(&thread_hash_mutex);
302         
303         ret=g_hash_table_lookup(thread_hash, &tid);
304         mono_mutex_unlock(&thread_hash_mutex);
305         
306         if(ret!=NULL) {
307                 _wapi_handle_ref (ret);
308         }
309         
310 #ifdef DEBUG
311         g_message (G_GNUC_PRETTY_FUNCTION ": returning thread handle %p", ret);
312 #endif
313         
314         return(ret);
315 }
316
317 /**
318  * ExitThread:
319  * @exitcode: Sets the thread's exit code, which can be read from
320  * another thread with GetExitCodeThread().
321  *
322  * Terminates the calling thread.  A thread can also exit by returning
323  * from its start function. When the last thread in a process
324  * terminates, the process itself terminates.
325  */
326 void ExitThread(guint32 exitcode)
327 {
328         _wapi_timed_thread_exit(exitcode);
329 }
330
331 /**
332  * GetExitCodeThread:
333  * @handle: The thread handle to query
334  * @exitcode: The thread @handle exit code is stored here
335  *
336  * Finds the exit code of @handle, and stores it in @exitcode.  If the
337  * thread @handle is still running, the value stored is %STILL_ACTIVE.
338  *
339  * Return value: %TRUE, or %FALSE on error.
340  */
341 gboolean GetExitCodeThread(gpointer handle, guint32 *exitcode)
342 {
343         struct _WapiHandle_thread *thread_handle;
344         struct _WapiHandlePrivate_thread *thread_private_handle;
345         gboolean ok;
346         
347         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
348                                 (gpointer *)&thread_handle,
349                                 (gpointer *)&thread_private_handle);
350         if(ok==FALSE) {
351                 g_warning (G_GNUC_PRETTY_FUNCTION
352                            ": error looking up thread handle %p", handle);
353                 return(FALSE);
354         }
355         
356 #ifdef DEBUG
357         g_message(G_GNUC_PRETTY_FUNCTION
358                   ": Finding exit status for thread handle %p id %ld", handle,
359                   thread_private_handle->thread->id);
360 #endif
361
362         if(exitcode==NULL) {
363 #ifdef DEBUG
364                 g_message(G_GNUC_PRETTY_FUNCTION
365                           ": Nowhere to store exit code");
366 #endif
367                 return(FALSE);
368         }
369         
370         if(thread_handle->state!=THREAD_STATE_EXITED) {
371 #ifdef DEBUG
372                 g_message(G_GNUC_PRETTY_FUNCTION
373                           ": Thread still active (state %d, exited is %d)",
374                           thread_handle->state, THREAD_STATE_EXITED);
375 #endif
376                 *exitcode=STILL_ACTIVE;
377                 return(TRUE);
378         }
379         
380         *exitcode=thread_handle->exitstatus;
381         
382         return(TRUE);
383 }
384
385 /**
386  * GetCurrentThreadId:
387  *
388  * Looks up the thread ID of the current thread.  This ID can be
389  * passed to OpenThread() to create a new handle on this thread.
390  *
391  * Return value: the thread ID.
392  */
393 guint32 GetCurrentThreadId(void)
394 {
395         pthread_t tid=pthread_self();
396         
397 #ifdef PTHREAD_POINTER_ID
398         return(GPOINTER_TO_UINT(tid));
399 #else
400         return(tid);
401 #endif
402 }
403
404 static gpointer thread_attach(guint32 *tid)
405 {
406         struct _WapiHandle_thread *thread_handle;
407         struct _WapiHandlePrivate_thread *thread_private_handle;
408         gpointer handle;
409         gboolean ok;
410         int ret;
411
412         mono_once(&thread_hash_once, thread_hash_init);
413         mono_once (&thread_ops_once, thread_ops_init);
414
415         handle=_wapi_handle_new (WAPI_HANDLE_THREAD);
416         if(handle==_WAPI_HANDLE_INVALID) {
417                 g_warning (G_GNUC_PRETTY_FUNCTION
418                            ": error creating thread handle");
419                 return(NULL);
420         }
421
422         _wapi_handle_lock_handle (handle);
423
424         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
425                                 (gpointer *)&thread_handle,
426                                 (gpointer *)&thread_private_handle);
427         if(ok==FALSE) {
428                 g_warning (G_GNUC_PRETTY_FUNCTION
429                            ": error looking up thread handle %p", handle);
430                 _wapi_handle_unlock_handle (handle);
431                 return(NULL);
432         }
433
434         /* Hold a reference while the thread is active, because we use
435          * the handle to store thread exit information
436          */
437         _wapi_handle_ref (handle);
438
439         thread_handle->state=THREAD_STATE_START;
440
441         /* Lock around the thread create, so that the new thread cant
442          * race us to look up the thread handle in GetCurrentThread()
443          */
444         mono_mutex_lock(&thread_hash_mutex);
445
446         ret=_wapi_timed_thread_attach(&thread_private_handle->thread,
447                                       thread_exit, handle);
448         if(ret!=0) {
449 #ifdef DEBUG
450                 g_message(G_GNUC_PRETTY_FUNCTION ": Thread attach error: %s",
451                           strerror(ret));
452 #endif
453                 mono_mutex_unlock(&thread_hash_mutex);
454                 _wapi_handle_unlock_handle (handle);
455                 _wapi_handle_unref (handle);
456
457                 /* And again, because of the reference we took above */
458                 _wapi_handle_unref (handle);
459                 return(NULL);
460         }
461
462         g_hash_table_insert(thread_hash, &thread_private_handle->thread->id,
463                             handle);
464         mono_mutex_unlock(&thread_hash_mutex);
465
466 #ifdef DEBUG
467         g_message(G_GNUC_PRETTY_FUNCTION
468                   ": Attached thread handle %p thread %p ID %ld", handle,
469                   thread_private_handle->thread,
470                   thread_private_handle->thread->id);
471 #endif
472
473         if(tid!=NULL) {
474 #ifdef PTHREAD_POINTER_ID
475                 *tid=GPOINTER_TO_UINT(thread_private_handle->thread->id);
476 #else
477                 *tid=thread_private_handle->thread->id;
478 #endif
479         }
480
481         _wapi_handle_unlock_handle (handle);
482
483         return(handle);
484 }
485
486 /**
487  * GetCurrentThread:
488  *
489  * Looks up the handle associated with the current thread.  Under
490  * Windows this is a pseudohandle, and must be duplicated with
491  * DuplicateHandle() for some operations.
492  *
493  * Return value: The current thread handle, or %NULL on failure.
494  * (Unknown whether Windows has a possible failure here.  It may be
495  * necessary to implement the pseudohandle-constant behaviour).
496  */
497 gpointer GetCurrentThread(void)
498 {
499         gpointer ret=NULL;
500         guint32 tid;
501         
502         mono_once(&thread_hash_once, thread_hash_init);
503         mono_once (&thread_ops_once, thread_ops_init);
504         
505         tid=GetCurrentThreadId();
506         
507         mono_mutex_lock(&thread_hash_mutex);
508
509         ret=g_hash_table_lookup(thread_hash, &tid);
510         mono_mutex_unlock(&thread_hash_mutex);
511         
512         if (!ret) {
513                 ret = thread_attach (NULL);
514         }
515
516         return(ret);
517 }
518
519 /**
520  * ResumeThread:
521  * @handle: the thread handle to resume
522  *
523  * Decrements the suspend count of thread @handle. A thread can only
524  * run if its suspend count is zero.
525  *
526  * Return value: the previous suspend count, or 0xFFFFFFFF on error.
527  */
528 guint32 ResumeThread(gpointer handle)
529 {
530         struct _WapiHandle_thread *thread_handle;
531         struct _WapiHandlePrivate_thread *thread_private_handle;
532         gboolean ok;
533         
534         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
535                                 (gpointer *)&thread_handle,
536                                 (gpointer *)&thread_private_handle);
537         if(ok==FALSE) {
538                 g_warning (G_GNUC_PRETTY_FUNCTION
539                            ": error looking up thread handle %p", handle);
540                 return(0xFFFFFFFF);
541         }
542
543 #ifdef WITH_INCLUDED_LIBGC
544         if (thread_private_handle->thread->suspend_count <= 1)
545                 _wapi_timed_thread_resume (thread_private_handle->thread);
546         
547         return --thread_private_handle->thread->suspend_count;
548 #else
549         /* This is still a kludge that only copes with starting a
550          * thread that was suspended on create, so don't bother with
551          * the suspend count crap yet
552          */
553         _wapi_timed_thread_resume (thread_private_handle->thread);
554         return(0xFFFFFFFF);
555 #endif
556 }
557
558 /**
559  * SuspendThread:
560  * @handle: the thread handle to suspend
561  *
562  * Increments the suspend count of thread @handle. A thread can only
563  * run if its suspend count is zero.
564  *
565  * Return value: the previous suspend count, or 0xFFFFFFFF on error.
566  */
567 guint32 SuspendThread(gpointer handle)
568 {
569 #ifdef WITH_INCLUDED_LIBGC
570         struct _WapiHandle_thread *thread_handle;
571         struct _WapiHandlePrivate_thread *thread_private_handle;
572         gpointer current;
573         gboolean ok;
574
575         current = GetCurrentThread ();
576         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
577                                 (gpointer *)&thread_handle,
578                                 (gpointer *)&thread_private_handle);
579         if(ok==FALSE) {
580                 g_warning (G_GNUC_PRETTY_FUNCTION
581                            ": error looking up thread handle %p", handle);
582                 return(0xFFFFFFFF);
583         }
584
585         if (!thread_private_handle->thread->suspend_count) {
586                 if (handle == current)
587                         _wapi_timed_thread_suspend (thread_private_handle->thread);
588                 else {
589                         pthread_kill (thread_private_handle->thread->id, SIGPWR);
590                         sem_wait (&thread_private_handle->thread->suspended_sem);
591                 }
592         }
593
594         return thread_private_handle->thread->suspend_count++;
595 #else
596         return(0xFFFFFFFF);
597 #endif
598 }
599
600 /*
601  * We assume here that TLS_MINIMUM_AVAILABLE is less than
602  * PTHREAD_KEYS_MAX, allowing enough overhead for a few TLS keys for
603  * library usage.
604  *
605  * Currently TLS_MINIMUM_AVAILABLE is 64 and _POSIX_THREAD_KEYS_MAX
606  * (the minimum value for PTHREAD_KEYS_MAX) is 128, so we should be
607  * fine.
608  */
609
610 static pthread_key_t TLS_keys[TLS_MINIMUM_AVAILABLE];
611 static gboolean TLS_used[TLS_MINIMUM_AVAILABLE]={FALSE};
612 #ifdef TLS_PTHREAD_MUTEX
613 static mono_mutex_t TLS_mutex=MONO_MUTEX_INITIALIZER;
614 #else
615 static guint32 TLS_spinlock=0;
616 #endif
617
618 /**
619  * TlsAlloc:
620  *
621  * Allocates a Thread Local Storage (TLS) index.  Any thread in the
622  * same process can use this index to store and retrieve values that
623  * are local to that thread.
624  *
625  * Return value: The index value, or %TLS_OUT_OF_INDEXES if no index
626  * is available.
627  */
628 guint32 TlsAlloc(void)
629 {
630         guint32 i;
631         
632 #ifdef TLS_PTHREAD_MUTEX
633         mono_mutex_lock(&TLS_mutex);
634 #else
635         MONO_SPIN_LOCK (TLS_spinlock);
636 #endif
637         
638         for(i=0; i<TLS_MINIMUM_AVAILABLE; i++) {
639                 if(TLS_used[i]==FALSE) {
640                         TLS_used[i]=TRUE;
641                         pthread_key_create(&TLS_keys[i], NULL);
642
643 #ifdef TLS_PTHREAD_MUTEX
644                         mono_mutex_unlock(&TLS_mutex);
645 #else
646                         MONO_SPIN_UNLOCK (TLS_spinlock);
647 #endif
648         
649 #ifdef TLS_DEBUG
650                         g_message (G_GNUC_PRETTY_FUNCTION ": returning key %d",
651                                    i);
652 #endif
653                         
654                         return(i);
655                 }
656         }
657
658 #ifdef TLS_PTHREAD_MUTEX
659         mono_mutex_unlock(&TLS_mutex);
660 #else
661         MONO_SPIN_UNLOCK (TLS_spinlock);
662 #endif
663         
664 #ifdef TLS_DEBUG
665         g_message (G_GNUC_PRETTY_FUNCTION ": out of indices");
666 #endif
667                         
668         
669         return(TLS_OUT_OF_INDEXES);
670 }
671
672 #define MAKE_GC_ID(idx) (GUINT_TO_POINTER((idx)|(GetCurrentThreadId()<<8)))
673
674 /**
675  * TlsFree:
676  * @idx: The TLS index to free
677  *
678  * Releases a TLS index, making it available for reuse.  This call
679  * will delete any TLS data stored under index @idx in all threads.
680  *
681  * Return value: %TRUE on success, %FALSE otherwise.
682  */
683 gboolean TlsFree(guint32 idx)
684 {
685 #ifdef TLS_DEBUG
686         g_message (G_GNUC_PRETTY_FUNCTION ": freeing key %d", idx);
687 #endif
688
689 #ifdef TLS_PTHREAD_MUTEX
690         mono_mutex_lock(&TLS_mutex);
691 #else
692         MONO_SPIN_LOCK (TLS_spinlock);
693 #endif
694         
695         if(TLS_used[idx]==FALSE) {
696 #ifdef TLS_PTHREAD_MUTEX
697                 mono_mutex_unlock(&TLS_mutex);
698 #else
699                 MONO_SPIN_UNLOCK (TLS_spinlock);
700 #endif
701                 return(FALSE);
702         }
703         
704         TLS_used[idx]=FALSE;
705         pthread_key_delete(TLS_keys[idx]);
706         
707 #if HAVE_BOEHM_GC
708         mono_g_hash_table_remove (tls_gc_hash, MAKE_GC_ID (idx));
709 #endif
710
711 #ifdef TLS_PTHREAD_MUTEX
712         mono_mutex_unlock(&TLS_mutex);
713 #else
714         MONO_SPIN_UNLOCK (TLS_spinlock);
715 #endif
716         
717         return(TRUE);
718 }
719
720 /**
721  * TlsGetValue:
722  * @idx: The TLS index to retrieve
723  *
724  * Retrieves the TLS data stored under index @idx.
725  *
726  * Return value: The value stored in the TLS index @idx in the current
727  * thread, or %NULL on error.  As %NULL can be a valid return value,
728  * in this case GetLastError() returns %ERROR_SUCCESS.
729  */
730 gpointer TlsGetValue(guint32 idx)
731 {
732         gpointer ret;
733         
734 #ifdef TLS_DEBUG
735         g_message (G_GNUC_PRETTY_FUNCTION ": looking up key %d", idx);
736 #endif
737         
738         ret=pthread_getspecific(TLS_keys[idx]);
739
740 #ifdef TLS_DEBUG
741         g_message (G_GNUC_PRETTY_FUNCTION ": returning %p", ret);
742 #endif
743         
744         return(ret);
745 }
746
747 /**
748  * TlsSetValue:
749  * @idx: The TLS index to store
750  * @value: The value to store under index @idx
751  *
752  * Stores @value at TLS index @idx.
753  *
754  * Return value: %TRUE on success, %FALSE otherwise.
755  */
756 gboolean TlsSetValue(guint32 idx, gpointer value)
757 {
758         int ret;
759
760 #ifdef TLS_DEBUG
761         g_message (G_GNUC_PRETTY_FUNCTION ": setting key %d to %p", idx,
762                    value);
763 #endif
764         
765 #ifdef TLS_PTHREAD_MUTEX
766         mono_mutex_lock(&TLS_mutex);
767 #else
768         MONO_SPIN_LOCK (TLS_spinlock);
769 #endif
770         
771         if(TLS_used[idx]==FALSE) {
772 #ifdef TLS_DEBUG
773                 g_message (G_GNUC_PRETTY_FUNCTION ": key %d unused", idx);
774 #endif
775
776 #ifdef TLS_PTHREAD_MUTEX
777                 mono_mutex_unlock(&TLS_mutex);
778 #else
779                 MONO_SPIN_UNLOCK (TLS_spinlock);
780 #endif
781                 return(FALSE);
782         }
783         
784         ret=pthread_setspecific(TLS_keys[idx], value);
785         if(ret!=0) {
786 #ifdef TLS_DEBUG
787                 g_message (G_GNUC_PRETTY_FUNCTION
788                            ": pthread_setspecific error: %s", strerror (ret));
789 #endif
790
791 #ifdef TLS_PTHREAD_MUTEX
792                 mono_mutex_unlock(&TLS_mutex);
793 #else
794                 MONO_SPIN_UNLOCK (TLS_spinlock);
795 #endif
796                 return(FALSE);
797         }
798         
799 #if HAVE_BOEHM_GC
800         if (!tls_gc_hash)
801                 tls_gc_hash = mono_g_hash_table_new(g_direct_hash, g_direct_equal);
802         mono_g_hash_table_insert (tls_gc_hash, MAKE_GC_ID (idx), value);
803 #endif
804
805 #ifdef TLS_PTHREAD_MUTEX
806         mono_mutex_unlock(&TLS_mutex);
807 #else
808         MONO_SPIN_UNLOCK (TLS_spinlock);
809 #endif
810         
811         return(TRUE);
812 }
813
814 /**
815  * Sleep:
816  * @ms: The time in milliseconds to suspend for
817  *
818  * Suspends execution of the current thread for @ms milliseconds.  A
819  * value of zero causes the thread to relinquish its time slice.  A
820  * value of %INFINITE causes an infinite delay.
821  */
822 void Sleep(guint32 ms)
823 {
824         struct timespec req, rem;
825         div_t divvy;
826         int ret;
827         
828 #ifdef DEBUG
829         g_message(G_GNUC_PRETTY_FUNCTION ": Sleeping for %d ms", ms);
830 #endif
831
832         if(ms==0) {
833                 sched_yield();
834                 return;
835         }
836         
837         /* FIXME: check for INFINITE and sleep forever */
838         divvy=div((int)ms, 1000);
839         
840         req.tv_sec=divvy.quot;
841         req.tv_nsec=divvy.rem*1000000;
842         
843 again:
844         ret=nanosleep(&req, &rem);
845         if(ret==-1) {
846                 /* Sleep interrupted with rem time remaining */
847 #ifdef DEBUG
848                 guint32 rems=rem.tv_sec*1000 + rem.tv_nsec/1000000;
849                 
850                 g_message(G_GNUC_PRETTY_FUNCTION ": Still got %d ms to go",
851                           rems);
852 #endif
853                 req=rem;
854                 goto again;
855         }
856 }
857
858 /* FIXME: implement alertable */
859 void SleepEx(guint32 ms, gboolean alertable)
860 {
861         if(alertable==TRUE) {
862                 g_warning(G_GNUC_PRETTY_FUNCTION ": alertable not implemented");
863         }
864         
865         Sleep(ms);
866 }
867
868 #ifdef WITH_INCLUDED_LIBGC
869
870 static void GC_suspend_handler (int sig)
871 {
872         struct _WapiHandle_thread *thread_handle;
873         struct _WapiHandlePrivate_thread *thread_private_handle;
874         gpointer handle;
875         gboolean ok;
876
877         handle = GetCurrentThread ();
878         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
879                                 (gpointer *)&thread_handle,
880                                 (gpointer *)&thread_private_handle);
881         if(ok==FALSE) {
882                 g_warning (G_GNUC_PRETTY_FUNCTION
883                            ": error looking up thread handle %p", handle);
884                 return;
885         }
886
887         thread_private_handle->thread->stack_ptr = &ok;
888         sem_post (&thread_private_handle->thread->suspended_sem);
889
890         _wapi_timed_thread_suspend (thread_private_handle->thread);
891
892         thread_private_handle->thread->stack_ptr = NULL;
893 }
894
895 static void gc_init (void)
896 {
897         struct sigaction act;
898
899         act.sa_handler = GC_suspend_handler;
900         g_assert (sigaction (SIGPWR, &act, NULL) == 0);
901 }
902
903 void mono_wapi_push_thread_stack (gpointer handle, gpointer stack_ptr)
904 {
905         struct _WapiHandle_thread *thread_handle;
906         struct _WapiHandlePrivate_thread *thread_private_handle;
907         gboolean ok;
908
909         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
910                                 (gpointer *)&thread_handle,
911                                 (gpointer *)&thread_private_handle);
912         if(ok==FALSE) {
913                 g_warning (G_GNUC_PRETTY_FUNCTION
914                            ": error looking up thread handle %p", handle);
915                 return;
916         }
917
918         GC_push_all_stack (thread_private_handle->thread->stack_ptr, stack_ptr);
919 }
920
921 #endif /* WITH_INCLUDED_LIBGC */