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