2 * threads.c: Thread handles
5 * Dick Porter (dick@ximian.com)
7 * (C) 2002 Ximian, Inc.
19 #include <sys/types.h>
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>
32 #if HAVE_VALGRIND_MEMCHECK_H
33 #include <valgrind/memcheck.h>
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
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;
47 static gboolean thread_own (gpointer handle);
49 struct _WapiHandleOps _wapi_thread_ops = {
50 NULL, /* close_shared */
56 static mono_once_t thread_ops_once=MONO_ONCE_INIT;
58 #ifdef WITH_INCLUDED_LIBGC
59 static void gc_init (void);
62 static void thread_ops_init (void)
64 _wapi_handle_register_capabilities (WAPI_HANDLE_THREAD,
65 WAPI_HANDLE_CAP_WAIT);
67 #ifdef WITH_INCLUDED_LIBGC
72 static gboolean thread_own (gpointer handle)
74 struct _WapiHandleShared shared_handle;
75 struct _WapiHandle_thread *thread_handle;
79 g_message ("%s: owning thread handle %p", __func__, handle);
82 ok = _wapi_copy_handle (handle, WAPI_HANDLE_THREAD,
85 g_warning ("%s: error copying thread handle %p", __func__,
89 thread_handle = &shared_handle.u.thread;
91 if (thread_handle->owner_pid != getpid()) {
93 g_message ("%s: can't join thread, %d not owner process %d",
94 __func__, getpid(), thread_handle->owner_pid);
96 /* FIXME: might need to return TRUE here so that other
97 * processes can WaitFor thread handles
102 if (thread_handle->joined == FALSE) {
103 _wapi_timed_thread_join (thread_handle->thread, NULL, NULL);
104 thread_handle->joined = TRUE;
106 _wapi_replace_handle (handle, WAPI_HANDLE_THREAD,
113 static void thread_exit(guint32 exitstatus, gpointer handle)
115 struct _WapiHandleShared shared_handle;
116 struct _WapiHandle_thread *thread_handle;
120 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
122 thr_ret = _wapi_handle_lock_handle (handle);
123 g_assert (thr_ret == 0);
125 ok = _wapi_copy_handle (handle, WAPI_HANDLE_THREAD,
128 g_warning ("%s: error copying thread handle %p", __func__,
132 thread_handle = &shared_handle.u.thread;
134 _wapi_mutex_check_abandoned (getpid (), thread_handle->thread->id);
137 g_message ("%s: Recording thread handle %p exit status", __func__,
141 thread_handle->exitstatus = exitstatus;
142 thread_handle->state = THREAD_STATE_EXITED;
144 _wapi_replace_handle (handle, WAPI_HANDLE_THREAD, &shared_handle);
146 _wapi_shared_handle_set_signal_state (handle, TRUE);
148 thr_ret = _wapi_handle_unlock_handle (handle);
149 g_assert (thr_ret == 0);
150 pthread_cleanup_pop (0);
153 g_message("%s: Recording thread handle %p id %ld status as %d",
154 __func__, handle, thread_handle->thread->id, exitstatus);
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);
163 g_hash_table_remove (thread_hash, GUINT_TO_POINTER (thread_handle->thread->id));
165 thr_ret = mono_mutex_unlock(&thread_hash_mutex);
166 g_assert (thr_ret == 0);
167 pthread_cleanup_pop (0);
169 /* The thread is no longer active, so unref it */
170 _wapi_handle_unref (handle);
173 static void thread_hash_init(void)
175 thread_hash = g_hash_table_new (NULL, NULL);
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.
190 * Creates a new threading handle.
192 * Return value: a new handle, or NULL
194 gpointer CreateThread(WapiSecurityAttributes *security G_GNUC_UNUSED, guint32 stacksize,
195 WapiThreadStart start, gpointer param, guint32 create,
198 struct _WapiHandleShared shared_handle;
199 struct _WapiHandle_thread thread_handle = {0};
205 gpointer ct_ret = NULL;
207 mono_once (&thread_hash_once, thread_hash_init);
208 mono_once (&thread_ops_once, thread_ops_init);
214 thread_handle.state = THREAD_STATE_START;
215 thread_handle.owner_pid = getpid();
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.)
222 thr_ret = pthread_attr_init(&attr);
223 g_assert (thr_ret == 0);
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
231 #if HAVE_VALGRIND_MEMCHECK_H
232 if (RUNNING_ON_VALGRIND) {
235 stacksize = (SIZEOF_VOID_P / 4) * 1024 * 1024;
238 stacksize = (SIZEOF_VOID_P / 4) * 1024 * 1024;
243 #ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE
244 thr_ret = pthread_attr_setstacksize(&attr, stacksize);
245 g_assert (thr_ret == 0);
248 /* Lock around the thread create, so that the new thread cant
249 * race us to look up the thread handle in GetCurrentThread()
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);
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;
263 ret = _wapi_timed_thread_create (&thread_handle.thread, &attr,
264 create, start, thread_exit, param,
268 g_message ("%s: Thread create error: %s", __func__,
271 _wapi_handle_unref (handle);
272 goto thread_hash_cleanup;
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
279 ok = _wapi_copy_handle (handle, WAPI_HANDLE_THREAD, &shared_handle);
281 g_warning ("%s: error copying thread handle %p", __func__,
283 _wapi_handle_unref (handle);
284 goto thread_hash_cleanup;
286 shared_handle.u.thread.thread = thread_handle.thread;
287 _wapi_replace_handle (handle, WAPI_HANDLE_THREAD, &shared_handle);
289 /* Hold a reference while the thread is active, because we use
290 * the handle to store thread exit information
292 _wapi_handle_ref (handle);
294 g_hash_table_insert (thread_hash, GUINT_TO_POINTER (thread_handle.thread->id), handle);
297 g_message("%s: Started thread handle %p thread %p ID %ld", __func__,
298 handle, thread_handle.thread, thread_handle.thread->id);
302 #ifdef PTHREAD_POINTER_ID
303 *tid = GPOINTER_TO_UINT (thread_handle.thread->id);
305 *tid = thread_handle.thread->id;
310 thr_ret = mono_mutex_unlock (&thread_hash_mutex);
311 g_assert (thr_ret == 0);
312 pthread_cleanup_pop (0);
317 gpointer OpenThread (guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, guint32 tid)
322 mono_once(&thread_hash_once, thread_hash_init);
323 mono_once (&thread_ops_once, thread_ops_init);
326 g_message ("%s: looking up thread %d", __func__, tid);
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);
334 ret = g_hash_table_lookup (thread_hash, GUINT_TO_POINTER (tid));
336 thr_ret = mono_mutex_unlock(&thread_hash_mutex);
337 g_assert (thr_ret == 0);
338 pthread_cleanup_pop (0);
341 _wapi_handle_ref (ret);
345 g_message ("%s: returning thread handle %p", __func__, ret);
353 * @exitcode: Sets the thread's exit code, which can be read from
354 * another thread with GetExitCodeThread().
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.
360 void ExitThread(guint32 exitcode)
362 _wapi_timed_thread_exit(exitcode);
367 * @handle: The thread handle to query
368 * @exitcode: The thread @handle exit code is stored here
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.
373 * Return value: %TRUE, or %FALSE on error.
375 gboolean GetExitCodeThread(gpointer handle, guint32 *exitcode)
378 g_message ("%s: Finding exit status for thread handle %p id %ld",
380 WAPI_SHARED_HANDLE_TYPED_DATA(handle, thread).thread->id);
383 if (exitcode == NULL) {
385 g_message ("%s: Nowhere to store exit code", __func__);
390 if (WAPI_SHARED_HANDLE_TYPED_DATA(handle, thread).state != THREAD_STATE_EXITED) {
392 g_message ("%s: Thread still active (state %d, exited is %d)",
394 WAPI_SHARED_HANDLE_TYPED_DATA(handle, thread).state,
395 THREAD_STATE_EXITED);
397 *exitcode = STILL_ACTIVE;
401 *exitcode = WAPI_SHARED_HANDLE_TYPED_DATA(handle, thread).exitstatus;
407 * GetCurrentThreadId:
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.
412 * Return value: the thread ID.
414 guint32 GetCurrentThreadId(void)
416 pthread_t tid = pthread_self();
418 #ifdef PTHREAD_POINTER_ID
419 return(GPOINTER_TO_UINT(tid));
425 static gpointer thread_attach(guint32 *tid)
427 struct _WapiHandleShared shared_handle;
428 struct _WapiHandle_thread thread_handle = {0};
433 gpointer ta_ret = NULL;
435 mono_once (&thread_hash_once, thread_hash_init);
436 mono_once (&thread_ops_once, thread_ops_init);
438 thread_handle.state = THREAD_STATE_START;
439 thread_handle.owner_pid = getpid();
441 /* Lock around the thread create, so that the new thread cant
442 * race us to look up the thread handle in GetCurrentThread()
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);
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;
456 ret = _wapi_timed_thread_attach (&thread_handle.thread, thread_exit,
460 g_message ("%s: Thread attach error: %s", __func__,
464 _wapi_handle_unref (handle);
465 goto thread_hash_cleanup;
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
472 ok = _wapi_copy_handle (handle, WAPI_HANDLE_THREAD, &shared_handle);
474 g_warning ("%s: error copying thread handle %p", __func__,
476 _wapi_handle_unref (handle);
477 goto thread_hash_cleanup;
479 shared_handle.u.thread.thread = thread_handle.thread;
480 _wapi_replace_handle (handle, WAPI_HANDLE_THREAD, &shared_handle);
482 /* Hold a reference while the thread is active, because we use
483 * the handle to store thread exit information
485 _wapi_handle_ref (handle);
487 g_hash_table_insert (thread_hash, GUINT_TO_POINTER (thread_handle.thread->id), handle);
490 g_message("%s: Attached thread handle %p thread %p ID %ld", __func__,
491 handle, thread_handle.thread, thread_handle.thread->id);
495 #ifdef PTHREAD_POINTER_ID
496 *tid = GPOINTER_TO_UINT(thread_handle.thread->id);
498 *tid = thread_handle.thread->id;
503 thr_ret = mono_mutex_unlock (&thread_hash_mutex);
504 g_assert (thr_ret == 0);
505 pthread_cleanup_pop (0);
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.
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).
521 gpointer GetCurrentThread(void)
527 mono_once(&thread_hash_once, thread_hash_init);
528 mono_once (&thread_ops_once, thread_ops_init);
530 tid=GetCurrentThreadId();
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);
537 ret = g_hash_table_lookup (thread_hash, GUINT_TO_POINTER (tid));
539 thr_ret = mono_mutex_unlock(&thread_hash_mutex);
540 g_assert (thr_ret == 0);
541 pthread_cleanup_pop (0);
544 ret = thread_attach (NULL);
552 * @handle: the thread handle to resume
554 * Decrements the suspend count of thread @handle. A thread can only
555 * run if its suspend count is zero.
557 * Return value: the previous suspend count, or 0xFFFFFFFF on error.
559 guint32 ResumeThread(gpointer handle)
561 if (WAPI_SHARED_HANDLE_TYPED_DATA(handle, thread).thread == NULL) {
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);
569 return (--(WAPI_SHARED_HANDLE_TYPED_DATA(handle, thread).thread->suspend_count));
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
575 _wapi_timed_thread_resume (WAPI_SHARED_HANDLE_TYPED_DATA(handle, thread).thread);
582 * @handle: the thread handle to suspend
584 * Increments the suspend count of thread @handle. A thread can only
585 * run if its suspend count is zero.
587 * Return value: the previous suspend count, or 0xFFFFFFFF on error.
589 guint32 SuspendThread(gpointer handle)
591 #ifdef WITH_INCLUDED_LIBGC
594 current = GetCurrentThread ();
596 if (WAPI_SHARED_HANDLE_DATA(handle, thread).thread == NULL) {
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);
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) {
613 return (WAPI_SHARED_HANDLE_DATA(handle, thread).thread->suspend_count++);
620 * We assume here that TLS_MINIMUM_AVAILABLE is less than
621 * PTHREAD_KEYS_MAX, allowing enough overhead for a few TLS keys for
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
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;
634 mono_pthread_key_for_tls (guint32 idx)
636 return (guint32)TLS_keys [idx];
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.
646 * Return value: The index value, or %TLS_OUT_OF_INDEXES if no index
649 guint32 TlsAlloc(void)
654 MONO_SPIN_LOCK (TLS_spinlock);
656 for(i=0; i<TLS_MINIMUM_AVAILABLE; i++) {
657 if(TLS_used[i]==FALSE) {
659 thr_ret = pthread_key_create(&TLS_keys[i], NULL);
660 g_assert (thr_ret == 0);
662 MONO_SPIN_UNLOCK (TLS_spinlock);
665 g_message ("%s: returning key %d", __func__, i);
672 MONO_SPIN_UNLOCK (TLS_spinlock);
675 g_message ("%s: out of indices", __func__);
679 return(TLS_OUT_OF_INDEXES);
682 #define MAKE_GC_ID(idx) (GUINT_TO_POINTER((idx)|(GetCurrentThreadId()<<8)))
686 * @idx: The TLS index to free
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.
691 * Return value: %TRUE on success, %FALSE otherwise.
693 gboolean TlsFree(guint32 idx)
698 g_message ("%s: freeing key %d", __func__, idx);
701 MONO_SPIN_LOCK (TLS_spinlock);
703 if(TLS_used[idx]==FALSE) {
704 MONO_SPIN_UNLOCK (TLS_spinlock);
710 thr_ret = pthread_key_delete(TLS_keys[idx]);
711 g_assert (thr_ret == 0);
713 MONO_SPIN_UNLOCK (TLS_spinlock);
720 * @idx: The TLS index to retrieve
722 * Retrieves the TLS data stored under index @idx.
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.
728 gpointer TlsGetValue(guint32 idx)
733 g_message ("%s: looking up key %d", __func__, idx);
736 ret=pthread_getspecific(TLS_keys[idx]);
739 g_message ("%s: returning %p", __func__, ret);
747 * @idx: The TLS index to store
748 * @value: The value to store under index @idx
750 * Stores @value at TLS index @idx.
752 * Return value: %TRUE on success, %FALSE otherwise.
754 gboolean TlsSetValue(guint32 idx, gpointer value)
759 g_message ("%s: setting key %d to %p", __func__, idx, value);
762 MONO_SPIN_LOCK (TLS_spinlock);
764 if(TLS_used[idx]==FALSE) {
766 g_message ("%s: key %d unused", __func__, idx);
769 MONO_SPIN_UNLOCK (TLS_spinlock);
774 ret=pthread_setspecific(TLS_keys[idx], value);
777 g_message ("%s: pthread_setspecific error: %s", __func__,
781 MONO_SPIN_UNLOCK (TLS_spinlock);
786 MONO_SPIN_UNLOCK (TLS_spinlock);
793 * @ms: The time in milliseconds to suspend for
794 * @alertable: if TRUE, the wait can be interrupted by an APC call
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.
800 guint32 SleepEx(guint32 ms, gboolean alertable)
802 struct timespec req, rem;
805 gpointer current_thread = NULL;
808 g_message("%s: Sleeping for %d ms", __func__, ms);
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;
824 /* FIXME: check for INFINITE and sleep forever */
829 req.tv_nsec=ms_rem*1000000;
832 ret=nanosleep(&req, &rem);
834 if (alertable && _wapi_thread_apc_pending (current_thread)) {
835 _wapi_thread_dispatch_apc_queue (current_thread);
836 return WAIT_IO_COMPLETION;
840 /* Sleep interrupted with rem time remaining */
842 guint32 rems=rem.tv_sec*1000 + rem.tv_nsec/1000000;
844 g_message("%s: Still got %d ms to go", __func__, rems);
853 void Sleep(guint32 ms)
858 guint32 QueueUserAPC (WapiApcProc apc_callback, gpointer handle,
861 _wapi_timed_thread_queue_apc (WAPI_SHARED_HANDLE_TYPED_DATA(handle, thread).thread, apc_callback, param);
865 gboolean _wapi_thread_cur_apc_pending (void)
867 return(_wapi_thread_apc_pending (GetCurrentThread ()));
870 gboolean _wapi_thread_apc_pending (gpointer handle)
872 return(_wapi_timed_thread_apc_pending (WAPI_SHARED_HANDLE_TYPED_DATA(handle, thread).thread));
875 gboolean _wapi_thread_dispatch_apc_queue (gpointer handle)
877 _wapi_timed_thread_dispatch_apc_queue (WAPI_SHARED_HANDLE_TYPED_DATA(handle, thread).thread);
883 #ifdef WITH_INCLUDED_LIBGC
885 static void GC_suspend_handler (int sig)
889 handle = GetCurrentThread ();
891 WAPI_SHARED_HANDLE_DATA(handle, thread).thread->stack_ptr = &ok;
892 MONO_SEM_POST (&WAPI_SHARED_HANDLE_DATA(handle, thread).thread->suspended_sem);
894 _wapi_timed_thread_suspend (WAPI_SHARED_HANDLE_DATA(handle, thread).thread);
896 WAPI_SHARED_HANDLE_DATA(handle, thread).thread->stack_ptr = NULL;
899 static void gc_init (void)
901 struct sigaction act;
903 act.sa_handler = GC_suspend_handler;
904 g_assert (sigaction (SIGPWR, &act, NULL) == 0);
907 void mono_wapi_push_thread_stack (gpointer handle, gpointer stack_ptr)
909 GC_push_all_stack (WAPI_SHARED_HANDLE_DATA(handle, thread).thread->stack_ptr, stack_ptr);
912 #endif /* WITH_INCLUDED_LIBGC */