2 * threads.c: Thread support internal calls
5 * Dick Porter (dick@ximian.com)
6 * Paolo Molaro (lupus@ximian.com)
7 * Patrik Torstensson (patrik.torstensson@labs2.com)
9 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
19 #include <mono/metadata/object.h>
20 #include <mono/metadata/domain-internals.h>
21 #include <mono/metadata/profiler-private.h>
22 #include <mono/metadata/threads.h>
23 #include <mono/metadata/threadpool.h>
24 #include <mono/metadata/threads-types.h>
25 #include <mono/metadata/exception.h>
26 #include <mono/metadata/environment.h>
27 #include <mono/metadata/monitor.h>
28 #include <mono/metadata/gc-internal.h>
29 #include <mono/metadata/marshal.h>
30 #include <mono/metadata/runtime.h>
31 #include <mono/io-layer/io-layer.h>
32 #include <mono/metadata/object-internals.h>
33 #include <mono/metadata/mono-debug-debugger.h>
34 #include <mono/utils/mono-compiler.h>
35 #include <mono/utils/mono-mmap.h>
36 #include <mono/utils/mono-membar.h>
37 #include <mono/utils/mono-time.h>
38 #include <mono/utils/mono-threads.h>
39 #include <mono/utils/hazard-pointer.h>
40 #include <mono/utils/mono-tls.h>
41 #include <mono/utils/atomic.h>
42 #include <mono/utils/mono-memory-model.h>
44 #include <mono/metadata/gc-internal.h>
50 #if defined(PLATFORM_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64)
51 #define USE_TKILL_ON_ANDROID 1
54 #ifdef PLATFORM_ANDROID
57 #ifdef USE_TKILL_ON_ANDROID
58 extern int tkill (pid_t tid
, int signal
);
62 /*#define THREAD_DEBUG(a) do { a; } while (0)*/
63 #define THREAD_DEBUG(a)
64 /*#define THREAD_WAIT_DEBUG(a) do { a; } while (0)*/
65 #define THREAD_WAIT_DEBUG(a)
66 /*#define LIBGC_DEBUG(a) do { a; } while (0)*/
67 #define LIBGC_DEBUG(a)
69 #define SPIN_TRYLOCK(i) (InterlockedCompareExchange (&(i), 1, 0) == 0)
70 #define SPIN_LOCK(i) do { \
71 if (SPIN_TRYLOCK (i)) \
75 #define SPIN_UNLOCK(i) i = 0
77 #define LOCK_THREAD(thread) lock_thread((thread))
78 #define UNLOCK_THREAD(thread) unlock_thread((thread))
80 /* Provide this for systems with glib < 2.6 */
81 #ifndef G_GSIZE_FORMAT
82 # if GLIB_SIZEOF_LONG == 8
83 # define G_GSIZE_FORMAT "lu"
85 # define G_GSIZE_FORMAT "u"
91 guint32 (*func
)(void *);
107 typedef struct _MonoThreadDomainTls MonoThreadDomainTls
;
108 struct _MonoThreadDomainTls
{
109 MonoThreadDomainTls
*next
;
117 MonoThreadDomainTls
*freelist
;
120 /* Number of cached culture objects in the MonoThread->cached_culture_info array
121 * (per-type): we use the first NUM entries for CultureInfo and the last for
122 * UICultureInfo. So the size of the array is really NUM_CACHED_CULTURES * 2.
124 #define NUM_CACHED_CULTURES 4
125 #define CULTURES_START_IDX 0
126 #define UICULTURES_START_IDX NUM_CACHED_CULTURES
128 /* Controls access to the 'threads' hash table */
129 static void mono_threads_lock (void);
130 static void mono_threads_unlock (void);
131 static mono_mutex_t threads_mutex
;
133 /* Controls access to context static data */
134 #define mono_contexts_lock() mono_mutex_lock (&contexts_mutex)
135 #define mono_contexts_unlock() mono_mutex_unlock (&contexts_mutex)
136 static mono_mutex_t contexts_mutex
;
138 /* Controls access to the 'joinable_threads' hash table */
139 #define joinable_threads_lock() mono_mutex_lock (&joinable_threads_mutex)
140 #define joinable_threads_unlock() mono_mutex_unlock (&joinable_threads_mutex)
141 static mono_mutex_t joinable_threads_mutex
;
143 /* Holds current status of static data heap */
144 static StaticDataInfo thread_static_info
;
145 static StaticDataInfo context_static_info
;
147 /* The hash of existing threads (key is thread ID, value is
148 * MonoInternalThread*) that need joining before exit
150 static MonoGHashTable
*threads
=NULL
;
153 * Threads which are starting up and they are not in the 'threads' hash yet.
154 * When handle_store is called for a thread, it will be removed from this hash table.
155 * Protected by mono_threads_lock ().
157 static MonoGHashTable
*threads_starting_up
= NULL
;
159 /* Maps a MonoThread to its start argument */
160 /* Protected by mono_threads_lock () */
161 static MonoGHashTable
*thread_start_args
= NULL
;
163 /* The TLS key that holds the MonoObject assigned to each thread */
164 static MonoNativeTlsKey current_object_key
;
167 /* Protected by the threads lock */
168 static GHashTable
*joinable_threads
;
169 static int joinable_thread_count
;
171 #ifdef MONO_HAVE_FAST_TLS
172 /* we need to use both the Tls* functions and __thread because
173 * the gc needs to see all the threads
175 MONO_FAST_TLS_DECLARE(tls_current_object
);
176 #define SET_CURRENT_OBJECT(x) do { \
177 MONO_FAST_TLS_SET (tls_current_object, x); \
178 mono_native_tls_set_value (current_object_key, x); \
180 #define GET_CURRENT_OBJECT() ((MonoInternalThread*) MONO_FAST_TLS_GET (tls_current_object))
182 #define SET_CURRENT_OBJECT(x) mono_native_tls_set_value (current_object_key, x)
183 #define GET_CURRENT_OBJECT() (MonoInternalThread*) mono_native_tls_get_value (current_object_key)
186 /* function called at thread start */
187 static MonoThreadStartCB mono_thread_start_cb
= NULL
;
189 /* function called at thread attach */
190 static MonoThreadAttachCB mono_thread_attach_cb
= NULL
;
192 /* function called at thread cleanup */
193 static MonoThreadCleanupFunc mono_thread_cleanup_fn
= NULL
;
195 /* function called to notify the runtime about a pending exception on the current thread */
196 static MonoThreadNotifyPendingExcFunc mono_thread_notify_pending_exc_fn
= NULL
;
198 /* The default stack size for each thread */
199 static guint32 default_stacksize
= 0;
200 #define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize)
202 static void thread_adjust_static_data (MonoInternalThread
*thread
);
203 static void mono_free_static_data (gpointer
* static_data
, gboolean threadlocal
);
204 static void mono_init_static_data_info (StaticDataInfo
*static_data
);
205 static guint32
mono_alloc_static_data_slot (StaticDataInfo
*static_data
, guint32 size
, guint32 align
);
206 static gboolean
mono_thread_resume (MonoInternalThread
* thread
);
207 static void signal_thread_state_change (MonoInternalThread
*thread
);
208 static void abort_thread_internal (MonoInternalThread
*thread
, gboolean can_raise_exception
, gboolean install_async_abort
);
209 static void suspend_thread_internal (MonoInternalThread
*thread
, gboolean interrupt
);
210 static void self_suspend_internal (MonoInternalThread
*thread
);
211 static gboolean
resume_thread_internal (MonoInternalThread
*thread
);
213 static MonoException
* mono_thread_execute_interruption (MonoInternalThread
*thread
);
214 static void ref_stack_destroy (gpointer rs
);
216 /* Spin lock for InterlockedXXX 64 bit functions */
217 #define mono_interlocked_lock() mono_mutex_lock (&interlocked_mutex)
218 #define mono_interlocked_unlock() mono_mutex_unlock (&interlocked_mutex)
219 static mono_mutex_t interlocked_mutex
;
221 /* global count of thread interruptions requested */
222 static gint32 thread_interruption_requested
= 0;
224 /* Event signaled when a thread changes its background mode */
225 static HANDLE background_change_event
;
227 static gboolean shutting_down
= FALSE
;
229 static gint32 managed_thread_id_counter
= 0;
233 mono_threads_lock (void)
236 mono_locks_acquire (&threads_mutex
, ThreadsLock
);
237 MONO_FINISH_TRY_BLOCKING
241 mono_threads_unlock (void)
243 mono_locks_release (&threads_mutex
, ThreadsLock
);
248 get_next_managed_thread_id (void)
250 return InterlockedIncrement (&managed_thread_id_counter
);
254 mono_thread_get_tls_key (void)
256 return current_object_key
;
260 mono_thread_get_tls_offset (void)
263 MONO_THREAD_VAR_OFFSET (tls_current_object
,offset
);
267 static inline MonoNativeThreadId
268 thread_get_tid (MonoInternalThread
*thread
)
270 /* We store the tid as a guint64 to keep the object layout constant between platforms */
271 return MONO_UINT_TO_NATIVE_THREAD_ID (thread
->tid
);
274 /* handle_store() and handle_remove() manage the array of threads that
275 * still need to be waited for when the main thread exits.
277 * If handle_store() returns FALSE the thread must not be started
278 * because Mono is shutting down.
280 static gboolean
handle_store(MonoThread
*thread
, gboolean force_attach
)
282 mono_threads_lock ();
284 THREAD_DEBUG (g_message ("%s: thread %p ID %"G_GSIZE_FORMAT
, __func__
, thread
, (gsize
)thread
->internal_thread
->tid
));
286 if (threads_starting_up
)
287 mono_g_hash_table_remove (threads_starting_up
, thread
);
289 if (shutting_down
&& !force_attach
) {
290 mono_threads_unlock ();
295 MONO_GC_REGISTER_ROOT_FIXED (threads
);
296 threads
=mono_g_hash_table_new_type (NULL
, NULL
, MONO_HASH_VALUE_GC
);
299 /* We don't need to duplicate thread->handle, because it is
300 * only closed when the thread object is finalized by the GC.
302 g_assert (thread
->internal_thread
);
303 mono_g_hash_table_insert(threads
, (gpointer
)(gsize
)(thread
->internal_thread
->tid
),
304 thread
->internal_thread
);
306 mono_threads_unlock ();
311 static gboolean
handle_remove(MonoInternalThread
*thread
)
314 gsize tid
= thread
->tid
;
316 THREAD_DEBUG (g_message ("%s: thread ID %"G_GSIZE_FORMAT
, __func__
, tid
));
318 mono_threads_lock ();
321 /* We have to check whether the thread object for the
322 * tid is still the same in the table because the
323 * thread might have been destroyed and the tid reused
324 * in the meantime, in which case the tid would be in
325 * the table, but with another thread object.
327 if (mono_g_hash_table_lookup (threads
, (gpointer
)tid
) == thread
) {
328 mono_g_hash_table_remove (threads
, (gpointer
)tid
);
337 mono_threads_unlock ();
339 /* Don't close the handle here, wait for the object finalizer
340 * to do it. Otherwise, the following race condition applies:
342 * 1) Thread exits (and handle_remove() closes the handle)
344 * 2) Some other handle is reassigned the same slot
346 * 3) Another thread tries to join the first thread, and
347 * blocks waiting for the reassigned handle to be signalled
348 * (which might never happen). This is possible, because the
349 * thread calling Join() still has a reference to the first
355 static void ensure_synch_cs_set (MonoInternalThread
*thread
)
357 mono_mutex_t
*synch_cs
;
359 if (thread
->synch_cs
!= NULL
) {
363 synch_cs
= g_new0 (mono_mutex_t
, 1);
364 mono_mutex_init_recursive (synch_cs
);
366 if (InterlockedCompareExchangePointer ((gpointer
*)&thread
->synch_cs
,
367 synch_cs
, NULL
) != NULL
) {
368 /* Another thread must have installed this CS */
369 mono_mutex_destroy (synch_cs
);
375 lock_thread (MonoInternalThread
*thread
)
377 if (!thread
->synch_cs
)
378 ensure_synch_cs_set (thread
);
380 g_assert (thread
->synch_cs
);
381 mono_mutex_lock (thread
->synch_cs
);
385 unlock_thread (MonoInternalThread
*thread
)
387 mono_mutex_unlock (thread
->synch_cs
);
391 * NOTE: this function can be called also for threads different from the current one:
392 * make sure no code called from it will ever assume it is run on the thread that is
393 * getting cleaned up.
395 static void thread_cleanup (MonoInternalThread
*thread
)
397 g_assert (thread
!= NULL
);
399 if (thread
->abort_state_handle
) {
400 mono_gchandle_free (thread
->abort_state_handle
);
401 thread
->abort_state_handle
= 0;
403 thread
->abort_exc
= NULL
;
404 thread
->current_appcontext
= NULL
;
407 * This is necessary because otherwise we might have
408 * cross-domain references which will not get cleaned up when
409 * the target domain is unloaded.
411 if (thread
->cached_culture_info
) {
413 for (i
= 0; i
< NUM_CACHED_CULTURES
* 2; ++i
)
414 mono_array_set (thread
->cached_culture_info
, MonoObject
*, i
, NULL
);
418 * thread->synch_cs can be NULL if this was called after
419 * ves_icall_System_Threading_InternalThread_Thread_free_internal.
420 * This can happen only during shutdown.
421 * The shutting_down flag is not always set, so we can't assert on it.
423 if (thread
->synch_cs
)
424 LOCK_THREAD (thread
);
426 thread
->state
|= ThreadState_Stopped
;
427 thread
->state
&= ~ThreadState_Background
;
429 if (thread
->synch_cs
)
430 UNLOCK_THREAD (thread
);
433 An interruption request has leaked to cleanup. Adjust the global counter.
435 This can happen is the abort source thread finds the abortee (this) thread
436 in unmanaged code. If this thread never trips back to managed code or check
437 the local flag it will be left set and positively unbalance the global counter.
439 Leaving the counter unbalanced will cause a performance degradation since all threads
440 will now keep checking their local flags all the time.
442 if (InterlockedExchange (&thread
->interruption_requested
, 0))
443 InterlockedDecrement (&thread_interruption_requested
);
445 /* if the thread is not in the hash it has been removed already */
446 if (!handle_remove (thread
)) {
447 if (thread
== mono_thread_internal_current ()) {
448 mono_domain_unset ();
449 mono_memory_barrier ();
451 /* This needs to be called even if handle_remove () fails */
452 if (mono_thread_cleanup_fn
)
453 mono_thread_cleanup_fn ((MonoNativeThreadId
)thread
->tid
);
456 mono_release_type_locks (thread
);
458 mono_profiler_thread_end (thread
->tid
);
460 if (thread
== mono_thread_internal_current ()) {
462 * This will signal async signal handlers that the thread has exited.
463 * The profiler callback needs this to be set, so it cannot be done earlier.
465 mono_domain_unset ();
466 mono_memory_barrier ();
469 if (thread
== mono_thread_internal_current ())
470 mono_thread_pop_appdomain_ref ();
472 thread
->cached_culture_info
= NULL
;
474 mono_free_static_data (thread
->static_data
, TRUE
);
475 thread
->static_data
= NULL
;
476 ref_stack_destroy (thread
->appdomain_refs
);
477 thread
->appdomain_refs
= NULL
;
479 if (mono_thread_cleanup_fn
)
480 mono_thread_cleanup_fn ((MonoNativeThreadId
)thread
->tid
);
482 if (mono_gc_is_moving ()) {
483 MONO_GC_UNREGISTER_ROOT (thread
->thread_pinning_ref
);
484 thread
->thread_pinning_ref
= NULL
;
489 get_thread_static_data (MonoInternalThread
*thread
, guint32 offset
)
492 g_assert ((offset
& 0x80000000) == 0);
493 offset
&= 0x7fffffff;
494 idx
= (offset
>> 24) - 1;
495 return ((char*) thread
->static_data
[idx
]) + (offset
& 0xffffff);
499 get_current_thread_ptr_for_domain (MonoDomain
*domain
, MonoInternalThread
*thread
)
501 static MonoClassField
*current_thread_field
= NULL
;
505 if (!current_thread_field
) {
506 current_thread_field
= mono_class_get_field_from_name (mono_defaults
.thread_class
, "current_thread");
507 g_assert (current_thread_field
);
510 mono_class_vtable (domain
, mono_defaults
.thread_class
);
511 mono_domain_lock (domain
);
512 offset
= GPOINTER_TO_UINT (g_hash_table_lookup (domain
->special_static_fields
, current_thread_field
));
513 mono_domain_unlock (domain
);
516 return get_thread_static_data (thread
, offset
);
520 set_current_thread_for_domain (MonoDomain
*domain
, MonoInternalThread
*thread
, MonoThread
*current
)
522 MonoThread
**current_thread_ptr
= get_current_thread_ptr_for_domain (domain
, thread
);
524 g_assert (current
->obj
.vtable
->domain
== domain
);
526 g_assert (!*current_thread_ptr
);
527 *current_thread_ptr
= current
;
531 create_thread_object (MonoDomain
*domain
)
533 MonoVTable
*vt
= mono_class_vtable (domain
, mono_defaults
.thread_class
);
534 return (MonoThread
*)mono_gc_alloc_mature (vt
);
538 new_thread_with_internal (MonoDomain
*domain
, MonoInternalThread
*internal
)
540 MonoThread
*thread
= create_thread_object (domain
);
541 MONO_OBJECT_SETREF (thread
, internal_thread
, internal
);
545 static MonoInternalThread
*
546 create_internal_thread (void)
548 MonoInternalThread
*thread
;
551 vt
= mono_class_vtable (mono_get_root_domain (), mono_defaults
.internal_thread_class
);
552 thread
= (MonoInternalThread
*)mono_gc_alloc_mature (vt
);
554 thread
->synch_cs
= g_new0 (mono_mutex_t
, 1);
555 mono_mutex_init_recursive (thread
->synch_cs
);
557 thread
->apartment_state
= ThreadApartmentState_Unknown
;
558 thread
->managed_id
= get_next_managed_thread_id ();
559 if (mono_gc_is_moving ()) {
560 thread
->thread_pinning_ref
= thread
;
561 MONO_GC_REGISTER_ROOT_PINNING (thread
->thread_pinning_ref
);
568 init_root_domain_thread (MonoInternalThread
*thread
, MonoThread
*candidate
)
570 MonoDomain
*domain
= mono_get_root_domain ();
572 if (!candidate
|| candidate
->obj
.vtable
->domain
!= domain
)
573 candidate
= new_thread_with_internal (domain
, thread
);
574 set_current_thread_for_domain (domain
, thread
, candidate
);
575 g_assert (!thread
->root_domain_thread
);
576 MONO_OBJECT_SETREF (thread
, root_domain_thread
, candidate
);
579 static guint32 WINAPI
start_wrapper_internal(void *data
)
581 MonoThreadInfo
*info
;
582 StartInfo
*start_info
= (StartInfo
*)data
;
583 guint32 (*start_func
)(void *);
587 * We don't create a local to hold start_info->obj, so hopefully it won't get pinned during a
590 MonoInternalThread
*internal
= start_info
->obj
->internal_thread
;
591 MonoObject
*start_delegate
= start_info
->delegate
;
592 MonoDomain
*domain
= start_info
->obj
->obj
.vtable
->domain
;
594 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT
") Start wrapper", __func__
, GetCurrentThreadId ()));
596 /* We can be sure start_info->obj->tid and
597 * start_info->obj->handle have been set, because the thread
598 * was created suspended, and these values were set before the
602 info
= mono_thread_info_current ();
604 internal
->thread_info
= info
;
605 internal
->small_id
= info
->small_id
;
609 SET_CURRENT_OBJECT (internal
);
611 /* Every thread references the appdomain which created it */
612 mono_thread_push_appdomain_ref (domain
);
614 if (!mono_domain_set (domain
, FALSE
)) {
615 /* No point in raising an appdomain_unloaded exception here */
616 /* FIXME: Cleanup here */
617 mono_thread_pop_appdomain_ref ();
621 start_func
= start_info
->func
;
622 start_arg
= start_info
->start_arg
;
624 /* We have to do this here because mono_thread_new_init()
625 requires that root_domain_thread is set up. */
626 thread_adjust_static_data (internal
);
627 init_root_domain_thread (internal
, start_info
->obj
);
629 /* This MUST be called before any managed code can be
630 * executed, as it calls the callback function that (for the
631 * jit) sets the lmf marker.
633 mono_thread_new_init (tid
, &tid
, start_func
);
634 internal
->stack_ptr
= &tid
;
636 LIBGC_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT
",%d) Setting thread stack to %p", __func__
, GetCurrentThreadId (), getpid (), thread
->stack_ptr
));
638 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT
") Setting current_object_key to %p", __func__
, GetCurrentThreadId (), internal
));
640 /* On 2.0 profile (and higher), set explicitly since state might have been
642 if (internal
->apartment_state
== ThreadApartmentState_Unknown
)
643 internal
->apartment_state
= ThreadApartmentState_MTA
;
645 mono_thread_init_apartment_state ();
647 if(internal
->start_notify
!=NULL
) {
648 /* Let the thread that called Start() know we're
651 ReleaseSemaphore (internal
->start_notify
, 1, NULL
);
654 mono_threads_lock ();
655 mono_g_hash_table_remove (thread_start_args
, start_info
->obj
);
656 mono_threads_unlock ();
658 mono_thread_set_execution_context (start_info
->obj
->ec_to_set
);
659 start_info
->obj
->ec_to_set
= NULL
;
662 THREAD_DEBUG (g_message ("%s: start_wrapper for %"G_GSIZE_FORMAT
, __func__
,
666 * Call this after calling start_notify, since the profiler callback might want
667 * to lock the thread, and the lock is held by thread_start () which waits for
670 mono_profiler_thread_start (tid
);
672 /* if the name was set before starting, we didn't invoke the profiler callback */
673 if (internal
->name
&& (internal
->flags
& MONO_THREAD_FLAG_NAME_SET
)) {
674 char *tname
= g_utf16_to_utf8 (internal
->name
, internal
->name_len
, NULL
, NULL
, NULL
);
675 mono_profiler_thread_name (internal
->tid
, tname
);
678 /* start_func is set only for unmanaged start functions */
680 start_func (start_arg
);
683 g_assert (start_delegate
!= NULL
);
684 args
[0] = start_arg
;
685 /* we may want to handle the exception here. See comment below on unhandled exceptions */
686 mono_runtime_delegate_invoke (start_delegate
, args
, NULL
);
689 /* If the thread calls ExitThread at all, this remaining code
690 * will not be executed, but the main thread will eventually
691 * call thread_cleanup() on this thread's behalf.
694 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT
") Start wrapper terminating", __func__
, GetCurrentThreadId ()));
696 /* Do any cleanup needed for apartment state. This
697 * cannot be done in thread_cleanup since thread_cleanup could be
698 * called for a thread other than the current thread.
699 * mono_thread_cleanup_apartment_state cleans up apartment
700 * for the current thead */
701 mono_thread_cleanup_apartment_state ();
703 thread_cleanup (internal
);
707 /* Remove the reference to the thread object in the TLS data,
708 * so the thread object can be finalized. This won't be
709 * reached if the thread threw an uncaught exception, so those
710 * thread handles will stay referenced :-( (This is due to
711 * missing support for scanning thread-specific data in the
712 * Boehm GC - the io-layer keeps a GC-visible hash of pointers
715 SET_CURRENT_OBJECT (NULL
);
720 static guint32 WINAPI
start_wrapper(void *data
)
724 /* Avoid scanning the frames above this frame during a GC */
725 mono_gc_set_stack_end ((void*)&dummy
);
727 return start_wrapper_internal (data
);
733 * Common thread creation code.
734 * LOCKING: Acquires the threads lock.
737 create_thread (MonoThread
*thread
, MonoInternalThread
*internal
, StartInfo
*start_info
, gboolean threadpool_thread
, guint32 stack_size
,
738 gboolean throw_on_failure
)
740 HANDLE thread_handle
;
741 MonoNativeThreadId tid
;
742 guint32 create_flags
;
745 * Join joinable threads to prevent running out of threads since the finalizer
746 * thread might be blocked/backlogged.
748 mono_threads_join_threads ();
750 mono_threads_lock ();
753 mono_threads_unlock ();
757 * The thread start argument may be an object reference, and there is
758 * no ref to keep it alive when the new thread is started but not yet
759 * registered with the collector. So we store it in a GC tracked hash
762 if (thread_start_args
== NULL
) {
763 MONO_GC_REGISTER_ROOT_FIXED (thread_start_args
);
764 thread_start_args
= mono_g_hash_table_new (NULL
, NULL
);
766 mono_g_hash_table_insert (thread_start_args
, thread
, start_info
->start_arg
);
767 if (threads_starting_up
== NULL
) {
768 MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up
);
769 threads_starting_up
= mono_g_hash_table_new_type (NULL
, NULL
, MONO_HASH_KEY_VALUE_GC
);
771 mono_g_hash_table_insert (threads_starting_up
, thread
, thread
);
772 mono_threads_unlock ();
774 internal
->start_notify
= CreateSemaphore (NULL
, 0, 0x7fffffff, NULL
);
775 if (!internal
->start_notify
) {
776 mono_threads_lock ();
777 mono_g_hash_table_remove (threads_starting_up
, thread
);
778 mono_threads_unlock ();
779 g_warning ("%s: CreateSemaphore error 0x%x", __func__
, GetLastError ());
785 stack_size
= default_stacksize_for_thread (internal
);
787 /* Create suspended, so we can do some housekeeping before the thread
790 create_flags
= CREATE_SUSPENDED
;
792 MONO_PREPARE_BLOCKING
793 thread_handle
= mono_threads_create_thread ((LPTHREAD_START_ROUTINE
)start_wrapper
, start_info
,
794 stack_size
, create_flags
, &tid
);
797 if (thread_handle
== NULL
) {
798 /* The thread couldn't be created, so throw an exception */
799 mono_threads_lock ();
800 mono_g_hash_table_remove (threads_starting_up
, thread
);
801 mono_threads_unlock ();
803 if (throw_on_failure
)
804 mono_raise_exception (mono_get_exception_execution_engine ("Couldn't create thread"));
806 g_warning ("%s: CreateThread error 0x%x", __func__
, GetLastError ());
809 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT
" (handle %p)", __func__
, tid
, thread_handle
));
811 internal
->handle
= thread_handle
;
812 internal
->tid
= MONO_NATIVE_THREAD_ID_TO_UINT (tid
);
814 internal
->threadpool_thread
= threadpool_thread
;
815 if (threadpool_thread
)
816 mono_thread_set_state (internal
, ThreadState_Background
);
818 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT
") Launching thread %p (%"G_GSIZE_FORMAT
")", __func__
, GetCurrentThreadId (), internal
, (gsize
)internal
->tid
));
820 /* Only store the handle when the thread is about to be
821 * launched, to avoid the main thread deadlocking while trying
822 * to clean up a thread that will never be signalled.
824 if (!handle_store (thread
, FALSE
))
827 MONO_PREPARE_BLOCKING
828 mono_thread_info_resume (tid
);
831 if (internal
->start_notify
) {
833 * Wait for the thread to set up its TLS data etc, so
834 * theres no potential race condition if someone tries
835 * to look up the data believing the thread has
838 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT
") waiting for thread %p (%"G_GSIZE_FORMAT
") to start", __func__
, GetCurrentThreadId (), internal
, (gsize
)internal
->tid
));
840 MONO_PREPARE_BLOCKING
841 WaitForSingleObjectEx (internal
->start_notify
, INFINITE
, FALSE
);
844 CloseHandle (internal
->start_notify
);
845 internal
->start_notify
= NULL
;
848 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT
") Done launching thread %p (%"G_GSIZE_FORMAT
")", __func__
, GetCurrentThreadId (), internal
, (gsize
)internal
->tid
));
853 void mono_thread_new_init (intptr_t tid
, gpointer stack_start
, gpointer func
)
855 if (mono_thread_start_cb
) {
856 mono_thread_start_cb (tid
, stack_start
, func
);
860 void mono_threads_set_default_stacksize (guint32 stacksize
)
862 default_stacksize
= stacksize
;
865 guint32
mono_threads_get_default_stacksize (void)
867 return default_stacksize
;
871 * mono_thread_create_internal:
875 mono_thread_create_internal (MonoDomain
*domain
, gpointer func
, gpointer arg
, gboolean threadpool_thread
, guint32 stack_size
)
878 MonoInternalThread
*internal
;
879 StartInfo
*start_info
;
882 thread
= create_thread_object (domain
);
883 internal
= create_internal_thread ();
884 MONO_OBJECT_SETREF (thread
, internal_thread
, internal
);
886 start_info
= g_new0 (StartInfo
, 1);
887 start_info
->func
= func
;
888 start_info
->obj
= thread
;
889 start_info
->start_arg
= arg
;
891 res
= create_thread (thread
, internal
, start_info
, threadpool_thread
, stack_size
, TRUE
);
895 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
896 if (mono_check_corlib_version () == NULL
)
897 g_assert (((char*)&internal
->unused2
- (char*)internal
) == mono_defaults
.internal_thread_class
->fields
[mono_defaults
.internal_thread_class
->field
.count
- 1].offset
);
903 mono_thread_create (MonoDomain
*domain
, gpointer func
, gpointer arg
)
905 mono_thread_create_internal (domain
, func
, arg
, FALSE
, 0);
909 mono_thread_attach (MonoDomain
*domain
)
911 return mono_thread_attach_full (domain
, FALSE
);
915 mono_thread_attach_full (MonoDomain
*domain
, gboolean force_attach
)
917 MonoThreadInfo
*info
;
918 MonoInternalThread
*thread
;
919 MonoThread
*current_thread
;
920 HANDLE thread_handle
;
923 if ((thread
= mono_thread_internal_current ())) {
924 if (domain
!= mono_domain_get ())
925 mono_domain_set (domain
, TRUE
);
926 /* Already attached */
927 return mono_thread_current ();
930 if (!mono_gc_register_thread (&domain
)) {
931 g_error ("Thread %"G_GSIZE_FORMAT
" calling into managed code is not registered with the GC. On UNIX, this can be fixed by #include-ing <gc.h> before <pthread.h> in the file containing the thread creation code.", GetCurrentThreadId ());
934 thread
= create_internal_thread ();
936 thread_handle
= mono_thread_info_open_handle ();
937 g_assert (thread_handle
);
939 tid
=GetCurrentThreadId ();
941 thread
->handle
=thread_handle
;
943 #ifdef PLATFORM_ANDROID
944 thread
->android_tid
= (gpointer
) gettid ();
946 thread
->stack_ptr
= &tid
;
948 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT
" (handle %p)", __func__
, tid
, thread_handle
));
950 info
= mono_thread_info_current ();
952 thread
->thread_info
= info
;
953 thread
->small_id
= info
->small_id
;
955 current_thread
= new_thread_with_internal (domain
, thread
);
957 if (!handle_store (current_thread
, force_attach
)) {
958 /* Mono is shutting down, so just wait for the end */
963 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT
") Setting current_object_key to %p", __func__
, GetCurrentThreadId (), thread
));
965 SET_CURRENT_OBJECT (thread
);
966 mono_domain_set (domain
, TRUE
);
968 thread_adjust_static_data (thread
);
970 init_root_domain_thread (thread
, current_thread
);
971 if (domain
!= mono_get_root_domain ())
972 set_current_thread_for_domain (domain
, thread
, current_thread
);
975 if (mono_thread_attach_cb
) {
979 mono_thread_info_get_stack_bounds (&staddr
, &stsize
);
982 mono_thread_attach_cb (tid
, &tid
);
984 mono_thread_attach_cb (tid
, staddr
+ stsize
);
987 // FIXME: Need a separate callback
988 mono_profiler_thread_start (tid
);
990 return current_thread
;
994 mono_thread_detach_internal (MonoInternalThread
*thread
)
996 g_return_if_fail (thread
!= NULL
);
998 THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT
")", __func__
, thread
, (gsize
)thread
->tid
));
1000 thread_cleanup (thread
);
1002 SET_CURRENT_OBJECT (NULL
);
1003 mono_domain_unset ();
1005 /* Don't need to CloseHandle this thread, even though we took a
1006 * reference in mono_thread_attach (), because the GC will do it
1007 * when the Thread object is finalised.
1012 mono_thread_detach (MonoThread
*thread
)
1015 mono_thread_detach_internal (thread
->internal_thread
);
1019 * mono_thread_detach_if_exiting:
1021 * Detach the current thread from the runtime if it is exiting, i.e. it is running pthread dtors.
1022 * This should be used at the end of embedding code which calls into managed code, and which
1023 * can be called from pthread dtors, like dealloc: implementations in objective-c.
1026 mono_thread_detach_if_exiting (void)
1028 if (mono_thread_info_is_exiting ()) {
1029 MonoInternalThread
*thread
;
1031 thread
= mono_thread_internal_current ();
1033 mono_thread_detach_internal (thread
);
1034 mono_thread_info_detach ();
1042 MonoInternalThread
*thread
= mono_thread_internal_current ();
1044 THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT
")", __func__
, thread
, (gsize
)thread
->tid
));
1046 thread_cleanup (thread
);
1047 SET_CURRENT_OBJECT (NULL
);
1048 mono_domain_unset ();
1050 /* we could add a callback here for embedders to use. */
1051 if (mono_thread_get_main () && (thread
== mono_thread_get_main ()->internal_thread
))
1052 exit (mono_environment_exitcode_get ());
1053 mono_thread_info_exit ();
1057 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread
*this)
1059 MonoInternalThread
*internal
= create_internal_thread ();
1061 internal
->state
= ThreadState_Unstarted
;
1063 InterlockedCompareExchangePointer ((gpointer
)&this->internal_thread
, internal
, NULL
);
1067 ves_icall_System_Threading_Thread_Thread_internal (MonoThread
*this,
1070 StartInfo
*start_info
;
1071 MonoInternalThread
*internal
;
1074 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__
, this, start
));
1076 if (!this->internal_thread
)
1077 ves_icall_System_Threading_Thread_ConstructInternalThread (this);
1078 internal
= this->internal_thread
;
1080 LOCK_THREAD (internal
);
1082 if ((internal
->state
& ThreadState_Unstarted
) == 0) {
1083 UNLOCK_THREAD (internal
);
1084 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has already been started."));
1088 if ((internal
->state
& ThreadState_Aborted
) != 0) {
1089 UNLOCK_THREAD (internal
);
1092 /* This is freed in start_wrapper */
1093 start_info
= g_new0 (StartInfo
, 1);
1094 start_info
->func
= NULL
;
1095 start_info
->start_arg
= this->start_obj
; /* FIXME: GC object stored in unmanaged memory */
1096 start_info
->delegate
= start
;
1097 start_info
->obj
= this;
1098 g_assert (this->obj
.vtable
->domain
== mono_domain_get ());
1100 res
= create_thread (this, internal
, start_info
, FALSE
, 0, FALSE
);
1102 UNLOCK_THREAD (internal
);
1106 internal
->state
&= ~ThreadState_Unstarted
;
1108 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT
" (handle %p)", __func__
, tid
, thread
));
1110 UNLOCK_THREAD (internal
);
1111 return internal
->handle
;
1115 * This is called from the finalizer of the internal thread object.
1118 ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread
*this, HANDLE thread
)
1120 THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__
, this, thread
));
1123 * Since threads keep a reference to their thread object while running, by the time this function is called,
1124 * the thread has already exited/detached, i.e. thread_cleanup () has ran. The exception is during shutdown,
1125 * when thread_cleanup () can be called after this.
1128 CloseHandle (thread
);
1130 if (this->synch_cs
) {
1131 mono_mutex_t
*synch_cs
= this->synch_cs
;
1132 this->synch_cs
= NULL
;
1133 mono_mutex_destroy (synch_cs
);
1138 void *name
= this->name
;
1145 ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms
)
1148 MonoInternalThread
*thread
= mono_thread_internal_current ();
1150 THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__
, ms
));
1152 mono_thread_current_check_pending_interrupt ();
1155 mono_thread_set_state (thread
, ThreadState_WaitSleepJoin
);
1157 MONO_PREPARE_BLOCKING
1158 res
= SleepEx(ms
,TRUE
);
1159 MONO_FINISH_BLOCKING
1161 mono_thread_clr_state (thread
, ThreadState_WaitSleepJoin
);
1163 if (res
== WAIT_IO_COMPLETION
) { /* we might have been interrupted */
1164 MonoException
* exc
= mono_thread_execute_interruption (thread
);
1166 mono_raise_exception (exc
);
1178 void ves_icall_System_Threading_Thread_SpinWait_nop (void)
1183 ves_icall_System_Threading_Thread_GetDomainID (void)
1185 return mono_domain_get()->domain_id
;
1189 ves_icall_System_Threading_Thread_Yield (void)
1191 return mono_thread_info_yield ();
1195 * mono_thread_get_name:
1197 * Return the name of the thread. NAME_LEN is set to the length of the name.
1198 * Return NULL if the thread has no name. The returned memory is owned by the
1202 mono_thread_get_name (MonoInternalThread
*this_obj
, guint32
*name_len
)
1206 LOCK_THREAD (this_obj
);
1208 if (!this_obj
->name
) {
1212 *name_len
= this_obj
->name_len
;
1213 res
= g_new (gunichar2
, this_obj
->name_len
);
1214 memcpy (res
, this_obj
->name
, sizeof (gunichar2
) * this_obj
->name_len
);
1217 UNLOCK_THREAD (this_obj
);
1223 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread
*this_obj
)
1227 LOCK_THREAD (this_obj
);
1229 if (!this_obj
->name
)
1232 str
= mono_string_new_utf16 (mono_domain_get (), this_obj
->name
, this_obj
->name_len
);
1234 UNLOCK_THREAD (this_obj
);
1240 mono_thread_set_name_internal (MonoInternalThread
*this_obj
, MonoString
*name
, gboolean managed
)
1242 LOCK_THREAD (this_obj
);
1244 if ((this_obj
->flags
& MONO_THREAD_FLAG_NAME_SET
) && !this_obj
->threadpool_thread
) {
1245 UNLOCK_THREAD (this_obj
);
1247 mono_raise_exception (mono_get_exception_invalid_operation ("Thread.Name can only be set once."));
1250 if (this_obj
->name
) {
1251 g_free (this_obj
->name
);
1252 this_obj
->name_len
= 0;
1255 this_obj
->name
= g_new (gunichar2
, mono_string_length (name
));
1256 memcpy (this_obj
->name
, mono_string_chars (name
), mono_string_length (name
) * 2);
1257 this_obj
->name_len
= mono_string_length (name
);
1260 this_obj
->name
= NULL
;
1263 this_obj
->flags
|= MONO_THREAD_FLAG_NAME_SET
;
1265 UNLOCK_THREAD (this_obj
);
1267 if (this_obj
->name
&& this_obj
->tid
) {
1268 char *tname
= mono_string_to_utf8 (name
);
1269 mono_profiler_thread_name (this_obj
->tid
, tname
);
1270 mono_thread_info_set_name (thread_get_tid (this_obj
), tname
);
1276 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread
*this_obj
, MonoString
*name
)
1278 mono_thread_set_name_internal (this_obj
, name
, TRUE
);
1282 ves_icall_System_Threading_Thread_GetPriority (MonoInternalThread
*thread
)
1284 return ThreadPriority_Lowest
;
1288 ves_icall_System_Threading_Thread_SetPriority (MonoInternalThread
*thread
, int priority
)
1292 /* If the array is already in the requested domain, we just return it,
1293 otherwise we return a copy in that domain. */
1295 byte_array_to_domain (MonoArray
*arr
, MonoDomain
*domain
)
1302 if (mono_object_domain (arr
) == domain
)
1305 copy
= mono_array_new (domain
, mono_defaults
.byte_class
, arr
->max_length
);
1306 memmove (mono_array_addr (copy
, guint8
, 0), mono_array_addr (arr
, guint8
, 0), arr
->max_length
);
1311 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray
*arr
)
1313 return byte_array_to_domain (arr
, mono_get_root_domain ());
1317 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray
*arr
)
1319 return byte_array_to_domain (arr
, mono_domain_get ());
1323 mono_thread_current (void)
1325 MonoDomain
*domain
= mono_domain_get ();
1326 MonoInternalThread
*internal
= mono_thread_internal_current ();
1327 MonoThread
**current_thread_ptr
;
1329 g_assert (internal
);
1330 current_thread_ptr
= get_current_thread_ptr_for_domain (domain
, internal
);
1332 if (!*current_thread_ptr
) {
1333 g_assert (domain
!= mono_get_root_domain ());
1334 *current_thread_ptr
= new_thread_with_internal (domain
, internal
);
1336 return *current_thread_ptr
;
1340 mono_thread_internal_current (void)
1342 MonoInternalThread
*res
= GET_CURRENT_OBJECT ();
1343 THREAD_DEBUG (g_message ("%s: returning %p", __func__
, res
));
1348 ves_icall_System_Threading_Thread_Join_internal(MonoInternalThread
*this,
1349 int ms
, HANDLE thread
)
1351 MonoInternalThread
*cur_thread
= mono_thread_internal_current ();
1354 mono_thread_current_check_pending_interrupt ();
1358 if ((this->state
& ThreadState_Unstarted
) != 0) {
1359 UNLOCK_THREAD (this);
1361 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started."));
1365 UNLOCK_THREAD (this);
1370 THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__
, thread
, ms
));
1372 mono_thread_set_state (cur_thread
, ThreadState_WaitSleepJoin
);
1374 MONO_PREPARE_BLOCKING
1375 ret
=WaitForSingleObjectEx (thread
, ms
, TRUE
);
1376 MONO_FINISH_BLOCKING
1378 mono_thread_clr_state (cur_thread
, ThreadState_WaitSleepJoin
);
1380 if(ret
==WAIT_OBJECT_0
) {
1381 THREAD_DEBUG (g_message ("%s: join successful", __func__
));
1386 THREAD_DEBUG (g_message ("%s: join failed", __func__
));
1392 mono_wait_uninterrupted (MonoInternalThread
*thread
, gboolean multiple
, guint32 numhandles
, gpointer
*handles
, gboolean waitall
, gint32 ms
, gboolean alertable
)
1400 start
= (ms
== -1) ? 0 : mono_100ns_ticks ();
1402 MONO_PREPARE_BLOCKING
1404 ret
= WaitForMultipleObjectsEx (numhandles
, handles
, waitall
, wait
, alertable
);
1406 ret
= WaitForSingleObjectEx (handles
[0], ms
, alertable
);
1407 MONO_FINISH_BLOCKING
1409 if (ret
!= WAIT_IO_COMPLETION
)
1412 exc
= mono_thread_execute_interruption (thread
);
1414 mono_raise_exception (exc
);
1419 /* Re-calculate ms according to the time passed */
1420 diff_ms
= (gint32
)((mono_100ns_ticks () - start
) / 10000);
1421 if (diff_ms
>= ms
) {
1425 wait
= ms
- diff_ms
;
1431 /* FIXME: exitContext isnt documented */
1432 gboolean
ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray
*mono_handles
, gint32 ms
, gboolean exitContext
)
1438 MonoObject
*waitHandle
;
1439 MonoInternalThread
*thread
= mono_thread_internal_current ();
1441 /* Do this WaitSleepJoin check before creating objects */
1442 mono_thread_current_check_pending_interrupt ();
1444 /* We fail in managed if the array has more than 64 elements */
1445 numhandles
= (guint32
)mono_array_length(mono_handles
);
1446 handles
= g_new0(HANDLE
, numhandles
);
1448 for(i
= 0; i
< numhandles
; i
++) {
1449 waitHandle
= mono_array_get(mono_handles
, MonoObject
*, i
);
1450 handles
[i
] = mono_wait_handle_get_handle ((MonoWaitHandle
*) waitHandle
);
1457 mono_thread_set_state (thread
, ThreadState_WaitSleepJoin
);
1459 ret
= mono_wait_uninterrupted (thread
, TRUE
, numhandles
, handles
, TRUE
, ms
, TRUE
);
1461 mono_thread_clr_state (thread
, ThreadState_WaitSleepJoin
);
1465 if(ret
==WAIT_FAILED
) {
1466 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT
") Wait failed", __func__
, GetCurrentThreadId ()));
1468 } else if(ret
==WAIT_TIMEOUT
) {
1469 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT
") Wait timed out", __func__
, GetCurrentThreadId ()));
1476 /* FIXME: exitContext isnt documented */
1477 gint32
ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray
*mono_handles
, gint32 ms
, gboolean exitContext
)
1479 HANDLE handles
[MAXIMUM_WAIT_OBJECTS
];
1480 uintptr_t numhandles
;
1483 MonoObject
*waitHandle
;
1484 MonoInternalThread
*thread
= mono_thread_internal_current ();
1486 /* Do this WaitSleepJoin check before creating objects */
1487 mono_thread_current_check_pending_interrupt ();
1489 numhandles
= mono_array_length(mono_handles
);
1490 if (numhandles
> MAXIMUM_WAIT_OBJECTS
)
1493 for(i
= 0; i
< numhandles
; i
++) {
1494 waitHandle
= mono_array_get(mono_handles
, MonoObject
*, i
);
1495 handles
[i
] = mono_wait_handle_get_handle ((MonoWaitHandle
*) waitHandle
);
1502 mono_thread_set_state (thread
, ThreadState_WaitSleepJoin
);
1504 ret
= mono_wait_uninterrupted (thread
, TRUE
, numhandles
, handles
, FALSE
, ms
, TRUE
);
1506 mono_thread_clr_state (thread
, ThreadState_WaitSleepJoin
);
1508 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT
") returning %d", __func__
, GetCurrentThreadId (), ret
));
1511 * These need to be here. See MSDN dos on WaitForMultipleObjects.
1513 if (ret
>= WAIT_OBJECT_0
&& ret
<= WAIT_OBJECT_0
+ numhandles
- 1) {
1514 return ret
- WAIT_OBJECT_0
;
1516 else if (ret
>= WAIT_ABANDONED_0
&& ret
<= WAIT_ABANDONED_0
+ numhandles
- 1) {
1517 return ret
- WAIT_ABANDONED_0
;
1524 /* FIXME: exitContext isnt documented */
1525 gboolean
ves_icall_System_Threading_WaitHandle_WaitOne_internal(MonoObject
*this, HANDLE handle
, gint32 ms
, gboolean exitContext
)
1528 MonoInternalThread
*thread
= mono_thread_internal_current ();
1530 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT
") waiting for %p, %d ms", __func__
, GetCurrentThreadId (), handle
, ms
));
1536 mono_thread_current_check_pending_interrupt ();
1538 mono_thread_set_state (thread
, ThreadState_WaitSleepJoin
);
1540 ret
= mono_wait_uninterrupted (thread
, FALSE
, 1, &handle
, FALSE
, ms
, TRUE
);
1542 mono_thread_clr_state (thread
, ThreadState_WaitSleepJoin
);
1544 if(ret
==WAIT_FAILED
) {
1545 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT
") Wait failed", __func__
, GetCurrentThreadId ()));
1547 } else if(ret
==WAIT_TIMEOUT
) {
1548 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT
") Wait timed out", __func__
, GetCurrentThreadId ()));
1556 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal
, HANDLE toWait
, gint32 ms
, gboolean exitContext
)
1559 MonoInternalThread
*thread
= mono_thread_internal_current ();
1564 mono_thread_current_check_pending_interrupt ();
1566 mono_thread_set_state (thread
, ThreadState_WaitSleepJoin
);
1568 MONO_PREPARE_BLOCKING
1569 ret
= SignalObjectAndWait (toSignal
, toWait
, ms
, TRUE
);
1570 MONO_FINISH_BLOCKING
1572 mono_thread_clr_state (thread
, ThreadState_WaitSleepJoin
);
1574 return (!(ret
== WAIT_TIMEOUT
|| ret
== WAIT_IO_COMPLETION
|| ret
== WAIT_FAILED
));
1577 HANDLE
ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned
, MonoString
*name
, MonoBoolean
*created
)
1584 mutex
= CreateMutex (NULL
, owned
, NULL
);
1586 mutex
= CreateMutex (NULL
, owned
, mono_string_chars (name
));
1588 if (GetLastError () == ERROR_ALREADY_EXISTS
) {
1596 MonoBoolean
ves_icall_System_Threading_Mutex_ReleaseMutex_internal (HANDLE handle
) {
1597 return(ReleaseMutex (handle
));
1600 HANDLE
ves_icall_System_Threading_Mutex_OpenMutex_internal (MonoString
*name
,
1606 *error
= ERROR_SUCCESS
;
1608 ret
= OpenMutex (rights
, FALSE
, mono_string_chars (name
));
1610 *error
= GetLastError ();
1617 HANDLE
ves_icall_System_Threading_Semaphore_CreateSemaphore_internal (gint32 initialCount
, gint32 maximumCount
, MonoString
*name
, MonoBoolean
*created
)
1624 sem
= CreateSemaphore (NULL
, initialCount
, maximumCount
, NULL
);
1626 sem
= CreateSemaphore (NULL
, initialCount
, maximumCount
,
1627 mono_string_chars (name
));
1629 if (GetLastError () == ERROR_ALREADY_EXISTS
) {
1637 gint32
ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal (HANDLE handle
, gint32 releaseCount
, MonoBoolean
*fail
)
1641 *fail
= !ReleaseSemaphore (handle
, releaseCount
, &prevcount
);
1646 HANDLE
ves_icall_System_Threading_Semaphore_OpenSemaphore_internal (MonoString
*name
, gint32 rights
, gint32
*error
)
1650 *error
= ERROR_SUCCESS
;
1652 ret
= OpenSemaphore (rights
, FALSE
, mono_string_chars (name
));
1654 *error
= GetLastError ();
1660 HANDLE
ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manual
, MonoBoolean initial
, MonoString
*name
, MonoBoolean
*created
)
1667 event
= CreateEvent (NULL
, manual
, initial
, NULL
);
1669 event
= CreateEvent (NULL
, manual
, initial
,
1670 mono_string_chars (name
));
1672 if (GetLastError () == ERROR_ALREADY_EXISTS
) {
1680 gboolean
ves_icall_System_Threading_Events_SetEvent_internal (HANDLE handle
) {
1681 return (SetEvent(handle
));
1684 gboolean
ves_icall_System_Threading_Events_ResetEvent_internal (HANDLE handle
) {
1685 return (ResetEvent(handle
));
1689 ves_icall_System_Threading_Events_CloseEvent_internal (HANDLE handle
) {
1690 CloseHandle (handle
);
1693 HANDLE
ves_icall_System_Threading_Events_OpenEvent_internal (MonoString
*name
,
1699 *error
= ERROR_SUCCESS
;
1701 ret
= OpenEvent (rights
, FALSE
, mono_string_chars (name
));
1703 *error
= GetLastError ();
1709 gint32
ves_icall_System_Threading_Interlocked_Increment_Int (gint32
*location
)
1711 return InterlockedIncrement (location
);
1714 gint64
ves_icall_System_Threading_Interlocked_Increment_Long (gint64
*location
)
1716 #if SIZEOF_VOID_P == 4
1717 if (G_UNLIKELY ((size_t)location
& 0x7)) {
1719 mono_interlocked_lock ();
1722 mono_interlocked_unlock ();
1726 return InterlockedIncrement64 (location
);
1729 gint32
ves_icall_System_Threading_Interlocked_Decrement_Int (gint32
*location
)
1731 return InterlockedDecrement(location
);
1734 gint64
ves_icall_System_Threading_Interlocked_Decrement_Long (gint64
* location
)
1736 #if SIZEOF_VOID_P == 4
1737 if (G_UNLIKELY ((size_t)location
& 0x7)) {
1739 mono_interlocked_lock ();
1742 mono_interlocked_unlock ();
1746 return InterlockedDecrement64 (location
);
1749 gint32
ves_icall_System_Threading_Interlocked_Exchange_Int (gint32
*location
, gint32 value
)
1751 return InterlockedExchange(location
, value
);
1754 MonoObject
* ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject
**location
, MonoObject
*value
)
1757 res
= (MonoObject
*) InterlockedExchangePointer((gpointer
*) location
, value
);
1758 mono_gc_wbarrier_generic_nostore (location
);
1762 gpointer
ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer
*location
, gpointer value
)
1764 return InterlockedExchangePointer(location
, value
);
1767 gfloat
ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat
*location
, gfloat value
)
1769 IntFloatUnion val
, ret
;
1772 ret
.ival
= InterlockedExchange((gint32
*) location
, val
.ival
);
1778 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64
*location
, gint64 value
)
1780 #if SIZEOF_VOID_P == 4
1781 if (G_UNLIKELY ((size_t)location
& 0x7)) {
1783 mono_interlocked_lock ();
1786 mono_interlocked_unlock ();
1790 return InterlockedExchange64 (location
, value
);
1794 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble
*location
, gdouble value
)
1796 LongDoubleUnion val
, ret
;
1799 ret
.ival
= (gint64
)InterlockedExchange64((gint64
*) location
, val
.ival
);
1804 gint32
ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32
*location
, gint32 value
, gint32 comparand
)
1806 return InterlockedCompareExchange(location
, value
, comparand
);
1809 gint32
ves_icall_System_Threading_Interlocked_CompareExchange_Int_Success(gint32
*location
, gint32 value
, gint32 comparand
, MonoBoolean
*success
)
1811 gint32 r
= InterlockedCompareExchange(location
, value
, comparand
);
1812 *success
= r
== comparand
;
1816 MonoObject
* ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject
**location
, MonoObject
*value
, MonoObject
*comparand
)
1819 res
= (MonoObject
*) InterlockedCompareExchangePointer((gpointer
*) location
, value
, comparand
);
1820 mono_gc_wbarrier_generic_nostore (location
);
1824 gpointer
ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer
*location
, gpointer value
, gpointer comparand
)
1826 return InterlockedCompareExchangePointer(location
, value
, comparand
);
1829 gfloat
ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat
*location
, gfloat value
, gfloat comparand
)
1831 IntFloatUnion val
, ret
, cmp
;
1834 cmp
.fval
= comparand
;
1835 ret
.ival
= InterlockedCompareExchange((gint32
*) location
, val
.ival
, cmp
.ival
);
1841 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble
*location
, gdouble value
, gdouble comparand
)
1843 #if SIZEOF_VOID_P == 8
1844 LongDoubleUnion val
, comp
, ret
;
1847 comp
.fval
= comparand
;
1848 ret
.ival
= (gint64
)InterlockedCompareExchangePointer((gpointer
*) location
, (gpointer
)val
.ival
, (gpointer
)comp
.ival
);
1854 mono_interlocked_lock ();
1856 if (old
== comparand
)
1858 mono_interlocked_unlock ();
1865 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64
*location
, gint64 value
, gint64 comparand
)
1867 #if SIZEOF_VOID_P == 4
1868 if (G_UNLIKELY ((size_t)location
& 0x7)) {
1870 mono_interlocked_lock ();
1872 if (old
== comparand
)
1874 mono_interlocked_unlock ();
1878 return InterlockedCompareExchange64 (location
, value
, comparand
);
1882 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject
**location
, MonoObject
*value
, MonoObject
*comparand
)
1885 res
= InterlockedCompareExchangePointer ((gpointer
*)location
, value
, comparand
);
1886 mono_gc_wbarrier_generic_nostore (location
);
1891 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject
**location
, MonoObject
*value
)
1894 res
= InterlockedExchangePointer ((gpointer
*)location
, value
);
1895 mono_gc_wbarrier_generic_nostore (location
);
1900 ves_icall_System_Threading_Interlocked_Add_Int (gint32
*location
, gint32 value
)
1902 return InterlockedAdd (location
, value
);
1906 ves_icall_System_Threading_Interlocked_Add_Long (gint64
*location
, gint64 value
)
1908 #if SIZEOF_VOID_P == 4
1909 if (G_UNLIKELY ((size_t)location
& 0x7)) {
1911 mono_interlocked_lock ();
1914 mono_interlocked_unlock ();
1918 return InterlockedAdd64 (location
, value
);
1922 ves_icall_System_Threading_Interlocked_Read_Long (gint64
*location
)
1924 #if SIZEOF_VOID_P == 4
1925 if (G_UNLIKELY ((size_t)location
& 0x7)) {
1927 mono_interlocked_lock ();
1929 mono_interlocked_unlock ();
1933 return InterlockedRead64 (location
);
1937 ves_icall_System_Threading_Thread_MemoryBarrier (void)
1939 mono_memory_barrier ();
1943 ves_icall_System_Threading_Thread_ClrState (MonoInternalThread
* this, guint32 state
)
1945 mono_thread_clr_state (this, state
);
1947 if (state
& ThreadState_Background
) {
1948 /* If the thread changes the background mode, the main thread has to
1949 * be notified, since it has to rebuild the list of threads to
1952 SetEvent (background_change_event
);
1957 ves_icall_System_Threading_Thread_SetState (MonoInternalThread
* this, guint32 state
)
1959 mono_thread_set_state (this, state
);
1961 if (state
& ThreadState_Background
) {
1962 /* If the thread changes the background mode, the main thread has to
1963 * be notified, since it has to rebuild the list of threads to
1966 SetEvent (background_change_event
);
1971 ves_icall_System_Threading_Thread_GetState (MonoInternalThread
* this)
1977 state
= this->state
;
1979 UNLOCK_THREAD (this);
1984 void ves_icall_System_Threading_Thread_Interrupt_internal (MonoInternalThread
*this)
1986 MonoInternalThread
*current
;
1991 current
= mono_thread_internal_current ();
1993 this->thread_interrupt_requested
= TRUE
;
1994 throw = current
!= this && (this->state
& ThreadState_WaitSleepJoin
);
1996 UNLOCK_THREAD (this);
1999 abort_thread_internal (this, TRUE
, FALSE
);
2003 void mono_thread_current_check_pending_interrupt ()
2005 MonoInternalThread
*thread
= mono_thread_internal_current ();
2006 gboolean
throw = FALSE
;
2008 LOCK_THREAD (thread
);
2010 if (thread
->thread_interrupt_requested
) {
2012 thread
->thread_interrupt_requested
= FALSE
;
2015 UNLOCK_THREAD (thread
);
2018 mono_raise_exception (mono_get_exception_thread_interrupted ());
2023 mono_thread_get_abort_signal (void)
2025 #if defined (HOST_WIN32) || !defined (HAVE_SIGACTION)
2027 #elif defined(PLATFORM_ANDROID)
2029 #elif !defined (SIGRTMIN)
2034 #endif /* SIGUSR1 */
2036 static int abort_signum
= -1;
2038 if (abort_signum
!= -1)
2039 return abort_signum
;
2040 /* we try to avoid SIGRTMIN and any one that might have been set already, see bug #75387 */
2041 for (i
= SIGRTMIN
+ 1; i
< SIGRTMAX
; ++i
) {
2042 struct sigaction sinfo
;
2043 sigaction (i
, NULL
, &sinfo
);
2044 if (sinfo
.sa_handler
== SIG_DFL
&& (void*)sinfo
.sa_sigaction
== (void*)SIG_DFL
) {
2049 /* fallback to the old way */
2051 #endif /* HOST_WIN32 */
2055 static void CALLBACK
interruption_request_apc (ULONG_PTR param
)
2057 MonoException
* exc
= mono_thread_request_interruption (FALSE
);
2058 if (exc
) mono_raise_exception (exc
);
2060 #endif /* HOST_WIN32 */
2063 * signal_thread_state_change
2065 * Tells the thread that his state has changed and it has to enter the new
2066 * state as soon as possible.
2068 static void signal_thread_state_change (MonoInternalThread
*thread
)
2071 gpointer wait_handle
;
2074 if (thread
== mono_thread_internal_current ()) {
2075 /* Do it synchronously */
2076 MonoException
*exc
= mono_thread_request_interruption (FALSE
);
2078 mono_raise_exception (exc
);
2082 QueueUserAPC ((PAPCFUNC
)interruption_request_apc
, thread
->handle
, (ULONG_PTR
)NULL
);
2085 * This will cause waits to be broken.
2086 * It will also prevent the thread from entering a wait, so if the thread returns
2087 * from the wait before it receives the abort signal, it will just spin in the wait
2088 * functions in the io-layer until the signal handler calls QueueUserAPC which will
2091 wait_handle
= mono_thread_info_prepare_interrupt (thread
->handle
);
2093 /* fixme: store the state somewhere */
2094 mono_thread_kill (thread
, mono_thread_get_abort_signal ());
2096 mono_thread_info_finish_interrupt (wait_handle
);
2097 #endif /* HOST_WIN32 */
2101 ves_icall_System_Threading_Thread_Abort (MonoInternalThread
*thread
, MonoObject
*state
)
2103 LOCK_THREAD (thread
);
2105 if ((thread
->state
& ThreadState_AbortRequested
) != 0 ||
2106 (thread
->state
& ThreadState_StopRequested
) != 0 ||
2107 (thread
->state
& ThreadState_Stopped
) != 0)
2109 UNLOCK_THREAD (thread
);
2113 if ((thread
->state
& ThreadState_Unstarted
) != 0) {
2114 thread
->state
|= ThreadState_Aborted
;
2115 UNLOCK_THREAD (thread
);
2119 thread
->state
|= ThreadState_AbortRequested
;
2120 if (thread
->abort_state_handle
)
2121 mono_gchandle_free (thread
->abort_state_handle
);
2123 thread
->abort_state_handle
= mono_gchandle_new (state
, FALSE
);
2124 g_assert (thread
->abort_state_handle
);
2126 thread
->abort_state_handle
= 0;
2128 thread
->abort_exc
= NULL
;
2131 * abort_exc is set in mono_thread_execute_interruption(),
2132 * triggered by the call to signal_thread_state_change(),
2133 * below. There's a point between where we have
2134 * abort_state_handle set, but abort_exc NULL, but that's not
2138 UNLOCK_THREAD (thread
);
2140 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT
") Abort requested for %p (%"G_GSIZE_FORMAT
")", __func__
, GetCurrentThreadId (), thread
, (gsize
)thread
->tid
));
2142 /* During shutdown, we can't wait for other threads */
2144 /* Make sure the thread is awake */
2145 mono_thread_resume (thread
);
2147 abort_thread_internal (thread
, TRUE
, TRUE
);
2151 ves_icall_System_Threading_Thread_ResetAbort (void)
2153 MonoInternalThread
*thread
= mono_thread_internal_current ();
2154 gboolean was_aborting
;
2156 LOCK_THREAD (thread
);
2157 was_aborting
= thread
->state
& ThreadState_AbortRequested
;
2158 thread
->state
&= ~ThreadState_AbortRequested
;
2159 UNLOCK_THREAD (thread
);
2161 if (!was_aborting
) {
2162 const char *msg
= "Unable to reset abort because no abort was requested";
2163 mono_set_pending_exception (mono_get_exception_thread_state (msg
));
2166 thread
->abort_exc
= NULL
;
2167 if (thread
->abort_state_handle
) {
2168 mono_gchandle_free (thread
->abort_state_handle
);
2169 /* This is actually not necessary - the handle
2170 only counts if the exception is set */
2171 thread
->abort_state_handle
= 0;
2176 mono_thread_internal_reset_abort (MonoInternalThread
*thread
)
2178 LOCK_THREAD (thread
);
2180 thread
->state
&= ~ThreadState_AbortRequested
;
2182 if (thread
->abort_exc
) {
2183 thread
->abort_exc
= NULL
;
2184 if (thread
->abort_state_handle
) {
2185 mono_gchandle_free (thread
->abort_state_handle
);
2186 /* This is actually not necessary - the handle
2187 only counts if the exception is set */
2188 thread
->abort_state_handle
= 0;
2192 UNLOCK_THREAD (thread
);
2196 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread
*this)
2198 MonoInternalThread
*thread
= this->internal_thread
;
2199 MonoObject
*state
, *deserialized
= NULL
, *exc
;
2202 if (!thread
->abort_state_handle
)
2205 state
= mono_gchandle_get_target (thread
->abort_state_handle
);
2208 domain
= mono_domain_get ();
2209 if (mono_object_domain (state
) == domain
)
2212 deserialized
= mono_object_xdomain_representation (state
, domain
, &exc
);
2214 if (!deserialized
) {
2215 MonoException
*invalid_op_exc
= mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
2217 MONO_OBJECT_SETREF (invalid_op_exc
, inner_ex
, exc
);
2218 mono_set_pending_exception (invalid_op_exc
);
2222 return deserialized
;
2226 mono_thread_suspend (MonoInternalThread
*thread
)
2228 LOCK_THREAD (thread
);
2230 if ((thread
->state
& ThreadState_Unstarted
) != 0 ||
2231 (thread
->state
& ThreadState_Aborted
) != 0 ||
2232 (thread
->state
& ThreadState_Stopped
) != 0)
2234 UNLOCK_THREAD (thread
);
2238 if ((thread
->state
& ThreadState_Suspended
) != 0 ||
2239 (thread
->state
& ThreadState_SuspendRequested
) != 0 ||
2240 (thread
->state
& ThreadState_StopRequested
) != 0)
2242 UNLOCK_THREAD (thread
);
2246 thread
->state
|= ThreadState_SuspendRequested
;
2248 UNLOCK_THREAD (thread
);
2250 suspend_thread_internal (thread
, FALSE
);
2255 ves_icall_System_Threading_Thread_Suspend (MonoInternalThread
*thread
)
2257 if (!mono_thread_suspend (thread
)) {
2258 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2264 mono_thread_resume (MonoInternalThread
*thread
)
2266 LOCK_THREAD (thread
);
2268 if ((thread
->state
& ThreadState_SuspendRequested
) != 0) {
2269 thread
->state
&= ~ThreadState_SuspendRequested
;
2270 UNLOCK_THREAD (thread
);
2274 if ((thread
->state
& ThreadState_Suspended
) == 0 ||
2275 (thread
->state
& ThreadState_Unstarted
) != 0 ||
2276 (thread
->state
& ThreadState_Aborted
) != 0 ||
2277 (thread
->state
& ThreadState_Stopped
) != 0)
2279 UNLOCK_THREAD (thread
);
2283 return resume_thread_internal (thread
);
2287 ves_icall_System_Threading_Thread_Resume (MonoThread
*thread
)
2289 if (!thread
->internal_thread
|| !mono_thread_resume (thread
->internal_thread
)) {
2290 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2296 mono_threads_is_critical_method (MonoMethod
*method
)
2298 switch (method
->wrapper_type
) {
2299 case MONO_WRAPPER_RUNTIME_INVOKE
:
2300 case MONO_WRAPPER_XDOMAIN_INVOKE
:
2301 case MONO_WRAPPER_XDOMAIN_DISPATCH
:
2308 find_wrapper (MonoMethod
*m
, gint no
, gint ilo
, gboolean managed
, gpointer data
)
2313 if (mono_threads_is_critical_method (m
)) {
2314 *((gboolean
*)data
) = TRUE
;
2321 is_running_protected_wrapper (void)
2323 gboolean found
= FALSE
;
2324 mono_stack_walk (find_wrapper
, &found
);
2328 void mono_thread_internal_stop (MonoInternalThread
*thread
)
2330 LOCK_THREAD (thread
);
2332 if ((thread
->state
& ThreadState_StopRequested
) != 0 ||
2333 (thread
->state
& ThreadState_Stopped
) != 0)
2335 UNLOCK_THREAD (thread
);
2339 /* Make sure the thread is awake */
2340 mono_thread_resume (thread
);
2342 thread
->state
|= ThreadState_StopRequested
;
2343 thread
->state
&= ~ThreadState_AbortRequested
;
2345 UNLOCK_THREAD (thread
);
2347 abort_thread_internal (thread
, TRUE
, TRUE
);
2350 void mono_thread_stop (MonoThread
*thread
)
2352 mono_thread_internal_stop (thread
->internal_thread
);
2356 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr
)
2359 mono_atomic_load_acquire (tmp
, gint8
, (volatile gint8
*) ptr
);
2364 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr
)
2367 mono_atomic_load_acquire (tmp
, gint16
, (volatile gint16
*) ptr
);
2372 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr
)
2375 mono_atomic_load_acquire (tmp
, gint32
, (volatile gint32
*) ptr
);
2380 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr
)
2383 mono_atomic_load_acquire (tmp
, gint64
, (volatile gint64
*) ptr
);
2388 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr
)
2391 mono_atomic_load_acquire (tmp
, volatile void *, (volatile void **) ptr
);
2392 return (void *) tmp
;
2396 ves_icall_System_Threading_Thread_VolatileReadObject (void *ptr
)
2398 volatile MonoObject
*tmp
;
2399 mono_atomic_load_acquire (tmp
, volatile MonoObject
*, (volatile MonoObject
**) ptr
);
2400 return (MonoObject
*) tmp
;
2404 ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr
)
2407 mono_atomic_load_acquire (tmp
, double, (volatile double *) ptr
);
2412 ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr
)
2415 mono_atomic_load_acquire (tmp
, float, (volatile float *) ptr
);
2420 ves_icall_System_Threading_Volatile_Read1 (void *ptr
)
2422 return InterlockedRead8 (ptr
);
2426 ves_icall_System_Threading_Volatile_Read2 (void *ptr
)
2428 return InterlockedRead16 (ptr
);
2432 ves_icall_System_Threading_Volatile_Read4 (void *ptr
)
2434 return InterlockedRead (ptr
);
2438 ves_icall_System_Threading_Volatile_Read8 (void *ptr
)
2440 #if SIZEOF_VOID_P == 4
2441 if (G_UNLIKELY ((size_t)ptr
& 0x7)) {
2443 mono_interlocked_lock ();
2444 val
= *(gint64
*)ptr
;
2445 mono_interlocked_unlock ();
2449 return InterlockedRead64 (ptr
);
2453 ves_icall_System_Threading_Volatile_ReadIntPtr (void *ptr
)
2455 return InterlockedReadPointer (ptr
);
2459 ves_icall_System_Threading_Volatile_ReadDouble (void *ptr
)
2463 #if SIZEOF_VOID_P == 4
2464 if (G_UNLIKELY ((size_t)ptr
& 0x7)) {
2466 mono_interlocked_lock ();
2467 val
= *(double*)ptr
;
2468 mono_interlocked_unlock ();
2473 u
.ival
= InterlockedRead64 (ptr
);
2479 ves_icall_System_Threading_Volatile_ReadFloat (void *ptr
)
2483 u
.ival
= InterlockedRead (ptr
);
2489 ves_icall_System_Threading_Volatile_Read_T (void *ptr
)
2491 return InterlockedReadPointer (ptr
);
2495 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr
, gint8 value
)
2497 mono_atomic_store_release ((volatile gint8
*) ptr
, value
);
2501 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr
, gint16 value
)
2503 mono_atomic_store_release ((volatile gint16
*) ptr
, value
);
2507 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr
, gint32 value
)
2509 mono_atomic_store_release ((volatile gint32
*) ptr
, value
);
2513 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr
, gint64 value
)
2515 mono_atomic_store_release ((volatile gint64
*) ptr
, value
);
2519 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr
, void *value
)
2521 mono_atomic_store_release ((volatile void **) ptr
, value
);
2525 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr
, MonoObject
*value
)
2527 mono_gc_wbarrier_generic_store_atomic (ptr
, value
);
2531 ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr
, double value
)
2533 mono_atomic_store_release ((volatile double *) ptr
, value
);
2537 ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr
, float value
)
2539 mono_atomic_store_release ((volatile float *) ptr
, value
);
2543 ves_icall_System_Threading_Volatile_Write1 (void *ptr
, gint8 value
)
2545 InterlockedWrite8 (ptr
, value
);
2549 ves_icall_System_Threading_Volatile_Write2 (void *ptr
, gint16 value
)
2551 InterlockedWrite16 (ptr
, value
);
2555 ves_icall_System_Threading_Volatile_Write4 (void *ptr
, gint32 value
)
2557 InterlockedWrite (ptr
, value
);
2561 ves_icall_System_Threading_Volatile_Write8 (void *ptr
, gint64 value
)
2563 #if SIZEOF_VOID_P == 4
2564 if (G_UNLIKELY ((size_t)ptr
& 0x7)) {
2565 mono_interlocked_lock ();
2566 *(gint64
*)ptr
= value
;
2567 mono_interlocked_unlock ();
2572 InterlockedWrite64 (ptr
, value
);
2576 ves_icall_System_Threading_Volatile_WriteIntPtr (void *ptr
, void *value
)
2578 InterlockedWritePointer (ptr
, value
);
2582 ves_icall_System_Threading_Volatile_WriteDouble (void *ptr
, double value
)
2586 #if SIZEOF_VOID_P == 4
2587 if (G_UNLIKELY ((size_t)ptr
& 0x7)) {
2588 mono_interlocked_lock ();
2589 *(double*)ptr
= value
;
2590 mono_interlocked_unlock ();
2597 InterlockedWrite64 (ptr
, u
.ival
);
2601 ves_icall_System_Threading_Volatile_WriteFloat (void *ptr
, float value
)
2607 InterlockedWrite (ptr
, u
.ival
);
2611 ves_icall_System_Threading_Volatile_Write_T (void *ptr
, MonoObject
*value
)
2613 mono_gc_wbarrier_generic_store_atomic (ptr
, value
);
2617 mono_thread_init_tls (void)
2619 MONO_FAST_TLS_INIT (tls_current_object
);
2620 mono_native_tls_alloc (¤t_object_key
, NULL
);
2623 void mono_thread_init (MonoThreadStartCB start_cb
,
2624 MonoThreadAttachCB attach_cb
)
2626 mono_mutex_init_recursive(&threads_mutex
);
2627 mono_mutex_init_recursive(&interlocked_mutex
);
2628 mono_mutex_init_recursive(&contexts_mutex
);
2629 mono_mutex_init_recursive(&joinable_threads_mutex
);
2631 background_change_event
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
2632 g_assert(background_change_event
!= NULL
);
2634 mono_init_static_data_info (&thread_static_info
);
2635 mono_init_static_data_info (&context_static_info
);
2637 THREAD_DEBUG (g_message ("%s: Allocated current_object_key %d", __func__
, current_object_key
));
2639 mono_thread_start_cb
= start_cb
;
2640 mono_thread_attach_cb
= attach_cb
;
2642 /* Get a pseudo handle to the current process. This is just a
2643 * kludge so that wapi can build a process handle if needed.
2644 * As a pseudo handle is returned, we don't need to clean
2647 GetCurrentProcess ();
2650 void mono_thread_cleanup (void)
2652 #if !defined(HOST_WIN32) && !defined(RUN_IN_SUBTHREAD)
2653 MonoThreadInfo
*info
;
2655 /* The main thread must abandon any held mutexes (particularly
2656 * important for named mutexes as they are shared across
2657 * processes, see bug 74680.) This will happen when the
2658 * thread exits, but if it's not running in a subthread it
2659 * won't exit in time.
2661 info
= mono_thread_info_current ();
2662 wapi_thread_handle_set_exited (info
->handle
, mono_environment_exitcode_get ());
2666 /* This stuff needs more testing, it seems one of these
2667 * critical sections can be locked when mono_thread_cleanup is
2670 mono_mutex_destroy (&threads_mutex
);
2671 mono_mutex_destroy (&interlocked_mutex
);
2672 mono_mutex_destroy (&contexts_mutex
);
2673 mono_mutex_destroy (&delayed_free_table_mutex
);
2674 mono_mutex_destroy (&small_id_mutex
);
2675 CloseHandle (background_change_event
);
2678 mono_native_tls_free (current_object_key
);
2682 mono_threads_install_cleanup (MonoThreadCleanupFunc func
)
2684 mono_thread_cleanup_fn
= func
;
2688 mono_thread_set_manage_callback (MonoThread
*thread
, MonoThreadManageCallback func
)
2690 thread
->internal_thread
->manage_callback
= func
;
2693 void mono_threads_install_notify_pending_exc (MonoThreadNotifyPendingExcFunc func
)
2695 mono_thread_notify_pending_exc_fn
= func
;
2699 static void print_tids (gpointer key
, gpointer value
, gpointer user
)
2701 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
2702 * sizeof(uint) and a cast to uint would overflow
2704 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
2705 * print this as a pointer.
2707 g_message ("Waiting for: %p", key
);
2712 HANDLE handles
[MAXIMUM_WAIT_OBJECTS
];
2713 MonoInternalThread
*threads
[MAXIMUM_WAIT_OBJECTS
];
2717 static void wait_for_tids (struct wait_data
*wait
, guint32 timeout
)
2721 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__
, wait
->num
));
2723 ret
=WaitForMultipleObjectsEx(wait
->num
, wait
->handles
, TRUE
, timeout
, TRUE
);
2725 if(ret
==WAIT_FAILED
) {
2726 /* See the comment in build_wait_tids() */
2727 THREAD_DEBUG (g_message ("%s: Wait failed", __func__
));
2731 for(i
=0; i
<wait
->num
; i
++)
2732 CloseHandle (wait
->handles
[i
]);
2734 if (ret
== WAIT_TIMEOUT
)
2737 for(i
=0; i
<wait
->num
; i
++) {
2738 gsize tid
= wait
->threads
[i
]->tid
;
2741 * On !win32, when the thread handle becomes signalled, it just means the thread has exited user code,
2742 * it can still run io-layer etc. code. So wait for it to really exit.
2743 * FIXME: This won't join threads which are not in the joinable_hash yet.
2745 mono_thread_join ((gpointer
)tid
);
2747 mono_threads_lock ();
2748 if(mono_g_hash_table_lookup (threads
, (gpointer
)tid
)!=NULL
) {
2749 /* This thread must have been killed, because
2750 * it hasn't cleaned itself up. (It's just
2751 * possible that the thread exited before the
2752 * parent thread had a chance to store the
2753 * handle, and now there is another pointer to
2754 * the already-exited thread stored. In this
2755 * case, we'll just get two
2756 * mono_profiler_thread_end() calls for the
2760 mono_threads_unlock ();
2761 THREAD_DEBUG (g_message ("%s: cleaning up after thread %p (%"G_GSIZE_FORMAT
")", __func__
, wait
->threads
[i
], tid
));
2762 thread_cleanup (wait
->threads
[i
]);
2764 mono_threads_unlock ();
2769 static void wait_for_tids_or_state_change (struct wait_data
*wait
, guint32 timeout
)
2771 guint32 i
, ret
, count
;
2773 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__
, wait
->num
));
2775 /* Add the thread state change event, so it wakes up if a thread changes
2776 * to background mode.
2779 if (count
< MAXIMUM_WAIT_OBJECTS
) {
2780 wait
->handles
[count
] = background_change_event
;
2784 ret
=WaitForMultipleObjectsEx (count
, wait
->handles
, FALSE
, timeout
, TRUE
);
2786 if(ret
==WAIT_FAILED
) {
2787 /* See the comment in build_wait_tids() */
2788 THREAD_DEBUG (g_message ("%s: Wait failed", __func__
));
2792 for(i
=0; i
<wait
->num
; i
++)
2793 CloseHandle (wait
->handles
[i
]);
2795 if (ret
== WAIT_TIMEOUT
)
2798 if (ret
< wait
->num
) {
2799 gsize tid
= wait
->threads
[ret
]->tid
;
2800 mono_threads_lock ();
2801 if (mono_g_hash_table_lookup (threads
, (gpointer
)tid
)!=NULL
) {
2802 /* See comment in wait_for_tids about thread cleanup */
2803 mono_threads_unlock ();
2804 THREAD_DEBUG (g_message ("%s: cleaning up after thread %"G_GSIZE_FORMAT
, __func__
, tid
));
2805 thread_cleanup (wait
->threads
[ret
]);
2807 mono_threads_unlock ();
2811 static void build_wait_tids (gpointer key
, gpointer value
, gpointer user
)
2813 struct wait_data
*wait
=(struct wait_data
*)user
;
2815 if(wait
->num
<MAXIMUM_WAIT_OBJECTS
) {
2817 MonoInternalThread
*thread
=(MonoInternalThread
*)value
;
2819 /* Ignore background threads, we abort them later */
2820 /* Do not lock here since it is not needed and the caller holds threads_lock */
2821 if (thread
->state
& ThreadState_Background
) {
2822 THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT
, __func__
, (gsize
)thread
->tid
));
2823 return; /* just leave, ignore */
2826 if (mono_gc_is_finalizer_internal_thread (thread
)) {
2827 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT
, __func__
, (gsize
)thread
->tid
));
2831 if (thread
== mono_thread_internal_current ()) {
2832 THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT
, __func__
, (gsize
)thread
->tid
));
2836 if (mono_thread_get_main () && (thread
== mono_thread_get_main ()->internal_thread
)) {
2837 THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT
, __func__
, (gsize
)thread
->tid
));
2841 if (thread
->flags
& MONO_THREAD_FLAG_DONT_MANAGE
) {
2842 THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT
"with DONT_MANAGE flag set.", __func__
, (gsize
)thread
->tid
));
2846 handle
= mono_threads_open_thread_handle (thread
->handle
, (MonoNativeThreadId
)thread
->tid
);
2847 if (handle
== NULL
) {
2848 THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT
, __func__
, (gsize
)thread
->tid
));
2852 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__
, thread
));
2853 if ((thread
->manage_callback
== NULL
) || (thread
->manage_callback (thread
->root_domain_thread
) == TRUE
)) {
2854 wait
->handles
[wait
->num
]=handle
;
2855 wait
->threads
[wait
->num
]=thread
;
2858 THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT
, __func__
, (gsize
)thread
->tid
));
2860 THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT
, __func__
, (gsize
)thread
->tid
));
2865 /* Just ignore the rest, we can't do anything with
2872 remove_and_abort_threads (gpointer key
, gpointer value
, gpointer user
)
2874 struct wait_data
*wait
=(struct wait_data
*)user
;
2875 gsize self
= GetCurrentThreadId ();
2876 MonoInternalThread
*thread
= value
;
2879 if (wait
->num
>= MAXIMUM_WAIT_OBJECTS
)
2882 /* The finalizer thread is not a background thread */
2883 if (thread
->tid
!= self
&& (thread
->state
& ThreadState_Background
) != 0 &&
2884 !(thread
->flags
& MONO_THREAD_FLAG_DONT_MANAGE
)) {
2886 handle
= mono_threads_open_thread_handle (thread
->handle
, (MonoNativeThreadId
)thread
->tid
);
2890 /* printf ("A: %d\n", wait->num); */
2891 wait
->handles
[wait
->num
]=thread
->handle
;
2892 wait
->threads
[wait
->num
]=thread
;
2895 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT
"\n", __func__
, (gsize
)thread
->tid
));
2896 mono_thread_internal_stop (thread
);
2900 return (thread
->tid
!= self
&& !mono_gc_is_finalizer_internal_thread (thread
));
2904 * mono_threads_set_shutting_down:
2906 * Is called by a thread that wants to shut down Mono. If the runtime is already
2907 * shutting down, the calling thread is suspended/stopped, and this function never
2911 mono_threads_set_shutting_down (void)
2913 MonoInternalThread
*current_thread
= mono_thread_internal_current ();
2915 mono_threads_lock ();
2917 if (shutting_down
) {
2918 mono_threads_unlock ();
2920 /* Make sure we're properly suspended/stopped */
2922 LOCK_THREAD (current_thread
);
2924 if ((current_thread
->state
& ThreadState_SuspendRequested
) ||
2925 (current_thread
->state
& ThreadState_AbortRequested
) ||
2926 (current_thread
->state
& ThreadState_StopRequested
)) {
2927 UNLOCK_THREAD (current_thread
);
2928 mono_thread_execute_interruption (current_thread
);
2930 current_thread
->state
|= ThreadState_Stopped
;
2931 UNLOCK_THREAD (current_thread
);
2934 /*since we're killing the thread, unset the current domain.*/
2935 mono_domain_unset ();
2937 /* Wake up other threads potentially waiting for us */
2938 mono_thread_info_exit ();
2940 shutting_down
= TRUE
;
2942 /* Not really a background state change, but this will
2943 * interrupt the main thread if it is waiting for all
2944 * the other threads.
2946 SetEvent (background_change_event
);
2948 mono_threads_unlock ();
2952 void mono_thread_manage (void)
2954 struct wait_data wait_data
;
2955 struct wait_data
*wait
= &wait_data
;
2957 memset (wait
, 0, sizeof (struct wait_data
));
2958 /* join each thread that's still running */
2959 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__
));
2961 mono_threads_lock ();
2963 THREAD_DEBUG (g_message("%s: No threads", __func__
));
2964 mono_threads_unlock ();
2967 mono_threads_unlock ();
2970 mono_threads_lock ();
2971 if (shutting_down
) {
2972 /* somebody else is shutting down */
2973 mono_threads_unlock ();
2976 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__
, mono_g_hash_table_size (threads
));
2977 mono_g_hash_table_foreach (threads
, print_tids
, NULL
));
2979 ResetEvent (background_change_event
);
2981 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
2982 memset (wait
->threads
, 0, MAXIMUM_WAIT_OBJECTS
* SIZEOF_VOID_P
);
2983 mono_g_hash_table_foreach (threads
, build_wait_tids
, wait
);
2984 mono_threads_unlock ();
2986 /* Something to wait for */
2987 wait_for_tids_or_state_change (wait
, INFINITE
);
2989 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__
, wait
->num
));
2990 } while(wait
->num
>0);
2992 /* Mono is shutting down, so just wait for the end */
2993 if (!mono_runtime_try_shutdown ()) {
2994 /*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
2995 mono_thread_suspend (mono_thread_internal_current ());
2996 mono_thread_execute_interruption (mono_thread_internal_current ());
3000 * Remove everything but the finalizer thread and self.
3001 * Also abort all the background threads
3004 mono_threads_lock ();
3007 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3008 memset (wait
->threads
, 0, MAXIMUM_WAIT_OBJECTS
* SIZEOF_VOID_P
);
3009 mono_g_hash_table_foreach_remove (threads
, remove_and_abort_threads
, wait
);
3011 mono_threads_unlock ();
3013 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__
, wait
->num
));
3015 /* Something to wait for */
3016 wait_for_tids (wait
, INFINITE
);
3018 } while (wait
->num
> 0);
3021 * give the subthreads a chance to really quit (this is mainly needed
3022 * to get correct user and system times from getrusage/wait/time(1)).
3023 * This could be removed if we avoid pthread_detach() and use pthread_join().
3025 mono_thread_info_yield ();
3028 static void terminate_thread (gpointer key
, gpointer value
, gpointer user
)
3030 MonoInternalThread
*thread
=(MonoInternalThread
*)value
;
3032 if(thread
->tid
!= (gsize
)user
) {
3033 /*TerminateThread (thread->handle, -1);*/
3037 void mono_thread_abort_all_other_threads (void)
3039 gsize self
= GetCurrentThreadId ();
3041 mono_threads_lock ();
3042 THREAD_DEBUG (g_message ("%s: There are %d threads to abort", __func__
,
3043 mono_g_hash_table_size (threads
));
3044 mono_g_hash_table_foreach (threads
, print_tids
, NULL
));
3046 mono_g_hash_table_foreach (threads
, terminate_thread
, (gpointer
)self
);
3048 mono_threads_unlock ();
3052 collect_threads_for_suspend (gpointer key
, gpointer value
, gpointer user_data
)
3054 MonoInternalThread
*thread
= (MonoInternalThread
*)value
;
3055 struct wait_data
*wait
= (struct wait_data
*)user_data
;
3059 * We try to exclude threads early, to avoid running into the MAXIMUM_WAIT_OBJECTS
3061 * This needs no locking.
3063 if ((thread
->state
& ThreadState_Suspended
) != 0 ||
3064 (thread
->state
& ThreadState_Stopped
) != 0)
3067 if (wait
->num
<MAXIMUM_WAIT_OBJECTS
) {
3068 handle
= mono_threads_open_thread_handle (thread
->handle
, (MonoNativeThreadId
)thread
->tid
);
3072 wait
->handles
[wait
->num
] = handle
;
3073 wait
->threads
[wait
->num
] = thread
;
3079 * mono_thread_suspend_all_other_threads:
3081 * Suspend all managed threads except the finalizer thread and this thread. It is
3082 * not possible to resume them later.
3084 void mono_thread_suspend_all_other_threads (void)
3086 struct wait_data wait_data
;
3087 struct wait_data
*wait
= &wait_data
;
3089 gsize self
= GetCurrentThreadId ();
3091 guint32 eventidx
= 0;
3092 gboolean starting
, finished
;
3094 memset (wait
, 0, sizeof (struct wait_data
));
3096 * The other threads could be in an arbitrary state at this point, i.e.
3097 * they could be starting up, shutting down etc. This means that there could be
3098 * threads which are not even in the threads hash table yet.
3102 * First we set a barrier which will be checked by all threads before they
3103 * are added to the threads hash table, and they will exit if the flag is set.
3104 * This ensures that no threads could be added to the hash later.
3105 * We will use shutting_down as the barrier for now.
3107 g_assert (shutting_down
);
3110 * We make multiple calls to WaitForMultipleObjects since:
3111 * - we can only wait for MAXIMUM_WAIT_OBJECTS threads
3112 * - some threads could exit without becoming suspended
3117 * Make a copy of the hashtable since we can't do anything with
3118 * threads while threads_mutex is held.
3121 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3122 memset (wait
->threads
, 0, MAXIMUM_WAIT_OBJECTS
* SIZEOF_VOID_P
);
3123 mono_threads_lock ();
3124 mono_g_hash_table_foreach (threads
, collect_threads_for_suspend
, wait
);
3125 mono_threads_unlock ();
3127 events
= g_new0 (gpointer
, wait
->num
);
3129 /* Get the suspended events that we'll be waiting for */
3130 for (i
= 0; i
< wait
->num
; ++i
) {
3131 MonoInternalThread
*thread
= wait
->threads
[i
];
3132 gboolean signal_suspend
= FALSE
;
3134 if ((thread
->tid
== self
) || mono_gc_is_finalizer_internal_thread (thread
) || (thread
->flags
& MONO_THREAD_FLAG_DONT_MANAGE
)) {
3135 //CloseHandle (wait->handles [i]);
3136 wait
->threads
[i
] = NULL
; /* ignore this thread in next loop */
3140 LOCK_THREAD (thread
);
3142 if (thread
->suspended_event
== NULL
) {
3143 thread
->suspended_event
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
3144 if (thread
->suspended_event
== NULL
) {
3145 /* Forget this one and go on to the next */
3146 UNLOCK_THREAD (thread
);
3151 if ((thread
->state
& ThreadState_Suspended
) != 0 ||
3152 (thread
->state
& ThreadState_StopRequested
) != 0 ||
3153 (thread
->state
& ThreadState_Stopped
) != 0) {
3154 UNLOCK_THREAD (thread
);
3155 CloseHandle (wait
->handles
[i
]);
3156 wait
->threads
[i
] = NULL
; /* ignore this thread in next loop */
3160 if ((thread
->state
& ThreadState_SuspendRequested
) == 0)
3161 signal_suspend
= TRUE
;
3163 events
[eventidx
++] = thread
->suspended_event
;
3165 /* Convert abort requests into suspend requests */
3166 if ((thread
->state
& ThreadState_AbortRequested
) != 0)
3167 thread
->state
&= ~ThreadState_AbortRequested
;
3169 thread
->state
|= ThreadState_SuspendRequested
;
3171 UNLOCK_THREAD (thread
);
3173 /* Signal the thread to suspend */
3174 if (mono_thread_info_new_interrupt_enabled ())
3175 suspend_thread_internal (thread
, TRUE
);
3176 else if (signal_suspend
)
3177 signal_thread_state_change (thread
);
3180 /*Only wait on the suspend event if we are using the old path */
3181 if (eventidx
> 0 && !mono_thread_info_new_interrupt_enabled ()) {
3182 WaitForMultipleObjectsEx (eventidx
, events
, TRUE
, 100, FALSE
);
3183 for (i
= 0; i
< wait
->num
; ++i
) {
3184 MonoInternalThread
*thread
= wait
->threads
[i
];
3189 LOCK_THREAD (thread
);
3190 if ((thread
->state
& ThreadState_Suspended
) != 0) {
3191 CloseHandle (thread
->suspended_event
);
3192 thread
->suspended_event
= NULL
;
3194 UNLOCK_THREAD (thread
);
3198 if (eventidx
<= 0) {
3200 * If there are threads which are starting up, we wait until they
3201 * are suspended when they try to register in the threads hash.
3202 * This is guaranteed to finish, since the threads which can create new
3203 * threads get suspended after a while.
3204 * FIXME: The finalizer thread can still create new threads.
3206 mono_threads_lock ();
3207 if (threads_starting_up
)
3208 starting
= mono_g_hash_table_size (threads_starting_up
) > 0;
3211 mono_threads_unlock ();
3223 collect_threads (gpointer key
, gpointer value
, gpointer user_data
)
3225 MonoInternalThread
*thread
= (MonoInternalThread
*)value
;
3226 struct wait_data
*wait
= (struct wait_data
*)user_data
;
3229 if (wait
->num
<MAXIMUM_WAIT_OBJECTS
) {
3230 handle
= mono_threads_open_thread_handle (thread
->handle
, (MonoNativeThreadId
)thread
->tid
);
3234 wait
->handles
[wait
->num
] = handle
;
3235 wait
->threads
[wait
->num
] = thread
;
3240 static gboolean thread_dump_requested
;
3242 static G_GNUC_UNUSED gboolean
3243 print_stack_frame_to_string (MonoStackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
3245 GString
*p
= (GString
*)data
;
3246 MonoMethod
*method
= NULL
;
3248 method
= mono_jit_info_get_method (frame
->ji
);
3251 gchar
*location
= mono_debug_print_stack_frame (method
, frame
->native_offset
, frame
->domain
);
3252 g_string_append_printf (p
, " %s\n", location
);
3255 g_string_append_printf (p
, " at <unknown> <0x%05x>\n", frame
->native_offset
);
3260 static SuspendThreadResult
3261 print_thread_dump (MonoThreadInfo
*info
, gpointer ud
)
3263 MonoInternalThread
*thread
= ud
;
3264 GString
* text
= g_string_new (0);
3266 GError
*error
= NULL
;
3269 name
= g_utf16_to_utf8 (thread
->name
, thread
->name_len
, NULL
, NULL
, &error
);
3271 g_string_append_printf (text
, "\n\"%s\"", name
);
3274 else if (thread
->threadpool_thread
)
3275 g_string_append (text
, "\n\"<threadpool thread>\"");
3277 g_string_append (text
, "\n\"<unnamed thread>\"");
3280 /* This no longer works with remote unwinding */
3282 wapi_desc
= wapi_current_thread_desc ();
3283 g_string_append_printf (text
, " tid=0x%p this=0x%p %s\n", (gpointer
)(gsize
)thread
->tid
, thread
, wapi_desc
);
3288 mono_get_eh_callbacks ()->mono_walk_stack_with_state (print_stack_frame_to_string
, mono_thread_info_get_suspend_state (info
), MONO_UNWIND_SIGNAL_SAFE
, text
);
3290 fprintf (stdout
, "%s", text
->str
);
3292 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3293 OutputDebugStringA(text
->str
);
3296 g_string_free (text
, TRUE
);
3298 return MonoResumeThread
;
3302 dump_thread (gpointer key
, gpointer value
, gpointer user
)
3304 MonoInternalThread
*thread
= (MonoInternalThread
*)value
;
3306 if (thread
== mono_thread_internal_current ())
3310 FIXME This still can hang if we stop a thread during malloc.
3311 FIXME This can hang if we suspend on a critical method and the GC kicks in. A fix might be to have function
3312 that takes a callback and runs it with the target suspended.
3313 We probably should loop a bit around trying to get it to either managed code
3316 mono_thread_info_safe_suspend_and_run ((MonoNativeThreadId
)(gsize
)thread
->tid
, FALSE
, print_thread_dump
, thread
);
3320 mono_threads_perform_thread_dump (void)
3322 if (!thread_dump_requested
)
3325 printf ("Full thread dump:\n");
3327 /* We take the loader lock and the root domain lock as to increase our odds of not deadlocking if
3328 something needs then in the process.
3330 mono_loader_lock ();
3331 mono_domain_lock (mono_get_root_domain ());
3333 mono_threads_lock ();
3334 mono_g_hash_table_foreach (threads
, dump_thread
, NULL
);
3335 mono_threads_unlock ();
3337 mono_domain_unlock (mono_get_root_domain ());
3338 mono_loader_unlock ();
3340 thread_dump_requested
= FALSE
;
3344 * mono_threads_request_thread_dump:
3346 * Ask all threads except the current to print their stacktrace to stdout.
3349 mono_threads_request_thread_dump (void)
3351 struct wait_data wait_data
;
3352 struct wait_data
*wait
= &wait_data
;
3355 /*The new thread dump code runs out of the finalizer thread. */
3356 if (mono_thread_info_new_interrupt_enabled ()) {
3357 thread_dump_requested
= TRUE
;
3358 mono_gc_finalize_notify ();
3363 memset (wait
, 0, sizeof (struct wait_data
));
3366 * Make a copy of the hashtable since we can't do anything with
3367 * threads while threads_mutex is held.
3369 mono_threads_lock ();
3370 mono_g_hash_table_foreach (threads
, collect_threads
, wait
);
3371 mono_threads_unlock ();
3373 for (i
= 0; i
< wait
->num
; ++i
) {
3374 MonoInternalThread
*thread
= wait
->threads
[i
];
3376 if (!mono_gc_is_finalizer_internal_thread (thread
) &&
3377 (thread
!= mono_thread_internal_current ()) &&
3378 !thread
->thread_dump_requested
) {
3379 thread
->thread_dump_requested
= TRUE
;
3381 signal_thread_state_change (thread
);
3384 CloseHandle (wait
->handles
[i
]);
3390 gint allocated
; /* +1 so that refs [allocated] == NULL */
3394 typedef struct ref_stack RefStack
;
3397 ref_stack_new (gint initial_size
)
3401 initial_size
= MAX (initial_size
, 16) + 1;
3402 rs
= g_new0 (RefStack
, 1);
3403 rs
->refs
= g_new0 (gpointer
, initial_size
);
3404 rs
->allocated
= initial_size
;
3409 ref_stack_destroy (gpointer ptr
)
3420 ref_stack_push (RefStack
*rs
, gpointer ptr
)
3422 g_assert (rs
!= NULL
);
3424 if (rs
->bottom
>= rs
->allocated
) {
3425 rs
->refs
= g_realloc (rs
->refs
, rs
->allocated
* 2 * sizeof (gpointer
) + 1);
3426 rs
->allocated
<<= 1;
3427 rs
->refs
[rs
->allocated
] = NULL
;
3429 rs
->refs
[rs
->bottom
++] = ptr
;
3433 ref_stack_pop (RefStack
*rs
)
3435 if (rs
== NULL
|| rs
->bottom
== 0)
3439 rs
->refs
[rs
->bottom
] = NULL
;
3443 ref_stack_find (RefStack
*rs
, gpointer ptr
)
3450 for (refs
= rs
->refs
; refs
&& *refs
; refs
++) {
3458 * mono_thread_push_appdomain_ref:
3460 * Register that the current thread may have references to objects in domain
3461 * @domain on its stack. Each call to this function should be paired with a
3462 * call to pop_appdomain_ref.
3465 mono_thread_push_appdomain_ref (MonoDomain
*domain
)
3467 MonoInternalThread
*thread
= mono_thread_internal_current ();
3470 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3471 SPIN_LOCK (thread
->lock_thread_id
);
3472 if (thread
->appdomain_refs
== NULL
)
3473 thread
->appdomain_refs
= ref_stack_new (16);
3474 ref_stack_push (thread
->appdomain_refs
, domain
);
3475 SPIN_UNLOCK (thread
->lock_thread_id
);
3480 mono_thread_pop_appdomain_ref (void)
3482 MonoInternalThread
*thread
= mono_thread_internal_current ();
3485 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3486 SPIN_LOCK (thread
->lock_thread_id
);
3487 ref_stack_pop (thread
->appdomain_refs
);
3488 SPIN_UNLOCK (thread
->lock_thread_id
);
3493 mono_thread_internal_has_appdomain_ref (MonoInternalThread
*thread
, MonoDomain
*domain
)
3496 SPIN_LOCK (thread
->lock_thread_id
);
3497 res
= ref_stack_find (thread
->appdomain_refs
, domain
);
3498 SPIN_UNLOCK (thread
->lock_thread_id
);
3503 mono_thread_has_appdomain_ref (MonoThread
*thread
, MonoDomain
*domain
)
3505 return mono_thread_internal_has_appdomain_ref (thread
->internal_thread
, domain
);
3508 typedef struct abort_appdomain_data
{
3509 struct wait_data wait
;
3511 } abort_appdomain_data
;
3514 collect_appdomain_thread (gpointer key
, gpointer value
, gpointer user_data
)
3516 MonoInternalThread
*thread
= (MonoInternalThread
*)value
;
3517 abort_appdomain_data
*data
= (abort_appdomain_data
*)user_data
;
3518 MonoDomain
*domain
= data
->domain
;
3520 if (mono_thread_internal_has_appdomain_ref (thread
, domain
)) {
3521 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3523 if(data
->wait
.num
<MAXIMUM_WAIT_OBJECTS
) {
3524 HANDLE handle
= mono_threads_open_thread_handle (thread
->handle
, (MonoNativeThreadId
)thread
->tid
);
3527 data
->wait
.handles
[data
->wait
.num
] = handle
;
3528 data
->wait
.threads
[data
->wait
.num
] = thread
;
3531 /* Just ignore the rest, we can't do anything with
3539 * mono_threads_abort_appdomain_threads:
3541 * Abort threads which has references to the given appdomain.
3544 mono_threads_abort_appdomain_threads (MonoDomain
*domain
, int timeout
)
3546 #ifdef __native_client__
3550 abort_appdomain_data user_data
;
3552 int orig_timeout
= timeout
;
3555 THREAD_DEBUG (g_message ("%s: starting abort", __func__
));
3557 start_time
= mono_msec_ticks ();
3559 mono_threads_lock ();
3561 user_data
.domain
= domain
;
3562 user_data
.wait
.num
= 0;
3563 /* This shouldn't take any locks */
3564 mono_g_hash_table_foreach (threads
, collect_appdomain_thread
, &user_data
);
3565 mono_threads_unlock ();
3567 if (user_data
.wait
.num
> 0) {
3568 /* Abort the threads outside the threads lock */
3569 for (i
= 0; i
< user_data
.wait
.num
; ++i
)
3570 ves_icall_System_Threading_Thread_Abort (user_data
.wait
.threads
[i
], NULL
);
3573 * We should wait for the threads either to abort, or to leave the
3574 * domain. We can't do the latter, so we wait with a timeout.
3576 wait_for_tids (&user_data
.wait
, 100);
3579 /* Update remaining time */
3580 timeout
-= mono_msec_ticks () - start_time
;
3581 start_time
= mono_msec_ticks ();
3583 if (orig_timeout
!= -1 && timeout
< 0)
3586 while (user_data
.wait
.num
> 0);
3588 THREAD_DEBUG (g_message ("%s: abort done", __func__
));
3594 clear_cached_culture (gpointer key
, gpointer value
, gpointer user_data
)
3596 MonoInternalThread
*thread
= (MonoInternalThread
*)value
;
3597 MonoDomain
*domain
= (MonoDomain
*)user_data
;
3600 /* No locking needed here */
3601 /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
3603 if (thread
->cached_culture_info
) {
3604 for (i
= 0; i
< NUM_CACHED_CULTURES
* 2; ++i
) {
3605 MonoObject
*obj
= mono_array_get (thread
->cached_culture_info
, MonoObject
*, i
);
3606 if (obj
&& obj
->vtable
->domain
== domain
)
3607 mono_array_set (thread
->cached_culture_info
, MonoObject
*, i
, NULL
);
3613 * mono_threads_clear_cached_culture:
3615 * Clear the cached_current_culture from all threads if it is in the
3619 mono_threads_clear_cached_culture (MonoDomain
*domain
)
3621 mono_threads_lock ();
3622 mono_g_hash_table_foreach (threads
, clear_cached_culture
, domain
);
3623 mono_threads_unlock ();
3627 * mono_thread_get_undeniable_exception:
3629 * Return an exception which needs to be raised when leaving a catch clause.
3630 * This is used for undeniable exception propagation.
3633 mono_thread_get_undeniable_exception (void)
3635 MonoInternalThread
*thread
= mono_thread_internal_current ();
3637 if (thread
&& thread
->abort_exc
&& !is_running_protected_wrapper ()) {
3639 * FIXME: Clear the abort exception and return an AppDomainUnloaded
3640 * exception if the thread no longer references a dying appdomain.
3642 thread
->abort_exc
->trace_ips
= NULL
;
3643 thread
->abort_exc
->stack_trace
= NULL
;
3644 return thread
->abort_exc
;
3650 #if MONO_SMALL_CONFIG
3651 #define NUM_STATIC_DATA_IDX 4
3652 static const int static_data_size
[NUM_STATIC_DATA_IDX
] = {
3656 #define NUM_STATIC_DATA_IDX 8
3657 static const int static_data_size
[NUM_STATIC_DATA_IDX
] = {
3658 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
3662 static uintptr_t* static_reference_bitmaps
[NUM_STATIC_DATA_IDX
];
3665 mark_tls_slots (void *addr
, MonoGCMarkFunc mark_func
, void *gc_data
)
3668 gpointer
*static_data
= addr
;
3669 for (i
= 0; i
< NUM_STATIC_DATA_IDX
; ++i
) {
3672 if (!static_data
[i
])
3674 numwords
= 1 + static_data_size
[i
] / sizeof (gpointer
) / (sizeof(uintptr_t) * 8);
3675 ptr
= static_data
[i
];
3676 for (j
= 0; j
< numwords
; ++j
, ptr
+= sizeof (uintptr_t) * 8) {
3677 uintptr_t bmap
= static_reference_bitmaps
[i
][j
];
3680 if ((bmap
& 1) && *p
) {
3681 mark_func (p
, gc_data
);
3691 * mono_alloc_static_data
3693 * Allocate memory blocks for storing threads or context static data
3696 mono_alloc_static_data (gpointer
**static_data_ptr
, guint32 offset
, gboolean threadlocal
)
3698 guint idx
= (offset
>> 24) - 1;
3701 gpointer
* static_data
= *static_data_ptr
;
3703 static void* tls_desc
= NULL
;
3704 if (mono_gc_user_markers_supported () && !tls_desc
)
3705 tls_desc
= mono_gc_make_root_descr_user (mark_tls_slots
);
3706 static_data
= mono_gc_alloc_fixed (static_data_size
[0], threadlocal
?tls_desc
:NULL
);
3707 *static_data_ptr
= static_data
;
3708 static_data
[0] = static_data
;
3711 for (i
= 1; i
<= idx
; ++i
) {
3712 if (static_data
[i
])
3714 if (mono_gc_user_markers_supported () && threadlocal
)
3715 static_data
[i
] = g_malloc0 (static_data_size
[i
]);
3717 static_data
[i
] = mono_gc_alloc_fixed (static_data_size
[i
], NULL
);
3722 mono_free_static_data (gpointer
* static_data
, gboolean threadlocal
)
3725 for (i
= 1; i
< NUM_STATIC_DATA_IDX
; ++i
) {
3726 gpointer p
= static_data
[i
];
3730 * At this point, the static data pointer array is still registered with the
3731 * GC, so must ensure that mark_tls_slots() will not encounter any invalid
3732 * data. Freeing the individual arrays without first nulling their slots
3733 * would make it possible for mark_tls_slots() to encounter a pointer to
3734 * such an already freed array. See bug #13813.
3736 static_data
[i
] = NULL
;
3737 mono_memory_write_barrier ();
3738 if (mono_gc_user_markers_supported () && threadlocal
)
3741 mono_gc_free_fixed (p
);
3743 mono_gc_free_fixed (static_data
);
3747 * mono_init_static_data_info
3749 * Initializes static data counters
3751 static void mono_init_static_data_info (StaticDataInfo
*static_data
)
3753 static_data
->idx
= 0;
3754 static_data
->offset
= 0;
3755 static_data
->freelist
= NULL
;
3759 * mono_alloc_static_data_slot
3761 * Generates an offset for static data. static_data contains the counters
3762 * used to generate it.
3765 mono_alloc_static_data_slot (StaticDataInfo
*static_data
, guint32 size
, guint32 align
)
3769 if (!static_data
->idx
&& !static_data
->offset
) {
3771 * we use the first chunk of the first allocation also as
3772 * an array for the rest of the data
3774 static_data
->offset
= sizeof (gpointer
) * NUM_STATIC_DATA_IDX
;
3776 static_data
->offset
+= align
- 1;
3777 static_data
->offset
&= ~(align
- 1);
3778 if (static_data
->offset
+ size
>= static_data_size
[static_data
->idx
]) {
3779 static_data
->idx
++;
3780 g_assert (size
<= static_data_size
[static_data
->idx
]);
3781 g_assert (static_data
->idx
< NUM_STATIC_DATA_IDX
);
3782 static_data
->offset
= 0;
3784 offset
= static_data
->offset
| ((static_data
->idx
+ 1) << 24);
3785 static_data
->offset
+= size
;
3790 * ensure thread static fields already allocated are valid for thread
3791 * This function is called when a thread is created or on thread attach.
3794 thread_adjust_static_data (MonoInternalThread
*thread
)
3798 mono_threads_lock ();
3799 if (thread_static_info
.offset
|| thread_static_info
.idx
> 0) {
3800 /* get the current allocated size */
3801 offset
= thread_static_info
.offset
| ((thread_static_info
.idx
+ 1) << 24);
3802 mono_alloc_static_data (&(thread
->static_data
), offset
, TRUE
);
3804 mono_threads_unlock ();
3808 alloc_thread_static_data_helper (gpointer key
, gpointer value
, gpointer user
)
3810 MonoInternalThread
*thread
= value
;
3811 guint32 offset
= GPOINTER_TO_UINT (user
);
3813 mono_alloc_static_data (&(thread
->static_data
), offset
, TRUE
);
3816 static MonoThreadDomainTls
*
3817 search_tls_slot_in_freelist (StaticDataInfo
*static_data
, guint32 size
, guint32 align
)
3819 MonoThreadDomainTls
* prev
= NULL
;
3820 MonoThreadDomainTls
* tmp
= static_data
->freelist
;
3822 if (tmp
->size
== size
) {
3824 prev
->next
= tmp
->next
;
3826 static_data
->freelist
= tmp
->next
;
3835 #if SIZEOF_VOID_P == 4
3842 update_tls_reference_bitmap (guint32 offset
, uintptr_t *bitmap
, int numbits
)
3845 int idx
= (offset
>> 24) - 1;
3847 if (!static_reference_bitmaps
[idx
])
3848 static_reference_bitmaps
[idx
] = g_new0 (uintptr_t, 1 + static_data_size
[idx
] / sizeof(gpointer
) / (sizeof(uintptr_t) * 8));
3849 rb
= static_reference_bitmaps
[idx
];
3851 offset
/= sizeof (gpointer
);
3852 /* offset is now the bitmap offset */
3853 for (i
= 0; i
< numbits
; ++i
) {
3854 if (bitmap
[i
/ sizeof (uintptr_t)] & (ONE_P
<< (i
& (sizeof (uintptr_t) * 8 -1))))
3855 rb
[(offset
+ i
) / (sizeof (uintptr_t) * 8)] |= (ONE_P
<< ((offset
+ i
) & (sizeof (uintptr_t) * 8 -1)));
3860 clear_reference_bitmap (guint32 offset
, guint32 size
)
3862 int idx
= (offset
>> 24) - 1;
3864 rb
= static_reference_bitmaps
[idx
];
3866 offset
/= sizeof (gpointer
);
3867 size
/= sizeof (gpointer
);
3869 /* offset is now the bitmap offset */
3870 for (; offset
< size
; ++offset
)
3871 rb
[offset
/ (sizeof (uintptr_t) * 8)] &= ~(1L << (offset
& (sizeof (uintptr_t) * 8 -1)));
3875 * The offset for a special static variable is composed of three parts:
3876 * a bit that indicates the type of static data (0:thread, 1:context),
3877 * an index in the array of chunks of memory for the thread (thread->static_data)
3878 * and an offset in that chunk of mem. This allows allocating less memory in the
3883 mono_alloc_special_static_data (guint32 static_type
, guint32 size
, guint32 align
, uintptr_t *bitmap
, int numbits
)
3886 if (static_type
== SPECIAL_STATIC_THREAD
) {
3887 MonoThreadDomainTls
*item
;
3888 mono_threads_lock ();
3889 item
= search_tls_slot_in_freelist (&thread_static_info
, size
, align
);
3890 /*g_print ("TLS alloc: %d in domain %p (total: %d), cached: %p\n", size, mono_domain_get (), thread_static_info.offset, item);*/
3892 offset
= item
->offset
;
3895 offset
= mono_alloc_static_data_slot (&thread_static_info
, size
, align
);
3897 update_tls_reference_bitmap (offset
, bitmap
, numbits
);
3898 /* This can be called during startup */
3899 if (threads
!= NULL
)
3900 mono_g_hash_table_foreach (threads
, alloc_thread_static_data_helper
, GUINT_TO_POINTER (offset
));
3901 mono_threads_unlock ();
3903 g_assert (static_type
== SPECIAL_STATIC_CONTEXT
);
3904 mono_contexts_lock ();
3905 offset
= mono_alloc_static_data_slot (&context_static_info
, size
, align
);
3906 mono_contexts_unlock ();
3907 offset
|= 0x80000000; /* Set the high bit to indicate context static data */
3913 mono_get_special_static_data_for_thread (MonoInternalThread
*thread
, guint32 offset
)
3915 /* The high bit means either thread (0) or static (1) data. */
3917 guint32 static_type
= (offset
& 0x80000000);
3920 offset
&= 0x7fffffff;
3921 idx
= (offset
>> 24) - 1;
3923 if (static_type
== 0) {
3924 return get_thread_static_data (thread
, offset
);
3926 /* Allocate static data block under demand, since we don't have a list
3929 MonoAppContext
*context
= mono_context_get ();
3930 if (!context
->static_data
|| !context
->static_data
[idx
]) {
3931 mono_contexts_lock ();
3932 mono_alloc_static_data (&(context
->static_data
), offset
, FALSE
);
3933 mono_contexts_unlock ();
3935 return ((char*) context
->static_data
[idx
]) + (offset
& 0xffffff);
3940 mono_get_special_static_data (guint32 offset
)
3942 return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset
);
3951 free_thread_static_data_helper (gpointer key
, gpointer value
, gpointer user
)
3953 MonoInternalThread
*thread
= value
;
3954 TlsOffsetSize
*data
= user
;
3955 int idx
= (data
->offset
>> 24) - 1;
3958 if (!thread
->static_data
|| !thread
->static_data
[idx
])
3960 ptr
= ((char*) thread
->static_data
[idx
]) + (data
->offset
& 0xffffff);
3961 mono_gc_bzero_atomic (ptr
, data
->size
);
3965 do_free_special_slot (guint32 offset
, guint32 size
)
3967 guint32 static_type
= (offset
& 0x80000000);
3968 /*g_print ("free %s , size: %d, offset: %x\n", field->name, size, offset);*/
3969 if (static_type
== 0) {
3971 MonoThreadDomainTls
*item
= g_new0 (MonoThreadDomainTls
, 1);
3972 data
.offset
= offset
& 0x7fffffff;
3974 clear_reference_bitmap (data
.offset
, data
.size
);
3975 if (threads
!= NULL
)
3976 mono_g_hash_table_foreach (threads
, free_thread_static_data_helper
, &data
);
3977 item
->offset
= offset
;
3980 if (!mono_runtime_is_shutting_down ()) {
3981 item
->next
= thread_static_info
.freelist
;
3982 thread_static_info
.freelist
= item
;
3984 /* We could be called during shutdown after mono_thread_cleanup () is called */
3988 /* FIXME: free context static data as well */
3993 do_free_special (gpointer key
, gpointer value
, gpointer data
)
3995 MonoClassField
*field
= key
;
3996 guint32 offset
= GPOINTER_TO_UINT (value
);
3999 size
= mono_type_size (field
->type
, &align
);
4000 do_free_special_slot (offset
, size
);
4004 mono_alloc_special_static_data_free (GHashTable
*special_static_fields
)
4006 mono_threads_lock ();
4007 g_hash_table_foreach (special_static_fields
, do_free_special
, NULL
);
4008 mono_threads_unlock ();
4012 mono_special_static_data_free_slot (guint32 offset
, guint32 size
)
4014 mono_threads_lock ();
4015 do_free_special_slot (offset
, size
);
4016 mono_threads_unlock ();
4020 * allocates room in the thread local area for storing an instance of the struct type
4021 * the allocation is kept track of in domain->tlsrec_list.
4024 mono_thread_alloc_tls (MonoReflectionType
*type
)
4026 MonoDomain
*domain
= mono_domain_get ();
4028 MonoTlsDataRecord
*tlsrec
;
4031 gsize default_bitmap
[4] = {0};
4032 uint32_t tls_offset
;
4036 klass
= mono_class_from_mono_type (type
->type
);
4037 /* TlsDatum is a struct, so we subtract the object header size offset */
4038 bitmap
= mono_class_compute_bitmap (klass
, default_bitmap
, sizeof (default_bitmap
) * 8, - (int)(sizeof (MonoObject
) / sizeof (gpointer
)), &max_set
, FALSE
);
4039 size
= mono_type_size (type
->type
, &align
);
4040 tls_offset
= mono_alloc_special_static_data (SPECIAL_STATIC_THREAD
, size
, align
, (uintptr_t*)bitmap
, max_set
+ 1);
4041 if (bitmap
!= default_bitmap
)
4043 tlsrec
= g_new0 (MonoTlsDataRecord
, 1);
4044 tlsrec
->tls_offset
= tls_offset
;
4045 tlsrec
->size
= size
;
4046 mono_domain_lock (domain
);
4047 tlsrec
->next
= domain
->tlsrec_list
;
4048 domain
->tlsrec_list
= tlsrec
;
4049 mono_domain_unlock (domain
);
4054 destroy_tls (MonoDomain
*domain
, uint32_t tls_offset
)
4056 MonoTlsDataRecord
*prev
= NULL
;
4057 MonoTlsDataRecord
*cur
;
4060 mono_domain_lock (domain
);
4061 cur
= domain
->tlsrec_list
;
4063 if (cur
->tls_offset
== tls_offset
) {
4065 prev
->next
= cur
->next
;
4067 domain
->tlsrec_list
= cur
->next
;
4075 mono_domain_unlock (domain
);
4077 mono_special_static_data_free_slot (tls_offset
, size
);
4081 mono_thread_destroy_tls (uint32_t tls_offset
)
4083 destroy_tls (mono_domain_get (), tls_offset
);
4087 * This is just to ensure cleanup: the finalizers should have taken care, so this is not perf-critical.
4090 mono_thread_destroy_domain_tls (MonoDomain
*domain
)
4092 while (domain
->tlsrec_list
)
4093 destroy_tls (domain
, domain
->tlsrec_list
->tls_offset
);
4096 static MonoClassField
*local_slots
= NULL
;
4099 /* local tls data to get locals_slot from a thread */
4102 /* index in the locals_slot array */
4107 clear_local_slot (gpointer key
, gpointer value
, gpointer user_data
)
4109 LocalSlotID
*sid
= user_data
;
4110 MonoInternalThread
*thread
= (MonoInternalThread
*)value
;
4111 MonoArray
*slots_array
;
4113 * the static field is stored at: ((char*) thread->static_data [idx]) + (offset & 0xffffff);
4114 * it is for the right domain, so we need to check if it is allocated an initialized
4115 * for the current thread.
4117 /*g_print ("handling thread %p\n", thread);*/
4118 if (!thread
->static_data
|| !thread
->static_data
[sid
->idx
])
4120 slots_array
= *(MonoArray
**)(((char*) thread
->static_data
[sid
->idx
]) + (sid
->offset
& 0xffffff));
4121 if (!slots_array
|| sid
->slot
>= mono_array_length (slots_array
))
4123 mono_array_set (slots_array
, MonoObject
*, sid
->slot
, NULL
);
4127 mono_thread_free_local_slot_values (int slot
, MonoBoolean thread_local
)
4135 local_slots
= mono_class_get_field_from_name (mono_defaults
.thread_class
, "local_slots");
4137 g_warning ("local_slots field not found in Thread class");
4141 domain
= mono_domain_get ();
4142 mono_domain_lock (domain
);
4143 if (domain
->special_static_fields
)
4144 addr
= g_hash_table_lookup (domain
->special_static_fields
, local_slots
);
4145 mono_domain_unlock (domain
);
4148 /*g_print ("freeing slot %d at %p\n", slot, addr);*/
4149 sid
.offset
= GPOINTER_TO_UINT (addr
);
4150 sid
.offset
&= 0x7fffffff;
4151 sid
.idx
= (sid
.offset
>> 24) - 1;
4152 mono_threads_lock ();
4153 mono_g_hash_table_foreach (threads
, clear_local_slot
, &sid
);
4154 mono_threads_unlock ();
4156 /* FIXME: clear the slot for MonoAppContexts, too */
4161 static void CALLBACK
dummy_apc (ULONG_PTR param
)
4167 * mono_thread_execute_interruption
4169 * Performs the operation that the requested thread state requires (abort,
4172 static MonoException
*
4173 mono_thread_execute_interruption (MonoInternalThread
*thread
)
4175 LOCK_THREAD (thread
);
4177 /* MonoThread::interruption_requested can only be changed with atomics */
4178 if (InterlockedCompareExchange (&thread
->interruption_requested
, FALSE
, TRUE
)) {
4179 /* this will consume pending APC calls */
4181 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE
);
4183 InterlockedDecrement (&thread_interruption_requested
);
4184 /* Clear the interrupted flag of the thread so it can wait again */
4185 mono_thread_info_clear_interruption ();
4188 if ((thread
->state
& ThreadState_AbortRequested
) != 0) {
4189 UNLOCK_THREAD (thread
);
4190 if (thread
->abort_exc
== NULL
) {
4192 * This might be racy, but it has to be called outside the lock
4193 * since it calls managed code.
4195 MONO_OBJECT_SETREF (thread
, abort_exc
, mono_get_exception_thread_abort ());
4197 return thread
->abort_exc
;
4199 else if ((thread
->state
& ThreadState_SuspendRequested
) != 0) {
4200 self_suspend_internal (thread
);
4203 else if ((thread
->state
& ThreadState_StopRequested
) != 0) {
4204 /* FIXME: do this through the JIT? */
4206 UNLOCK_THREAD (thread
);
4208 mono_thread_exit ();
4210 } else if (thread
->pending_exception
) {
4213 exc
= thread
->pending_exception
;
4214 thread
->pending_exception
= NULL
;
4216 UNLOCK_THREAD (thread
);
4218 } else if (thread
->thread_interrupt_requested
) {
4220 thread
->thread_interrupt_requested
= FALSE
;
4221 UNLOCK_THREAD (thread
);
4223 return(mono_get_exception_thread_interrupted ());
4226 UNLOCK_THREAD (thread
);
4232 * mono_thread_request_interruption
4234 * A signal handler can call this method to request the interruption of a
4235 * thread. The result of the interruption will depend on the current state of
4236 * the thread. If the result is an exception that needs to be throw, it is
4237 * provided as return value.
4240 mono_thread_request_interruption (gboolean running_managed
)
4242 MonoInternalThread
*thread
= mono_thread_internal_current ();
4244 /* The thread may already be stopping */
4249 if (thread
->interrupt_on_stop
&&
4250 thread
->state
& ThreadState_StopRequested
&&
4251 thread
->state
& ThreadState_Background
)
4255 if (InterlockedCompareExchange (&thread
->interruption_requested
, 1, 0) == 1)
4257 InterlockedIncrement (&thread_interruption_requested
);
4259 if (!running_managed
|| is_running_protected_wrapper ()) {
4260 /* Can't stop while in unmanaged code. Increase the global interruption
4261 request count. When exiting the unmanaged method the count will be
4262 checked and the thread will be interrupted. */
4264 if (mono_thread_notify_pending_exc_fn
&& !running_managed
)
4265 /* The JIT will notify the thread about the interruption */
4266 /* This shouldn't take any locks */
4267 mono_thread_notify_pending_exc_fn (NULL
);
4269 /* this will awake the thread if it is in WaitForSingleObject
4271 /* Our implementation of this function ignores the func argument */
4273 QueueUserAPC ((PAPCFUNC
)dummy_apc
, thread
->handle
, (ULONG_PTR
)NULL
);
4275 mono_thread_info_self_interrupt ();
4280 return mono_thread_execute_interruption (thread
);
4284 /*This function should be called by a thread after it has exited all of
4285 * its handle blocks at interruption time.*/
4287 mono_thread_resume_interruption (void)
4289 MonoInternalThread
*thread
= mono_thread_internal_current ();
4290 gboolean still_aborting
;
4292 /* The thread may already be stopping */
4296 LOCK_THREAD (thread
);
4297 still_aborting
= (thread
->state
& ThreadState_AbortRequested
) != 0;
4298 UNLOCK_THREAD (thread
);
4300 /*This can happen if the protected block called Thread::ResetAbort*/
4301 if (!still_aborting
)
4304 if (InterlockedCompareExchange (&thread
->interruption_requested
, 1, 0) == 1)
4306 InterlockedIncrement (&thread_interruption_requested
);
4308 mono_thread_info_self_interrupt ();
4310 return mono_thread_execute_interruption (thread
);
4313 gboolean
mono_thread_interruption_requested ()
4315 if (thread_interruption_requested
) {
4316 MonoInternalThread
*thread
= mono_thread_internal_current ();
4317 /* The thread may already be stopping */
4319 return (thread
->interruption_requested
);
4324 static MonoException
*
4325 mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection
)
4327 MonoInternalThread
*thread
= mono_thread_internal_current ();
4329 /* The thread may already be stopping */
4333 if (thread
->interruption_requested
&& (bypass_abort_protection
|| !is_running_protected_wrapper ())) {
4334 MonoException
* exc
= mono_thread_execute_interruption (thread
);
4342 * Performs the interruption of the current thread, if one has been requested,
4343 * and the thread is not running a protected wrapper.
4344 * Return the exception which needs to be thrown, if any.
4347 mono_thread_interruption_checkpoint (void)
4349 return mono_thread_interruption_checkpoint_request (FALSE
);
4353 * Performs the interruption of the current thread, if one has been requested.
4354 * Return the exception which needs to be thrown, if any.
4357 mono_thread_force_interruption_checkpoint_noraise (void)
4359 return mono_thread_interruption_checkpoint_request (TRUE
);
4363 * Performs the interruption of the current thread, if one has been requested.
4364 * Throw the exception which needs to be thrown, if any.
4367 mono_thread_force_interruption_checkpoint (void)
4371 ex
= mono_thread_interruption_checkpoint_request (TRUE
);
4373 mono_raise_exception (ex
);
4377 * mono_thread_get_and_clear_pending_exception:
4379 * Return any pending exceptions for the current thread and clear it as a side effect.
4382 mono_thread_get_and_clear_pending_exception (void)
4384 MonoInternalThread
*thread
= mono_thread_internal_current ();
4386 /* The thread may already be stopping */
4390 if (thread
->interruption_requested
&& !is_running_protected_wrapper ()) {
4391 return mono_thread_execute_interruption (thread
);
4394 if (thread
->pending_exception
) {
4395 MonoException
*exc
= thread
->pending_exception
;
4397 thread
->pending_exception
= NULL
;
4405 * mono_set_pending_exception:
4407 * Set the pending exception of the current thread to EXC.
4408 * The exception will be thrown when execution returns to managed code.
4411 mono_set_pending_exception (MonoException
*exc
)
4413 MonoInternalThread
*thread
= mono_thread_internal_current ();
4415 /* The thread may already be stopping */
4419 MONO_OBJECT_SETREF (thread
, pending_exception
, exc
);
4421 mono_thread_request_interruption (FALSE
);
4425 * mono_thread_interruption_request_flag:
4427 * Returns the address of a flag that will be non-zero if an interruption has
4428 * been requested for a thread. The thread to interrupt may not be the current
4429 * thread, so an additional call to mono_thread_interruption_requested() or
4430 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4433 gint32
* mono_thread_interruption_request_flag ()
4435 return &thread_interruption_requested
;
4439 mono_thread_init_apartment_state (void)
4442 MonoInternalThread
* thread
= mono_thread_internal_current ();
4444 /* Positive return value indicates success, either
4445 * S_OK if this is first CoInitialize call, or
4446 * S_FALSE if CoInitialize already called, but with same
4447 * threading model. A negative value indicates failure,
4448 * probably due to trying to change the threading model.
4450 if (CoInitializeEx(NULL
, (thread
->apartment_state
== ThreadApartmentState_STA
)
4451 ? COINIT_APARTMENTTHREADED
4452 : COINIT_MULTITHREADED
) < 0) {
4453 thread
->apartment_state
= ThreadApartmentState_Unknown
;
4459 mono_thread_cleanup_apartment_state (void)
4462 MonoInternalThread
* thread
= mono_thread_internal_current ();
4464 if (thread
&& thread
->apartment_state
!= ThreadApartmentState_Unknown
) {
4471 mono_thread_set_state (MonoInternalThread
*thread
, MonoThreadState state
)
4473 LOCK_THREAD (thread
);
4474 thread
->state
|= state
;
4475 UNLOCK_THREAD (thread
);
4479 mono_thread_clr_state (MonoInternalThread
*thread
, MonoThreadState state
)
4481 LOCK_THREAD (thread
);
4482 thread
->state
&= ~state
;
4483 UNLOCK_THREAD (thread
);
4487 mono_thread_test_state (MonoInternalThread
*thread
, MonoThreadState test
)
4489 gboolean ret
= FALSE
;
4491 LOCK_THREAD (thread
);
4493 if ((thread
->state
& test
) != 0) {
4497 UNLOCK_THREAD (thread
);
4502 //static MonoClassField *execution_context_field;
4505 get_execution_context_addr (void)
4507 MonoDomain
*domain
= mono_domain_get ();
4508 guint32 offset
= domain
->execution_context_field_offset
;
4511 MonoClassField
*field
= mono_class_get_field_from_name (mono_defaults
.thread_class
, "_ec");
4514 g_assert (mono_class_try_get_vtable (domain
, mono_defaults
.appdomain_class
));
4516 mono_domain_lock (domain
);
4517 offset
= GPOINTER_TO_UINT (g_hash_table_lookup (domain
->special_static_fields
, field
));
4518 mono_domain_unlock (domain
);
4521 domain
->execution_context_field_offset
= offset
;
4524 return (MonoObject
**) mono_get_special_static_data (offset
);
4528 mono_thread_get_execution_context (void)
4530 return *get_execution_context_addr ();
4534 mono_thread_set_execution_context (MonoObject
*ec
)
4536 *get_execution_context_addr () = ec
;
4539 static gboolean has_tls_get
= FALSE
;
4542 mono_runtime_set_has_tls_get (gboolean val
)
4548 mono_runtime_has_tls_get (void)
4554 mono_thread_kill (MonoInternalThread
*thread
, int signal
)
4556 #ifdef __native_client__
4557 /* Workaround pthread_kill abort() in NaCl glibc. */
4560 #if defined (HOST_WIN32) || !defined (HAVE_SIGACTION)
4561 /* Win32 uses QueueUserAPC and callers of this are guarded */
4562 g_assert_not_reached ();
4564 # ifdef PTHREAD_POINTER_ID
4565 return pthread_kill ((gpointer
)(gsize
)(thread
->tid
), mono_thread_get_abort_signal ());
4567 # ifdef USE_TKILL_ON_ANDROID
4568 if (thread
->android_tid
!= 0) {
4570 int old_errno
= errno
;
4572 ret
= tkill ((pid_t
) thread
->android_tid
, signal
);
4581 return pthread_kill (thread
->tid
, mono_thread_get_abort_signal ());
4583 return pthread_kill (thread
->tid
, mono_thread_get_abort_signal ());
4590 self_interrupt_thread (void *_unused
)
4592 MonoThreadInfo
*info
= mono_thread_info_current ();
4593 MonoException
*exc
= mono_thread_execute_interruption (mono_thread_internal_current ());
4594 if (exc
) /*We must use _with_context since we didn't trampoline into the runtime*/
4595 mono_raise_exception_with_context (exc
, &info
->thread_saved_state
[ASYNC_SUSPEND_STATE_INDEX
].ctx
); /* FIXME using thread_saved_state [ASYNC_SUSPEND_STATE_INDEX] can race with another suspend coming in. */
4596 g_assert_not_reached (); /*this MUST not happen since we can't resume from an async call*/
4600 mono_jit_info_match (MonoJitInfo
*ji
, gpointer ip
)
4604 return ji
->code_start
<= ip
&& (char*)ip
< (char*)ji
->code_start
+ ji
->code_size
;
4608 last_managed (MonoStackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
4610 MonoJitInfo
**dest
= data
;
4616 mono_thread_info_get_last_managed (MonoThreadInfo
*info
)
4618 MonoJitInfo
*ji
= NULL
;
4621 mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed
, mono_thread_info_get_suspend_state (info
), MONO_UNWIND_SIGNAL_SAFE
, &ji
);
4626 MonoInternalThread
*thread
;
4627 gboolean install_async_abort
;
4628 gpointer interrupt_handle
;
4631 static SuspendThreadResult
4632 abort_thread_critical (MonoThreadInfo
*info
, gpointer ud
)
4634 AbortThreadData
*data
= ud
;
4635 MonoInternalThread
*thread
= data
->thread
;
4636 MonoJitInfo
*ji
= NULL
;
4637 gboolean protected_wrapper
;
4638 gboolean running_managed
;
4640 if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info
)))
4641 return MonoResumeThread
;
4643 /*someone is already interrupting it*/
4644 if (InterlockedCompareExchange (&thread
->interruption_requested
, 1, 0) == 1)
4645 return MonoResumeThread
;
4647 InterlockedIncrement (&thread_interruption_requested
);
4649 ji
= mono_thread_info_get_last_managed (info
);
4650 protected_wrapper
= ji
&& mono_threads_is_critical_method (mono_jit_info_get_method (ji
));
4651 running_managed
= mono_jit_info_match (ji
, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info
)->ctx
));
4653 if (!protected_wrapper
&& running_managed
) {
4654 /*We are in managed code*/
4655 /*Set the thread to call */
4656 if (data
->install_async_abort
)
4657 mono_thread_info_setup_async_call (info
, self_interrupt_thread
, NULL
);
4658 return MonoResumeThread
;
4660 if (mono_thread_notify_pending_exc_fn
)
4661 /* The JIT will notify the thread about the interruption */
4662 mono_thread_notify_pending_exc_fn (info
);
4665 * This will cause waits to be broken.
4666 * It will also prevent the thread from entering a wait, so if the thread returns
4667 * from the wait before it receives the abort signal, it will just spin in the wait
4668 * functions in the io-layer until the signal handler calls QueueUserAPC which will
4671 data
->interrupt_handle
= mono_thread_info_prepare_interrupt (thread
->handle
);
4672 return MonoResumeThread
;
4677 abort_thread_internal (MonoInternalThread
*thread
, gboolean can_raise_exception
, gboolean install_async_abort
)
4679 AbortThreadData data
= { 0 };
4680 data
.thread
= thread
;
4681 data
.install_async_abort
= install_async_abort
;
4683 if (!mono_thread_info_new_interrupt_enabled ()) {
4684 signal_thread_state_change (thread
);
4689 FIXME this is insanely broken, it doesn't cause interruption to happen
4690 synchronously since passing FALSE to mono_thread_request_interruption makes sure it returns NULL
4692 if (thread
== mono_thread_internal_current ()) {
4693 /* Do it synchronously */
4694 MonoException
*exc
= mono_thread_request_interruption (can_raise_exception
);
4696 mono_raise_exception (exc
);
4697 mono_thread_info_interrupt (thread
->handle
);
4701 mono_thread_info_safe_suspend_and_run ((MonoNativeThreadId
)(gsize
)thread
->tid
, TRUE
, abort_thread_critical
, &data
);
4702 if (data
.interrupt_handle
)
4703 mono_thread_info_finish_interrupt (data
.interrupt_handle
);
4704 /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4708 MonoInternalThread
*thread
;
4710 gpointer interrupt_handle
;
4711 } SuspendThreadData
;
4713 static SuspendThreadResult
4714 suspend_thread_critical (MonoThreadInfo
*info
, gpointer ud
)
4716 SuspendThreadData
*data
= ud
;
4717 MonoInternalThread
*thread
= data
->thread
;
4718 MonoJitInfo
*ji
= NULL
;
4719 gboolean protected_wrapper
;
4720 gboolean running_managed
;
4722 ji
= mono_thread_info_get_last_managed (info
);
4723 protected_wrapper
= ji
&& !ji
->async
&& mono_threads_is_critical_method (mono_jit_info_get_method (ji
));
4724 running_managed
= mono_jit_info_match (ji
, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info
)->ctx
));
4726 if (running_managed
&& !protected_wrapper
) {
4727 thread
->state
&= ~ThreadState_SuspendRequested
;
4728 thread
->state
|= ThreadState_Suspended
;
4729 return KeepSuspended
;
4731 if (InterlockedCompareExchange (&thread
->interruption_requested
, 1, 0) == 0)
4732 InterlockedIncrement (&thread_interruption_requested
);
4733 if (data
->interrupt
)
4734 data
->interrupt_handle
= mono_thread_info_prepare_interrupt (thread
->handle
);
4736 if (mono_thread_notify_pending_exc_fn
&& !running_managed
)
4737 /* The JIT will notify the thread about the interruption */
4738 mono_thread_notify_pending_exc_fn (info
);
4739 return MonoResumeThread
;
4744 suspend_thread_internal (MonoInternalThread
*thread
, gboolean interrupt
)
4746 if (!mono_thread_info_new_interrupt_enabled ()) {
4747 signal_thread_state_change (thread
);
4751 LOCK_THREAD (thread
);
4752 if (thread
== mono_thread_internal_current ()) {
4753 mono_thread_info_begin_self_suspend ();
4754 //XXX replace this with better named functions
4755 thread
->state
&= ~ThreadState_SuspendRequested
;
4756 thread
->state
|= ThreadState_Suspended
;
4757 UNLOCK_THREAD (thread
);
4758 mono_thread_info_end_self_suspend ();
4760 SuspendThreadData data
= { 0 };
4761 data
.thread
= thread
;
4762 data
.interrupt
= interrupt
;
4764 mono_thread_info_safe_suspend_and_run ((MonoNativeThreadId
)(gsize
)thread
->tid
, interrupt
, suspend_thread_critical
, &data
);
4765 if (data
.interrupt_handle
)
4766 mono_thread_info_finish_interrupt (data
.interrupt_handle
);
4767 UNLOCK_THREAD (thread
);
4771 /*This is called with @thread synch_cs held and it must release it*/
4773 self_suspend_internal (MonoInternalThread
*thread
)
4775 if (!mono_thread_info_new_interrupt_enabled ()) {
4776 thread
->state
&= ~ThreadState_SuspendRequested
;
4777 thread
->state
|= ThreadState_Suspended
;
4778 thread
->suspend_event
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
4779 if (thread
->suspend_event
== NULL
) {
4780 UNLOCK_THREAD (thread
);
4783 if (thread
->suspended_event
)
4784 SetEvent (thread
->suspended_event
);
4786 UNLOCK_THREAD (thread
);
4788 if (shutting_down
) {
4789 /* After we left the lock, the runtime might shut down so everything becomes invalid */
4794 WaitForSingleObject (thread
->suspend_event
, INFINITE
);
4796 LOCK_THREAD (thread
);
4798 CloseHandle (thread
->suspend_event
);
4799 thread
->suspend_event
= NULL
;
4800 thread
->state
&= ~ThreadState_Suspended
;
4802 /* The thread that requested the resume will have replaced this event
4803 * and will be waiting for it
4805 SetEvent (thread
->resume_event
);
4807 UNLOCK_THREAD (thread
);
4811 mono_thread_info_begin_self_suspend ();
4812 thread
->state
&= ~ThreadState_SuspendRequested
;
4813 thread
->state
|= ThreadState_Suspended
;
4814 UNLOCK_THREAD (thread
);
4815 mono_thread_info_end_self_suspend ();
4818 /*This is called with @thread synch_cs held and it must release it*/
4820 resume_thread_internal (MonoInternalThread
*thread
)
4822 if (!mono_thread_info_new_interrupt_enabled ()) {
4823 thread
->resume_event
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
4824 if (thread
->resume_event
== NULL
) {
4825 UNLOCK_THREAD (thread
);
4829 /* Awake the thread */
4830 SetEvent (thread
->suspend_event
);
4832 UNLOCK_THREAD (thread
);
4834 /* Wait for the thread to awake */
4835 WaitForSingleObject (thread
->resume_event
, INFINITE
);
4836 CloseHandle (thread
->resume_event
);
4837 thread
->resume_event
= NULL
;
4841 UNLOCK_THREAD (thread
);
4842 /* Awake the thread */
4843 if (!mono_thread_info_resume ((MonoNativeThreadId
)(gpointer
)(gsize
)thread
->tid
))
4845 LOCK_THREAD (thread
);
4846 thread
->state
&= ~ThreadState_Suspended
;
4847 UNLOCK_THREAD (thread
);
4853 * mono_thread_is_foreign:
4854 * @thread: the thread to query
4856 * This function allows one to determine if a thread was created by the mono runtime and has
4857 * a well defined lifecycle or it's a foreigh one, created by the native environment.
4859 * Returns: true if @thread was not created by the runtime.
4862 mono_thread_is_foreign (MonoThread
*thread
)
4864 MonoThreadInfo
*info
= thread
->internal_thread
->thread_info
;
4865 return info
->runtime_thread
== FALSE
;
4869 * mono_add_joinable_thread:
4871 * Add TID to the list of joinable threads.
4872 * LOCKING: Acquires the threads lock.
4875 mono_threads_add_joinable_thread (gpointer tid
)
4879 * We cannot detach from threads because it causes problems like
4880 * 2fd16f60/r114307. So we collect them and join them when
4881 * we have time (in he finalizer thread).
4883 joinable_threads_lock ();
4884 if (!joinable_threads
)
4885 joinable_threads
= g_hash_table_new (NULL
, NULL
);
4886 g_hash_table_insert (joinable_threads
, tid
, tid
);
4887 joinable_thread_count
++;
4888 joinable_threads_unlock ();
4890 mono_gc_finalize_notify ();
4895 * mono_threads_join_threads:
4897 * Join all joinable threads. This is called from the finalizer thread.
4898 * LOCKING: Acquires the threads lock.
4901 mono_threads_join_threads (void)
4904 GHashTableIter iter
;
4911 if (!joinable_thread_count
)
4915 joinable_threads_lock ();
4917 if (g_hash_table_size (joinable_threads
)) {
4918 g_hash_table_iter_init (&iter
, joinable_threads
);
4919 g_hash_table_iter_next (&iter
, &key
, (void**)&tid
);
4920 thread
= (pthread_t
)tid
;
4921 g_hash_table_remove (joinable_threads
, key
);
4922 joinable_thread_count
--;
4925 joinable_threads_unlock ();
4927 if (thread
!= pthread_self ())
4928 /* This shouldn't block */
4929 pthread_join (thread
, NULL
);
4940 * Wait for thread TID to exit.
4941 * LOCKING: Acquires the threads lock.
4944 mono_thread_join (gpointer tid
)
4948 gboolean found
= FALSE
;
4950 joinable_threads_lock ();
4951 if (!joinable_threads
)
4952 joinable_threads
= g_hash_table_new (NULL
, NULL
);
4953 if (g_hash_table_lookup (joinable_threads
, tid
)) {
4954 g_hash_table_remove (joinable_threads
, tid
);
4955 joinable_thread_count
--;
4958 joinable_threads_unlock ();
4961 thread
= (pthread_t
)tid
;
4962 pthread_join (thread
, NULL
);