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