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