Update thread_hash hash/equals functions to operate on plain ints.
[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 _WapiHandleShared shared_handle;
75         struct _WapiHandle_thread *thread_handle;
76         gboolean ok;
77         
78 #ifdef DEBUG
79         g_message ("%s: owning thread handle %p", __func__, handle);
80 #endif
81
82         ok = _wapi_copy_handle (handle, WAPI_HANDLE_THREAD,
83                                 &shared_handle);
84         if (ok == FALSE) {
85                 g_warning ("%s: error copying thread handle %p", __func__,
86                            handle);
87                 return(FALSE);
88         }
89         thread_handle = &shared_handle.u.thread;
90
91         if (thread_handle->owner_pid != getpid()) {
92 #ifdef DEBUG
93                 g_message ("%s: can't join thread, %d not owner process %d",
94                            __func__, getpid(), thread_handle->owner_pid);
95 #endif
96                 /* FIXME: might need to return TRUE here so that other
97                  * processes can WaitFor thread handles
98                  */
99                 return(FALSE);
100         }
101         
102         if (thread_handle->joined == FALSE) {
103                 _wapi_timed_thread_join (thread_handle->thread, NULL, NULL);
104                 thread_handle->joined = TRUE;
105
106                 _wapi_replace_handle (handle, WAPI_HANDLE_THREAD,
107                                       &shared_handle);
108         }
109
110         return(TRUE);
111 }
112
113 static void thread_exit(guint32 exitstatus, gpointer handle)
114 {
115         struct _WapiHandleShared shared_handle;
116         struct _WapiHandle_thread *thread_handle;
117         gboolean ok;
118         int thr_ret;
119
120         pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
121                               handle);
122         thr_ret = _wapi_handle_lock_handle (handle);
123         g_assert (thr_ret == 0);
124         
125         ok = _wapi_copy_handle (handle, WAPI_HANDLE_THREAD,
126                                 &shared_handle);
127         if (ok == FALSE) {
128                 g_warning ("%s: error copying thread handle %p", __func__,
129                            handle);
130                 return;
131         }
132         thread_handle = &shared_handle.u.thread;
133         
134         _wapi_mutex_check_abandoned (getpid (), thread_handle->thread->id);
135
136 #ifdef DEBUG
137         g_message ("%s: Recording thread handle %p exit status", __func__,
138                    handle);
139 #endif
140         
141         thread_handle->exitstatus = exitstatus;
142         thread_handle->state = THREAD_STATE_EXITED;
143
144         _wapi_replace_handle (handle, WAPI_HANDLE_THREAD, &shared_handle);
145         
146         _wapi_shared_handle_set_signal_state (handle, TRUE);
147
148         thr_ret = _wapi_handle_unlock_handle (handle);
149         g_assert (thr_ret == 0);
150         pthread_cleanup_pop (0);
151         
152 #ifdef DEBUG
153         g_message("%s: Recording thread handle %p id %ld status as %d",
154                   __func__, handle, thread_handle->thread->id, exitstatus);
155 #endif
156
157         /* Remove this thread from the hash */
158         pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
159                               (void *)&thread_hash_mutex);
160         thr_ret = mono_mutex_lock(&thread_hash_mutex);
161         g_assert (thr_ret == 0);
162         
163         g_hash_table_remove (thread_hash, GUINT_TO_POINTER (thread_handle->thread->id));
164
165         thr_ret = mono_mutex_unlock(&thread_hash_mutex);
166         g_assert (thr_ret == 0);
167         pthread_cleanup_pop (0);
168
169         /* The thread is no longer active, so unref it */
170         _wapi_handle_unref (handle);
171 }
172
173 static void thread_hash_init(void)
174 {
175         thread_hash = g_hash_table_new (NULL, NULL);
176 }
177
178 /**
179  * CreateThread:
180  * @security: Ignored for now.
181  * @stacksize: the size in bytes of the new thread's stack. Use 0 to
182  * default to the normal stack size. (Ignored for now).
183  * @start: The function that the new thread should start with
184  * @param: The parameter to give to @start.
185  * @create: If 0, the new thread is ready to run immediately.  If
186  * %CREATE_SUSPENDED, the new thread will be in the suspended state,
187  * requiring a ResumeThread() call to continue running.
188  * @tid: If non-NULL, the ID of the new thread is stored here.
189  *
190  * Creates a new threading handle.
191  *
192  * Return value: a new handle, or NULL
193  */
194 gpointer CreateThread(WapiSecurityAttributes *security G_GNUC_UNUSED, guint32 stacksize,
195                       WapiThreadStart start, gpointer param, guint32 create,
196                       guint32 *tid) 
197 {
198         struct _WapiHandleShared shared_handle;
199         struct _WapiHandle_thread thread_handle = {0};
200         pthread_attr_t attr;
201         gpointer handle;
202         gboolean ok;
203         int ret;
204         int thr_ret;
205         gpointer ct_ret = NULL;
206         
207         mono_once (&thread_hash_once, thread_hash_init);
208         mono_once (&thread_ops_once, thread_ops_init);
209         
210         if (start == NULL) {
211                 return(NULL);
212         }
213
214         thread_handle.state = THREAD_STATE_START;
215         thread_handle.owner_pid = getpid();
216         
217         /* Set a 2M stack size.  This is the default on Linux, but BSD
218          * needs it.  (The original bug report from Martin Dvorak <md@9ll.cz>
219          * set the size to 2M-4k.  I don't know why it's short by 4k, so
220          * I'm leaving it as 2M until I'm told differently.)
221          */
222         thr_ret = pthread_attr_init(&attr);
223         g_assert (thr_ret == 0);
224         
225         /* defaults of 2Mb for 32bits and 4Mb for 64bits */
226         /* temporarily changed to use 1 MB: this allows more threads to be used,
227          * as well as using less virtual memory and so more is available for
228          * the GC heap.
229          */
230         if (stacksize == 0){
231 #if HAVE_VALGRIND_MEMCHECK_H
232                 if (RUNNING_ON_VALGRIND) {
233                         stacksize = 1 << 20;
234                 } else {
235                         stacksize = (SIZEOF_VOID_P / 4) * 1024 * 1024;
236                 }
237 #else
238                 stacksize = (SIZEOF_VOID_P / 4) * 1024 * 1024;
239 #endif
240                 
241         }
242
243 #ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE
244         thr_ret = pthread_attr_setstacksize(&attr, stacksize);
245         g_assert (thr_ret == 0);
246 #endif
247         
248         /* Lock around the thread create, so that the new thread cant
249          * race us to look up the thread handle in GetCurrentThread()
250          */
251         pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
252                               (void *)&thread_hash_mutex);
253         thr_ret = mono_mutex_lock(&thread_hash_mutex);
254         g_assert (thr_ret == 0);
255         
256         handle = _wapi_handle_new (WAPI_HANDLE_THREAD, &thread_handle);
257         if (handle == _WAPI_HANDLE_INVALID) {
258                 g_warning ("%s: error creating thread handle", __func__);
259                 goto thread_hash_cleanup;
260         }
261         ct_ret = handle;
262
263         ret = _wapi_timed_thread_create (&thread_handle.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                 _wapi_handle_unref (handle);
272                 goto thread_hash_cleanup;
273         }
274
275         /* Need to update the handle with the state info that
276          * _wapi_timed_thread_create created, after the initial handle
277          * info was copied into shared memory
278          */
279         ok = _wapi_copy_handle (handle, WAPI_HANDLE_THREAD, &shared_handle);
280         if (ok == FALSE) {
281                 g_warning ("%s: error copying thread handle %p", __func__,
282                            handle);
283                 _wapi_handle_unref (handle);
284                 goto thread_hash_cleanup;
285         }
286         shared_handle.u.thread.thread = thread_handle.thread;
287         _wapi_replace_handle (handle, WAPI_HANDLE_THREAD, &shared_handle);
288         
289         /* Hold a reference while the thread is active, because we use
290          * the handle to store thread exit information
291          */
292         _wapi_handle_ref (handle);
293         
294         g_hash_table_insert (thread_hash, GUINT_TO_POINTER (thread_handle.thread->id), handle);
295         
296 #ifdef DEBUG
297         g_message("%s: Started thread handle %p thread %p ID %ld", __func__,
298                   handle, thread_handle.thread, thread_handle.thread->id);
299 #endif
300         
301         if (tid != NULL) {
302 #ifdef PTHREAD_POINTER_ID
303                 *tid = GPOINTER_TO_UINT (thread_handle.thread->id);
304 #else
305                 *tid = thread_handle.thread->id;
306 #endif
307         }
308
309 thread_hash_cleanup:
310         thr_ret = mono_mutex_unlock (&thread_hash_mutex);
311         g_assert (thr_ret == 0);
312         pthread_cleanup_pop (0);
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 #ifdef DEBUG
378         g_message ("%s: Finding exit status for thread handle %p id %ld",
379                    __func__, handle,
380                    WAPI_SHARED_HANDLE_TYPED_DATA(handle, thread).thread->id);
381 #endif
382
383         if (exitcode == NULL) {
384 #ifdef DEBUG
385                 g_message ("%s: Nowhere to store exit code", __func__);
386 #endif
387                 return(FALSE);
388         }
389         
390         if (WAPI_SHARED_HANDLE_TYPED_DATA(handle, thread).state != THREAD_STATE_EXITED) {
391 #ifdef DEBUG
392                 g_message ("%s: Thread still active (state %d, exited is %d)",
393                            __func__,
394                            WAPI_SHARED_HANDLE_TYPED_DATA(handle, thread).state,
395                            THREAD_STATE_EXITED);
396 #endif
397                 *exitcode = STILL_ACTIVE;
398                 return(TRUE);
399         }
400         
401         *exitcode = WAPI_SHARED_HANDLE_TYPED_DATA(handle, thread).exitstatus;
402         
403         return(TRUE);
404 }
405
406 /**
407  * GetCurrentThreadId:
408  *
409  * Looks up the thread ID of the current thread.  This ID can be
410  * passed to OpenThread() to create a new handle on this thread.
411  *
412  * Return value: the thread ID.
413  */
414 guint32 GetCurrentThreadId(void)
415 {
416         pthread_t tid = pthread_self();
417         
418 #ifdef PTHREAD_POINTER_ID
419         return(GPOINTER_TO_UINT(tid));
420 #else
421         return(tid);
422 #endif
423 }
424
425 static gpointer thread_attach(guint32 *tid)
426 {
427         struct _WapiHandleShared shared_handle;
428         struct _WapiHandle_thread thread_handle = {0};
429         gpointer handle;
430         gboolean ok;
431         int ret;
432         int thr_ret;
433         gpointer ta_ret = NULL;
434         
435         mono_once (&thread_hash_once, thread_hash_init);
436         mono_once (&thread_ops_once, thread_ops_init);
437
438         thread_handle.state = THREAD_STATE_START;
439         thread_handle.owner_pid = getpid();
440
441         /* Lock around the thread create, so that the new thread cant
442          * race us to look up the thread handle in GetCurrentThread()
443          */
444         pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
445                               (void *)&thread_hash_mutex);
446         thr_ret = mono_mutex_lock(&thread_hash_mutex);
447         g_assert (thr_ret == 0);
448
449         handle = _wapi_handle_new (WAPI_HANDLE_THREAD, &thread_handle);
450         if (handle == _WAPI_HANDLE_INVALID) {
451                 g_warning ("%s: error creating thread handle", __func__);
452                 goto thread_hash_cleanup;
453         }
454         ta_ret = handle;
455
456         ret = _wapi_timed_thread_attach (&thread_handle.thread, thread_exit,
457                                          handle);
458         if (ret != 0) {
459 #ifdef DEBUG
460                 g_message ("%s: Thread attach error: %s", __func__,
461                            strerror(ret));
462 #endif
463
464                 _wapi_handle_unref (handle);
465                 goto thread_hash_cleanup;
466         }
467
468         /* Need to update the handle with the state info that
469          * _wapi_timed_thread_create created, after the initial handle
470          * info was copied into shared memory
471          */
472         ok = _wapi_copy_handle (handle, WAPI_HANDLE_THREAD, &shared_handle);
473         if (ok == FALSE) {
474                 g_warning ("%s: error copying thread handle %p", __func__,
475                            handle);
476                 _wapi_handle_unref (handle);
477                 goto thread_hash_cleanup;
478         }
479         shared_handle.u.thread.thread = thread_handle.thread;
480         _wapi_replace_handle (handle, WAPI_HANDLE_THREAD, &shared_handle);
481
482         /* Hold a reference while the thread is active, because we use
483          * the handle to store thread exit information
484          */
485         _wapi_handle_ref (handle);
486         
487         g_hash_table_insert (thread_hash, GUINT_TO_POINTER (thread_handle.thread->id), handle);
488
489 #ifdef DEBUG
490         g_message("%s: Attached thread handle %p thread %p ID %ld", __func__,
491                   handle, thread_handle.thread, thread_handle.thread->id);
492 #endif
493
494         if (tid != NULL) {
495 #ifdef PTHREAD_POINTER_ID
496                 *tid = GPOINTER_TO_UINT(thread_handle.thread->id);
497 #else
498                 *tid = thread_handle.thread->id;
499 #endif
500         }
501
502 thread_hash_cleanup:
503         thr_ret = mono_mutex_unlock (&thread_hash_mutex);
504         g_assert (thr_ret == 0);
505         pthread_cleanup_pop (0);
506         
507         return(ta_ret);
508 }
509
510 /**
511  * GetCurrentThread:
512  *
513  * Looks up the handle associated with the current thread.  Under
514  * Windows this is a pseudohandle, and must be duplicated with
515  * DuplicateHandle() for some operations.
516  *
517  * Return value: The current thread handle, or %NULL on failure.
518  * (Unknown whether Windows has a possible failure here.  It may be
519  * necessary to implement the pseudohandle-constant behaviour).
520  */
521 gpointer GetCurrentThread(void)
522 {
523         gpointer ret=NULL;
524         guint32 tid;
525         int thr_ret;
526         
527         mono_once(&thread_hash_once, thread_hash_init);
528         mono_once (&thread_ops_once, thread_ops_init);
529         
530         tid=GetCurrentThreadId();
531         
532         pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
533                               (void *)&thread_hash_mutex);
534         thr_ret = mono_mutex_lock(&thread_hash_mutex);
535         g_assert (thr_ret == 0);
536
537         ret = g_hash_table_lookup (thread_hash, GUINT_TO_POINTER (tid));
538
539         thr_ret = mono_mutex_unlock(&thread_hash_mutex);
540         g_assert (thr_ret == 0);
541         pthread_cleanup_pop (0);
542         
543         if (!ret) {
544                 ret = thread_attach (NULL);
545         }
546
547         return(ret);
548 }
549
550 /**
551  * ResumeThread:
552  * @handle: the thread handle to resume
553  *
554  * Decrements the suspend count of thread @handle. A thread can only
555  * run if its suspend count is zero.
556  *
557  * Return value: the previous suspend count, or 0xFFFFFFFF on error.
558  */
559 guint32 ResumeThread(gpointer handle)
560 {
561         if (WAPI_SHARED_HANDLE_TYPED_DATA(handle, thread).thread == NULL) {
562                 return(0xFFFFFFFF);
563         }
564
565 #ifdef WITH_INCLUDED_LIBGC
566         if (WAPI_SHARED_HANDLE_DATA(handle, thread).thread->suspend_count <= 1)
567                 _wapi_timed_thread_resume (WAPI_SHARED_HANDLE_TYPED_DATA(handle, thread).thread);
568         
569         return (--(WAPI_SHARED_HANDLE_TYPED_DATA(handle, thread).thread->suspend_count));
570 #else
571         /* This is still a kludge that only copes with starting a
572          * thread that was suspended on create, so don't bother with
573          * the suspend count crap yet
574          */
575         _wapi_timed_thread_resume (WAPI_SHARED_HANDLE_TYPED_DATA(handle, thread).thread);
576         return(0xFFFFFFFF);
577 #endif
578 }
579
580 /**
581  * SuspendThread:
582  * @handle: the thread handle to suspend
583  *
584  * Increments the suspend count of thread @handle. A thread can only
585  * run if its suspend count is zero.
586  *
587  * Return value: the previous suspend count, or 0xFFFFFFFF on error.
588  */
589 guint32 SuspendThread(gpointer handle)
590 {
591 #ifdef WITH_INCLUDED_LIBGC
592         gpointer current;
593
594         current = GetCurrentThread ();
595
596         if (WAPI_SHARED_HANDLE_DATA(handle, thread).thread == NULL) {
597                 return(0xFFFFFFFF);
598         }
599
600         if (!WAPI_SHARED_HANDLE_DATA(handle, thread).thread->suspend_count) {
601                 if (handle == current)
602                         _wapi_timed_thread_suspend (WAPI_SHARED_HANDLE_DATA(handle, thread).thread);
603                 else {
604                         pthread_kill (WAPI_SHARED_HANDLE_DATA(handle, thread).thread->id, SIGPWR);
605                         while (MONO_SEM_WAIT (&WAPI_SHARED_HANDLE_DATA(handle, thread).thread->suspended_sem) != 0) {
606                                 if (errno != EINTR) {
607                                         return(0xFFFFFFFF);
608                                 }
609                         }
610                 }
611         }
612
613         return (WAPI_SHARED_HANDLE_DATA(handle, thread).thread->suspend_count++);
614 #else
615         return(0xFFFFFFFF);
616 #endif
617 }
618
619 /*
620  * We assume here that TLS_MINIMUM_AVAILABLE is less than
621  * PTHREAD_KEYS_MAX, allowing enough overhead for a few TLS keys for
622  * library usage.
623  *
624  * Currently TLS_MINIMUM_AVAILABLE is 64 and _POSIX_THREAD_KEYS_MAX
625  * (the minimum value for PTHREAD_KEYS_MAX) is 128, so we should be
626  * fine.
627  */
628
629 static pthread_key_t TLS_keys[TLS_MINIMUM_AVAILABLE];
630 static gboolean TLS_used[TLS_MINIMUM_AVAILABLE]={FALSE};
631 static guint32 TLS_spinlock=0;
632
633 guint32
634 mono_pthread_key_for_tls (guint32 idx)
635 {
636         return (guint32)TLS_keys [idx];
637 }
638
639 /**
640  * TlsAlloc:
641  *
642  * Allocates a Thread Local Storage (TLS) index.  Any thread in the
643  * same process can use this index to store and retrieve values that
644  * are local to that thread.
645  *
646  * Return value: The index value, or %TLS_OUT_OF_INDEXES if no index
647  * is available.
648  */
649 guint32 TlsAlloc(void)
650 {
651         guint32 i;
652         int thr_ret;
653         
654         MONO_SPIN_LOCK (TLS_spinlock);
655         
656         for(i=0; i<TLS_MINIMUM_AVAILABLE; i++) {
657                 if(TLS_used[i]==FALSE) {
658                         TLS_used[i]=TRUE;
659                         thr_ret = pthread_key_create(&TLS_keys[i], NULL);
660                         g_assert (thr_ret == 0);
661
662                         MONO_SPIN_UNLOCK (TLS_spinlock);
663         
664 #ifdef TLS_DEBUG
665                         g_message ("%s: returning key %d", __func__, i);
666 #endif
667                         
668                         return(i);
669                 }
670         }
671
672         MONO_SPIN_UNLOCK (TLS_spinlock);
673         
674 #ifdef TLS_DEBUG
675         g_message ("%s: out of indices", __func__);
676 #endif
677                         
678         
679         return(TLS_OUT_OF_INDEXES);
680 }
681
682 #define MAKE_GC_ID(idx) (GUINT_TO_POINTER((idx)|(GetCurrentThreadId()<<8)))
683
684 /**
685  * TlsFree:
686  * @idx: The TLS index to free
687  *
688  * Releases a TLS index, making it available for reuse.  This call
689  * will delete any TLS data stored under index @idx in all threads.
690  *
691  * Return value: %TRUE on success, %FALSE otherwise.
692  */
693 gboolean TlsFree(guint32 idx)
694 {
695         int thr_ret;
696         
697 #ifdef TLS_DEBUG
698         g_message ("%s: freeing key %d", __func__, idx);
699 #endif
700
701         MONO_SPIN_LOCK (TLS_spinlock);
702         
703         if(TLS_used[idx]==FALSE) {
704                 MONO_SPIN_UNLOCK (TLS_spinlock);
705
706                 return(FALSE);
707         }
708         
709         TLS_used[idx]=FALSE;
710         thr_ret = pthread_key_delete(TLS_keys[idx]);
711         g_assert (thr_ret == 0);
712         
713         MONO_SPIN_UNLOCK (TLS_spinlock);
714         
715         return(TRUE);
716 }
717
718 /**
719  * TlsGetValue:
720  * @idx: The TLS index to retrieve
721  *
722  * Retrieves the TLS data stored under index @idx.
723  *
724  * Return value: The value stored in the TLS index @idx in the current
725  * thread, or %NULL on error.  As %NULL can be a valid return value,
726  * in this case GetLastError() returns %ERROR_SUCCESS.
727  */
728 gpointer TlsGetValue(guint32 idx)
729 {
730         gpointer ret;
731         
732 #ifdef TLS_DEBUG
733         g_message ("%s: looking up key %d", __func__, idx);
734 #endif
735         
736         ret=pthread_getspecific(TLS_keys[idx]);
737
738 #ifdef TLS_DEBUG
739         g_message ("%s: returning %p", __func__, ret);
740 #endif
741         
742         return(ret);
743 }
744
745 /**
746  * TlsSetValue:
747  * @idx: The TLS index to store
748  * @value: The value to store under index @idx
749  *
750  * Stores @value at TLS index @idx.
751  *
752  * Return value: %TRUE on success, %FALSE otherwise.
753  */
754 gboolean TlsSetValue(guint32 idx, gpointer value)
755 {
756         int ret;
757
758 #ifdef TLS_DEBUG
759         g_message ("%s: setting key %d to %p", __func__, idx, value);
760 #endif
761         
762         MONO_SPIN_LOCK (TLS_spinlock);
763         
764         if(TLS_used[idx]==FALSE) {
765 #ifdef TLS_DEBUG
766                 g_message ("%s: key %d unused", __func__, idx);
767 #endif
768
769                 MONO_SPIN_UNLOCK (TLS_spinlock);
770
771                 return(FALSE);
772         }
773         
774         ret=pthread_setspecific(TLS_keys[idx], value);
775         if(ret!=0) {
776 #ifdef TLS_DEBUG
777                 g_message ("%s: pthread_setspecific error: %s", __func__,
778                            strerror (ret));
779 #endif
780
781                 MONO_SPIN_UNLOCK (TLS_spinlock);
782
783                 return(FALSE);
784         }
785         
786         MONO_SPIN_UNLOCK (TLS_spinlock);
787         
788         return(TRUE);
789 }
790
791 /**
792  * SleepEx:
793  * @ms: The time in milliseconds to suspend for
794  * @alertable: if TRUE, the wait can be interrupted by an APC call
795  *
796  * Suspends execution of the current thread for @ms milliseconds.  A
797  * value of zero causes the thread to relinquish its time slice.  A
798  * value of %INFINITE causes an infinite delay.
799  */
800 guint32 SleepEx(guint32 ms, gboolean alertable)
801 {
802         struct timespec req, rem;
803         int ms_quot, ms_rem;
804         int ret;
805         gpointer current_thread = NULL;
806         
807 #ifdef DEBUG
808         g_message("%s: Sleeping for %d ms", __func__, ms);
809 #endif
810
811         if (alertable) {
812                 current_thread = GetCurrentThread ();
813                 if (_wapi_thread_apc_pending (current_thread)) {
814                         _wapi_thread_dispatch_apc_queue (current_thread);
815                         return WAIT_IO_COMPLETION;
816                 }
817         }
818         
819         if(ms==0) {
820                 sched_yield();
821                 return 0;
822         }
823         
824         /* FIXME: check for INFINITE and sleep forever */
825         ms_quot = ms / 1000;
826         ms_rem = ms % 1000;
827         
828         req.tv_sec=ms_quot;
829         req.tv_nsec=ms_rem*1000000;
830         
831 again:
832         ret=nanosleep(&req, &rem);
833
834         if (alertable && _wapi_thread_apc_pending (current_thread)) {
835                 _wapi_thread_dispatch_apc_queue (current_thread);
836                 return WAIT_IO_COMPLETION;
837         }
838         
839         if(ret==-1) {
840                 /* Sleep interrupted with rem time remaining */
841 #ifdef DEBUG
842                 guint32 rems=rem.tv_sec*1000 + rem.tv_nsec/1000000;
843                 
844                 g_message("%s: Still got %d ms to go", __func__, rems);
845 #endif
846                 req=rem;
847                 goto again;
848         }
849
850         return 0;
851 }
852
853 void Sleep(guint32 ms)
854 {
855         SleepEx(ms, FALSE);
856 }
857
858 guint32 QueueUserAPC (WapiApcProc apc_callback, gpointer handle, 
859                                         gpointer param)
860 {
861         _wapi_timed_thread_queue_apc (WAPI_SHARED_HANDLE_TYPED_DATA(handle, thread).thread, apc_callback, param);
862         return(1);
863 }
864
865 gboolean _wapi_thread_cur_apc_pending (void)
866 {
867         return(_wapi_thread_apc_pending (GetCurrentThread ()));
868 }
869
870 gboolean _wapi_thread_apc_pending (gpointer handle)
871 {
872         return(_wapi_timed_thread_apc_pending (WAPI_SHARED_HANDLE_TYPED_DATA(handle, thread).thread));
873 }
874
875 gboolean _wapi_thread_dispatch_apc_queue (gpointer handle)
876 {
877         _wapi_timed_thread_dispatch_apc_queue (WAPI_SHARED_HANDLE_TYPED_DATA(handle, thread).thread);
878         return(1);
879 }
880
881
882
883 #ifdef WITH_INCLUDED_LIBGC
884
885 static void GC_suspend_handler (int sig)
886 {
887         gpointer handle;
888
889         handle = GetCurrentThread ();
890
891         WAPI_SHARED_HANDLE_DATA(handle, thread).thread->stack_ptr = &ok;
892         MONO_SEM_POST (&WAPI_SHARED_HANDLE_DATA(handle, thread).thread->suspended_sem);
893
894         _wapi_timed_thread_suspend (WAPI_SHARED_HANDLE_DATA(handle, thread).thread);
895
896         WAPI_SHARED_HANDLE_DATA(handle, thread).thread->stack_ptr = NULL;
897 }
898
899 static void gc_init (void)
900 {
901         struct sigaction act;
902
903         act.sa_handler = GC_suspend_handler;
904         g_assert (sigaction (SIGPWR, &act, NULL) == 0);
905 }
906
907 void mono_wapi_push_thread_stack (gpointer handle, gpointer stack_ptr)
908 {
909         GC_push_all_stack (WAPI_SHARED_HANDLE_DATA(handle, thread).thread->stack_ptr, stack_ptr);
910 }
911
912 #endif /* WITH_INCLUDED_LIBGC */