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