2004-05-29 Zoltan Varga <vargaz@freemail.hu>
[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 <stdio.h>
16 #include <glib.h>
17 #include <string.h>
18 #include <pthread.h>
19 #include <signal.h>
20 #include <sched.h>
21 #include <sys/time.h>
22 #include <errno.h>
23
24 #include <mono/io-layer/wapi.h>
25 #include <mono/io-layer/wapi-private.h>
26 #include <mono/io-layer/timed-thread.h>
27 #include <mono/io-layer/handles-private.h>
28 #include <mono/io-layer/misc-private.h>
29 #include <mono/io-layer/mono-mutex.h>
30 #include <mono/io-layer/thread-private.h>
31 #include <mono/io-layer/mono-spinlock.h>
32
33 #undef DEBUG
34 #undef TLS_DEBUG
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         int thr_ret;
128         
129         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
130                                 (gpointer *)&thread_handle,
131                                 (gpointer *)&thread_private_handle);
132         if(ok==FALSE) {
133                 g_warning (G_GNUC_PRETTY_FUNCTION
134                            ": error looking up thread handle %p", handle);
135                 return;
136         }
137
138         pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
139                               handle);
140         thr_ret = _wapi_handle_lock_handle (handle);
141         g_assert (thr_ret == 0);
142
143 #ifdef DEBUG
144         g_message (G_GNUC_PRETTY_FUNCTION
145                    ": Recording thread handle %p exit status", handle);
146 #endif
147         
148         thread_handle->exitstatus=exitstatus;
149         thread_handle->state=THREAD_STATE_EXITED;
150         _wapi_handle_set_signal_state (handle, TRUE, TRUE);
151
152         thr_ret = _wapi_handle_unlock_handle (handle);
153         g_assert (thr_ret == 0);
154         pthread_cleanup_pop (0);
155         
156 #ifdef DEBUG
157         g_message(G_GNUC_PRETTY_FUNCTION
158                   ": Recording thread handle %p id %ld status as %d",
159                   handle, thread_private_handle->thread->id, exitstatus);
160 #endif
161
162         /* Remove this thread from the hash */
163         pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
164                               (void *)&thread_hash_mutex);
165         thr_ret = mono_mutex_lock(&thread_hash_mutex);
166         g_assert (thr_ret == 0);
167         
168         g_hash_table_remove(thread_hash, &thread_private_handle->thread->id);
169
170         thr_ret = mono_mutex_unlock(&thread_hash_mutex);
171         g_assert (thr_ret == 0);
172         pthread_cleanup_pop (0);
173
174         /* The thread is no longer active, so unref it */
175         _wapi_handle_unref (handle);
176 }
177
178 static void thread_hash_init(void)
179 {
180         thread_hash=g_hash_table_new(g_int_hash, g_int_equal);
181 }
182
183 /**
184  * CreateThread:
185  * @security: Ignored for now.
186  * @stacksize: the size in bytes of the new thread's stack. Use 0 to
187  * default to the normal stack size. (Ignored for now).
188  * @start: The function that the new thread should start with
189  * @param: The parameter to give to @start.
190  * @create: If 0, the new thread is ready to run immediately.  If
191  * %CREATE_SUSPENDED, the new thread will be in the suspended state,
192  * requiring a ResumeThread() call to continue running.
193  * @tid: If non-NULL, the ID of the new thread is stored here.
194  *
195  * Creates a new threading handle.
196  *
197  * Return value: a new handle, or NULL
198  */
199 gpointer CreateThread(WapiSecurityAttributes *security G_GNUC_UNUSED, guint32 stacksize,
200                       WapiThreadStart start, gpointer param, guint32 create,
201                       guint32 *tid) 
202 {
203         struct _WapiHandle_thread *thread_handle;
204         struct _WapiHandlePrivate_thread *thread_private_handle;
205         pthread_attr_t attr;
206         gpointer handle;
207         gboolean ok;
208         int ret;
209         int thr_ret;
210         int i, unrefs = 0;
211         gpointer ct_ret = NULL;
212         
213         mono_once(&thread_hash_once, thread_hash_init);
214         mono_once (&thread_ops_once, thread_ops_init);
215         
216         if(start==NULL) {
217                 return(NULL);
218         }
219         
220         handle=_wapi_handle_new (WAPI_HANDLE_THREAD);
221         if(handle==_WAPI_HANDLE_INVALID) {
222                 g_warning (G_GNUC_PRETTY_FUNCTION
223                            ": error creating thread handle");
224                 return(NULL);
225         }
226
227         pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
228                               handle);
229         thr_ret = _wapi_handle_lock_handle (handle);
230         g_assert (thr_ret == 0);
231         
232         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
233                                 (gpointer *)&thread_handle,
234                                 (gpointer *)&thread_private_handle);
235         if(ok==FALSE) {
236                 g_warning (G_GNUC_PRETTY_FUNCTION
237                            ": error looking up thread handle %p", handle);
238                 goto cleanup;
239         }
240
241         /* Hold a reference while the thread is active, because we use
242          * the handle to store thread exit information
243          */
244         _wapi_handle_ref (handle);
245
246         thread_handle->state=THREAD_STATE_START;
247         
248         /* Lock around the thread create, so that the new thread cant
249          * race us to look up the thread handle in GetCurrentThread()
250          */
251         pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
252                               (void *)&thread_hash_mutex);
253         thr_ret = mono_mutex_lock(&thread_hash_mutex);
254         g_assert (thr_ret == 0);
255         
256         /* Set a 2M stack size.  This is the default on Linux, but BSD
257          * needs it.  (The original bug report from Martin Dvorak <md@9ll.cz>
258          * set the size to 2M-4k.  I don't know why it's short by 4k, so
259          * I'm leaving it as 2M until I'm told differently.)
260          */
261         thr_ret = pthread_attr_init(&attr);
262         g_assert (thr_ret == 0);
263         
264         /* defaults of 2Mb for 32bits and 4Mb for 64bits */
265         if (stacksize == 0)
266                 stacksize = (SIZEOF_VOID_P / 2) * 1024 *1024;
267
268 #ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE
269         thr_ret = pthread_attr_setstacksize(&attr, stacksize);
270         g_assert (thr_ret == 0);
271 #endif
272
273         ret=_wapi_timed_thread_create(&thread_private_handle->thread, &attr,
274                                       create, start, thread_exit, param,
275                                       handle);
276         if(ret!=0) {
277 #ifdef DEBUG
278                 g_message(G_GNUC_PRETTY_FUNCTION ": Thread create error: %s",
279                           strerror(ret));
280 #endif
281                 /* Two, because of the reference we took above */
282                 unrefs = 2;
283                 goto thread_hash_cleanup;
284         }
285         ct_ret = handle;
286         
287         g_hash_table_insert(thread_hash, &thread_private_handle->thread->id,
288                             handle);
289         
290 #ifdef DEBUG
291         g_message(G_GNUC_PRETTY_FUNCTION
292                   ": Started thread handle %p thread %p ID %ld", handle,
293                   thread_private_handle->thread,
294                   thread_private_handle->thread->id);
295 #endif
296         
297         if(tid!=NULL) {
298 #ifdef PTHREAD_POINTER_ID
299                 *tid=GPOINTER_TO_UINT(thread_private_handle->thread->id);
300 #else
301                 *tid=thread_private_handle->thread->id;
302 #endif
303         }
304
305 thread_hash_cleanup:
306         thr_ret = mono_mutex_unlock (&thread_hash_mutex);
307         g_assert (thr_ret == 0);
308         pthread_cleanup_pop (0);
309         
310 cleanup:
311         thr_ret = _wapi_handle_unlock_handle (handle);
312         g_assert (thr_ret == 0);
313         pthread_cleanup_pop (0);
314         
315         /* Must not call _wapi_handle_unref() with the handle already
316          * locked
317          */
318         for (i = 0; i < unrefs; i++) {
319                 _wapi_handle_unref (handle);
320         }
321
322         return(ct_ret);
323 }
324
325 gpointer OpenThread (guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, guint32 tid)
326 {
327         gpointer ret=NULL;
328         int thr_ret;
329         
330         mono_once(&thread_hash_once, thread_hash_init);
331         mono_once (&thread_ops_once, thread_ops_init);
332         
333 #ifdef DEBUG
334         g_message (G_GNUC_PRETTY_FUNCTION ": looking up thread %d", tid);
335 #endif
336
337         pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
338                               (void *)&thread_hash_mutex);
339         thr_ret = mono_mutex_lock(&thread_hash_mutex);
340         g_assert (thr_ret == 0);
341         
342         ret=g_hash_table_lookup(thread_hash, &tid);
343
344         thr_ret = mono_mutex_unlock(&thread_hash_mutex);
345         g_assert (thr_ret == 0);
346         pthread_cleanup_pop (0);
347         
348         if(ret!=NULL) {
349                 _wapi_handle_ref (ret);
350         }
351         
352 #ifdef DEBUG
353         g_message (G_GNUC_PRETTY_FUNCTION ": returning thread handle %p", ret);
354 #endif
355         
356         return(ret);
357 }
358
359 /**
360  * ExitThread:
361  * @exitcode: Sets the thread's exit code, which can be read from
362  * another thread with GetExitCodeThread().
363  *
364  * Terminates the calling thread.  A thread can also exit by returning
365  * from its start function. When the last thread in a process
366  * terminates, the process itself terminates.
367  */
368 void ExitThread(guint32 exitcode)
369 {
370         _wapi_timed_thread_exit(exitcode);
371 }
372
373 /**
374  * GetExitCodeThread:
375  * @handle: The thread handle to query
376  * @exitcode: The thread @handle exit code is stored here
377  *
378  * Finds the exit code of @handle, and stores it in @exitcode.  If the
379  * thread @handle is still running, the value stored is %STILL_ACTIVE.
380  *
381  * Return value: %TRUE, or %FALSE on error.
382  */
383 gboolean GetExitCodeThread(gpointer handle, guint32 *exitcode)
384 {
385         struct _WapiHandle_thread *thread_handle;
386         struct _WapiHandlePrivate_thread *thread_private_handle;
387         gboolean ok;
388         
389         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
390                                 (gpointer *)&thread_handle,
391                                 (gpointer *)&thread_private_handle);
392         if(ok==FALSE) {
393                 g_warning (G_GNUC_PRETTY_FUNCTION
394                            ": error looking up thread handle %p", handle);
395                 return(FALSE);
396         }
397         
398 #ifdef DEBUG
399         g_message(G_GNUC_PRETTY_FUNCTION
400                   ": Finding exit status for thread handle %p id %ld", handle,
401                   thread_private_handle->thread->id);
402 #endif
403
404         if(exitcode==NULL) {
405 #ifdef DEBUG
406                 g_message(G_GNUC_PRETTY_FUNCTION
407                           ": Nowhere to store exit code");
408 #endif
409                 return(FALSE);
410         }
411         
412         if(thread_handle->state!=THREAD_STATE_EXITED) {
413 #ifdef DEBUG
414                 g_message(G_GNUC_PRETTY_FUNCTION
415                           ": Thread still active (state %d, exited is %d)",
416                           thread_handle->state, THREAD_STATE_EXITED);
417 #endif
418                 *exitcode=STILL_ACTIVE;
419                 return(TRUE);
420         }
421         
422         *exitcode=thread_handle->exitstatus;
423         
424         return(TRUE);
425 }
426
427 /**
428  * GetCurrentThreadId:
429  *
430  * Looks up the thread ID of the current thread.  This ID can be
431  * passed to OpenThread() to create a new handle on this thread.
432  *
433  * Return value: the thread ID.
434  */
435 guint32 GetCurrentThreadId(void)
436 {
437         pthread_t tid=pthread_self();
438         
439 #ifdef PTHREAD_POINTER_ID
440         return(GPOINTER_TO_UINT(tid));
441 #else
442         return(tid);
443 #endif
444 }
445
446 static gpointer thread_attach(guint32 *tid)
447 {
448         struct _WapiHandle_thread *thread_handle;
449         struct _WapiHandlePrivate_thread *thread_private_handle;
450         gpointer handle;
451         gboolean ok;
452         int ret;
453         int thr_ret;
454         int i, unrefs = 0;
455         gpointer ta_ret = NULL;
456         
457         mono_once(&thread_hash_once, thread_hash_init);
458         mono_once (&thread_ops_once, thread_ops_init);
459
460         handle=_wapi_handle_new (WAPI_HANDLE_THREAD);
461         if(handle==_WAPI_HANDLE_INVALID) {
462                 g_warning (G_GNUC_PRETTY_FUNCTION
463                            ": error creating thread handle");
464                 return(NULL);
465         }
466
467         pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
468                               handle);
469         thr_ret = _wapi_handle_lock_handle (handle);
470         g_assert (thr_ret == 0);
471
472         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
473                                 (gpointer *)&thread_handle,
474                                 (gpointer *)&thread_private_handle);
475         if(ok==FALSE) {
476                 g_warning (G_GNUC_PRETTY_FUNCTION
477                            ": error looking up thread handle %p", handle);
478                 goto cleanup;
479         }
480
481         /* Hold a reference while the thread is active, because we use
482          * the handle to store thread exit information
483          */
484         _wapi_handle_ref (handle);
485
486         thread_handle->state=THREAD_STATE_START;
487
488         /* Lock around the thread create, so that the new thread cant
489          * race us to look up the thread handle in GetCurrentThread()
490          */
491         pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
492                               (void *)&thread_hash_mutex);
493         thr_ret = mono_mutex_lock(&thread_hash_mutex);
494         g_assert (thr_ret == 0);
495
496         ret=_wapi_timed_thread_attach(&thread_private_handle->thread,
497                                       thread_exit, handle);
498         if(ret!=0) {
499 #ifdef DEBUG
500                 g_message(G_GNUC_PRETTY_FUNCTION ": Thread attach error: %s",
501                           strerror(ret));
502 #endif
503                 /* Two, because of the reference we took above */
504                 unrefs = 2;
505
506                 goto thread_hash_cleanup;
507         }
508         ta_ret = handle;
509         
510         g_hash_table_insert(thread_hash, &thread_private_handle->thread->id,
511                             handle);
512
513 #ifdef DEBUG
514         g_message(G_GNUC_PRETTY_FUNCTION
515                   ": Attached thread handle %p thread %p ID %ld", handle,
516                   thread_private_handle->thread,
517                   thread_private_handle->thread->id);
518 #endif
519
520         if(tid!=NULL) {
521 #ifdef PTHREAD_POINTER_ID
522                 *tid=GPOINTER_TO_UINT(thread_private_handle->thread->id);
523 #else
524                 *tid=thread_private_handle->thread->id;
525 #endif
526         }
527
528 thread_hash_cleanup:
529         thr_ret = mono_mutex_unlock (&thread_hash_mutex);
530         g_assert (thr_ret == 0);
531         pthread_cleanup_pop (0);
532         
533 cleanup:
534         thr_ret = _wapi_handle_unlock_handle (handle);
535         g_assert (thr_ret == 0);
536         pthread_cleanup_pop (0);
537
538         /* Must not call _wapi_handle_unref() with the handle already
539          * locked
540          */
541         for (i = 0; i < unrefs; i++) {
542                 _wapi_handle_unref (handle);
543         }
544         
545         return(ta_ret);
546 }
547
548 /**
549  * GetCurrentThread:
550  *
551  * Looks up the handle associated with the current thread.  Under
552  * Windows this is a pseudohandle, and must be duplicated with
553  * DuplicateHandle() for some operations.
554  *
555  * Return value: The current thread handle, or %NULL on failure.
556  * (Unknown whether Windows has a possible failure here.  It may be
557  * necessary to implement the pseudohandle-constant behaviour).
558  */
559 gpointer GetCurrentThread(void)
560 {
561         gpointer ret=NULL;
562         guint32 tid;
563         int thr_ret;
564         
565         mono_once(&thread_hash_once, thread_hash_init);
566         mono_once (&thread_ops_once, thread_ops_init);
567         
568         tid=GetCurrentThreadId();
569         
570         pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
571                               (void *)&thread_hash_mutex);
572         thr_ret = mono_mutex_lock(&thread_hash_mutex);
573         g_assert (thr_ret == 0);
574
575         ret=g_hash_table_lookup(thread_hash, &tid);
576
577         thr_ret = mono_mutex_unlock(&thread_hash_mutex);
578         g_assert (thr_ret == 0);
579         pthread_cleanup_pop (0);
580         
581         if (!ret) {
582                 ret = thread_attach (NULL);
583         }
584
585         return(ret);
586 }
587
588 /**
589  * ResumeThread:
590  * @handle: the thread handle to resume
591  *
592  * Decrements the suspend count of thread @handle. A thread can only
593  * run if its suspend count is zero.
594  *
595  * Return value: the previous suspend count, or 0xFFFFFFFF on error.
596  */
597 guint32 ResumeThread(gpointer handle)
598 {
599         struct _WapiHandle_thread *thread_handle;
600         struct _WapiHandlePrivate_thread *thread_private_handle;
601         gboolean ok;
602         
603         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
604                                 (gpointer *)&thread_handle,
605                                 (gpointer *)&thread_private_handle);
606         if(ok==FALSE) {
607                 g_warning (G_GNUC_PRETTY_FUNCTION
608                            ": error looking up thread handle %p", handle);
609                 return(0xFFFFFFFF);
610         }
611
612 #ifdef WITH_INCLUDED_LIBGC
613         if (thread_private_handle->thread->suspend_count <= 1)
614                 _wapi_timed_thread_resume (thread_private_handle->thread);
615         
616         return --thread_private_handle->thread->suspend_count;
617 #else
618         /* This is still a kludge that only copes with starting a
619          * thread that was suspended on create, so don't bother with
620          * the suspend count crap yet
621          */
622         _wapi_timed_thread_resume (thread_private_handle->thread);
623         return(0xFFFFFFFF);
624 #endif
625 }
626
627 /**
628  * SuspendThread:
629  * @handle: the thread handle to suspend
630  *
631  * Increments the suspend count of thread @handle. A thread can only
632  * run if its suspend count is zero.
633  *
634  * Return value: the previous suspend count, or 0xFFFFFFFF on error.
635  */
636 guint32 SuspendThread(gpointer handle)
637 {
638 #ifdef WITH_INCLUDED_LIBGC
639         struct _WapiHandle_thread *thread_handle;
640         struct _WapiHandlePrivate_thread *thread_private_handle;
641         gpointer current;
642         gboolean ok;
643
644         current = GetCurrentThread ();
645         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
646                                 (gpointer *)&thread_handle,
647                                 (gpointer *)&thread_private_handle);
648         if(ok==FALSE) {
649                 g_warning (G_GNUC_PRETTY_FUNCTION
650                            ": error looking up thread handle %p", handle);
651                 return(0xFFFFFFFF);
652         }
653
654         if (!thread_private_handle->thread->suspend_count) {
655                 if (handle == current)
656                         _wapi_timed_thread_suspend (thread_private_handle->thread);
657                 else {
658                         pthread_kill (thread_private_handle->thread->id, SIGPWR);
659                         MONO_SEM_WAIT (&thread_private_handle->thread->suspended_sem);
660                 }
661         }
662
663         return thread_private_handle->thread->suspend_count++;
664 #else
665         return(0xFFFFFFFF);
666 #endif
667 }
668
669 /*
670  * We assume here that TLS_MINIMUM_AVAILABLE is less than
671  * PTHREAD_KEYS_MAX, allowing enough overhead for a few TLS keys for
672  * library usage.
673  *
674  * Currently TLS_MINIMUM_AVAILABLE is 64 and _POSIX_THREAD_KEYS_MAX
675  * (the minimum value for PTHREAD_KEYS_MAX) is 128, so we should be
676  * fine.
677  */
678
679 static pthread_key_t TLS_keys[TLS_MINIMUM_AVAILABLE];
680 static gboolean TLS_used[TLS_MINIMUM_AVAILABLE]={FALSE};
681 static guint32 TLS_spinlock=0;
682
683 /**
684  * TlsAlloc:
685  *
686  * Allocates a Thread Local Storage (TLS) index.  Any thread in the
687  * same process can use this index to store and retrieve values that
688  * are local to that thread.
689  *
690  * Return value: The index value, or %TLS_OUT_OF_INDEXES if no index
691  * is available.
692  */
693 guint32 TlsAlloc(void)
694 {
695         guint32 i;
696         int thr_ret;
697         
698         MONO_SPIN_LOCK (TLS_spinlock);
699         
700         for(i=0; i<TLS_MINIMUM_AVAILABLE; i++) {
701                 if(TLS_used[i]==FALSE) {
702                         TLS_used[i]=TRUE;
703                         thr_ret = pthread_key_create(&TLS_keys[i], NULL);
704                         g_assert (thr_ret == 0);
705
706                         MONO_SPIN_UNLOCK (TLS_spinlock);
707         
708 #ifdef TLS_DEBUG
709                         g_message (G_GNUC_PRETTY_FUNCTION ": returning key %d",
710                                    i);
711 #endif
712                         
713                         return(i);
714                 }
715         }
716
717         MONO_SPIN_UNLOCK (TLS_spinlock);
718         
719 #ifdef TLS_DEBUG
720         g_message (G_GNUC_PRETTY_FUNCTION ": out of indices");
721 #endif
722                         
723         
724         return(TLS_OUT_OF_INDEXES);
725 }
726
727 #define MAKE_GC_ID(idx) (GUINT_TO_POINTER((idx)|(GetCurrentThreadId()<<8)))
728
729 /**
730  * TlsFree:
731  * @idx: The TLS index to free
732  *
733  * Releases a TLS index, making it available for reuse.  This call
734  * will delete any TLS data stored under index @idx in all threads.
735  *
736  * Return value: %TRUE on success, %FALSE otherwise.
737  */
738 gboolean TlsFree(guint32 idx)
739 {
740         int thr_ret;
741         
742 #ifdef TLS_DEBUG
743         g_message (G_GNUC_PRETTY_FUNCTION ": freeing key %d", idx);
744 #endif
745
746         MONO_SPIN_LOCK (TLS_spinlock);
747         
748         if(TLS_used[idx]==FALSE) {
749                 MONO_SPIN_UNLOCK (TLS_spinlock);
750
751                 return(FALSE);
752         }
753         
754         TLS_used[idx]=FALSE;
755         thr_ret = pthread_key_delete(TLS_keys[idx]);
756         g_assert (thr_ret == 0);
757         
758 #if HAVE_BOEHM_GC
759         mono_g_hash_table_remove (tls_gc_hash, MAKE_GC_ID (idx));
760 #endif
761
762         MONO_SPIN_UNLOCK (TLS_spinlock);
763         
764         return(TRUE);
765 }
766
767 /**
768  * TlsGetValue:
769  * @idx: The TLS index to retrieve
770  *
771  * Retrieves the TLS data stored under index @idx.
772  *
773  * Return value: The value stored in the TLS index @idx in the current
774  * thread, or %NULL on error.  As %NULL can be a valid return value,
775  * in this case GetLastError() returns %ERROR_SUCCESS.
776  */
777 gpointer TlsGetValue(guint32 idx)
778 {
779         gpointer ret;
780         
781 #ifdef TLS_DEBUG
782         g_message (G_GNUC_PRETTY_FUNCTION ": looking up key %d", idx);
783 #endif
784         
785         ret=pthread_getspecific(TLS_keys[idx]);
786
787 #ifdef TLS_DEBUG
788         g_message (G_GNUC_PRETTY_FUNCTION ": returning %p", ret);
789 #endif
790         
791         return(ret);
792 }
793
794 /**
795  * TlsSetValue:
796  * @idx: The TLS index to store
797  * @value: The value to store under index @idx
798  *
799  * Stores @value at TLS index @idx.
800  *
801  * Return value: %TRUE on success, %FALSE otherwise.
802  */
803 gboolean TlsSetValue(guint32 idx, gpointer value)
804 {
805         int ret;
806
807 #ifdef TLS_DEBUG
808         g_message (G_GNUC_PRETTY_FUNCTION ": setting key %d to %p", idx,
809                    value);
810 #endif
811         
812         MONO_SPIN_LOCK (TLS_spinlock);
813         
814         if(TLS_used[idx]==FALSE) {
815 #ifdef TLS_DEBUG
816                 g_message (G_GNUC_PRETTY_FUNCTION ": key %d unused", idx);
817 #endif
818
819                 MONO_SPIN_UNLOCK (TLS_spinlock);
820
821                 return(FALSE);
822         }
823         
824         ret=pthread_setspecific(TLS_keys[idx], value);
825         if(ret!=0) {
826 #ifdef TLS_DEBUG
827                 g_message (G_GNUC_PRETTY_FUNCTION
828                            ": pthread_setspecific error: %s", strerror (ret));
829 #endif
830
831                 MONO_SPIN_UNLOCK (TLS_spinlock);
832
833                 return(FALSE);
834         }
835         
836 #if HAVE_BOEHM_GC
837         if (!tls_gc_hash)
838                 tls_gc_hash = mono_g_hash_table_new(g_direct_hash, g_direct_equal);
839         mono_g_hash_table_insert (tls_gc_hash, MAKE_GC_ID (idx), value);
840 #endif
841
842         MONO_SPIN_UNLOCK (TLS_spinlock);
843         
844         return(TRUE);
845 }
846
847 /**
848  * Sleep:
849  * @ms: The time in milliseconds to suspend for
850  *
851  * Suspends execution of the current thread for @ms milliseconds.  A
852  * value of zero causes the thread to relinquish its time slice.  A
853  * value of %INFINITE causes an infinite delay.
854  */
855 void Sleep(guint32 ms)
856 {
857         struct timespec req, rem;
858         int ms_quot, ms_rem;
859         int ret;
860         
861 #ifdef DEBUG
862         g_message(G_GNUC_PRETTY_FUNCTION ": Sleeping for %d ms", ms);
863 #endif
864
865         if(ms==0) {
866                 sched_yield();
867                 return;
868         }
869         
870         /* FIXME: check for INFINITE and sleep forever */
871         ms_quot = ms / 1000;
872         ms_rem = ms % 1000;
873         
874         req.tv_sec=ms_quot;
875         req.tv_nsec=ms_rem*1000000;
876         
877 again:
878         ret=nanosleep(&req, &rem);
879         if(ret==-1) {
880                 /* Sleep interrupted with rem time remaining */
881 #ifdef DEBUG
882                 guint32 rems=rem.tv_sec*1000 + rem.tv_nsec/1000000;
883                 
884                 g_message(G_GNUC_PRETTY_FUNCTION ": Still got %d ms to go",
885                           rems);
886 #endif
887                 req=rem;
888                 goto again;
889         }
890 }
891
892 /* FIXME: implement alertable */
893 void SleepEx(guint32 ms, gboolean alertable)
894 {
895         if(alertable==TRUE) {
896                 g_warning(G_GNUC_PRETTY_FUNCTION ": alertable not implemented");
897         }
898         
899         Sleep(ms);
900 }
901
902 gboolean
903 BindIoCompletionCallback (gpointer handle,
904                           WapiOverlappedCB callback,
905                           guint64 flags)
906 {
907         WapiHandleType type;
908         
909         type = _wapi_handle_type (handle);
910         if (type == WAPI_HANDLE_FILE || type == WAPI_HANDLE_PIPE)
911                 return _wapi_io_add_callback (handle, callback, flags);
912
913         SetLastError (ERROR_NOT_SUPPORTED);
914         return FALSE;
915 }
916
917 guint32 QueueUserAPC (WapiApcProc apc_callback, gpointer handle, 
918                                         gpointer param)
919 {
920         struct _WapiHandle_thread *thread_handle;
921         struct _WapiHandlePrivate_thread *thread_private_handle;
922         gboolean ok;
923
924         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
925                                 (gpointer *)&thread_handle,
926                                 (gpointer *)&thread_private_handle);
927         if(ok==FALSE) {
928                 g_warning (G_GNUC_PRETTY_FUNCTION
929                            ": error looking up thread handle %p", handle);
930                 return(0);
931         }
932
933         _wapi_timed_thread_queue_apc (thread_private_handle->thread, 
934                                                         apc_callback, param);
935         return(1);
936 }
937
938 gboolean _wapi_thread_cur_apc_pending (void)
939 {
940         return _wapi_thread_apc_pending (GetCurrentThread ());
941 }
942
943 gboolean _wapi_thread_apc_pending (gpointer handle)
944 {
945         struct _WapiHandle_thread *thread_handle;
946         struct _WapiHandlePrivate_thread *thread_private_handle;
947         gboolean ok;
948
949         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
950                                 (gpointer *)&thread_handle,
951                                 (gpointer *)&thread_private_handle);
952         if(ok==FALSE) {
953                 g_warning (G_GNUC_PRETTY_FUNCTION
954                            ": error looking up thread handle %p", handle);
955                 return(FALSE);
956         }
957
958         return _wapi_timed_thread_apc_pending (thread_private_handle->thread);
959 }
960
961 gboolean _wapi_thread_dispatch_apc_queue (gpointer handle)
962 {
963         struct _WapiHandle_thread *thread_handle;
964         struct _WapiHandlePrivate_thread *thread_private_handle;
965         gboolean ok;
966
967         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
968                                 (gpointer *)&thread_handle,
969                                 (gpointer *)&thread_private_handle);
970         if(ok==FALSE) {
971                 g_warning (G_GNUC_PRETTY_FUNCTION
972                            ": error looking up thread handle %p", handle);
973                 return(0);
974         }
975
976         _wapi_timed_thread_dispatch_apc_queue (thread_private_handle->thread);
977         return(1);
978 }
979
980
981
982 #ifdef WITH_INCLUDED_LIBGC
983
984 static void GC_suspend_handler (int sig)
985 {
986         struct _WapiHandle_thread *thread_handle;
987         struct _WapiHandlePrivate_thread *thread_private_handle;
988         gpointer handle;
989         gboolean ok;
990
991         handle = GetCurrentThread ();
992         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
993                                 (gpointer *)&thread_handle,
994                                 (gpointer *)&thread_private_handle);
995         if(ok==FALSE) {
996                 g_warning (G_GNUC_PRETTY_FUNCTION
997                            ": error looking up thread handle %p", handle);
998                 return;
999         }
1000
1001         thread_private_handle->thread->stack_ptr = &ok;
1002         MONO_SEM_POST (&thread_private_handle->thread->suspended_sem);
1003
1004         _wapi_timed_thread_suspend (thread_private_handle->thread);
1005
1006         thread_private_handle->thread->stack_ptr = NULL;
1007 }
1008
1009 static void gc_init (void)
1010 {
1011         struct sigaction act;
1012
1013         act.sa_handler = GC_suspend_handler;
1014         g_assert (sigaction (SIGPWR, &act, NULL) == 0);
1015 }
1016
1017 void mono_wapi_push_thread_stack (gpointer handle, gpointer stack_ptr)
1018 {
1019         struct _WapiHandle_thread *thread_handle;
1020         struct _WapiHandlePrivate_thread *thread_private_handle;
1021         gboolean ok;
1022
1023         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
1024                                 (gpointer *)&thread_handle,
1025                                 (gpointer *)&thread_private_handle);
1026         if(ok==FALSE) {
1027                 g_warning (G_GNUC_PRETTY_FUNCTION
1028                            ": error looking up thread handle %p", handle);
1029                 return;
1030         }
1031
1032         GC_push_all_stack (thread_private_handle->thread->stack_ptr, stack_ptr);
1033 }
1034
1035 #endif /* WITH_INCLUDED_LIBGC */