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