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/gc-internals.h>
30 #include <mono/metadata/marshal.h>
31 #include <mono/metadata/runtime.h>
32 #include <mono/metadata/object-internals.h>
33 #include <mono/metadata/debug-internals.h>
34 #include <mono/utils/monobitset.h>
35 #include <mono/utils/mono-compiler.h>
36 #include <mono/utils/mono-mmap.h>
37 #include <mono/utils/mono-membar.h>
38 #include <mono/utils/mono-time.h>
39 #include <mono/utils/mono-threads.h>
40 #include <mono/utils/mono-threads-coop.h>
41 #include <mono/utils/mono-tls.h>
42 #include <mono/utils/atomic.h>
43 #include <mono/utils/mono-memory-model.h>
44 #include <mono/utils/mono-error-internals.h>
45 #include <mono/utils/os-event.h>
46 #include <mono/utils/mono-threads-debug.h>
47 #include <mono/utils/unlocked.h>
48 #include <mono/metadata/w32handle.h>
49 #include <mono/metadata/w32event.h>
50 #include <mono/metadata/w32mutex.h>
52 #include <mono/metadata/reflection-internals.h>
53 #include <mono/metadata/abi-details.h>
54 #include <mono/metadata/w32error.h>
55 #include <mono/utils/w32api.h>
56 #include <mono/utils/mono-os-wait.h>
62 #if defined(HOST_WIN32)
66 mono_native_thread_join_handle (HANDLE thread_handle
, gboolean close_handle
);
69 #if defined(HOST_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64)
70 #define USE_TKILL_ON_ANDROID 1
76 #ifdef USE_TKILL_ON_ANDROID
77 extern int tkill (pid_t tid
, int signal
);
81 /*#define THREAD_DEBUG(a) do { a; } while (0)*/
82 #define THREAD_DEBUG(a)
83 /*#define THREAD_WAIT_DEBUG(a) do { a; } while (0)*/
84 #define THREAD_WAIT_DEBUG(a)
85 /*#define LIBGC_DEBUG(a) do { a; } while (0)*/
86 #define LIBGC_DEBUG(a)
88 #define SPIN_TRYLOCK(i) (mono_atomic_cas_i32 (&(i), 1, 0) == 0)
89 #define SPIN_LOCK(i) do { \
90 if (SPIN_TRYLOCK (i)) \
94 #define SPIN_UNLOCK(i) i = 0
96 #define LOCK_THREAD(thread) lock_thread((thread))
97 #define UNLOCK_THREAD(thread) unlock_thread((thread))
109 typedef struct _StaticDataFreeList StaticDataFreeList
;
110 struct _StaticDataFreeList
{
111 StaticDataFreeList
*next
;
119 StaticDataFreeList
*freelist
;
122 /* Controls access to the 'threads' hash table */
123 static void mono_threads_lock (void);
124 static void mono_threads_unlock (void);
125 static MonoCoopMutex threads_mutex
;
127 /* Controls access to the 'joinable_threads' hash table */
128 #define joinable_threads_lock() mono_os_mutex_lock (&joinable_threads_mutex)
129 #define joinable_threads_unlock() mono_os_mutex_unlock (&joinable_threads_mutex)
130 static mono_mutex_t joinable_threads_mutex
;
132 /* Holds current status of static data heap */
133 static StaticDataInfo thread_static_info
;
134 static StaticDataInfo context_static_info
;
136 /* The hash of existing threads (key is thread ID, value is
137 * MonoInternalThread*) that need joining before exit
139 static MonoGHashTable
*threads
=NULL
;
141 /* List of app context GC handles.
142 * Added to from mono_threads_register_app_context ().
144 static GHashTable
*contexts
= NULL
;
146 /* Cleanup queue for contexts. */
147 static MonoReferenceQueue
*context_queue
;
150 * Threads which are starting up and they are not in the 'threads' hash yet.
151 * When mono_thread_attach_internal is called for a thread, it will be removed from this hash table.
152 * Protected by mono_threads_lock ().
154 static MonoGHashTable
*threads_starting_up
= NULL
;
157 /* Protected by the threads lock */
158 static GHashTable
*joinable_threads
;
159 static gint32 joinable_thread_count
;
161 static GHashTable
*pending_joinable_threads
;
162 static gint32 pending_joinable_thread_count
;
164 static mono_cond_t zero_pending_joinable_thread_event
;
166 static void threads_add_pending_joinable_runtime_thread (MonoThreadInfo
*mono_thread_info
);
167 static gboolean
threads_wait_pending_joinable_threads (uint32_t timeout
);
169 #define SET_CURRENT_OBJECT(x) mono_tls_set_thread (x)
170 #define GET_CURRENT_OBJECT() (MonoInternalThread*) mono_tls_get_thread ()
172 /* function called at thread start */
173 static MonoThreadStartCB mono_thread_start_cb
= NULL
;
175 /* function called at thread attach */
176 static MonoThreadAttachCB mono_thread_attach_cb
= NULL
;
178 /* function called at thread cleanup */
179 static MonoThreadCleanupFunc mono_thread_cleanup_fn
= NULL
;
181 /* The default stack size for each thread */
182 static guint32 default_stacksize
= 0;
183 #define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize)
185 static void context_adjust_static_data (MonoAppContext
*ctx
);
186 static void mono_free_static_data (gpointer
* static_data
);
187 static void mono_init_static_data_info (StaticDataInfo
*static_data
);
188 static guint32
mono_alloc_static_data_slot (StaticDataInfo
*static_data
, guint32 size
, guint32 align
);
189 static gboolean
mono_thread_resume (MonoInternalThread
* thread
);
190 static void async_abort_internal (MonoInternalThread
*thread
, gboolean install_async_abort
);
191 static void self_abort_internal (MonoError
*error
);
192 static void async_suspend_internal (MonoInternalThread
*thread
, gboolean interrupt
);
193 static void self_suspend_internal (void);
195 static MonoException
* mono_thread_execute_interruption (void);
196 static void ref_stack_destroy (gpointer rs
);
198 /* Spin lock for InterlockedXXX 64 bit functions */
199 #define mono_interlocked_lock() mono_os_mutex_lock (&interlocked_mutex)
200 #define mono_interlocked_unlock() mono_os_mutex_unlock (&interlocked_mutex)
201 static mono_mutex_t interlocked_mutex
;
203 /* global count of thread interruptions requested */
204 static gint32 thread_interruption_requested
= 0;
206 /* Event signaled when a thread changes its background mode */
207 static MonoOSEvent background_change_event
;
209 static gboolean shutting_down
= FALSE
;
211 static gint32 managed_thread_id_counter
= 0;
214 mono_threads_lock (void)
216 mono_locks_coop_acquire (&threads_mutex
, ThreadsLock
);
220 mono_threads_unlock (void)
222 mono_locks_coop_release (&threads_mutex
, ThreadsLock
);
227 get_next_managed_thread_id (void)
229 return mono_atomic_inc_i32 (&managed_thread_id_counter
);
233 * We separate interruptions/exceptions into either sync (they can be processed anytime,
234 * normally as soon as they are set, and are set by the same thread) and async (they can't
235 * be processed inside abort protected blocks and are normally set by other threads). We
236 * can have both a pending sync and async interruption. In this case, the sync exception is
237 * processed first. Since we clean sync flag first, mono_thread_execute_interruption must
238 * also handle all sync type exceptions before the async type exceptions.
241 INTERRUPT_SYNC_REQUESTED_BIT
= 0x1,
242 INTERRUPT_ASYNC_REQUESTED_BIT
= 0x2,
243 INTERRUPT_REQUESTED_MASK
= 0x3,
244 ABORT_PROT_BLOCK_SHIFT
= 2,
245 ABORT_PROT_BLOCK_BITS
= 8,
246 ABORT_PROT_BLOCK_MASK
= (((1 << ABORT_PROT_BLOCK_BITS
) - 1) << ABORT_PROT_BLOCK_SHIFT
)
250 mono_thread_get_abort_prot_block_count (MonoInternalThread
*thread
)
252 gsize state
= thread
->thread_state
;
253 return (state
& ABORT_PROT_BLOCK_MASK
) >> ABORT_PROT_BLOCK_SHIFT
;
257 mono_threads_begin_abort_protected_block (void)
259 MonoInternalThread
*thread
= mono_thread_internal_current ();
260 gsize old_state
, new_state
;
263 old_state
= thread
->thread_state
;
265 new_val
= ((old_state
& ABORT_PROT_BLOCK_MASK
) >> ABORT_PROT_BLOCK_SHIFT
) + 1;
266 //bounds check abort_prot_count
267 g_assert (new_val
> 0);
268 g_assert (new_val
< (1 << ABORT_PROT_BLOCK_BITS
));
270 new_state
= old_state
+ (1 << ABORT_PROT_BLOCK_SHIFT
);
271 } while (mono_atomic_cas_ptr ((volatile gpointer
*)&thread
->thread_state
, (gpointer
)new_state
, (gpointer
)old_state
) != (gpointer
)old_state
);
273 /* Defer async request since we won't be able to process until exiting the block */
274 if (new_val
== 1 && (new_state
& INTERRUPT_ASYNC_REQUESTED_BIT
)) {
275 mono_atomic_dec_i32 (&thread_interruption_requested
);
276 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
);
277 if (thread_interruption_requested
< 0)
278 g_warning ("bad thread_interruption_requested state");
280 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
);
285 mono_thread_state_has_interruption (gsize state
)
287 /* pending exception, self abort */
288 if (state
& INTERRUPT_SYNC_REQUESTED_BIT
)
291 /* abort, interruption, suspend */
292 if ((state
& INTERRUPT_ASYNC_REQUESTED_BIT
) && !(state
& ABORT_PROT_BLOCK_MASK
))
299 mono_threads_end_abort_protected_block (void)
301 MonoInternalThread
*thread
= mono_thread_internal_current ();
302 gsize old_state
, new_state
;
305 old_state
= thread
->thread_state
;
307 //bounds check abort_prot_count
308 new_val
= ((old_state
& ABORT_PROT_BLOCK_MASK
) >> ABORT_PROT_BLOCK_SHIFT
) - 1;
309 g_assert (new_val
>= 0);
310 g_assert (new_val
< (1 << ABORT_PROT_BLOCK_BITS
));
312 new_state
= old_state
- (1 << ABORT_PROT_BLOCK_SHIFT
);
313 } while (mono_atomic_cas_ptr ((volatile gpointer
*)&thread
->thread_state
, (gpointer
)new_state
, (gpointer
)old_state
) != (gpointer
)old_state
);
315 if (new_val
== 0 && (new_state
& INTERRUPT_ASYNC_REQUESTED_BIT
)) {
316 mono_atomic_inc_i32 (&thread_interruption_requested
);
317 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
);
319 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
);
322 return mono_thread_state_has_interruption (new_state
);
326 mono_thread_get_interruption_requested (MonoInternalThread
*thread
)
328 gsize state
= thread
->thread_state
;
330 return mono_thread_state_has_interruption (state
);
334 * Returns TRUE is there was a state change
335 * We clear a single interruption request, sync has priority.
338 mono_thread_clear_interruption_requested (MonoInternalThread
*thread
)
340 gsize old_state
, new_state
;
342 old_state
= thread
->thread_state
;
344 // no interruption to process
345 if (!(old_state
& INTERRUPT_SYNC_REQUESTED_BIT
) &&
346 (!(old_state
& INTERRUPT_ASYNC_REQUESTED_BIT
) || (old_state
& ABORT_PROT_BLOCK_MASK
)))
349 if (old_state
& INTERRUPT_SYNC_REQUESTED_BIT
)
350 new_state
= old_state
& ~INTERRUPT_SYNC_REQUESTED_BIT
;
352 new_state
= old_state
& ~INTERRUPT_ASYNC_REQUESTED_BIT
;
353 } while (mono_atomic_cas_ptr ((volatile gpointer
*)&thread
->thread_state
, (gpointer
)new_state
, (gpointer
)old_state
) != (gpointer
)old_state
);
355 mono_atomic_dec_i32 (&thread_interruption_requested
);
356 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
);
357 if (thread_interruption_requested
< 0)
358 g_warning ("bad thread_interruption_requested state");
362 /* Returns TRUE is there was a state change and the interruption can be processed */
364 mono_thread_set_interruption_requested (MonoInternalThread
*thread
)
366 //always force when the current thread is doing it to itself.
367 gboolean sync
= thread
== mono_thread_internal_current ();
368 gsize old_state
, new_state
;
370 old_state
= thread
->thread_state
;
373 if ((sync
&& (old_state
& INTERRUPT_SYNC_REQUESTED_BIT
)) ||
374 (!sync
&& (old_state
& INTERRUPT_ASYNC_REQUESTED_BIT
)))
378 new_state
= old_state
| INTERRUPT_SYNC_REQUESTED_BIT
;
380 new_state
= old_state
| INTERRUPT_ASYNC_REQUESTED_BIT
;
381 } while (mono_atomic_cas_ptr ((volatile gpointer
*)&thread
->thread_state
, (gpointer
)new_state
, (gpointer
)old_state
) != (gpointer
)old_state
);
383 if (sync
|| !(new_state
& ABORT_PROT_BLOCK_MASK
)) {
384 mono_atomic_inc_i32 (&thread_interruption_requested
);
385 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
);
387 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
);
390 return sync
|| !(new_state
& ABORT_PROT_BLOCK_MASK
);
393 static inline MonoNativeThreadId
394 thread_get_tid (MonoInternalThread
*thread
)
396 /* We store the tid as a guint64 to keep the object layout constant between platforms */
397 return MONO_UINT_TO_NATIVE_THREAD_ID (thread
->tid
);
400 static void ensure_synch_cs_set (MonoInternalThread
*thread
)
402 MonoCoopMutex
*synch_cs
;
404 if (thread
->synch_cs
!= NULL
) {
408 synch_cs
= g_new0 (MonoCoopMutex
, 1);
409 mono_coop_mutex_init_recursive (synch_cs
);
411 if (mono_atomic_cas_ptr ((gpointer
*)&thread
->synch_cs
,
412 synch_cs
, NULL
) != NULL
) {
413 /* Another thread must have installed this CS */
414 mono_coop_mutex_destroy (synch_cs
);
420 lock_thread (MonoInternalThread
*thread
)
422 if (!thread
->synch_cs
)
423 ensure_synch_cs_set (thread
);
425 g_assert (thread
->synch_cs
);
427 mono_coop_mutex_lock (thread
->synch_cs
);
431 unlock_thread (MonoInternalThread
*thread
)
433 mono_coop_mutex_unlock (thread
->synch_cs
);
436 static inline gboolean
437 is_appdomainunloaded_exception (MonoClass
*klass
)
439 return klass
== mono_class_get_appdomain_unloaded_exception_class ();
442 static inline gboolean
443 is_threadabort_exception (MonoClass
*klass
)
445 return klass
== mono_defaults
.threadabortexception_class
;
449 * A special static data offset (guint32) consists of 3 parts:
451 * [0] 6-bit index into the array of chunks.
452 * [6] 25-bit offset into the array.
453 * [31] Bit indicating thread or context static.
458 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
469 } SpecialStaticOffset
;
471 #define SPECIAL_STATIC_OFFSET_TYPE_THREAD 0
472 #define SPECIAL_STATIC_OFFSET_TYPE_CONTEXT 1
474 #define MAKE_SPECIAL_STATIC_OFFSET(idx, off, ty) \
475 ((SpecialStaticOffset) { .fields = { .index = (idx), .offset = (off), .type = (ty) } }.raw)
476 #define ACCESS_SPECIAL_STATIC_OFFSET(x,f) \
477 (((SpecialStaticOffset *) &(x))->fields.f)
480 get_thread_static_data (MonoInternalThread
*thread
, guint32 offset
)
482 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset
, type
) == SPECIAL_STATIC_OFFSET_TYPE_THREAD
);
484 int idx
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, index
);
485 int off
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, offset
);
487 return ((char *) thread
->static_data
[idx
]) + off
;
491 get_context_static_data (MonoAppContext
*ctx
, guint32 offset
)
493 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset
, type
) == SPECIAL_STATIC_OFFSET_TYPE_CONTEXT
);
495 int idx
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, index
);
496 int off
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, offset
);
498 return ((char *) ctx
->static_data
[idx
]) + off
;
502 get_current_thread_ptr_for_domain (MonoDomain
*domain
, MonoInternalThread
*thread
)
504 static MonoClassField
*current_thread_field
= NULL
;
508 if (!current_thread_field
) {
509 current_thread_field
= mono_class_get_field_from_name (mono_defaults
.thread_class
, "current_thread");
510 g_assert (current_thread_field
);
513 ERROR_DECL_VALUE (thread_vt_error
);
514 mono_class_vtable_checked (domain
, mono_defaults
.thread_class
, &thread_vt_error
);
515 mono_error_assert_ok (&thread_vt_error
);
516 mono_domain_lock (domain
);
517 offset
= GPOINTER_TO_UINT (g_hash_table_lookup (domain
->special_static_fields
, current_thread_field
));
518 mono_domain_unlock (domain
);
521 return (MonoThread
**)get_thread_static_data (thread
, offset
);
525 set_current_thread_for_domain (MonoDomain
*domain
, MonoInternalThread
*thread
, MonoThread
*current
)
527 MonoThread
**current_thread_ptr
= get_current_thread_ptr_for_domain (domain
, thread
);
529 g_assert (current
->obj
.vtable
->domain
== domain
);
531 g_assert (!*current_thread_ptr
);
532 *current_thread_ptr
= current
;
536 create_thread_object (MonoDomain
*domain
, MonoInternalThread
*internal
)
542 vtable
= mono_class_vtable_checked (domain
, mono_defaults
.thread_class
, error
);
543 mono_error_assert_ok (error
);
545 thread
= (MonoThread
*)mono_object_new_mature (vtable
, error
);
546 /* only possible failure mode is OOM, from which we don't expect to recover. */
547 mono_error_assert_ok (error
);
549 MONO_OBJECT_SETREF (thread
, internal_thread
, internal
);
554 static MonoInternalThread
*
555 create_internal_thread_object (void)
558 MonoInternalThread
*thread
;
561 vt
= mono_class_vtable_checked (mono_get_root_domain (), mono_defaults
.internal_thread_class
, error
);
562 mono_error_assert_ok (error
);
563 thread
= (MonoInternalThread
*) mono_object_new_mature (vt
, error
);
564 /* only possible failure mode is OOM, from which we don't exect to recover */
565 mono_error_assert_ok (error
);
567 thread
->synch_cs
= g_new0 (MonoCoopMutex
, 1);
568 mono_coop_mutex_init_recursive (thread
->synch_cs
);
570 thread
->apartment_state
= ThreadApartmentState_Unknown
;
571 thread
->managed_id
= get_next_managed_thread_id ();
572 if (mono_gc_is_moving ()) {
573 thread
->thread_pinning_ref
= thread
;
574 MONO_GC_REGISTER_ROOT_PINNING (thread
->thread_pinning_ref
, MONO_ROOT_SOURCE_THREADING
, NULL
, "Thread Pinning Reference");
577 thread
->priority
= MONO_THREAD_PRIORITY_NORMAL
;
579 thread
->suspended
= g_new0 (MonoOSEvent
, 1);
580 mono_os_event_init (thread
->suspended
, TRUE
);
586 mono_thread_internal_set_priority (MonoInternalThread
*internal
, MonoThreadPriority priority
)
590 g_assert (priority
>= MONO_THREAD_PRIORITY_LOWEST
);
591 g_assert (priority
<= MONO_THREAD_PRIORITY_HIGHEST
);
592 g_assert (MONO_THREAD_PRIORITY_LOWEST
< MONO_THREAD_PRIORITY_HIGHEST
);
597 g_assert (internal
->native_handle
);
599 res
= SetThreadPriority (internal
->native_handle
, priority
- 2);
601 g_error ("%s: SetThreadPriority failed, error %d", __func__
, GetLastError ());
602 #else /* HOST_WIN32 */
605 struct sched_param param
;
608 tid
= thread_get_tid (internal
);
610 res
= pthread_getschedparam (tid
, &policy
, ¶m
);
612 g_error ("%s: pthread_getschedparam failed, error: \"%s\" (%d)", __func__
, g_strerror (res
), res
);
614 #ifdef _POSIX_PRIORITY_SCHEDULING
617 /* Necessary to get valid priority range */
619 min
= sched_get_priority_min (policy
);
620 max
= sched_get_priority_max (policy
);
622 if (max
> 0 && min
>= 0 && max
> min
) {
623 double srange
, drange
, sposition
, dposition
;
624 srange
= MONO_THREAD_PRIORITY_HIGHEST
- MONO_THREAD_PRIORITY_LOWEST
;
626 sposition
= priority
- MONO_THREAD_PRIORITY_LOWEST
;
627 dposition
= (sposition
/ srange
) * drange
;
628 param
.sched_priority
= (int)(dposition
+ min
);
635 param
.sched_priority
= 50;
641 param
.sched_priority
= 0;
644 g_warning ("%s: unknown policy %d", __func__
, policy
);
649 res
= pthread_setschedparam (tid
, policy
, ¶m
);
652 g_warning ("%s: pthread_setschedparam failed, error: \"%s\" (%d)", __func__
, g_strerror (res
), res
);
655 g_error ("%s: pthread_setschedparam failed, error: \"%s\" (%d)", __func__
, g_strerror (res
), res
);
657 #endif /* HOST_WIN32 */
661 mono_alloc_static_data (gpointer
**static_data_ptr
, guint32 offset
, void *alloc_key
, gboolean threadlocal
);
664 mono_thread_attach_internal (MonoThread
*thread
, gboolean force_attach
, gboolean force_domain
)
666 MonoThreadInfo
*info
;
667 MonoInternalThread
*internal
;
668 MonoDomain
*domain
, *root_domain
;
673 info
= mono_thread_info_current ();
676 internal
= thread
->internal_thread
;
679 /* It is needed to store the MonoInternalThread on the MonoThreadInfo, because of the following case:
680 * - the MonoInternalThread TLS key is destroyed: set it to NULL
681 * - the MonoThreadInfo TLS key is destroyed: calls mono_thread_info_detach
682 * - it calls MonoThreadInfoCallbacks.thread_detach
683 * - mono_thread_internal_current returns NULL -> fails to detach the MonoInternalThread. */
684 mono_thread_info_set_internal_thread_gchandle (info
, mono_gchandle_new ((MonoObject
*) internal
, FALSE
));
686 internal
->handle
= mono_threads_open_thread_handle (info
->handle
);
688 internal
->native_handle
= OpenThread (THREAD_ALL_ACCESS
, FALSE
, GetCurrentThreadId ());
690 internal
->tid
= MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ());
691 internal
->thread_info
= info
;
692 internal
->small_id
= info
->small_id
;
694 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT
") Setting current_object_key to %p", __func__
, mono_native_thread_id_get (), internal
));
696 SET_CURRENT_OBJECT (internal
);
698 domain
= mono_object_domain (thread
);
700 mono_thread_push_appdomain_ref (domain
);
701 if (!mono_domain_set (domain
, force_domain
)) {
702 mono_thread_pop_appdomain_ref ();
706 mono_threads_lock ();
708 if (shutting_down
&& !force_attach
) {
709 mono_threads_unlock ();
710 mono_thread_pop_appdomain_ref ();
714 if (threads_starting_up
)
715 mono_g_hash_table_remove (threads_starting_up
, thread
);
718 threads
= mono_g_hash_table_new_type (NULL
, NULL
, MONO_HASH_VALUE_GC
, MONO_ROOT_SOURCE_THREADING
, NULL
, "Thread Table");
721 /* We don't need to duplicate thread->handle, because it is
722 * only closed when the thread object is finalized by the GC. */
723 mono_g_hash_table_insert (threads
, (gpointer
)(gsize
)(internal
->tid
), internal
);
725 /* We have to do this here because mono_thread_start_cb
726 * requires that root_domain_thread is set up. */
727 if (thread_static_info
.offset
|| thread_static_info
.idx
> 0) {
728 /* get the current allocated size */
729 guint32 offset
= MAKE_SPECIAL_STATIC_OFFSET (thread_static_info
.idx
, thread_static_info
.offset
, 0);
730 mono_alloc_static_data (&internal
->static_data
, offset
, (void *) MONO_UINT_TO_NATIVE_THREAD_ID (internal
->tid
), TRUE
);
733 mono_threads_unlock ();
735 root_domain
= mono_get_root_domain ();
737 g_assert (!internal
->root_domain_thread
);
738 if (domain
!= root_domain
)
739 MONO_OBJECT_SETREF (internal
, root_domain_thread
, create_thread_object (root_domain
, internal
));
741 MONO_OBJECT_SETREF (internal
, root_domain_thread
, thread
);
743 if (domain
!= root_domain
)
744 set_current_thread_for_domain (root_domain
, internal
, internal
->root_domain_thread
);
746 set_current_thread_for_domain (domain
, internal
, thread
);
748 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT
" (handle %p)", __func__
, internal
->tid
, internal
->handle
));
753 mono_threads_lock ();
754 if (threads_starting_up
)
755 mono_g_hash_table_remove (threads_starting_up
, thread
);
756 mono_threads_unlock ();
758 if (!mono_thread_info_try_get_internal_thread_gchandle (info
, &gchandle
))
759 g_error ("%s: failed to get gchandle, info %p", __func__
, info
);
761 mono_gchandle_free (gchandle
);
763 mono_thread_info_unset_internal_thread_gchandle (info
);
765 SET_CURRENT_OBJECT(NULL
);
771 mono_thread_detach_internal (MonoInternalThread
*thread
)
773 MonoThreadInfo
*info
;
774 MonoInternalThread
*value
;
778 g_assert (mono_thread_internal_is_current (thread
));
780 g_assert (thread
!= NULL
);
781 SET_CURRENT_OBJECT (thread
);
783 info
= (MonoThreadInfo
*) thread
->thread_info
;
786 THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT
")", __func__
, thread
, (gsize
)thread
->tid
));
788 MONO_PROFILER_RAISE (thread_stopping
, (thread
->tid
));
791 * Prevent race condition between thread shutdown and runtime shutdown.
792 * Including all runtime threads in the pending joinable count will make
793 * sure shutdown will wait for it to get onto the joinable thread list before
794 * critical resources have been cleanup (like GC memory). Threads getting onto
795 * the joinable thread list should just about to exit and not blocking a potential
796 * join call. Owner of threads attached to the runtime but not identified as runtime
797 * threads needs to make sure thread detach calls won't race with runtime shutdown.
799 threads_add_pending_joinable_runtime_thread (info
);
802 mono_w32mutex_abandon (thread
);
805 if (thread
->abort_state_handle
) {
806 mono_gchandle_free (thread
->abort_state_handle
);
807 thread
->abort_state_handle
= 0;
810 thread
->abort_exc
= NULL
;
811 thread
->current_appcontext
= NULL
;
814 * thread->synch_cs can be NULL if this was called after
815 * ves_icall_System_Threading_InternalThread_Thread_free_internal.
816 * This can happen only during shutdown.
817 * The shutting_down flag is not always set, so we can't assert on it.
819 if (thread
->synch_cs
)
820 LOCK_THREAD (thread
);
822 thread
->state
|= ThreadState_Stopped
;
823 thread
->state
&= ~ThreadState_Background
;
825 if (thread
->synch_cs
)
826 UNLOCK_THREAD (thread
);
829 An interruption request has leaked to cleanup. Adjust the global counter.
831 This can happen is the abort source thread finds the abortee (this) thread
832 in unmanaged code. If this thread never trips back to managed code or check
833 the local flag it will be left set and positively unbalance the global counter.
835 Leaving the counter unbalanced will cause a performance degradation since all threads
836 will now keep checking their local flags all the time.
838 mono_thread_clear_interruption_requested (thread
);
840 mono_threads_lock ();
844 if (!mono_g_hash_table_lookup_extended (threads
, (gpointer
)thread
->tid
, NULL
, (gpointer
*) &value
)) {
845 g_error ("%s: thread %p (tid: %p) should not have been removed yet from threads", __func__
, thread
, thread
->tid
);
846 } else if (thread
!= value
) {
847 /* We have to check whether the thread object for the tid is still the same in the table because the
848 * thread might have been destroyed and the tid reused in the meantime, in which case the tid would be in
849 * the table, but with another thread object. */
850 g_error ("%s: thread %p (tid: %p) do not match with value %p (tid: %p)", __func__
, thread
, thread
->tid
, value
, value
->tid
);
853 removed
= mono_g_hash_table_remove (threads
, (gpointer
)thread
->tid
);
856 mono_threads_unlock ();
858 /* Don't close the handle here, wait for the object finalizer
859 * to do it. Otherwise, the following race condition applies:
861 * 1) Thread exits (and mono_thread_detach_internal() closes the handle)
863 * 2) Some other handle is reassigned the same slot
865 * 3) Another thread tries to join the first thread, and
866 * blocks waiting for the reassigned handle to be signalled
867 * (which might never happen). This is possible, because the
868 * thread calling Join() still has a reference to the first
872 mono_release_type_locks (thread
);
874 MONO_PROFILER_RAISE (thread_stopped
, (thread
->tid
));
875 MONO_PROFILER_RAISE (gc_root_unregister
, (info
->stack_start_limit
));
876 MONO_PROFILER_RAISE (gc_root_unregister
, (info
->handle_stack
));
879 * This will signal async signal handlers that the thread has exited.
880 * The profiler callback needs this to be set, so it cannot be done earlier.
882 mono_domain_unset ();
883 mono_memory_barrier ();
885 mono_thread_pop_appdomain_ref ();
887 mono_free_static_data (thread
->static_data
);
888 thread
->static_data
= NULL
;
889 ref_stack_destroy (thread
->appdomain_refs
);
890 thread
->appdomain_refs
= NULL
;
892 g_assert (thread
->suspended
);
893 mono_os_event_destroy (thread
->suspended
);
894 g_free (thread
->suspended
);
895 thread
->suspended
= NULL
;
897 if (mono_thread_cleanup_fn
)
898 mono_thread_cleanup_fn (thread_get_tid (thread
));
900 mono_memory_barrier ();
902 if (mono_gc_is_moving ()) {
903 MONO_GC_UNREGISTER_ROOT (thread
->thread_pinning_ref
);
904 thread
->thread_pinning_ref
= NULL
;
907 /* There is no more any guarantee that `thread` is alive */
908 mono_memory_barrier ();
910 SET_CURRENT_OBJECT (NULL
);
911 mono_domain_unset ();
913 if (!mono_thread_info_try_get_internal_thread_gchandle (info
, &gchandle
))
914 g_error ("%s: failed to get gchandle, info = %p", __func__
, info
);
916 mono_gchandle_free (gchandle
);
918 mono_thread_info_unset_internal_thread_gchandle (info
);
920 MONO_PROFILER_RAISE (thread_exited
, (thread
->tid
));
922 /* Don't need to close the handle to this thread, even though we took a
923 * reference in mono_thread_attach (), because the GC will do it
924 * when the Thread object is finalised.
931 MonoObject
*start_delegate
;
932 MonoObject
*start_delegate_arg
;
933 MonoThreadStart start_func
;
934 gpointer start_func_arg
;
935 gboolean force_attach
;
937 MonoCoopSem registered
;
941 fire_attach_profiler_events (MonoNativeThreadId tid
)
943 MONO_PROFILER_RAISE (thread_started
, ((uintptr_t) tid
));
945 MonoThreadInfo
*info
= mono_thread_info_current ();
947 MONO_PROFILER_RAISE (gc_root_register
, (
948 info
->stack_start_limit
,
949 (char *) info
->stack_end
- (char *) info
->stack_start_limit
,
950 MONO_ROOT_SOURCE_STACK
,
954 // The handle stack is a pseudo-root similar to the finalizer queues.
955 MONO_PROFILER_RAISE (gc_root_register
, (
958 MONO_ROOT_SOURCE_HANDLE
,
963 static guint32 WINAPI
start_wrapper_internal(StartInfo
*start_info
, gsize
*stack_ptr
)
966 MonoThreadStart start_func
;
967 void *start_func_arg
;
970 * We don't create a local to hold start_info->thread, so hopefully it won't get pinned during a
974 MonoInternalThread
*internal
;
975 MonoObject
*start_delegate
;
976 MonoObject
*start_delegate_arg
;
979 thread
= start_info
->thread
;
980 internal
= thread
->internal_thread
;
981 domain
= mono_object_domain (start_info
->thread
);
983 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT
") Start wrapper", __func__
, mono_native_thread_id_get ()));
985 if (!mono_thread_attach_internal (thread
, start_info
->force_attach
, FALSE
)) {
986 start_info
->failed
= TRUE
;
988 mono_coop_sem_post (&start_info
->registered
);
990 if (mono_atomic_dec_i32 (&start_info
->ref
) == 0) {
991 mono_coop_sem_destroy (&start_info
->registered
);
998 mono_thread_internal_set_priority (internal
, internal
->priority
);
1000 tid
= internal
->tid
;
1002 start_delegate
= start_info
->start_delegate
;
1003 start_delegate_arg
= start_info
->start_delegate_arg
;
1004 start_func
= start_info
->start_func
;
1005 start_func_arg
= start_info
->start_func_arg
;
1007 /* This MUST be called before any managed code can be
1008 * executed, as it calls the callback function that (for the
1009 * jit) sets the lmf marker.
1012 if (mono_thread_start_cb
)
1013 mono_thread_start_cb (tid
, stack_ptr
, start_func
);
1015 /* On 2.0 profile (and higher), set explicitly since state might have been
1017 if (internal
->apartment_state
== ThreadApartmentState_Unknown
)
1018 internal
->apartment_state
= ThreadApartmentState_MTA
;
1020 mono_thread_init_apartment_state ();
1022 /* Let the thread that called Start() know we're ready */
1023 mono_coop_sem_post (&start_info
->registered
);
1025 if (mono_atomic_dec_i32 (&start_info
->ref
) == 0) {
1026 mono_coop_sem_destroy (&start_info
->registered
);
1027 g_free (start_info
);
1030 /* start_info is not valid anymore */
1034 * Call this after calling start_notify, since the profiler callback might want
1035 * to lock the thread, and the lock is held by thread_start () which waits for
1038 fire_attach_profiler_events ((MonoNativeThreadId
) tid
);
1040 /* if the name was set before starting, we didn't invoke the profiler callback */
1041 if (internal
->name
) {
1042 char *tname
= g_utf16_to_utf8 (internal
->name
, internal
->name_len
, NULL
, NULL
, NULL
);
1043 MONO_PROFILER_RAISE (thread_name
, (internal
->tid
, tname
));
1044 mono_native_thread_set_name (MONO_UINT_TO_NATIVE_THREAD_ID (internal
->tid
), tname
);
1048 /* start_func is set only for unmanaged start functions */
1050 start_func (start_func_arg
);
1054 g_assert (start_delegate
!= NULL
);
1056 /* we may want to handle the exception here. See comment below on unhandled exceptions */
1057 args
[0] = (gpointer
) start_delegate_arg
;
1058 mono_runtime_delegate_invoke_checked (start_delegate
, args
, error
);
1060 if (!mono_error_ok (error
)) {
1061 MonoException
*ex
= mono_error_convert_to_exception (error
);
1063 g_assert (ex
!= NULL
);
1064 MonoClass
*klass
= mono_object_get_class (&ex
->object
);
1065 if ((mono_runtime_unhandled_exception_policy_get () != MONO_UNHANDLED_POLICY_LEGACY
) &&
1066 !is_threadabort_exception (klass
)) {
1067 mono_unhandled_exception (&ex
->object
);
1068 mono_invoke_unhandled_exception_hook (&ex
->object
);
1069 g_assert_not_reached ();
1072 mono_error_cleanup (error
);
1076 /* If the thread calls ExitThread at all, this remaining code
1077 * will not be executed, but the main thread will eventually
1078 * call mono_thread_detach_internal() on this thread's behalf.
1081 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT
") Start wrapper terminating", __func__
, mono_native_thread_id_get ()));
1083 /* Do any cleanup needed for apartment state. This
1084 * cannot be done in mono_thread_detach_internal since
1085 * mono_thread_detach_internal could be called for a
1086 * thread other than the current thread.
1087 * mono_thread_cleanup_apartment_state cleans up apartment
1088 * for the current thead */
1089 mono_thread_cleanup_apartment_state ();
1091 mono_thread_detach_internal (internal
);
1097 start_wrapper (gpointer data
)
1099 StartInfo
*start_info
;
1100 MonoThreadInfo
*info
;
1103 start_info
= (StartInfo
*) data
;
1104 g_assert (start_info
);
1106 info
= mono_thread_info_attach ();
1107 info
->runtime_thread
= TRUE
;
1109 /* Run the actual main function of the thread */
1110 res
= start_wrapper_internal (start_info
, info
->stack_end
);
1112 mono_thread_info_exit (res
);
1114 g_assert_not_reached ();
1120 * Common thread creation code.
1121 * LOCKING: Acquires the threads lock.
1124 create_thread (MonoThread
*thread
, MonoInternalThread
*internal
, MonoObject
*start_delegate
, MonoThreadStart start_func
, gpointer start_func_arg
,
1125 MonoThreadCreateFlags flags
, MonoError
*error
)
1127 StartInfo
*start_info
= NULL
;
1128 MonoNativeThreadId tid
;
1130 gsize stack_set_size
;
1133 g_assert (!start_func
&& !start_func_arg
);
1135 g_assert (!start_delegate
);
1137 if (flags
& MONO_THREAD_CREATE_FLAGS_THREADPOOL
) {
1138 g_assert (!(flags
& MONO_THREAD_CREATE_FLAGS_DEBUGGER
));
1139 g_assert (!(flags
& MONO_THREAD_CREATE_FLAGS_FORCE_CREATE
));
1141 if (flags
& MONO_THREAD_CREATE_FLAGS_DEBUGGER
) {
1142 g_assert (!(flags
& MONO_THREAD_CREATE_FLAGS_THREADPOOL
));
1143 g_assert (!(flags
& MONO_THREAD_CREATE_FLAGS_FORCE_CREATE
));
1147 * Join joinable threads to prevent running out of threads since the finalizer
1148 * thread might be blocked/backlogged.
1150 mono_threads_join_threads ();
1154 mono_threads_lock ();
1155 if (shutting_down
&& !(flags
& MONO_THREAD_CREATE_FLAGS_FORCE_CREATE
)) {
1156 mono_threads_unlock ();
1159 if (threads_starting_up
== NULL
) {
1160 threads_starting_up
= mono_g_hash_table_new_type (NULL
, NULL
, MONO_HASH_KEY_VALUE_GC
, MONO_ROOT_SOURCE_THREADING
, NULL
, "Thread Starting Table");
1162 mono_g_hash_table_insert (threads_starting_up
, thread
, thread
);
1163 mono_threads_unlock ();
1165 internal
->threadpool_thread
= flags
& MONO_THREAD_CREATE_FLAGS_THREADPOOL
;
1166 if (internal
->threadpool_thread
)
1167 mono_thread_set_state (internal
, ThreadState_Background
);
1169 internal
->debugger_thread
= flags
& MONO_THREAD_CREATE_FLAGS_DEBUGGER
;
1171 start_info
= g_new0 (StartInfo
, 1);
1172 start_info
->ref
= 2;
1173 start_info
->thread
= thread
;
1174 start_info
->start_delegate
= start_delegate
;
1175 start_info
->start_delegate_arg
= thread
->start_obj
;
1176 start_info
->start_func
= start_func
;
1177 start_info
->start_func_arg
= start_func_arg
;
1178 start_info
->force_attach
= flags
& MONO_THREAD_CREATE_FLAGS_FORCE_CREATE
;
1179 start_info
->failed
= FALSE
;
1180 mono_coop_sem_init (&start_info
->registered
, 0);
1182 if (flags
!= MONO_THREAD_CREATE_FLAGS_SMALL_STACK
)
1183 stack_set_size
= default_stacksize_for_thread (internal
);
1187 if (!mono_thread_platform_create_thread ((MonoThreadStart
)start_wrapper
, start_info
, &stack_set_size
, &tid
)) {
1188 /* The thread couldn't be created, so set an exception */
1189 mono_threads_lock ();
1190 mono_g_hash_table_remove (threads_starting_up
, thread
);
1191 mono_threads_unlock ();
1192 mono_error_set_execution_engine (error
, "Couldn't create thread. Error 0x%x", mono_w32error_get_last());
1193 /* ref is not going to be decremented in start_wrapper_internal */
1194 mono_atomic_dec_i32 (&start_info
->ref
);
1199 internal
->stack_size
= (int) stack_set_size
;
1201 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT
") Launching thread %p (%"G_GSIZE_FORMAT
")", __func__
, mono_native_thread_id_get (), internal
, (gsize
)internal
->tid
));
1204 * Wait for the thread to set up its TLS data etc, so
1205 * theres no potential race condition if someone tries
1206 * to look up the data believing the thread has
1210 mono_coop_sem_wait (&start_info
->registered
, MONO_SEM_FLAGS_NONE
);
1212 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
));
1214 ret
= !start_info
->failed
;
1217 if (mono_atomic_dec_i32 (&start_info
->ref
) == 0) {
1218 mono_coop_sem_destroy (&start_info
->registered
);
1219 g_free (start_info
);
1226 * mono_thread_new_init:
1229 mono_thread_new_init (intptr_t tid
, gpointer stack_start
, gpointer func
)
1231 if (mono_thread_start_cb
) {
1232 mono_thread_start_cb (tid
, stack_start
, func
);
1237 * mono_threads_set_default_stacksize:
1240 mono_threads_set_default_stacksize (guint32 stacksize
)
1242 default_stacksize
= stacksize
;
1246 * mono_threads_get_default_stacksize:
1249 mono_threads_get_default_stacksize (void)
1251 return default_stacksize
;
1255 * mono_thread_create_internal:
1257 * ARG should not be a GC reference.
1260 mono_thread_create_internal (MonoDomain
*domain
, gpointer func
, gpointer arg
, MonoThreadCreateFlags flags
, MonoError
*error
)
1263 MonoInternalThread
*internal
;
1268 internal
= create_internal_thread_object ();
1270 thread
= create_thread_object (domain
, internal
);
1272 LOCK_THREAD (internal
);
1274 res
= create_thread (thread
, internal
, NULL
, (MonoThreadStart
) func
, arg
, flags
, error
);
1276 UNLOCK_THREAD (internal
);
1278 return_val_if_nok (error
, NULL
);
1283 * mono_thread_create:
1286 mono_thread_create (MonoDomain
*domain
, gpointer func
, gpointer arg
)
1289 if (!mono_thread_create_checked (domain
, func
, arg
, error
))
1290 mono_error_cleanup (error
);
1294 mono_thread_create_checked (MonoDomain
*domain
, gpointer func
, gpointer arg
, MonoError
*error
)
1296 return (NULL
!= mono_thread_create_internal (domain
, func
, arg
, MONO_THREAD_CREATE_FLAGS_NONE
, error
));
1300 * mono_thread_attach:
1303 mono_thread_attach (MonoDomain
*domain
)
1305 MonoInternalThread
*internal
;
1307 MonoThreadInfo
*info
;
1308 MonoNativeThreadId tid
;
1310 if (mono_thread_internal_current_is_attached ()) {
1311 if (domain
!= mono_domain_get ())
1312 mono_domain_set (domain
, TRUE
);
1313 /* Already attached */
1314 return mono_thread_current ();
1317 info
= mono_thread_info_attach ();
1320 tid
=mono_native_thread_id_get ();
1322 internal
= create_internal_thread_object ();
1324 thread
= create_thread_object (domain
, internal
);
1326 if (!mono_thread_attach_internal (thread
, FALSE
, TRUE
)) {
1327 /* Mono is shutting down, so just wait for the end */
1329 mono_thread_info_sleep (10000, NULL
);
1332 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT
" (handle %p)", __func__
, tid
, internal
->handle
));
1334 if (mono_thread_attach_cb
)
1335 mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid
), info
->stack_end
);
1337 fire_attach_profiler_events (tid
);
1343 * mono_thread_detach:
1346 mono_thread_detach (MonoThread
*thread
)
1349 mono_thread_detach_internal (thread
->internal_thread
);
1353 * mono_thread_detach_if_exiting:
1355 * Detach the current thread from the runtime if it is exiting, i.e. it is running pthread dtors.
1356 * This should be used at the end of embedding code which calls into managed code, and which
1357 * can be called from pthread dtors, like <code>dealloc:</code> implementations in Objective-C.
1360 mono_thread_detach_if_exiting (void)
1362 if (mono_thread_info_is_exiting ()) {
1363 MonoInternalThread
*thread
;
1365 thread
= mono_thread_internal_current ();
1367 mono_thread_detach_internal (thread
);
1368 mono_thread_info_detach ();
1376 mono_thread_internal_current_is_attached (void)
1378 MonoInternalThread
*internal
;
1380 internal
= GET_CURRENT_OBJECT ();
1391 mono_thread_exit (void)
1393 MonoInternalThread
*thread
= mono_thread_internal_current ();
1395 THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT
")", __func__
, thread
, (gsize
)thread
->tid
));
1397 mono_thread_detach_internal (thread
);
1399 /* we could add a callback here for embedders to use. */
1400 if (mono_thread_get_main () && (thread
== mono_thread_get_main ()->internal_thread
))
1401 exit (mono_environment_exitcode_get ());
1403 mono_thread_info_exit (0);
1407 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread
*this_obj
)
1409 MonoInternalThread
*internal
;
1411 internal
= create_internal_thread_object ();
1413 internal
->state
= ThreadState_Unstarted
;
1415 mono_atomic_cas_ptr ((volatile gpointer
*)&this_obj
->internal_thread
, internal
, NULL
);
1418 MonoThreadObjectHandle
1419 ves_icall_System_Threading_Thread_GetCurrentThread (MonoError
*error
)
1421 return MONO_HANDLE_NEW (MonoThreadObject
, mono_thread_current ());
1425 ves_icall_System_Threading_Thread_Thread_internal (MonoThread
*this_obj
,
1429 MonoInternalThread
*internal
;
1432 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__
, this_obj
, start
));
1434 if (!this_obj
->internal_thread
)
1435 ves_icall_System_Threading_Thread_ConstructInternalThread (this_obj
);
1436 internal
= this_obj
->internal_thread
;
1438 LOCK_THREAD (internal
);
1440 if ((internal
->state
& ThreadState_Unstarted
) == 0) {
1441 UNLOCK_THREAD (internal
);
1442 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has already been started."));
1446 if ((internal
->state
& ThreadState_Aborted
) != 0) {
1447 UNLOCK_THREAD (internal
);
1451 res
= create_thread (this_obj
, internal
, start
, NULL
, NULL
, MONO_THREAD_CREATE_FLAGS_NONE
, error
);
1453 mono_error_cleanup (error
);
1454 UNLOCK_THREAD (internal
);
1458 internal
->state
&= ~ThreadState_Unstarted
;
1460 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT
" (handle %p)", __func__
, tid
, thread
));
1462 UNLOCK_THREAD (internal
);
1463 return internal
->handle
;
1467 * This is called from the finalizer of the internal thread object.
1470 ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread
*this_obj
)
1472 THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__
, this, this_obj
->handle
));
1475 * Since threads keep a reference to their thread object while running, by
1476 * the time this function is called, the thread has already exited/detached,
1477 * i.e. mono_thread_detach_internal () has ran. The exception is during
1478 * shutdown, when mono_thread_detach_internal () can be called after this.
1480 if (this_obj
->handle
) {
1481 mono_threads_close_thread_handle (this_obj
->handle
);
1482 this_obj
->handle
= NULL
;
1486 CloseHandle (this_obj
->native_handle
);
1489 if (this_obj
->synch_cs
) {
1490 MonoCoopMutex
*synch_cs
= this_obj
->synch_cs
;
1491 this_obj
->synch_cs
= NULL
;
1492 mono_coop_mutex_destroy (synch_cs
);
1496 if (this_obj
->name
) {
1497 void *name
= this_obj
->name
;
1498 this_obj
->name
= NULL
;
1504 ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms
)
1507 MonoInternalThread
*thread
= mono_thread_internal_current ();
1509 THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__
, ms
));
1511 if (mono_thread_current_check_pending_interrupt ())
1515 gboolean alerted
= FALSE
;
1517 mono_thread_set_state (thread
, ThreadState_WaitSleepJoin
);
1519 res
= mono_thread_info_sleep (ms
, &alerted
);
1521 mono_thread_clr_state (thread
, ThreadState_WaitSleepJoin
);
1524 MonoException
* exc
= mono_thread_execute_interruption ();
1526 mono_set_pending_exception (exc
);
1529 // FIXME: !MONO_INFINITE_WAIT
1530 if (ms
!= MONO_INFINITE_WAIT
)
1539 void ves_icall_System_Threading_Thread_SpinWait_nop (void)
1544 ves_icall_System_Threading_Thread_GetDomainID (void)
1546 return mono_domain_get()->domain_id
;
1550 ves_icall_System_Threading_Thread_Yield (void)
1552 return mono_thread_info_yield ();
1556 * mono_thread_get_name:
1558 * Return the name of the thread. NAME_LEN is set to the length of the name.
1559 * Return NULL if the thread has no name. The returned memory is owned by the
1563 mono_thread_get_name (MonoInternalThread
*this_obj
, guint32
*name_len
)
1567 LOCK_THREAD (this_obj
);
1569 if (!this_obj
->name
) {
1573 *name_len
= this_obj
->name_len
;
1574 res
= g_new (gunichar2
, this_obj
->name_len
);
1575 memcpy (res
, this_obj
->name
, sizeof (gunichar2
) * this_obj
->name_len
);
1578 UNLOCK_THREAD (this_obj
);
1584 * mono_thread_get_name_utf8:
1585 * \returns the name of the thread in UTF-8.
1586 * Return NULL if the thread has no name.
1587 * The returned memory is owned by the caller.
1590 mono_thread_get_name_utf8 (MonoThread
*thread
)
1595 MonoInternalThread
*internal
= thread
->internal_thread
;
1596 if (internal
== NULL
)
1599 LOCK_THREAD (internal
);
1601 char *tname
= g_utf16_to_utf8 (internal
->name
, internal
->name_len
, NULL
, NULL
, NULL
);
1603 UNLOCK_THREAD (internal
);
1609 * mono_thread_get_managed_id:
1610 * \returns the \c Thread.ManagedThreadId value of \p thread.
1611 * Returns \c -1 if \p thread is NULL.
1614 mono_thread_get_managed_id (MonoThread
*thread
)
1619 MonoInternalThread
*internal
= thread
->internal_thread
;
1620 if (internal
== NULL
)
1623 int32_t id
= internal
->managed_id
;
1629 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread
*this_obj
)
1636 LOCK_THREAD (this_obj
);
1638 if (!this_obj
->name
)
1641 str
= mono_string_new_utf16_checked (mono_domain_get (), this_obj
->name
, this_obj
->name_len
, error
);
1643 UNLOCK_THREAD (this_obj
);
1645 if (mono_error_set_pending_exception (error
))
1652 mono_thread_set_name_internal (MonoInternalThread
*this_obj
, MonoString
*name
, gboolean permanent
, gboolean reset
, MonoError
*error
)
1654 MonoNativeThreadId tid
= 0;
1656 LOCK_THREAD (this_obj
);
1661 this_obj
->flags
&= ~MONO_THREAD_FLAG_NAME_SET
;
1662 } else if (this_obj
->flags
& MONO_THREAD_FLAG_NAME_SET
) {
1663 UNLOCK_THREAD (this_obj
);
1665 mono_error_set_invalid_operation (error
, "Thread.Name can only be set once.");
1668 if (this_obj
->name
) {
1669 g_free (this_obj
->name
);
1670 this_obj
->name_len
= 0;
1673 this_obj
->name
= g_memdup (mono_string_chars (name
), mono_string_length (name
) * sizeof (gunichar2
));
1674 this_obj
->name_len
= mono_string_length (name
);
1677 this_obj
->flags
|= MONO_THREAD_FLAG_NAME_SET
;
1680 this_obj
->name
= NULL
;
1682 if (!(this_obj
->state
& ThreadState_Stopped
))
1683 tid
= thread_get_tid (this_obj
);
1685 UNLOCK_THREAD (this_obj
);
1687 if (this_obj
->name
&& tid
) {
1688 char *tname
= mono_string_to_utf8_checked (name
, error
);
1689 return_if_nok (error
);
1690 MONO_PROFILER_RAISE (thread_name
, ((uintptr_t)tid
, tname
));
1691 mono_native_thread_set_name (tid
, tname
);
1697 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread
*this_obj
, MonoString
*name
)
1700 mono_thread_set_name_internal (this_obj
, name
, TRUE
, FALSE
, error
);
1701 mono_error_set_pending_exception (error
);
1705 * ves_icall_System_Threading_Thread_GetPriority_internal:
1706 * @param this_obj: The MonoInternalThread on which to operate.
1708 * Gets the priority of the given thread.
1709 * @return: The priority of the given thread.
1712 ves_icall_System_Threading_Thread_GetPriority (MonoThreadObjectHandle this_obj
, MonoError
*error
)
1716 // InternalThreads are always pinned.
1717 MonoInternalThread
*internal
= MONO_HANDLE_GETVAL(this_obj
, internal_thread
);
1719 LOCK_THREAD (internal
);
1720 priority
= internal
->priority
;
1721 UNLOCK_THREAD (internal
);
1727 * ves_icall_System_Threading_Thread_SetPriority_internal:
1728 * @param this_obj: The MonoInternalThread on which to operate.
1729 * @param priority: The priority to set.
1731 * Sets the priority of the given thread.
1734 ves_icall_System_Threading_Thread_SetPriority (MonoThreadObjectHandle this_obj
, int priority
, MonoError
*error
)
1736 // InternalThreads are always pinned.
1737 MonoInternalThread
*internal
= MONO_HANDLE_GETVAL(this_obj
, internal_thread
);
1739 LOCK_THREAD (internal
);
1740 internal
->priority
= priority
;
1741 if (internal
->thread_info
!= NULL
)
1742 mono_thread_internal_set_priority (internal
, priority
);
1743 UNLOCK_THREAD (internal
);
1746 /* If the array is already in the requested domain, we just return it,
1747 otherwise we return a copy in that domain. */
1749 byte_array_to_domain (MonoArray
*arr
, MonoDomain
*domain
, MonoError
*error
)
1757 if (mono_object_domain (arr
) == domain
)
1760 copy
= mono_array_new_checked (domain
, mono_defaults
.byte_class
, arr
->max_length
, error
);
1761 memmove (mono_array_addr (copy
, guint8
, 0), mono_array_addr (arr
, guint8
, 0), arr
->max_length
);
1766 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray
*arr
)
1769 MonoArray
*result
= byte_array_to_domain (arr
, mono_get_root_domain (), error
);
1770 mono_error_set_pending_exception (error
);
1775 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray
*arr
)
1778 MonoArray
*result
= byte_array_to_domain (arr
, mono_domain_get (), error
);
1779 mono_error_set_pending_exception (error
);
1784 * mono_thread_current:
1787 mono_thread_current (void)
1789 MonoDomain
*domain
= mono_domain_get ();
1790 MonoInternalThread
*internal
= mono_thread_internal_current ();
1791 MonoThread
**current_thread_ptr
;
1793 g_assert (internal
);
1794 current_thread_ptr
= get_current_thread_ptr_for_domain (domain
, internal
);
1796 if (!*current_thread_ptr
) {
1797 g_assert (domain
!= mono_get_root_domain ());
1798 *current_thread_ptr
= create_thread_object (domain
, internal
);
1800 return *current_thread_ptr
;
1803 /* Return the thread object belonging to INTERNAL in the current domain */
1805 mono_thread_current_for_thread (MonoInternalThread
*internal
)
1807 MonoDomain
*domain
= mono_domain_get ();
1808 MonoThread
**current_thread_ptr
;
1810 g_assert (internal
);
1811 current_thread_ptr
= get_current_thread_ptr_for_domain (domain
, internal
);
1813 if (!*current_thread_ptr
) {
1814 g_assert (domain
!= mono_get_root_domain ());
1815 *current_thread_ptr
= create_thread_object (domain
, internal
);
1817 return *current_thread_ptr
;
1821 mono_thread_internal_current (void)
1823 MonoInternalThread
*res
= GET_CURRENT_OBJECT ();
1824 THREAD_DEBUG (g_message ("%s: returning %p", __func__
, res
));
1828 static MonoThreadInfoWaitRet
1829 mono_join_uninterrupted (MonoThreadHandle
* thread_to_join
, gint32 ms
, MonoError
*error
)
1832 MonoThreadInfoWaitRet ret
;
1839 start
= (ms
== -1) ? 0 : mono_msec_ticks ();
1842 ret
= mono_thread_info_wait_one_handle (thread_to_join
, ms
, TRUE
);
1845 if (ret
!= MONO_THREAD_INFO_WAIT_RET_ALERTED
)
1848 exc
= mono_thread_execute_interruption ();
1850 mono_error_set_exception_instance (error
, exc
);
1857 /* Re-calculate ms according to the time passed */
1858 diff_ms
= (gint32
)(mono_msec_ticks () - start
);
1859 if (diff_ms
>= ms
) {
1860 ret
= MONO_THREAD_INFO_WAIT_RET_TIMEOUT
;
1863 wait
= ms
- diff_ms
;
1870 ves_icall_System_Threading_Thread_Join_internal (MonoThread
*this_obj
, int ms
)
1872 MonoInternalThread
*thread
= this_obj
->internal_thread
;
1873 MonoThreadHandle
*handle
= thread
->handle
;
1874 MonoInternalThread
*cur_thread
= mono_thread_internal_current ();
1878 if (mono_thread_current_check_pending_interrupt ())
1881 LOCK_THREAD (thread
);
1883 if ((thread
->state
& ThreadState_Unstarted
) != 0) {
1884 UNLOCK_THREAD (thread
);
1886 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started."));
1890 UNLOCK_THREAD (thread
);
1893 ms
= MONO_INFINITE_WAIT
;
1894 THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__
, handle
, ms
));
1896 mono_thread_set_state (cur_thread
, ThreadState_WaitSleepJoin
);
1898 ret
= mono_join_uninterrupted (handle
, ms
, error
);
1900 mono_thread_clr_state (cur_thread
, ThreadState_WaitSleepJoin
);
1902 mono_error_set_pending_exception (error
);
1904 if (ret
== MONO_THREAD_INFO_WAIT_RET_SUCCESS_0
) {
1905 THREAD_DEBUG (g_message ("%s: join successful", __func__
));
1907 /* Wait for the thread to really exit */
1908 MonoNativeThreadId tid
= thread_get_tid (thread
);
1909 mono_thread_join (tid
);
1914 THREAD_DEBUG (g_message ("%s: join failed", __func__
));
1919 #define MANAGED_WAIT_FAILED 0x7fffffff
1922 map_native_wait_result_to_managed (MonoW32HandleWaitRet val
, gsize numobjects
)
1924 if (val
>= MONO_W32HANDLE_WAIT_RET_SUCCESS_0
&& val
< MONO_W32HANDLE_WAIT_RET_SUCCESS_0
+ numobjects
) {
1925 return WAIT_OBJECT_0
+ (val
- MONO_W32HANDLE_WAIT_RET_SUCCESS_0
);
1926 } else if (val
>= MONO_W32HANDLE_WAIT_RET_ABANDONED_0
&& val
< MONO_W32HANDLE_WAIT_RET_ABANDONED_0
+ numobjects
) {
1927 return WAIT_ABANDONED_0
+ (val
- MONO_W32HANDLE_WAIT_RET_ABANDONED_0
);
1928 } else if (val
== MONO_W32HANDLE_WAIT_RET_ALERTED
) {
1929 return WAIT_IO_COMPLETION
;
1930 } else if (val
== MONO_W32HANDLE_WAIT_RET_TIMEOUT
) {
1931 return WAIT_TIMEOUT
;
1932 } else if (val
== MONO_W32HANDLE_WAIT_RET_FAILED
) {
1933 /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1934 return MANAGED_WAIT_FAILED
;
1936 g_error ("%s: unknown val value %d", __func__
, val
);
1941 ves_icall_System_Threading_WaitHandle_Wait_internal (gpointer
*handles
, gint32 numhandles
, MonoBoolean waitall
, gint32 timeout
, MonoError
*error
)
1943 MonoW32HandleWaitRet ret
;
1944 MonoInternalThread
*thread
;
1947 guint32 timeoutLeft
;
1949 /* Do this WaitSleepJoin check before creating objects */
1950 if (mono_thread_current_check_pending_interrupt ())
1951 return map_native_wait_result_to_managed (MONO_W32HANDLE_WAIT_RET_FAILED
, 0);
1953 thread
= mono_thread_internal_current ();
1955 mono_thread_set_state (thread
, ThreadState_WaitSleepJoin
);
1958 timeout
= MONO_INFINITE_WAIT
;
1959 if (timeout
!= MONO_INFINITE_WAIT
)
1960 start
= mono_msec_ticks ();
1962 timeoutLeft
= timeout
;
1967 if (numhandles
!= 1)
1968 ret
= mono_w32handle_convert_wait_ret (mono_win32_wait_for_multiple_objects_ex(numhandles
, handles
, waitall
, timeoutLeft
, TRUE
), numhandles
);
1970 ret
= mono_w32handle_convert_wait_ret (mono_win32_wait_for_single_object_ex (handles
[0], timeoutLeft
, TRUE
), 1);
1973 /* mono_w32handle_wait_multiple optimizes the case for numhandles == 1 */
1974 ret
= mono_w32handle_wait_multiple (handles
, numhandles
, waitall
, timeoutLeft
, TRUE
);
1975 #endif /* HOST_WIN32 */
1977 if (ret
!= MONO_W32HANDLE_WAIT_RET_ALERTED
)
1980 exc
= mono_thread_execute_interruption ();
1982 mono_error_set_exception_instance (error
, exc
);
1986 if (timeout
!= MONO_INFINITE_WAIT
) {
1989 elapsed
= mono_msec_ticks () - start
;
1990 if (elapsed
>= timeout
) {
1991 ret
= MONO_W32HANDLE_WAIT_RET_TIMEOUT
;
1995 timeoutLeft
= timeout
- elapsed
;
1999 mono_thread_clr_state (thread
, ThreadState_WaitSleepJoin
);
2001 return map_native_wait_result_to_managed (ret
, numhandles
);
2005 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (gpointer toSignal
, gpointer toWait
, gint32 ms
, MonoError
*error
)
2007 MonoW32HandleWaitRet ret
;
2008 MonoInternalThread
*thread
= mono_thread_internal_current ();
2011 ms
= MONO_INFINITE_WAIT
;
2013 if (mono_thread_current_check_pending_interrupt ())
2014 return map_native_wait_result_to_managed (MONO_W32HANDLE_WAIT_RET_FAILED
, 0);
2016 mono_thread_set_state (thread
, ThreadState_WaitSleepJoin
);
2020 ret
= mono_w32handle_convert_wait_ret (mono_win32_signal_object_and_wait (toSignal
, toWait
, ms
, TRUE
), 1);
2022 ret
= mono_w32handle_signal_and_wait (toSignal
, toWait
, ms
, TRUE
);
2026 mono_thread_clr_state (thread
, ThreadState_WaitSleepJoin
);
2028 return map_native_wait_result_to_managed (ret
, 1);
2031 gint32
ves_icall_System_Threading_Interlocked_Increment_Int (gint32
*location
)
2033 return mono_atomic_inc_i32 (location
);
2036 gint64
ves_icall_System_Threading_Interlocked_Increment_Long (gint64
*location
)
2038 #if SIZEOF_VOID_P == 4
2039 if (G_UNLIKELY ((size_t)location
& 0x7)) {
2041 mono_interlocked_lock ();
2044 mono_interlocked_unlock ();
2048 return mono_atomic_inc_i64 (location
);
2051 gint32
ves_icall_System_Threading_Interlocked_Decrement_Int (gint32
*location
)
2053 return mono_atomic_dec_i32(location
);
2056 gint64
ves_icall_System_Threading_Interlocked_Decrement_Long (gint64
* location
)
2058 #if SIZEOF_VOID_P == 4
2059 if (G_UNLIKELY ((size_t)location
& 0x7)) {
2061 mono_interlocked_lock ();
2064 mono_interlocked_unlock ();
2068 return mono_atomic_dec_i64 (location
);
2071 gint32
ves_icall_System_Threading_Interlocked_Exchange_Int (gint32
*location
, gint32 value
)
2073 return mono_atomic_xchg_i32(location
, value
);
2076 MonoObject
* ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject
**location
, MonoObject
*value
)
2079 res
= (MonoObject
*) mono_atomic_xchg_ptr((gpointer
*) location
, value
);
2080 mono_gc_wbarrier_generic_nostore (location
);
2084 gpointer
ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer
*location
, gpointer value
)
2086 return mono_atomic_xchg_ptr(location
, value
);
2089 gfloat
ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat
*location
, gfloat value
)
2091 IntFloatUnion val
, ret
;
2094 ret
.ival
= mono_atomic_xchg_i32((gint32
*) location
, val
.ival
);
2100 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64
*location
, gint64 value
)
2102 #if SIZEOF_VOID_P == 4
2103 if (G_UNLIKELY ((size_t)location
& 0x7)) {
2105 mono_interlocked_lock ();
2108 mono_interlocked_unlock ();
2112 return mono_atomic_xchg_i64 (location
, value
);
2116 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble
*location
, gdouble value
)
2118 LongDoubleUnion val
, ret
;
2121 ret
.ival
= (gint64
)mono_atomic_xchg_i64((gint64
*) location
, val
.ival
);
2126 gint32
ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32
*location
, gint32 value
, gint32 comparand
)
2128 return mono_atomic_cas_i32(location
, value
, comparand
);
2131 gint32
ves_icall_System_Threading_Interlocked_CompareExchange_Int_Success(gint32
*location
, gint32 value
, gint32 comparand
, MonoBoolean
*success
)
2133 gint32 r
= mono_atomic_cas_i32(location
, value
, comparand
);
2134 *success
= r
== comparand
;
2138 MonoObject
* ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject
**location
, MonoObject
*value
, MonoObject
*comparand
)
2141 res
= (MonoObject
*) mono_atomic_cas_ptr((gpointer
*) location
, value
, comparand
);
2142 mono_gc_wbarrier_generic_nostore (location
);
2146 gpointer
ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer
*location
, gpointer value
, gpointer comparand
)
2148 return mono_atomic_cas_ptr(location
, value
, comparand
);
2151 gfloat
ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat
*location
, gfloat value
, gfloat comparand
)
2153 IntFloatUnion val
, ret
, cmp
;
2156 cmp
.fval
= comparand
;
2157 ret
.ival
= mono_atomic_cas_i32((gint32
*) location
, val
.ival
, cmp
.ival
);
2163 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble
*location
, gdouble value
, gdouble comparand
)
2165 #if SIZEOF_VOID_P == 8
2166 LongDoubleUnion val
, comp
, ret
;
2169 comp
.fval
= comparand
;
2170 ret
.ival
= (gint64
)mono_atomic_cas_ptr((gpointer
*) location
, (gpointer
)val
.ival
, (gpointer
)comp
.ival
);
2176 mono_interlocked_lock ();
2178 if (old
== comparand
)
2180 mono_interlocked_unlock ();
2187 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64
*location
, gint64 value
, gint64 comparand
)
2189 #if SIZEOF_VOID_P == 4
2190 if (G_UNLIKELY ((size_t)location
& 0x7)) {
2192 mono_interlocked_lock ();
2194 if (old
== comparand
)
2196 mono_interlocked_unlock ();
2200 return mono_atomic_cas_i64 (location
, value
, comparand
);
2204 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject
**location
, MonoObject
*value
, MonoObject
*comparand
)
2207 res
= (MonoObject
*)mono_atomic_cas_ptr ((volatile gpointer
*)location
, value
, comparand
);
2208 mono_gc_wbarrier_generic_nostore (location
);
2213 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject
**location
, MonoObject
*value
)
2216 MONO_CHECK_NULL (location
, NULL
);
2217 res
= (MonoObject
*)mono_atomic_xchg_ptr ((volatile gpointer
*)location
, value
);
2218 mono_gc_wbarrier_generic_nostore (location
);
2223 ves_icall_System_Threading_Interlocked_Add_Int (gint32
*location
, gint32 value
)
2225 return mono_atomic_add_i32 (location
, value
);
2229 ves_icall_System_Threading_Interlocked_Add_Long (gint64
*location
, gint64 value
)
2231 #if SIZEOF_VOID_P == 4
2232 if (G_UNLIKELY ((size_t)location
& 0x7)) {
2234 mono_interlocked_lock ();
2237 mono_interlocked_unlock ();
2241 return mono_atomic_add_i64 (location
, value
);
2245 ves_icall_System_Threading_Interlocked_Read_Long (gint64
*location
)
2247 #if SIZEOF_VOID_P == 4
2248 if (G_UNLIKELY ((size_t)location
& 0x7)) {
2250 mono_interlocked_lock ();
2252 mono_interlocked_unlock ();
2256 return mono_atomic_load_i64 (location
);
2260 ves_icall_System_Threading_Thread_MemoryBarrier (void)
2262 mono_memory_barrier ();
2266 ves_icall_System_Threading_Thread_ClrState (MonoInternalThreadHandle this_obj
, guint32 state
, MonoError
*error
)
2268 // InternalThreads are always pinned, so shallowly coop-handleize.
2269 mono_thread_clr_state (mono_internal_thread_handle_ptr (this_obj
), state
);
2273 ves_icall_System_Threading_Thread_SetState (MonoInternalThreadHandle thread_handle
, guint32 state
, MonoError
*error
)
2275 // InternalThreads are always pinned, so shallowly coop-handleize.
2276 mono_thread_set_state (mono_internal_thread_handle_ptr (thread_handle
), state
);
2280 ves_icall_System_Threading_Thread_GetState (MonoInternalThreadHandle thread_handle
, MonoError
*error
)
2282 // InternalThreads are always pinned, so shallowly coop-handleize.
2283 MonoInternalThread
*this_obj
= mono_internal_thread_handle_ptr (thread_handle
);
2287 LOCK_THREAD (this_obj
);
2289 state
= this_obj
->state
;
2291 UNLOCK_THREAD (this_obj
);
2296 void ves_icall_System_Threading_Thread_Interrupt_internal (MonoThread
*this_obj
)
2298 MonoInternalThread
*current
;
2300 MonoInternalThread
*thread
= this_obj
->internal_thread
;
2302 LOCK_THREAD (thread
);
2304 current
= mono_thread_internal_current ();
2306 thread
->thread_interrupt_requested
= TRUE
;
2307 throw_
= current
!= thread
&& (thread
->state
& ThreadState_WaitSleepJoin
);
2309 UNLOCK_THREAD (thread
);
2312 async_abort_internal (thread
, FALSE
);
2317 * mono_thread_current_check_pending_interrupt:
2318 * Checks if there's a interruption request and set the pending exception if so.
2319 * \returns true if a pending exception was set
2322 mono_thread_current_check_pending_interrupt (void)
2324 MonoInternalThread
*thread
= mono_thread_internal_current ();
2325 gboolean throw_
= FALSE
;
2327 LOCK_THREAD (thread
);
2329 if (thread
->thread_interrupt_requested
) {
2331 thread
->thread_interrupt_requested
= FALSE
;
2334 UNLOCK_THREAD (thread
);
2337 mono_set_pending_exception (mono_get_exception_thread_interrupted ());
2342 request_thread_abort (MonoInternalThread
*thread
, MonoObject
*state
, gboolean appdomain_unload
)
2344 LOCK_THREAD (thread
);
2346 if (thread
->state
& (ThreadState_AbortRequested
| ThreadState_Stopped
))
2348 UNLOCK_THREAD (thread
);
2352 if ((thread
->state
& ThreadState_Unstarted
) != 0) {
2353 thread
->state
|= ThreadState_Aborted
;
2354 UNLOCK_THREAD (thread
);
2358 thread
->state
|= ThreadState_AbortRequested
;
2359 if (appdomain_unload
)
2360 thread
->flags
|= MONO_THREAD_FLAG_APPDOMAIN_ABORT
;
2362 thread
->flags
&= ~MONO_THREAD_FLAG_APPDOMAIN_ABORT
;
2364 if (thread
->abort_state_handle
)
2365 mono_gchandle_free (thread
->abort_state_handle
);
2367 thread
->abort_state_handle
= mono_gchandle_new (state
, FALSE
);
2368 g_assert (thread
->abort_state_handle
);
2370 thread
->abort_state_handle
= 0;
2372 thread
->abort_exc
= NULL
;
2374 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
));
2376 /* During shutdown, we can't wait for other threads */
2378 /* Make sure the thread is awake */
2379 mono_thread_resume (thread
);
2381 UNLOCK_THREAD (thread
);
2386 ves_icall_System_Threading_Thread_Abort (MonoInternalThread
*thread
, MonoObject
*state
)
2388 if (!request_thread_abort (thread
, state
, FALSE
))
2391 if (thread
== mono_thread_internal_current ()) {
2393 self_abort_internal (error
);
2394 mono_error_set_pending_exception (error
);
2396 async_abort_internal (thread
, TRUE
);
2401 * mono_thread_internal_abort:
2402 * Request thread \p thread to be aborted.
2403 * \p thread MUST NOT be the current thread.
2406 mono_thread_internal_abort (MonoInternalThread
*thread
, gboolean appdomain_unload
)
2408 g_assert (thread
!= mono_thread_internal_current ());
2410 if (!request_thread_abort (thread
, NULL
, appdomain_unload
))
2412 async_abort_internal (thread
, TRUE
);
2416 ves_icall_System_Threading_Thread_ResetAbort (MonoThread
*this_obj
)
2418 MonoInternalThread
*thread
= mono_thread_internal_current ();
2419 gboolean was_aborting
, is_domain_abort
;
2421 LOCK_THREAD (thread
);
2422 was_aborting
= thread
->state
& ThreadState_AbortRequested
;
2423 is_domain_abort
= thread
->flags
& MONO_THREAD_FLAG_APPDOMAIN_ABORT
;
2425 if (was_aborting
&& !is_domain_abort
)
2426 thread
->state
&= ~ThreadState_AbortRequested
;
2427 UNLOCK_THREAD (thread
);
2429 if (!was_aborting
) {
2430 const char *msg
= "Unable to reset abort because no abort was requested";
2431 mono_set_pending_exception (mono_get_exception_thread_state (msg
));
2433 } else if (is_domain_abort
) {
2434 /* Silently ignore abort resets in unloading appdomains */
2438 mono_get_eh_callbacks ()->mono_clear_abort_threshold ();
2439 thread
->abort_exc
= NULL
;
2440 if (thread
->abort_state_handle
) {
2441 mono_gchandle_free (thread
->abort_state_handle
);
2442 /* This is actually not necessary - the handle
2443 only counts if the exception is set */
2444 thread
->abort_state_handle
= 0;
2449 mono_thread_internal_reset_abort (MonoInternalThread
*thread
)
2451 LOCK_THREAD (thread
);
2453 thread
->state
&= ~ThreadState_AbortRequested
;
2455 if (thread
->abort_exc
) {
2456 mono_get_eh_callbacks ()->mono_clear_abort_threshold ();
2457 thread
->abort_exc
= NULL
;
2458 if (thread
->abort_state_handle
) {
2459 mono_gchandle_free (thread
->abort_state_handle
);
2460 /* This is actually not necessary - the handle
2461 only counts if the exception is set */
2462 thread
->abort_state_handle
= 0;
2466 UNLOCK_THREAD (thread
);
2470 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread
*this_obj
)
2473 MonoInternalThread
*thread
= this_obj
->internal_thread
;
2474 MonoObject
*state
, *deserialized
= NULL
;
2477 if (!thread
->abort_state_handle
)
2480 state
= mono_gchandle_get_target (thread
->abort_state_handle
);
2483 domain
= mono_domain_get ();
2484 if (mono_object_domain (state
) == domain
)
2487 deserialized
= mono_object_xdomain_representation (state
, domain
, error
);
2489 if (!deserialized
) {
2490 MonoException
*invalid_op_exc
= mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
2491 if (!is_ok (error
)) {
2492 MonoObject
*exc
= (MonoObject
*)mono_error_convert_to_exception (error
);
2493 MONO_OBJECT_SETREF (invalid_op_exc
, inner_ex
, exc
);
2495 mono_set_pending_exception (invalid_op_exc
);
2499 return deserialized
;
2503 mono_thread_suspend (MonoInternalThread
*thread
)
2505 LOCK_THREAD (thread
);
2507 if (thread
->state
& (ThreadState_Unstarted
| ThreadState_Aborted
| ThreadState_Stopped
))
2509 UNLOCK_THREAD (thread
);
2513 if (thread
->state
& (ThreadState_Suspended
| ThreadState_SuspendRequested
| ThreadState_AbortRequested
))
2515 UNLOCK_THREAD (thread
);
2519 thread
->state
|= ThreadState_SuspendRequested
;
2520 mono_os_event_reset (thread
->suspended
);
2522 if (thread
== mono_thread_internal_current ()) {
2523 /* calls UNLOCK_THREAD (thread) */
2524 self_suspend_internal ();
2526 /* calls UNLOCK_THREAD (thread) */
2527 async_suspend_internal (thread
, FALSE
);
2534 ves_icall_System_Threading_Thread_Suspend (MonoThread
*this_obj
)
2536 if (!mono_thread_suspend (this_obj
->internal_thread
)) {
2537 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2542 /* LOCKING: LOCK_THREAD(thread) must be held */
2544 mono_thread_resume (MonoInternalThread
*thread
)
2546 if ((thread
->state
& ThreadState_SuspendRequested
) != 0) {
2547 // MOSTLY_ASYNC_SAFE_PRINTF ("RESUME (1) thread %p\n", thread_get_tid (thread));
2548 thread
->state
&= ~ThreadState_SuspendRequested
;
2549 mono_os_event_set (thread
->suspended
);
2553 if ((thread
->state
& ThreadState_Suspended
) == 0 ||
2554 (thread
->state
& ThreadState_Unstarted
) != 0 ||
2555 (thread
->state
& ThreadState_Aborted
) != 0 ||
2556 (thread
->state
& ThreadState_Stopped
) != 0)
2558 // MOSTLY_ASYNC_SAFE_PRINTF ("RESUME (2) thread %p\n", thread_get_tid (thread));
2562 // MOSTLY_ASYNC_SAFE_PRINTF ("RESUME (3) thread %p\n", thread_get_tid (thread));
2564 mono_os_event_set (thread
->suspended
);
2566 if (!thread
->self_suspended
) {
2567 UNLOCK_THREAD (thread
);
2569 /* Awake the thread */
2570 if (!mono_thread_info_resume (thread_get_tid (thread
)))
2573 LOCK_THREAD (thread
);
2576 thread
->state
&= ~ThreadState_Suspended
;
2582 ves_icall_System_Threading_Thread_Resume (MonoThread
*thread
)
2584 if (!thread
->internal_thread
) {
2585 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2587 LOCK_THREAD (thread
->internal_thread
);
2588 if (!mono_thread_resume (thread
->internal_thread
))
2589 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2590 UNLOCK_THREAD (thread
->internal_thread
);
2595 mono_threads_is_critical_method (MonoMethod
*method
)
2597 switch (method
->wrapper_type
) {
2598 case MONO_WRAPPER_RUNTIME_INVOKE
:
2599 case MONO_WRAPPER_XDOMAIN_INVOKE
:
2600 case MONO_WRAPPER_XDOMAIN_DISPATCH
:
2607 find_wrapper (MonoMethod
*m
, gint no
, gint ilo
, gboolean managed
, gpointer data
)
2612 if (mono_threads_is_critical_method (m
)) {
2613 *((gboolean
*)data
) = TRUE
;
2620 is_running_protected_wrapper (void)
2622 gboolean found
= FALSE
;
2623 mono_stack_walk (find_wrapper
, &found
);
2631 mono_thread_stop (MonoThread
*thread
)
2633 MonoInternalThread
*internal
= thread
->internal_thread
;
2635 if (!request_thread_abort (internal
, NULL
, FALSE
))
2638 if (internal
== mono_thread_internal_current ()) {
2640 self_abort_internal (error
);
2642 This function is part of the embeding API and has no way to return the exception
2643 to be thrown. So what we do is keep the old behavior and raise the exception.
2645 mono_error_raise_exception_deprecated (error
); /* OK to throw, see note */
2647 async_abort_internal (internal
, TRUE
);
2652 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr
)
2654 gint8 tmp
= *(volatile gint8
*)ptr
;
2655 mono_memory_barrier ();
2660 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr
)
2662 gint16 tmp
= *(volatile gint16
*)ptr
;
2663 mono_memory_barrier ();
2668 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr
)
2670 gint32 tmp
= *(volatile gint32
*)ptr
;
2671 mono_memory_barrier ();
2676 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr
)
2678 gint64 tmp
= *(volatile gint64
*)ptr
;
2679 mono_memory_barrier ();
2684 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr
)
2686 volatile void *tmp
= *(volatile void **)ptr
;
2687 mono_memory_barrier ();
2688 return (void *) tmp
;
2692 ves_icall_System_Threading_Thread_VolatileReadObject (void *ptr
)
2694 volatile MonoObject
*tmp
= *(volatile MonoObject
**)ptr
;
2695 mono_memory_barrier ();
2696 return (MonoObject
*) tmp
;
2700 ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr
)
2702 double tmp
= *(volatile double *)ptr
;
2703 mono_memory_barrier ();
2708 ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr
)
2710 float tmp
= *(volatile float *)ptr
;
2711 mono_memory_barrier ();
2716 ves_icall_System_Threading_Volatile_Read1 (void *ptr
)
2718 return mono_atomic_load_i8 ((volatile gint8
*)ptr
);
2722 ves_icall_System_Threading_Volatile_Read2 (void *ptr
)
2724 return mono_atomic_load_i16 ((volatile gint16
*)ptr
);
2728 ves_icall_System_Threading_Volatile_Read4 (void *ptr
)
2730 return mono_atomic_load_i32 ((volatile gint32
*)ptr
);
2734 ves_icall_System_Threading_Volatile_Read8 (void *ptr
)
2736 #if SIZEOF_VOID_P == 4
2737 if (G_UNLIKELY ((size_t)ptr
& 0x7)) {
2739 mono_interlocked_lock ();
2740 val
= *(gint64
*)ptr
;
2741 mono_interlocked_unlock ();
2745 return mono_atomic_load_i64 ((volatile gint64
*)ptr
);
2749 ves_icall_System_Threading_Volatile_ReadIntPtr (void *ptr
)
2751 return mono_atomic_load_ptr ((volatile gpointer
*)ptr
);
2755 ves_icall_System_Threading_Volatile_ReadDouble (void *ptr
)
2759 #if SIZEOF_VOID_P == 4
2760 if (G_UNLIKELY ((size_t)ptr
& 0x7)) {
2762 mono_interlocked_lock ();
2763 val
= *(double*)ptr
;
2764 mono_interlocked_unlock ();
2769 u
.ival
= mono_atomic_load_i64 ((volatile gint64
*)ptr
);
2775 ves_icall_System_Threading_Volatile_ReadFloat (void *ptr
)
2779 u
.ival
= mono_atomic_load_i32 ((volatile gint32
*)ptr
);
2785 ves_icall_System_Threading_Volatile_Read_T (void *ptr
)
2787 return (MonoObject
*)mono_atomic_load_ptr ((volatile gpointer
*)ptr
);
2791 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr
, gint8 value
)
2793 mono_memory_barrier ();
2794 *(volatile gint8
*)ptr
= value
;
2798 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr
, gint16 value
)
2800 mono_memory_barrier ();
2801 *(volatile gint16
*)ptr
= value
;
2805 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr
, gint32 value
)
2807 mono_memory_barrier ();
2808 *(volatile gint32
*)ptr
= value
;
2812 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr
, gint64 value
)
2814 mono_memory_barrier ();
2815 *(volatile gint64
*)ptr
= value
;
2819 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr
, void *value
)
2821 mono_memory_barrier ();
2822 *(volatile void **)ptr
= value
;
2826 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr
, MonoObject
*value
)
2828 mono_memory_barrier ();
2829 mono_gc_wbarrier_generic_store (ptr
, value
);
2833 ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr
, double value
)
2835 mono_memory_barrier ();
2836 *(volatile double *)ptr
= value
;
2840 ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr
, float value
)
2842 mono_memory_barrier ();
2843 *(volatile float *)ptr
= value
;
2847 ves_icall_System_Threading_Volatile_Write1 (void *ptr
, gint8 value
)
2849 mono_atomic_store_i8 ((volatile gint8
*)ptr
, value
);
2853 ves_icall_System_Threading_Volatile_Write2 (void *ptr
, gint16 value
)
2855 mono_atomic_store_i16 ((volatile gint16
*)ptr
, value
);
2859 ves_icall_System_Threading_Volatile_Write4 (void *ptr
, gint32 value
)
2861 mono_atomic_store_i32 ((volatile gint32
*)ptr
, value
);
2865 ves_icall_System_Threading_Volatile_Write8 (void *ptr
, gint64 value
)
2867 #if SIZEOF_VOID_P == 4
2868 if (G_UNLIKELY ((size_t)ptr
& 0x7)) {
2869 mono_interlocked_lock ();
2870 *(gint64
*)ptr
= value
;
2871 mono_interlocked_unlock ();
2876 mono_atomic_store_i64 ((volatile gint64
*)ptr
, value
);
2880 ves_icall_System_Threading_Volatile_WriteIntPtr (void *ptr
, void *value
)
2882 mono_atomic_store_ptr ((volatile gpointer
*)ptr
, value
);
2886 ves_icall_System_Threading_Volatile_WriteDouble (void *ptr
, double value
)
2890 #if SIZEOF_VOID_P == 4
2891 if (G_UNLIKELY ((size_t)ptr
& 0x7)) {
2892 mono_interlocked_lock ();
2893 *(double*)ptr
= value
;
2894 mono_interlocked_unlock ();
2901 mono_atomic_store_i64 ((volatile gint64
*)ptr
, u
.ival
);
2905 ves_icall_System_Threading_Volatile_WriteFloat (void *ptr
, float value
)
2911 mono_atomic_store_i32 ((volatile gint32
*)ptr
, u
.ival
);
2915 ves_icall_System_Threading_Volatile_Write_T (void *ptr
, MonoObject
*value
)
2917 mono_gc_wbarrier_generic_store_atomic (ptr
, value
);
2921 free_context (void *user_data
)
2923 ContextStaticData
*data
= user_data
;
2925 mono_threads_lock ();
2928 * There is no guarantee that, by the point this reference queue callback
2929 * has been invoked, the GC handle associated with the object will fail to
2930 * resolve as one might expect. So if we don't free and remove the GC
2931 * handle here, free_context_static_data_helper () could end up resolving
2932 * a GC handle to an actually-dead context which would contain a pointer
2933 * to an already-freed static data segment, resulting in a crash when
2936 g_hash_table_remove (contexts
, GUINT_TO_POINTER (data
->gc_handle
));
2938 mono_threads_unlock ();
2940 mono_gchandle_free (data
->gc_handle
);
2941 mono_free_static_data (data
->static_data
);
2946 mono_threads_register_app_context (MonoAppContext
*ctx
, MonoError
*error
)
2949 mono_threads_lock ();
2951 //g_print ("Registering context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2954 contexts
= g_hash_table_new (NULL
, NULL
);
2957 context_queue
= mono_gc_reference_queue_new (free_context
);
2959 gpointer gch
= GUINT_TO_POINTER (mono_gchandle_new_weakref (&ctx
->obj
, FALSE
));
2960 g_hash_table_insert (contexts
, gch
, gch
);
2963 * We use this intermediate structure to contain a duplicate pointer to
2964 * the static data because we can't rely on being able to resolve the GC
2965 * handle in the reference queue callback.
2967 ContextStaticData
*data
= g_new0 (ContextStaticData
, 1);
2968 data
->gc_handle
= GPOINTER_TO_UINT (gch
);
2971 context_adjust_static_data (ctx
);
2972 mono_gc_reference_queue_add (context_queue
, &ctx
->obj
, data
);
2974 mono_threads_unlock ();
2976 MONO_PROFILER_RAISE (context_loaded
, (ctx
));
2980 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (MonoAppContextHandle ctx
, MonoError
*error
)
2983 mono_threads_register_app_context (MONO_HANDLE_RAW (ctx
), error
); /* FIXME use handles in mono_threads_register_app_context */
2987 mono_threads_release_app_context (MonoAppContext
* ctx
, MonoError
*error
)
2990 * NOTE: Since finalizers are unreliable for the purposes of ensuring
2991 * cleanup in exceptional circumstances, we don't actually do any
2992 * cleanup work here. We instead do this via a reference queue.
2995 //g_print ("Releasing context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2997 MONO_PROFILER_RAISE (context_unloaded
, (ctx
));
3001 ves_icall_System_Runtime_Remoting_Contexts_Context_ReleaseContext (MonoAppContextHandle ctx
, MonoError
*error
)
3004 mono_threads_release_app_context (MONO_HANDLE_RAW (ctx
), error
); /* FIXME use handles in mono_threads_release_app_context */
3007 void mono_thread_init (MonoThreadStartCB start_cb
,
3008 MonoThreadAttachCB attach_cb
)
3010 mono_coop_mutex_init_recursive (&threads_mutex
);
3012 mono_os_mutex_init_recursive(&interlocked_mutex
);
3013 mono_os_mutex_init_recursive(&joinable_threads_mutex
);
3015 mono_os_event_init (&background_change_event
, FALSE
);
3017 mono_os_cond_init (&zero_pending_joinable_thread_event
);
3019 mono_init_static_data_info (&thread_static_info
);
3020 mono_init_static_data_info (&context_static_info
);
3022 mono_thread_start_cb
= start_cb
;
3023 mono_thread_attach_cb
= attach_cb
;
3027 thread_attach (MonoThreadInfo
*info
)
3029 return mono_gc_thread_attach (info
);
3033 thread_detach (MonoThreadInfo
*info
)
3035 MonoInternalThread
*internal
;
3038 /* If a delegate is passed to native code and invoked on a thread we dont
3039 * know about, marshal will register it with mono_threads_attach_coop, but
3040 * we have no way of knowing when that thread goes away. SGen has a TSD
3041 * so we assume that if the domain is still registered, we can detach
3046 if (!mono_thread_info_try_get_internal_thread_gchandle (info
, &gchandle
))
3049 internal
= (MonoInternalThread
*) mono_gchandle_get_target (gchandle
);
3050 g_assert (internal
);
3052 mono_gchandle_free (gchandle
);
3054 mono_thread_detach_internal (internal
);
3058 thread_detach_with_lock (MonoThreadInfo
*info
)
3060 mono_gc_thread_detach_with_lock (info
);
3064 thread_in_critical_region (MonoThreadInfo
*info
)
3066 return mono_gc_thread_in_critical_region (info
);
3070 ip_in_critical_region (MonoDomain
*domain
, gpointer ip
)
3076 * We pass false for 'try_aot' so this becomes async safe.
3077 * It won't find aot methods whose jit info is not yet loaded,
3078 * so we preload their jit info in the JIT.
3080 ji
= mono_jit_info_table_find_internal (domain
, ip
, FALSE
, FALSE
);
3084 method
= mono_jit_info_get_method (ji
);
3087 return mono_gc_is_critical_method (method
);
3091 mono_thread_callbacks_init (void)
3093 MonoThreadInfoCallbacks cb
;
3095 memset (&cb
, 0, sizeof(cb
));
3096 cb
.thread_attach
= thread_attach
;
3097 cb
.thread_detach
= thread_detach
;
3098 cb
.thread_detach_with_lock
= thread_detach_with_lock
;
3099 cb
.ip_in_critical_region
= ip_in_critical_region
;
3100 cb
.thread_in_critical_region
= thread_in_critical_region
;
3101 mono_thread_info_callbacks_init (&cb
);
3105 * mono_thread_cleanup:
3108 mono_thread_cleanup (void)
3110 /* Wait for pending threads to park on joinable threads list */
3111 /* NOTE, waiting on this should be extremely rare and will only happen */
3112 /* under certain specific conditions. */
3113 gboolean wait_result
= threads_wait_pending_joinable_threads (2000);
3115 g_warning ("Waiting on threads to park on joinable thread list timed out.");
3117 mono_threads_join_threads ();
3119 #if !defined(RUN_IN_SUBTHREAD) && !defined(HOST_WIN32)
3120 /* The main thread must abandon any held mutexes (particularly
3121 * important for named mutexes as they are shared across
3122 * processes, see bug 74680.) This will happen when the
3123 * thread exits, but if it's not running in a subthread it
3124 * won't exit in time.
3126 mono_w32mutex_abandon (mono_thread_internal_current ());
3130 /* This stuff needs more testing, it seems one of these
3131 * critical sections can be locked when mono_thread_cleanup is
3134 mono_coop_mutex_destroy (&threads_mutex
);
3135 mono_os_mutex_destroy (&interlocked_mutex
);
3136 mono_os_mutex_destroy (&delayed_free_table_mutex
);
3137 mono_os_mutex_destroy (&small_id_mutex
);
3138 mono_os_cond_destroy (&zero_pending_joinable_runtime_thread_event
);
3139 mono_os_event_destroy (&background_change_event
);
3144 mono_threads_install_cleanup (MonoThreadCleanupFunc func
)
3146 mono_thread_cleanup_fn
= func
;
3150 * mono_thread_set_manage_callback:
3153 mono_thread_set_manage_callback (MonoThread
*thread
, MonoThreadManageCallback func
)
3155 thread
->internal_thread
->manage_callback
= func
;
3159 static void print_tids (gpointer key
, gpointer value
, gpointer user
)
3161 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
3162 * sizeof(uint) and a cast to uint would overflow
3164 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
3165 * print this as a pointer.
3167 g_message ("Waiting for: %p", key
);
3172 MonoThreadHandle
*handles
[MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
];
3173 MonoInternalThread
*threads
[MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
];
3178 wait_for_tids (struct wait_data
*wait
, guint32 timeout
, gboolean check_state_change
)
3181 MonoThreadInfoWaitRet ret
;
3183 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__
, wait
->num
));
3185 /* Add the thread state change event, so it wakes
3186 * up if a thread changes to background mode. */
3189 if (check_state_change
)
3190 ret
= mono_thread_info_wait_multiple_handle (wait
->handles
, wait
->num
, &background_change_event
, FALSE
, timeout
, TRUE
);
3192 ret
= mono_thread_info_wait_multiple_handle (wait
->handles
, wait
->num
, NULL
, TRUE
, timeout
, TRUE
);
3195 if (ret
== MONO_THREAD_INFO_WAIT_RET_FAILED
) {
3196 /* See the comment in build_wait_tids() */
3197 THREAD_DEBUG (g_message ("%s: Wait failed", __func__
));
3201 for( i
= 0; i
< wait
->num
; i
++)
3202 mono_threads_close_thread_handle (wait
->handles
[i
]);
3204 if (ret
== MONO_THREAD_INFO_WAIT_RET_TIMEOUT
)
3207 if (ret
< wait
->num
) {
3208 MonoInternalThread
*internal
;
3210 internal
= wait
->threads
[ret
];
3212 mono_threads_lock ();
3213 if (mono_g_hash_table_lookup (threads
, (gpointer
) internal
->tid
) == internal
)
3214 g_error ("%s: failed to call mono_thread_detach_internal on thread %p, InternalThread: %p", __func__
, internal
->tid
, internal
);
3215 mono_threads_unlock ();
3219 static void build_wait_tids (gpointer key
, gpointer value
, gpointer user
)
3221 struct wait_data
*wait
=(struct wait_data
*)user
;
3223 if(wait
->num
<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
- 1) {
3224 MonoInternalThread
*thread
=(MonoInternalThread
*)value
;
3226 /* Ignore background threads, we abort them later */
3227 /* Do not lock here since it is not needed and the caller holds threads_lock */
3228 if (thread
->state
& ThreadState_Background
) {
3229 THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT
, __func__
, (gsize
)thread
->tid
));
3230 return; /* just leave, ignore */
3233 if (mono_gc_is_finalizer_internal_thread (thread
)) {
3234 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT
, __func__
, (gsize
)thread
->tid
));
3238 if (thread
== mono_thread_internal_current ()) {
3239 THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT
, __func__
, (gsize
)thread
->tid
));
3243 if (mono_thread_get_main () && (thread
== mono_thread_get_main ()->internal_thread
)) {
3244 THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT
, __func__
, (gsize
)thread
->tid
));
3248 if (thread
->flags
& MONO_THREAD_FLAG_DONT_MANAGE
) {
3249 THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT
"with DONT_MANAGE flag set.", __func__
, (gsize
)thread
->tid
));
3253 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__
, thread
));
3254 if ((thread
->manage_callback
== NULL
) || (thread
->manage_callback (thread
->root_domain_thread
) == TRUE
)) {
3255 wait
->handles
[wait
->num
]=mono_threads_open_thread_handle (thread
->handle
);
3256 wait
->threads
[wait
->num
]=thread
;
3259 THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT
, __func__
, (gsize
)thread
->tid
));
3261 THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT
, __func__
, (gsize
)thread
->tid
));
3266 /* Just ignore the rest, we can't do anything with
3273 abort_threads (gpointer key
, gpointer value
, gpointer user
)
3275 struct wait_data
*wait
=(struct wait_data
*)user
;
3276 MonoNativeThreadId self
= mono_native_thread_id_get ();
3277 MonoInternalThread
*thread
= (MonoInternalThread
*)value
;
3279 if (wait
->num
>= MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
)
3282 if (mono_native_thread_id_equals (thread_get_tid (thread
), self
))
3284 if (mono_gc_is_finalizer_internal_thread (thread
))
3287 if ((thread
->flags
& MONO_THREAD_FLAG_DONT_MANAGE
))
3290 wait
->handles
[wait
->num
] = mono_threads_open_thread_handle (thread
->handle
);
3291 wait
->threads
[wait
->num
] = thread
;
3294 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT
"\n", __func__
, (gsize
)thread
->tid
));
3295 mono_thread_internal_abort (thread
, FALSE
);
3299 * mono_threads_set_shutting_down:
3301 * Is called by a thread that wants to shut down Mono. If the runtime is already
3302 * shutting down, the calling thread is suspended/stopped, and this function never
3306 mono_threads_set_shutting_down (void)
3308 MonoInternalThread
*current_thread
= mono_thread_internal_current ();
3310 mono_threads_lock ();
3312 if (shutting_down
) {
3313 mono_threads_unlock ();
3315 /* Make sure we're properly suspended/stopped */
3317 LOCK_THREAD (current_thread
);
3319 if (current_thread
->state
& (ThreadState_SuspendRequested
| ThreadState_AbortRequested
)) {
3320 UNLOCK_THREAD (current_thread
);
3321 mono_thread_execute_interruption ();
3323 UNLOCK_THREAD (current_thread
);
3326 /*since we're killing the thread, detach it.*/
3327 mono_thread_detach_internal (current_thread
);
3329 /* Wake up other threads potentially waiting for us */
3330 mono_thread_info_exit (0);
3332 shutting_down
= TRUE
;
3334 /* Not really a background state change, but this will
3335 * interrupt the main thread if it is waiting for all
3336 * the other threads.
3338 mono_os_event_set (&background_change_event
);
3340 mono_threads_unlock ();
3345 * mono_thread_manage:
3348 mono_thread_manage (void)
3350 struct wait_data wait_data
;
3351 struct wait_data
*wait
= &wait_data
;
3353 memset (wait
, 0, sizeof (struct wait_data
));
3354 /* join each thread that's still running */
3355 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__
));
3357 mono_threads_lock ();
3359 THREAD_DEBUG (g_message("%s: No threads", __func__
));
3360 mono_threads_unlock ();
3364 mono_threads_unlock ();
3367 mono_threads_lock ();
3368 if (shutting_down
) {
3369 /* somebody else is shutting down */
3370 mono_threads_unlock ();
3373 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__
, mono_g_hash_table_size (threads
));
3374 mono_g_hash_table_foreach (threads
, print_tids
, NULL
));
3376 mono_os_event_reset (&background_change_event
);
3378 /* We must zero all InternalThread pointers to avoid making the GC unhappy. */
3379 memset (wait
->threads
, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
* SIZEOF_VOID_P
);
3380 mono_g_hash_table_foreach (threads
, build_wait_tids
, wait
);
3381 mono_threads_unlock ();
3383 /* Something to wait for */
3384 wait_for_tids (wait
, MONO_INFINITE_WAIT
, TRUE
);
3385 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__
, wait
->num
));
3386 } while(wait
->num
>0);
3388 /* Mono is shutting down, so just wait for the end */
3389 if (!mono_runtime_try_shutdown ()) {
3390 /*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
3391 mono_thread_suspend (mono_thread_internal_current ());
3392 mono_thread_execute_interruption ();
3396 * Remove everything but the finalizer thread and self.
3397 * Also abort all the background threads
3400 mono_threads_lock ();
3403 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3404 memset (wait
->threads
, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
* SIZEOF_VOID_P
);
3405 mono_g_hash_table_foreach (threads
, abort_threads
, wait
);
3407 mono_threads_unlock ();
3409 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__
, wait
->num
));
3410 if (wait
->num
> 0) {
3411 /* Something to wait for */
3412 wait_for_tids (wait
, MONO_INFINITE_WAIT
, FALSE
);
3414 } while (wait
->num
> 0);
3417 * give the subthreads a chance to really quit (this is mainly needed
3418 * to get correct user and system times from getrusage/wait/time(1)).
3419 * This could be removed if we avoid pthread_detach() and use pthread_join().
3421 mono_thread_info_yield ();
3425 collect_threads_for_suspend (gpointer key
, gpointer value
, gpointer user_data
)
3427 MonoInternalThread
*thread
= (MonoInternalThread
*)value
;
3428 struct wait_data
*wait
= (struct wait_data
*)user_data
;
3431 * We try to exclude threads early, to avoid running into the MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
3433 * This needs no locking.
3435 if ((thread
->state
& ThreadState_Suspended
) != 0 ||
3436 (thread
->state
& ThreadState_Stopped
) != 0)
3439 if (wait
->num
<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
) {
3440 wait
->handles
[wait
->num
] = mono_threads_open_thread_handle (thread
->handle
);
3441 wait
->threads
[wait
->num
] = thread
;
3447 * mono_thread_suspend_all_other_threads:
3449 * Suspend all managed threads except the finalizer thread and this thread. It is
3450 * not possible to resume them later.
3452 void mono_thread_suspend_all_other_threads (void)
3454 struct wait_data wait_data
;
3455 struct wait_data
*wait
= &wait_data
;
3457 MonoNativeThreadId self
= mono_native_thread_id_get ();
3458 guint32 eventidx
= 0;
3459 gboolean starting
, finished
;
3461 memset (wait
, 0, sizeof (struct wait_data
));
3463 * The other threads could be in an arbitrary state at this point, i.e.
3464 * they could be starting up, shutting down etc. This means that there could be
3465 * threads which are not even in the threads hash table yet.
3469 * First we set a barrier which will be checked by all threads before they
3470 * are added to the threads hash table, and they will exit if the flag is set.
3471 * This ensures that no threads could be added to the hash later.
3472 * We will use shutting_down as the barrier for now.
3474 g_assert (shutting_down
);
3477 * We make multiple calls to WaitForMultipleObjects since:
3478 * - we can only wait for MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS threads
3479 * - some threads could exit without becoming suspended
3484 * Make a copy of the hashtable since we can't do anything with
3485 * threads while threads_mutex is held.
3488 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3489 memset (wait
->threads
, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
* SIZEOF_VOID_P
);
3490 mono_threads_lock ();
3491 mono_g_hash_table_foreach (threads
, collect_threads_for_suspend
, wait
);
3492 mono_threads_unlock ();
3495 /* Get the suspended events that we'll be waiting for */
3496 for (i
= 0; i
< wait
->num
; ++i
) {
3497 MonoInternalThread
*thread
= wait
->threads
[i
];
3499 if (mono_native_thread_id_equals (thread_get_tid (thread
), self
)
3500 || mono_gc_is_finalizer_internal_thread (thread
)
3501 || (thread
->flags
& MONO_THREAD_FLAG_DONT_MANAGE
)
3503 mono_threads_close_thread_handle (wait
->handles
[i
]);
3504 wait
->threads
[i
] = NULL
;
3508 LOCK_THREAD (thread
);
3510 if (thread
->state
& (ThreadState_Suspended
| ThreadState_Stopped
)) {
3511 UNLOCK_THREAD (thread
);
3512 mono_threads_close_thread_handle (wait
->handles
[i
]);
3513 wait
->threads
[i
] = NULL
;
3519 /* Convert abort requests into suspend requests */
3520 if ((thread
->state
& ThreadState_AbortRequested
) != 0)
3521 thread
->state
&= ~ThreadState_AbortRequested
;
3523 thread
->state
|= ThreadState_SuspendRequested
;
3524 mono_os_event_reset (thread
->suspended
);
3526 /* Signal the thread to suspend + calls UNLOCK_THREAD (thread) */
3527 async_suspend_internal (thread
, TRUE
);
3529 mono_threads_close_thread_handle (wait
->handles
[i
]);
3530 wait
->threads
[i
] = NULL
;
3532 if (eventidx
<= 0) {
3534 * If there are threads which are starting up, we wait until they
3535 * are suspended when they try to register in the threads hash.
3536 * This is guaranteed to finish, since the threads which can create new
3537 * threads get suspended after a while.
3538 * FIXME: The finalizer thread can still create new threads.
3540 mono_threads_lock ();
3541 if (threads_starting_up
)
3542 starting
= mono_g_hash_table_size (threads_starting_up
) > 0;
3545 mono_threads_unlock ();
3547 mono_thread_info_sleep (100, NULL
);
3555 MonoInternalThread
*thread
;
3556 MonoStackFrameInfo
*frames
;
3557 int nframes
, max_frames
;
3558 int nthreads
, max_threads
;
3559 MonoInternalThread
**threads
;
3560 } ThreadDumpUserData
;
3562 static gboolean thread_dump_requested
;
3564 /* This needs to be async safe */
3566 collect_frame (MonoStackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
3568 ThreadDumpUserData
*ud
= (ThreadDumpUserData
*)data
;
3570 if (ud
->nframes
< ud
->max_frames
) {
3571 memcpy (&ud
->frames
[ud
->nframes
], frame
, sizeof (MonoStackFrameInfo
));
3578 /* This needs to be async safe */
3579 static SuspendThreadResult
3580 get_thread_dump (MonoThreadInfo
*info
, gpointer ud
)
3582 ThreadDumpUserData
*user_data
= (ThreadDumpUserData
*)ud
;
3583 MonoInternalThread
*thread
= user_data
->thread
;
3586 /* This no longer works with remote unwinding */
3587 g_string_append_printf (text
, " tid=0x%p this=0x%p ", (gpointer
)(gsize
)thread
->tid
, thread
);
3588 mono_thread_internal_describe (thread
, text
);
3589 g_string_append (text
, "\n");
3592 if (thread
== mono_thread_internal_current ())
3593 mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (collect_frame
, NULL
, MONO_UNWIND_SIGNAL_SAFE
, ud
);
3595 mono_get_eh_callbacks ()->mono_walk_stack_with_state (collect_frame
, mono_thread_info_get_suspend_state (info
), MONO_UNWIND_SIGNAL_SAFE
, ud
);
3597 return MonoResumeThread
;
3601 int nthreads
, max_threads
;
3602 MonoInternalThread
**threads
;
3603 } CollectThreadsUserData
;
3606 collect_thread (gpointer key
, gpointer value
, gpointer user
)
3608 CollectThreadsUserData
*ud
= (CollectThreadsUserData
*)user
;
3609 MonoInternalThread
*thread
= (MonoInternalThread
*)value
;
3611 if (ud
->nthreads
< ud
->max_threads
)
3612 ud
->threads
[ud
->nthreads
++] = thread
;
3616 * Collect running threads into the THREADS array.
3617 * THREADS should be an array allocated on the stack.
3620 collect_threads (MonoInternalThread
**thread_array
, int max_threads
)
3622 CollectThreadsUserData ud
;
3624 memset (&ud
, 0, sizeof (ud
));
3625 /* This array contains refs, but its on the stack, so its ok */
3626 ud
.threads
= thread_array
;
3627 ud
.max_threads
= max_threads
;
3629 mono_threads_lock ();
3630 mono_g_hash_table_foreach (threads
, collect_thread
, &ud
);
3631 mono_threads_unlock ();
3637 dump_thread (MonoInternalThread
*thread
, ThreadDumpUserData
*ud
)
3639 GString
* text
= g_string_new (0);
3641 GError
*gerror
= NULL
;
3644 ud
->thread
= thread
;
3647 /* Collect frames for the thread */
3648 if (thread
== mono_thread_internal_current ()) {
3649 get_thread_dump (mono_thread_info_current (), ud
);
3651 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread
), FALSE
, get_thread_dump
, ud
);
3655 * Do all the non async-safe work outside of get_thread_dump.
3658 name
= g_utf16_to_utf8 (thread
->name
, thread
->name_len
, NULL
, NULL
, &gerror
);
3660 g_string_append_printf (text
, "\n\"%s\"", name
);
3663 else if (thread
->threadpool_thread
) {
3664 g_string_append (text
, "\n\"<threadpool thread>\"");
3666 g_string_append (text
, "\n\"<unnamed thread>\"");
3669 for (i
= 0; i
< ud
->nframes
; ++i
) {
3670 MonoStackFrameInfo
*frame
= &ud
->frames
[i
];
3671 MonoMethod
*method
= NULL
;
3673 if (frame
->type
== FRAME_TYPE_MANAGED
)
3674 method
= mono_jit_info_get_method (frame
->ji
);
3677 gchar
*location
= mono_debug_print_stack_frame (method
, frame
->native_offset
, frame
->domain
);
3678 g_string_append_printf (text
, " %s\n", location
);
3681 g_string_append_printf (text
, " at <unknown> <0x%05x>\n", frame
->native_offset
);
3685 fprintf (stdout
, "%s", text
->str
);
3687 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3688 OutputDebugStringA(text
->str
);
3691 g_string_free (text
, TRUE
);
3696 mono_threads_perform_thread_dump (void)
3698 ThreadDumpUserData ud
;
3699 MonoInternalThread
*thread_array
[128];
3700 int tindex
, nthreads
;
3702 if (!thread_dump_requested
)
3705 printf ("Full thread dump:\n");
3707 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3708 nthreads
= collect_threads (thread_array
, 128);
3710 memset (&ud
, 0, sizeof (ud
));
3711 ud
.frames
= g_new0 (MonoStackFrameInfo
, 256);
3712 ud
.max_frames
= 256;
3714 for (tindex
= 0; tindex
< nthreads
; ++tindex
)
3715 dump_thread (thread_array
[tindex
], &ud
);
3719 thread_dump_requested
= FALSE
;
3722 /* Obtain the thread dump of all threads */
3724 mono_threads_get_thread_dump (MonoArray
**out_threads
, MonoArray
**out_stack_frames
, MonoError
*error
)
3727 ThreadDumpUserData ud
;
3728 MonoInternalThread
*thread_array
[128];
3729 MonoDomain
*domain
= mono_domain_get ();
3730 MonoDebugSourceLocation
*location
;
3731 int tindex
, nthreads
;
3735 *out_threads
= NULL
;
3736 *out_stack_frames
= NULL
;
3738 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3739 nthreads
= collect_threads (thread_array
, 128);
3741 memset (&ud
, 0, sizeof (ud
));
3742 ud
.frames
= g_new0 (MonoStackFrameInfo
, 256);
3743 ud
.max_frames
= 256;
3745 *out_threads
= mono_array_new_checked (domain
, mono_defaults
.thread_class
, nthreads
, error
);
3746 goto_if_nok (error
, leave
);
3747 *out_stack_frames
= mono_array_new_checked (domain
, mono_defaults
.array_class
, nthreads
, error
);
3748 goto_if_nok (error
, leave
);
3750 for (tindex
= 0; tindex
< nthreads
; ++tindex
) {
3751 MonoInternalThread
*thread
= thread_array
[tindex
];
3752 MonoArray
*thread_frames
;
3758 /* Collect frames for the thread */
3759 if (thread
== mono_thread_internal_current ()) {
3760 get_thread_dump (mono_thread_info_current (), &ud
);
3762 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread
), FALSE
, get_thread_dump
, &ud
);
3765 mono_array_setref_fast (*out_threads
, tindex
, mono_thread_current_for_thread (thread
));
3767 thread_frames
= mono_array_new_checked (domain
, mono_defaults
.stack_frame_class
, ud
.nframes
, error
);
3768 goto_if_nok (error
, leave
);
3769 mono_array_setref_fast (*out_stack_frames
, tindex
, thread_frames
);
3771 for (i
= 0; i
< ud
.nframes
; ++i
) {
3772 MonoStackFrameInfo
*frame
= &ud
.frames
[i
];
3773 MonoMethod
*method
= NULL
;
3774 MonoStackFrame
*sf
= (MonoStackFrame
*)mono_object_new_checked (domain
, mono_defaults
.stack_frame_class
, error
);
3775 goto_if_nok (error
, leave
);
3777 sf
->native_offset
= frame
->native_offset
;
3779 if (frame
->type
== FRAME_TYPE_MANAGED
)
3780 method
= mono_jit_info_get_method (frame
->ji
);
3783 sf
->method_address
= (gsize
) frame
->ji
->code_start
;
3785 MonoReflectionMethod
*rm
= mono_method_get_object_checked (domain
, method
, NULL
, error
);
3786 goto_if_nok (error
, leave
);
3787 MONO_OBJECT_SETREF (sf
, method
, rm
);
3789 location
= mono_debug_lookup_source_location (method
, frame
->native_offset
, domain
);
3791 sf
->il_offset
= location
->il_offset
;
3793 if (location
&& location
->source_file
) {
3794 MonoString
*filename
= mono_string_new_checked (domain
, location
->source_file
, error
);
3795 goto_if_nok (error
, leave
);
3796 MONO_OBJECT_SETREF (sf
, filename
, filename
);
3797 sf
->line
= location
->row
;
3798 sf
->column
= location
->column
;
3800 mono_debug_free_source_location (location
);
3805 mono_array_setref (thread_frames
, i
, sf
);
3811 return is_ok (error
);
3815 * mono_threads_request_thread_dump:
3817 * Ask all threads except the current to print their stacktrace to stdout.
3820 mono_threads_request_thread_dump (void)
3822 /*The new thread dump code runs out of the finalizer thread. */
3823 thread_dump_requested
= TRUE
;
3824 mono_gc_finalize_notify ();
3829 gint allocated
; /* +1 so that refs [allocated] == NULL */
3833 typedef struct ref_stack RefStack
;
3836 ref_stack_new (gint initial_size
)
3840 initial_size
= MAX (initial_size
, 16) + 1;
3841 rs
= g_new0 (RefStack
, 1);
3842 rs
->refs
= g_new0 (gpointer
, initial_size
);
3843 rs
->allocated
= initial_size
;
3848 ref_stack_destroy (gpointer ptr
)
3850 RefStack
*rs
= (RefStack
*)ptr
;
3859 ref_stack_push (RefStack
*rs
, gpointer ptr
)
3861 g_assert (rs
!= NULL
);
3863 if (rs
->bottom
>= rs
->allocated
) {
3864 rs
->refs
= (void **)g_realloc (rs
->refs
, rs
->allocated
* 2 * sizeof (gpointer
) + 1);
3865 rs
->allocated
<<= 1;
3866 rs
->refs
[rs
->allocated
] = NULL
;
3868 rs
->refs
[rs
->bottom
++] = ptr
;
3872 ref_stack_pop (RefStack
*rs
)
3874 if (rs
== NULL
|| rs
->bottom
== 0)
3878 rs
->refs
[rs
->bottom
] = NULL
;
3882 ref_stack_find (RefStack
*rs
, gpointer ptr
)
3889 for (refs
= rs
->refs
; refs
&& *refs
; refs
++) {
3897 * mono_thread_push_appdomain_ref:
3899 * Register that the current thread may have references to objects in domain
3900 * @domain on its stack. Each call to this function should be paired with a
3901 * call to pop_appdomain_ref.
3904 mono_thread_push_appdomain_ref (MonoDomain
*domain
)
3906 MonoInternalThread
*thread
= mono_thread_internal_current ();
3909 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3910 SPIN_LOCK (thread
->lock_thread_id
);
3911 if (thread
->appdomain_refs
== NULL
)
3912 thread
->appdomain_refs
= ref_stack_new (16);
3913 ref_stack_push ((RefStack
*)thread
->appdomain_refs
, domain
);
3914 SPIN_UNLOCK (thread
->lock_thread_id
);
3919 mono_thread_pop_appdomain_ref (void)
3921 MonoInternalThread
*thread
= mono_thread_internal_current ();
3924 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3925 SPIN_LOCK (thread
->lock_thread_id
);
3926 ref_stack_pop ((RefStack
*)thread
->appdomain_refs
);
3927 SPIN_UNLOCK (thread
->lock_thread_id
);
3932 mono_thread_internal_has_appdomain_ref (MonoInternalThread
*thread
, MonoDomain
*domain
)
3935 SPIN_LOCK (thread
->lock_thread_id
);
3936 res
= ref_stack_find ((RefStack
*)thread
->appdomain_refs
, domain
);
3937 SPIN_UNLOCK (thread
->lock_thread_id
);
3942 mono_thread_has_appdomain_ref (MonoThread
*thread
, MonoDomain
*domain
)
3944 return mono_thread_internal_has_appdomain_ref (thread
->internal_thread
, domain
);
3947 typedef struct abort_appdomain_data
{
3948 struct wait_data wait
;
3950 } abort_appdomain_data
;
3953 collect_appdomain_thread (gpointer key
, gpointer value
, gpointer user_data
)
3955 MonoInternalThread
*thread
= (MonoInternalThread
*)value
;
3956 abort_appdomain_data
*data
= (abort_appdomain_data
*)user_data
;
3957 MonoDomain
*domain
= data
->domain
;
3959 if (mono_thread_internal_has_appdomain_ref (thread
, domain
)) {
3960 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3962 if(data
->wait
.num
<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
) {
3963 data
->wait
.handles
[data
->wait
.num
] = mono_threads_open_thread_handle (thread
->handle
);
3964 data
->wait
.threads
[data
->wait
.num
] = thread
;
3967 /* Just ignore the rest, we can't do anything with
3975 * mono_threads_abort_appdomain_threads:
3977 * Abort threads which has references to the given appdomain.
3980 mono_threads_abort_appdomain_threads (MonoDomain
*domain
, int timeout
)
3982 abort_appdomain_data user_data
;
3984 int orig_timeout
= timeout
;
3987 THREAD_DEBUG (g_message ("%s: starting abort", __func__
));
3989 start_time
= mono_msec_ticks ();
3991 mono_threads_lock ();
3993 user_data
.domain
= domain
;
3994 user_data
.wait
.num
= 0;
3995 /* This shouldn't take any locks */
3996 mono_g_hash_table_foreach (threads
, collect_appdomain_thread
, &user_data
);
3997 mono_threads_unlock ();
3999 if (user_data
.wait
.num
> 0) {
4000 /* Abort the threads outside the threads lock */
4001 for (i
= 0; i
< user_data
.wait
.num
; ++i
)
4002 mono_thread_internal_abort (user_data
.wait
.threads
[i
], TRUE
);
4005 * We should wait for the threads either to abort, or to leave the
4006 * domain. We can't do the latter, so we wait with a timeout.
4008 wait_for_tids (&user_data
.wait
, 100, FALSE
);
4011 /* Update remaining time */
4012 timeout
-= mono_msec_ticks () - start_time
;
4013 start_time
= mono_msec_ticks ();
4015 if (orig_timeout
!= -1 && timeout
< 0)
4018 while (user_data
.wait
.num
> 0);
4020 THREAD_DEBUG (g_message ("%s: abort done", __func__
));
4026 mono_thread_self_abort (void)
4029 self_abort_internal (error
);
4030 mono_error_set_pending_exception (error
);
4034 * mono_thread_get_undeniable_exception:
4036 * Return an exception which needs to be raised when leaving a catch clause.
4037 * This is used for undeniable exception propagation.
4040 mono_thread_get_undeniable_exception (void)
4042 MonoInternalThread
*thread
= mono_thread_internal_current ();
4044 if (!(thread
&& thread
->abort_exc
&& !is_running_protected_wrapper ()))
4047 // We don't want to have our exception effect calls made by
4048 // the catching block
4050 if (!mono_get_eh_callbacks ()->mono_above_abort_threshold ())
4054 * FIXME: Clear the abort exception and return an AppDomainUnloaded
4055 * exception if the thread no longer references a dying appdomain.
4057 thread
->abort_exc
->trace_ips
= NULL
;
4058 thread
->abort_exc
->stack_trace
= NULL
;
4059 return thread
->abort_exc
;
4062 #if MONO_SMALL_CONFIG
4063 #define NUM_STATIC_DATA_IDX 4
4064 static const int static_data_size
[NUM_STATIC_DATA_IDX
] = {
4068 #define NUM_STATIC_DATA_IDX 8
4069 static const int static_data_size
[NUM_STATIC_DATA_IDX
] = {
4070 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
4074 static MonoBitSet
*thread_reference_bitmaps
[NUM_STATIC_DATA_IDX
];
4075 static MonoBitSet
*context_reference_bitmaps
[NUM_STATIC_DATA_IDX
];
4078 mark_slots (void *addr
, MonoBitSet
**bitmaps
, MonoGCMarkFunc mark_func
, void *gc_data
)
4080 gpointer
*static_data
= (gpointer
*)addr
;
4082 for (int i
= 0; i
< NUM_STATIC_DATA_IDX
; ++i
) {
4083 void **ptr
= (void **)static_data
[i
];
4088 MONO_BITSET_FOREACH (bitmaps
[i
], idx
, {
4089 void **p
= ptr
+ idx
;
4092 mark_func ((MonoObject
**)p
, gc_data
);
4098 mark_tls_slots (void *addr
, MonoGCMarkFunc mark_func
, void *gc_data
)
4100 mark_slots (addr
, thread_reference_bitmaps
, mark_func
, gc_data
);
4104 mark_ctx_slots (void *addr
, MonoGCMarkFunc mark_func
, void *gc_data
)
4106 mark_slots (addr
, context_reference_bitmaps
, mark_func
, gc_data
);
4110 * mono_alloc_static_data
4112 * Allocate memory blocks for storing threads or context static data
4115 mono_alloc_static_data (gpointer
**static_data_ptr
, guint32 offset
, void *alloc_key
, gboolean threadlocal
)
4117 guint idx
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, index
);
4120 gpointer
* static_data
= *static_data_ptr
;
4122 static MonoGCDescriptor tls_desc
= MONO_GC_DESCRIPTOR_NULL
;
4123 static MonoGCDescriptor ctx_desc
= MONO_GC_DESCRIPTOR_NULL
;
4125 if (mono_gc_user_markers_supported ()) {
4126 if (tls_desc
== MONO_GC_DESCRIPTOR_NULL
)
4127 tls_desc
= mono_gc_make_root_descr_user (mark_tls_slots
);
4129 if (ctx_desc
== MONO_GC_DESCRIPTOR_NULL
)
4130 ctx_desc
= mono_gc_make_root_descr_user (mark_ctx_slots
);
4133 static_data
= (void **)mono_gc_alloc_fixed (static_data_size
[0], threadlocal
? tls_desc
: ctx_desc
,
4134 threadlocal
? MONO_ROOT_SOURCE_THREAD_STATIC
: MONO_ROOT_SOURCE_CONTEXT_STATIC
,
4136 threadlocal
? "ThreadStatic Fields" : "ContextStatic Fields");
4137 *static_data_ptr
= static_data
;
4138 static_data
[0] = static_data
;
4141 for (i
= 1; i
<= idx
; ++i
) {
4142 if (static_data
[i
])
4145 if (mono_gc_user_markers_supported ())
4146 static_data
[i
] = g_malloc0 (static_data_size
[i
]);
4148 static_data
[i
] = mono_gc_alloc_fixed (static_data_size
[i
], MONO_GC_DESCRIPTOR_NULL
,
4149 threadlocal
? MONO_ROOT_SOURCE_THREAD_STATIC
: MONO_ROOT_SOURCE_CONTEXT_STATIC
,
4151 threadlocal
? "ThreadStatic Fields" : "ContextStatic Fields");
4156 mono_free_static_data (gpointer
* static_data
)
4159 for (i
= 1; i
< NUM_STATIC_DATA_IDX
; ++i
) {
4160 gpointer p
= static_data
[i
];
4164 * At this point, the static data pointer array is still registered with the
4165 * GC, so must ensure that mark_tls_slots() will not encounter any invalid
4166 * data. Freeing the individual arrays without first nulling their slots
4167 * would make it possible for mark_tls/ctx_slots() to encounter a pointer to
4168 * such an already freed array. See bug #13813.
4170 static_data
[i
] = NULL
;
4171 mono_memory_write_barrier ();
4172 if (mono_gc_user_markers_supported ())
4175 mono_gc_free_fixed (p
);
4177 mono_gc_free_fixed (static_data
);
4181 * mono_init_static_data_info
4183 * Initializes static data counters
4185 static void mono_init_static_data_info (StaticDataInfo
*static_data
)
4187 static_data
->idx
= 0;
4188 static_data
->offset
= 0;
4189 static_data
->freelist
= NULL
;
4193 * mono_alloc_static_data_slot
4195 * Generates an offset for static data. static_data contains the counters
4196 * used to generate it.
4199 mono_alloc_static_data_slot (StaticDataInfo
*static_data
, guint32 size
, guint32 align
)
4201 if (!static_data
->idx
&& !static_data
->offset
) {
4203 * we use the first chunk of the first allocation also as
4204 * an array for the rest of the data
4206 static_data
->offset
= sizeof (gpointer
) * NUM_STATIC_DATA_IDX
;
4208 static_data
->offset
+= align
- 1;
4209 static_data
->offset
&= ~(align
- 1);
4210 if (static_data
->offset
+ size
>= static_data_size
[static_data
->idx
]) {
4211 static_data
->idx
++;
4212 g_assert (size
<= static_data_size
[static_data
->idx
]);
4213 g_assert (static_data
->idx
< NUM_STATIC_DATA_IDX
);
4214 static_data
->offset
= 0;
4216 guint32 offset
= MAKE_SPECIAL_STATIC_OFFSET (static_data
->idx
, static_data
->offset
, 0);
4217 static_data
->offset
+= size
;
4222 * LOCKING: requires that threads_mutex is held
4225 context_adjust_static_data (MonoAppContext
*ctx
)
4227 if (context_static_info
.offset
|| context_static_info
.idx
> 0) {
4228 guint32 offset
= MAKE_SPECIAL_STATIC_OFFSET (context_static_info
.idx
, context_static_info
.offset
, 0);
4229 mono_alloc_static_data (&ctx
->static_data
, offset
, ctx
, FALSE
);
4230 ctx
->data
->static_data
= ctx
->static_data
;
4235 * LOCKING: requires that threads_mutex is held
4238 alloc_thread_static_data_helper (gpointer key
, gpointer value
, gpointer user
)
4240 MonoInternalThread
*thread
= (MonoInternalThread
*)value
;
4241 guint32 offset
= GPOINTER_TO_UINT (user
);
4243 mono_alloc_static_data (&(thread
->static_data
), offset
, (void *) MONO_UINT_TO_NATIVE_THREAD_ID (thread
->tid
), TRUE
);
4247 * LOCKING: requires that threads_mutex is held
4250 alloc_context_static_data_helper (gpointer key
, gpointer value
, gpointer user
)
4252 MonoAppContext
*ctx
= (MonoAppContext
*) mono_gchandle_get_target (GPOINTER_TO_INT (key
));
4257 guint32 offset
= GPOINTER_TO_UINT (user
);
4258 mono_alloc_static_data (&ctx
->static_data
, offset
, ctx
, FALSE
);
4259 ctx
->data
->static_data
= ctx
->static_data
;
4262 static StaticDataFreeList
*
4263 search_slot_in_freelist (StaticDataInfo
*static_data
, guint32 size
, guint32 align
)
4265 StaticDataFreeList
* prev
= NULL
;
4266 StaticDataFreeList
* tmp
= static_data
->freelist
;
4268 if (tmp
->size
== size
) {
4270 prev
->next
= tmp
->next
;
4272 static_data
->freelist
= tmp
->next
;
4281 #if SIZEOF_VOID_P == 4
4288 update_reference_bitmap (MonoBitSet
**sets
, guint32 offset
, uintptr_t *bitmap
, int numbits
)
4290 int idx
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, index
);
4292 sets
[idx
] = mono_bitset_new (static_data_size
[idx
] / sizeof (uintptr_t), 0);
4293 MonoBitSet
*rb
= sets
[idx
];
4294 offset
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, offset
);
4295 offset
/= sizeof (uintptr_t);
4296 /* offset is now the bitmap offset */
4297 for (int i
= 0; i
< numbits
; ++i
) {
4298 if (bitmap
[i
/ sizeof (uintptr_t)] & (ONE_P
<< (i
& (sizeof (uintptr_t) * 8 -1))))
4299 mono_bitset_set_fast (rb
, offset
+ i
);
4304 clear_reference_bitmap (MonoBitSet
**sets
, guint32 offset
, guint32 size
)
4306 int idx
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, index
);
4307 MonoBitSet
*rb
= sets
[idx
];
4308 offset
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, offset
);
4309 offset
/= sizeof (uintptr_t);
4310 /* offset is now the bitmap offset */
4311 for (int i
= 0; i
< size
/ sizeof (uintptr_t); i
++)
4312 mono_bitset_clear_fast (rb
, offset
+ i
);
4316 mono_alloc_special_static_data (guint32 static_type
, guint32 size
, guint32 align
, uintptr_t *bitmap
, int numbits
)
4318 g_assert (static_type
== SPECIAL_STATIC_THREAD
|| static_type
== SPECIAL_STATIC_CONTEXT
);
4320 StaticDataInfo
*info
;
4323 if (static_type
== SPECIAL_STATIC_THREAD
) {
4324 info
= &thread_static_info
;
4325 sets
= thread_reference_bitmaps
;
4327 info
= &context_static_info
;
4328 sets
= context_reference_bitmaps
;
4331 mono_threads_lock ();
4333 StaticDataFreeList
*item
= search_slot_in_freelist (info
, size
, align
);
4337 offset
= item
->offset
;
4340 offset
= mono_alloc_static_data_slot (info
, size
, align
);
4343 update_reference_bitmap (sets
, offset
, bitmap
, numbits
);
4345 if (static_type
== SPECIAL_STATIC_THREAD
) {
4346 /* This can be called during startup */
4347 if (threads
!= NULL
)
4348 mono_g_hash_table_foreach (threads
, alloc_thread_static_data_helper
, GUINT_TO_POINTER (offset
));
4350 if (contexts
!= NULL
)
4351 g_hash_table_foreach (contexts
, alloc_context_static_data_helper
, GUINT_TO_POINTER (offset
));
4353 ACCESS_SPECIAL_STATIC_OFFSET (offset
, type
) = SPECIAL_STATIC_OFFSET_TYPE_CONTEXT
;
4356 mono_threads_unlock ();
4362 mono_get_special_static_data_for_thread (MonoInternalThread
*thread
, guint32 offset
)
4364 guint32 static_type
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, type
);
4366 if (static_type
== SPECIAL_STATIC_OFFSET_TYPE_THREAD
) {
4367 return get_thread_static_data (thread
, offset
);
4369 return get_context_static_data (thread
->current_appcontext
, offset
);
4374 mono_get_special_static_data (guint32 offset
)
4376 return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset
);
4385 * LOCKING: requires that threads_mutex is held
4388 free_thread_static_data_helper (gpointer key
, gpointer value
, gpointer user
)
4390 MonoInternalThread
*thread
= (MonoInternalThread
*)value
;
4391 OffsetSize
*data
= (OffsetSize
*)user
;
4392 int idx
= ACCESS_SPECIAL_STATIC_OFFSET (data
->offset
, index
);
4393 int off
= ACCESS_SPECIAL_STATIC_OFFSET (data
->offset
, offset
);
4396 if (!thread
->static_data
|| !thread
->static_data
[idx
])
4398 ptr
= ((char*) thread
->static_data
[idx
]) + off
;
4399 mono_gc_bzero_atomic (ptr
, data
->size
);
4403 * LOCKING: requires that threads_mutex is held
4406 free_context_static_data_helper (gpointer key
, gpointer value
, gpointer user
)
4408 MonoAppContext
*ctx
= (MonoAppContext
*) mono_gchandle_get_target (GPOINTER_TO_INT (key
));
4413 OffsetSize
*data
= (OffsetSize
*)user
;
4414 int idx
= ACCESS_SPECIAL_STATIC_OFFSET (data
->offset
, index
);
4415 int off
= ACCESS_SPECIAL_STATIC_OFFSET (data
->offset
, offset
);
4418 if (!ctx
->static_data
|| !ctx
->static_data
[idx
])
4421 ptr
= ((char*) ctx
->static_data
[idx
]) + off
;
4422 mono_gc_bzero_atomic (ptr
, data
->size
);
4426 do_free_special_slot (guint32 offset
, guint32 size
)
4428 guint32 static_type
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, type
);
4430 StaticDataInfo
*info
;
4432 if (static_type
== SPECIAL_STATIC_OFFSET_TYPE_THREAD
) {
4433 info
= &thread_static_info
;
4434 sets
= thread_reference_bitmaps
;
4436 info
= &context_static_info
;
4437 sets
= context_reference_bitmaps
;
4440 guint32 data_offset
= offset
;
4441 ACCESS_SPECIAL_STATIC_OFFSET (data_offset
, type
) = 0;
4442 OffsetSize data
= { data_offset
, size
};
4444 clear_reference_bitmap (sets
, data
.offset
, data
.size
);
4446 if (static_type
== SPECIAL_STATIC_OFFSET_TYPE_THREAD
) {
4447 if (threads
!= NULL
)
4448 mono_g_hash_table_foreach (threads
, free_thread_static_data_helper
, &data
);
4450 if (contexts
!= NULL
)
4451 g_hash_table_foreach (contexts
, free_context_static_data_helper
, &data
);
4454 if (!mono_runtime_is_shutting_down ()) {
4455 StaticDataFreeList
*item
= g_new0 (StaticDataFreeList
, 1);
4457 item
->offset
= offset
;
4460 item
->next
= info
->freelist
;
4461 info
->freelist
= item
;
4466 do_free_special (gpointer key
, gpointer value
, gpointer data
)
4468 MonoClassField
*field
= (MonoClassField
*)key
;
4469 guint32 offset
= GPOINTER_TO_UINT (value
);
4472 size
= mono_type_size (field
->type
, &align
);
4473 do_free_special_slot (offset
, size
);
4477 mono_alloc_special_static_data_free (GHashTable
*special_static_fields
)
4479 mono_threads_lock ();
4481 g_hash_table_foreach (special_static_fields
, do_free_special
, NULL
);
4483 mono_threads_unlock ();
4487 static void CALLBACK
dummy_apc (ULONG_PTR param
)
4493 * mono_thread_execute_interruption
4495 * Performs the operation that the requested thread state requires (abort,
4498 static MonoException
*
4499 mono_thread_execute_interruption (void)
4501 MonoInternalThread
*thread
= mono_thread_internal_current ();
4502 MonoThread
*sys_thread
= mono_thread_current ();
4504 LOCK_THREAD (thread
);
4506 /* MonoThread::interruption_requested can only be changed with atomics */
4507 if (!mono_thread_clear_interruption_requested (thread
)) {
4508 UNLOCK_THREAD (thread
);
4512 /* this will consume pending APC calls */
4515 mono_win32_wait_for_single_object_ex (GetCurrentThread (), 0, TRUE
);
4519 /* Clear the interrupted flag of the thread so it can wait again */
4520 mono_thread_info_clear_self_interrupt ();
4522 /* If there's a pending exception and an AbortRequested, the pending exception takes precedence */
4523 if (sys_thread
->pending_exception
) {
4526 exc
= sys_thread
->pending_exception
;
4527 sys_thread
->pending_exception
= NULL
;
4529 UNLOCK_THREAD (thread
);
4531 } else if (thread
->state
& (ThreadState_AbortRequested
)) {
4532 UNLOCK_THREAD (thread
);
4533 g_assert (sys_thread
->pending_exception
== NULL
);
4534 if (thread
->abort_exc
== NULL
) {
4536 * This might be racy, but it has to be called outside the lock
4537 * since it calls managed code.
4539 MONO_OBJECT_SETREF (thread
, abort_exc
, mono_get_exception_thread_abort ());
4541 return thread
->abort_exc
;
4542 } else if (thread
->state
& (ThreadState_SuspendRequested
)) {
4543 /* calls UNLOCK_THREAD (thread) */
4544 self_suspend_internal ();
4546 } else if (thread
->thread_interrupt_requested
) {
4548 thread
->thread_interrupt_requested
= FALSE
;
4549 UNLOCK_THREAD (thread
);
4551 return(mono_get_exception_thread_interrupted ());
4554 UNLOCK_THREAD (thread
);
4560 * mono_thread_request_interruption
4562 * A signal handler can call this method to request the interruption of a
4563 * thread. The result of the interruption will depend on the current state of
4564 * the thread. If the result is an exception that needs to be throw, it is
4565 * provided as return value.
4568 mono_thread_request_interruption (gboolean running_managed
)
4570 MonoInternalThread
*thread
= mono_thread_internal_current ();
4572 /* The thread may already be stopping */
4576 if (!mono_thread_set_interruption_requested (thread
))
4579 if (!running_managed
|| is_running_protected_wrapper ()) {
4580 /* Can't stop while in unmanaged code. Increase the global interruption
4581 request count. When exiting the unmanaged method the count will be
4582 checked and the thread will be interrupted. */
4584 /* this will awake the thread if it is in WaitForSingleObject
4587 mono_win32_interrupt_wait (thread
->thread_info
, thread
->native_handle
, (DWORD
)thread
->tid
);
4589 mono_thread_info_self_interrupt ();
4594 return mono_thread_execute_interruption ();
4598 /*This function should be called by a thread after it has exited all of
4599 * its handle blocks at interruption time.*/
4601 mono_thread_resume_interruption (gboolean exec
)
4603 MonoInternalThread
*thread
= mono_thread_internal_current ();
4604 gboolean still_aborting
;
4606 /* The thread may already be stopping */
4610 LOCK_THREAD (thread
);
4611 still_aborting
= (thread
->state
& (ThreadState_AbortRequested
)) != 0;
4612 UNLOCK_THREAD (thread
);
4614 /*This can happen if the protected block called Thread::ResetAbort*/
4615 if (!still_aborting
)
4618 if (!mono_thread_set_interruption_requested (thread
))
4621 mono_thread_info_self_interrupt ();
4624 return mono_thread_execute_interruption ();
4629 gboolean
mono_thread_interruption_requested ()
4631 if (thread_interruption_requested
) {
4632 MonoInternalThread
*thread
= mono_thread_internal_current ();
4633 /* The thread may already be stopping */
4635 return mono_thread_get_interruption_requested (thread
);
4640 static MonoException
*
4641 mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection
)
4643 MonoInternalThread
*thread
= mono_thread_internal_current ();
4645 /* The thread may already be stopping */
4648 if (!mono_thread_get_interruption_requested (thread
))
4650 if (!bypass_abort_protection
&& !mono_thread_current ()->pending_exception
&& is_running_protected_wrapper ())
4653 return mono_thread_execute_interruption ();
4657 * Performs the interruption of the current thread, if one has been requested,
4658 * and the thread is not running a protected wrapper.
4659 * Return the exception which needs to be thrown, if any.
4662 mono_thread_interruption_checkpoint (void)
4664 return mono_thread_interruption_checkpoint_request (FALSE
);
4668 * Performs the interruption of the current thread, if one has been requested.
4669 * Return the exception which needs to be thrown, if any.
4672 mono_thread_force_interruption_checkpoint_noraise (void)
4674 return mono_thread_interruption_checkpoint_request (TRUE
);
4678 * mono_set_pending_exception:
4680 * Set the pending exception of the current thread to EXC.
4681 * The exception will be thrown when execution returns to managed code.
4684 mono_set_pending_exception (MonoException
*exc
)
4686 MonoThread
*thread
= mono_thread_current ();
4688 /* The thread may already be stopping */
4692 MONO_OBJECT_SETREF (thread
, pending_exception
, exc
);
4694 mono_thread_request_interruption (FALSE
);
4698 * mono_thread_interruption_request_flag:
4700 * Returns the address of a flag that will be non-zero if an interruption has
4701 * been requested for a thread. The thread to interrupt may not be the current
4702 * thread, so an additional call to mono_thread_interruption_requested() or
4703 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4706 gint32
* mono_thread_interruption_request_flag ()
4708 return &thread_interruption_requested
;
4712 mono_thread_init_apartment_state (void)
4715 MonoInternalThread
* thread
= mono_thread_internal_current ();
4717 /* Positive return value indicates success, either
4718 * S_OK if this is first CoInitialize call, or
4719 * S_FALSE if CoInitialize already called, but with same
4720 * threading model. A negative value indicates failure,
4721 * probably due to trying to change the threading model.
4723 if (CoInitializeEx(NULL
, (thread
->apartment_state
== ThreadApartmentState_STA
)
4724 ? COINIT_APARTMENTTHREADED
4725 : COINIT_MULTITHREADED
) < 0) {
4726 thread
->apartment_state
= ThreadApartmentState_Unknown
;
4732 mono_thread_cleanup_apartment_state (void)
4735 MonoInternalThread
* thread
= mono_thread_internal_current ();
4737 if (thread
&& thread
->apartment_state
!= ThreadApartmentState_Unknown
) {
4744 mono_thread_notify_change_state (MonoThreadState old_state
, MonoThreadState new_state
)
4746 MonoThreadState diff
= old_state
^ new_state
;
4747 if (diff
& ThreadState_Background
) {
4748 /* If the thread changes the background mode, the main thread has to
4749 * be notified, since it has to rebuild the list of threads to
4752 mono_os_event_set (&background_change_event
);
4757 mono_thread_clear_and_set_state (MonoInternalThread
*thread
, MonoThreadState clear
, MonoThreadState set
)
4759 LOCK_THREAD (thread
);
4761 MonoThreadState
const old_state
= thread
->state
;
4762 MonoThreadState
const new_state
= (old_state
& ~clear
) | set
;
4763 thread
->state
= new_state
;
4765 UNLOCK_THREAD (thread
);
4767 mono_thread_notify_change_state (old_state
, new_state
);
4771 mono_thread_set_state (MonoInternalThread
*thread
, MonoThreadState state
)
4773 mono_thread_clear_and_set_state (thread
, 0, state
);
4777 * mono_thread_test_and_set_state:
4778 * Test if current state of \p thread include \p test. If it does not, OR \p set into the state.
4779 * \returns TRUE if \p set was OR'd in.
4782 mono_thread_test_and_set_state (MonoInternalThread
*thread
, MonoThreadState test
, MonoThreadState set
)
4784 LOCK_THREAD (thread
);
4786 MonoThreadState
const old_state
= thread
->state
;
4788 if ((old_state
& test
) != 0) {
4789 UNLOCK_THREAD (thread
);
4793 MonoThreadState
const new_state
= old_state
| set
;
4794 thread
->state
= new_state
;
4796 UNLOCK_THREAD (thread
);
4798 mono_thread_notify_change_state (old_state
, new_state
);
4804 mono_thread_clr_state (MonoInternalThread
*thread
, MonoThreadState state
)
4806 mono_thread_clear_and_set_state (thread
, state
, 0);
4810 mono_thread_test_state (MonoInternalThread
*thread
, MonoThreadState test
)
4812 LOCK_THREAD (thread
);
4814 gboolean
const ret
= ((thread
->state
& test
) != 0);
4816 UNLOCK_THREAD (thread
);
4822 self_interrupt_thread (void *_unused
)
4825 MonoThreadInfo
*info
;
4827 exc
= mono_thread_execute_interruption ();
4829 if (mono_threads_is_coop_enabled ()) {
4830 /* We can return from an async call in coop, as
4831 * it's simply called when exiting the safepoint */
4835 g_error ("%s: we can't resume from an async call", __func__
);
4838 info
= mono_thread_info_current ();
4840 mono_raise_exception_with_context (exc
, &info
->thread_saved_state
[ASYNC_SUSPEND_STATE_INDEX
].ctx
); /* FIXME using thread_saved_state [ASYNC_SUSPEND_STATE_INDEX] can race with another suspend coming in. */
4844 mono_jit_info_match (MonoJitInfo
*ji
, gpointer ip
)
4848 return ji
->code_start
<= ip
&& (char*)ip
< (char*)ji
->code_start
+ ji
->code_size
;
4852 last_managed (MonoStackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
4854 MonoJitInfo
**dest
= (MonoJitInfo
**)data
;
4860 mono_thread_info_get_last_managed (MonoThreadInfo
*info
)
4862 MonoJitInfo
*ji
= NULL
;
4867 * The suspended thread might be holding runtime locks. Make sure we don't try taking
4868 * any runtime locks while unwinding. In coop case we shouldn't safepoint in regions
4869 * where we hold runtime locks.
4871 if (!mono_threads_is_coop_enabled ())
4872 mono_thread_info_set_is_async_context (TRUE
);
4873 mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed
, mono_thread_info_get_suspend_state (info
), MONO_UNWIND_SIGNAL_SAFE
, &ji
);
4874 if (!mono_threads_is_coop_enabled ())
4875 mono_thread_info_set_is_async_context (FALSE
);
4880 MonoInternalThread
*thread
;
4881 gboolean install_async_abort
;
4882 MonoThreadInfoInterruptToken
*interrupt_token
;
4885 static SuspendThreadResult
4886 async_abort_critical (MonoThreadInfo
*info
, gpointer ud
)
4888 AbortThreadData
*data
= (AbortThreadData
*)ud
;
4889 MonoInternalThread
*thread
= data
->thread
;
4890 MonoJitInfo
*ji
= NULL
;
4891 gboolean protected_wrapper
;
4892 gboolean running_managed
;
4894 if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info
)))
4895 return MonoResumeThread
;
4897 /*someone is already interrupting it*/
4898 if (!mono_thread_set_interruption_requested (thread
))
4899 return MonoResumeThread
;
4901 ji
= mono_thread_info_get_last_managed (info
);
4902 protected_wrapper
= ji
&& !ji
->is_trampoline
&& !ji
->async
&& mono_threads_is_critical_method (mono_jit_info_get_method (ji
));
4903 running_managed
= mono_jit_info_match (ji
, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info
)->ctx
));
4905 if (!protected_wrapper
&& running_managed
) {
4906 /*We are in managed code*/
4907 /*Set the thread to call */
4908 if (data
->install_async_abort
)
4909 mono_thread_info_setup_async_call (info
, self_interrupt_thread
, NULL
);
4910 return MonoResumeThread
;
4913 * This will cause waits to be broken.
4914 * It will also prevent the thread from entering a wait, so if the thread returns
4915 * from the wait before it receives the abort signal, it will just spin in the wait
4916 * functions in the io-layer until the signal handler calls QueueUserAPC which will
4919 data
->interrupt_token
= mono_thread_info_prepare_interrupt (info
);
4921 return MonoResumeThread
;
4926 async_abort_internal (MonoInternalThread
*thread
, gboolean install_async_abort
)
4928 AbortThreadData data
;
4930 g_assert (thread
!= mono_thread_internal_current ());
4932 data
.thread
= thread
;
4933 data
.install_async_abort
= install_async_abort
;
4934 data
.interrupt_token
= NULL
;
4936 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread
), TRUE
, async_abort_critical
, &data
);
4937 if (data
.interrupt_token
)
4938 mono_thread_info_finish_interrupt (data
.interrupt_token
);
4939 /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4943 self_abort_internal (MonoError
*error
)
4949 /* FIXME this is insanely broken, it doesn't cause interruption to happen synchronously
4950 * since passing FALSE to mono_thread_request_interruption makes sure it returns NULL */
4953 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.
4955 exc
= mono_thread_request_interruption (TRUE
);
4957 mono_error_set_exception_instance (error
, exc
);
4959 mono_thread_info_self_interrupt ();
4963 MonoInternalThread
*thread
;
4965 MonoThreadInfoInterruptToken
*interrupt_token
;
4966 } SuspendThreadData
;
4968 static SuspendThreadResult
4969 async_suspend_critical (MonoThreadInfo
*info
, gpointer ud
)
4971 SuspendThreadData
*data
= (SuspendThreadData
*)ud
;
4972 MonoInternalThread
*thread
= data
->thread
;
4973 MonoJitInfo
*ji
= NULL
;
4974 gboolean protected_wrapper
;
4975 gboolean running_managed
;
4977 ji
= mono_thread_info_get_last_managed (info
);
4978 protected_wrapper
= ji
&& !ji
->is_trampoline
&& !ji
->async
&& mono_threads_is_critical_method (mono_jit_info_get_method (ji
));
4979 running_managed
= mono_jit_info_match (ji
, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info
)->ctx
));
4981 if (running_managed
&& !protected_wrapper
) {
4982 if (mono_threads_is_coop_enabled ()) {
4983 mono_thread_info_setup_async_call (info
, self_interrupt_thread
, NULL
);
4984 return MonoResumeThread
;
4986 thread
->state
&= ~ThreadState_SuspendRequested
;
4987 thread
->state
|= ThreadState_Suspended
;
4988 return KeepSuspended
;
4991 mono_thread_set_interruption_requested (thread
);
4992 if (data
->interrupt
)
4993 data
->interrupt_token
= mono_thread_info_prepare_interrupt ((MonoThreadInfo
*)thread
->thread_info
);
4995 return MonoResumeThread
;
4999 /* LOCKING: called with @thread synch_cs held, and releases it */
5001 async_suspend_internal (MonoInternalThread
*thread
, gboolean interrupt
)
5003 SuspendThreadData data
;
5005 g_assert (thread
!= mono_thread_internal_current ());
5007 // MOSTLY_ASYNC_SAFE_PRINTF ("ASYNC SUSPEND thread %p\n", thread_get_tid (thread));
5009 thread
->self_suspended
= FALSE
;
5011 data
.thread
= thread
;
5012 data
.interrupt
= interrupt
;
5013 data
.interrupt_token
= NULL
;
5015 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread
), interrupt
, async_suspend_critical
, &data
);
5016 if (data
.interrupt_token
)
5017 mono_thread_info_finish_interrupt (data
.interrupt_token
);
5019 UNLOCK_THREAD (thread
);
5022 /* LOCKING: called with @thread synch_cs held, and releases it */
5024 self_suspend_internal (void)
5026 MonoInternalThread
*thread
;
5028 MonoOSEventWaitRet res
;
5030 thread
= mono_thread_internal_current ();
5032 // MOSTLY_ASYNC_SAFE_PRINTF ("SELF SUSPEND thread %p\n", thread_get_tid (thread));
5034 thread
->self_suspended
= TRUE
;
5036 thread
->state
&= ~ThreadState_SuspendRequested
;
5037 thread
->state
|= ThreadState_Suspended
;
5039 UNLOCK_THREAD (thread
);
5041 event
= thread
->suspended
;
5044 res
= mono_os_event_wait_one (event
, MONO_INFINITE_WAIT
, TRUE
);
5045 g_assert (res
== MONO_OS_EVENT_WAIT_RET_SUCCESS_0
|| res
== MONO_OS_EVENT_WAIT_RET_ALERTED
);
5050 suspend_for_shutdown_async_call (gpointer unused
)
5053 mono_thread_info_yield ();
5056 static SuspendThreadResult
5057 suspend_for_shutdown_critical (MonoThreadInfo
*info
, gpointer unused
)
5059 mono_thread_info_setup_async_call (info
, suspend_for_shutdown_async_call
, NULL
);
5060 return MonoResumeThread
;
5064 mono_thread_internal_suspend_for_shutdown (MonoInternalThread
*thread
)
5066 g_assert (thread
!= mono_thread_internal_current ());
5068 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread
), FALSE
, suspend_for_shutdown_critical
, NULL
);
5072 * mono_thread_is_foreign:
5073 * \param thread the thread to query
5075 * This function allows one to determine if a thread was created by the mono runtime and has
5076 * a well defined lifecycle or it's a foreign one, created by the native environment.
5078 * \returns TRUE if \p thread was not created by the runtime.
5081 mono_thread_is_foreign (MonoThread
*thread
)
5083 MonoThreadInfo
*info
= (MonoThreadInfo
*)thread
->internal_thread
->thread_info
;
5084 return info
->runtime_thread
== FALSE
;
5089 threads_native_thread_join_lock (gpointer tid
, gpointer value
)
5091 pthread_t thread
= (pthread_t
)tid
;
5092 if (thread
!= pthread_self ()) {
5094 /* This shouldn't block */
5095 mono_threads_join_lock ();
5096 mono_native_thread_join (thread
);
5097 mono_threads_join_unlock ();
5102 threads_native_thread_join_nolock (gpointer tid
, gpointer value
)
5104 pthread_t thread
= (pthread_t
)tid
;
5106 mono_native_thread_join (thread
);
5111 threads_add_joinable_thread_nolock (gpointer tid
)
5113 g_hash_table_insert (joinable_threads
, tid
, tid
);
5117 threads_native_thread_join_lock (gpointer tid
, gpointer value
)
5119 MonoNativeThreadId thread_id
= (MonoNativeThreadId
)(guint64
)tid
;
5120 HANDLE thread_handle
= (HANDLE
)value
;
5121 if (thread_id
!= GetCurrentThreadId () && thread_handle
!= NULL
&& thread_handle
!= INVALID_HANDLE_VALUE
) {
5123 /* This shouldn't block */
5124 mono_threads_join_lock ();
5125 mono_native_thread_join_handle (thread_handle
, TRUE
);
5126 mono_threads_join_unlock ();
5132 threads_native_thread_join_nolock (gpointer tid
, gpointer value
)
5134 HANDLE thread_handle
= (HANDLE
)value
;
5136 mono_native_thread_join_handle (thread_handle
, TRUE
);
5141 threads_add_joinable_thread_nolock (gpointer tid
)
5143 g_hash_table_insert (joinable_threads
, tid
, (gpointer
)OpenThread (SYNCHRONIZE
, TRUE
, (MonoNativeThreadId
)(guint64
)tid
));
5148 threads_add_pending_joinable_thread (gpointer tid
)
5150 joinable_threads_lock ();
5152 if (!pending_joinable_threads
)
5153 pending_joinable_threads
= g_hash_table_new (NULL
, NULL
);
5158 if (!g_hash_table_lookup_extended (pending_joinable_threads
, tid
, &orig_key
, &value
)) {
5159 g_hash_table_insert (pending_joinable_threads
, tid
, tid
);
5160 UnlockedIncrement (&pending_joinable_thread_count
);
5163 joinable_threads_unlock ();
5167 threads_add_pending_joinable_runtime_thread (MonoThreadInfo
*mono_thread_info
)
5169 g_assert (mono_thread_info
);
5171 if (mono_thread_info
->runtime_thread
) {
5172 threads_add_pending_joinable_thread ((gpointer
)(MONO_UINT_TO_NATIVE_THREAD_ID (mono_thread_info_get_tid (mono_thread_info
))));
5177 threads_remove_pending_joinable_thread_nolock (gpointer tid
)
5182 if (pending_joinable_threads
&& g_hash_table_lookup_extended (pending_joinable_threads
, tid
, &orig_key
, &value
)) {
5183 g_hash_table_remove (pending_joinable_threads
, tid
);
5184 if (UnlockedDecrement (&pending_joinable_thread_count
) == 0)
5185 mono_os_cond_broadcast (&zero_pending_joinable_thread_event
);
5190 threads_wait_pending_joinable_threads (uint32_t timeout
)
5192 if (UnlockedRead (&pending_joinable_thread_count
) > 0) {
5193 joinable_threads_lock ();
5194 if (timeout
== MONO_INFINITE_WAIT
) {
5195 while (UnlockedRead (&pending_joinable_thread_count
) > 0)
5196 mono_os_cond_wait (&zero_pending_joinable_thread_event
, &joinable_threads_mutex
);
5198 gint64 start
= mono_msec_ticks ();
5200 while (UnlockedRead (&pending_joinable_thread_count
) > 0 && elapsed
< timeout
) {
5201 mono_os_cond_timedwait (&zero_pending_joinable_thread_event
, &joinable_threads_mutex
, timeout
- (uint32_t)elapsed
);
5202 elapsed
= mono_msec_ticks () - start
;
5205 joinable_threads_unlock ();
5208 return UnlockedRead (&pending_joinable_thread_count
) == 0;
5212 threads_add_unique_joinable_thread_nolock (gpointer tid
)
5214 if (!joinable_threads
)
5215 joinable_threads
= g_hash_table_new (NULL
, NULL
);
5220 if (!g_hash_table_lookup_extended (joinable_threads
, tid
, &orig_key
, &value
)) {
5221 threads_add_joinable_thread_nolock (tid
);
5222 UnlockedIncrement (&joinable_thread_count
);
5227 mono_threads_add_joinable_runtime_thread (gpointer thread_info
)
5229 g_assert (thread_info
);
5230 MonoThreadInfo
*mono_thread_info
= (MonoThreadInfo
*)thread_info
;
5232 if (mono_thread_info
->runtime_thread
) {
5233 gpointer tid
= (gpointer
)(MONO_UINT_TO_NATIVE_THREAD_ID (mono_thread_info_get_tid (mono_thread_info
)));
5235 joinable_threads_lock ();
5237 // Add to joinable thread list, if not already included.
5238 threads_add_unique_joinable_thread_nolock (tid
);
5240 // Remove thread from pending joinable list, if present.
5241 threads_remove_pending_joinable_thread_nolock (tid
);
5243 joinable_threads_unlock ();
5245 mono_gc_finalize_notify ();
5250 * mono_add_joinable_thread:
5252 * Add TID to the list of joinable threads.
5253 * LOCKING: Acquires the threads lock.
5256 mono_threads_add_joinable_thread (gpointer tid
)
5259 * We cannot detach from threads because it causes problems like
5260 * 2fd16f60/r114307. So we collect them and join them when
5261 * we have time (in the finalizer thread).
5263 joinable_threads_lock ();
5264 threads_add_unique_joinable_thread_nolock (tid
);
5265 joinable_threads_unlock ();
5267 mono_gc_finalize_notify ();
5271 * mono_threads_join_threads:
5273 * Join all joinable threads. This is called from the finalizer thread.
5274 * LOCKING: Acquires the threads lock.
5277 mono_threads_join_threads (void)
5279 GHashTableIter iter
;
5285 if (!UnlockedRead (&joinable_thread_count
))
5289 joinable_threads_lock ();
5291 if (g_hash_table_size (joinable_threads
)) {
5292 g_hash_table_iter_init (&iter
, joinable_threads
);
5293 g_hash_table_iter_next (&iter
, &key
, (void**)&value
);
5294 g_hash_table_remove (joinable_threads
, key
);
5295 UnlockedDecrement (&joinable_thread_count
);
5298 joinable_threads_unlock ();
5300 threads_native_thread_join_lock (key
, value
);
5309 * Wait for thread TID to exit.
5310 * LOCKING: Acquires the threads lock.
5313 mono_thread_join (gpointer tid
)
5315 gboolean found
= FALSE
;
5319 joinable_threads_lock ();
5320 if (!joinable_threads
)
5321 joinable_threads
= g_hash_table_new (NULL
, NULL
);
5323 if (g_hash_table_lookup_extended (joinable_threads
, tid
, &orig_key
, &value
)) {
5324 g_hash_table_remove (joinable_threads
, tid
);
5325 UnlockedDecrement (&joinable_thread_count
);
5328 joinable_threads_unlock ();
5333 threads_native_thread_join_nolock (tid
, value
);
5337 mono_thread_internal_unhandled_exception (MonoObject
* exc
)
5339 MonoClass
*klass
= exc
->vtable
->klass
;
5340 if (is_threadabort_exception (klass
)) {
5341 mono_thread_internal_reset_abort (mono_thread_internal_current ());
5342 } else if (!is_appdomainunloaded_exception (klass
)
5343 && mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT
) {
5344 mono_unhandled_exception (exc
);
5345 if (mono_environment_exitcode_get () == 1) {
5346 mono_environment_exitcode_set (255);
5347 mono_invoke_unhandled_exception_hook (exc
);
5348 g_assert_not_reached ();
5354 ves_icall_System_Threading_Thread_GetStackTraces (MonoArray
**out_threads
, MonoArray
**out_stack_traces
)
5357 mono_threads_get_thread_dump (out_threads
, out_stack_traces
, error
);
5358 mono_error_set_pending_exception (error
);
5362 * mono_threads_attach_coop: called by native->managed wrappers
5365 * - blocking mode: contains gc unsafe transition cookie
5366 * - non-blocking mode: contains random data
5367 * - @return: the original domain which needs to be restored, or NULL.
5370 mono_threads_attach_coop (MonoDomain
*domain
, gpointer
*dummy
)
5373 MonoThreadInfo
*info
;
5376 orig
= mono_domain_get ();
5379 /* Happens when called from AOTed code which is only used in the root domain. */
5380 domain
= mono_get_root_domain ();
5384 /* On coop, when we detached, we moved the thread from RUNNING->BLOCKING.
5385 * If we try to reattach we do a BLOCKING->RUNNING transition. If the thread
5386 * is fresh, mono_thread_attach() will do a STARTING->RUNNING transition so
5387 * we're only responsible for making the cookie. */
5388 if (mono_threads_is_blocking_transition_enabled ())
5389 external
= !(info
= mono_thread_info_current_unchecked ()) || !mono_thread_info_is_live (info
);
5391 if (!mono_thread_internal_current ()) {
5392 mono_thread_attach (domain
);
5395 mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background
);
5399 mono_domain_set (domain
, TRUE
);
5401 if (mono_threads_is_blocking_transition_enabled ()) {
5403 /* mono_thread_attach put the thread in RUNNING mode from STARTING, but we need to
5404 * return the right cookie. */
5405 *dummy
= mono_threads_enter_gc_unsafe_region_cookie ();
5407 /* thread state (BLOCKING|RUNNING) -> RUNNING */
5408 *dummy
= mono_threads_enter_gc_unsafe_region (dummy
);
5416 * mono_threads_detach_coop: called by native->managed wrappers
5418 * - @cookie: the original domain which needs to be restored, or NULL.
5420 * - blocking mode: contains gc unsafe transition cookie
5421 * - non-blocking mode: contains random data
5424 mono_threads_detach_coop (gpointer cookie
, gpointer
*dummy
)
5426 MonoDomain
*domain
, *orig
;
5428 orig
= (MonoDomain
*) cookie
;
5430 domain
= mono_domain_get ();
5433 if (mono_threads_is_blocking_transition_enabled ()) {
5434 /* it won't do anything if cookie is NULL
5435 * thread state RUNNING -> (RUNNING|BLOCKING) */
5436 mono_threads_exit_gc_unsafe_region (*dummy
, dummy
);
5439 if (orig
!= domain
) {
5441 mono_domain_unset ();
5443 mono_domain_set (orig
, TRUE
);
5448 /* Returns TRUE if the current thread is ready to be interrupted. */
5450 mono_threads_is_ready_to_be_interrupted (void)
5452 MonoInternalThread
*thread
;
5454 thread
= mono_thread_internal_current ();
5455 LOCK_THREAD (thread
);
5456 if (thread
->state
& (ThreadState_SuspendRequested
| ThreadState_AbortRequested
)) {
5457 UNLOCK_THREAD (thread
);
5461 if (mono_thread_get_abort_prot_block_count (thread
) || mono_get_eh_callbacks ()->mono_current_thread_has_handle_block_guard ()) {
5462 UNLOCK_THREAD (thread
);
5466 UNLOCK_THREAD (thread
);
5472 mono_thread_internal_describe (MonoInternalThread
*internal
, GString
*text
)
5474 g_string_append_printf (text
, ", thread handle : %p", internal
->handle
);
5476 if (internal
->thread_info
) {
5477 g_string_append (text
, ", state : ");
5478 mono_thread_info_describe_interrupt_token ((MonoThreadInfo
*) internal
->thread_info
, text
);
5481 if (internal
->owned_mutexes
) {
5484 g_string_append (text
, ", owns : [");
5485 for (i
= 0; i
< internal
->owned_mutexes
->len
; i
++)
5486 g_string_append_printf (text
, i
== 0 ? "%p" : ", %p", g_ptr_array_index (internal
->owned_mutexes
, i
));
5487 g_string_append (text
, "]");
5492 mono_thread_internal_is_current (MonoInternalThread
*internal
)
5494 g_assert (internal
);
5495 return mono_native_thread_id_equals (mono_native_thread_id_get (), MONO_UINT_TO_NATIVE_THREAD_ID (internal
->tid
));