3 * Thread support internal calls
6 * Dick Porter (dick@ximian.com)
7 * Paolo Molaro (lupus@ximian.com)
8 * Patrik Torstensson (patrik.torstensson@labs2.com)
10 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
11 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
12 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
13 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
21 #include <mono/metadata/object.h>
22 #include <mono/metadata/domain-internals.h>
23 #include <mono/metadata/profiler-private.h>
24 #include <mono/metadata/threads.h>
25 #include <mono/metadata/threads-types.h>
26 #include <mono/metadata/exception.h>
27 #include <mono/metadata/environment.h>
28 #include <mono/metadata/monitor.h>
29 #include <mono/metadata/mono-hash-internals.h>
30 #include <mono/metadata/gc-internals.h>
31 #include <mono/metadata/marshal.h>
32 #include <mono/metadata/runtime.h>
33 #include <mono/metadata/object-internals.h>
34 #include <mono/metadata/debug-internals.h>
35 #include <mono/utils/monobitset.h>
36 #include <mono/utils/mono-compiler.h>
37 #include <mono/utils/mono-mmap.h>
38 #include <mono/utils/mono-membar.h>
39 #include <mono/utils/mono-time.h>
40 #include <mono/utils/mono-threads.h>
41 #include <mono/utils/mono-threads-coop.h>
42 #include <mono/utils/mono-tls.h>
43 #include <mono/utils/atomic.h>
44 #include <mono/utils/mono-memory-model.h>
45 #include <mono/utils/mono-error-internals.h>
46 #include <mono/utils/os-event.h>
47 #include <mono/utils/mono-threads-debug.h>
48 #include <mono/utils/unlocked.h>
49 #include <mono/metadata/w32handle.h>
50 #include <mono/metadata/w32event.h>
51 #include <mono/metadata/w32mutex.h>
53 #include <mono/metadata/reflection-internals.h>
54 #include <mono/metadata/abi-details.h>
55 #include <mono/metadata/w32error.h>
56 #include <mono/utils/w32api.h>
57 #include <mono/utils/mono-os-wait.h>
58 #include <mono/metadata/exception-internals.h>
59 #include <mono/utils/mono-state.h>
60 #include <mono/metadata/w32subset.h>
62 #ifdef HAVE_SYS_WAIT_H
70 #if defined(HOST_WIN32)
72 #include <sys/timeb.h>
74 mono_native_thread_join_handle (HANDLE thread_handle
, gboolean close_handle
);
77 #if defined(HOST_FUCHSIA)
78 #include <zircon/syscalls.h>
81 #if defined(HOST_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64)
82 #define USE_TKILL_ON_ANDROID 1
88 #ifdef USE_TKILL_ON_ANDROID
89 extern int tkill (pid_t tid
, int signal
);
93 #include "icall-decl.h"
95 /*#define THREAD_DEBUG(a) do { a; } while (0)*/
96 #define THREAD_DEBUG(a)
97 /*#define THREAD_WAIT_DEBUG(a) do { a; } while (0)*/
98 #define THREAD_WAIT_DEBUG(a)
99 /*#define LIBGC_DEBUG(a) do { a; } while (0)*/
100 #define LIBGC_DEBUG(a)
102 #define SPIN_TRYLOCK(i) (mono_atomic_cas_i32 (&(i), 1, 0) == 0)
103 #define SPIN_LOCK(i) do { \
104 if (SPIN_TRYLOCK (i)) \
108 #define SPIN_UNLOCK(i) i = 0
110 #define LOCK_THREAD(thread) lock_thread((thread))
111 #define UNLOCK_THREAD(thread) unlock_thread((thread))
123 typedef struct _StaticDataFreeList StaticDataFreeList
;
124 struct _StaticDataFreeList
{
125 StaticDataFreeList
*next
;
133 StaticDataFreeList
*freelist
;
136 /* Controls access to the 'threads' hash table */
137 static void mono_threads_lock (void);
138 static void mono_threads_unlock (void);
139 static MonoCoopMutex threads_mutex
;
141 /* Controls access to the 'joinable_threads' hash table */
142 #define joinable_threads_lock() mono_coop_mutex_lock (&joinable_threads_mutex)
143 #define joinable_threads_unlock() mono_coop_mutex_unlock (&joinable_threads_mutex)
144 static MonoCoopMutex joinable_threads_mutex
;
146 /* Holds current status of static data heap */
147 static StaticDataInfo thread_static_info
;
148 static StaticDataInfo context_static_info
;
150 /* The hash of existing threads (key is thread ID, value is
151 * MonoInternalThread*) that need joining before exit
153 static MonoGHashTable
*threads
=NULL
;
155 /* List of app context GC handles.
156 * Added to from mono_threads_register_app_context ().
158 static GHashTable
*contexts
= NULL
;
160 /* Cleanup queue for contexts. */
161 static MonoReferenceQueue
*context_queue
;
164 * Threads which are starting up and they are not in the 'threads' hash yet.
165 * When mono_thread_attach_internal is called for a thread, it will be removed from this hash table.
166 * Protected by mono_threads_lock ().
168 static MonoGHashTable
*threads_starting_up
= NULL
;
171 /* Protected by the threads lock */
172 static GHashTable
*joinable_threads
;
173 static gint32 joinable_thread_count
;
175 /* mono_threads_join_threads will take threads from joinable_threads list and wait for them. */
176 /* When this happens, the tid is not on the list anymore so mono_thread_join assumes the thread has complete */
177 /* and will return back to the caller. This could cause a race since caller of join assumes thread has completed */
178 /* and on some OS it could cause errors. Keeping the tid's currently pending a native thread join call */
179 /* in a separate table (only affecting callers interested in this internal join detail) and look at that table in mono_thread_join */
180 /* will close this race. */
181 static GHashTable
*pending_native_thread_join_calls
;
182 static MonoCoopCond pending_native_thread_join_calls_event
;
184 static GHashTable
*pending_joinable_threads
;
185 static gint32 pending_joinable_thread_count
;
187 static MonoCoopCond zero_pending_joinable_thread_event
;
189 static void threads_add_pending_joinable_runtime_thread (MonoThreadInfo
*mono_thread_info
);
190 static gboolean
threads_wait_pending_joinable_threads (uint32_t timeout
);
191 static gchar
* thread_dump_dir
= NULL
;
193 #define SET_CURRENT_OBJECT mono_tls_set_thread
194 #define GET_CURRENT_OBJECT mono_tls_get_thread
196 /* function called at thread start */
197 static MonoThreadStartCB mono_thread_start_cb
= NULL
;
199 /* function called at thread attach */
200 static MonoThreadAttachCB mono_thread_attach_cb
= NULL
;
202 /* function called at thread cleanup */
203 static MonoThreadCleanupFunc mono_thread_cleanup_fn
= NULL
;
205 /* The default stack size for each thread */
206 static guint32 default_stacksize
= 0;
207 #define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize)
209 static void context_adjust_static_data (MonoAppContextHandle ctx
);
210 static void mono_free_static_data (gpointer
* static_data
);
211 static void mono_init_static_data_info (StaticDataInfo
*static_data
);
212 static guint32
mono_alloc_static_data_slot (StaticDataInfo
*static_data
, guint32 size
, guint32 align
);
213 static gboolean
mono_thread_resume (MonoInternalThread
* thread
);
214 static void async_abort_internal (MonoInternalThread
*thread
, gboolean install_async_abort
);
215 static void self_abort_internal (MonoError
*error
);
216 static void async_suspend_internal (MonoInternalThread
*thread
, gboolean interrupt
);
217 static void self_suspend_internal (void);
220 mono_thread_set_interruption_requested_flags (MonoInternalThread
*thread
, gboolean sync
);
223 mono_set_pending_exception_handle (MonoExceptionHandle exc
);
225 static MonoException
*
226 mono_thread_execute_interruption_ptr (void);
229 mono_thread_execute_interruption_void (void);
232 mono_thread_execute_interruption (MonoExceptionHandle
*pexc
);
234 static void ref_stack_destroy (gpointer rs
);
236 #if SIZEOF_VOID_P == 4
237 /* Spin lock for unaligned InterlockedXXX 64 bit functions on 32bit platforms. */
238 #define mono_interlocked_lock() mono_os_mutex_lock (&interlocked_mutex)
239 #define mono_interlocked_unlock() mono_os_mutex_unlock (&interlocked_mutex)
240 static mono_mutex_t interlocked_mutex
;
243 /* global count of thread interruptions requested */
244 static gint32 thread_interruption_requested
= 0;
246 /* Event signaled when a thread changes its background mode */
247 static MonoOSEvent background_change_event
;
249 static gboolean shutting_down
= FALSE
;
251 static gint32 managed_thread_id_counter
= 0;
254 mono_threads_lock (void)
256 mono_locks_coop_acquire (&threads_mutex
, ThreadsLock
);
260 mono_threads_unlock (void)
262 mono_locks_coop_release (&threads_mutex
, ThreadsLock
);
267 get_next_managed_thread_id (void)
269 return mono_atomic_inc_i32 (&managed_thread_id_counter
);
273 * We separate interruptions/exceptions into either sync (they can be processed anytime,
274 * normally as soon as they are set, and are set by the same thread) and async (they can't
275 * be processed inside abort protected blocks and are normally set by other threads). We
276 * can have both a pending sync and async interruption. In this case, the sync exception is
277 * processed first. Since we clean sync flag first, mono_thread_execute_interruption must
278 * also handle all sync type exceptions before the async type exceptions.
281 INTERRUPT_SYNC_REQUESTED_BIT
= 0x1,
282 INTERRUPT_ASYNC_REQUESTED_BIT
= 0x2,
283 INTERRUPT_REQUESTED_MASK
= 0x3,
284 ABORT_PROT_BLOCK_SHIFT
= 2,
285 ABORT_PROT_BLOCK_BITS
= 8,
286 ABORT_PROT_BLOCK_MASK
= (((1 << ABORT_PROT_BLOCK_BITS
) - 1) << ABORT_PROT_BLOCK_SHIFT
)
290 mono_thread_get_abort_prot_block_count (MonoInternalThread
*thread
)
292 gsize state
= thread
->thread_state
;
293 return (state
& ABORT_PROT_BLOCK_MASK
) >> ABORT_PROT_BLOCK_SHIFT
;
297 mono_threads_is_current_thread_in_protected_block (void)
299 MonoInternalThread
*thread
= mono_thread_internal_current ();
301 return mono_thread_get_abort_prot_block_count (thread
) > 0;
305 mono_threads_begin_abort_protected_block (void)
307 MonoInternalThread
*thread
= mono_thread_internal_current ();
308 gsize old_state
, new_state
;
311 old_state
= thread
->thread_state
;
313 new_val
= ((old_state
& ABORT_PROT_BLOCK_MASK
) >> ABORT_PROT_BLOCK_SHIFT
) + 1;
314 //bounds check abort_prot_count
315 g_assert (new_val
> 0);
316 g_assert (new_val
< (1 << ABORT_PROT_BLOCK_BITS
));
318 new_state
= old_state
+ (1 << ABORT_PROT_BLOCK_SHIFT
);
319 } while (mono_atomic_cas_ptr ((volatile gpointer
*)&thread
->thread_state
, (gpointer
)new_state
, (gpointer
)old_state
) != (gpointer
)old_state
);
321 /* Defer async request since we won't be able to process until exiting the block */
322 if (new_val
== 1 && (new_state
& INTERRUPT_ASYNC_REQUESTED_BIT
)) {
323 mono_atomic_dec_i32 (&thread_interruption_requested
);
324 THREADS_INTERRUPT_DEBUG ("[%d] begin abort protected block old_state %ld new_state %ld, defer tir %d\n", thread
->small_id
, old_state
, new_state
, thread_interruption_requested
);
325 if (thread_interruption_requested
< 0)
326 g_warning ("bad thread_interruption_requested state");
328 THREADS_INTERRUPT_DEBUG ("[%d] begin abort protected block old_state %ld new_state %ld, tir %d\n", thread
->small_id
, old_state
, new_state
, thread_interruption_requested
);
333 mono_thread_state_has_interruption (gsize state
)
335 /* pending exception, self abort */
336 if (state
& INTERRUPT_SYNC_REQUESTED_BIT
)
339 /* abort, interruption, suspend */
340 if ((state
& INTERRUPT_ASYNC_REQUESTED_BIT
) && !(state
& ABORT_PROT_BLOCK_MASK
))
347 mono_threads_end_abort_protected_block (void)
349 MonoInternalThread
*thread
= mono_thread_internal_current ();
350 gsize old_state
, new_state
;
353 old_state
= thread
->thread_state
;
355 //bounds check abort_prot_count
356 new_val
= ((old_state
& ABORT_PROT_BLOCK_MASK
) >> ABORT_PROT_BLOCK_SHIFT
) - 1;
357 g_assert (new_val
>= 0);
358 g_assert (new_val
< (1 << ABORT_PROT_BLOCK_BITS
));
360 new_state
= old_state
- (1 << ABORT_PROT_BLOCK_SHIFT
);
361 } while (mono_atomic_cas_ptr ((volatile gpointer
*)&thread
->thread_state
, (gpointer
)new_state
, (gpointer
)old_state
) != (gpointer
)old_state
);
363 if (new_val
== 0 && (new_state
& INTERRUPT_ASYNC_REQUESTED_BIT
)) {
364 mono_atomic_inc_i32 (&thread_interruption_requested
);
365 THREADS_INTERRUPT_DEBUG ("[%d] end abort protected block old_state %ld new_state %ld, restore tir %d\n", thread
->small_id
, old_state
, new_state
, thread_interruption_requested
);
367 THREADS_INTERRUPT_DEBUG ("[%d] end abort protected block old_state %ld new_state %ld, tir %d\n", thread
->small_id
, old_state
, new_state
, thread_interruption_requested
);
370 return mono_thread_state_has_interruption (new_state
);
374 mono_thread_get_interruption_requested (MonoInternalThread
*thread
)
376 gsize state
= thread
->thread_state
;
378 return mono_thread_state_has_interruption (state
);
382 * Returns TRUE is there was a state change
383 * We clear a single interruption request, sync has priority.
386 mono_thread_clear_interruption_requested (MonoInternalThread
*thread
)
388 gsize old_state
, new_state
;
390 old_state
= thread
->thread_state
;
392 // no interruption to process
393 if (!(old_state
& INTERRUPT_SYNC_REQUESTED_BIT
) &&
394 (!(old_state
& INTERRUPT_ASYNC_REQUESTED_BIT
) || (old_state
& ABORT_PROT_BLOCK_MASK
)))
397 if (old_state
& INTERRUPT_SYNC_REQUESTED_BIT
)
398 new_state
= old_state
& ~INTERRUPT_SYNC_REQUESTED_BIT
;
400 new_state
= old_state
& ~INTERRUPT_ASYNC_REQUESTED_BIT
;
401 } while (mono_atomic_cas_ptr ((volatile gpointer
*)&thread
->thread_state
, (gpointer
)new_state
, (gpointer
)old_state
) != (gpointer
)old_state
);
403 mono_atomic_dec_i32 (&thread_interruption_requested
);
404 THREADS_INTERRUPT_DEBUG ("[%d] clear interruption old_state %ld new_state %ld, tir %d\n", thread
->small_id
, old_state
, new_state
, thread_interruption_requested
);
405 if (thread_interruption_requested
< 0)
406 g_warning ("bad thread_interruption_requested state");
411 mono_thread_clear_interruption_requested_handle (MonoInternalThreadHandle thread
)
413 // Internal threads are pinned so shallow coop/handle.
414 return mono_thread_clear_interruption_requested (mono_internal_thread_handle_ptr (thread
));
417 /* Returns TRUE is there was a state change and the interruption can be processed */
419 mono_thread_set_interruption_requested (MonoInternalThread
*thread
)
421 //always force when the current thread is doing it to itself.
422 gboolean sync
= thread
== mono_thread_internal_current ();
423 /* Normally synchronous interruptions can bypass abort protection. */
424 return mono_thread_set_interruption_requested_flags (thread
, sync
);
427 /* Returns TRUE if there was a state change and the interruption can be
428 * processed. This variant defers a self abort when inside an abort protected
429 * block. Normally this should only be done when a thread has received an
430 * outside indication that it should abort. (For example when the JIT sets a
431 * flag in an finally block.)
435 mono_thread_set_self_interruption_respect_abort_prot (void)
437 MonoInternalThread
*thread
= mono_thread_internal_current ();
438 /* N.B. Sets the ASYNC_REQUESTED_BIT for current this thread,
439 * which is unusual. */
440 return mono_thread_set_interruption_requested_flags (thread
, FALSE
);
443 /* Returns TRUE if there was a state change and the interruption can be processed. */
445 mono_thread_set_interruption_requested_flags (MonoInternalThread
*thread
, gboolean sync
)
447 gsize old_state
, new_state
;
449 old_state
= thread
->thread_state
;
452 if ((sync
&& (old_state
& INTERRUPT_SYNC_REQUESTED_BIT
)) ||
453 (!sync
&& (old_state
& INTERRUPT_ASYNC_REQUESTED_BIT
)))
457 new_state
= old_state
| INTERRUPT_SYNC_REQUESTED_BIT
;
459 new_state
= old_state
| INTERRUPT_ASYNC_REQUESTED_BIT
;
460 } while (mono_atomic_cas_ptr ((volatile gpointer
*)&thread
->thread_state
, (gpointer
)new_state
, (gpointer
)old_state
) != (gpointer
)old_state
);
462 if (sync
|| !(new_state
& ABORT_PROT_BLOCK_MASK
)) {
463 mono_atomic_inc_i32 (&thread_interruption_requested
);
464 THREADS_INTERRUPT_DEBUG ("[%d] set interruption on [%d] old_state %ld new_state %ld, tir %d\n", mono_thread_internal_current ()->small_id
, thread
->small_id
, old_state
, new_state
, thread_interruption_requested
);
466 THREADS_INTERRUPT_DEBUG ("[%d] set interruption on [%d] old_state %ld new_state %ld, tir deferred %d\n", mono_thread_internal_current ()->small_id
, thread
->small_id
, old_state
, new_state
, thread_interruption_requested
);
469 return sync
|| !(new_state
& ABORT_PROT_BLOCK_MASK
);
472 static inline MonoNativeThreadId
473 thread_get_tid (MonoInternalThread
*thread
)
475 /* We store the tid as a guint64 to keep the object layout constant between platforms */
476 return MONO_UINT_TO_NATIVE_THREAD_ID (thread
->tid
);
480 free_synch_cs (MonoCoopMutex
*synch_cs
)
483 mono_coop_mutex_destroy (synch_cs
);
488 free_longlived_thread_data (void *user_data
)
490 MonoLongLivedThreadData
*lltd
= (MonoLongLivedThreadData
*)user_data
;
491 free_synch_cs (lltd
->synch_cs
);
497 init_longlived_thread_data (MonoLongLivedThreadData
*lltd
)
499 mono_refcount_init (lltd
, free_longlived_thread_data
);
500 mono_refcount_inc (lltd
);
501 /* Initial refcount is 2: decremented once by
502 * mono_thread_detach_internal and once by the MonoInternalThread
503 * finalizer - whichever one happens later will deallocate. */
505 lltd
->synch_cs
= g_new0 (MonoCoopMutex
, 1);
506 mono_coop_mutex_init_recursive (lltd
->synch_cs
);
508 mono_memory_barrier ();
512 dec_longlived_thread_data (MonoLongLivedThreadData
*lltd
)
514 mono_refcount_dec (lltd
);
518 lock_thread (MonoInternalThread
*thread
)
520 g_assert (thread
->longlived
);
521 g_assert (thread
->longlived
->synch_cs
);
523 mono_coop_mutex_lock (thread
->longlived
->synch_cs
);
527 unlock_thread (MonoInternalThread
*thread
)
529 mono_coop_mutex_unlock (thread
->longlived
->synch_cs
);
533 lock_thread_handle (MonoInternalThreadHandle thread
)
535 lock_thread (mono_internal_thread_handle_ptr (thread
));
539 unlock_thread_handle (MonoInternalThreadHandle thread
)
541 unlock_thread (mono_internal_thread_handle_ptr (thread
));
544 static inline gboolean
545 is_appdomainunloaded_exception (MonoClass
*klass
)
547 #ifdef ENABLE_NETCORE
550 return klass
== mono_class_get_appdomain_unloaded_exception_class ();
554 static inline gboolean
555 is_threadabort_exception (MonoClass
*klass
)
557 return klass
== mono_defaults
.threadabortexception_class
;
561 * A special static data offset (guint32) consists of 3 parts:
563 * [0] 6-bit index into the array of chunks.
564 * [6] 25-bit offset into the array.
565 * [31] Bit indicating thread or context static.
570 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
581 } SpecialStaticOffset
;
583 #define SPECIAL_STATIC_OFFSET_TYPE_THREAD 0
584 #define SPECIAL_STATIC_OFFSET_TYPE_CONTEXT 1
587 MAKE_SPECIAL_STATIC_OFFSET (guint32 index
, guint32 offset
, guint32 type
)
589 SpecialStaticOffset special_static_offset
;
590 memset (&special_static_offset
, 0, sizeof (special_static_offset
));
591 special_static_offset
.fields
.index
= index
;
592 special_static_offset
.fields
.offset
= offset
;
593 special_static_offset
.fields
.type
= type
;
594 return special_static_offset
.raw
;
597 #define ACCESS_SPECIAL_STATIC_OFFSET(x,f) \
598 (((SpecialStaticOffset *) &(x))->fields.f)
601 get_thread_static_data (MonoInternalThread
*thread
, guint32 offset
)
603 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset
, type
) == SPECIAL_STATIC_OFFSET_TYPE_THREAD
);
605 int idx
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, index
);
606 int off
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, offset
);
608 return ((char *) thread
->static_data
[idx
]) + off
;
612 get_context_static_data (MonoAppContext
*ctx
, guint32 offset
)
614 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset
, type
) == SPECIAL_STATIC_OFFSET_TYPE_CONTEXT
);
616 int idx
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, index
);
617 int off
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, offset
);
619 return ((char *) ctx
->static_data
[idx
]) + off
;
623 get_current_thread_ptr_for_domain (MonoDomain
*domain
, MonoInternalThread
*thread
)
625 static MonoClassField
*current_thread_field
= NULL
;
629 if (!current_thread_field
) {
630 current_thread_field
= mono_class_get_field_from_name_full (mono_defaults
.thread_class
, "current_thread", NULL
);
631 g_assert (current_thread_field
);
634 ERROR_DECL (thread_vt_error
);
635 mono_class_vtable_checked (domain
, mono_defaults
.thread_class
, thread_vt_error
);
636 mono_error_assert_ok (thread_vt_error
);
637 mono_domain_lock (domain
);
638 offset
= GPOINTER_TO_UINT (g_hash_table_lookup (domain
->special_static_fields
, current_thread_field
));
639 mono_domain_unlock (domain
);
642 return (MonoThread
**)get_thread_static_data (thread
, offset
);
646 set_current_thread_for_domain (MonoDomain
*domain
, MonoInternalThread
*thread
, MonoThread
*current
)
648 #ifndef ENABLE_NETCORE
649 MonoThread
**current_thread_ptr
= get_current_thread_ptr_for_domain (domain
, thread
);
651 g_assert (current
->obj
.vtable
->domain
== domain
);
653 g_assert (!*current_thread_ptr
);
654 *current_thread_ptr
= current
;
659 create_thread_object (MonoDomain
*domain
, MonoInternalThread
*internal
)
661 #ifdef ENABLE_NETCORE
662 MONO_OBJECT_SETREF_INTERNAL (internal
, internal_thread
, internal
);
669 vtable
= mono_class_vtable_checked (domain
, mono_defaults
.thread_class
, error
);
670 mono_error_assert_ok (error
);
672 thread
= (MonoThread
*)mono_object_new_mature (vtable
, error
);
673 /* only possible failure mode is OOM, from which we don't expect to recover. */
674 mono_error_assert_ok (error
);
676 MONO_OBJECT_SETREF_INTERNAL (thread
, internal_thread
, internal
);
683 init_internal_thread_object (MonoInternalThread
*thread
)
685 thread
->longlived
= g_new0 (MonoLongLivedThreadData
, 1);
686 init_longlived_thread_data (thread
->longlived
);
688 thread
->apartment_state
= ThreadApartmentState_Unknown
;
689 thread
->managed_id
= get_next_managed_thread_id ();
690 if (mono_gc_is_moving ()) {
691 thread
->thread_pinning_ref
= thread
;
692 MONO_GC_REGISTER_ROOT_PINNING (thread
->thread_pinning_ref
, MONO_ROOT_SOURCE_THREADING
, NULL
, "Thread Pinning Reference");
695 thread
->priority
= MONO_THREAD_PRIORITY_NORMAL
;
697 thread
->suspended
= g_new0 (MonoOSEvent
, 1);
698 mono_os_event_init (thread
->suspended
, TRUE
);
701 static MonoInternalThread
*
702 create_internal_thread_object (void)
705 MonoInternalThread
*thread
;
708 vt
= mono_class_vtable_checked (mono_get_root_domain (), mono_defaults
.internal_thread_class
, error
);
709 mono_error_assert_ok (error
);
710 thread
= (MonoInternalThread
*) mono_object_new_mature (vt
, error
);
711 /* only possible failure mode is OOM, from which we don't exect to recover */
712 mono_error_assert_ok (error
);
714 init_internal_thread_object (thread
);
720 mono_thread_internal_set_priority (MonoInternalThread
*internal
, MonoThreadPriority priority
)
724 g_assert (priority
>= MONO_THREAD_PRIORITY_LOWEST
);
725 g_assert (priority
<= MONO_THREAD_PRIORITY_HIGHEST
);
726 g_assert (MONO_THREAD_PRIORITY_LOWEST
< MONO_THREAD_PRIORITY_HIGHEST
);
732 g_assert (internal
->native_handle
);
735 res
= SetThreadPriority (internal
->native_handle
, (int)priority
- 2);
736 last_error
= GetLastError ();
739 g_error ("%s: SetThreadPriority failed, error %d", __func__
, last_error
);
740 #elif defined(HOST_FUCHSIA)
743 if (priority
== MONO_THREAD_PRIORITY_LOWEST
)
744 z_priority
= ZX_PRIORITY_LOWEST
;
745 else if (priority
== MONO_THREAD_PRIORITY_BELOW_NORMAL
)
746 z_priority
= ZX_PRIORITY_LOW
;
747 else if (priority
== MONO_THREAD_PRIORITY_NORMAL
)
748 z_priority
= ZX_PRIORITY_DEFAULT
;
749 else if (priority
== MONO_THREAD_PRIORITY_ABOVE_NORMAL
)
750 z_priority
= ZX_PRIORITY_HIGH
;
751 else if (priority
== MONO_THREAD_PRIORITY_HIGHEST
)
752 z_priority
= ZX_PRIORITY_HIGHEST
;
757 // When this API becomes available on an arbitrary thread, we can use it,
758 // not available on current Zircon
760 #else /* !HOST_WIN32 and not HOST_FUCHSIA */
763 struct sched_param param
;
766 tid
= thread_get_tid (internal
);
769 res
= pthread_getschedparam (tid
, &policy
, ¶m
);
772 g_error ("%s: pthread_getschedparam failed, error: \"%s\" (%d)", __func__
, g_strerror (res
), res
);
774 #ifdef _POSIX_PRIORITY_SCHEDULING
777 /* Necessary to get valid priority range */
780 #if defined(__PASE__)
781 /* only priorities allowed by IBM i */
785 min
= sched_get_priority_min (policy
);
786 max
= sched_get_priority_max (policy
);
790 if (max
> 0 && min
>= 0 && max
> min
) {
791 double srange
, drange
, sposition
, dposition
;
792 srange
= MONO_THREAD_PRIORITY_HIGHEST
- MONO_THREAD_PRIORITY_LOWEST
;
794 sposition
= priority
- MONO_THREAD_PRIORITY_LOWEST
;
795 dposition
= (sposition
/ srange
) * drange
;
796 param
.sched_priority
= (int)(dposition
+ min
);
803 param
.sched_priority
= 50;
809 param
.sched_priority
= 0;
812 g_warning ("%s: unknown policy %d", __func__
, policy
);
818 #if defined(__PASE__)
819 /* only scheduling param allowed by IBM i */
820 res
= pthread_setschedparam (tid
, SCHED_OTHER
, ¶m
);
822 res
= pthread_setschedparam (tid
, policy
, ¶m
);
828 /* AIX doesn't like doing this and will spam this every time;
829 * weirdly, i doesn't complain
831 g_warning ("%s: pthread_setschedparam failed, error: \"%s\" (%d)", __func__
, g_strerror (res
), res
);
835 g_error ("%s: pthread_setschedparam failed, error: \"%s\" (%d)", __func__
, g_strerror (res
), res
);
837 #endif /* HOST_WIN32 */
841 mono_alloc_static_data (gpointer
**static_data_ptr
, guint32 offset
, void *alloc_key
, gboolean threadlocal
);
844 mono_thread_attach_internal (MonoThread
*thread
, gboolean force_attach
, gboolean force_domain
)
846 MonoThreadInfo
*info
;
847 MonoInternalThread
*internal
;
848 MonoDomain
*domain
, *root_domain
;
853 info
= mono_thread_info_current ();
856 internal
= thread
->internal_thread
;
859 /* It is needed to store the MonoInternalThread on the MonoThreadInfo, because of the following case:
860 * - the MonoInternalThread TLS key is destroyed: set it to NULL
861 * - the MonoThreadInfo TLS key is destroyed: calls mono_thread_info_detach
862 * - it calls MonoThreadInfoCallbacks.thread_detach
863 * - mono_thread_internal_current returns NULL -> fails to detach the MonoInternalThread. */
864 mono_thread_info_set_internal_thread_gchandle (info
, mono_gchandle_new_internal ((MonoObject
*) internal
, FALSE
));
866 internal
->handle
= mono_threads_open_thread_handle (info
->handle
);
867 internal
->native_handle
= MONO_NATIVE_THREAD_HANDLE_TO_GPOINTER (mono_threads_open_native_thread_handle (info
->native_handle
));
868 internal
->tid
= MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ());
869 internal
->thread_info
= info
;
870 internal
->small_id
= info
->small_id
;
872 THREAD_DEBUG (g_message ("%s: (%" G_GSIZE_FORMAT
") Setting current_object_key to %p", __func__
, mono_native_thread_id_get (), internal
));
874 SET_CURRENT_OBJECT (internal
);
876 domain
= mono_object_domain (thread
);
878 mono_thread_push_appdomain_ref (domain
);
879 if (!mono_domain_set_fast (domain
, force_domain
)) {
880 mono_thread_pop_appdomain_ref ();
884 mono_threads_lock ();
886 if (shutting_down
&& !force_attach
) {
887 mono_threads_unlock ();
888 mono_thread_pop_appdomain_ref ();
892 if (threads_starting_up
)
893 mono_g_hash_table_remove (threads_starting_up
, thread
);
896 threads
= mono_g_hash_table_new_type_internal (NULL
, NULL
, MONO_HASH_VALUE_GC
, MONO_ROOT_SOURCE_THREADING
, NULL
, "Thread Table");
899 /* We don't need to duplicate thread->handle, because it is
900 * only closed when the thread object is finalized by the GC. */
901 mono_g_hash_table_insert_internal (threads
, (gpointer
)(gsize
)(internal
->tid
), internal
);
903 /* We have to do this here because mono_thread_start_cb
904 * requires that root_domain_thread is set up. */
905 if (thread_static_info
.offset
|| thread_static_info
.idx
> 0) {
906 /* get the current allocated size */
907 guint32 offset
= MAKE_SPECIAL_STATIC_OFFSET (thread_static_info
.idx
, thread_static_info
.offset
, 0);
908 mono_alloc_static_data (&internal
->static_data
, offset
, (void *) MONO_UINT_TO_NATIVE_THREAD_ID (internal
->tid
), TRUE
);
911 mono_threads_unlock ();
913 root_domain
= mono_get_root_domain ();
915 g_assert (!internal
->root_domain_thread
);
916 if (domain
!= root_domain
)
917 MONO_OBJECT_SETREF_INTERNAL (internal
, root_domain_thread
, create_thread_object (root_domain
, internal
));
919 MONO_OBJECT_SETREF_INTERNAL (internal
, root_domain_thread
, thread
);
921 if (domain
!= root_domain
)
922 set_current_thread_for_domain (root_domain
, internal
, internal
->root_domain_thread
);
924 set_current_thread_for_domain (domain
, internal
, thread
);
926 THREAD_DEBUG (g_message ("%s: Attached thread ID %" G_GSIZE_FORMAT
" (handle %p)", __func__
, internal
->tid
, internal
->handle
));
931 mono_threads_lock ();
932 if (threads_starting_up
)
933 mono_g_hash_table_remove (threads_starting_up
, thread
);
934 mono_threads_unlock ();
936 if (!mono_thread_info_try_get_internal_thread_gchandle (info
, &gchandle
))
937 g_error ("%s: failed to get gchandle, info %p", __func__
, info
);
939 mono_gchandle_free_internal (gchandle
);
941 mono_thread_info_unset_internal_thread_gchandle (info
);
943 SET_CURRENT_OBJECT(NULL
);
949 mono_thread_detach_internal (MonoInternalThread
*thread
)
951 MonoThreadInfo
*info
;
952 MonoInternalThread
*value
;
956 g_assert (mono_thread_internal_is_current (thread
));
958 g_assert (thread
!= NULL
);
959 SET_CURRENT_OBJECT (thread
);
961 info
= thread
->thread_info
;
964 THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%" G_GSIZE_FORMAT
")", __func__
, thread
, (gsize
)thread
->tid
));
966 MONO_PROFILER_RAISE (thread_stopping
, (thread
->tid
));
969 * Prevent race condition between thread shutdown and runtime shutdown.
970 * Including all runtime threads in the pending joinable count will make
971 * sure shutdown will wait for it to get onto the joinable thread list before
972 * critical resources have been cleanup (like GC memory). Threads getting onto
973 * the joinable thread list should just about to exit and not blocking a potential
974 * join call. Owner of threads attached to the runtime but not identified as runtime
975 * threads needs to make sure thread detach calls won't race with runtime shutdown.
977 threads_add_pending_joinable_runtime_thread (info
);
980 mono_w32mutex_abandon (thread
);
983 mono_gchandle_free_internal (thread
->abort_state_handle
);
984 thread
->abort_state_handle
= 0;
986 thread
->abort_exc
= NULL
;
987 thread
->current_appcontext
= NULL
;
989 LOCK_THREAD (thread
);
991 thread
->state
|= ThreadState_Stopped
;
992 thread
->state
&= ~ThreadState_Background
;
994 UNLOCK_THREAD (thread
);
997 An interruption request has leaked to cleanup. Adjust the global counter.
999 This can happen is the abort source thread finds the abortee (this) thread
1000 in unmanaged code. If this thread never trips back to managed code or check
1001 the local flag it will be left set and positively unbalance the global counter.
1003 Leaving the counter unbalanced will cause a performance degradation since all threads
1004 will now keep checking their local flags all the time.
1006 mono_thread_clear_interruption_requested (thread
);
1008 mono_threads_lock ();
1012 if (!mono_g_hash_table_lookup_extended (threads
, (gpointer
)thread
->tid
, NULL
, (gpointer
*) &value
)) {
1013 g_error ("%s: thread %p (tid: %p) should not have been removed yet from threads", __func__
, thread
, thread
->tid
);
1014 } else if (thread
!= value
) {
1015 /* We have to check whether the thread object for the tid is still the same in the table because the
1016 * thread might have been destroyed and the tid reused in the meantime, in which case the tid would be in
1017 * the table, but with another thread object. */
1018 g_error ("%s: thread %p (tid: %p) do not match with value %p (tid: %p)", __func__
, thread
, thread
->tid
, value
, value
->tid
);
1021 removed
= mono_g_hash_table_remove (threads
, (gpointer
)thread
->tid
);
1024 mono_threads_unlock ();
1026 /* Don't close the handle here, wait for the object finalizer
1027 * to do it. Otherwise, the following race condition applies:
1029 * 1) Thread exits (and mono_thread_detach_internal() closes the handle)
1031 * 2) Some other handle is reassigned the same slot
1033 * 3) Another thread tries to join the first thread, and
1034 * blocks waiting for the reassigned handle to be signalled
1035 * (which might never happen). This is possible, because the
1036 * thread calling Join() still has a reference to the first
1040 mono_release_type_locks (thread
);
1042 MONO_PROFILER_RAISE (thread_stopped
, (thread
->tid
));
1043 MONO_PROFILER_RAISE (gc_root_unregister
, ((const mono_byte
*)(info
->stack_start_limit
)));
1044 MONO_PROFILER_RAISE (gc_root_unregister
, ((const mono_byte
*)(info
->handle_stack
)));
1047 * This will signal async signal handlers that the thread has exited.
1048 * The profiler callback needs this to be set, so it cannot be done earlier.
1050 mono_domain_unset ();
1051 mono_memory_barrier ();
1053 mono_thread_pop_appdomain_ref ();
1055 mono_free_static_data (thread
->static_data
);
1056 thread
->static_data
= NULL
;
1057 ref_stack_destroy (thread
->appdomain_refs
);
1058 thread
->appdomain_refs
= NULL
;
1060 g_assert (thread
->suspended
);
1061 mono_os_event_destroy (thread
->suspended
);
1062 g_free (thread
->suspended
);
1063 thread
->suspended
= NULL
;
1065 if (mono_thread_cleanup_fn
)
1066 mono_thread_cleanup_fn (thread_get_tid (thread
));
1068 mono_memory_barrier ();
1070 if (mono_gc_is_moving ()) {
1071 MONO_GC_UNREGISTER_ROOT (thread
->thread_pinning_ref
);
1072 thread
->thread_pinning_ref
= NULL
;
1075 /* There is no more any guarantee that `thread` is alive */
1076 mono_memory_barrier ();
1078 SET_CURRENT_OBJECT (NULL
);
1079 mono_domain_unset ();
1081 if (!mono_thread_info_try_get_internal_thread_gchandle (info
, &gchandle
))
1082 g_error ("%s: failed to get gchandle, info = %p", __func__
, info
);
1084 mono_gchandle_free_internal (gchandle
);
1086 mono_thread_info_unset_internal_thread_gchandle (info
);
1088 /* Possibly free synch_cs, if the finalizer for InternalThread already
1090 dec_longlived_thread_data (thread
->longlived
);
1092 MONO_PROFILER_RAISE (thread_exited
, (thread
->tid
));
1094 /* Don't need to close the handle to this thread, even though we took a
1095 * reference in mono_thread_attach (), because the GC will do it
1096 * when the Thread object is finalised.
1103 MonoObject
*start_delegate
;
1104 MonoObject
*start_delegate_arg
;
1105 MonoThreadStart start_func
;
1106 gpointer start_func_arg
;
1107 gboolean force_attach
;
1109 MonoCoopSem registered
;
1113 fire_attach_profiler_events (MonoNativeThreadId tid
)
1115 MONO_PROFILER_RAISE (thread_started
, ((uintptr_t) tid
));
1117 MonoThreadInfo
*info
= mono_thread_info_current ();
1119 MONO_PROFILER_RAISE (gc_root_register
, (
1120 (const mono_byte
*)(info
->stack_start_limit
),
1121 (char *) info
->stack_end
- (char *) info
->stack_start_limit
,
1122 MONO_ROOT_SOURCE_STACK
,
1126 // The handle stack is a pseudo-root similar to the finalizer queues.
1127 MONO_PROFILER_RAISE (gc_root_register
, (
1128 (const mono_byte
*)info
->handle_stack
,
1130 MONO_ROOT_SOURCE_HANDLE
,
1135 static guint32 WINAPI
1136 start_wrapper_internal (StartInfo
*start_info
, gsize
*stack_ptr
)
1139 MonoThreadStart start_func
;
1140 void *start_func_arg
;
1143 * We don't create a local to hold start_info->thread, so hopefully it won't get pinned during a
1147 MonoInternalThread
*internal
;
1148 MonoObject
*start_delegate
;
1149 MonoObject
*start_delegate_arg
;
1151 thread
= start_info
->thread
;
1152 internal
= thread
->internal_thread
;
1154 THREAD_DEBUG (g_message ("%s: (%" G_GSIZE_FORMAT
") Start wrapper", __func__
, mono_native_thread_id_get ()));
1156 if (!mono_thread_attach_internal (thread
, start_info
->force_attach
, FALSE
)) {
1157 start_info
->failed
= TRUE
;
1159 mono_coop_sem_post (&start_info
->registered
);
1161 if (mono_atomic_dec_i32 (&start_info
->ref
) == 0) {
1162 mono_coop_sem_destroy (&start_info
->registered
);
1163 g_free (start_info
);
1169 mono_thread_internal_set_priority (internal
, (MonoThreadPriority
)internal
->priority
);
1171 tid
= internal
->tid
;
1173 start_delegate
= start_info
->start_delegate
;
1174 start_delegate_arg
= start_info
->start_delegate_arg
;
1175 start_func
= start_info
->start_func
;
1176 start_func_arg
= start_info
->start_func_arg
;
1178 /* This MUST be called before any managed code can be
1179 * executed, as it calls the callback function that (for the
1180 * jit) sets the lmf marker.
1183 if (mono_thread_start_cb
)
1184 mono_thread_start_cb (tid
, stack_ptr
, (gpointer
)start_func
);
1186 /* On 2.0 profile (and higher), set explicitly since state might have been
1188 if (internal
->apartment_state
== ThreadApartmentState_Unknown
)
1189 internal
->apartment_state
= ThreadApartmentState_MTA
;
1191 mono_thread_init_apartment_state ();
1193 /* Let the thread that called Start() know we're ready */
1194 mono_coop_sem_post (&start_info
->registered
);
1196 if (mono_atomic_dec_i32 (&start_info
->ref
) == 0) {
1197 mono_coop_sem_destroy (&start_info
->registered
);
1198 g_free (start_info
);
1201 /* start_info is not valid anymore */
1205 * Call this after calling start_notify, since the profiler callback might want
1206 * to lock the thread, and the lock is held by thread_start () which waits for
1209 fire_attach_profiler_events ((MonoNativeThreadId
) tid
);
1211 /* if the name was set before starting, we didn't invoke the profiler callback */
1212 if (internal
->name
) {
1213 char *tname
= g_utf16_to_utf8 (internal
->name
, internal
->name_len
, NULL
, NULL
, NULL
);
1214 MONO_PROFILER_RAISE (thread_name
, (internal
->tid
, tname
));
1215 mono_native_thread_set_name (MONO_UINT_TO_NATIVE_THREAD_ID (internal
->tid
), tname
);
1219 /* start_func is set only for unmanaged start functions */
1221 start_func (start_func_arg
);
1223 #ifdef ENABLE_NETCORE
1224 static MonoMethod
*cb
;
1226 /* Call a callback in the RuntimeThread class */
1227 g_assert (start_delegate
== NULL
);
1229 cb
= mono_class_get_method_from_name_checked (internal
->obj
.vtable
->klass
, "StartCallback", 0, 0, error
);
1231 mono_error_assert_ok (error
);
1233 mono_runtime_invoke_checked (cb
, internal
, NULL
, error
);
1237 g_assert (start_delegate
!= NULL
);
1239 /* we may want to handle the exception here. See comment below on unhandled exceptions */
1240 args
[0] = (gpointer
) start_delegate_arg
;
1241 mono_runtime_delegate_invoke_checked (start_delegate
, args
, error
);
1244 if (!mono_error_ok (error
)) {
1245 MonoException
*ex
= mono_error_convert_to_exception (error
);
1247 g_assert (ex
!= NULL
);
1248 MonoClass
*klass
= mono_object_class (ex
);
1249 if ((mono_runtime_unhandled_exception_policy_get () != MONO_UNHANDLED_POLICY_LEGACY
) &&
1250 !is_threadabort_exception (klass
)) {
1251 mono_unhandled_exception_internal (&ex
->object
);
1252 mono_invoke_unhandled_exception_hook (&ex
->object
);
1253 g_assert_not_reached ();
1256 mono_error_cleanup (error
);
1260 /* If the thread calls ExitThread at all, this remaining code
1261 * will not be executed, but the main thread will eventually
1262 * call mono_thread_detach_internal() on this thread's behalf.
1265 THREAD_DEBUG (g_message ("%s: (%" G_GSIZE_FORMAT
") Start wrapper terminating", __func__
, mono_native_thread_id_get ()));
1267 /* Do any cleanup needed for apartment state. This
1268 * cannot be done in mono_thread_detach_internal since
1269 * mono_thread_detach_internal could be called for a
1270 * thread other than the current thread.
1271 * mono_thread_cleanup_apartment_state cleans up apartment
1272 * for the current thead */
1273 mono_thread_cleanup_apartment_state ();
1275 mono_thread_detach_internal (internal
);
1280 static mono_thread_start_return_t WINAPI
1281 start_wrapper (gpointer data
)
1283 StartInfo
*start_info
;
1284 MonoThreadInfo
*info
;
1287 start_info
= (StartInfo
*) data
;
1288 g_assert (start_info
);
1290 info
= mono_thread_info_attach ();
1291 info
->runtime_thread
= TRUE
;
1293 /* Run the actual main function of the thread */
1294 res
= start_wrapper_internal (start_info
, (gsize
*)info
->stack_end
);
1296 mono_thread_info_exit (res
);
1298 g_assert_not_reached ();
1304 * Common thread creation code.
1305 * LOCKING: Acquires the threads lock.
1308 create_thread (MonoThread
*thread
, MonoInternalThread
*internal
, MonoObject
*start_delegate
, MonoThreadStart start_func
, gpointer start_func_arg
,
1309 MonoThreadCreateFlags flags
, MonoError
*error
)
1311 StartInfo
*start_info
= NULL
;
1312 MonoNativeThreadId tid
;
1314 gsize stack_set_size
;
1317 g_assert (!start_func
&& !start_func_arg
);
1319 g_assert (!start_delegate
);
1321 if (flags
& MONO_THREAD_CREATE_FLAGS_THREADPOOL
) {
1322 g_assert (!(flags
& MONO_THREAD_CREATE_FLAGS_DEBUGGER
));
1323 g_assert (!(flags
& MONO_THREAD_CREATE_FLAGS_FORCE_CREATE
));
1325 if (flags
& MONO_THREAD_CREATE_FLAGS_DEBUGGER
) {
1326 g_assert (!(flags
& MONO_THREAD_CREATE_FLAGS_THREADPOOL
));
1327 g_assert (!(flags
& MONO_THREAD_CREATE_FLAGS_FORCE_CREATE
));
1331 * Join joinable threads to prevent running out of threads since the finalizer
1332 * thread might be blocked/backlogged.
1334 mono_threads_join_threads ();
1338 mono_threads_lock ();
1339 if (shutting_down
&& !(flags
& MONO_THREAD_CREATE_FLAGS_FORCE_CREATE
)) {
1340 mono_threads_unlock ();
1341 mono_error_set_execution_engine (error
, "Couldn't create thread. Runtime is shutting down.");
1344 if (threads_starting_up
== NULL
) {
1345 threads_starting_up
= mono_g_hash_table_new_type_internal (NULL
, NULL
, MONO_HASH_KEY_VALUE_GC
, MONO_ROOT_SOURCE_THREADING
, NULL
, "Thread Starting Table");
1347 mono_g_hash_table_insert_internal (threads_starting_up
, thread
, thread
);
1348 mono_threads_unlock ();
1350 internal
->threadpool_thread
= flags
& MONO_THREAD_CREATE_FLAGS_THREADPOOL
;
1351 if (internal
->threadpool_thread
)
1352 mono_thread_set_state (internal
, ThreadState_Background
);
1354 internal
->debugger_thread
= flags
& MONO_THREAD_CREATE_FLAGS_DEBUGGER
;
1356 start_info
= g_new0 (StartInfo
, 1);
1357 start_info
->ref
= 2;
1358 start_info
->thread
= thread
;
1359 start_info
->start_delegate
= start_delegate
;
1360 start_info
->start_delegate_arg
= thread
->start_obj
;
1361 start_info
->start_func
= start_func
;
1362 start_info
->start_func_arg
= start_func_arg
;
1363 start_info
->force_attach
= flags
& MONO_THREAD_CREATE_FLAGS_FORCE_CREATE
;
1364 start_info
->failed
= FALSE
;
1365 mono_coop_sem_init (&start_info
->registered
, 0);
1367 if (flags
!= MONO_THREAD_CREATE_FLAGS_SMALL_STACK
)
1368 stack_set_size
= default_stacksize_for_thread (internal
);
1372 if (!mono_thread_platform_create_thread (start_wrapper
, start_info
, &stack_set_size
, &tid
)) {
1373 /* The thread couldn't be created, so set an exception */
1374 mono_threads_lock ();
1375 mono_g_hash_table_remove (threads_starting_up
, thread
);
1376 mono_threads_unlock ();
1377 mono_error_set_execution_engine (error
, "Couldn't create thread. Error 0x%x", mono_w32error_get_last());
1378 /* ref is not going to be decremented in start_wrapper_internal */
1379 mono_atomic_dec_i32 (&start_info
->ref
);
1384 internal
->stack_size
= (int) stack_set_size
;
1386 THREAD_DEBUG (g_message ("%s: (%" G_GSIZE_FORMAT
") Launching thread %p (%" G_GSIZE_FORMAT
")", __func__
, mono_native_thread_id_get (), internal
, (gsize
)internal
->tid
));
1389 * Wait for the thread to set up its TLS data etc, so
1390 * theres no potential race condition if someone tries
1391 * to look up the data believing the thread has
1395 mono_coop_sem_wait (&start_info
->registered
, MONO_SEM_FLAGS_NONE
);
1397 THREAD_DEBUG (g_message ("%s: (%" G_GSIZE_FORMAT
") Done launching thread %p (%" G_GSIZE_FORMAT
")", __func__
, mono_native_thread_id_get (), internal
, (gsize
)internal
->tid
));
1399 ret
= !start_info
->failed
;
1402 if (mono_atomic_dec_i32 (&start_info
->ref
) == 0) {
1403 mono_coop_sem_destroy (&start_info
->registered
);
1404 g_free (start_info
);
1411 * mono_thread_new_init:
1414 mono_thread_new_init (intptr_t tid
, gpointer stack_start
, gpointer func
)
1416 if (mono_thread_start_cb
) {
1417 mono_thread_start_cb (tid
, stack_start
, func
);
1422 * mono_threads_set_default_stacksize:
1425 mono_threads_set_default_stacksize (guint32 stacksize
)
1427 default_stacksize
= stacksize
;
1431 * mono_threads_get_default_stacksize:
1434 mono_threads_get_default_stacksize (void)
1436 return default_stacksize
;
1440 * mono_thread_create_internal:
1442 * ARG should not be a GC reference.
1445 mono_thread_create_internal (MonoDomain
*domain
, gpointer func
, gpointer arg
, MonoThreadCreateFlags flags
, MonoError
*error
)
1448 MonoInternalThread
*internal
;
1453 internal
= create_internal_thread_object ();
1455 thread
= create_thread_object (domain
, internal
);
1457 LOCK_THREAD (internal
);
1459 res
= create_thread (thread
, internal
, NULL
, (MonoThreadStart
) func
, arg
, flags
, error
);
1461 UNLOCK_THREAD (internal
);
1463 return_val_if_nok (error
, NULL
);
1467 MonoInternalThreadHandle
1468 mono_thread_create_internal_handle (MonoDomain
*domain
, gpointer func
, gpointer arg
, MonoThreadCreateFlags flags
, MonoError
*error
)
1471 return MONO_HANDLE_NEW (MonoInternalThread
, mono_thread_create_internal (domain
, func
, arg
, flags
, error
));
1475 * mono_thread_create:
1478 mono_thread_create (MonoDomain
*domain
, gpointer func
, gpointer arg
)
1480 MONO_ENTER_GC_UNSAFE
;
1482 if (!mono_thread_create_checked (domain
, func
, arg
, error
))
1483 mono_error_cleanup (error
);
1484 MONO_EXIT_GC_UNSAFE
;
1488 mono_thread_create_checked (MonoDomain
*domain
, gpointer func
, gpointer arg
, MonoError
*error
)
1490 return (NULL
!= mono_thread_create_internal (domain
, func
, arg
, MONO_THREAD_CREATE_FLAGS_NONE
, error
));
1494 * mono_thread_attach:
1497 mono_thread_attach (MonoDomain
*domain
)
1499 MonoInternalThread
*internal
;
1501 MonoThreadInfo
*info
;
1502 MonoNativeThreadId tid
;
1504 if (mono_thread_internal_current_is_attached ()) {
1505 if (domain
!= mono_domain_get ())
1506 mono_domain_set_fast (domain
, TRUE
);
1507 /* Already attached */
1508 return mono_thread_current ();
1511 info
= mono_thread_info_attach ();
1514 tid
=mono_native_thread_id_get ();
1516 if (mono_runtime_get_no_exec ())
1519 internal
= create_internal_thread_object ();
1521 thread
= create_thread_object (domain
, internal
);
1523 if (!mono_thread_attach_internal (thread
, FALSE
, TRUE
)) {
1524 /* Mono is shutting down, so just wait for the end */
1526 mono_thread_info_sleep (10000, NULL
);
1529 THREAD_DEBUG (g_message ("%s: Attached thread ID %" G_GSIZE_FORMAT
" (handle %p)", __func__
, tid
, internal
->handle
));
1531 if (mono_thread_attach_cb
)
1532 mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid
), info
->stack_end
);
1534 fire_attach_profiler_events (tid
);
1540 * mono_thread_detach:
1543 mono_thread_detach (MonoThread
*thread
)
1546 mono_thread_detach_internal (thread
->internal_thread
);
1550 * mono_thread_detach_if_exiting:
1552 * Detach the current thread from the runtime if it is exiting, i.e. it is running pthread dtors.
1553 * This should be used at the end of embedding code which calls into managed code, and which
1554 * can be called from pthread dtors, like <code>dealloc:</code> implementations in Objective-C.
1557 mono_thread_detach_if_exiting (void)
1559 if (mono_thread_info_is_exiting ()) {
1560 MonoInternalThread
*thread
;
1562 thread
= mono_thread_internal_current ();
1564 // Switch to GC Unsafe thread state before detaching;
1565 // don't expect to undo this switch, hence unbalanced.
1567 (void) mono_threads_enter_gc_unsafe_region_unbalanced (&dummy
);
1569 mono_thread_detach_internal (thread
);
1570 mono_thread_info_detach ();
1578 mono_thread_internal_current_is_attached (void)
1580 MonoInternalThread
*internal
;
1582 internal
= GET_CURRENT_OBJECT ();
1593 mono_thread_exit (void)
1595 MonoInternalThread
*thread
= mono_thread_internal_current ();
1597 THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%" G_GSIZE_FORMAT
")", __func__
, thread
, (gsize
)thread
->tid
));
1599 mono_thread_detach_internal (thread
);
1601 /* we could add a callback here for embedders to use. */
1602 if (mono_thread_get_main () && (thread
== mono_thread_get_main ()->internal_thread
))
1603 exit (mono_environment_exitcode_get ());
1605 mono_thread_info_exit (0);
1609 mono_thread_construct_internal (MonoThreadObjectHandle this_obj_handle
)
1611 MonoInternalThread
* const internal
= create_internal_thread_object ();
1613 internal
->state
= ThreadState_Unstarted
;
1615 int const thread_gchandle
= mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject
, this_obj_handle
), TRUE
);
1617 MonoThreadObject
*this_obj
= MONO_HANDLE_RAW (this_obj_handle
);
1619 mono_atomic_cas_ptr ((volatile gpointer
*)&this_obj
->internal_thread
, internal
, NULL
);
1621 mono_gchandle_free_internal (thread_gchandle
);
1624 #ifndef ENABLE_NETCORE
1626 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThreadObjectHandle this_obj_handle
, MonoError
*error
)
1628 mono_thread_construct_internal (this_obj_handle
);
1632 MonoThreadObjectHandle
1633 ves_icall_System_Threading_Thread_GetCurrentThread (MonoError
*error
)
1635 return MONO_HANDLE_NEW (MonoThreadObject
, mono_thread_current ());
1638 static MonoInternalThread
*
1639 thread_handle_to_internal_ptr (MonoThreadObjectHandle thread_handle
)
1641 return MONO_HANDLE_GETVAL(thread_handle
, internal_thread
); // InternalThreads are always pinned.
1645 mono_error_set_exception_thread_state (MonoError
*error
, const char *exception_message
)
1647 mono_error_set_generic_error (error
, "System.Threading", "ThreadStateException", "%s", exception_message
);
1651 mono_error_set_exception_thread_not_started_or_dead (MonoError
*error
)
1653 mono_error_set_exception_thread_state (error
, "Thread has not been started, or is dead.");
1656 #ifndef ENABLE_NETCORE
1658 ves_icall_System_Threading_Thread_Thread_internal (MonoThreadObjectHandle thread_handle
, MonoObjectHandle start_handle
, MonoError
*error
)
1660 MonoInternalThread
*internal
;
1662 MonoThread
*this_obj
= MONO_HANDLE_RAW (thread_handle
);
1663 MonoObject
*start
= MONO_HANDLE_RAW (start_handle
);
1665 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__
, this_obj
, start
));
1667 internal
= thread_handle_to_internal_ptr (thread_handle
);
1670 mono_thread_construct_internal (thread_handle
);
1671 internal
= thread_handle_to_internal_ptr (thread_handle
);
1672 g_assert (internal
);
1675 LOCK_THREAD (internal
);
1677 if ((internal
->state
& ThreadState_Unstarted
) == 0) {
1678 UNLOCK_THREAD (internal
);
1679 mono_error_set_exception_thread_state (error
, "Thread has already been started.");
1683 if ((internal
->state
& ThreadState_Aborted
) != 0) {
1684 UNLOCK_THREAD (internal
);
1688 res
= create_thread (this_obj
, internal
, start
, NULL
, NULL
, MONO_THREAD_CREATE_FLAGS_NONE
, error
);
1690 UNLOCK_THREAD (internal
);
1694 internal
->state
&= ~ThreadState_Unstarted
;
1696 THREAD_DEBUG (g_message ("%s: Started thread ID %" G_GSIZE_FORMAT
" (handle %p)", __func__
, tid
, thread
));
1698 UNLOCK_THREAD (internal
);
1704 * This is called from the finalizer of the internal thread object.
1707 ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThreadHandle this_obj_handle
, MonoError
*error
)
1709 MonoInternalThread
*this_obj
= mono_internal_thread_handle_ptr (this_obj_handle
);
1710 THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__
, this_obj
, this_obj
->handle
));
1713 * Since threads keep a reference to their thread object while running, by
1714 * the time this function is called, the thread has already exited/detached,
1715 * i.e. mono_thread_detach_internal () has ran. The exception is during
1716 * shutdown, when mono_thread_detach_internal () can be called after this.
1718 if (this_obj
->handle
) {
1719 mono_threads_close_thread_handle (this_obj
->handle
);
1720 this_obj
->handle
= NULL
;
1723 mono_threads_close_native_thread_handle (MONO_GPOINTER_TO_NATIVE_THREAD_HANDLE (this_obj
->native_handle
));
1724 this_obj
->native_handle
= NULL
;
1726 /* Possibly free synch_cs, if the thread already detached also. */
1727 dec_longlived_thread_data (this_obj
->longlived
);
1730 if (this_obj
->name
) {
1731 void *name
= this_obj
->name
;
1732 this_obj
->name
= NULL
;
1738 ves_icall_System_Threading_Thread_Sleep_internal (gint32 ms
, MonoError
*error
)
1740 THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__
, ms
));
1742 if (mono_thread_current_check_pending_interrupt ())
1745 MonoInternalThread
* const thread
= mono_thread_internal_current ();
1747 HANDLE_LOOP_PREPARE
;
1750 gboolean alerted
= FALSE
;
1752 mono_thread_set_state (thread
, ThreadState_WaitSleepJoin
);
1754 (void)mono_thread_info_sleep (ms
, &alerted
);
1756 mono_thread_clr_state (thread
, ThreadState_WaitSleepJoin
);
1763 MonoExceptionHandle exc
= MONO_HANDLE_NEW (MonoException
, NULL
);
1765 const gboolean interrupt
= mono_thread_execute_interruption (&exc
);
1768 mono_set_pending_exception_handle (exc
);
1774 if (ms
== MONO_INFINITE_WAIT
) // FIXME: !MONO_INFINITE_WAIT
1781 ves_icall_System_Threading_Thread_SpinWait_nop (MonoError
*error
)
1785 #ifndef ENABLE_NETCORE
1787 ves_icall_System_Threading_Thread_GetDomainID (MonoError
*error
)
1789 return mono_domain_get()->domain_id
;
1794 * mono_thread_get_name:
1796 * Return the name of the thread. NAME_LEN is set to the length of the name.
1797 * Return NULL if the thread has no name. The returned memory is owned by the
1801 mono_thread_get_name (MonoInternalThread
*this_obj
, guint32
*name_len
)
1805 LOCK_THREAD (this_obj
);
1807 if (!this_obj
->name
) {
1811 *name_len
= this_obj
->name_len
;
1812 res
= g_new (gunichar2
, this_obj
->name_len
);
1813 memcpy (res
, this_obj
->name
, sizeof (gunichar2
) * this_obj
->name_len
);
1816 UNLOCK_THREAD (this_obj
);
1822 * mono_thread_get_name_utf8:
1823 * \returns the name of the thread in UTF-8.
1824 * Return NULL if the thread has no name.
1825 * The returned memory is owned by the caller (g_free it).
1828 mono_thread_get_name_utf8 (MonoThread
*thread
)
1833 MonoInternalThread
*internal
= thread
->internal_thread
;
1834 if (internal
== NULL
)
1837 LOCK_THREAD (internal
);
1839 char *tname
= g_utf16_to_utf8 (internal
->name
, internal
->name_len
, NULL
, NULL
, NULL
);
1841 UNLOCK_THREAD (internal
);
1847 * mono_thread_get_managed_id:
1848 * \returns the \c Thread.ManagedThreadId value of \p thread.
1849 * Returns \c -1 if \p thread is NULL.
1852 mono_thread_get_managed_id (MonoThread
*thread
)
1857 MonoInternalThread
*internal
= thread
->internal_thread
;
1858 if (internal
== NULL
)
1861 int32_t id
= internal
->managed_id
;
1866 #ifndef ENABLE_NETCORE
1868 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThreadHandle thread_handle
, MonoError
*error
)
1870 // InternalThreads are always pinned, so shallowly coop-handleize.
1871 MonoInternalThread
* const this_obj
= mono_internal_thread_handle_ptr (thread_handle
);
1873 MonoStringHandle str
= MONO_HANDLE_NEW (MonoString
, NULL
);
1875 LOCK_THREAD (this_obj
);
1878 MONO_HANDLE_ASSIGN (str
, mono_string_new_utf16_handle (mono_domain_get (), this_obj
->name
, this_obj
->name_len
, error
));
1880 UNLOCK_THREAD (this_obj
);
1887 mono_thread_set_name_internal (MonoInternalThread
*this_obj
, MonoString
*name
, gboolean permanent
, gboolean reset
, MonoError
*error
)
1889 MonoNativeThreadId tid
= 0;
1891 LOCK_THREAD (this_obj
);
1896 this_obj
->flags
&= ~MONO_THREAD_FLAG_NAME_SET
;
1897 } else if (this_obj
->flags
& MONO_THREAD_FLAG_NAME_SET
) {
1898 UNLOCK_THREAD (this_obj
);
1900 mono_error_set_invalid_operation (error
, "%s", "Thread.Name can only be set once.");
1903 if (this_obj
->name
) {
1904 g_free (this_obj
->name
);
1905 this_obj
->name_len
= 0;
1908 this_obj
->name
= g_memdup (mono_string_chars_internal (name
), mono_string_length_internal (name
) * sizeof (gunichar2
));
1909 this_obj
->name_len
= mono_string_length_internal (name
);
1912 this_obj
->flags
|= MONO_THREAD_FLAG_NAME_SET
;
1915 this_obj
->name
= NULL
;
1917 if (!(this_obj
->state
& ThreadState_Stopped
))
1918 tid
= thread_get_tid (this_obj
);
1920 UNLOCK_THREAD (this_obj
);
1922 if (this_obj
->name
&& tid
) {
1923 char *tname
= mono_string_to_utf8_checked_internal (name
, error
);
1924 return_if_nok (error
);
1925 MONO_PROFILER_RAISE (thread_name
, ((uintptr_t)tid
, tname
));
1926 mono_native_thread_set_name (tid
, tname
);
1932 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread
*this_obj
, MonoString
*name
)
1935 mono_thread_set_name_internal (this_obj
, name
, TRUE
, FALSE
, error
);
1936 mono_error_set_pending_exception (error
);
1939 #ifndef ENABLE_NETCORE
1941 * ves_icall_System_Threading_Thread_GetPriority_internal:
1942 * @param this_obj: The MonoInternalThread on which to operate.
1944 * Gets the priority of the given thread.
1945 * @return: The priority of the given thread.
1948 ves_icall_System_Threading_Thread_GetPriority (MonoThreadObjectHandle this_obj
, MonoError
*error
)
1952 MonoInternalThread
*internal
= thread_handle_to_internal_ptr (this_obj
);
1954 LOCK_THREAD (internal
);
1955 priority
= internal
->priority
;
1956 UNLOCK_THREAD (internal
);
1963 * ves_icall_System_Threading_Thread_SetPriority_internal:
1964 * @param this_obj: The MonoInternalThread on which to operate.
1965 * @param priority: The priority to set.
1967 * Sets the priority of the given thread.
1970 ves_icall_System_Threading_Thread_SetPriority (MonoThreadObjectHandle this_obj
, int priority
, MonoError
*error
)
1972 MonoInternalThread
*internal
= thread_handle_to_internal_ptr (this_obj
);
1974 LOCK_THREAD (internal
);
1975 internal
->priority
= priority
;
1976 if (internal
->thread_info
!= NULL
)
1977 mono_thread_internal_set_priority (internal
, (MonoThreadPriority
)priority
);
1978 UNLOCK_THREAD (internal
);
1981 /* If the array is already in the requested domain, we just return it,
1982 otherwise we return a copy in that domain. */
1983 static MonoArrayHandle
1984 byte_array_to_domain (MonoArrayHandle arr
, MonoDomain
*domain
, MonoError
*error
)
1986 HANDLE_FUNCTION_ENTER ()
1988 if (MONO_HANDLE_IS_NULL (arr
))
1989 return MONO_HANDLE_NEW (MonoArray
, NULL
);
1991 if (MONO_HANDLE_DOMAIN (arr
) == domain
)
1994 size_t const size
= mono_array_handle_length (arr
);
1996 // Capture arrays into common representation for repetitious code.
1997 // These two variables could also be an array of size 2 and
1998 // repitition implemented with a loop.
2000 MonoArrayHandle handle
;
2005 dest
= { mono_array_new_handle (domain
, mono_defaults
.byte_class
, size
, error
) };
2006 goto_if_nok (error
, exit
);
2009 source
.p
= mono_array_handle_pin_with_size (source
.handle
, size
, 0, &source
.gchandle
);
2010 dest
.p
= mono_array_handle_pin_with_size (dest
.handle
, size
, 0, &dest
.gchandle
);
2012 memmove (dest
.p
, source
.p
, size
);
2014 // Unpin both arrays.
2015 mono_gchandle_free_internal (source
.gchandle
);
2016 mono_gchandle_free_internal (dest
.gchandle
);
2018 HANDLE_FUNCTION_RETURN_REF (MonoArray
, dest
.handle
)
2021 #ifndef ENABLE_NETCORE
2023 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArrayHandle arr
, MonoError
*error
)
2025 return byte_array_to_domain (arr
, mono_get_root_domain (), error
);
2029 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArrayHandle arr
, MonoError
*error
)
2031 return byte_array_to_domain (arr
, mono_domain_get (), error
);
2036 * mono_thread_current:
2039 mono_thread_current (void)
2041 #ifdef ENABLE_NETCORE
2042 return mono_thread_internal_current ();
2044 MonoDomain
*domain
= mono_domain_get ();
2045 MonoInternalThread
*internal
= mono_thread_internal_current ();
2046 MonoThread
**current_thread_ptr
;
2048 g_assert (internal
);
2049 current_thread_ptr
= get_current_thread_ptr_for_domain (domain
, internal
);
2051 if (!*current_thread_ptr
) {
2052 g_assert (domain
!= mono_get_root_domain ());
2053 *current_thread_ptr
= create_thread_object (domain
, internal
);
2055 return *current_thread_ptr
;
2059 static MonoThreadObjectHandle
2060 mono_thread_current_handle (void)
2062 return MONO_HANDLE_NEW (MonoThreadObject
, mono_thread_current ());
2065 /* Return the thread object belonging to INTERNAL in the current domain */
2067 mono_thread_current_for_thread (MonoInternalThread
*internal
)
2069 #ifdef ENABLE_NETCORE
2070 return mono_thread_internal_current ();
2072 MonoDomain
*domain
= mono_domain_get ();
2073 MonoThread
**current_thread_ptr
;
2075 g_assert (internal
);
2076 current_thread_ptr
= get_current_thread_ptr_for_domain (domain
, internal
);
2078 if (!*current_thread_ptr
) {
2079 g_assert (domain
!= mono_get_root_domain ());
2080 *current_thread_ptr
= create_thread_object (domain
, internal
);
2082 return *current_thread_ptr
;
2087 mono_thread_internal_current (void)
2089 MonoInternalThread
*res
= GET_CURRENT_OBJECT ();
2090 THREAD_DEBUG (g_message ("%s: returning %p", __func__
, res
));
2094 MonoInternalThreadHandle
2095 mono_thread_internal_current_handle (void)
2097 return MONO_HANDLE_NEW (MonoInternalThread
, mono_thread_internal_current ());
2100 static MonoThreadInfoWaitRet
2101 mono_join_uninterrupted (MonoThreadHandle
* thread_to_join
, gint32 ms
, MonoError
*error
)
2103 MonoThreadInfoWaitRet ret
;
2106 const gint64 start
= (ms
== -1) ? 0 : mono_msec_ticks ();
2109 ret
= mono_thread_info_wait_one_handle (thread_to_join
, wait
, TRUE
);
2112 if (ret
!= MONO_THREAD_INFO_WAIT_RET_ALERTED
)
2115 MonoException
*exc
= mono_thread_execute_interruption_ptr ();
2117 mono_error_set_exception_instance (error
, exc
);
2124 /* Re-calculate ms according to the time passed */
2125 const gint32 diff_ms
= (gint32
)(mono_msec_ticks () - start
);
2126 if (diff_ms
>= ms
) {
2127 ret
= MONO_THREAD_INFO_WAIT_RET_TIMEOUT
;
2130 wait
= ms
- diff_ms
;
2137 ves_icall_System_Threading_Thread_Join_internal (MonoThreadObjectHandle thread_handle
, int ms
, MonoError
*error
)
2139 if (mono_thread_current_check_pending_interrupt ())
2142 // Internal threads are pinned so shallow coop/handle.
2143 MonoInternalThread
* const thread
= thread_handle_to_internal_ptr (thread_handle
);
2144 MonoThreadHandle
*handle
= thread
->handle
;
2145 MonoInternalThread
*cur_thread
= mono_thread_internal_current ();
2146 gboolean ret
= FALSE
;
2148 LOCK_THREAD (thread
);
2150 if ((thread
->state
& ThreadState_Unstarted
) != 0) {
2151 UNLOCK_THREAD (thread
);
2153 mono_error_set_exception_thread_state (error
, "Thread has not been started.");
2157 UNLOCK_THREAD (thread
);
2160 ms
= MONO_INFINITE_WAIT
;
2161 THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__
, handle
, ms
));
2163 mono_thread_set_state (cur_thread
, ThreadState_WaitSleepJoin
);
2165 ret
= mono_join_uninterrupted (handle
, ms
, error
);
2167 mono_thread_clr_state (cur_thread
, ThreadState_WaitSleepJoin
);
2169 if (ret
== MONO_THREAD_INFO_WAIT_RET_SUCCESS_0
) {
2170 THREAD_DEBUG (g_message ("%s: join successful", __func__
));
2172 mono_error_assert_ok (error
);
2174 /* Wait for the thread to really exit */
2175 MonoNativeThreadId tid
= thread_get_tid (thread
);
2176 mono_thread_join ((gpointer
)(gsize
)tid
);
2181 THREAD_DEBUG (g_message ("%s: join failed", __func__
));
2186 #define MANAGED_WAIT_FAILED 0x7fffffff
2189 map_native_wait_result_to_managed (MonoW32HandleWaitRet val
, gsize numobjects
)
2191 if (val
>= MONO_W32HANDLE_WAIT_RET_SUCCESS_0
&& val
< MONO_W32HANDLE_WAIT_RET_SUCCESS_0
+ numobjects
) {
2192 return WAIT_OBJECT_0
+ (val
- MONO_W32HANDLE_WAIT_RET_SUCCESS_0
);
2193 } else if (val
>= MONO_W32HANDLE_WAIT_RET_ABANDONED_0
&& val
< MONO_W32HANDLE_WAIT_RET_ABANDONED_0
+ numobjects
) {
2194 return WAIT_ABANDONED_0
+ (val
- MONO_W32HANDLE_WAIT_RET_ABANDONED_0
);
2195 } else if (val
== MONO_W32HANDLE_WAIT_RET_ALERTED
) {
2196 return WAIT_IO_COMPLETION
;
2197 } else if (val
== MONO_W32HANDLE_WAIT_RET_TIMEOUT
) {
2198 return WAIT_TIMEOUT
;
2199 } else if (val
== MONO_W32HANDLE_WAIT_RET_TOO_MANY_POSTS
) {
2200 return WAIT_TOO_MANY_POSTS
;
2201 } else if (val
== MONO_W32HANDLE_WAIT_RET_NOT_OWNED_BY_CALLER
) {
2202 return WAIT_NOT_OWNED_BY_CALLER
;
2203 } else if (val
== MONO_W32HANDLE_WAIT_RET_FAILED
) {
2204 /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
2205 return MANAGED_WAIT_FAILED
;
2207 g_error ("%s: unknown val value %d", __func__
, val
);
2212 ves_icall_System_Threading_WaitHandle_Wait_internal (gpointer
*handles
, gint32 numhandles
, MonoBoolean waitall
, gint32 timeout
, MonoError
*error
)
2214 /* Do this WaitSleepJoin check before creating objects */
2215 if (mono_thread_current_check_pending_interrupt ())
2216 return map_native_wait_result_to_managed (MONO_W32HANDLE_WAIT_RET_FAILED
, 0);
2218 MonoInternalThread
* const thread
= mono_thread_internal_current ();
2220 mono_thread_set_state (thread
, ThreadState_WaitSleepJoin
);
2225 timeout
= MONO_INFINITE_WAIT
;
2226 if (timeout
!= MONO_INFINITE_WAIT
)
2227 start
= mono_msec_ticks ();
2229 guint32 timeoutLeft
= timeout
;
2231 MonoW32HandleWaitRet ret
;
2233 HANDLE_LOOP_PREPARE
;
2237 /* mono_w32handle_wait_multiple optimizes the case for numhandles == 1 */
2238 ret
= mono_w32handle_wait_multiple (handles
, numhandles
, waitall
, timeoutLeft
, TRUE
, error
);
2240 if (ret
!= MONO_W32HANDLE_WAIT_RET_ALERTED
)
2245 MonoExceptionHandle exc
= MONO_HANDLE_NEW (MonoException
, NULL
);
2247 const gboolean interrupt
= mono_thread_execute_interruption (&exc
);
2250 mono_error_set_exception_handle (error
, exc
);
2257 if (timeout
!= MONO_INFINITE_WAIT
) {
2258 gint64
const elapsed
= mono_msec_ticks () - start
;
2259 if (elapsed
>= timeout
) {
2260 ret
= MONO_W32HANDLE_WAIT_RET_TIMEOUT
;
2264 timeoutLeft
= timeout
- elapsed
;
2268 mono_thread_clr_state (thread
, ThreadState_WaitSleepJoin
);
2270 return map_native_wait_result_to_managed (ret
, numhandles
);
2273 #if HAVE_API_SUPPORT_WIN32_SIGNAL_OBJECT_AND_WAIT
2275 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (gpointer toSignal
, gpointer toWait
, gint32 ms
, MonoError
*error
)
2277 MonoW32HandleWaitRet ret
;
2278 MonoInternalThread
*thread
= mono_thread_internal_current ();
2281 ms
= MONO_INFINITE_WAIT
;
2283 if (mono_thread_current_check_pending_interrupt ())
2284 return map_native_wait_result_to_managed (MONO_W32HANDLE_WAIT_RET_FAILED
, 0);
2286 mono_thread_set_state (thread
, ThreadState_WaitSleepJoin
);
2288 ret
= mono_w32handle_signal_and_wait (toSignal
, toWait
, ms
, TRUE
);
2290 mono_thread_clr_state (thread
, ThreadState_WaitSleepJoin
);
2292 return map_native_wait_result_to_managed (ret
, 1);
2297 gint32
ves_icall_System_Threading_Interlocked_Increment_Int (gint32
*location
)
2299 return mono_atomic_inc_i32 (location
);
2302 gint64
ves_icall_System_Threading_Interlocked_Increment_Long (gint64
*location
)
2304 #if SIZEOF_VOID_P == 4
2305 if (G_UNLIKELY ((size_t)location
& 0x7)) {
2307 mono_interlocked_lock ();
2310 mono_interlocked_unlock ();
2314 return mono_atomic_inc_i64 (location
);
2317 gint32
ves_icall_System_Threading_Interlocked_Decrement_Int (gint32
*location
)
2319 return mono_atomic_dec_i32(location
);
2322 gint64
ves_icall_System_Threading_Interlocked_Decrement_Long (gint64
* location
)
2324 #if SIZEOF_VOID_P == 4
2325 if (G_UNLIKELY ((size_t)location
& 0x7)) {
2327 mono_interlocked_lock ();
2330 mono_interlocked_unlock ();
2334 return mono_atomic_dec_i64 (location
);
2337 gint32
ves_icall_System_Threading_Interlocked_Exchange_Int (gint32
*location
, gint32 value
)
2339 return mono_atomic_xchg_i32(location
, value
);
2342 MonoObject
* ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject
**location
, MonoObject
*value
)
2345 res
= (MonoObject
*) mono_atomic_xchg_ptr((gpointer
*) location
, value
);
2346 mono_gc_wbarrier_generic_nostore_internal (location
);
2350 gpointer
ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer
*location
, gpointer value
)
2352 return mono_atomic_xchg_ptr(location
, value
);
2355 gfloat
ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat
*location
, gfloat value
)
2357 IntFloatUnion val
, ret
;
2360 ret
.ival
= mono_atomic_xchg_i32((gint32
*) location
, val
.ival
);
2366 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64
*location
, gint64 value
)
2368 #if SIZEOF_VOID_P == 4
2369 if (G_UNLIKELY ((size_t)location
& 0x7)) {
2371 mono_interlocked_lock ();
2374 mono_interlocked_unlock ();
2378 return mono_atomic_xchg_i64 (location
, value
);
2382 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble
*location
, gdouble value
)
2384 LongDoubleUnion val
, ret
;
2387 ret
.ival
= (gint64
)mono_atomic_xchg_i64((gint64
*) location
, val
.ival
);
2392 gint32
ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32
*location
, gint32 value
, gint32 comparand
)
2394 return mono_atomic_cas_i32(location
, value
, comparand
);
2397 gint32
ves_icall_System_Threading_Interlocked_CompareExchange_Int_Success(gint32
*location
, gint32 value
, gint32 comparand
, MonoBoolean
*success
)
2399 gint32 r
= mono_atomic_cas_i32(location
, value
, comparand
);
2400 *success
= r
== comparand
;
2404 MonoObject
* ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject
**location
, MonoObject
*value
, MonoObject
*comparand
)
2407 res
= (MonoObject
*) mono_atomic_cas_ptr((gpointer
*) location
, value
, comparand
);
2408 mono_gc_wbarrier_generic_nostore_internal (location
);
2412 gpointer
ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer
*location
, gpointer value
, gpointer comparand
)
2414 return mono_atomic_cas_ptr(location
, value
, comparand
);
2417 gfloat
ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat
*location
, gfloat value
, gfloat comparand
)
2419 IntFloatUnion val
, ret
, cmp
;
2422 cmp
.fval
= comparand
;
2423 ret
.ival
= mono_atomic_cas_i32((gint32
*) location
, val
.ival
, cmp
.ival
);
2429 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble
*location
, gdouble value
, gdouble comparand
)
2431 #if SIZEOF_VOID_P == 8
2432 LongDoubleUnion val
, comp
, ret
;
2435 comp
.fval
= comparand
;
2436 ret
.ival
= (gint64
)mono_atomic_cas_ptr((gpointer
*) location
, (gpointer
)val
.ival
, (gpointer
)comp
.ival
);
2442 mono_interlocked_lock ();
2444 if (old
== comparand
)
2446 mono_interlocked_unlock ();
2453 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64
*location
, gint64 value
, gint64 comparand
)
2455 #if SIZEOF_VOID_P == 4
2456 if (G_UNLIKELY ((size_t)location
& 0x7)) {
2458 mono_interlocked_lock ();
2460 if (old
== comparand
)
2462 mono_interlocked_unlock ();
2466 return mono_atomic_cas_i64 (location
, value
, comparand
);
2470 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject
**location
, MonoObject
*value
, MonoObject
*comparand
)
2473 res
= (MonoObject
*)mono_atomic_cas_ptr ((volatile gpointer
*)location
, value
, comparand
);
2474 mono_gc_wbarrier_generic_nostore_internal (location
);
2479 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject
**location
, MonoObject
*value
)
2482 MONO_CHECK_NULL (location
, NULL
);
2483 res
= (MonoObject
*)mono_atomic_xchg_ptr ((volatile gpointer
*)location
, value
);
2484 mono_gc_wbarrier_generic_nostore_internal (location
);
2489 ves_icall_System_Threading_Interlocked_Add_Int (gint32
*location
, gint32 value
)
2491 return mono_atomic_add_i32 (location
, value
);
2495 ves_icall_System_Threading_Interlocked_Add_Long (gint64
*location
, gint64 value
)
2497 #if SIZEOF_VOID_P == 4
2498 if (G_UNLIKELY ((size_t)location
& 0x7)) {
2500 mono_interlocked_lock ();
2503 mono_interlocked_unlock ();
2507 return mono_atomic_add_i64 (location
, value
);
2511 ves_icall_System_Threading_Interlocked_Read_Long (gint64
*location
)
2513 #if SIZEOF_VOID_P == 4
2514 if (G_UNLIKELY ((size_t)location
& 0x7)) {
2516 mono_interlocked_lock ();
2518 mono_interlocked_unlock ();
2522 return mono_atomic_load_i64 (location
);
2526 ves_icall_System_Threading_Interlocked_MemoryBarrierProcessWide (void)
2528 mono_memory_barrier_process_wide ();
2532 ves_icall_System_Threading_Thread_MemoryBarrier (void)
2534 mono_memory_barrier ();
2538 ves_icall_System_Threading_Thread_ClrState (MonoInternalThreadHandle this_obj
, guint32 state
, MonoError
*error
)
2540 // InternalThreads are always pinned, so shallowly coop-handleize.
2541 mono_thread_clr_state (mono_internal_thread_handle_ptr (this_obj
), (MonoThreadState
)state
);
2545 ves_icall_System_Threading_Thread_SetState (MonoInternalThreadHandle thread_handle
, guint32 state
, MonoError
*error
)
2547 // InternalThreads are always pinned, so shallowly coop-handleize.
2548 mono_thread_set_state (mono_internal_thread_handle_ptr (thread_handle
), (MonoThreadState
)state
);
2552 ves_icall_System_Threading_Thread_GetState (MonoInternalThreadHandle thread_handle
, MonoError
*error
)
2554 // InternalThreads are always pinned, so shallowly coop-handleize.
2555 MonoInternalThread
*this_obj
= mono_internal_thread_handle_ptr (thread_handle
);
2559 LOCK_THREAD (this_obj
);
2561 state
= this_obj
->state
;
2563 UNLOCK_THREAD (this_obj
);
2569 ves_icall_System_Threading_Thread_Interrupt_internal (MonoThreadObjectHandle thread_handle
, MonoError
*error
)
2571 // Internal threads are pinned so shallow coop/handle.
2572 MonoInternalThread
* const thread
= thread_handle_to_internal_ptr (thread_handle
);
2573 MonoInternalThread
* const current
= mono_thread_internal_current ();
2575 LOCK_THREAD (thread
);
2577 thread
->thread_interrupt_requested
= TRUE
;
2578 gboolean
const throw_
= current
!= thread
&& (thread
->state
& ThreadState_WaitSleepJoin
);
2580 UNLOCK_THREAD (thread
);
2583 async_abort_internal (thread
, FALSE
);
2587 * mono_thread_current_check_pending_interrupt:
2588 * Checks if there's a interruption request and set the pending exception if so.
2589 * \returns true if a pending exception was set
2592 mono_thread_current_check_pending_interrupt (void)
2594 MonoInternalThread
*thread
= mono_thread_internal_current ();
2595 gboolean throw_
= FALSE
;
2597 LOCK_THREAD (thread
);
2599 if (thread
->thread_interrupt_requested
) {
2601 thread
->thread_interrupt_requested
= FALSE
;
2604 UNLOCK_THREAD (thread
);
2608 mono_error_set_thread_interrupted (error
);
2609 mono_error_set_pending_exception (error
);
2615 request_thread_abort (MonoInternalThread
*thread
, MonoObjectHandle
*state
, gboolean appdomain_unload
)
2616 // state is a pointer to a handle in order to be optional,
2617 // and be passed unspecified from functions not using handles.
2618 // When raw pointers is gone, it need not be a pointer,
2619 // though this would still work efficiently.
2621 LOCK_THREAD (thread
);
2623 /* With self abort we always throw a new exception */
2624 if (thread
== mono_thread_internal_current ())
2625 thread
->abort_exc
= NULL
;
2627 if (thread
->state
& (ThreadState_AbortRequested
| ThreadState_Stopped
))
2629 UNLOCK_THREAD (thread
);
2633 if ((thread
->state
& ThreadState_Unstarted
) != 0) {
2634 thread
->state
|= ThreadState_Aborted
;
2635 UNLOCK_THREAD (thread
);
2639 thread
->state
|= ThreadState_AbortRequested
;
2640 if (appdomain_unload
)
2641 thread
->flags
|= MONO_THREAD_FLAG_APPDOMAIN_ABORT
;
2643 thread
->flags
&= ~MONO_THREAD_FLAG_APPDOMAIN_ABORT
;
2645 mono_gchandle_free_internal (thread
->abort_state_handle
);
2646 thread
->abort_state_handle
= 0;
2649 if (state
&& !MONO_HANDLE_IS_NULL (*state
)) {
2650 thread
->abort_state_handle
= mono_gchandle_from_handle (*state
, FALSE
);
2651 g_assert (thread
->abort_state_handle
);
2654 thread
->abort_exc
= NULL
;
2656 THREAD_DEBUG (g_message ("%s: (%" G_GSIZE_FORMAT
") Abort requested for %p (%" G_GSIZE_FORMAT
")", __func__
, mono_native_thread_id_get (), thread
, (gsize
)thread
->tid
));
2658 /* During shutdown, we can't wait for other threads */
2660 /* Make sure the thread is awake */
2661 mono_thread_resume (thread
);
2663 UNLOCK_THREAD (thread
);
2667 #ifndef ENABLE_NETCORE
2669 ves_icall_System_Threading_Thread_Abort (MonoInternalThreadHandle thread_handle
, MonoObjectHandle state
, MonoError
*error
)
2671 // InternalThreads are always pinned, so shallowly coop-handleize.
2672 MonoInternalThread
* const thread
= mono_internal_thread_handle_ptr (thread_handle
);
2673 gboolean is_self
= thread
== mono_thread_internal_current ();
2675 /* For self aborts we always process the abort */
2676 if (!request_thread_abort (thread
, &state
, FALSE
) && !is_self
)
2680 self_abort_internal (error
);
2682 async_abort_internal (thread
, TRUE
);
2688 * mono_thread_internal_abort:
2689 * Request thread \p thread to be aborted.
2690 * \p thread MUST NOT be the current thread.
2693 mono_thread_internal_abort (MonoInternalThread
*thread
, gboolean appdomain_unload
)
2695 g_assert (thread
!= mono_thread_internal_current ());
2697 if (!request_thread_abort (thread
, NULL
, appdomain_unload
))
2699 async_abort_internal (thread
, TRUE
);
2702 #ifndef ENABLE_NETCORE
2704 ves_icall_System_Threading_Thread_ResetAbort (MonoThreadObjectHandle this_obj
, MonoError
*error
)
2706 MonoInternalThread
*thread
= mono_thread_internal_current ();
2707 gboolean was_aborting
, is_domain_abort
;
2709 LOCK_THREAD (thread
);
2710 was_aborting
= thread
->state
& ThreadState_AbortRequested
;
2711 is_domain_abort
= thread
->flags
& MONO_THREAD_FLAG_APPDOMAIN_ABORT
;
2713 if (was_aborting
&& !is_domain_abort
)
2714 thread
->state
&= ~ThreadState_AbortRequested
;
2715 UNLOCK_THREAD (thread
);
2717 if (!was_aborting
) {
2718 mono_error_set_exception_thread_state (error
, "Unable to reset abort because no abort was requested");
2720 } else if (is_domain_abort
) {
2721 /* Silently ignore abort resets in unloading appdomains */
2725 mono_get_eh_callbacks ()->mono_clear_abort_threshold ();
2726 thread
->abort_exc
= NULL
;
2727 mono_gchandle_free_internal (thread
->abort_state_handle
);
2728 /* This is actually not necessary - the handle
2729 only counts if the exception is set */
2730 thread
->abort_state_handle
= 0;
2735 mono_thread_internal_reset_abort (MonoInternalThread
*thread
)
2737 LOCK_THREAD (thread
);
2739 thread
->state
&= ~ThreadState_AbortRequested
;
2741 if (thread
->abort_exc
) {
2742 mono_get_eh_callbacks ()->mono_clear_abort_threshold ();
2743 thread
->abort_exc
= NULL
;
2744 mono_gchandle_free_internal (thread
->abort_state_handle
);
2745 /* This is actually not necessary - the handle
2746 only counts if the exception is set */
2747 thread
->abort_state_handle
= 0;
2750 UNLOCK_THREAD (thread
);
2753 #ifndef ENABLE_NETCORE
2755 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThreadObjectHandle this_obj
, MonoError
*error
)
2757 MonoInternalThread
*thread
= thread_handle_to_internal_ptr (this_obj
);
2759 if (!thread
->abort_state_handle
)
2760 return NULL_HANDLE
; // No state. No error.
2762 // Convert gc handle to coop handle.
2763 MonoObjectHandle state
= mono_gchandle_get_target_handle (thread
->abort_state_handle
);
2764 g_assert (MONO_HANDLE_BOOL (state
));
2766 MonoDomain
*domain
= mono_domain_get ();
2767 if (MONO_HANDLE_DOMAIN (state
) == domain
)
2768 return state
; // No need to cross domain, return state directly.
2770 // Attempt move state cross-domain.
2771 MonoObjectHandle deserialized
= mono_object_xdomain_representation (state
, domain
, error
);
2773 // If deserialized is null, there must be an error, and vice versa.
2774 g_assert (is_ok (error
) == MONO_HANDLE_BOOL (deserialized
));
2776 if (MONO_HANDLE_BOOL (deserialized
))
2777 return deserialized
; // Cross-domain serialization succeeded. Return it.
2779 // Wrap error in InvalidOperationException.
2780 ERROR_DECL (error_creating_exception
);
2781 MonoExceptionHandle invalid_op_exc
= mono_exception_new_invalid_operation (
2782 "Thread.ExceptionState cannot access an ExceptionState from a different AppDomain", error_creating_exception
);
2783 mono_error_assert_ok (error_creating_exception
);
2784 g_assert (!is_ok (error
) && 1);
2785 MONO_HANDLE_SET (invalid_op_exc
, inner_ex
, mono_error_convert_to_exception_handle (error
));
2786 error_init_reuse (error
);
2787 mono_error_set_exception_handle (error
, invalid_op_exc
);
2788 g_assert (!is_ok (error
) && 2);
2790 // There is state, but we failed to return it.
2796 mono_thread_suspend (MonoInternalThread
*thread
)
2798 LOCK_THREAD (thread
);
2800 if (thread
->state
& (ThreadState_Unstarted
| ThreadState_Aborted
| ThreadState_Stopped
))
2802 UNLOCK_THREAD (thread
);
2806 if (thread
->state
& (ThreadState_Suspended
| ThreadState_SuspendRequested
| ThreadState_AbortRequested
))
2808 UNLOCK_THREAD (thread
);
2812 thread
->state
|= ThreadState_SuspendRequested
;
2814 mono_os_event_reset (thread
->suspended
);
2817 if (thread
== mono_thread_internal_current ()) {
2818 /* calls UNLOCK_THREAD (thread) */
2819 self_suspend_internal ();
2821 /* calls UNLOCK_THREAD (thread) */
2822 async_suspend_internal (thread
, FALSE
);
2828 #ifndef ENABLE_NETCORE
2830 ves_icall_System_Threading_Thread_Suspend (MonoThreadObjectHandle this_obj
, MonoError
*error
)
2832 if (!mono_thread_suspend (thread_handle_to_internal_ptr (this_obj
)))
2833 mono_error_set_exception_thread_not_started_or_dead (error
);
2838 /* LOCKING: LOCK_THREAD(thread) must be held */
2840 mono_thread_resume (MonoInternalThread
*thread
)
2842 if ((thread
->state
& ThreadState_SuspendRequested
) != 0) {
2843 // g_async_safe_printf ("RESUME (1) thread %p\n", thread_get_tid (thread));
2844 thread
->state
&= ~ThreadState_SuspendRequested
;
2846 mono_os_event_set (thread
->suspended
);
2851 if ((thread
->state
& ThreadState_Suspended
) == 0 ||
2852 (thread
->state
& ThreadState_Unstarted
) != 0 ||
2853 (thread
->state
& ThreadState_Aborted
) != 0 ||
2854 (thread
->state
& ThreadState_Stopped
) != 0)
2856 // g_async_safe_printf ("RESUME (2) thread %p\n", thread_get_tid (thread));
2860 // g_async_safe_printf ("RESUME (3) thread %p\n", thread_get_tid (thread));
2863 mono_os_event_set (thread
->suspended
);
2866 if (!thread
->self_suspended
) {
2867 UNLOCK_THREAD (thread
);
2869 /* Awake the thread */
2870 if (!mono_thread_info_resume (thread_get_tid (thread
)))
2873 LOCK_THREAD (thread
);
2876 thread
->state
&= ~ThreadState_Suspended
;
2881 #ifndef ENABLE_NETCORE
2883 ves_icall_System_Threading_Thread_Resume (MonoThreadObjectHandle thread_handle
, MonoError
*error
)
2885 // Internal threads are pinned so shallow coop/handle.
2886 MonoInternalThread
* const internal_thread
= thread_handle_to_internal_ptr (thread_handle
);
2887 gboolean exception
= FALSE
;
2889 if (!internal_thread
) {
2892 LOCK_THREAD (internal_thread
);
2893 if (!mono_thread_resume (internal_thread
))
2895 UNLOCK_THREAD (internal_thread
);
2899 mono_error_set_exception_thread_not_started_or_dead (error
);
2904 mono_threads_is_critical_method (MonoMethod
*method
)
2906 switch (method
->wrapper_type
) {
2907 case MONO_WRAPPER_RUNTIME_INVOKE
:
2908 case MONO_WRAPPER_XDOMAIN_INVOKE
:
2909 case MONO_WRAPPER_XDOMAIN_DISPATCH
:
2916 find_wrapper (MonoMethod
*m
, gint no
, gint ilo
, gboolean managed
, gpointer data
)
2921 if (mono_threads_is_critical_method (m
)) {
2922 *((gboolean
*)data
) = TRUE
;
2929 is_running_protected_wrapper (void)
2931 gboolean found
= FALSE
;
2932 mono_stack_walk (find_wrapper
, &found
);
2940 mono_thread_stop (MonoThread
*thread
)
2942 MonoInternalThread
*internal
= thread
->internal_thread
;
2944 if (!request_thread_abort (internal
, NULL
, FALSE
))
2947 if (internal
== mono_thread_internal_current ()) {
2949 self_abort_internal (error
);
2951 This function is part of the embeding API and has no way to return the exception
2952 to be thrown. So what we do is keep the old behavior and raise the exception.
2954 mono_error_raise_exception_deprecated (error
); /* OK to throw, see note */
2956 async_abort_internal (internal
, TRUE
);
2961 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr
)
2963 gint8 tmp
= *(volatile gint8
*)ptr
;
2964 mono_memory_barrier ();
2969 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr
)
2971 gint16 tmp
= *(volatile gint16
*)ptr
;
2972 mono_memory_barrier ();
2977 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr
)
2979 gint32 tmp
= *(volatile gint32
*)ptr
;
2980 mono_memory_barrier ();
2985 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr
)
2987 gint64 tmp
= *(volatile gint64
*)ptr
;
2988 mono_memory_barrier ();
2993 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr
)
2995 volatile void *tmp
= *(volatile void **)ptr
;
2996 mono_memory_barrier ();
2997 return (void *) tmp
;
3001 ves_icall_System_Threading_Thread_VolatileReadObject (void *ptr
)
3003 volatile MonoObject
*tmp
= *(volatile MonoObject
**)ptr
;
3004 mono_memory_barrier ();
3005 return (MonoObject
*) tmp
;
3009 ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr
)
3011 double tmp
= *(volatile double *)ptr
;
3012 mono_memory_barrier ();
3017 ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr
)
3019 float tmp
= *(volatile float *)ptr
;
3020 mono_memory_barrier ();
3025 ves_icall_System_Threading_Volatile_Read1 (void *ptr
)
3027 return mono_atomic_load_i8 ((volatile gint8
*)ptr
);
3031 ves_icall_System_Threading_Volatile_Read2 (void *ptr
)
3033 return mono_atomic_load_i16 ((volatile gint16
*)ptr
);
3037 ves_icall_System_Threading_Volatile_Read4 (void *ptr
)
3039 return mono_atomic_load_i32 ((volatile gint32
*)ptr
);
3043 ves_icall_System_Threading_Volatile_Read8 (void *ptr
)
3045 #if SIZEOF_VOID_P == 4
3046 if (G_UNLIKELY ((size_t)ptr
& 0x7)) {
3048 mono_interlocked_lock ();
3049 val
= *(gint64
*)ptr
;
3050 mono_interlocked_unlock ();
3054 return mono_atomic_load_i64 ((volatile gint64
*)ptr
);
3058 ves_icall_System_Threading_Volatile_ReadU8 (void *ptr
)
3060 #if SIZEOF_VOID_P == 4
3061 if (G_UNLIKELY ((size_t)ptr
& 0x7)) {
3063 mono_interlocked_lock ();
3064 val
= *(guint64
*)ptr
;
3065 mono_interlocked_unlock ();
3069 return (guint64
)mono_atomic_load_i64 ((volatile gint64
*)ptr
);
3073 ves_icall_System_Threading_Volatile_ReadIntPtr (void *ptr
)
3075 return mono_atomic_load_ptr ((volatile gpointer
*)ptr
);
3079 ves_icall_System_Threading_Volatile_ReadDouble (void *ptr
)
3083 #if SIZEOF_VOID_P == 4
3084 if (G_UNLIKELY ((size_t)ptr
& 0x7)) {
3086 mono_interlocked_lock ();
3087 val
= *(double*)ptr
;
3088 mono_interlocked_unlock ();
3093 u
.ival
= mono_atomic_load_i64 ((volatile gint64
*)ptr
);
3099 ves_icall_System_Threading_Volatile_ReadFloat (void *ptr
)
3103 u
.ival
= mono_atomic_load_i32 ((volatile gint32
*)ptr
);
3109 ves_icall_System_Threading_Volatile_Read_T (void *ptr
)
3111 return (MonoObject
*)mono_atomic_load_ptr ((volatile gpointer
*)ptr
);
3115 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr
, gint8 value
)
3117 mono_memory_barrier ();
3118 *(volatile gint8
*)ptr
= value
;
3122 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr
, gint16 value
)
3124 mono_memory_barrier ();
3125 *(volatile gint16
*)ptr
= value
;
3129 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr
, gint32 value
)
3131 mono_memory_barrier ();
3132 *(volatile gint32
*)ptr
= value
;
3136 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr
, gint64 value
)
3138 mono_memory_barrier ();
3139 *(volatile gint64
*)ptr
= value
;
3143 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr
, void *value
)
3145 mono_memory_barrier ();
3146 *(volatile void **)ptr
= value
;
3150 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr
, MonoObject
*value
)
3152 mono_memory_barrier ();
3153 mono_gc_wbarrier_generic_store_internal (ptr
, value
);
3157 ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr
, double value
)
3159 mono_memory_barrier ();
3160 *(volatile double *)ptr
= value
;
3164 ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr
, float value
)
3166 mono_memory_barrier ();
3167 *(volatile float *)ptr
= value
;
3171 ves_icall_System_Threading_Volatile_Write1 (void *ptr
, gint8 value
)
3173 mono_atomic_store_i8 ((volatile gint8
*)ptr
, value
);
3177 ves_icall_System_Threading_Volatile_Write2 (void *ptr
, gint16 value
)
3179 mono_atomic_store_i16 ((volatile gint16
*)ptr
, value
);
3183 ves_icall_System_Threading_Volatile_Write4 (void *ptr
, gint32 value
)
3185 mono_atomic_store_i32 ((volatile gint32
*)ptr
, value
);
3189 ves_icall_System_Threading_Volatile_Write8 (void *ptr
, gint64 value
)
3191 #if SIZEOF_VOID_P == 4
3192 if (G_UNLIKELY ((size_t)ptr
& 0x7)) {
3193 mono_interlocked_lock ();
3194 *(gint64
*)ptr
= value
;
3195 mono_interlocked_unlock ();
3200 mono_atomic_store_i64 ((volatile gint64
*)ptr
, value
);
3204 ves_icall_System_Threading_Volatile_WriteU8 (void *ptr
, guint64 value
)
3206 #if SIZEOF_VOID_P == 4
3207 if (G_UNLIKELY ((size_t)ptr
& 0x7)) {
3208 mono_interlocked_lock ();
3209 *(guint64
*)ptr
= value
;
3210 mono_interlocked_unlock ();
3215 mono_atomic_store_i64 ((volatile gint64
*)ptr
, (gint64
)value
);
3219 ves_icall_System_Threading_Volatile_WriteIntPtr (void *ptr
, void *value
)
3221 mono_atomic_store_ptr ((volatile gpointer
*)ptr
, value
);
3225 ves_icall_System_Threading_Volatile_WriteDouble (void *ptr
, double value
)
3229 #if SIZEOF_VOID_P == 4
3230 if (G_UNLIKELY ((size_t)ptr
& 0x7)) {
3231 mono_interlocked_lock ();
3232 *(double*)ptr
= value
;
3233 mono_interlocked_unlock ();
3240 mono_atomic_store_i64 ((volatile gint64
*)ptr
, u
.ival
);
3244 ves_icall_System_Threading_Volatile_WriteFloat (void *ptr
, float value
)
3250 mono_atomic_store_i32 ((volatile gint32
*)ptr
, u
.ival
);
3254 ves_icall_System_Threading_Volatile_Write_T (void *ptr
, MonoObject
*value
)
3256 mono_gc_wbarrier_generic_store_atomic_internal (ptr
, value
);
3260 free_context (void *user_data
)
3262 ContextStaticData
*data
= (ContextStaticData
*)user_data
;
3264 mono_threads_lock ();
3267 * There is no guarantee that, by the point this reference queue callback
3268 * has been invoked, the GC handle associated with the object will fail to
3269 * resolve as one might expect. So if we don't free and remove the GC
3270 * handle here, free_context_static_data_helper () could end up resolving
3271 * a GC handle to an actually-dead context which would contain a pointer
3272 * to an already-freed static data segment, resulting in a crash when
3275 g_hash_table_remove (contexts
, GUINT_TO_POINTER (data
->gc_handle
));
3277 mono_threads_unlock ();
3279 mono_gchandle_free_internal (data
->gc_handle
);
3280 mono_free_static_data (data
->static_data
);
3285 mono_threads_register_app_context (MonoAppContextHandle ctx
, MonoError
*error
)
3288 mono_threads_lock ();
3290 //g_print ("Registering context %d in domain %d\n", ctx->context_id, ctx->domain_id);
3293 contexts
= g_hash_table_new (NULL
, NULL
);
3296 context_queue
= mono_gc_reference_queue_new_internal (free_context
);
3298 gpointer gch
= GUINT_TO_POINTER (mono_gchandle_new_weakref_from_handle (MONO_HANDLE_CAST (MonoObject
, ctx
)));
3299 g_hash_table_insert (contexts
, gch
, gch
);
3302 * We use this intermediate structure to contain a duplicate pointer to
3303 * the static data because we can't rely on being able to resolve the GC
3304 * handle in the reference queue callback.
3306 ContextStaticData
*data
= g_new0 (ContextStaticData
, 1);
3307 data
->gc_handle
= GPOINTER_TO_UINT (gch
);
3308 MONO_HANDLE_SETVAL (ctx
, data
, ContextStaticData
*, data
);
3310 context_adjust_static_data (ctx
);
3311 mono_gc_reference_queue_add_handle (context_queue
, ctx
, data
);
3313 mono_threads_unlock ();
3315 MONO_PROFILER_RAISE (context_loaded
, (MONO_HANDLE_RAW (ctx
)));
3319 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (MonoAppContextHandle ctx
, MonoError
*error
)
3321 mono_threads_register_app_context (ctx
, error
);
3325 mono_threads_release_app_context (MonoAppContext
* ctx
, MonoError
*error
)
3328 * NOTE: Since finalizers are unreliable for the purposes of ensuring
3329 * cleanup in exceptional circumstances, we don't actually do any
3330 * cleanup work here. We instead do this via a reference queue.
3333 //g_print ("Releasing context %d in domain %d\n", ctx->context_id, ctx->domain_id);
3335 MONO_PROFILER_RAISE (context_unloaded
, (ctx
));
3339 ves_icall_System_Runtime_Remoting_Contexts_Context_ReleaseContext (MonoAppContextHandle ctx
, MonoError
*error
)
3341 mono_threads_release_app_context (MONO_HANDLE_RAW (ctx
), error
); /* FIXME use handles in mono_threads_release_app_context */
3344 void mono_thread_init (MonoThreadStartCB start_cb
,
3345 MonoThreadAttachCB attach_cb
)
3347 mono_coop_mutex_init_recursive (&threads_mutex
);
3349 #if SIZEOF_VOID_P == 4
3350 mono_os_mutex_init (&interlocked_mutex
);
3352 mono_coop_mutex_init_recursive(&joinable_threads_mutex
);
3354 mono_os_event_init (&background_change_event
, FALSE
);
3356 mono_coop_cond_init (&pending_native_thread_join_calls_event
);
3357 mono_coop_cond_init (&zero_pending_joinable_thread_event
);
3359 mono_init_static_data_info (&thread_static_info
);
3360 mono_init_static_data_info (&context_static_info
);
3362 mono_thread_start_cb
= start_cb
;
3363 mono_thread_attach_cb
= attach_cb
;
3368 thread_attach (MonoThreadInfo
*info
)
3370 return mono_gc_thread_attach (info
);
3374 thread_detach (MonoThreadInfo
*info
)
3376 MonoInternalThread
*internal
;
3379 /* If a delegate is passed to native code and invoked on a thread we dont
3380 * know about, marshal will register it with mono_threads_attach_coop, but
3381 * we have no way of knowing when that thread goes away. SGen has a TSD
3382 * so we assume that if the domain is still registered, we can detach
3386 g_assert (mono_thread_info_is_current (info
));
3388 if (!mono_thread_info_try_get_internal_thread_gchandle (info
, &gchandle
))
3391 internal
= (MonoInternalThread
*) mono_gchandle_get_target_internal (gchandle
);
3392 g_assert (internal
);
3394 mono_thread_detach_internal (internal
);
3398 thread_detach_with_lock (MonoThreadInfo
*info
)
3400 mono_gc_thread_detach_with_lock (info
);
3404 thread_in_critical_region (MonoThreadInfo
*info
)
3406 return mono_gc_thread_in_critical_region (info
);
3410 ip_in_critical_region (MonoDomain
*domain
, gpointer ip
)
3416 * We pass false for 'try_aot' so this becomes async safe.
3417 * It won't find aot methods whose jit info is not yet loaded,
3418 * so we preload their jit info in the JIT.
3420 ji
= mono_jit_info_table_find_internal (domain
, ip
, FALSE
, FALSE
);
3424 method
= mono_jit_info_get_method (ji
);
3427 return mono_gc_is_critical_method (method
);
3431 thread_flags_changing (MonoThreadInfoFlags old
, MonoThreadInfoFlags new_
)
3433 mono_gc_skip_thread_changing (!!(new_
& MONO_THREAD_INFO_FLAGS_NO_GC
));
3437 thread_flags_changed (MonoThreadInfoFlags old
, MonoThreadInfoFlags new_
)
3439 mono_gc_skip_thread_changed (!!(new_
& MONO_THREAD_INFO_FLAGS_NO_GC
));
3443 mono_thread_callbacks_init (void)
3445 MonoThreadInfoCallbacks cb
;
3447 memset (&cb
, 0, sizeof(cb
));
3448 cb
.thread_attach
= thread_attach
;
3449 cb
.thread_detach
= thread_detach
;
3450 cb
.thread_detach_with_lock
= thread_detach_with_lock
;
3451 cb
.ip_in_critical_region
= ip_in_critical_region
;
3452 cb
.thread_in_critical_region
= thread_in_critical_region
;
3453 cb
.thread_flags_changing
= thread_flags_changing
;
3454 cb
.thread_flags_changed
= thread_flags_changed
;
3455 mono_thread_info_callbacks_init (&cb
);
3459 * mono_thread_cleanup:
3462 mono_thread_cleanup (void)
3464 /* Wait for pending threads to park on joinable threads list */
3465 /* NOTE, waiting on this should be extremely rare and will only happen */
3466 /* under certain specific conditions. */
3467 gboolean wait_result
= threads_wait_pending_joinable_threads (2000);
3469 g_warning ("Waiting on threads to park on joinable thread list timed out.");
3471 mono_threads_join_threads ();
3473 #if !defined(HOST_WIN32)
3474 /* The main thread must abandon any held mutexes (particularly
3475 * important for named mutexes as they are shared across
3476 * processes, see bug 74680.) This will happen when the
3477 * thread exits, but if it's not running in a subthread it
3478 * won't exit in time.
3480 if (!mono_runtime_get_no_exec ())
3481 mono_w32mutex_abandon (mono_thread_internal_current ());
3485 /* This stuff needs more testing, it seems one of these
3486 * critical sections can be locked when mono_thread_cleanup is
3489 mono_coop_mutex_destroy (&threads_mutex
);
3490 mono_os_mutex_destroy (&interlocked_mutex
);
3491 mono_os_mutex_destroy (&delayed_free_table_mutex
);
3492 mono_os_mutex_destroy (&small_id_mutex
);
3493 mono_coop_cond_destroy (&zero_pending_joinable_thread_event
);
3494 mono_coop_cond_destroy (&pending_native_thread_join_calls_event
);
3495 mono_os_event_destroy (&background_change_event
);
3500 mono_threads_install_cleanup (MonoThreadCleanupFunc func
)
3502 mono_thread_cleanup_fn
= func
;
3506 * mono_thread_set_manage_callback:
3509 mono_thread_set_manage_callback (MonoThread
*thread
, MonoThreadManageCallback func
)
3511 thread
->internal_thread
->manage_callback
= func
;
3515 static void print_tids (gpointer key
, gpointer value
, gpointer user
)
3517 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
3518 * sizeof(uint) and a cast to uint would overflow
3520 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
3521 * print this as a pointer.
3523 g_message ("Waiting for: %p", key
);
3528 MonoThreadHandle
*handles
[MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
];
3529 MonoInternalThread
*threads
[MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
];
3534 wait_for_tids (struct wait_data
*wait
, guint32 timeout
, gboolean check_state_change
)
3537 MonoThreadInfoWaitRet ret
;
3539 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__
, wait
->num
));
3541 /* Add the thread state change event, so it wakes
3542 * up if a thread changes to background mode. */
3545 if (check_state_change
)
3546 ret
= mono_thread_info_wait_multiple_handle (wait
->handles
, wait
->num
, &background_change_event
, FALSE
, timeout
, TRUE
);
3548 ret
= mono_thread_info_wait_multiple_handle (wait
->handles
, wait
->num
, NULL
, TRUE
, timeout
, TRUE
);
3551 if (ret
== MONO_THREAD_INFO_WAIT_RET_FAILED
) {
3552 /* See the comment in build_wait_tids() */
3553 THREAD_DEBUG (g_message ("%s: Wait failed", __func__
));
3557 for( i
= 0; i
< wait
->num
; i
++)
3558 mono_threads_close_thread_handle (wait
->handles
[i
]);
3560 if (ret
>= MONO_THREAD_INFO_WAIT_RET_SUCCESS_0
&& ret
< (MONO_THREAD_INFO_WAIT_RET_SUCCESS_0
+ wait
->num
)) {
3561 MonoInternalThread
*internal
;
3563 internal
= wait
->threads
[ret
- MONO_THREAD_INFO_WAIT_RET_SUCCESS_0
];
3565 mono_threads_lock ();
3566 if (mono_g_hash_table_lookup (threads
, (gpointer
) internal
->tid
) == internal
)
3567 g_error ("%s: failed to call mono_thread_detach_internal on thread %p, InternalThread: %p", __func__
, internal
->tid
, internal
);
3568 mono_threads_unlock ();
3572 static void build_wait_tids (gpointer key
, gpointer value
, gpointer user
)
3574 struct wait_data
*wait
=(struct wait_data
*)user
;
3576 if(wait
->num
<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
- 1) {
3577 MonoInternalThread
*thread
=(MonoInternalThread
*)value
;
3579 /* Ignore background threads, we abort them later */
3580 /* Do not lock here since it is not needed and the caller holds threads_lock */
3581 if (thread
->state
& ThreadState_Background
) {
3582 THREAD_DEBUG (g_message ("%s: ignoring background thread %" G_GSIZE_FORMAT
, __func__
, (gsize
)thread
->tid
));
3583 return; /* just leave, ignore */
3586 if (mono_gc_is_finalizer_internal_thread (thread
)) {
3587 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %" G_GSIZE_FORMAT
, __func__
, (gsize
)thread
->tid
));
3591 if (thread
== mono_thread_internal_current ()) {
3592 THREAD_DEBUG (g_message ("%s: ignoring current thread %" G_GSIZE_FORMAT
, __func__
, (gsize
)thread
->tid
));
3596 if (mono_thread_get_main () && (thread
== mono_thread_get_main ()->internal_thread
)) {
3597 THREAD_DEBUG (g_message ("%s: ignoring main thread %" G_GSIZE_FORMAT
, __func__
, (gsize
)thread
->tid
));
3601 if (thread
->flags
& MONO_THREAD_FLAG_DONT_MANAGE
) {
3602 THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT
"with DONT_MANAGE flag set.", __func__
, (gsize
)thread
->tid
));
3606 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__
, thread
));
3607 if ((thread
->manage_callback
== NULL
) || (thread
->manage_callback (thread
->root_domain_thread
) == TRUE
)) {
3608 wait
->handles
[wait
->num
]=mono_threads_open_thread_handle (thread
->handle
);
3609 wait
->threads
[wait
->num
]=thread
;
3612 THREAD_DEBUG (g_message ("%s: adding thread %" G_GSIZE_FORMAT
, __func__
, (gsize
)thread
->tid
));
3614 THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %" G_GSIZE_FORMAT
, __func__
, (gsize
)thread
->tid
));
3619 /* Just ignore the rest, we can't do anything with
3626 abort_threads (gpointer key
, gpointer value
, gpointer user
)
3628 struct wait_data
*wait
=(struct wait_data
*)user
;
3629 MonoNativeThreadId self
= mono_native_thread_id_get ();
3630 MonoInternalThread
*thread
= (MonoInternalThread
*)value
;
3632 if (wait
->num
>= MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
)
3635 if (mono_native_thread_id_equals (thread_get_tid (thread
), self
))
3637 if (mono_gc_is_finalizer_internal_thread (thread
))
3640 if ((thread
->flags
& MONO_THREAD_FLAG_DONT_MANAGE
))
3643 wait
->handles
[wait
->num
] = mono_threads_open_thread_handle (thread
->handle
);
3644 wait
->threads
[wait
->num
] = thread
;
3647 THREAD_DEBUG (g_print ("%s: Aborting id: %" G_GSIZE_FORMAT
"\n", __func__
, (gsize
)thread
->tid
));
3648 mono_thread_internal_abort (thread
, FALSE
);
3652 * mono_threads_set_shutting_down:
3654 * Is called by a thread that wants to shut down Mono. If the runtime is already
3655 * shutting down, the calling thread is suspended/stopped, and this function never
3659 mono_threads_set_shutting_down (void)
3661 MonoInternalThread
*current_thread
= mono_thread_internal_current ();
3663 mono_threads_lock ();
3665 if (shutting_down
) {
3666 mono_threads_unlock ();
3668 /* Make sure we're properly suspended/stopped */
3670 LOCK_THREAD (current_thread
);
3672 if (current_thread
->state
& (ThreadState_SuspendRequested
| ThreadState_AbortRequested
)) {
3673 UNLOCK_THREAD (current_thread
);
3674 mono_thread_execute_interruption_void ();
3676 UNLOCK_THREAD (current_thread
);
3679 /*since we're killing the thread, detach it.*/
3680 mono_thread_detach_internal (current_thread
);
3682 /* Wake up other threads potentially waiting for us */
3683 mono_thread_info_exit (0);
3685 shutting_down
= TRUE
;
3687 /* Not really a background state change, but this will
3688 * interrupt the main thread if it is waiting for all
3689 * the other threads.
3692 mono_os_event_set (&background_change_event
);
3695 mono_threads_unlock ();
3700 * mono_thread_manage:
3703 mono_thread_manage (void)
3705 struct wait_data wait_data
;
3706 struct wait_data
*wait
= &wait_data
;
3708 memset (wait
, 0, sizeof (struct wait_data
));
3709 /* join each thread that's still running */
3710 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__
));
3712 mono_threads_lock ();
3714 THREAD_DEBUG (g_message("%s: No threads", __func__
));
3715 mono_threads_unlock ();
3719 mono_threads_unlock ();
3722 mono_threads_lock ();
3723 if (shutting_down
) {
3724 /* somebody else is shutting down */
3725 mono_threads_unlock ();
3728 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__
, mono_g_hash_table_size (threads
));
3729 mono_g_hash_table_foreach (threads
, print_tids
, NULL
));
3732 mono_os_event_reset (&background_change_event
);
3735 /* We must zero all InternalThread pointers to avoid making the GC unhappy. */
3736 memset (wait
->threads
, 0, sizeof (wait
->threads
));
3737 mono_g_hash_table_foreach (threads
, build_wait_tids
, wait
);
3738 mono_threads_unlock ();
3740 /* Something to wait for */
3741 wait_for_tids (wait
, MONO_INFINITE_WAIT
, TRUE
);
3742 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__
, wait
->num
));
3743 } while(wait
->num
>0);
3745 /* Mono is shutting down, so just wait for the end */
3746 if (!mono_runtime_try_shutdown ()) {
3747 /*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
3748 mono_thread_suspend (mono_thread_internal_current ());
3749 mono_thread_execute_interruption_void ();
3752 #ifndef ENABLE_NETCORE
3754 * Under netcore, we don't abort any threads, just exit.
3755 * This is not a problem since we don't do runtime cleanup either.
3758 * Remove everything but the finalizer thread and self.
3759 * Also abort all the background threads
3762 mono_threads_lock ();
3765 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3766 memset (wait
->threads
, 0, sizeof (wait
->threads
));
3767 mono_g_hash_table_foreach (threads
, abort_threads
, wait
);
3769 mono_threads_unlock ();
3771 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__
, wait
->num
));
3772 if (wait
->num
> 0) {
3773 /* Something to wait for */
3774 wait_for_tids (wait
, MONO_INFINITE_WAIT
, FALSE
);
3776 } while (wait
->num
> 0);
3780 * give the subthreads a chance to really quit (this is mainly needed
3781 * to get correct user and system times from getrusage/wait/time(1)).
3782 * This could be removed if we avoid pthread_detach() and use pthread_join().
3784 mono_thread_info_yield ();
3788 collect_threads_for_suspend (gpointer key
, gpointer value
, gpointer user_data
)
3790 MonoInternalThread
*thread
= (MonoInternalThread
*)value
;
3791 struct wait_data
*wait
= (struct wait_data
*)user_data
;
3794 * We try to exclude threads early, to avoid running into the MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
3796 * This needs no locking.
3798 if ((thread
->state
& ThreadState_Suspended
) != 0 ||
3799 (thread
->state
& ThreadState_Stopped
) != 0)
3802 if (wait
->num
<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
) {
3803 wait
->handles
[wait
->num
] = mono_threads_open_thread_handle (thread
->handle
);
3804 wait
->threads
[wait
->num
] = thread
;
3810 * mono_thread_suspend_all_other_threads:
3812 * Suspend all managed threads except the finalizer thread and this thread. It is
3813 * not possible to resume them later.
3815 void mono_thread_suspend_all_other_threads (void)
3817 struct wait_data wait_data
;
3818 struct wait_data
*wait
= &wait_data
;
3820 MonoNativeThreadId self
= mono_native_thread_id_get ();
3821 guint32 eventidx
= 0;
3822 gboolean starting
, finished
;
3824 memset (wait
, 0, sizeof (struct wait_data
));
3826 * The other threads could be in an arbitrary state at this point, i.e.
3827 * they could be starting up, shutting down etc. This means that there could be
3828 * threads which are not even in the threads hash table yet.
3832 * First we set a barrier which will be checked by all threads before they
3833 * are added to the threads hash table, and they will exit if the flag is set.
3834 * This ensures that no threads could be added to the hash later.
3835 * We will use shutting_down as the barrier for now.
3837 g_assert (shutting_down
);
3840 * We make multiple calls to WaitForMultipleObjects since:
3841 * - we can only wait for MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS threads
3842 * - some threads could exit without becoming suspended
3847 * Make a copy of the hashtable since we can't do anything with
3848 * threads while threads_mutex is held.
3851 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3852 memset (wait
->threads
, 0, sizeof (wait
->threads
));
3853 mono_threads_lock ();
3854 mono_g_hash_table_foreach (threads
, collect_threads_for_suspend
, wait
);
3855 mono_threads_unlock ();
3858 /* Get the suspended events that we'll be waiting for */
3859 for (i
= 0; i
< wait
->num
; ++i
) {
3860 MonoInternalThread
*thread
= wait
->threads
[i
];
3862 if (mono_native_thread_id_equals (thread_get_tid (thread
), self
)
3863 || mono_gc_is_finalizer_internal_thread (thread
)
3864 || (thread
->flags
& MONO_THREAD_FLAG_DONT_MANAGE
)
3866 mono_threads_close_thread_handle (wait
->handles
[i
]);
3867 wait
->threads
[i
] = NULL
;
3871 LOCK_THREAD (thread
);
3873 if (thread
->state
& (ThreadState_Suspended
| ThreadState_Stopped
)) {
3874 UNLOCK_THREAD (thread
);
3875 mono_threads_close_thread_handle (wait
->handles
[i
]);
3876 wait
->threads
[i
] = NULL
;
3882 /* Convert abort requests into suspend requests */
3883 if ((thread
->state
& ThreadState_AbortRequested
) != 0)
3884 thread
->state
&= ~ThreadState_AbortRequested
;
3886 thread
->state
|= ThreadState_SuspendRequested
;
3888 mono_os_event_reset (thread
->suspended
);
3891 /* Signal the thread to suspend + calls UNLOCK_THREAD (thread) */
3892 async_suspend_internal (thread
, TRUE
);
3894 mono_threads_close_thread_handle (wait
->handles
[i
]);
3895 wait
->threads
[i
] = NULL
;
3897 if (eventidx
<= 0) {
3899 * If there are threads which are starting up, we wait until they
3900 * are suspended when they try to register in the threads hash.
3901 * This is guaranteed to finish, since the threads which can create new
3902 * threads get suspended after a while.
3903 * FIXME: The finalizer thread can still create new threads.
3905 mono_threads_lock ();
3906 if (threads_starting_up
)
3907 starting
= mono_g_hash_table_size (threads_starting_up
) > 0;
3910 mono_threads_unlock ();
3912 mono_thread_info_sleep (100, NULL
);
3920 MonoInternalThread
*thread
;
3921 MonoStackFrameInfo
*frames
;
3922 int nframes
, max_frames
;
3923 int nthreads
, max_threads
;
3924 MonoInternalThread
**threads
;
3925 } ThreadDumpUserData
;
3927 static gboolean thread_dump_requested
;
3929 /* This needs to be async safe */
3931 collect_frame (MonoStackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
3933 ThreadDumpUserData
*ud
= (ThreadDumpUserData
*)data
;
3935 if (ud
->nframes
< ud
->max_frames
) {
3936 memcpy (&ud
->frames
[ud
->nframes
], frame
, sizeof (MonoStackFrameInfo
));
3943 /* This needs to be async safe */
3944 static SuspendThreadResult
3945 get_thread_dump (MonoThreadInfo
*info
, gpointer ud
)
3947 ThreadDumpUserData
*user_data
= (ThreadDumpUserData
*)ud
;
3948 MonoInternalThread
*thread
= user_data
->thread
;
3951 /* This no longer works with remote unwinding */
3952 g_string_append_printf (text
, " tid=0x%p this=0x%p ", (gpointer
)(gsize
)thread
->tid
, thread
);
3953 mono_thread_internal_describe (thread
, text
);
3954 g_string_append (text
, "\n");
3957 if (thread
== mono_thread_internal_current ())
3958 mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (collect_frame
, NULL
, MONO_UNWIND_SIGNAL_SAFE
, ud
);
3960 mono_get_eh_callbacks ()->mono_walk_stack_with_state (collect_frame
, mono_thread_info_get_suspend_state (info
), MONO_UNWIND_SIGNAL_SAFE
, ud
);
3962 return MonoResumeThread
;
3966 int nthreads
, max_threads
;
3969 } CollectThreadsUserData
;
3972 int nthreads
, max_threads
;
3973 MonoNativeThreadId
*threads
;
3974 } CollectThreadIdsUserData
;
3977 collect_thread (gpointer key
, gpointer value
, gpointer user
)
3979 CollectThreadsUserData
*ud
= (CollectThreadsUserData
*)user
;
3980 MonoInternalThread
*thread
= (MonoInternalThread
*)value
;
3982 if (ud
->nthreads
< ud
->max_threads
)
3983 ud
->threads
[ud
->nthreads
++] = mono_gchandle_new_internal (&thread
->obj
, TRUE
);
3987 collect_thread_id (gpointer key
, gpointer value
, gpointer user
)
3989 CollectThreadIdsUserData
*ud
= (CollectThreadIdsUserData
*)user
;
3990 MonoInternalThread
*thread
= (MonoInternalThread
*)value
;
3992 if (ud
->nthreads
< ud
->max_threads
)
3993 ud
->threads
[ud
->nthreads
++] = thread_get_tid (thread
);
3997 * Collect running threads into the THREADS array.
3998 * THREADS should be an array allocated on the stack.
4001 collect_threads (guint32
*thread_handles
, int max_threads
)
4003 CollectThreadsUserData ud
;
4005 mono_memory_barrier ();
4009 memset (&ud
, 0, sizeof (ud
));
4010 /* This array contains refs, but its on the stack, so its ok */
4011 ud
.threads
= thread_handles
;
4012 ud
.max_threads
= max_threads
;
4014 mono_threads_lock ();
4015 mono_g_hash_table_foreach (threads
, collect_thread
, &ud
);
4016 mono_threads_unlock ();
4022 collect_thread_ids (MonoNativeThreadId
*thread_ids
, int max_threads
)
4024 CollectThreadIdsUserData ud
;
4026 mono_memory_barrier ();
4030 memset (&ud
, 0, sizeof (ud
));
4031 /* This array contains refs, but its on the stack, so its ok */
4032 ud
.threads
= thread_ids
;
4033 ud
.max_threads
= max_threads
;
4035 mono_threads_lock ();
4036 mono_g_hash_table_foreach (threads
, collect_thread_id
, &ud
);
4037 mono_threads_unlock ();
4043 dump_thread (MonoInternalThread
*thread
, ThreadDumpUserData
*ud
, FILE* output_file
)
4045 GString
* text
= g_string_new (0);
4047 GError
*gerror
= NULL
;
4050 ud
->thread
= thread
;
4053 /* Collect frames for the thread */
4054 if (thread
== mono_thread_internal_current ()) {
4055 get_thread_dump (mono_thread_info_current (), ud
);
4057 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread
), FALSE
, get_thread_dump
, ud
);
4061 * Do all the non async-safe work outside of get_thread_dump.
4064 name
= g_utf16_to_utf8 (thread
->name
, thread
->name_len
, NULL
, NULL
, &gerror
);
4066 g_string_append_printf (text
, "\n\"%s\"", name
);
4069 else if (thread
->threadpool_thread
) {
4070 g_string_append (text
, "\n\"<threadpool thread>\"");
4072 g_string_append (text
, "\n\"<unnamed thread>\"");
4075 for (i
= 0; i
< ud
->nframes
; ++i
) {
4076 MonoStackFrameInfo
*frame
= &ud
->frames
[i
];
4077 MonoMethod
*method
= NULL
;
4079 if (frame
->type
== FRAME_TYPE_MANAGED
)
4080 method
= mono_jit_info_get_method (frame
->ji
);
4083 gchar
*location
= mono_debug_print_stack_frame (method
, frame
->native_offset
, frame
->domain
);
4084 g_string_append_printf (text
, " %s\n", location
);
4087 g_string_append_printf (text
, " at <unknown> <0x%05x>\n", frame
->native_offset
);
4091 g_fprintf (output_file
, "%s", text
->str
);
4093 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
4094 OutputDebugStringA(text
->str
);
4097 g_string_free (text
, TRUE
);
4098 fflush (output_file
);
4102 mono_get_time_of_day (struct timeval
*tv
) {
4106 tv
->tv_sec
= time
.time
;
4107 tv
->tv_usec
= time
.millitm
* 1000;
4109 if (gettimeofday (tv
, NULL
) == -1) {
4110 g_error ("gettimeofday() failed; errno is %d (%s)", errno
, strerror (errno
));
4116 mono_local_time (const struct timeval
*tv
, struct tm
*tm
) {
4117 #ifdef HAVE_LOCALTIME_R
4118 localtime_r(&tv
->tv_sec
, tm
);
4120 time_t const tv_sec
= tv
->tv_sec
; // Copy due to Win32/Posix contradiction.
4121 *tm
= *localtime (&tv_sec
);
4126 mono_threads_perform_thread_dump (void)
4128 FILE* output_file
= NULL
;
4129 ThreadDumpUserData ud
;
4130 guint32 thread_array
[128];
4131 int tindex
, nthreads
;
4133 if (!thread_dump_requested
)
4136 if (thread_dump_dir
!= NULL
) {
4137 GString
* path
= g_string_new (0);
4142 mono_get_time_of_day (&tv
);
4143 mono_local_time(&tv
, &tod
);
4144 strftime(time_str
, sizeof(time_str
), MONO_STRFTIME_F
"_" MONO_STRFTIME_T
, &tod
);
4145 ms
= tv
.tv_usec
/ 1000;
4146 g_string_append_printf (path
, "%s/%s.%03ld.tdump", thread_dump_dir
, time_str
, ms
);
4147 output_file
= fopen (path
->str
, "w");
4148 g_string_free (path
, TRUE
);
4150 if (output_file
== NULL
) {
4151 g_print ("Full thread dump:\n");
4154 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
4155 nthreads
= collect_threads (thread_array
, 128);
4157 memset (&ud
, 0, sizeof (ud
));
4158 ud
.frames
= g_new0 (MonoStackFrameInfo
, 256);
4159 ud
.max_frames
= 256;
4161 for (tindex
= 0; tindex
< nthreads
; ++tindex
) {
4162 guint32 handle
= thread_array
[tindex
];
4163 MonoInternalThread
*thread
= (MonoInternalThread
*) mono_gchandle_get_target_internal (handle
);
4164 dump_thread (thread
, &ud
, output_file
!= NULL
? output_file
: stdout
);
4165 mono_gchandle_free_internal (handle
);
4168 if (output_file
!= NULL
) {
4169 fclose (output_file
);
4173 thread_dump_requested
= FALSE
;
4176 /* Obtain the thread dump of all threads */
4178 mono_threads_get_thread_dump (MonoArray
**out_threads
, MonoArray
**out_stack_frames
, MonoError
*error
)
4181 ThreadDumpUserData ud
;
4182 guint32 thread_array
[128];
4183 MonoDomain
*domain
= mono_domain_get ();
4184 MonoDebugSourceLocation
*location
;
4185 int tindex
, nthreads
;
4189 *out_threads
= NULL
;
4190 *out_stack_frames
= NULL
;
4192 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
4193 nthreads
= collect_threads (thread_array
, 128);
4195 memset (&ud
, 0, sizeof (ud
));
4196 ud
.frames
= g_new0 (MonoStackFrameInfo
, 256);
4197 ud
.max_frames
= 256;
4199 *out_threads
= mono_array_new_checked (domain
, mono_defaults
.thread_class
, nthreads
, error
);
4200 goto_if_nok (error
, leave
);
4201 *out_stack_frames
= mono_array_new_checked (domain
, mono_defaults
.array_class
, nthreads
, error
);
4202 goto_if_nok (error
, leave
);
4204 for (tindex
= 0; tindex
< nthreads
; ++tindex
) {
4205 guint32 handle
= thread_array
[tindex
];
4206 MonoInternalThread
*thread
= (MonoInternalThread
*) mono_gchandle_get_target_internal (handle
);
4208 MonoArray
*thread_frames
;
4214 /* Collect frames for the thread */
4215 if (thread
== mono_thread_internal_current ()) {
4216 get_thread_dump (mono_thread_info_current (), &ud
);
4218 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread
), FALSE
, get_thread_dump
, &ud
);
4221 mono_array_setref_fast (*out_threads
, tindex
, mono_thread_current_for_thread (thread
));
4223 thread_frames
= mono_array_new_checked (domain
, mono_defaults
.stack_frame_class
, ud
.nframes
, error
);
4224 goto_if_nok (error
, leave
);
4225 mono_array_setref_fast (*out_stack_frames
, tindex
, thread_frames
);
4227 for (i
= 0; i
< ud
.nframes
; ++i
) {
4228 MonoStackFrameInfo
*frame
= &ud
.frames
[i
];
4229 MonoMethod
*method
= NULL
;
4230 MonoStackFrame
*sf
= (MonoStackFrame
*)mono_object_new_checked (domain
, mono_defaults
.stack_frame_class
, error
);
4231 goto_if_nok (error
, leave
);
4233 sf
->native_offset
= frame
->native_offset
;
4235 if (frame
->type
== FRAME_TYPE_MANAGED
)
4236 method
= mono_jit_info_get_method (frame
->ji
);
4239 sf
->method_address
= (gsize
) frame
->ji
->code_start
;
4241 MonoReflectionMethod
*rm
= mono_method_get_object_checked (domain
, method
, NULL
, error
);
4242 goto_if_nok (error
, leave
);
4243 MONO_OBJECT_SETREF_INTERNAL (sf
, method
, rm
);
4245 location
= mono_debug_lookup_source_location (method
, frame
->native_offset
, domain
);
4247 sf
->il_offset
= location
->il_offset
;
4249 if (location
->source_file
) {
4250 MonoString
*filename
= mono_string_new_checked (domain
, location
->source_file
, error
);
4251 goto_if_nok (error
, leave
);
4252 MONO_OBJECT_SETREF_INTERNAL (sf
, filename
, filename
);
4253 sf
->line
= location
->row
;
4254 sf
->column
= location
->column
;
4256 mono_debug_free_source_location (location
);
4261 mono_array_setref_internal (thread_frames
, i
, sf
);
4264 mono_gchandle_free_internal (handle
);
4269 return is_ok (error
);
4273 * mono_threads_request_thread_dump:
4275 * Ask all threads except the current to print their stacktrace to stdout.
4278 mono_threads_request_thread_dump (void)
4280 /*The new thread dump code runs out of the finalizer thread. */
4281 thread_dump_requested
= TRUE
;
4282 mono_gc_finalize_notify ();
4287 gint allocated
; /* +1 so that refs [allocated] == NULL */
4291 typedef struct ref_stack RefStack
;
4294 ref_stack_new (gint initial_size
)
4298 initial_size
= MAX (initial_size
, 16) + 1;
4299 rs
= g_new0 (RefStack
, 1);
4300 rs
->refs
= g_new0 (gpointer
, initial_size
);
4301 rs
->allocated
= initial_size
;
4306 ref_stack_destroy (gpointer ptr
)
4308 RefStack
*rs
= (RefStack
*)ptr
;
4317 ref_stack_push (RefStack
*rs
, gpointer ptr
)
4319 g_assert (rs
!= NULL
);
4321 if (rs
->bottom
>= rs
->allocated
) {
4322 rs
->refs
= (void **)g_realloc (rs
->refs
, rs
->allocated
* 2 * sizeof (gpointer
) + 1);
4323 rs
->allocated
<<= 1;
4324 rs
->refs
[rs
->allocated
] = NULL
;
4326 rs
->refs
[rs
->bottom
++] = ptr
;
4330 ref_stack_pop (RefStack
*rs
)
4332 if (rs
== NULL
|| rs
->bottom
== 0)
4336 rs
->refs
[rs
->bottom
] = NULL
;
4340 ref_stack_find (RefStack
*rs
, gpointer ptr
)
4347 for (refs
= rs
->refs
; refs
&& *refs
; refs
++) {
4355 * mono_thread_push_appdomain_ref:
4357 * Register that the current thread may have references to objects in domain
4358 * @domain on its stack. Each call to this function should be paired with a
4359 * call to pop_appdomain_ref.
4362 mono_thread_push_appdomain_ref (MonoDomain
*domain
)
4364 MonoInternalThread
*thread
= mono_thread_internal_current ();
4367 /* printf ("PUSH REF: %" G_GSIZE_FORMAT " -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
4368 SPIN_LOCK (thread
->lock_thread_id
);
4369 if (thread
->appdomain_refs
== NULL
)
4370 thread
->appdomain_refs
= ref_stack_new (16);
4371 ref_stack_push ((RefStack
*)thread
->appdomain_refs
, domain
);
4372 SPIN_UNLOCK (thread
->lock_thread_id
);
4377 mono_thread_pop_appdomain_ref (void)
4379 MonoInternalThread
*thread
= mono_thread_internal_current ();
4382 /* printf ("POP REF: %" G_GSIZE_FORMAT " -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
4383 SPIN_LOCK (thread
->lock_thread_id
);
4384 ref_stack_pop ((RefStack
*)thread
->appdomain_refs
);
4385 SPIN_UNLOCK (thread
->lock_thread_id
);
4390 mono_thread_internal_has_appdomain_ref (MonoInternalThread
*thread
, MonoDomain
*domain
)
4393 SPIN_LOCK (thread
->lock_thread_id
);
4394 res
= ref_stack_find ((RefStack
*)thread
->appdomain_refs
, domain
);
4395 SPIN_UNLOCK (thread
->lock_thread_id
);
4400 mono_thread_has_appdomain_ref (MonoThread
*thread
, MonoDomain
*domain
)
4402 return mono_thread_internal_has_appdomain_ref (thread
->internal_thread
, domain
);
4405 typedef struct abort_appdomain_data
{
4406 struct wait_data wait
;
4408 } abort_appdomain_data
;
4411 collect_appdomain_thread (gpointer key
, gpointer value
, gpointer user_data
)
4413 MonoInternalThread
*thread
= (MonoInternalThread
*)value
;
4414 abort_appdomain_data
*data
= (abort_appdomain_data
*)user_data
;
4415 MonoDomain
*domain
= data
->domain
;
4417 if (mono_thread_internal_has_appdomain_ref (thread
, domain
)) {
4418 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
4420 if(data
->wait
.num
<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
) {
4421 data
->wait
.handles
[data
->wait
.num
] = mono_threads_open_thread_handle (thread
->handle
);
4422 data
->wait
.threads
[data
->wait
.num
] = thread
;
4425 /* Just ignore the rest, we can't do anything with
4433 * mono_threads_abort_appdomain_threads:
4435 * Abort threads which has references to the given appdomain.
4438 mono_threads_abort_appdomain_threads (MonoDomain
*domain
, int timeout
)
4440 abort_appdomain_data user_data
;
4442 int orig_timeout
= timeout
;
4445 THREAD_DEBUG (g_message ("%s: starting abort", __func__
));
4447 start_time
= mono_msec_ticks ();
4449 mono_threads_lock ();
4451 user_data
.domain
= domain
;
4452 user_data
.wait
.num
= 0;
4453 /* This shouldn't take any locks */
4454 mono_g_hash_table_foreach (threads
, collect_appdomain_thread
, &user_data
);
4455 mono_threads_unlock ();
4457 if (user_data
.wait
.num
> 0) {
4458 /* Abort the threads outside the threads lock */
4459 for (i
= 0; i
< user_data
.wait
.num
; ++i
)
4460 mono_thread_internal_abort (user_data
.wait
.threads
[i
], TRUE
);
4463 * We should wait for the threads either to abort, or to leave the
4464 * domain. We can't do the latter, so we wait with a timeout.
4466 wait_for_tids (&user_data
.wait
, 100, FALSE
);
4469 /* Update remaining time */
4470 timeout
-= mono_msec_ticks () - start_time
;
4471 start_time
= mono_msec_ticks ();
4473 if (orig_timeout
!= -1 && timeout
< 0)
4476 while (user_data
.wait
.num
> 0);
4478 THREAD_DEBUG (g_message ("%s: abort done", __func__
));
4483 /* This is a JIT icall. This icall is called from a finally block when
4484 * mono_install_handler_block_guard called by another thread has flipped the
4485 * finally block's exvar (see mono_find_exvar_for_offset). In that case, if
4486 * the finally is in an abort protected block, we must defer the abort
4487 * exception until we leave the abort protected block. Otherwise we proceed
4488 * with a synchronous self-abort.
4491 ves_icall_thread_finish_async_abort (void)
4493 /* We were called from the handler block and are about to
4494 * leave it. (If we end up postponing the abort because we're
4495 * in an abort protected block, the unwinder won't run and
4496 * won't clear the handler block itself which will confuse the
4497 * unwinder if we're in a try {} catch {} and we throw again.
4499 * static Constructor () {
4503 * icall (); // Thread.Abort landed here,
4504 * // and caused the handler block to be installed
4506 * ves_icall_thread_finish_async_abort (); // we're here
4510 * // unwinder will get confused here and synthesize a self abort
4514 * More interestingly, this doesn't only happen with icalls - a JIT
4515 * trampoline is native code that will cause a handler to be installed.
4516 * So the above situation can happen with any code in a "finally"
4519 mono_get_eh_callbacks ()->mono_uninstall_current_handler_block_guard ();
4520 /* Just set the async interruption requested bit. Rely on the icall
4521 * wrapper of this icall to process the thread interruption, respecting
4522 * any abort protection blocks in our call stack.
4524 mono_thread_set_self_interruption_respect_abort_prot ();
4528 * mono_thread_get_undeniable_exception:
4530 * Return an exception which needs to be raised when leaving a catch clause.
4531 * This is used for undeniable exception propagation.
4534 mono_thread_get_undeniable_exception (void)
4536 MonoInternalThread
*thread
= mono_thread_internal_current ();
4538 if (!(thread
&& thread
->abort_exc
&& !is_running_protected_wrapper ()))
4541 // We don't want to have our exception effect calls made by
4542 // the catching block
4544 if (!mono_get_eh_callbacks ()->mono_above_abort_threshold ())
4548 * FIXME: Clear the abort exception and return an AppDomainUnloaded
4549 * exception if the thread no longer references a dying appdomain.
4551 thread
->abort_exc
->trace_ips
= NULL
;
4552 thread
->abort_exc
->stack_trace
= NULL
;
4553 return thread
->abort_exc
;
4556 #if MONO_SMALL_CONFIG
4557 #define NUM_STATIC_DATA_IDX 4
4558 static const int static_data_size
[NUM_STATIC_DATA_IDX
] = {
4562 #define NUM_STATIC_DATA_IDX 8
4563 static const int static_data_size
[NUM_STATIC_DATA_IDX
] = {
4564 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
4568 static MonoBitSet
*thread_reference_bitmaps
[NUM_STATIC_DATA_IDX
];
4569 static MonoBitSet
*context_reference_bitmaps
[NUM_STATIC_DATA_IDX
];
4572 mark_slots (void *addr
, MonoBitSet
**bitmaps
, MonoGCMarkFunc mark_func
, void *gc_data
)
4574 gpointer
*static_data
= (gpointer
*)addr
;
4576 for (int i
= 0; i
< NUM_STATIC_DATA_IDX
; ++i
) {
4577 void **ptr
= (void **)static_data
[i
];
4582 MONO_BITSET_FOREACH (bitmaps
[i
], idx
, {
4583 void **p
= ptr
+ idx
;
4586 mark_func ((MonoObject
**)p
, gc_data
);
4592 mark_tls_slots (void *addr
, MonoGCMarkFunc mark_func
, void *gc_data
)
4594 mark_slots (addr
, thread_reference_bitmaps
, mark_func
, gc_data
);
4598 mark_ctx_slots (void *addr
, MonoGCMarkFunc mark_func
, void *gc_data
)
4600 mark_slots (addr
, context_reference_bitmaps
, mark_func
, gc_data
);
4604 * mono_alloc_static_data
4606 * Allocate memory blocks for storing threads or context static data
4609 mono_alloc_static_data (gpointer
**static_data_ptr
, guint32 offset
, void *alloc_key
, gboolean threadlocal
)
4611 guint idx
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, index
);
4614 gpointer
* static_data
= *static_data_ptr
;
4616 static MonoGCDescriptor tls_desc
= MONO_GC_DESCRIPTOR_NULL
;
4617 static MonoGCDescriptor ctx_desc
= MONO_GC_DESCRIPTOR_NULL
;
4619 if (mono_gc_user_markers_supported ()) {
4620 if (tls_desc
== MONO_GC_DESCRIPTOR_NULL
)
4621 tls_desc
= mono_gc_make_root_descr_user (mark_tls_slots
);
4623 if (ctx_desc
== MONO_GC_DESCRIPTOR_NULL
)
4624 ctx_desc
= mono_gc_make_root_descr_user (mark_ctx_slots
);
4627 static_data
= (void **)mono_gc_alloc_fixed (static_data_size
[0], threadlocal
? tls_desc
: ctx_desc
,
4628 threadlocal
? MONO_ROOT_SOURCE_THREAD_STATIC
: MONO_ROOT_SOURCE_CONTEXT_STATIC
,
4630 threadlocal
? "ThreadStatic Fields" : "ContextStatic Fields");
4631 *static_data_ptr
= static_data
;
4632 static_data
[0] = static_data
;
4635 for (i
= 1; i
<= idx
; ++i
) {
4636 if (static_data
[i
])
4639 if (mono_gc_user_markers_supported ())
4640 static_data
[i
] = g_malloc0 (static_data_size
[i
]);
4642 static_data
[i
] = mono_gc_alloc_fixed (static_data_size
[i
], MONO_GC_DESCRIPTOR_NULL
,
4643 threadlocal
? MONO_ROOT_SOURCE_THREAD_STATIC
: MONO_ROOT_SOURCE_CONTEXT_STATIC
,
4645 threadlocal
? "ThreadStatic Fields" : "ContextStatic Fields");
4650 mono_free_static_data (gpointer
* static_data
)
4653 for (i
= 1; i
< NUM_STATIC_DATA_IDX
; ++i
) {
4654 gpointer p
= static_data
[i
];
4658 * At this point, the static data pointer array is still registered with the
4659 * GC, so must ensure that mark_tls_slots() will not encounter any invalid
4660 * data. Freeing the individual arrays without first nulling their slots
4661 * would make it possible for mark_tls/ctx_slots() to encounter a pointer to
4662 * such an already freed array. See bug #13813.
4664 static_data
[i
] = NULL
;
4665 mono_memory_write_barrier ();
4666 if (mono_gc_user_markers_supported ())
4669 mono_gc_free_fixed (p
);
4671 mono_gc_free_fixed (static_data
);
4675 * mono_init_static_data_info
4677 * Initializes static data counters
4679 static void mono_init_static_data_info (StaticDataInfo
*static_data
)
4681 static_data
->idx
= 0;
4682 static_data
->offset
= 0;
4683 static_data
->freelist
= NULL
;
4687 * mono_alloc_static_data_slot
4689 * Generates an offset for static data. static_data contains the counters
4690 * used to generate it.
4693 mono_alloc_static_data_slot (StaticDataInfo
*static_data
, guint32 size
, guint32 align
)
4695 if (!static_data
->idx
&& !static_data
->offset
) {
4697 * we use the first chunk of the first allocation also as
4698 * an array for the rest of the data
4700 static_data
->offset
= sizeof (gpointer
) * NUM_STATIC_DATA_IDX
;
4702 static_data
->offset
+= align
- 1;
4703 static_data
->offset
&= ~(align
- 1);
4704 if (static_data
->offset
+ size
>= static_data_size
[static_data
->idx
]) {
4705 static_data
->idx
++;
4706 g_assert (size
<= static_data_size
[static_data
->idx
]);
4707 g_assert (static_data
->idx
< NUM_STATIC_DATA_IDX
);
4708 static_data
->offset
= 0;
4710 guint32 offset
= MAKE_SPECIAL_STATIC_OFFSET (static_data
->idx
, static_data
->offset
, 0);
4711 static_data
->offset
+= size
;
4716 * LOCKING: requires that threads_mutex is held
4719 context_adjust_static_data (MonoAppContextHandle ctx_handle
)
4721 MonoAppContext
*ctx
= MONO_HANDLE_RAW (ctx_handle
);
4722 if (context_static_info
.offset
|| context_static_info
.idx
> 0) {
4723 guint32 offset
= MAKE_SPECIAL_STATIC_OFFSET (context_static_info
.idx
, context_static_info
.offset
, 0);
4724 mono_alloc_static_data (&ctx
->static_data
, offset
, ctx
, FALSE
);
4725 ctx
->data
->static_data
= ctx
->static_data
;
4730 * LOCKING: requires that threads_mutex is held
4733 alloc_thread_static_data_helper (gpointer key
, gpointer value
, gpointer user
)
4735 MonoInternalThread
*thread
= (MonoInternalThread
*)value
;
4736 guint32 offset
= GPOINTER_TO_UINT (user
);
4738 mono_alloc_static_data (&(thread
->static_data
), offset
, (void *) MONO_UINT_TO_NATIVE_THREAD_ID (thread
->tid
), TRUE
);
4742 * LOCKING: requires that threads_mutex is held
4745 alloc_context_static_data_helper (gpointer key
, gpointer value
, gpointer user
)
4747 MonoAppContext
*ctx
= (MonoAppContext
*) mono_gchandle_get_target_internal (GPOINTER_TO_INT (key
));
4752 guint32 offset
= GPOINTER_TO_UINT (user
);
4753 mono_alloc_static_data (&ctx
->static_data
, offset
, ctx
, FALSE
);
4754 ctx
->data
->static_data
= ctx
->static_data
;
4757 static StaticDataFreeList
*
4758 search_slot_in_freelist (StaticDataInfo
*static_data
, guint32 size
, guint32 align
)
4760 StaticDataFreeList
* prev
= NULL
;
4761 StaticDataFreeList
* tmp
= static_data
->freelist
;
4763 if (tmp
->size
== size
) {
4765 prev
->next
= tmp
->next
;
4767 static_data
->freelist
= tmp
->next
;
4776 #if SIZEOF_VOID_P == 4
4783 update_reference_bitmap (MonoBitSet
**sets
, guint32 offset
, uintptr_t *bitmap
, int numbits
)
4785 int idx
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, index
);
4787 sets
[idx
] = mono_bitset_new (static_data_size
[idx
] / sizeof (uintptr_t), 0);
4788 MonoBitSet
*rb
= sets
[idx
];
4789 offset
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, offset
);
4790 offset
/= sizeof (uintptr_t);
4791 /* offset is now the bitmap offset */
4792 for (int i
= 0; i
< numbits
; ++i
) {
4793 if (bitmap
[i
/ sizeof (uintptr_t)] & (ONE_P
<< (i
& (sizeof (uintptr_t) * 8 -1))))
4794 mono_bitset_set_fast (rb
, offset
+ i
);
4799 clear_reference_bitmap (MonoBitSet
**sets
, guint32 offset
, guint32 size
)
4801 int idx
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, index
);
4802 MonoBitSet
*rb
= sets
[idx
];
4803 offset
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, offset
);
4804 offset
/= sizeof (uintptr_t);
4805 /* offset is now the bitmap offset */
4806 for (int i
= 0; i
< size
/ sizeof (uintptr_t); i
++)
4807 mono_bitset_clear_fast (rb
, offset
+ i
);
4811 mono_alloc_special_static_data (guint32 static_type
, guint32 size
, guint32 align
, uintptr_t *bitmap
, int numbits
)
4813 g_assert (static_type
== SPECIAL_STATIC_THREAD
|| static_type
== SPECIAL_STATIC_CONTEXT
);
4815 StaticDataInfo
*info
;
4818 if (static_type
== SPECIAL_STATIC_THREAD
) {
4819 info
= &thread_static_info
;
4820 sets
= thread_reference_bitmaps
;
4822 info
= &context_static_info
;
4823 sets
= context_reference_bitmaps
;
4826 mono_threads_lock ();
4828 StaticDataFreeList
*item
= search_slot_in_freelist (info
, size
, align
);
4832 offset
= item
->offset
;
4835 offset
= mono_alloc_static_data_slot (info
, size
, align
);
4838 update_reference_bitmap (sets
, offset
, bitmap
, numbits
);
4840 if (static_type
== SPECIAL_STATIC_THREAD
) {
4841 /* This can be called during startup */
4842 if (threads
!= NULL
)
4843 mono_g_hash_table_foreach (threads
, alloc_thread_static_data_helper
, GUINT_TO_POINTER (offset
));
4845 if (contexts
!= NULL
)
4846 g_hash_table_foreach (contexts
, alloc_context_static_data_helper
, GUINT_TO_POINTER (offset
));
4848 ACCESS_SPECIAL_STATIC_OFFSET (offset
, type
) = SPECIAL_STATIC_OFFSET_TYPE_CONTEXT
;
4851 mono_threads_unlock ();
4857 mono_get_special_static_data_for_thread (MonoInternalThread
*thread
, guint32 offset
)
4859 guint32 static_type
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, type
);
4861 if (static_type
== SPECIAL_STATIC_OFFSET_TYPE_THREAD
) {
4862 return get_thread_static_data (thread
, offset
);
4864 return get_context_static_data (thread
->current_appcontext
, offset
);
4869 mono_get_special_static_data (guint32 offset
)
4871 return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset
);
4880 * LOCKING: requires that threads_mutex is held
4883 free_thread_static_data_helper (gpointer key
, gpointer value
, gpointer user
)
4885 MonoInternalThread
*thread
= (MonoInternalThread
*)value
;
4886 OffsetSize
*data
= (OffsetSize
*)user
;
4887 int idx
= ACCESS_SPECIAL_STATIC_OFFSET (data
->offset
, index
);
4888 int off
= ACCESS_SPECIAL_STATIC_OFFSET (data
->offset
, offset
);
4891 if (!thread
->static_data
|| !thread
->static_data
[idx
])
4893 ptr
= ((char*) thread
->static_data
[idx
]) + off
;
4894 mono_gc_bzero_atomic (ptr
, data
->size
);
4898 * LOCKING: requires that threads_mutex is held
4901 free_context_static_data_helper (gpointer key
, gpointer value
, gpointer user
)
4903 MonoAppContext
*ctx
= (MonoAppContext
*) mono_gchandle_get_target_internal (GPOINTER_TO_INT (key
));
4908 OffsetSize
*data
= (OffsetSize
*)user
;
4909 int idx
= ACCESS_SPECIAL_STATIC_OFFSET (data
->offset
, index
);
4910 int off
= ACCESS_SPECIAL_STATIC_OFFSET (data
->offset
, offset
);
4913 if (!ctx
->static_data
|| !ctx
->static_data
[idx
])
4916 ptr
= ((char*) ctx
->static_data
[idx
]) + off
;
4917 mono_gc_bzero_atomic (ptr
, data
->size
);
4921 do_free_special_slot (guint32 offset
, guint32 size
)
4923 guint32 static_type
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, type
);
4925 StaticDataInfo
*info
;
4927 if (static_type
== SPECIAL_STATIC_OFFSET_TYPE_THREAD
) {
4928 info
= &thread_static_info
;
4929 sets
= thread_reference_bitmaps
;
4931 info
= &context_static_info
;
4932 sets
= context_reference_bitmaps
;
4935 guint32 data_offset
= offset
;
4936 ACCESS_SPECIAL_STATIC_OFFSET (data_offset
, type
) = 0;
4937 OffsetSize data
= { data_offset
, size
};
4939 clear_reference_bitmap (sets
, data
.offset
, data
.size
);
4941 if (static_type
== SPECIAL_STATIC_OFFSET_TYPE_THREAD
) {
4942 if (threads
!= NULL
)
4943 mono_g_hash_table_foreach (threads
, free_thread_static_data_helper
, &data
);
4945 if (contexts
!= NULL
)
4946 g_hash_table_foreach (contexts
, free_context_static_data_helper
, &data
);
4949 if (!mono_runtime_is_shutting_down ()) {
4950 StaticDataFreeList
*item
= g_new0 (StaticDataFreeList
, 1);
4952 item
->offset
= offset
;
4955 item
->next
= info
->freelist
;
4956 info
->freelist
= item
;
4961 do_free_special (gpointer key
, gpointer value
, gpointer data
)
4963 MonoClassField
*field
= (MonoClassField
*)key
;
4964 guint32 offset
= GPOINTER_TO_UINT (value
);
4967 size
= mono_type_size (field
->type
, &align
);
4968 do_free_special_slot (offset
, size
);
4972 mono_alloc_special_static_data_free (GHashTable
*special_static_fields
)
4974 mono_threads_lock ();
4976 g_hash_table_foreach (special_static_fields
, do_free_special
, NULL
);
4978 mono_threads_unlock ();
4983 flush_thread_interrupt_queue (void)
4985 /* Consume pending APC calls for current thread.*/
4986 /* Since this function get's called from interrupt handler it must use a direct */
4987 /* Win32 API call and can't go through mono_coop_win32_wait_for_single_object_ex */
4988 /* or it will detect a pending interrupt and not entering the wait call needed */
4989 /* to consume pending APC's.*/
4991 WaitForSingleObjectEx (GetCurrentThread (), 0, TRUE
);
4996 flush_thread_interrupt_queue (void)
5002 * mono_thread_execute_interruption
5004 * Performs the operation that the requested thread state requires (abort,
5008 mono_thread_execute_interruption (MonoExceptionHandle
*pexc
)
5010 gboolean fexc
= FALSE
;
5012 // Optimize away frame if caller supplied one.
5014 HANDLE_FUNCTION_ENTER ();
5015 MonoExceptionHandle exc
= MONO_HANDLE_NEW (MonoException
, NULL
);
5016 fexc
= mono_thread_execute_interruption (&exc
);
5017 HANDLE_FUNCTION_RETURN_VAL (fexc
);
5020 MONO_REQ_GC_UNSAFE_MODE
;
5022 MonoInternalThreadHandle thread
= mono_thread_internal_current_handle ();
5023 MonoExceptionHandle exc
= MONO_HANDLE_NEW (MonoException
, NULL
);
5025 lock_thread_handle (thread
);
5026 gboolean unlock
= TRUE
;
5028 /* MonoThread::interruption_requested can only be changed with atomics */
5029 if (!mono_thread_clear_interruption_requested_handle (thread
))
5032 MonoThreadObjectHandle sys_thread
;
5033 sys_thread
= mono_thread_current_handle ();
5035 flush_thread_interrupt_queue ();
5037 /* Clear the interrupted flag of the thread so it can wait again */
5038 mono_thread_info_clear_self_interrupt ();
5040 /* If there's a pending exception and an AbortRequested, the pending exception takes precedence */
5041 MONO_HANDLE_GET (exc
, sys_thread
, pending_exception
);
5042 if (!MONO_HANDLE_IS_NULL (exc
)) {
5043 // sys_thread->pending_exception = NULL;
5044 MONO_HANDLE_SETRAW (sys_thread
, pending_exception
, NULL
);
5047 } else if (MONO_HANDLE_GETVAL (thread
, state
) & ThreadState_AbortRequested
) {
5048 // Does the thread already have an abort exception?
5049 // If not, create a new one and set it on demand.
5050 // exc = thread->abort_exc;
5051 MONO_HANDLE_GET (exc
, thread
, abort_exc
);
5052 if (MONO_HANDLE_IS_NULL (exc
)) {
5054 exc
= mono_exception_new_thread_abort (error
);
5055 mono_error_assert_ok (error
); // FIXME
5056 // thread->abort_exc = exc;
5057 MONO_HANDLE_SET (thread
, abort_exc
, exc
);
5060 } else if (MONO_HANDLE_GETVAL (thread
, state
) & ThreadState_SuspendRequested
) {
5061 /* calls UNLOCK_THREAD (thread) */
5062 self_suspend_internal ();
5064 } else if (MONO_HANDLE_GETVAL (thread
, thread_interrupt_requested
)) {
5065 // thread->thread_interrupt_requested = FALSE
5066 MONO_HANDLE_SETVAL (thread
, thread_interrupt_requested
, MonoBoolean
, FALSE
);
5067 unlock_thread_handle (thread
);
5070 exc
= mono_exception_new_thread_interrupted (error
);
5071 mono_error_assert_ok (error
); // FIXME
5076 unlock_thread_handle (thread
);
5079 MONO_HANDLE_ASSIGN (*pexc
, exc
);
5085 mono_thread_execute_interruption_void (void)
5087 (void)mono_thread_execute_interruption (NULL
);
5090 static MonoException
*
5091 mono_thread_execute_interruption_ptr (void)
5093 HANDLE_FUNCTION_ENTER ();
5094 MonoExceptionHandle exc
= MONO_HANDLE_NEW (MonoException
, NULL
);
5095 MonoException
* const exc_raw
= mono_thread_execute_interruption (&exc
) ? MONO_HANDLE_RAW (exc
) : NULL
;
5096 HANDLE_FUNCTION_RETURN_VAL (exc_raw
);
5100 * mono_thread_request_interruption_internal
5102 * A signal handler can call this method to request the interruption of a
5103 * thread. The result of the interruption will depend on the current state of
5104 * the thread. If the result is an exception that needs to be thrown, it is
5105 * provided as return value.
5108 mono_thread_request_interruption_internal (gboolean running_managed
, MonoExceptionHandle
*pexc
)
5110 MonoInternalThread
*thread
= mono_thread_internal_current ();
5112 /* The thread may already be stopping */
5116 if (!mono_thread_set_interruption_requested (thread
))
5119 if (!running_managed
|| is_running_protected_wrapper ()) {
5120 /* Can't stop while in unmanaged code. Increase the global interruption
5121 request count. When exiting the unmanaged method the count will be
5122 checked and the thread will be interrupted. */
5124 /* this will awake the thread if it is in WaitForSingleObject
5127 mono_win32_interrupt_wait (thread
->thread_info
, thread
->native_handle
, (DWORD
)thread
->tid
);
5129 mono_thread_info_self_interrupt ();
5133 return mono_thread_execute_interruption (pexc
);
5137 mono_thread_request_interruption_native (void)
5139 (void)mono_thread_request_interruption_internal (FALSE
, NULL
);
5143 mono_thread_request_interruption_managed (MonoExceptionHandle
*exc
)
5145 return mono_thread_request_interruption_internal (TRUE
, exc
);
5148 /*This function should be called by a thread after it has exited all of
5149 * its handle blocks at interruption time.*/
5151 mono_thread_resume_interruption (gboolean exec
)
5153 MonoInternalThread
*thread
= mono_thread_internal_current ();
5154 gboolean still_aborting
;
5156 /* The thread may already be stopping */
5160 LOCK_THREAD (thread
);
5161 still_aborting
= (thread
->state
& (ThreadState_AbortRequested
)) != 0;
5162 UNLOCK_THREAD (thread
);
5164 /*This can happen if the protected block called Thread::ResetAbort*/
5165 if (!still_aborting
)
5168 if (!mono_thread_set_interruption_requested (thread
))
5171 mono_thread_info_self_interrupt ();
5173 if (exec
) // Ignore the exception here, it will be raised later.
5174 mono_thread_execute_interruption_void ();
5178 mono_thread_interruption_requested (void)
5180 if (thread_interruption_requested
) {
5181 MonoInternalThread
*thread
= mono_thread_internal_current ();
5182 /* The thread may already be stopping */
5184 return mono_thread_get_interruption_requested (thread
);
5189 static MonoException
*
5190 mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection
)
5192 MonoInternalThread
*thread
= mono_thread_internal_current ();
5194 /* The thread may already be stopping */
5197 if (!mono_thread_get_interruption_requested (thread
))
5199 if (!bypass_abort_protection
&& !mono_thread_current ()->pending_exception
&& is_running_protected_wrapper ())
5202 return mono_thread_execute_interruption_ptr ();
5206 * Performs the interruption of the current thread, if one has been requested,
5207 * and the thread is not running a protected wrapper.
5208 * Return the exception which needs to be thrown, if any.
5211 mono_thread_interruption_checkpoint (void)
5213 return mono_thread_interruption_checkpoint_request (FALSE
);
5217 mono_thread_interruption_checkpoint_bool (void)
5219 return mono_thread_interruption_checkpoint () != NULL
;
5223 mono_thread_interruption_checkpoint_void (void)
5225 mono_thread_interruption_checkpoint ();
5229 * Performs the interruption of the current thread, if one has been requested.
5230 * Return the exception which needs to be thrown, if any.
5233 mono_thread_force_interruption_checkpoint_noraise (void)
5235 return mono_thread_interruption_checkpoint_request (TRUE
);
5239 * mono_set_pending_exception:
5241 * Set the pending exception of the current thread to EXC.
5242 * The exception will be thrown when execution returns to managed code.
5245 mono_set_pending_exception (MonoException
*exc
)
5247 MonoThread
*thread
= mono_thread_current ();
5249 /* The thread may already be stopping */
5253 MONO_OBJECT_SETREF_INTERNAL (thread
, pending_exception
, exc
);
5255 mono_thread_request_interruption_native ();
5259 * mono_runtime_set_pending_exception:
5261 * Set the pending exception of the current thread to \p exc.
5262 * The exception will be thrown when execution returns to managed code.
5263 * Can optionally \p overwrite any existing pending exceptions (it's not supported
5264 * to overwrite any pending exceptions if the runtime is processing a thread abort request,
5265 * in which case the behavior will be undefined).
5266 * Return whether the pending exception was set or not.
5267 * It will not be set if:
5268 * * The thread or runtime is stopping or shutting down
5269 * * There already is a pending exception (and \p overwrite is false)
5272 mono_runtime_set_pending_exception (MonoException
*exc
, mono_bool overwrite
)
5274 MonoThread
*thread
= mono_thread_current ();
5276 /* The thread may already be stopping */
5280 /* Don't overwrite any existing pending exceptions unless asked to */
5281 if (!overwrite
&& thread
->pending_exception
)
5284 MONO_OBJECT_SETREF_INTERNAL (thread
, pending_exception
, exc
);
5286 mono_thread_request_interruption_native ();
5293 * mono_set_pending_exception_handle:
5295 * Set the pending exception of the current thread to EXC.
5296 * The exception will be thrown when execution returns to managed code.
5299 mono_set_pending_exception_handle (MonoExceptionHandle exc
)
5301 MonoThread
*thread
= mono_thread_current ();
5303 /* The thread may already be stopping */
5307 MONO_OBJECT_SETREF_INTERNAL (thread
, pending_exception
, MONO_HANDLE_RAW (exc
));
5309 mono_thread_request_interruption_native ();
5313 * mono_thread_interruption_request_flag:
5315 * Returns the address of a flag that will be non-zero if an interruption has
5316 * been requested for a thread. The thread to interrupt may not be the current
5317 * thread, so an additional call to mono_thread_interruption_requested() or
5318 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
5322 mono_thread_interruption_request_flag (void)
5324 return &thread_interruption_requested
;
5328 mono_thread_init_apartment_state (void)
5331 MonoInternalThread
* thread
= mono_thread_internal_current ();
5333 /* Positive return value indicates success, either
5334 * S_OK if this is first CoInitialize call, or
5335 * S_FALSE if CoInitialize already called, but with same
5336 * threading model. A negative value indicates failure,
5337 * probably due to trying to change the threading model.
5339 if (CoInitializeEx(NULL
, (thread
->apartment_state
== ThreadApartmentState_STA
)
5340 ? COINIT_APARTMENTTHREADED
5341 : COINIT_MULTITHREADED
) < 0) {
5342 thread
->apartment_state
= ThreadApartmentState_Unknown
;
5348 mono_thread_cleanup_apartment_state (void)
5351 MonoInternalThread
* thread
= mono_thread_internal_current ();
5353 if (thread
&& thread
->apartment_state
!= ThreadApartmentState_Unknown
) {
5360 mono_thread_notify_change_state (MonoThreadState old_state
, MonoThreadState new_state
)
5362 MonoThreadState diff
= old_state
^ new_state
;
5363 if (diff
& ThreadState_Background
) {
5364 /* If the thread changes the background mode, the main thread has to
5365 * be notified, since it has to rebuild the list of threads to
5369 mono_os_event_set (&background_change_event
);
5375 mono_thread_clear_and_set_state (MonoInternalThread
*thread
, MonoThreadState clear
, MonoThreadState set
)
5377 LOCK_THREAD (thread
);
5379 MonoThreadState
const old_state
= (MonoThreadState
)thread
->state
;
5380 MonoThreadState
const new_state
= (old_state
& ~clear
) | set
;
5381 thread
->state
= new_state
;
5383 UNLOCK_THREAD (thread
);
5385 mono_thread_notify_change_state (old_state
, new_state
);
5389 mono_thread_set_state (MonoInternalThread
*thread
, MonoThreadState state
)
5391 mono_thread_clear_and_set_state (thread
, (MonoThreadState
)0, state
);
5395 * mono_thread_test_and_set_state:
5396 * Test if current state of \p thread include \p test. If it does not, OR \p set into the state.
5397 * \returns TRUE if \p set was OR'd in.
5400 mono_thread_test_and_set_state (MonoInternalThread
*thread
, MonoThreadState test
, MonoThreadState set
)
5402 LOCK_THREAD (thread
);
5404 MonoThreadState
const old_state
= (MonoThreadState
)thread
->state
;
5406 if ((old_state
& test
) != 0) {
5407 UNLOCK_THREAD (thread
);
5411 MonoThreadState
const new_state
= old_state
| set
;
5412 thread
->state
= new_state
;
5414 UNLOCK_THREAD (thread
);
5416 mono_thread_notify_change_state (old_state
, new_state
);
5422 mono_thread_clr_state (MonoInternalThread
*thread
, MonoThreadState state
)
5424 mono_thread_clear_and_set_state (thread
, state
, (MonoThreadState
)0);
5428 mono_thread_test_state (MonoInternalThread
*thread
, MonoThreadState test
)
5430 LOCK_THREAD (thread
);
5432 gboolean
const ret
= ((thread
->state
& test
) != 0);
5434 UNLOCK_THREAD (thread
);
5440 self_interrupt_thread (void *_unused
)
5443 MonoThreadInfo
*info
;
5446 exc
= mono_thread_execute_interruption_ptr ();
5448 if (mono_threads_are_safepoints_enabled ()) {
5449 /* We can return from an async call in coop, as
5450 * it's simply called when exiting the safepoint */
5451 /* If we're using hybrid suspend, we only self
5452 * interrupt if we were running, hence using
5457 g_error ("%s: we can't resume from an async call", __func__
);
5460 info
= mono_thread_info_current ();
5462 /* FIXME using thread_saved_state [ASYNC_SUSPEND_STATE_INDEX] can race with another suspend coming in. */
5463 ctx
= info
->thread_saved_state
[ASYNC_SUSPEND_STATE_INDEX
].ctx
;
5465 mono_raise_exception_with_context (exc
, &ctx
);
5469 mono_jit_info_match (MonoJitInfo
*ji
, gpointer ip
)
5473 return ji
->code_start
<= ip
&& (char*)ip
< (char*)ji
->code_start
+ ji
->code_size
;
5477 last_managed (MonoStackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
5479 MonoJitInfo
**dest
= (MonoJitInfo
**)data
;
5485 mono_thread_info_get_last_managed (MonoThreadInfo
*info
)
5487 MonoJitInfo
*ji
= NULL
;
5492 * The suspended thread might be holding runtime locks. Make sure we don't try taking
5493 * any runtime locks while unwinding.
5495 mono_thread_info_set_is_async_context (TRUE
);
5496 mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed
, mono_thread_info_get_suspend_state (info
), MONO_UNWIND_SIGNAL_SAFE
, &ji
);
5497 mono_thread_info_set_is_async_context (FALSE
);
5502 MonoInternalThread
*thread
;
5503 gboolean install_async_abort
;
5504 MonoThreadInfoInterruptToken
*interrupt_token
;
5507 static SuspendThreadResult
5508 async_abort_critical (MonoThreadInfo
*info
, gpointer ud
)
5510 AbortThreadData
*data
= (AbortThreadData
*)ud
;
5511 MonoInternalThread
*thread
= data
->thread
;
5512 MonoJitInfo
*ji
= NULL
;
5513 gboolean protected_wrapper
;
5514 gboolean running_managed
;
5516 if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info
)))
5517 return MonoResumeThread
;
5519 /*someone is already interrupting it*/
5520 if (!mono_thread_set_interruption_requested (thread
))
5521 return MonoResumeThread
;
5523 ji
= mono_thread_info_get_last_managed (info
);
5524 protected_wrapper
= ji
&& !ji
->is_trampoline
&& !ji
->async
&& mono_threads_is_critical_method (mono_jit_info_get_method (ji
));
5525 running_managed
= mono_jit_info_match (ji
, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info
)->ctx
));
5527 if (!protected_wrapper
&& running_managed
) {
5528 /*We are in managed code*/
5529 /*Set the thread to call */
5530 if (data
->install_async_abort
)
5531 mono_thread_info_setup_async_call (info
, self_interrupt_thread
, NULL
);
5532 return MonoResumeThread
;
5535 * This will cause waits to be broken.
5536 * It will also prevent the thread from entering a wait, so if the thread returns
5537 * from the wait before it receives the abort signal, it will just spin in the wait
5538 * functions in the io-layer until the signal handler calls QueueUserAPC which will
5541 data
->interrupt_token
= mono_thread_info_prepare_interrupt (info
);
5543 return MonoResumeThread
;
5548 async_abort_internal (MonoInternalThread
*thread
, gboolean install_async_abort
)
5550 AbortThreadData data
;
5552 g_assert (thread
!= mono_thread_internal_current ());
5554 data
.thread
= thread
;
5555 data
.install_async_abort
= install_async_abort
;
5556 data
.interrupt_token
= NULL
;
5558 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread
), TRUE
, async_abort_critical
, &data
);
5559 if (data
.interrupt_token
)
5560 mono_thread_info_finish_interrupt (data
.interrupt_token
);
5561 /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
5565 self_abort_internal (MonoError
*error
)
5567 HANDLE_FUNCTION_ENTER ();
5571 /* FIXME this is insanely broken, it doesn't cause interruption to happen synchronously
5572 * since passing FALSE to mono_thread_request_interruption makes sure it returns NULL */
5575 Self aborts ignore the protected block logic and raise the TAE regardless. This is verified by one of the tests in mono/tests/abort-cctor.cs.
5577 MonoExceptionHandle exc
= MONO_HANDLE_NEW (MonoException
, NULL
);
5578 if (mono_thread_request_interruption_managed (&exc
))
5579 mono_error_set_exception_handle (error
, exc
);
5581 mono_thread_info_self_interrupt ();
5583 HANDLE_FUNCTION_RETURN ();
5587 MonoInternalThread
*thread
;
5589 MonoThreadInfoInterruptToken
*interrupt_token
;
5590 } SuspendThreadData
;
5592 static SuspendThreadResult
5593 async_suspend_critical (MonoThreadInfo
*info
, gpointer ud
)
5595 SuspendThreadData
*data
= (SuspendThreadData
*)ud
;
5596 MonoInternalThread
*thread
= data
->thread
;
5597 MonoJitInfo
*ji
= NULL
;
5598 gboolean protected_wrapper
;
5599 gboolean running_managed
;
5601 ji
= mono_thread_info_get_last_managed (info
);
5602 protected_wrapper
= ji
&& !ji
->is_trampoline
&& !ji
->async
&& mono_threads_is_critical_method (mono_jit_info_get_method (ji
));
5603 running_managed
= mono_jit_info_match (ji
, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info
)->ctx
));
5605 if (running_managed
&& !protected_wrapper
) {
5606 if (mono_threads_are_safepoints_enabled ()) {
5607 mono_thread_info_setup_async_call (info
, self_interrupt_thread
, NULL
);
5608 return MonoResumeThread
;
5610 thread
->state
&= ~ThreadState_SuspendRequested
;
5611 thread
->state
|= ThreadState_Suspended
;
5612 return KeepSuspended
;
5615 mono_thread_set_interruption_requested (thread
);
5616 if (data
->interrupt
)
5617 data
->interrupt_token
= mono_thread_info_prepare_interrupt ((MonoThreadInfo
*)thread
->thread_info
);
5619 return MonoResumeThread
;
5623 /* LOCKING: called with @thread longlived->synch_cs held, and releases it */
5625 async_suspend_internal (MonoInternalThread
*thread
, gboolean interrupt
)
5627 SuspendThreadData data
;
5629 g_assert (thread
!= mono_thread_internal_current ());
5631 // g_async_safe_printf ("ASYNC SUSPEND thread %p\n", thread_get_tid (thread));
5633 thread
->self_suspended
= FALSE
;
5635 data
.thread
= thread
;
5636 data
.interrupt
= interrupt
;
5637 data
.interrupt_token
= NULL
;
5639 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread
), interrupt
, async_suspend_critical
, &data
);
5640 if (data
.interrupt_token
)
5641 mono_thread_info_finish_interrupt (data
.interrupt_token
);
5643 UNLOCK_THREAD (thread
);
5646 /* LOCKING: called with @thread longlived->synch_cs held, and releases it */
5648 self_suspend_internal (void)
5650 MonoInternalThread
*thread
;
5652 MonoOSEventWaitRet res
;
5654 thread
= mono_thread_internal_current ();
5656 // g_async_safe_printf ("SELF SUSPEND thread %p\n", thread_get_tid (thread));
5658 thread
->self_suspended
= TRUE
;
5660 thread
->state
&= ~ThreadState_SuspendRequested
;
5661 thread
->state
|= ThreadState_Suspended
;
5663 UNLOCK_THREAD (thread
);
5665 event
= thread
->suspended
;
5668 res
= mono_os_event_wait_one (event
, MONO_INFINITE_WAIT
, TRUE
);
5669 g_assert (res
== MONO_OS_EVENT_WAIT_RET_SUCCESS_0
|| res
== MONO_OS_EVENT_WAIT_RET_ALERTED
);
5674 suspend_for_shutdown_async_call (gpointer unused
)
5677 mono_thread_info_yield ();
5680 static SuspendThreadResult
5681 suspend_for_shutdown_critical (MonoThreadInfo
*info
, gpointer unused
)
5683 mono_thread_info_setup_async_call (info
, suspend_for_shutdown_async_call
, NULL
);
5684 return MonoResumeThread
;
5688 mono_thread_internal_suspend_for_shutdown (MonoInternalThread
*thread
)
5690 g_assert (thread
!= mono_thread_internal_current ());
5692 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread
), FALSE
, suspend_for_shutdown_critical
, NULL
);
5696 * mono_thread_is_foreign:
5697 * \param thread the thread to query
5699 * This function allows one to determine if a thread was created by the mono runtime and has
5700 * a well defined lifecycle or it's a foreign one, created by the native environment.
5702 * \returns TRUE if \p thread was not created by the runtime.
5705 mono_thread_is_foreign (MonoThread
*thread
)
5708 MONO_ENTER_GC_UNSAFE
;
5709 MonoThreadInfo
*info
= (MonoThreadInfo
*)thread
->internal_thread
->thread_info
;
5710 result
= (info
->runtime_thread
== FALSE
);
5711 MONO_EXIT_GC_UNSAFE
;
5717 threads_native_thread_join_lock (gpointer tid
, gpointer value
)
5719 pthread_t thread
= (pthread_t
)tid
;
5720 if (thread
!= pthread_self ()) {
5722 /* This shouldn't block */
5723 mono_threads_join_lock ();
5724 mono_native_thread_join (thread
);
5725 mono_threads_join_unlock ();
5730 threads_native_thread_join_nolock (gpointer tid
, gpointer value
)
5732 pthread_t thread
= (pthread_t
)tid
;
5734 mono_native_thread_join (thread
);
5739 threads_add_joinable_thread_nolock (gpointer tid
)
5741 g_hash_table_insert (joinable_threads
, tid
, tid
);
5745 threads_native_thread_join_lock (gpointer tid
, gpointer value
)
5747 MonoNativeThreadId thread_id
= (MonoNativeThreadId
)(guint64
)tid
;
5748 HANDLE thread_handle
= (HANDLE
)value
;
5749 if (thread_id
!= GetCurrentThreadId () && thread_handle
!= NULL
&& thread_handle
!= INVALID_HANDLE_VALUE
) {
5751 /* This shouldn't block */
5752 mono_threads_join_lock ();
5753 mono_native_thread_join_handle (thread_handle
, TRUE
);
5754 mono_threads_join_unlock ();
5760 threads_native_thread_join_nolock (gpointer tid
, gpointer value
)
5762 HANDLE thread_handle
= (HANDLE
)value
;
5764 mono_native_thread_join_handle (thread_handle
, TRUE
);
5769 threads_add_joinable_thread_nolock (gpointer tid
)
5771 g_hash_table_insert (joinable_threads
, tid
, (gpointer
)OpenThread (SYNCHRONIZE
, TRUE
, (MonoNativeThreadId
)(guint64
)tid
));
5776 threads_add_pending_joinable_thread (gpointer tid
)
5778 joinable_threads_lock ();
5780 if (!pending_joinable_threads
)
5781 pending_joinable_threads
= g_hash_table_new (NULL
, NULL
);
5786 if (!g_hash_table_lookup_extended (pending_joinable_threads
, tid
, &orig_key
, &value
)) {
5787 g_hash_table_insert (pending_joinable_threads
, tid
, tid
);
5788 UnlockedIncrement (&pending_joinable_thread_count
);
5791 joinable_threads_unlock ();
5795 threads_add_pending_joinable_runtime_thread (MonoThreadInfo
*mono_thread_info
)
5797 g_assert (mono_thread_info
);
5799 if (mono_thread_info
->runtime_thread
) {
5800 threads_add_pending_joinable_thread ((gpointer
)(MONO_UINT_TO_NATIVE_THREAD_ID (mono_thread_info_get_tid (mono_thread_info
))));
5805 threads_remove_pending_joinable_thread_nolock (gpointer tid
)
5810 if (pending_joinable_threads
&& g_hash_table_lookup_extended (pending_joinable_threads
, tid
, &orig_key
, &value
)) {
5811 g_hash_table_remove (pending_joinable_threads
, tid
);
5812 if (UnlockedDecrement (&pending_joinable_thread_count
) == 0)
5813 mono_coop_cond_broadcast (&zero_pending_joinable_thread_event
);
5818 threads_wait_pending_joinable_threads (uint32_t timeout
)
5820 if (UnlockedRead (&pending_joinable_thread_count
) > 0) {
5821 joinable_threads_lock ();
5822 if (timeout
== MONO_INFINITE_WAIT
) {
5823 while (UnlockedRead (&pending_joinable_thread_count
) > 0)
5824 mono_coop_cond_wait (&zero_pending_joinable_thread_event
, &joinable_threads_mutex
);
5826 gint64 start
= mono_msec_ticks ();
5828 while (UnlockedRead (&pending_joinable_thread_count
) > 0 && elapsed
< timeout
) {
5829 mono_coop_cond_timedwait (&zero_pending_joinable_thread_event
, &joinable_threads_mutex
, timeout
- (uint32_t)elapsed
);
5830 elapsed
= mono_msec_ticks () - start
;
5833 joinable_threads_unlock ();
5836 return UnlockedRead (&pending_joinable_thread_count
) == 0;
5840 threads_add_unique_joinable_thread_nolock (gpointer tid
)
5842 if (!joinable_threads
)
5843 joinable_threads
= g_hash_table_new (NULL
, NULL
);
5848 if (!g_hash_table_lookup_extended (joinable_threads
, tid
, &orig_key
, &value
)) {
5849 threads_add_joinable_thread_nolock (tid
);
5850 UnlockedIncrement (&joinable_thread_count
);
5855 mono_threads_add_joinable_runtime_thread (MonoThreadInfo
*thread_info
)
5857 g_assert (thread_info
);
5858 MonoThreadInfo
*mono_thread_info
= thread_info
;
5860 if (mono_thread_info
->runtime_thread
) {
5861 gpointer tid
= (gpointer
)(MONO_UINT_TO_NATIVE_THREAD_ID (mono_thread_info_get_tid (mono_thread_info
)));
5863 joinable_threads_lock ();
5865 // Add to joinable thread list, if not already included.
5866 threads_add_unique_joinable_thread_nolock (tid
);
5868 // Remove thread from pending joinable list, if present.
5869 threads_remove_pending_joinable_thread_nolock (tid
);
5871 joinable_threads_unlock ();
5873 mono_gc_finalize_notify ();
5878 threads_add_pending_native_thread_join_call_nolock (gpointer tid
)
5880 if (!pending_native_thread_join_calls
)
5881 pending_native_thread_join_calls
= g_hash_table_new (NULL
, NULL
);
5886 if (!g_hash_table_lookup_extended (pending_native_thread_join_calls
, tid
, &orig_key
, &value
))
5887 g_hash_table_insert (pending_native_thread_join_calls
, tid
, tid
);
5891 threads_remove_pending_native_thread_join_call_nolock (gpointer tid
)
5893 if (pending_native_thread_join_calls
)
5894 g_hash_table_remove (pending_native_thread_join_calls
, tid
);
5896 mono_coop_cond_broadcast (&pending_native_thread_join_calls_event
);
5900 threads_wait_pending_native_thread_join_call_nolock (gpointer tid
)
5905 while (g_hash_table_lookup_extended (pending_native_thread_join_calls
, tid
, &orig_key
, &value
)) {
5906 mono_coop_cond_wait (&pending_native_thread_join_calls_event
, &joinable_threads_mutex
);
5911 * mono_add_joinable_thread:
5913 * Add TID to the list of joinable threads.
5914 * LOCKING: Acquires the threads lock.
5917 mono_threads_add_joinable_thread (gpointer tid
)
5920 * We cannot detach from threads because it causes problems like
5921 * 2fd16f60/r114307. So we collect them and join them when
5922 * we have time (in the finalizer thread).
5924 joinable_threads_lock ();
5925 threads_add_unique_joinable_thread_nolock (tid
);
5926 joinable_threads_unlock ();
5928 mono_gc_finalize_notify ();
5932 * mono_threads_join_threads:
5934 * Join all joinable threads. This is called from the finalizer thread.
5935 * LOCKING: Acquires the threads lock.
5938 mono_threads_join_threads (void)
5940 GHashTableIter iter
;
5941 gpointer key
= NULL
;
5942 gpointer value
= NULL
;
5943 gboolean found
= FALSE
;
5946 if (!UnlockedRead (&joinable_thread_count
))
5950 joinable_threads_lock ();
5952 // Previous native thread join call completed.
5953 threads_remove_pending_native_thread_join_call_nolock (key
);
5956 if (g_hash_table_size (joinable_threads
)) {
5957 g_hash_table_iter_init (&iter
, joinable_threads
);
5958 g_hash_table_iter_next (&iter
, &key
, (void**)&value
);
5959 g_hash_table_remove (joinable_threads
, key
);
5960 UnlockedDecrement (&joinable_thread_count
);
5963 // Add to table of tid's with pending native thread join call.
5964 threads_add_pending_native_thread_join_call_nolock (key
);
5966 joinable_threads_unlock ();
5968 threads_native_thread_join_lock (key
, value
);
5977 * Wait for thread TID to exit.
5978 * LOCKING: Acquires the threads lock.
5981 mono_thread_join (gpointer tid
)
5983 gboolean found
= FALSE
;
5987 joinable_threads_lock ();
5988 if (!joinable_threads
)
5989 joinable_threads
= g_hash_table_new (NULL
, NULL
);
5991 if (g_hash_table_lookup_extended (joinable_threads
, tid
, &orig_key
, &value
)) {
5992 g_hash_table_remove (joinable_threads
, tid
);
5993 UnlockedDecrement (&joinable_thread_count
);
5996 // Add to table of tid's with pending native join call.
5997 threads_add_pending_native_thread_join_call_nolock (tid
);
6001 // Wait for any pending native thread join call not yet completed for this tid.
6002 threads_wait_pending_native_thread_join_call_nolock (tid
);
6005 joinable_threads_unlock ();
6010 threads_native_thread_join_nolock (tid
, value
);
6012 joinable_threads_lock ();
6013 // Native thread join call completed for this tid.
6014 threads_remove_pending_native_thread_join_call_nolock (tid
);
6015 joinable_threads_unlock ();
6019 mono_thread_internal_unhandled_exception (MonoObject
* exc
)
6021 MonoClass
*klass
= exc
->vtable
->klass
;
6022 if (is_threadabort_exception (klass
)) {
6023 mono_thread_internal_reset_abort (mono_thread_internal_current ());
6024 } else if (!is_appdomainunloaded_exception (klass
)
6025 && mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT
) {
6026 mono_unhandled_exception_internal (exc
);
6027 if (mono_environment_exitcode_get () == 1) {
6028 mono_environment_exitcode_set (255);
6029 mono_invoke_unhandled_exception_hook (exc
);
6030 g_assert_not_reached ();
6036 ves_icall_System_Threading_Thread_GetStackTraces (MonoArray
**out_threads
, MonoArray
**out_stack_traces
)
6039 mono_threads_get_thread_dump (out_threads
, out_stack_traces
, error
);
6040 mono_error_set_pending_exception (error
);
6044 * mono_threads_attach_coop_internal: called by native->managed wrappers
6047 * - blocking mode: contains gc unsafe transition cookie
6048 * - non-blocking mode: contains random data
6049 * - @stackdata: semi-opaque struct: stackpointer and function_name
6050 * - @return: the original domain which needs to be restored, or NULL.
6053 mono_threads_attach_coop_internal (MonoDomain
*domain
, gpointer
*cookie
, MonoStackData
*stackdata
)
6056 MonoThreadInfo
*info
;
6057 gboolean external
= FALSE
;
6059 orig
= mono_domain_get ();
6062 /* Happens when called from AOTed code which is only used in the root domain. */
6063 domain
= mono_get_root_domain ();
6067 /* On coop, when we detached, we moved the thread from RUNNING->BLOCKING.
6068 * If we try to reattach we do a BLOCKING->RUNNING transition. If the thread
6069 * is fresh, mono_thread_attach() will do a STARTING->RUNNING transition so
6070 * we're only responsible for making the cookie. */
6071 if (mono_threads_is_blocking_transition_enabled ())
6072 external
= !(info
= mono_thread_info_current_unchecked ()) || !mono_thread_info_is_live (info
);
6074 if (!mono_thread_internal_current ()) {
6075 mono_thread_attach (domain
);
6078 mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background
);
6081 if (mono_threads_is_blocking_transition_enabled ()) {
6083 /* mono_thread_attach put the thread in RUNNING mode from STARTING, but we need to
6084 * return the right cookie. */
6085 *cookie
= mono_threads_enter_gc_unsafe_region_cookie ();
6087 /* thread state (BLOCKING|RUNNING) -> RUNNING */
6088 *cookie
= mono_threads_enter_gc_unsafe_region_unbalanced_internal (stackdata
);
6093 mono_domain_set_fast (domain
, TRUE
);
6099 * mono_threads_attach_coop: called by native->managed wrappers
6102 * - blocking mode: contains gc unsafe transition cookie
6103 * - non-blocking mode: contains random data
6104 * - a pointer to stack, used for some checks
6105 * - @return: the original domain which needs to be restored, or NULL.
6108 mono_threads_attach_coop (MonoDomain
*domain
, gpointer
*dummy
)
6110 MONO_STACKDATA (stackdata
);
6111 stackdata
.stackpointer
= dummy
;
6112 return mono_threads_attach_coop_internal (domain
, dummy
, &stackdata
);
6116 * mono_threads_detach_coop_internal: called by native->managed wrappers
6118 * - @orig: the original domain which needs to be restored, or NULL.
6119 * - @stackdata: semi-opaque struct: stackpointer and function_name
6121 * - blocking mode: contains gc unsafe transition cookie
6122 * - non-blocking mode: contains random data
6125 mono_threads_detach_coop_internal (MonoDomain
*orig
, gpointer cookie
, MonoStackData
*stackdata
)
6127 MonoDomain
*domain
= mono_domain_get ();
6130 if (orig
!= domain
) {
6132 mono_domain_unset ();
6134 mono_domain_set_fast (orig
, TRUE
);
6137 if (mono_threads_is_blocking_transition_enabled ()) {
6138 /* it won't do anything if cookie is NULL
6139 * thread state RUNNING -> (RUNNING|BLOCKING) */
6140 mono_threads_exit_gc_unsafe_region_unbalanced_internal (cookie
, stackdata
);
6145 * mono_threads_detach_coop: called by native->managed wrappers
6147 * - @orig: the original domain which needs to be restored, or NULL.
6149 * - blocking mode: contains gc unsafe transition cookie
6150 * - non-blocking mode: contains random data
6151 * - a pointer to stack, used for some checks
6154 mono_threads_detach_coop (gpointer orig
, gpointer
*dummy
)
6156 MONO_STACKDATA (stackdata
);
6157 stackdata
.stackpointer
= dummy
;
6158 mono_threads_detach_coop_internal ((MonoDomain
*)orig
, *dummy
, &stackdata
);
6162 /* Returns TRUE if the current thread is ready to be interrupted. */
6164 mono_threads_is_ready_to_be_interrupted (void)
6166 MonoInternalThread
*thread
;
6168 thread
= mono_thread_internal_current ();
6169 LOCK_THREAD (thread
);
6170 if (thread
->state
& (ThreadState_SuspendRequested
| ThreadState_AbortRequested
)) {
6171 UNLOCK_THREAD (thread
);
6175 if (mono_thread_get_abort_prot_block_count (thread
) || mono_get_eh_callbacks ()->mono_current_thread_has_handle_block_guard ()) {
6176 UNLOCK_THREAD (thread
);
6180 UNLOCK_THREAD (thread
);
6186 mono_thread_internal_describe (MonoInternalThread
*internal
, GString
*text
)
6188 g_string_append_printf (text
, ", thread handle : %p", internal
->handle
);
6190 if (internal
->thread_info
) {
6191 g_string_append (text
, ", state : ");
6192 mono_thread_info_describe_interrupt_token (internal
->thread_info
, text
);
6195 if (internal
->owned_mutexes
) {
6198 g_string_append (text
, ", owns : [");
6199 for (i
= 0; i
< internal
->owned_mutexes
->len
; i
++)
6200 g_string_append_printf (text
, i
== 0 ? "%p" : ", %p", g_ptr_array_index (internal
->owned_mutexes
, i
));
6201 g_string_append (text
, "]");
6206 mono_thread_internal_is_current (MonoInternalThread
*internal
)
6208 g_assert (internal
);
6209 return mono_native_thread_id_equals (mono_native_thread_id_get (), MONO_UINT_TO_NATIVE_THREAD_ID (internal
->tid
));
6213 mono_set_thread_dump_dir (gchar
* dir
) {
6214 thread_dump_dir
= dir
;
6217 #ifdef DISABLE_CRASH_REPORTING
6219 mono_threads_summarize (MonoContext
*ctx
, gchar
**out
, MonoStackHash
*hashes
, gboolean silent
, gboolean signal_handler_controller
, gchar
*mem
, size_t provided_size
)
6225 mono_threads_summarize_one (MonoThreadSummary
*out
, MonoContext
*ctx
)
6233 mono_threads_summarize_native_self (MonoThreadSummary
*out
, MonoContext
*ctx
)
6235 if (!mono_get_eh_callbacks ()->mono_summarize_managed_stack
)
6238 memset (out
, 0, sizeof (MonoThreadSummary
));
6241 MonoNativeThreadId current
= mono_native_thread_id_get();
6242 out
->native_thread_id
= (intptr_t) current
;
6244 mono_get_eh_callbacks ()->mono_summarize_unmanaged_stack (out
);
6246 mono_native_thread_get_name (current
, out
->name
, MONO_MAX_SUMMARY_NAME_LEN
);
6251 // Not safe to call from signal handler
6253 mono_threads_summarize_one (MonoThreadSummary
*out
, MonoContext
*ctx
)
6255 gboolean success
= mono_threads_summarize_native_self (out
, ctx
);
6257 // Finish this on the same thread
6259 if (success
&& mono_get_eh_callbacks ()->mono_summarize_managed_stack
)
6260 mono_get_eh_callbacks ()->mono_summarize_managed_stack (out
);
6265 #define TIMEOUT_CRASH_REPORTER_FATAL 30
6266 #define MAX_NUM_THREADS 128
6268 gint32 has_owner
; // state of this memory
6270 MonoSemType update
; // notify of addition of threads
6273 MonoNativeThreadId thread_array
[MAX_NUM_THREADS
]; // ids of threads we're dumping
6275 int nthreads_attached
; // Number of threads self-registered
6276 MonoThreadSummary
*all_threads
[MAX_NUM_THREADS
];
6278 gboolean silent
; // print to stdout
6279 } SummarizerGlobalState
;
6281 #if defined(HAVE_KILL) && !defined(HOST_ANDROID) && defined(HAVE_WAITPID) && ((!defined(HOST_DARWIN) && defined(SYS_fork)) || HAVE_FORK)
6282 #define HAVE_MONO_SUMMARIZER_SUPERVISOR 1
6286 MonoSemType supervisor
;
6288 pid_t supervisor_pid
;
6289 } SummarizerSupervisorState
;
6291 #ifndef HAVE_MONO_SUMMARIZER_SUPERVISOR
6293 summarizer_supervisor_wait (SummarizerSupervisorState
*state
)
6299 summarizer_supervisor_start (SummarizerSupervisorState
*state
)
6301 // nonzero, so caller doesn't think it's the supervisor
6306 summarizer_supervisor_end (SummarizerSupervisorState
*state
)
6313 summarizer_supervisor_wait (SummarizerSupervisorState
*state
)
6315 sleep (TIMEOUT_CRASH_REPORTER_FATAL
);
6317 // If we haven't been SIGKILL'ed yet, we signal our parent
6320 g_async_safe_printf("Crash Reporter has timed out, sending SIGSEGV\n");
6321 kill (state
->pid
, SIGSEGV
);
6323 g_error ("kill () is not supported by this platform");
6330 summarizer_supervisor_start (SummarizerSupervisorState
*state
)
6332 memset (state
, 0, sizeof (*state
));
6335 state
->pid
= getpid();
6338 * glibc fork acquires some locks, so if the crash happened inside malloc/free,
6339 * it will deadlock. Call the syscall directly instead.
6341 #if defined(HOST_ANDROID)
6342 /* SYS_fork is defined to be __NR_fork which is not defined in some ndk versions */
6343 // We disable this when we set HAVE_MONO_SUMMARIZER_SUPERVISOR above
6344 g_assert_not_reached ();
6345 #elif !defined(HOST_DARWIN) && defined(SYS_fork)
6346 pid
= (pid_t
) syscall (SYS_fork
);
6348 pid
= (pid_t
) fork ();
6350 g_assert_not_reached ();
6354 state
->supervisor_pid
= pid
;
6360 summarizer_supervisor_end (SummarizerSupervisorState
*state
)
6363 kill (state
->supervisor_pid
, SIGKILL
);
6366 #if defined (HAVE_WAITPID)
6367 // Accessed on same thread that sets it.
6369 waitpid (state
->supervisor_pid
, &status
, 0);
6375 summarizer_state_init (SummarizerGlobalState
*state
, MonoNativeThreadId current
, int *my_index
)
6377 gint32 started_state
= mono_atomic_cas_i32 (&state
->has_owner
, 1 /* set */, 0 /* compare */);
6378 gboolean not_started
= started_state
== 0;
6380 state
->nthreads
= collect_thread_ids (state
->thread_array
, MAX_NUM_THREADS
);
6381 mono_os_sem_init (&state
->update
, 0);
6384 for (int i
= 0; i
< state
->nthreads
; i
++) {
6385 if (state
->thread_array
[i
] == current
) {
6395 summarizer_signal_other_threads (SummarizerGlobalState
*state
, MonoNativeThreadId current
, int current_idx
)
6397 sigset_t sigset
, old_sigset
;
6398 sigemptyset(&sigset
);
6399 sigaddset(&sigset
, SIGTERM
);
6401 for (int i
=0; i
< state
->nthreads
; i
++) {
6402 sigprocmask (SIG_UNBLOCK
, &sigset
, &old_sigset
);
6404 if (i
== current_idx
)
6407 #ifdef HAVE_PTHREAD_KILL
6408 pthread_kill (state
->thread_array
[i
], SIGTERM
);
6411 g_async_safe_printf("Pkilling 0x%zx from 0x%zx\n", MONO_NATIVE_THREAD_ID_TO_UINT (state
->thread_array
[i
]), MONO_NATIVE_THREAD_ID_TO_UINT (current
));
6413 g_error ("pthread_kill () is not supported by this platform");
6418 // Returns true when there are shared global references to "this_thread"
6420 summarizer_post_dump (SummarizerGlobalState
*state
, MonoThreadSummary
*this_thread
, int current_idx
)
6422 mono_memory_barrier ();
6424 gpointer old
= mono_atomic_cas_ptr ((volatile gpointer
*)&state
->all_threads
[current_idx
], this_thread
, NULL
);
6426 if (old
== GINT_TO_POINTER (-1)) {
6427 g_async_safe_printf ("Trying to register response after dumping period ended");
6429 } else if (old
!= NULL
) {
6430 g_async_safe_printf ("Thread dump raced for thread slot.");
6434 // We added our pointer
6435 gint32 count
= mono_atomic_inc_i32 ((volatile gint32
*) &state
->nthreads_attached
);
6436 if (count
== state
->nthreads
)
6437 mono_os_sem_post (&state
->update
);
6442 // A lockless spinwait with a timeout
6443 // Used in environments where locks are unsafe
6445 // If set_pos is true, we wait until the expected number of threads have
6446 // responded and then count that the expected number are set. If it is not true,
6447 // then we wait for them to be unset.
6449 summary_timedwait (SummarizerGlobalState
*state
, int timeout_seconds
)
6451 const gint64 milliseconds_in_second
= 1000;
6452 gint64 timeout_total
= milliseconds_in_second
* timeout_seconds
;
6454 gint64 end
= mono_msec_ticks () + timeout_total
;
6457 if (mono_atomic_load_i32 ((volatile gint32
*) &state
->nthreads_attached
) == state
->nthreads
)
6460 gint64 now
= mono_msec_ticks ();
6461 gint64 remaining
= end
- now
;
6465 mono_os_sem_timedwait (&state
->update
, remaining
, MONO_SEM_FLAGS_NONE
);
6471 static MonoThreadSummary
*
6472 summarizer_try_read_thread (SummarizerGlobalState
*state
, int index
)
6474 gpointer old_value
= NULL
;
6475 gpointer new_value
= GINT_TO_POINTER(-1);
6478 old_value
= state
->all_threads
[index
];
6479 } while (mono_atomic_cas_ptr ((volatile gpointer
*) &state
->all_threads
[index
], new_value
, old_value
) != old_value
);
6481 MonoThreadSummary
*thread
= (MonoThreadSummary
*) old_value
;
6486 summarizer_state_term (SummarizerGlobalState
*state
, gchar
**out
, gchar
*mem
, size_t provided_size
, MonoThreadSummary
*controlling
)
6488 // See the array writes
6489 mono_memory_barrier ();
6491 MonoThreadSummary
*threads
[MAX_NUM_THREADS
];
6492 memset (threads
, 0, sizeof(threads
));
6494 mono_summarize_timeline_phase_log (MonoSummaryManagedStacks
);
6495 for (int i
=0; i
< state
->nthreads
; i
++) {
6496 threads
[i
] = summarizer_try_read_thread (state
, i
);
6500 // We are doing this dump on the controlling thread because this isn't
6501 // an async context sometimes. There's still some reliance on malloc here, but it's
6502 // much more stable to do it all from the controlling thread.
6504 // This is non-null, checked in mono_threads_summarize
6505 // with early exit there
6506 mono_get_eh_callbacks ()->mono_summarize_managed_stack (threads
[i
]);
6509 MonoStateWriter writer
;
6510 memset (&writer
, 0, sizeof (writer
));
6512 mono_summarize_timeline_phase_log (MonoSummaryStateWriter
);
6513 mono_summarize_native_state_begin (&writer
, mem
, provided_size
);
6514 for (int i
=0; i
< state
->nthreads
; i
++) {
6515 MonoThreadSummary
*thread
= threads
[i
];
6519 mono_summarize_native_state_add_thread (&writer
, thread
, thread
->ctx
, thread
== controlling
);
6520 // Set non-shared state to notify the waiting thread to clean up
6521 // without having to keep our shared state alive
6522 mono_atomic_store_i32 (&thread
->done
, 0x1);
6523 mono_os_sem_post (&thread
->done_wait
);
6525 *out
= mono_summarize_native_state_end (&writer
);
6526 mono_summarize_timeline_phase_log (MonoSummaryStateWriterDone
);
6528 mono_os_sem_destroy (&state
->update
);
6530 memset (state
, 0, sizeof (*state
));
6531 mono_atomic_store_i32 ((volatile gint32
*)&state
->has_owner
, 0);
6535 summarizer_state_wait (MonoThreadSummary
*thread
)
6537 gint64 milliseconds_in_second
= 1000;
6539 // cond_wait can spuriously wake up, so we need to check
6541 while (!mono_atomic_load_i32 (&thread
->done
))
6542 mono_os_sem_timedwait (&thread
->done_wait
, milliseconds_in_second
, MONO_SEM_FLAGS_NONE
);
6546 mono_threads_summarize_execute_internal (MonoContext
*ctx
, gchar
**out
, MonoStackHash
*hashes
, gboolean silent
, gchar
*working_mem
, size_t provided_size
, gboolean this_thread_controls
)
6548 static SummarizerGlobalState state
;
6551 MonoNativeThreadId current
= mono_native_thread_id_get ();
6552 gboolean thread_given_control
= summarizer_state_init (&state
, current
, ¤t_idx
);
6554 g_assert (this_thread_controls
== thread_given_control
);
6556 if (state
.nthreads
== 0) {
6558 g_async_safe_printf("No threads attached to runtime.\n");
6559 memset (&state
, 0, sizeof (state
));
6563 if (this_thread_controls
) {
6564 g_assert (working_mem
);
6566 mono_summarize_timeline_phase_log (MonoSummarySuspendHandshake
);
6567 state
.silent
= silent
;
6568 summarizer_signal_other_threads (&state
, current
, current_idx
);
6569 mono_summarize_timeline_phase_log (MonoSummaryUnmanagedStacks
);
6573 gboolean success
= mono_state_alloc_mem (&mem
, (long) current
, sizeof (MonoThreadSummary
));
6577 MonoThreadSummary
*this_thread
= (MonoThreadSummary
*) mem
.mem
;
6579 if (mono_threads_summarize_native_self (this_thread
, ctx
)) {
6580 // Init the synchronization between the controlling thread and the
6582 mono_os_sem_init (&this_thread
->done_wait
, 0);
6584 // Store a reference to our stack memory into global state
6585 gboolean success
= summarizer_post_dump (&state
, this_thread
, current_idx
);
6586 if (!success
&& !state
.silent
)
6587 g_async_safe_printf("Thread 0x%zx reported itself.\n", MONO_NATIVE_THREAD_ID_TO_UINT (current
));
6588 } else if (!state
.silent
) {
6589 g_async_safe_printf("Thread 0x%zx couldn't report itself.\n", MONO_NATIVE_THREAD_ID_TO_UINT (current
));
6592 // From summarizer, wait and dump.
6593 if (this_thread_controls
) {
6595 g_async_safe_printf("Entering thread summarizer pause from 0x%zx\n", MONO_NATIVE_THREAD_ID_TO_UINT (current
));
6597 // Wait up to 2 seconds for all of the other threads to catch up
6598 summary_timedwait (&state
, 2);
6601 g_async_safe_printf("Finished thread summarizer pause from 0x%zx.\n", MONO_NATIVE_THREAD_ID_TO_UINT (current
));
6603 // Dump and cleanup all the stack memory
6604 summarizer_state_term (&state
, out
, working_mem
, provided_size
, this_thread
);
6606 // Wait here, keeping our stack memory alive
6608 summarizer_state_wait (this_thread
);
6611 // FIXME: How many threads should be counted?
6613 *hashes
= this_thread
->hashes
;
6615 mono_state_free_mem (&mem
);
6621 mono_threads_summarize_execute (MonoContext
*ctx
, gchar
**out
, MonoStackHash
*hashes
, gboolean silent
, gchar
*working_mem
, size_t provided_size
)
6623 return mono_threads_summarize_execute_internal (ctx
, out
, hashes
, silent
, working_mem
, provided_size
, FALSE
);
6627 mono_threads_summarize (MonoContext
*ctx
, gchar
**out
, MonoStackHash
*hashes
, gboolean silent
, gboolean signal_handler_controller
, gchar
*mem
, size_t provided_size
)
6629 if (!mono_get_eh_callbacks ()->mono_summarize_managed_stack
)
6632 // The staggered values are due to the need to use inc_i64 for the first value
6633 static gint64 next_pending_request_id
= 0;
6634 static gint64 request_available_to_run
= 1;
6635 gint64 this_request_id
= mono_atomic_inc_i64 ((volatile gint64
*) &next_pending_request_id
);
6637 // This is a global queue of summary requests.
6638 // It's not safe to signal a thread while they're in the
6639 // middle of a dump. Dladdr is not reentrant. It's the one lock
6640 // we rely on being able to take.
6642 // We don't use it in almost any other place in managed code, so
6643 // our problem is in the stack dumping code racing with the signalling code.
6645 // A dump is wait-free to the degree that it's not going to loop indefinitely.
6646 // If we're running from a crash handler block, we're not in any position to
6647 // wait for an in-flight dump to finish. If we crashed while dumping, we cannot dump.
6648 // We should simply return so we can die cleanly.
6650 // signal_handler_controller should be set only from a handler that expects itself to be the only
6651 // entry point, where the runtime already being dumping means we should just give up
6653 gboolean success
= FALSE
;
6656 gint64 next_request_id
= mono_atomic_load_i64 ((volatile gint64
*) &request_available_to_run
);
6658 if (next_request_id
== this_request_id
) {
6659 gboolean already_async
= mono_thread_info_is_async_context ();
6661 mono_thread_info_set_is_async_context (TRUE
);
6663 SummarizerSupervisorState synch
;
6664 if (summarizer_supervisor_start (&synch
)) {
6666 success
= mono_threads_summarize_execute_internal (ctx
, out
, hashes
, silent
, mem
, provided_size
, TRUE
);
6667 summarizer_supervisor_end (&synch
);
6669 summarizer_supervisor_wait (&synch
);
6673 mono_thread_info_set_is_async_context (FALSE
);
6675 // Only the thread that gets the ticket can unblock future dumpers.
6676 mono_atomic_inc_i64 ((volatile gint64
*) &request_available_to_run
);
6678 } else if (signal_handler_controller
) {
6679 // We're done. We can't do anything.
6680 g_async_safe_printf ("Attempted to dump for critical failure when already in dump. Error reporting crashed?");
6681 mono_summarize_double_fault_log ();
6685 g_async_safe_printf ("Waiting for in-flight dump to complete.");
6695 #ifdef ENABLE_NETCORE
6697 ves_icall_System_Threading_Thread_StartInternal (MonoThreadObjectHandle thread_handle
, MonoError
*error
)
6699 MonoThread
*internal
= MONO_HANDLE_RAW (thread_handle
);
6702 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p)", __func__
, internal
));
6704 LOCK_THREAD (internal
);
6706 if ((internal
->state
& ThreadState_Unstarted
) == 0) {
6707 UNLOCK_THREAD (internal
);
6708 mono_error_set_exception_thread_state (error
, "Thread has already been started.");
6712 if ((internal
->state
& ThreadState_Aborted
) != 0) {
6713 UNLOCK_THREAD (internal
);
6717 res
= create_thread (internal
, internal
, NULL
, NULL
, NULL
, MONO_THREAD_CREATE_FLAGS_NONE
, error
);
6719 UNLOCK_THREAD (internal
);
6723 internal
->state
&= ~ThreadState_Unstarted
;
6725 THREAD_DEBUG (g_message ("%s: Started thread ID %" G_GSIZE_FORMAT
" (handle %p)", __func__
, (gsize
)internal
->tid
, internal
->handle
));
6727 UNLOCK_THREAD (internal
);
6731 ves_icall_System_Threading_Thread_InitInternal (MonoThreadObjectHandle thread_handle
, MonoError
*error
)
6733 MonoThread
*internal
= MONO_HANDLE_RAW (thread_handle
);
6735 // Need to initialize thread objects created from managed code
6736 init_internal_thread_object (internal
);
6737 internal
->state
= ThreadState_Unstarted
;
6738 MONO_OBJECT_SETREF_INTERNAL (internal
, internal_thread
, internal
);
6742 ves_icall_System_Threading_Thread_GetCurrentOSThreadId (MonoError
*error
)
6744 return mono_native_thread_os_id_get ();