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