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