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