3 * Thread support internal calls
6 * Dick Porter (dick@ximian.com)
7 * Paolo Molaro (lupus@ximian.com)
8 * Patrik Torstensson (patrik.torstensson@labs2.com)
10 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
11 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
12 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
13 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
21 #include <mono/metadata/object.h>
22 #include <mono/metadata/domain-internals.h>
23 #include <mono/metadata/profiler-private.h>
24 #include <mono/metadata/threads.h>
25 #include <mono/metadata/threads-types.h>
26 #include <mono/metadata/exception.h>
27 #include <mono/metadata/environment.h>
28 #include <mono/metadata/monitor.h>
29 #include <mono/metadata/mono-hash-internals.h>
30 #include <mono/metadata/gc-internals.h>
31 #include <mono/metadata/marshal.h>
32 #include <mono/metadata/runtime.h>
33 #include <mono/metadata/object-internals.h>
34 #include <mono/metadata/debug-internals.h>
35 #include <mono/utils/monobitset.h>
36 #include <mono/utils/mono-compiler.h>
37 #include <mono/utils/mono-mmap.h>
38 #include <mono/utils/mono-membar.h>
39 #include <mono/utils/mono-time.h>
40 #include <mono/utils/mono-threads.h>
41 #include <mono/utils/mono-threads-coop.h>
42 #include <mono/utils/mono-tls.h>
43 #include <mono/utils/atomic.h>
44 #include <mono/utils/mono-memory-model.h>
45 #include <mono/utils/mono-error-internals.h>
46 #include <mono/utils/os-event.h>
47 #include <mono/utils/mono-threads-debug.h>
48 #include <mono/utils/unlocked.h>
49 #include <mono/metadata/w32handle.h>
50 #include <mono/metadata/w32event.h>
51 #include <mono/metadata/w32mutex.h>
53 #include <mono/metadata/reflection-internals.h>
54 #include <mono/metadata/abi-details.h>
55 #include <mono/metadata/w32error.h>
56 #include <mono/utils/w32api.h>
57 #include <mono/utils/mono-os-wait.h>
58 #include <mono/metadata/exception-internals.h>
59 #include <mono/utils/mono-state.h>
60 #include <mono/metadata/w32subset.h>
62 #ifdef HAVE_SYS_WAIT_H
70 #if defined(HOST_WIN32)
72 #include <sys/timeb.h>
74 mono_native_thread_join_handle (HANDLE thread_handle
, gboolean close_handle
);
77 #if defined(HOST_FUCHSIA)
78 #include <zircon/syscalls.h>
81 #if defined(HOST_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64)
82 #define USE_TKILL_ON_ANDROID 1
88 #ifdef USE_TKILL_ON_ANDROID
89 extern int tkill (pid_t tid
, int signal
);
93 #include "icall-decl.h"
95 /*#define THREAD_DEBUG(a) do { a; } while (0)*/
96 #define THREAD_DEBUG(a)
97 /*#define THREAD_WAIT_DEBUG(a) do { a; } while (0)*/
98 #define THREAD_WAIT_DEBUG(a)
99 /*#define LIBGC_DEBUG(a) do { a; } while (0)*/
100 #define LIBGC_DEBUG(a)
102 #define SPIN_TRYLOCK(i) (mono_atomic_cas_i32 (&(i), 1, 0) == 0)
103 #define SPIN_LOCK(i) do { \
104 if (SPIN_TRYLOCK (i)) \
108 #define SPIN_UNLOCK(i) i = 0
110 #define LOCK_THREAD(thread) lock_thread((thread))
111 #define UNLOCK_THREAD(thread) unlock_thread((thread))
123 typedef struct _StaticDataFreeList StaticDataFreeList
;
124 struct _StaticDataFreeList
{
125 StaticDataFreeList
*next
;
133 StaticDataFreeList
*freelist
;
136 /* Controls access to the 'threads' hash table */
137 static void mono_threads_lock (void);
138 static void mono_threads_unlock (void);
139 static MonoCoopMutex threads_mutex
;
141 /* Controls access to the 'joinable_threads' hash table */
142 #define joinable_threads_lock() mono_coop_mutex_lock (&joinable_threads_mutex)
143 #define joinable_threads_unlock() mono_coop_mutex_unlock (&joinable_threads_mutex)
144 static MonoCoopMutex joinable_threads_mutex
;
146 /* Holds current status of static data heap */
147 static StaticDataInfo thread_static_info
;
148 static StaticDataInfo context_static_info
;
150 /* The hash of existing threads (key is thread ID, value is
151 * MonoInternalThread*) that need joining before exit
153 static MonoGHashTable
*threads
=NULL
;
155 /* List of app context GC handles.
156 * Added to from mono_threads_register_app_context ().
158 static GHashTable
*contexts
= NULL
;
160 /* Cleanup queue for contexts. */
161 static MonoReferenceQueue
*context_queue
;
164 * Threads which are starting up and they are not in the 'threads' hash yet.
165 * When mono_thread_attach_internal is called for a thread, it will be removed from this hash table.
166 * Protected by mono_threads_lock ().
168 static MonoGHashTable
*threads_starting_up
= NULL
;
171 /* Protected by the threads lock */
172 static GHashTable
*joinable_threads
;
173 static gint32 joinable_thread_count
;
175 /* mono_threads_join_threads will take threads from joinable_threads list and wait for them. */
176 /* When this happens, the tid is not on the list anymore so mono_thread_join assumes the thread has complete */
177 /* and will return back to the caller. This could cause a race since caller of join assumes thread has completed */
178 /* and on some OS it could cause errors. Keeping the tid's currently pending a native thread join call */
179 /* in a separate table (only affecting callers interested in this internal join detail) and look at that table in mono_thread_join */
180 /* will close this race. */
181 static GHashTable
*pending_native_thread_join_calls
;
182 static MonoCoopCond pending_native_thread_join_calls_event
;
184 static GHashTable
*pending_joinable_threads
;
185 static gint32 pending_joinable_thread_count
;
187 static MonoCoopCond zero_pending_joinable_thread_event
;
189 static void threads_add_pending_joinable_runtime_thread (MonoThreadInfo
*mono_thread_info
);
190 static gboolean
threads_wait_pending_joinable_threads (uint32_t timeout
);
191 static gchar
* thread_dump_dir
= NULL
;
193 #define SET_CURRENT_OBJECT mono_tls_set_thread
194 #define GET_CURRENT_OBJECT mono_tls_get_thread
196 /* function called at thread start */
197 static MonoThreadStartCB mono_thread_start_cb
= NULL
;
199 /* function called at thread attach */
200 static MonoThreadAttachCB mono_thread_attach_cb
= NULL
;
202 /* function called at thread cleanup */
203 static MonoThreadCleanupFunc mono_thread_cleanup_fn
= NULL
;
205 /* The default stack size for each thread */
206 static guint32 default_stacksize
= 0;
207 #define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize)
209 static void context_adjust_static_data (MonoAppContextHandle ctx
);
210 static void mono_free_static_data (gpointer
* static_data
);
211 static void mono_init_static_data_info (StaticDataInfo
*static_data
);
212 static guint32
mono_alloc_static_data_slot (StaticDataInfo
*static_data
, guint32 size
, guint32 align
);
213 static gboolean
mono_thread_resume (MonoInternalThread
* thread
);
214 static void async_abort_internal (MonoInternalThread
*thread
, gboolean install_async_abort
);
215 static void self_abort_internal (MonoError
*error
);
216 static void async_suspend_internal (MonoInternalThread
*thread
, gboolean interrupt
);
217 static void self_suspend_internal (void);
220 mono_thread_set_interruption_requested_flags (MonoInternalThread
*thread
, gboolean sync
);
223 mono_set_pending_exception_handle (MonoExceptionHandle exc
);
225 static MonoException
*
226 mono_thread_execute_interruption_ptr (void);
229 mono_thread_execute_interruption_void (void);
232 mono_thread_execute_interruption (MonoExceptionHandle
*pexc
);
234 static void ref_stack_destroy (gpointer rs
);
236 #if SIZEOF_VOID_P == 4
237 /* Spin lock for unaligned InterlockedXXX 64 bit functions on 32bit platforms. */
238 #define mono_interlocked_lock() mono_os_mutex_lock (&interlocked_mutex)
239 #define mono_interlocked_unlock() mono_os_mutex_unlock (&interlocked_mutex)
240 static mono_mutex_t interlocked_mutex
;
243 /* global count of thread interruptions requested */
244 static gint32 thread_interruption_requested
= 0;
246 /* Event signaled when a thread changes its background mode */
247 static MonoOSEvent background_change_event
;
249 static gboolean shutting_down
= FALSE
;
251 static gint32 managed_thread_id_counter
= 0;
254 mono_threads_lock (void)
256 mono_locks_coop_acquire (&threads_mutex
, ThreadsLock
);
260 mono_threads_unlock (void)
262 mono_locks_coop_release (&threads_mutex
, ThreadsLock
);
267 get_next_managed_thread_id (void)
269 return mono_atomic_inc_i32 (&managed_thread_id_counter
);
273 * We separate interruptions/exceptions into either sync (they can be processed anytime,
274 * normally as soon as they are set, and are set by the same thread) and async (they can't
275 * be processed inside abort protected blocks and are normally set by other threads). We
276 * can have both a pending sync and async interruption. In this case, the sync exception is
277 * processed first. Since we clean sync flag first, mono_thread_execute_interruption must
278 * also handle all sync type exceptions before the async type exceptions.
281 INTERRUPT_SYNC_REQUESTED_BIT
= 0x1,
282 INTERRUPT_ASYNC_REQUESTED_BIT
= 0x2,
283 INTERRUPT_REQUESTED_MASK
= 0x3,
284 ABORT_PROT_BLOCK_SHIFT
= 2,
285 ABORT_PROT_BLOCK_BITS
= 8,
286 ABORT_PROT_BLOCK_MASK
= (((1 << ABORT_PROT_BLOCK_BITS
) - 1) << ABORT_PROT_BLOCK_SHIFT
)
290 mono_thread_get_abort_prot_block_count (MonoInternalThread
*thread
)
292 gsize state
= thread
->thread_state
;
293 return (state
& ABORT_PROT_BLOCK_MASK
) >> ABORT_PROT_BLOCK_SHIFT
;
297 mono_threads_is_current_thread_in_protected_block (void)
299 MonoInternalThread
*thread
= mono_thread_internal_current ();
301 return mono_thread_get_abort_prot_block_count (thread
) > 0;
305 mono_threads_begin_abort_protected_block (void)
307 MonoInternalThread
*thread
= mono_thread_internal_current ();
308 gsize old_state
, new_state
;
311 old_state
= thread
->thread_state
;
313 new_val
= ((old_state
& ABORT_PROT_BLOCK_MASK
) >> ABORT_PROT_BLOCK_SHIFT
) + 1;
314 //bounds check abort_prot_count
315 g_assert (new_val
> 0);
316 g_assert (new_val
< (1 << ABORT_PROT_BLOCK_BITS
));
318 new_state
= old_state
+ (1 << ABORT_PROT_BLOCK_SHIFT
);
319 } while (mono_atomic_cas_ptr ((volatile gpointer
*)&thread
->thread_state
, (gpointer
)new_state
, (gpointer
)old_state
) != (gpointer
)old_state
);
321 /* Defer async request since we won't be able to process until exiting the block */
322 if (new_val
== 1 && (new_state
& INTERRUPT_ASYNC_REQUESTED_BIT
)) {
323 mono_atomic_dec_i32 (&thread_interruption_requested
);
324 THREADS_INTERRUPT_DEBUG ("[%d] begin abort protected block old_state %ld new_state %ld, defer tir %d\n", thread
->small_id
, old_state
, new_state
, thread_interruption_requested
);
325 if (thread_interruption_requested
< 0)
326 g_warning ("bad thread_interruption_requested state");
328 THREADS_INTERRUPT_DEBUG ("[%d] begin abort protected block old_state %ld new_state %ld, tir %d\n", thread
->small_id
, old_state
, new_state
, thread_interruption_requested
);
333 mono_thread_state_has_interruption (gsize state
)
335 /* pending exception, self abort */
336 if (state
& INTERRUPT_SYNC_REQUESTED_BIT
)
339 /* abort, interruption, suspend */
340 if ((state
& INTERRUPT_ASYNC_REQUESTED_BIT
) && !(state
& ABORT_PROT_BLOCK_MASK
))
347 mono_threads_end_abort_protected_block (void)
349 MonoInternalThread
*thread
= mono_thread_internal_current ();
350 gsize old_state
, new_state
;
353 old_state
= thread
->thread_state
;
355 //bounds check abort_prot_count
356 new_val
= ((old_state
& ABORT_PROT_BLOCK_MASK
) >> ABORT_PROT_BLOCK_SHIFT
) - 1;
357 g_assert (new_val
>= 0);
358 g_assert (new_val
< (1 << ABORT_PROT_BLOCK_BITS
));
360 new_state
= old_state
- (1 << ABORT_PROT_BLOCK_SHIFT
);
361 } while (mono_atomic_cas_ptr ((volatile gpointer
*)&thread
->thread_state
, (gpointer
)new_state
, (gpointer
)old_state
) != (gpointer
)old_state
);
363 if (new_val
== 0 && (new_state
& INTERRUPT_ASYNC_REQUESTED_BIT
)) {
364 mono_atomic_inc_i32 (&thread_interruption_requested
);
365 THREADS_INTERRUPT_DEBUG ("[%d] end abort protected block old_state %ld new_state %ld, restore tir %d\n", thread
->small_id
, old_state
, new_state
, thread_interruption_requested
);
367 THREADS_INTERRUPT_DEBUG ("[%d] end abort protected block old_state %ld new_state %ld, tir %d\n", thread
->small_id
, old_state
, new_state
, thread_interruption_requested
);
370 return mono_thread_state_has_interruption (new_state
);
374 mono_thread_get_interruption_requested (MonoInternalThread
*thread
)
376 gsize state
= thread
->thread_state
;
378 return mono_thread_state_has_interruption (state
);
382 * Returns TRUE is there was a state change
383 * We clear a single interruption request, sync has priority.
386 mono_thread_clear_interruption_requested (MonoInternalThread
*thread
)
388 gsize old_state
, new_state
;
390 old_state
= thread
->thread_state
;
392 // no interruption to process
393 if (!(old_state
& INTERRUPT_SYNC_REQUESTED_BIT
) &&
394 (!(old_state
& INTERRUPT_ASYNC_REQUESTED_BIT
) || (old_state
& ABORT_PROT_BLOCK_MASK
)))
397 if (old_state
& INTERRUPT_SYNC_REQUESTED_BIT
)
398 new_state
= old_state
& ~INTERRUPT_SYNC_REQUESTED_BIT
;
400 new_state
= old_state
& ~INTERRUPT_ASYNC_REQUESTED_BIT
;
401 } while (mono_atomic_cas_ptr ((volatile gpointer
*)&thread
->thread_state
, (gpointer
)new_state
, (gpointer
)old_state
) != (gpointer
)old_state
);
403 mono_atomic_dec_i32 (&thread_interruption_requested
);
404 THREADS_INTERRUPT_DEBUG ("[%d] clear interruption old_state %ld new_state %ld, tir %d\n", thread
->small_id
, old_state
, new_state
, thread_interruption_requested
);
405 if (thread_interruption_requested
< 0)
406 g_warning ("bad thread_interruption_requested state");
411 mono_thread_clear_interruption_requested_handle (MonoInternalThreadHandle thread
)
413 // Internal threads are pinned so shallow coop/handle.
414 return mono_thread_clear_interruption_requested (mono_internal_thread_handle_ptr (thread
));
417 /* Returns TRUE is there was a state change and the interruption can be processed */
419 mono_thread_set_interruption_requested (MonoInternalThread
*thread
)
421 //always force when the current thread is doing it to itself.
422 gboolean sync
= thread
== mono_thread_internal_current ();
423 /* Normally synchronous interruptions can bypass abort protection. */
424 return mono_thread_set_interruption_requested_flags (thread
, sync
);
427 /* Returns TRUE if there was a state change and the interruption can be
428 * processed. This variant defers a self abort when inside an abort protected
429 * block. Normally this should only be done when a thread has received an
430 * outside indication that it should abort. (For example when the JIT sets a
431 * flag in an finally block.)
435 mono_thread_set_self_interruption_respect_abort_prot (void)
437 MonoInternalThread
*thread
= mono_thread_internal_current ();
438 /* N.B. Sets the ASYNC_REQUESTED_BIT for current this thread,
439 * which is unusual. */
440 return mono_thread_set_interruption_requested_flags (thread
, FALSE
);
443 /* Returns TRUE if there was a state change and the interruption can be processed. */
445 mono_thread_set_interruption_requested_flags (MonoInternalThread
*thread
, gboolean sync
)
447 gsize old_state
, new_state
;
449 old_state
= thread
->thread_state
;
452 if ((sync
&& (old_state
& INTERRUPT_SYNC_REQUESTED_BIT
)) ||
453 (!sync
&& (old_state
& INTERRUPT_ASYNC_REQUESTED_BIT
)))
457 new_state
= old_state
| INTERRUPT_SYNC_REQUESTED_BIT
;
459 new_state
= old_state
| INTERRUPT_ASYNC_REQUESTED_BIT
;
460 } while (mono_atomic_cas_ptr ((volatile gpointer
*)&thread
->thread_state
, (gpointer
)new_state
, (gpointer
)old_state
) != (gpointer
)old_state
);
462 if (sync
|| !(new_state
& ABORT_PROT_BLOCK_MASK
)) {
463 mono_atomic_inc_i32 (&thread_interruption_requested
);
464 THREADS_INTERRUPT_DEBUG ("[%d] set interruption on [%d] old_state %ld new_state %ld, tir %d\n", mono_thread_internal_current ()->small_id
, thread
->small_id
, old_state
, new_state
, thread_interruption_requested
);
466 THREADS_INTERRUPT_DEBUG ("[%d] set interruption on [%d] old_state %ld new_state %ld, tir deferred %d\n", mono_thread_internal_current ()->small_id
, thread
->small_id
, old_state
, new_state
, thread_interruption_requested
);
469 return sync
|| !(new_state
& ABORT_PROT_BLOCK_MASK
);
472 static inline MonoNativeThreadId
473 thread_get_tid (MonoInternalThread
*thread
)
475 /* We store the tid as a guint64 to keep the object layout constant between platforms */
476 return MONO_UINT_TO_NATIVE_THREAD_ID (thread
->tid
);
480 free_synch_cs (MonoCoopMutex
*synch_cs
)
483 mono_coop_mutex_destroy (synch_cs
);
488 free_longlived_thread_data (void *user_data
)
490 MonoLongLivedThreadData
*lltd
= (MonoLongLivedThreadData
*)user_data
;
491 free_synch_cs (lltd
->synch_cs
);
497 init_longlived_thread_data (MonoLongLivedThreadData
*lltd
)
499 mono_refcount_init (lltd
, free_longlived_thread_data
);
500 mono_refcount_inc (lltd
);
501 /* Initial refcount is 2: decremented once by
502 * mono_thread_detach_internal and once by the MonoInternalThread
503 * finalizer - whichever one happens later will deallocate. */
505 lltd
->synch_cs
= g_new0 (MonoCoopMutex
, 1);
506 mono_coop_mutex_init_recursive (lltd
->synch_cs
);
508 mono_memory_barrier ();
512 dec_longlived_thread_data (MonoLongLivedThreadData
*lltd
)
514 mono_refcount_dec (lltd
);
518 lock_thread (MonoInternalThread
*thread
)
520 g_assert (thread
->longlived
);
521 g_assert (thread
->longlived
->synch_cs
);
523 mono_coop_mutex_lock (thread
->longlived
->synch_cs
);
527 unlock_thread (MonoInternalThread
*thread
)
529 mono_coop_mutex_unlock (thread
->longlived
->synch_cs
);
533 lock_thread_handle (MonoInternalThreadHandle thread
)
535 lock_thread (mono_internal_thread_handle_ptr (thread
));
539 unlock_thread_handle (MonoInternalThreadHandle thread
)
541 unlock_thread (mono_internal_thread_handle_ptr (thread
));
544 static inline gboolean
545 is_appdomainunloaded_exception (MonoClass
*klass
)
547 #ifdef ENABLE_NETCORE
550 return klass
== mono_class_get_appdomain_unloaded_exception_class ();
554 static inline gboolean
555 is_threadabort_exception (MonoClass
*klass
)
557 return klass
== mono_defaults
.threadabortexception_class
;
561 * A special static data offset (guint32) consists of 3 parts:
563 * [0] 6-bit index into the array of chunks.
564 * [6] 25-bit offset into the array.
565 * [31] Bit indicating thread or context static.
570 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
581 } SpecialStaticOffset
;
583 #define SPECIAL_STATIC_OFFSET_TYPE_THREAD 0
584 #define SPECIAL_STATIC_OFFSET_TYPE_CONTEXT 1
587 MAKE_SPECIAL_STATIC_OFFSET (guint32 index
, guint32 offset
, guint32 type
)
589 SpecialStaticOffset special_static_offset
;
590 memset (&special_static_offset
, 0, sizeof (special_static_offset
));
591 special_static_offset
.fields
.index
= index
;
592 special_static_offset
.fields
.offset
= offset
;
593 special_static_offset
.fields
.type
= type
;
594 return special_static_offset
.raw
;
597 #define ACCESS_SPECIAL_STATIC_OFFSET(x,f) \
598 (((SpecialStaticOffset *) &(x))->fields.f)
601 get_thread_static_data (MonoInternalThread
*thread
, guint32 offset
)
603 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset
, type
) == SPECIAL_STATIC_OFFSET_TYPE_THREAD
);
605 int idx
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, index
);
606 int off
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, offset
);
608 return ((char *) thread
->static_data
[idx
]) + off
;
612 get_context_static_data (MonoAppContext
*ctx
, guint32 offset
)
614 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset
, type
) == SPECIAL_STATIC_OFFSET_TYPE_CONTEXT
);
616 int idx
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, index
);
617 int off
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, offset
);
619 return ((char *) ctx
->static_data
[idx
]) + off
;
623 get_current_thread_ptr_for_domain (MonoDomain
*domain
, MonoInternalThread
*thread
)
625 static MonoClassField
*current_thread_field
= NULL
;
629 if (!current_thread_field
) {
630 current_thread_field
= mono_class_get_field_from_name_full (mono_defaults
.thread_class
, "current_thread", NULL
);
631 g_assert (current_thread_field
);
634 ERROR_DECL (thread_vt_error
);
635 mono_class_vtable_checked (domain
, mono_defaults
.thread_class
, thread_vt_error
);
636 mono_error_assert_ok (thread_vt_error
);
637 mono_domain_lock (domain
);
638 offset
= GPOINTER_TO_UINT (g_hash_table_lookup (domain
->special_static_fields
, current_thread_field
));
639 mono_domain_unlock (domain
);
642 return (MonoThread
**)get_thread_static_data (thread
, offset
);
646 set_current_thread_for_domain (MonoDomain
*domain
, MonoInternalThread
*thread
, MonoThread
*current
)
648 #ifndef ENABLE_NETCORE
649 MonoThread
**current_thread_ptr
= get_current_thread_ptr_for_domain (domain
, thread
);
651 g_assert (current
->obj
.vtable
->domain
== domain
);
653 g_assert (!*current_thread_ptr
);
654 *current_thread_ptr
= current
;
659 create_thread_object (MonoDomain
*domain
, MonoInternalThread
*internal
)
661 #ifdef ENABLE_NETCORE
662 MONO_OBJECT_SETREF_INTERNAL (internal
, internal_thread
, internal
);
669 vtable
= mono_class_vtable_checked (domain
, mono_defaults
.thread_class
, error
);
670 mono_error_assert_ok (error
);
672 thread
= (MonoThread
*)mono_object_new_mature (vtable
, error
);
673 /* only possible failure mode is OOM, from which we don't expect to recover. */
674 mono_error_assert_ok (error
);
676 MONO_OBJECT_SETREF_INTERNAL (thread
, internal_thread
, internal
);
683 init_internal_thread_object (MonoInternalThread
*thread
)
685 thread
->longlived
= g_new0 (MonoLongLivedThreadData
, 1);
686 init_longlived_thread_data (thread
->longlived
);
688 thread
->apartment_state
= ThreadApartmentState_Unknown
;
689 thread
->managed_id
= get_next_managed_thread_id ();
690 if (mono_gc_is_moving ()) {
691 thread
->thread_pinning_ref
= thread
;
692 MONO_GC_REGISTER_ROOT_PINNING (thread
->thread_pinning_ref
, MONO_ROOT_SOURCE_THREADING
, NULL
, "Thread Pinning Reference");
695 thread
->priority
= MONO_THREAD_PRIORITY_NORMAL
;
697 thread
->suspended
= g_new0 (MonoOSEvent
, 1);
698 mono_os_event_init (thread
->suspended
, TRUE
);
701 static MonoInternalThread
*
702 create_internal_thread_object (void)
705 MonoInternalThread
*thread
;
708 vt
= mono_class_vtable_checked (mono_get_root_domain (), mono_defaults
.internal_thread_class
, error
);
709 mono_error_assert_ok (error
);
710 thread
= (MonoInternalThread
*) mono_object_new_mature (vt
, error
);
711 /* only possible failure mode is OOM, from which we don't exect to recover */
712 mono_error_assert_ok (error
);
714 init_internal_thread_object (thread
);
720 mono_thread_internal_set_priority (MonoInternalThread
*internal
, MonoThreadPriority priority
)
724 g_assert (priority
>= MONO_THREAD_PRIORITY_LOWEST
);
725 g_assert (priority
<= MONO_THREAD_PRIORITY_HIGHEST
);
726 g_assert (MONO_THREAD_PRIORITY_LOWEST
< MONO_THREAD_PRIORITY_HIGHEST
);
732 g_assert (internal
->native_handle
);
735 res
= SetThreadPriority (internal
->native_handle
, (int)priority
- 2);
736 last_error
= GetLastError ();
739 g_error ("%s: SetThreadPriority failed, error %d", __func__
, last_error
);
740 #elif defined(HOST_FUCHSIA)
743 if (priority
== MONO_THREAD_PRIORITY_LOWEST
)
744 z_priority
= ZX_PRIORITY_LOWEST
;
745 else if (priority
== MONO_THREAD_PRIORITY_BELOW_NORMAL
)
746 z_priority
= ZX_PRIORITY_LOW
;
747 else if (priority
== MONO_THREAD_PRIORITY_NORMAL
)
748 z_priority
= ZX_PRIORITY_DEFAULT
;
749 else if (priority
== MONO_THREAD_PRIORITY_ABOVE_NORMAL
)
750 z_priority
= ZX_PRIORITY_HIGH
;
751 else if (priority
== MONO_THREAD_PRIORITY_HIGHEST
)
752 z_priority
= ZX_PRIORITY_HIGHEST
;
757 // When this API becomes available on an arbitrary thread, we can use it,
758 // not available on current Zircon
760 #else /* !HOST_WIN32 and not HOST_FUCHSIA */
763 struct sched_param param
;
766 tid
= thread_get_tid (internal
);
769 res
= pthread_getschedparam (tid
, &policy
, ¶m
);
772 g_error ("%s: pthread_getschedparam failed, error: \"%s\" (%d)", __func__
, g_strerror (res
), res
);
774 #ifdef _POSIX_PRIORITY_SCHEDULING
777 /* Necessary to get valid priority range */
780 #if defined(__PASE__)
781 /* only priorities allowed by IBM i */
785 min
= sched_get_priority_min (policy
);
786 max
= sched_get_priority_max (policy
);
790 if (max
> 0 && min
>= 0 && max
> min
) {
791 double srange
, drange
, sposition
, dposition
;
792 srange
= MONO_THREAD_PRIORITY_HIGHEST
- MONO_THREAD_PRIORITY_LOWEST
;
794 sposition
= priority
- MONO_THREAD_PRIORITY_LOWEST
;
795 dposition
= (sposition
/ srange
) * drange
;
796 param
.sched_priority
= (int)(dposition
+ min
);
803 param
.sched_priority
= 50;
809 param
.sched_priority
= 0;
812 g_warning ("%s: unknown policy %d", __func__
, policy
);
818 #if defined(__PASE__)
819 /* only scheduling param allowed by IBM i */
820 res
= pthread_setschedparam (tid
, SCHED_OTHER
, ¶m
);
822 res
= pthread_setschedparam (tid
, policy
, ¶m
);
828 /* AIX doesn't like doing this and will spam this every time;
829 * weirdly, i doesn't complain
831 g_warning ("%s: pthread_setschedparam failed, error: \"%s\" (%d)", __func__
, g_strerror (res
), res
);
835 g_error ("%s: pthread_setschedparam failed, error: \"%s\" (%d)", __func__
, g_strerror (res
), res
);
837 #endif /* HOST_WIN32 */
841 mono_alloc_static_data (gpointer
**static_data_ptr
, guint32 offset
, void *alloc_key
, gboolean threadlocal
);
844 mono_thread_attach_internal (MonoThread
*thread
, gboolean force_attach
, gboolean force_domain
)
846 MonoThreadInfo
*info
;
847 MonoInternalThread
*internal
;
848 MonoDomain
*domain
, *root_domain
;
853 info
= mono_thread_info_current ();
856 internal
= thread
->internal_thread
;
859 /* It is needed to store the MonoInternalThread on the MonoThreadInfo, because of the following case:
860 * - the MonoInternalThread TLS key is destroyed: set it to NULL
861 * - the MonoThreadInfo TLS key is destroyed: calls mono_thread_info_detach
862 * - it calls MonoThreadInfoCallbacks.thread_detach
863 * - mono_thread_internal_current returns NULL -> fails to detach the MonoInternalThread. */
864 mono_thread_info_set_internal_thread_gchandle (info
, mono_gchandle_new_internal ((MonoObject
*) internal
, FALSE
));
866 internal
->handle
= mono_threads_open_thread_handle (info
->handle
);
867 internal
->native_handle
= MONO_NATIVE_THREAD_HANDLE_TO_GPOINTER (mono_threads_open_native_thread_handle (info
->native_handle
));
868 internal
->tid
= MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ());
869 internal
->thread_info
= info
;
870 internal
->small_id
= info
->small_id
;
872 THREAD_DEBUG (g_message ("%s: (%" G_GSIZE_FORMAT
") Setting current_object_key to %p", __func__
, mono_native_thread_id_get (), internal
));
874 SET_CURRENT_OBJECT (internal
);
876 domain
= mono_object_domain (thread
);
878 mono_thread_push_appdomain_ref (domain
);
879 if (!mono_domain_set_fast (domain
, force_domain
)) {
880 mono_thread_pop_appdomain_ref ();
884 mono_threads_lock ();
886 if (shutting_down
&& !force_attach
) {
887 mono_threads_unlock ();
888 mono_thread_pop_appdomain_ref ();
892 if (threads_starting_up
)
893 mono_g_hash_table_remove (threads_starting_up
, thread
);
896 threads
= mono_g_hash_table_new_type_internal (NULL
, NULL
, MONO_HASH_VALUE_GC
, MONO_ROOT_SOURCE_THREADING
, NULL
, "Thread Table");
899 /* We don't need to duplicate thread->handle, because it is
900 * only closed when the thread object is finalized by the GC. */
901 mono_g_hash_table_insert_internal (threads
, (gpointer
)(gsize
)(internal
->tid
), internal
);
903 /* We have to do this here because mono_thread_start_cb
904 * requires that root_domain_thread is set up. */
905 if (thread_static_info
.offset
|| thread_static_info
.idx
> 0) {
906 /* get the current allocated size */
907 guint32 offset
= MAKE_SPECIAL_STATIC_OFFSET (thread_static_info
.idx
, thread_static_info
.offset
, 0);
908 mono_alloc_static_data (&internal
->static_data
, offset
, (void *) MONO_UINT_TO_NATIVE_THREAD_ID (internal
->tid
), TRUE
);
911 mono_threads_unlock ();
913 root_domain
= mono_get_root_domain ();
915 g_assert (!internal
->root_domain_thread
);
916 if (domain
!= root_domain
)
917 MONO_OBJECT_SETREF_INTERNAL (internal
, root_domain_thread
, create_thread_object (root_domain
, internal
));
919 MONO_OBJECT_SETREF_INTERNAL (internal
, root_domain_thread
, thread
);
921 if (domain
!= root_domain
)
922 set_current_thread_for_domain (root_domain
, internal
, internal
->root_domain_thread
);
924 set_current_thread_for_domain (domain
, internal
, thread
);
926 THREAD_DEBUG (g_message ("%s: Attached thread ID %" G_GSIZE_FORMAT
" (handle %p)", __func__
, internal
->tid
, internal
->handle
));
931 mono_threads_lock ();
932 if (threads_starting_up
)
933 mono_g_hash_table_remove (threads_starting_up
, thread
);
934 mono_threads_unlock ();
936 if (!mono_thread_info_try_get_internal_thread_gchandle (info
, &gchandle
))
937 g_error ("%s: failed to get gchandle, info %p", __func__
, info
);
939 mono_gchandle_free_internal (gchandle
);
941 mono_thread_info_unset_internal_thread_gchandle (info
);
943 SET_CURRENT_OBJECT(NULL
);
949 mono_thread_detach_internal (MonoInternalThread
*thread
)
951 MonoThreadInfo
*info
;
952 MonoInternalThread
*value
;
956 g_assert (mono_thread_internal_is_current (thread
));
958 g_assert (thread
!= NULL
);
959 SET_CURRENT_OBJECT (thread
);
961 info
= thread
->thread_info
;
964 THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%" G_GSIZE_FORMAT
")", __func__
, thread
, (gsize
)thread
->tid
));
966 MONO_PROFILER_RAISE (thread_stopping
, (thread
->tid
));
969 * Prevent race condition between thread shutdown and runtime shutdown.
970 * Including all runtime threads in the pending joinable count will make
971 * sure shutdown will wait for it to get onto the joinable thread list before
972 * critical resources have been cleanup (like GC memory). Threads getting onto
973 * the joinable thread list should just about to exit and not blocking a potential
974 * join call. Owner of threads attached to the runtime but not identified as runtime
975 * threads needs to make sure thread detach calls won't race with runtime shutdown.
977 threads_add_pending_joinable_runtime_thread (info
);
980 mono_w32mutex_abandon (thread
);
983 mono_gchandle_free_internal (thread
->abort_state_handle
);
984 thread
->abort_state_handle
= 0;
986 thread
->abort_exc
= NULL
;
987 thread
->current_appcontext
= NULL
;
989 LOCK_THREAD (thread
);
991 thread
->state
|= ThreadState_Stopped
;
992 thread
->state
&= ~ThreadState_Background
;
994 UNLOCK_THREAD (thread
);
997 An interruption request has leaked to cleanup. Adjust the global counter.
999 This can happen is the abort source thread finds the abortee (this) thread
1000 in unmanaged code. If this thread never trips back to managed code or check
1001 the local flag it will be left set and positively unbalance the global counter.
1003 Leaving the counter unbalanced will cause a performance degradation since all threads
1004 will now keep checking their local flags all the time.
1006 mono_thread_clear_interruption_requested (thread
);
1008 mono_threads_lock ();
1012 if (!mono_g_hash_table_lookup_extended (threads
, (gpointer
)thread
->tid
, NULL
, (gpointer
*) &value
)) {
1013 g_error ("%s: thread %p (tid: %p) should not have been removed yet from threads", __func__
, thread
, thread
->tid
);
1014 } else if (thread
!= value
) {
1015 /* We have to check whether the thread object for the tid is still the same in the table because the
1016 * thread might have been destroyed and the tid reused in the meantime, in which case the tid would be in
1017 * the table, but with another thread object. */
1018 g_error ("%s: thread %p (tid: %p) do not match with value %p (tid: %p)", __func__
, thread
, thread
->tid
, value
, value
->tid
);
1021 removed
= mono_g_hash_table_remove (threads
, (gpointer
)thread
->tid
);
1024 mono_threads_unlock ();
1026 /* Don't close the handle here, wait for the object finalizer
1027 * to do it. Otherwise, the following race condition applies:
1029 * 1) Thread exits (and mono_thread_detach_internal() closes the handle)
1031 * 2) Some other handle is reassigned the same slot
1033 * 3) Another thread tries to join the first thread, and
1034 * blocks waiting for the reassigned handle to be signalled
1035 * (which might never happen). This is possible, because the
1036 * thread calling Join() still has a reference to the first
1040 mono_release_type_locks (thread
);
1042 MONO_PROFILER_RAISE (thread_stopped
, (thread
->tid
));
1043 MONO_PROFILER_RAISE (gc_root_unregister
, ((const mono_byte
*)(info
->stack_start_limit
)));
1044 MONO_PROFILER_RAISE (gc_root_unregister
, ((const mono_byte
*)(info
->handle_stack
)));
1047 * This will signal async signal handlers that the thread has exited.
1048 * The profiler callback needs this to be set, so it cannot be done earlier.
1050 mono_domain_unset ();
1051 mono_memory_barrier ();
1053 mono_thread_pop_appdomain_ref ();
1055 mono_free_static_data (thread
->static_data
);
1056 thread
->static_data
= NULL
;
1057 ref_stack_destroy (thread
->appdomain_refs
);
1058 thread
->appdomain_refs
= NULL
;
1060 g_assert (thread
->suspended
);
1061 mono_os_event_destroy (thread
->suspended
);
1062 g_free (thread
->suspended
);
1063 thread
->suspended
= NULL
;
1065 if (mono_thread_cleanup_fn
)
1066 mono_thread_cleanup_fn (thread_get_tid (thread
));
1068 mono_memory_barrier ();
1070 if (mono_gc_is_moving ()) {
1071 MONO_GC_UNREGISTER_ROOT (thread
->thread_pinning_ref
);
1072 thread
->thread_pinning_ref
= NULL
;
1075 /* There is no more any guarantee that `thread` is alive */
1076 mono_memory_barrier ();
1078 SET_CURRENT_OBJECT (NULL
);
1079 mono_domain_unset ();
1081 if (!mono_thread_info_try_get_internal_thread_gchandle (info
, &gchandle
))
1082 g_error ("%s: failed to get gchandle, info = %p", __func__
, info
);
1084 mono_gchandle_free_internal (gchandle
);
1086 mono_thread_info_unset_internal_thread_gchandle (info
);
1088 /* Possibly free synch_cs, if the finalizer for InternalThread already
1090 dec_longlived_thread_data (thread
->longlived
);
1092 MONO_PROFILER_RAISE (thread_exited
, (thread
->tid
));
1094 /* Don't need to close the handle to this thread, even though we took a
1095 * reference in mono_thread_attach (), because the GC will do it
1096 * when the Thread object is finalised.
1103 MonoObject
*start_delegate
;
1104 MonoObject
*start_delegate_arg
;
1105 MonoThreadStart start_func
;
1106 gpointer start_func_arg
;
1107 gboolean force_attach
;
1109 MonoCoopSem registered
;
1113 fire_attach_profiler_events (MonoNativeThreadId tid
)
1115 MONO_PROFILER_RAISE (thread_started
, ((uintptr_t) tid
));
1117 MonoThreadInfo
*info
= mono_thread_info_current ();
1119 MONO_PROFILER_RAISE (gc_root_register
, (
1120 (const mono_byte
*)(info
->stack_start_limit
),
1121 (char *) info
->stack_end
- (char *) info
->stack_start_limit
,
1122 MONO_ROOT_SOURCE_STACK
,
1126 // The handle stack is a pseudo-root similar to the finalizer queues.
1127 MONO_PROFILER_RAISE (gc_root_register
, (
1128 (const mono_byte
*)info
->handle_stack
,
1130 MONO_ROOT_SOURCE_HANDLE
,
1135 static guint32 WINAPI
1136 start_wrapper_internal (StartInfo
*start_info
, gsize
*stack_ptr
)
1139 MonoThreadStart start_func
;
1140 void *start_func_arg
;
1143 * We don't create a local to hold start_info->thread, so hopefully it won't get pinned during a
1147 MonoInternalThread
*internal
;
1148 MonoObject
*start_delegate
;
1149 MonoObject
*start_delegate_arg
;
1151 thread
= start_info
->thread
;
1152 internal
= thread
->internal_thread
;
1154 THREAD_DEBUG (g_message ("%s: (%" G_GSIZE_FORMAT
") Start wrapper", __func__
, mono_native_thread_id_get ()));
1156 if (!mono_thread_attach_internal (thread
, start_info
->force_attach
, FALSE
)) {
1157 start_info
->failed
= TRUE
;
1159 mono_coop_sem_post (&start_info
->registered
);
1161 if (mono_atomic_dec_i32 (&start_info
->ref
) == 0) {
1162 mono_coop_sem_destroy (&start_info
->registered
);
1163 g_free (start_info
);
1169 mono_thread_internal_set_priority (internal
, (MonoThreadPriority
)internal
->priority
);
1171 tid
= internal
->tid
;
1173 start_delegate
= start_info
->start_delegate
;
1174 start_delegate_arg
= start_info
->start_delegate_arg
;
1175 start_func
= start_info
->start_func
;
1176 start_func_arg
= start_info
->start_func_arg
;
1178 /* This MUST be called before any managed code can be
1179 * executed, as it calls the callback function that (for the
1180 * jit) sets the lmf marker.
1183 if (mono_thread_start_cb
)
1184 mono_thread_start_cb (tid
, stack_ptr
, (gpointer
)start_func
);
1186 /* On 2.0 profile (and higher), set explicitly since state might have been
1188 if (internal
->apartment_state
== ThreadApartmentState_Unknown
)
1189 internal
->apartment_state
= ThreadApartmentState_MTA
;
1191 mono_thread_init_apartment_state ();
1193 /* Let the thread that called Start() know we're ready */
1194 mono_coop_sem_post (&start_info
->registered
);
1196 if (mono_atomic_dec_i32 (&start_info
->ref
) == 0) {
1197 mono_coop_sem_destroy (&start_info
->registered
);
1198 g_free (start_info
);
1201 /* start_info is not valid anymore */
1205 * Call this after calling start_notify, since the profiler callback might want
1206 * to lock the thread, and the lock is held by thread_start () which waits for
1209 fire_attach_profiler_events ((MonoNativeThreadId
) tid
);
1211 /* if the name was set before starting, we didn't invoke the profiler callback */
1212 if (internal
->name
) {
1213 char *tname
= g_utf16_to_utf8 (internal
->name
, internal
->name_len
, NULL
, NULL
, NULL
);
1214 MONO_PROFILER_RAISE (thread_name
, (internal
->tid
, tname
));
1215 mono_native_thread_set_name (MONO_UINT_TO_NATIVE_THREAD_ID (internal
->tid
), tname
);
1219 /* start_func is set only for unmanaged start functions */
1221 start_func (start_func_arg
);
1223 #ifdef ENABLE_NETCORE
1224 static MonoMethod
*cb
;
1226 /* Call a callback in the RuntimeThread class */
1227 g_assert (start_delegate
== NULL
);
1229 cb
= mono_class_get_method_from_name_checked (internal
->obj
.vtable
->klass
, "StartCallback", 0, 0, error
);
1231 mono_error_assert_ok (error
);
1233 mono_runtime_invoke_checked (cb
, internal
, NULL
, error
);
1237 g_assert (start_delegate
!= NULL
);
1239 /* we may want to handle the exception here. See comment below on unhandled exceptions */
1240 args
[0] = (gpointer
) start_delegate_arg
;
1241 mono_runtime_delegate_invoke_checked (start_delegate
, args
, error
);
1244 if (!mono_error_ok (error
)) {
1245 MonoException
*ex
= mono_error_convert_to_exception (error
);
1247 g_assert (ex
!= NULL
);
1248 MonoClass
*klass
= mono_object_class (ex
);
1249 if ((mono_runtime_unhandled_exception_policy_get () != MONO_UNHANDLED_POLICY_LEGACY
) &&
1250 !is_threadabort_exception (klass
)) {
1251 mono_unhandled_exception_internal (&ex
->object
);
1252 mono_invoke_unhandled_exception_hook (&ex
->object
);
1253 g_assert_not_reached ();
1256 mono_error_cleanup (error
);
1260 /* If the thread calls ExitThread at all, this remaining code
1261 * will not be executed, but the main thread will eventually
1262 * call mono_thread_detach_internal() on this thread's behalf.
1265 THREAD_DEBUG (g_message ("%s: (%" G_GSIZE_FORMAT
") Start wrapper terminating", __func__
, mono_native_thread_id_get ()));
1267 /* Do any cleanup needed for apartment state. This
1268 * cannot be done in mono_thread_detach_internal since
1269 * mono_thread_detach_internal could be called for a
1270 * thread other than the current thread.
1271 * mono_thread_cleanup_apartment_state cleans up apartment
1272 * for the current thead */
1273 mono_thread_cleanup_apartment_state ();
1275 mono_thread_detach_internal (internal
);
1280 static mono_thread_start_return_t WINAPI
1281 start_wrapper (gpointer data
)
1283 StartInfo
*start_info
;
1284 MonoThreadInfo
*info
;
1287 start_info
= (StartInfo
*) data
;
1288 g_assert (start_info
);
1290 info
= mono_thread_info_attach ();
1291 info
->runtime_thread
= TRUE
;
1293 /* Run the actual main function of the thread */
1294 res
= start_wrapper_internal (start_info
, (gsize
*)info
->stack_end
);
1296 mono_thread_info_exit (res
);
1298 g_assert_not_reached ();
1304 * Common thread creation code.
1305 * LOCKING: Acquires the threads lock.
1308 create_thread (MonoThread
*thread
, MonoInternalThread
*internal
, MonoObject
*start_delegate
, MonoThreadStart start_func
, gpointer start_func_arg
,
1309 MonoThreadCreateFlags flags
, MonoError
*error
)
1311 StartInfo
*start_info
= NULL
;
1312 MonoNativeThreadId tid
;
1314 gsize stack_set_size
;
1317 g_assert (!start_func
&& !start_func_arg
);
1319 g_assert (!start_delegate
);
1321 if (flags
& MONO_THREAD_CREATE_FLAGS_THREADPOOL
) {
1322 g_assert (!(flags
& MONO_THREAD_CREATE_FLAGS_DEBUGGER
));
1323 g_assert (!(flags
& MONO_THREAD_CREATE_FLAGS_FORCE_CREATE
));
1325 if (flags
& MONO_THREAD_CREATE_FLAGS_DEBUGGER
) {
1326 g_assert (!(flags
& MONO_THREAD_CREATE_FLAGS_THREADPOOL
));
1327 g_assert (!(flags
& MONO_THREAD_CREATE_FLAGS_FORCE_CREATE
));
1331 * Join joinable threads to prevent running out of threads since the finalizer
1332 * thread might be blocked/backlogged.
1334 mono_threads_join_threads ();
1338 mono_threads_lock ();
1339 if (shutting_down
&& !(flags
& MONO_THREAD_CREATE_FLAGS_FORCE_CREATE
)) {
1340 mono_threads_unlock ();
1341 mono_error_set_execution_engine (error
, "Couldn't create thread. Runtime is shutting down.");
1344 if (threads_starting_up
== NULL
) {
1345 threads_starting_up
= mono_g_hash_table_new_type_internal (NULL
, NULL
, MONO_HASH_KEY_VALUE_GC
, MONO_ROOT_SOURCE_THREADING
, NULL
, "Thread Starting Table");
1347 mono_g_hash_table_insert_internal (threads_starting_up
, thread
, thread
);
1348 mono_threads_unlock ();
1350 internal
->threadpool_thread
= flags
& MONO_THREAD_CREATE_FLAGS_THREADPOOL
;
1351 if (internal
->threadpool_thread
)
1352 mono_thread_set_state (internal
, ThreadState_Background
);
1354 internal
->debugger_thread
= flags
& MONO_THREAD_CREATE_FLAGS_DEBUGGER
;
1356 start_info
= g_new0 (StartInfo
, 1);
1357 start_info
->ref
= 2;
1358 start_info
->thread
= thread
;
1359 start_info
->start_delegate
= start_delegate
;
1360 start_info
->start_delegate_arg
= thread
->start_obj
;
1361 start_info
->start_func
= start_func
;
1362 start_info
->start_func_arg
= start_func_arg
;
1363 start_info
->force_attach
= flags
& MONO_THREAD_CREATE_FLAGS_FORCE_CREATE
;
1364 start_info
->failed
= FALSE
;
1365 mono_coop_sem_init (&start_info
->registered
, 0);
1367 if (flags
!= MONO_THREAD_CREATE_FLAGS_SMALL_STACK
)
1368 stack_set_size
= default_stacksize_for_thread (internal
);
1372 if (!mono_thread_platform_create_thread (start_wrapper
, start_info
, &stack_set_size
, &tid
)) {
1373 /* The thread couldn't be created, so set an exception */
1374 mono_threads_lock ();
1375 mono_g_hash_table_remove (threads_starting_up
, thread
);
1376 mono_threads_unlock ();
1377 mono_error_set_execution_engine (error
, "Couldn't create thread. Error 0x%x", mono_w32error_get_last());
1378 /* ref is not going to be decremented in start_wrapper_internal */
1379 mono_atomic_dec_i32 (&start_info
->ref
);
1384 internal
->stack_size
= (int) stack_set_size
;
1386 THREAD_DEBUG (g_message ("%s: (%" G_GSIZE_FORMAT
") Launching thread %p (%" G_GSIZE_FORMAT
")", __func__
, mono_native_thread_id_get (), internal
, (gsize
)internal
->tid
));
1389 * Wait for the thread to set up its TLS data etc, so
1390 * theres no potential race condition if someone tries
1391 * to look up the data believing the thread has
1395 mono_coop_sem_wait (&start_info
->registered
, MONO_SEM_FLAGS_NONE
);
1397 THREAD_DEBUG (g_message ("%s: (%" G_GSIZE_FORMAT
") Done launching thread %p (%" G_GSIZE_FORMAT
")", __func__
, mono_native_thread_id_get (), internal
, (gsize
)internal
->tid
));
1399 ret
= !start_info
->failed
;
1402 if (mono_atomic_dec_i32 (&start_info
->ref
) == 0) {
1403 mono_coop_sem_destroy (&start_info
->registered
);
1404 g_free (start_info
);
1411 * mono_thread_new_init:
1414 mono_thread_new_init (intptr_t tid
, gpointer stack_start
, gpointer func
)
1416 if (mono_thread_start_cb
) {
1417 mono_thread_start_cb (tid
, stack_start
, func
);
1422 * mono_threads_set_default_stacksize:
1425 mono_threads_set_default_stacksize (guint32 stacksize
)
1427 default_stacksize
= stacksize
;
1431 * mono_threads_get_default_stacksize:
1434 mono_threads_get_default_stacksize (void)
1436 return default_stacksize
;
1440 * mono_thread_create_internal:
1442 * ARG should not be a GC reference.
1445 mono_thread_create_internal (MonoDomain
*domain
, gpointer func
, gpointer arg
, MonoThreadCreateFlags flags
, MonoError
*error
)
1448 MonoInternalThread
*internal
;
1453 internal
= create_internal_thread_object ();
1455 thread
= create_thread_object (domain
, internal
);
1457 LOCK_THREAD (internal
);
1459 res
= create_thread (thread
, internal
, NULL
, (MonoThreadStart
) func
, arg
, flags
, error
);
1462 UNLOCK_THREAD (internal
);
1464 return_val_if_nok (error
, NULL
);
1468 MonoInternalThreadHandle
1469 mono_thread_create_internal_handle (MonoDomain
*domain
, gpointer func
, gpointer arg
, MonoThreadCreateFlags flags
, MonoError
*error
)
1472 return MONO_HANDLE_NEW (MonoInternalThread
, mono_thread_create_internal (domain
, func
, arg
, flags
, error
));
1476 * mono_thread_create:
1479 mono_thread_create (MonoDomain
*domain
, gpointer func
, gpointer arg
)
1481 MONO_ENTER_GC_UNSAFE
;
1483 if (!mono_thread_create_checked (domain
, func
, arg
, error
))
1484 mono_error_cleanup (error
);
1485 MONO_EXIT_GC_UNSAFE
;
1489 mono_thread_create_checked (MonoDomain
*domain
, gpointer func
, gpointer arg
, MonoError
*error
)
1491 return (NULL
!= mono_thread_create_internal (domain
, func
, arg
, MONO_THREAD_CREATE_FLAGS_NONE
, error
));
1495 * mono_thread_attach:
1498 mono_thread_attach (MonoDomain
*domain
)
1500 MonoInternalThread
*internal
;
1502 MonoThreadInfo
*info
;
1503 MonoNativeThreadId tid
;
1505 if (mono_thread_internal_current_is_attached ()) {
1506 if (domain
!= mono_domain_get ())
1507 mono_domain_set_fast (domain
, TRUE
);
1508 /* Already attached */
1509 return mono_thread_current ();
1512 info
= mono_thread_info_attach ();
1515 tid
=mono_native_thread_id_get ();
1517 if (mono_runtime_get_no_exec ())
1520 internal
= create_internal_thread_object ();
1522 thread
= create_thread_object (domain
, internal
);
1524 if (!mono_thread_attach_internal (thread
, FALSE
, TRUE
)) {
1525 /* Mono is shutting down, so just wait for the end */
1527 mono_thread_info_sleep (10000, NULL
);
1530 THREAD_DEBUG (g_message ("%s: Attached thread ID %" G_GSIZE_FORMAT
" (handle %p)", __func__
, tid
, internal
->handle
));
1532 if (mono_thread_attach_cb
)
1533 mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid
), info
->stack_end
);
1535 fire_attach_profiler_events (tid
);
1541 * mono_thread_detach:
1544 mono_thread_detach (MonoThread
*thread
)
1547 mono_thread_detach_internal (thread
->internal_thread
);
1551 * mono_thread_detach_if_exiting:
1553 * Detach the current thread from the runtime if it is exiting, i.e. it is running pthread dtors.
1554 * This should be used at the end of embedding code which calls into managed code, and which
1555 * can be called from pthread dtors, like <code>dealloc:</code> implementations in Objective-C.
1558 mono_thread_detach_if_exiting (void)
1560 if (mono_thread_info_is_exiting ()) {
1561 MonoInternalThread
*thread
;
1563 thread
= mono_thread_internal_current ();
1565 // Switch to GC Unsafe thread state before detaching;
1566 // don't expect to undo this switch, hence unbalanced.
1568 (void) mono_threads_enter_gc_unsafe_region_unbalanced (&dummy
);
1570 mono_thread_detach_internal (thread
);
1571 mono_thread_info_detach ();
1579 mono_thread_internal_current_is_attached (void)
1581 MonoInternalThread
*internal
;
1583 internal
= GET_CURRENT_OBJECT ();
1594 mono_thread_exit (void)
1596 MonoInternalThread
*thread
= mono_thread_internal_current ();
1598 THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%" G_GSIZE_FORMAT
")", __func__
, thread
, (gsize
)thread
->tid
));
1600 mono_thread_detach_internal (thread
);
1602 /* we could add a callback here for embedders to use. */
1603 if (mono_thread_get_main () && (thread
== mono_thread_get_main ()->internal_thread
))
1604 exit (mono_environment_exitcode_get ());
1606 mono_thread_info_exit (0);
1610 mono_thread_construct_internal (MonoThreadObjectHandle this_obj_handle
)
1612 MonoInternalThread
* const internal
= create_internal_thread_object ();
1614 internal
->state
= ThreadState_Unstarted
;
1616 int const thread_gchandle
= mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject
, this_obj_handle
), TRUE
);
1618 MonoThreadObject
*this_obj
= MONO_HANDLE_RAW (this_obj_handle
);
1620 mono_atomic_cas_ptr ((volatile gpointer
*)&this_obj
->internal_thread
, internal
, NULL
);
1622 mono_gchandle_free_internal (thread_gchandle
);
1625 #ifndef ENABLE_NETCORE
1627 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThreadObjectHandle this_obj_handle
, MonoError
*error
)
1629 mono_thread_construct_internal (this_obj_handle
);
1633 MonoThreadObjectHandle
1634 ves_icall_System_Threading_Thread_GetCurrentThread (MonoError
*error
)
1636 return MONO_HANDLE_NEW (MonoThreadObject
, mono_thread_current ());
1639 static MonoInternalThread
*
1640 thread_handle_to_internal_ptr (MonoThreadObjectHandle thread_handle
)
1642 return MONO_HANDLE_GETVAL(thread_handle
, internal_thread
); // InternalThreads are always pinned.
1646 mono_error_set_exception_thread_state (MonoError
*error
, const char *exception_message
)
1648 mono_error_set_generic_error (error
, "System.Threading", "ThreadStateException", "%s", exception_message
);
1652 mono_error_set_exception_thread_not_started_or_dead (MonoError
*error
)
1654 mono_error_set_exception_thread_state (error
, "Thread has not been started, or is dead.");
1657 #ifndef ENABLE_NETCORE
1659 ves_icall_System_Threading_Thread_Thread_internal (MonoThreadObjectHandle thread_handle
, MonoObjectHandle start_handle
, MonoError
*error
)
1661 MonoInternalThread
*internal
;
1663 MonoThread
*this_obj
= MONO_HANDLE_RAW (thread_handle
);
1664 MonoObject
*start
= MONO_HANDLE_RAW (start_handle
);
1666 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__
, this_obj
, start
));
1668 internal
= thread_handle_to_internal_ptr (thread_handle
);
1671 mono_thread_construct_internal (thread_handle
);
1672 internal
= thread_handle_to_internal_ptr (thread_handle
);
1673 g_assert (internal
);
1676 LOCK_THREAD (internal
);
1678 if ((internal
->state
& ThreadState_Unstarted
) == 0) {
1679 UNLOCK_THREAD (internal
);
1680 mono_error_set_exception_thread_state (error
, "Thread has already been started.");
1684 if ((internal
->state
& ThreadState_Aborted
) != 0) {
1685 UNLOCK_THREAD (internal
);
1689 res
= create_thread (this_obj
, internal
, start
, NULL
, NULL
, MONO_THREAD_CREATE_FLAGS_NONE
, error
);
1691 UNLOCK_THREAD (internal
);
1695 internal
->state
&= ~ThreadState_Unstarted
;
1697 THREAD_DEBUG (g_message ("%s: Started thread ID %" G_GSIZE_FORMAT
" (handle %p)", __func__
, tid
, thread
));
1699 UNLOCK_THREAD (internal
);
1705 * This is called from the finalizer of the internal thread object.
1708 ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThreadHandle this_obj_handle
, MonoError
*error
)
1710 MonoInternalThread
*this_obj
= mono_internal_thread_handle_ptr (this_obj_handle
);
1711 THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__
, this_obj
, this_obj
->handle
));
1714 * Since threads keep a reference to their thread object while running, by
1715 * the time this function is called, the thread has already exited/detached,
1716 * i.e. mono_thread_detach_internal () has ran. The exception is during
1717 * shutdown, when mono_thread_detach_internal () can be called after this.
1719 if (this_obj
->handle
) {
1720 mono_threads_close_thread_handle (this_obj
->handle
);
1721 this_obj
->handle
= NULL
;
1724 mono_threads_close_native_thread_handle (MONO_GPOINTER_TO_NATIVE_THREAD_HANDLE (this_obj
->native_handle
));
1725 this_obj
->native_handle
= NULL
;
1727 /* Possibly free synch_cs, if the thread already detached also. */
1728 dec_longlived_thread_data (this_obj
->longlived
);
1731 if (this_obj
->name
) {
1732 void *name
= this_obj
->name
;
1733 this_obj
->name
= NULL
;
1739 ves_icall_System_Threading_Thread_Sleep_internal (gint32 ms
, MonoError
*error
)
1741 THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__
, ms
));
1743 if (mono_thread_current_check_pending_interrupt ())
1746 MonoInternalThread
* const thread
= mono_thread_internal_current ();
1748 HANDLE_LOOP_PREPARE
;
1751 gboolean alerted
= FALSE
;
1753 mono_thread_set_state (thread
, ThreadState_WaitSleepJoin
);
1755 (void)mono_thread_info_sleep (ms
, &alerted
);
1757 mono_thread_clr_state (thread
, ThreadState_WaitSleepJoin
);
1764 MonoExceptionHandle exc
= MONO_HANDLE_NEW (MonoException
, NULL
);
1766 const gboolean interrupt
= mono_thread_execute_interruption (&exc
);
1769 mono_set_pending_exception_handle (exc
);
1775 if (ms
== MONO_INFINITE_WAIT
) // FIXME: !MONO_INFINITE_WAIT
1782 ves_icall_System_Threading_Thread_SpinWait_nop (MonoError
*error
)
1786 #ifndef ENABLE_NETCORE
1788 ves_icall_System_Threading_Thread_GetDomainID (MonoError
*error
)
1790 return mono_domain_get()->domain_id
;
1795 * mono_thread_get_name_utf8:
1796 * \returns the name of the thread in UTF-8.
1797 * Return NULL if the thread has no name.
1798 * The returned memory is owned by the caller (g_free it).
1801 mono_thread_get_name_utf8 (MonoThread
*thread
)
1806 MonoInternalThread
*internal
= thread
->internal_thread
;
1807 if (internal
== NULL
)
1810 LOCK_THREAD (internal
);
1812 char *tname
= g_utf16_to_utf8 (internal
->name
, internal
->name_len
, NULL
, NULL
, NULL
);
1814 UNLOCK_THREAD (internal
);
1820 * mono_thread_get_managed_id:
1821 * \returns the \c Thread.ManagedThreadId value of \p thread.
1822 * Returns \c -1 if \p thread is NULL.
1825 mono_thread_get_managed_id (MonoThread
*thread
)
1830 MonoInternalThread
*internal
= thread
->internal_thread
;
1831 if (internal
== NULL
)
1834 int32_t id
= internal
->managed_id
;
1839 #ifndef ENABLE_NETCORE
1841 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThreadHandle thread_handle
, MonoError
*error
)
1843 // InternalThreads are always pinned, so shallowly coop-handleize.
1844 MonoInternalThread
* const this_obj
= mono_internal_thread_handle_ptr (thread_handle
);
1846 MonoStringHandle str
= MONO_HANDLE_NEW (MonoString
, NULL
);
1848 LOCK_THREAD (this_obj
);
1851 MONO_HANDLE_ASSIGN (str
, mono_string_new_utf16_handle (mono_domain_get (), this_obj
->name
, this_obj
->name_len
, error
));
1853 UNLOCK_THREAD (this_obj
);
1860 mono_thread_set_name_internal (MonoInternalThread
*this_obj
,
1862 MonoSetThreadNameFlags flags
, MonoError
*error
)
1864 MonoNativeThreadId tid
= 0;
1866 LOCK_THREAD (this_obj
);
1868 if (flags
& MonoSetThreadNameFlag_Reset
) {
1869 this_obj
->flags
&= ~MONO_THREAD_FLAG_NAME_SET
;
1870 } else if (this_obj
->flags
& MONO_THREAD_FLAG_NAME_SET
) {
1871 UNLOCK_THREAD (this_obj
);
1873 mono_error_set_invalid_operation (error
, "%s", "Thread.Name can only be set once.");
1876 if (this_obj
->name
) {
1877 g_free (this_obj
->name
);
1878 this_obj
->name_len
= 0;
1881 this_obj
->name
= g_memdup (mono_string_chars_internal (name
), mono_string_length_internal (name
) * sizeof (gunichar2
));
1882 this_obj
->name_len
= mono_string_length_internal (name
);
1884 if (flags
& MonoSetThreadNameFlag_Permanent
)
1885 this_obj
->flags
|= MONO_THREAD_FLAG_NAME_SET
;
1888 this_obj
->name
= NULL
;
1890 if (!(this_obj
->state
& ThreadState_Stopped
))
1891 tid
= thread_get_tid (this_obj
);
1893 UNLOCK_THREAD (this_obj
);
1895 if (this_obj
->name
&& tid
) {
1896 char *tname
= mono_string_to_utf8_checked_internal (name
, error
);
1897 return_if_nok (error
);
1898 MONO_PROFILER_RAISE (thread_name
, ((uintptr_t)tid
, tname
));
1899 mono_native_thread_set_name (tid
, tname
);
1903 mono_thread_set_name_windows (this_obj
->native_handle
, name
? mono_string_chars_internal (name
) : NULL
);
1907 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread
*this_obj
, MonoString
*name
)
1910 mono_thread_set_name_internal (this_obj
, name
, MonoSetThreadNameFlag_Permanent
, error
);
1911 mono_error_set_pending_exception (error
);
1914 #ifndef ENABLE_NETCORE
1916 * ves_icall_System_Threading_Thread_GetPriority_internal:
1917 * @param this_obj: The MonoInternalThread on which to operate.
1919 * Gets the priority of the given thread.
1920 * @return: The priority of the given thread.
1923 ves_icall_System_Threading_Thread_GetPriority (MonoThreadObjectHandle this_obj
, MonoError
*error
)
1927 MonoInternalThread
*internal
= thread_handle_to_internal_ptr (this_obj
);
1929 LOCK_THREAD (internal
);
1930 priority
= internal
->priority
;
1931 UNLOCK_THREAD (internal
);
1938 * ves_icall_System_Threading_Thread_SetPriority_internal:
1939 * @param this_obj: The MonoInternalThread on which to operate.
1940 * @param priority: The priority to set.
1942 * Sets the priority of the given thread.
1945 ves_icall_System_Threading_Thread_SetPriority (MonoThreadObjectHandle this_obj
, int priority
, MonoError
*error
)
1947 MonoInternalThread
*internal
= thread_handle_to_internal_ptr (this_obj
);
1949 LOCK_THREAD (internal
);
1950 internal
->priority
= priority
;
1951 if (internal
->thread_info
!= NULL
)
1952 mono_thread_internal_set_priority (internal
, (MonoThreadPriority
)priority
);
1953 UNLOCK_THREAD (internal
);
1956 /* If the array is already in the requested domain, we just return it,
1957 otherwise we return a copy in that domain. */
1958 static MonoArrayHandle
1959 byte_array_to_domain (MonoArrayHandle arr
, MonoDomain
*domain
, MonoError
*error
)
1961 HANDLE_FUNCTION_ENTER ()
1963 if (MONO_HANDLE_IS_NULL (arr
))
1964 return MONO_HANDLE_NEW (MonoArray
, NULL
);
1966 if (MONO_HANDLE_DOMAIN (arr
) == domain
)
1969 size_t const size
= mono_array_handle_length (arr
);
1971 // Capture arrays into common representation for repetitious code.
1972 // These two variables could also be an array of size 2 and
1973 // repitition implemented with a loop.
1975 MonoArrayHandle handle
;
1980 dest
= { mono_array_new_handle (domain
, mono_defaults
.byte_class
, size
, error
) };
1981 goto_if_nok (error
, exit
);
1984 source
.p
= mono_array_handle_pin_with_size (source
.handle
, size
, 0, &source
.gchandle
);
1985 dest
.p
= mono_array_handle_pin_with_size (dest
.handle
, size
, 0, &dest
.gchandle
);
1987 memmove (dest
.p
, source
.p
, size
);
1989 // Unpin both arrays.
1990 mono_gchandle_free_internal (source
.gchandle
);
1991 mono_gchandle_free_internal (dest
.gchandle
);
1993 HANDLE_FUNCTION_RETURN_REF (MonoArray
, dest
.handle
)
1996 #ifndef ENABLE_NETCORE
1998 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArrayHandle arr
, MonoError
*error
)
2000 return byte_array_to_domain (arr
, mono_get_root_domain (), error
);
2004 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArrayHandle arr
, MonoError
*error
)
2006 return byte_array_to_domain (arr
, mono_domain_get (), error
);
2011 * mono_thread_current:
2014 mono_thread_current (void)
2016 #ifdef ENABLE_NETCORE
2017 return mono_thread_internal_current ();
2019 MonoDomain
*domain
= mono_domain_get ();
2020 MonoInternalThread
*internal
= mono_thread_internal_current ();
2021 MonoThread
**current_thread_ptr
;
2023 g_assert (internal
);
2024 current_thread_ptr
= get_current_thread_ptr_for_domain (domain
, internal
);
2026 if (!*current_thread_ptr
) {
2027 g_assert (domain
!= mono_get_root_domain ());
2028 *current_thread_ptr
= create_thread_object (domain
, internal
);
2030 return *current_thread_ptr
;
2034 static MonoThreadObjectHandle
2035 mono_thread_current_handle (void)
2037 return MONO_HANDLE_NEW (MonoThreadObject
, mono_thread_current ());
2040 /* Return the thread object belonging to INTERNAL in the current domain */
2042 mono_thread_current_for_thread (MonoInternalThread
*internal
)
2044 #ifdef ENABLE_NETCORE
2045 return mono_thread_internal_current ();
2047 MonoDomain
*domain
= mono_domain_get ();
2048 MonoThread
**current_thread_ptr
;
2050 g_assert (internal
);
2051 current_thread_ptr
= get_current_thread_ptr_for_domain (domain
, internal
);
2053 if (!*current_thread_ptr
) {
2054 g_assert (domain
!= mono_get_root_domain ());
2055 *current_thread_ptr
= create_thread_object (domain
, internal
);
2057 return *current_thread_ptr
;
2062 mono_thread_internal_current (void)
2064 MonoInternalThread
*res
= GET_CURRENT_OBJECT ();
2065 THREAD_DEBUG (g_message ("%s: returning %p", __func__
, res
));
2069 MonoInternalThreadHandle
2070 mono_thread_internal_current_handle (void)
2072 return MONO_HANDLE_NEW (MonoInternalThread
, mono_thread_internal_current ());
2075 static MonoThreadInfoWaitRet
2076 mono_join_uninterrupted (MonoThreadHandle
* thread_to_join
, gint32 ms
, MonoError
*error
)
2078 MonoThreadInfoWaitRet ret
;
2081 const gint64 start
= (ms
== -1) ? 0 : mono_msec_ticks ();
2084 ret
= mono_thread_info_wait_one_handle (thread_to_join
, wait
, TRUE
);
2087 if (ret
!= MONO_THREAD_INFO_WAIT_RET_ALERTED
)
2090 MonoException
*exc
= mono_thread_execute_interruption_ptr ();
2092 mono_error_set_exception_instance (error
, exc
);
2099 /* Re-calculate ms according to the time passed */
2100 const gint32 diff_ms
= (gint32
)(mono_msec_ticks () - start
);
2101 if (diff_ms
>= ms
) {
2102 ret
= MONO_THREAD_INFO_WAIT_RET_TIMEOUT
;
2105 wait
= ms
- diff_ms
;
2112 ves_icall_System_Threading_Thread_Join_internal (MonoThreadObjectHandle thread_handle
, int ms
, MonoError
*error
)
2114 if (mono_thread_current_check_pending_interrupt ())
2117 // Internal threads are pinned so shallow coop/handle.
2118 MonoInternalThread
* const thread
= thread_handle_to_internal_ptr (thread_handle
);
2119 MonoThreadHandle
*handle
= thread
->handle
;
2120 MonoInternalThread
*cur_thread
= mono_thread_internal_current ();
2121 gboolean ret
= FALSE
;
2123 LOCK_THREAD (thread
);
2125 if ((thread
->state
& ThreadState_Unstarted
) != 0) {
2126 UNLOCK_THREAD (thread
);
2128 mono_error_set_exception_thread_state (error
, "Thread has not been started.");
2132 UNLOCK_THREAD (thread
);
2135 ms
= MONO_INFINITE_WAIT
;
2136 THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__
, handle
, ms
));
2138 mono_thread_set_state (cur_thread
, ThreadState_WaitSleepJoin
);
2140 ret
= mono_join_uninterrupted (handle
, ms
, error
);
2142 mono_thread_clr_state (cur_thread
, ThreadState_WaitSleepJoin
);
2144 if (ret
== MONO_THREAD_INFO_WAIT_RET_SUCCESS_0
) {
2145 THREAD_DEBUG (g_message ("%s: join successful", __func__
));
2147 mono_error_assert_ok (error
);
2149 /* Wait for the thread to really exit */
2150 MonoNativeThreadId tid
= thread_get_tid (thread
);
2151 mono_thread_join ((gpointer
)(gsize
)tid
);
2156 THREAD_DEBUG (g_message ("%s: join failed", __func__
));
2161 #define MANAGED_WAIT_FAILED 0x7fffffff
2164 map_native_wait_result_to_managed (MonoW32HandleWaitRet val
, gsize numobjects
)
2166 if (val
>= MONO_W32HANDLE_WAIT_RET_SUCCESS_0
&& val
< MONO_W32HANDLE_WAIT_RET_SUCCESS_0
+ numobjects
) {
2167 return WAIT_OBJECT_0
+ (val
- MONO_W32HANDLE_WAIT_RET_SUCCESS_0
);
2168 } else if (val
>= MONO_W32HANDLE_WAIT_RET_ABANDONED_0
&& val
< MONO_W32HANDLE_WAIT_RET_ABANDONED_0
+ numobjects
) {
2169 return WAIT_ABANDONED_0
+ (val
- MONO_W32HANDLE_WAIT_RET_ABANDONED_0
);
2170 } else if (val
== MONO_W32HANDLE_WAIT_RET_ALERTED
) {
2171 return WAIT_IO_COMPLETION
;
2172 } else if (val
== MONO_W32HANDLE_WAIT_RET_TIMEOUT
) {
2173 return WAIT_TIMEOUT
;
2174 } else if (val
== MONO_W32HANDLE_WAIT_RET_TOO_MANY_POSTS
) {
2175 return WAIT_TOO_MANY_POSTS
;
2176 } else if (val
== MONO_W32HANDLE_WAIT_RET_NOT_OWNED_BY_CALLER
) {
2177 return WAIT_NOT_OWNED_BY_CALLER
;
2178 } else if (val
== MONO_W32HANDLE_WAIT_RET_FAILED
) {
2179 /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
2180 return MANAGED_WAIT_FAILED
;
2182 g_error ("%s: unknown val value %d", __func__
, val
);
2187 ves_icall_System_Threading_WaitHandle_Wait_internal (gpointer
*handles
, gint32 numhandles
, MonoBoolean waitall
, gint32 timeout
, MonoError
*error
)
2189 /* Do this WaitSleepJoin check before creating objects */
2190 if (mono_thread_current_check_pending_interrupt ())
2191 return map_native_wait_result_to_managed (MONO_W32HANDLE_WAIT_RET_FAILED
, 0);
2193 MonoInternalThread
* const thread
= mono_thread_internal_current ();
2195 mono_thread_set_state (thread
, ThreadState_WaitSleepJoin
);
2200 timeout
= MONO_INFINITE_WAIT
;
2201 if (timeout
!= MONO_INFINITE_WAIT
)
2202 start
= mono_msec_ticks ();
2204 guint32 timeoutLeft
= timeout
;
2206 MonoW32HandleWaitRet ret
;
2208 HANDLE_LOOP_PREPARE
;
2212 /* mono_w32handle_wait_multiple optimizes the case for numhandles == 1 */
2213 ret
= mono_w32handle_wait_multiple (handles
, numhandles
, waitall
, timeoutLeft
, TRUE
, error
);
2215 if (ret
!= MONO_W32HANDLE_WAIT_RET_ALERTED
)
2220 MonoExceptionHandle exc
= MONO_HANDLE_NEW (MonoException
, NULL
);
2222 const gboolean interrupt
= mono_thread_execute_interruption (&exc
);
2225 mono_error_set_exception_handle (error
, exc
);
2232 if (timeout
!= MONO_INFINITE_WAIT
) {
2233 gint64
const elapsed
= mono_msec_ticks () - start
;
2234 if (elapsed
>= timeout
) {
2235 ret
= MONO_W32HANDLE_WAIT_RET_TIMEOUT
;
2239 timeoutLeft
= timeout
- elapsed
;
2243 mono_thread_clr_state (thread
, ThreadState_WaitSleepJoin
);
2245 return map_native_wait_result_to_managed (ret
, numhandles
);
2248 #if HAVE_API_SUPPORT_WIN32_SIGNAL_OBJECT_AND_WAIT
2250 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (gpointer toSignal
, gpointer toWait
, gint32 ms
, MonoError
*error
)
2252 MonoW32HandleWaitRet ret
;
2253 MonoInternalThread
*thread
= mono_thread_internal_current ();
2256 ms
= MONO_INFINITE_WAIT
;
2258 if (mono_thread_current_check_pending_interrupt ())
2259 return map_native_wait_result_to_managed (MONO_W32HANDLE_WAIT_RET_FAILED
, 0);
2261 mono_thread_set_state (thread
, ThreadState_WaitSleepJoin
);
2263 ret
= mono_w32handle_signal_and_wait (toSignal
, toWait
, ms
, TRUE
);
2265 mono_thread_clr_state (thread
, ThreadState_WaitSleepJoin
);
2267 return map_native_wait_result_to_managed (ret
, 1);
2272 gint32
ves_icall_System_Threading_Interlocked_Increment_Int (gint32
*location
)
2274 return mono_atomic_inc_i32 (location
);
2277 gint64
ves_icall_System_Threading_Interlocked_Increment_Long (gint64
*location
)
2279 #if SIZEOF_VOID_P == 4
2280 if (G_UNLIKELY ((size_t)location
& 0x7)) {
2282 mono_interlocked_lock ();
2285 mono_interlocked_unlock ();
2289 return mono_atomic_inc_i64 (location
);
2292 gint32
ves_icall_System_Threading_Interlocked_Decrement_Int (gint32
*location
)
2294 return mono_atomic_dec_i32(location
);
2297 gint64
ves_icall_System_Threading_Interlocked_Decrement_Long (gint64
* location
)
2299 #if SIZEOF_VOID_P == 4
2300 if (G_UNLIKELY ((size_t)location
& 0x7)) {
2302 mono_interlocked_lock ();
2305 mono_interlocked_unlock ();
2309 return mono_atomic_dec_i64 (location
);
2312 gint32
ves_icall_System_Threading_Interlocked_Exchange_Int (gint32
*location
, gint32 value
)
2314 return mono_atomic_xchg_i32(location
, value
);
2317 MonoObject
* ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject
**location
, MonoObject
*value
)
2320 res
= (MonoObject
*) mono_atomic_xchg_ptr((gpointer
*) location
, value
);
2321 mono_gc_wbarrier_generic_nostore_internal (location
);
2325 gpointer
ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer
*location
, gpointer value
)
2327 return mono_atomic_xchg_ptr(location
, value
);
2330 gfloat
ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat
*location
, gfloat value
)
2332 IntFloatUnion val
, ret
;
2335 ret
.ival
= mono_atomic_xchg_i32((gint32
*) location
, val
.ival
);
2341 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64
*location
, gint64 value
)
2343 #if SIZEOF_VOID_P == 4
2344 if (G_UNLIKELY ((size_t)location
& 0x7)) {
2346 mono_interlocked_lock ();
2349 mono_interlocked_unlock ();
2353 return mono_atomic_xchg_i64 (location
, value
);
2357 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble
*location
, gdouble value
)
2359 LongDoubleUnion val
, ret
;
2362 ret
.ival
= (gint64
)mono_atomic_xchg_i64((gint64
*) location
, val
.ival
);
2367 gint32
ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32
*location
, gint32 value
, gint32 comparand
)
2369 return mono_atomic_cas_i32(location
, value
, comparand
);
2372 gint32
ves_icall_System_Threading_Interlocked_CompareExchange_Int_Success(gint32
*location
, gint32 value
, gint32 comparand
, MonoBoolean
*success
)
2374 gint32 r
= mono_atomic_cas_i32(location
, value
, comparand
);
2375 *success
= r
== comparand
;
2379 MonoObject
* ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject
**location
, MonoObject
*value
, MonoObject
*comparand
)
2382 res
= (MonoObject
*) mono_atomic_cas_ptr((gpointer
*) location
, value
, comparand
);
2383 mono_gc_wbarrier_generic_nostore_internal (location
);
2387 gpointer
ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer
*location
, gpointer value
, gpointer comparand
)
2389 return mono_atomic_cas_ptr(location
, value
, comparand
);
2392 gfloat
ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat
*location
, gfloat value
, gfloat comparand
)
2394 IntFloatUnion val
, ret
, cmp
;
2397 cmp
.fval
= comparand
;
2398 ret
.ival
= mono_atomic_cas_i32((gint32
*) location
, val
.ival
, cmp
.ival
);
2404 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble
*location
, gdouble value
, gdouble comparand
)
2406 #if SIZEOF_VOID_P == 8
2407 LongDoubleUnion val
, comp
, ret
;
2410 comp
.fval
= comparand
;
2411 ret
.ival
= (gint64
)mono_atomic_cas_ptr((gpointer
*) location
, (gpointer
)val
.ival
, (gpointer
)comp
.ival
);
2417 mono_interlocked_lock ();
2419 if (old
== comparand
)
2421 mono_interlocked_unlock ();
2428 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64
*location
, gint64 value
, gint64 comparand
)
2430 #if SIZEOF_VOID_P == 4
2431 if (G_UNLIKELY ((size_t)location
& 0x7)) {
2433 mono_interlocked_lock ();
2435 if (old
== comparand
)
2437 mono_interlocked_unlock ();
2441 return mono_atomic_cas_i64 (location
, value
, comparand
);
2445 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject
**location
, MonoObject
*value
, MonoObject
*comparand
)
2448 res
= (MonoObject
*)mono_atomic_cas_ptr ((volatile gpointer
*)location
, value
, comparand
);
2449 mono_gc_wbarrier_generic_nostore_internal (location
);
2454 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject
**location
, MonoObject
*value
)
2457 MONO_CHECK_NULL (location
, NULL
);
2458 res
= (MonoObject
*)mono_atomic_xchg_ptr ((volatile gpointer
*)location
, value
);
2459 mono_gc_wbarrier_generic_nostore_internal (location
);
2464 ves_icall_System_Threading_Interlocked_Add_Int (gint32
*location
, gint32 value
)
2466 return mono_atomic_add_i32 (location
, value
);
2470 ves_icall_System_Threading_Interlocked_Add_Long (gint64
*location
, gint64 value
)
2472 #if SIZEOF_VOID_P == 4
2473 if (G_UNLIKELY ((size_t)location
& 0x7)) {
2475 mono_interlocked_lock ();
2478 mono_interlocked_unlock ();
2482 return mono_atomic_add_i64 (location
, value
);
2486 ves_icall_System_Threading_Interlocked_Read_Long (gint64
*location
)
2488 #if SIZEOF_VOID_P == 4
2489 if (G_UNLIKELY ((size_t)location
& 0x7)) {
2491 mono_interlocked_lock ();
2493 mono_interlocked_unlock ();
2497 return mono_atomic_load_i64 (location
);
2501 ves_icall_System_Threading_Interlocked_MemoryBarrierProcessWide (void)
2503 mono_memory_barrier_process_wide ();
2507 ves_icall_System_Threading_Thread_MemoryBarrier (void)
2509 mono_memory_barrier ();
2513 ves_icall_System_Threading_Thread_ClrState (MonoInternalThreadHandle this_obj
, guint32 state
, MonoError
*error
)
2515 // InternalThreads are always pinned, so shallowly coop-handleize.
2516 mono_thread_clr_state (mono_internal_thread_handle_ptr (this_obj
), (MonoThreadState
)state
);
2520 ves_icall_System_Threading_Thread_SetState (MonoInternalThreadHandle thread_handle
, guint32 state
, MonoError
*error
)
2522 // InternalThreads are always pinned, so shallowly coop-handleize.
2523 mono_thread_set_state (mono_internal_thread_handle_ptr (thread_handle
), (MonoThreadState
)state
);
2527 ves_icall_System_Threading_Thread_GetState (MonoInternalThreadHandle thread_handle
, MonoError
*error
)
2529 // InternalThreads are always pinned, so shallowly coop-handleize.
2530 MonoInternalThread
*this_obj
= mono_internal_thread_handle_ptr (thread_handle
);
2534 LOCK_THREAD (this_obj
);
2536 state
= this_obj
->state
;
2538 UNLOCK_THREAD (this_obj
);
2544 ves_icall_System_Threading_Thread_Interrupt_internal (MonoThreadObjectHandle thread_handle
, MonoError
*error
)
2546 // Internal threads are pinned so shallow coop/handle.
2547 MonoInternalThread
* const thread
= thread_handle_to_internal_ptr (thread_handle
);
2548 MonoInternalThread
* const current
= mono_thread_internal_current ();
2550 LOCK_THREAD (thread
);
2552 thread
->thread_interrupt_requested
= TRUE
;
2553 gboolean
const throw_
= current
!= thread
&& (thread
->state
& ThreadState_WaitSleepJoin
);
2555 UNLOCK_THREAD (thread
);
2558 async_abort_internal (thread
, FALSE
);
2562 * mono_thread_current_check_pending_interrupt:
2563 * Checks if there's a interruption request and set the pending exception if so.
2564 * \returns true if a pending exception was set
2567 mono_thread_current_check_pending_interrupt (void)
2569 MonoInternalThread
*thread
= mono_thread_internal_current ();
2570 gboolean throw_
= FALSE
;
2572 LOCK_THREAD (thread
);
2574 if (thread
->thread_interrupt_requested
) {
2576 thread
->thread_interrupt_requested
= FALSE
;
2579 UNLOCK_THREAD (thread
);
2583 mono_error_set_thread_interrupted (error
);
2584 mono_error_set_pending_exception (error
);
2590 request_thread_abort (MonoInternalThread
*thread
, MonoObjectHandle
*state
, gboolean appdomain_unload
)
2591 // state is a pointer to a handle in order to be optional,
2592 // and be passed unspecified from functions not using handles.
2593 // When raw pointers is gone, it need not be a pointer,
2594 // though this would still work efficiently.
2596 LOCK_THREAD (thread
);
2598 /* With self abort we always throw a new exception */
2599 if (thread
== mono_thread_internal_current ())
2600 thread
->abort_exc
= NULL
;
2602 if (thread
->state
& (ThreadState_AbortRequested
| ThreadState_Stopped
))
2604 UNLOCK_THREAD (thread
);
2608 if ((thread
->state
& ThreadState_Unstarted
) != 0) {
2609 thread
->state
|= ThreadState_Aborted
;
2610 UNLOCK_THREAD (thread
);
2614 thread
->state
|= ThreadState_AbortRequested
;
2615 if (appdomain_unload
)
2616 thread
->flags
|= MONO_THREAD_FLAG_APPDOMAIN_ABORT
;
2618 thread
->flags
&= ~MONO_THREAD_FLAG_APPDOMAIN_ABORT
;
2620 mono_gchandle_free_internal (thread
->abort_state_handle
);
2621 thread
->abort_state_handle
= 0;
2624 if (state
&& !MONO_HANDLE_IS_NULL (*state
)) {
2625 thread
->abort_state_handle
= mono_gchandle_from_handle (*state
, FALSE
);
2626 g_assert (thread
->abort_state_handle
);
2629 thread
->abort_exc
= NULL
;
2631 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
));
2633 /* During shutdown, we can't wait for other threads */
2635 /* Make sure the thread is awake */
2636 mono_thread_resume (thread
);
2638 UNLOCK_THREAD (thread
);
2642 #ifndef ENABLE_NETCORE
2644 ves_icall_System_Threading_Thread_Abort (MonoInternalThreadHandle thread_handle
, MonoObjectHandle state
, MonoError
*error
)
2646 // InternalThreads are always pinned, so shallowly coop-handleize.
2647 MonoInternalThread
* const thread
= mono_internal_thread_handle_ptr (thread_handle
);
2648 gboolean is_self
= thread
== mono_thread_internal_current ();
2650 /* For self aborts we always process the abort */
2651 if (!request_thread_abort (thread
, &state
, FALSE
) && !is_self
)
2655 self_abort_internal (error
);
2657 async_abort_internal (thread
, TRUE
);
2663 * mono_thread_internal_abort:
2664 * Request thread \p thread to be aborted.
2665 * \p thread MUST NOT be the current thread.
2668 mono_thread_internal_abort (MonoInternalThread
*thread
, gboolean appdomain_unload
)
2670 g_assert (thread
!= mono_thread_internal_current ());
2672 if (!request_thread_abort (thread
, NULL
, appdomain_unload
))
2674 async_abort_internal (thread
, TRUE
);
2677 #ifndef ENABLE_NETCORE
2679 ves_icall_System_Threading_Thread_ResetAbort (MonoThreadObjectHandle this_obj
, MonoError
*error
)
2681 MonoInternalThread
*thread
= mono_thread_internal_current ();
2682 gboolean was_aborting
, is_domain_abort
;
2684 LOCK_THREAD (thread
);
2685 was_aborting
= thread
->state
& ThreadState_AbortRequested
;
2686 is_domain_abort
= thread
->flags
& MONO_THREAD_FLAG_APPDOMAIN_ABORT
;
2688 if (was_aborting
&& !is_domain_abort
)
2689 thread
->state
&= ~ThreadState_AbortRequested
;
2690 UNLOCK_THREAD (thread
);
2692 if (!was_aborting
) {
2693 mono_error_set_exception_thread_state (error
, "Unable to reset abort because no abort was requested");
2695 } else if (is_domain_abort
) {
2696 /* Silently ignore abort resets in unloading appdomains */
2700 mono_get_eh_callbacks ()->mono_clear_abort_threshold ();
2701 thread
->abort_exc
= NULL
;
2702 mono_gchandle_free_internal (thread
->abort_state_handle
);
2703 /* This is actually not necessary - the handle
2704 only counts if the exception is set */
2705 thread
->abort_state_handle
= 0;
2710 mono_thread_internal_reset_abort (MonoInternalThread
*thread
)
2712 LOCK_THREAD (thread
);
2714 thread
->state
&= ~ThreadState_AbortRequested
;
2716 if (thread
->abort_exc
) {
2717 mono_get_eh_callbacks ()->mono_clear_abort_threshold ();
2718 thread
->abort_exc
= NULL
;
2719 mono_gchandle_free_internal (thread
->abort_state_handle
);
2720 /* This is actually not necessary - the handle
2721 only counts if the exception is set */
2722 thread
->abort_state_handle
= 0;
2725 UNLOCK_THREAD (thread
);
2728 #ifndef ENABLE_NETCORE
2730 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThreadObjectHandle this_obj
, MonoError
*error
)
2732 MonoInternalThread
*thread
= thread_handle_to_internal_ptr (this_obj
);
2734 if (!thread
->abort_state_handle
)
2735 return NULL_HANDLE
; // No state. No error.
2737 // Convert gc handle to coop handle.
2738 MonoObjectHandle state
= mono_gchandle_get_target_handle (thread
->abort_state_handle
);
2739 g_assert (MONO_HANDLE_BOOL (state
));
2741 MonoDomain
*domain
= mono_domain_get ();
2742 if (MONO_HANDLE_DOMAIN (state
) == domain
)
2743 return state
; // No need to cross domain, return state directly.
2745 // Attempt move state cross-domain.
2746 MonoObjectHandle deserialized
= mono_object_xdomain_representation (state
, domain
, error
);
2748 // If deserialized is null, there must be an error, and vice versa.
2749 g_assert (is_ok (error
) == MONO_HANDLE_BOOL (deserialized
));
2751 if (MONO_HANDLE_BOOL (deserialized
))
2752 return deserialized
; // Cross-domain serialization succeeded. Return it.
2754 // Wrap error in InvalidOperationException.
2755 ERROR_DECL (error_creating_exception
);
2756 MonoExceptionHandle invalid_op_exc
= mono_exception_new_invalid_operation (
2757 "Thread.ExceptionState cannot access an ExceptionState from a different AppDomain", error_creating_exception
);
2758 mono_error_assert_ok (error_creating_exception
);
2759 g_assert (!is_ok (error
) && 1);
2760 MONO_HANDLE_SET (invalid_op_exc
, inner_ex
, mono_error_convert_to_exception_handle (error
));
2761 error_init_reuse (error
);
2762 mono_error_set_exception_handle (error
, invalid_op_exc
);
2763 g_assert (!is_ok (error
) && 2);
2765 // There is state, but we failed to return it.
2771 mono_thread_suspend (MonoInternalThread
*thread
)
2773 LOCK_THREAD (thread
);
2775 if (thread
->state
& (ThreadState_Unstarted
| ThreadState_Aborted
| ThreadState_Stopped
))
2777 UNLOCK_THREAD (thread
);
2781 if (thread
->state
& (ThreadState_Suspended
| ThreadState_SuspendRequested
| ThreadState_AbortRequested
))
2783 UNLOCK_THREAD (thread
);
2787 thread
->state
|= ThreadState_SuspendRequested
;
2789 mono_os_event_reset (thread
->suspended
);
2792 if (thread
== mono_thread_internal_current ()) {
2793 /* calls UNLOCK_THREAD (thread) */
2794 self_suspend_internal ();
2796 /* calls UNLOCK_THREAD (thread) */
2797 async_suspend_internal (thread
, FALSE
);
2803 #ifndef ENABLE_NETCORE
2805 ves_icall_System_Threading_Thread_Suspend (MonoThreadObjectHandle this_obj
, MonoError
*error
)
2807 if (!mono_thread_suspend (thread_handle_to_internal_ptr (this_obj
)))
2808 mono_error_set_exception_thread_not_started_or_dead (error
);
2813 /* LOCKING: LOCK_THREAD(thread) must be held */
2815 mono_thread_resume (MonoInternalThread
*thread
)
2817 if ((thread
->state
& ThreadState_SuspendRequested
) != 0) {
2818 // g_async_safe_printf ("RESUME (1) thread %p\n", thread_get_tid (thread));
2819 thread
->state
&= ~ThreadState_SuspendRequested
;
2821 mono_os_event_set (thread
->suspended
);
2826 if ((thread
->state
& ThreadState_Suspended
) == 0 ||
2827 (thread
->state
& ThreadState_Unstarted
) != 0 ||
2828 (thread
->state
& ThreadState_Aborted
) != 0 ||
2829 (thread
->state
& ThreadState_Stopped
) != 0)
2831 // g_async_safe_printf ("RESUME (2) thread %p\n", thread_get_tid (thread));
2835 // g_async_safe_printf ("RESUME (3) thread %p\n", thread_get_tid (thread));
2838 mono_os_event_set (thread
->suspended
);
2841 if (!thread
->self_suspended
) {
2842 UNLOCK_THREAD (thread
);
2844 /* Awake the thread */
2845 if (!mono_thread_info_resume (thread_get_tid (thread
)))
2848 LOCK_THREAD (thread
);
2851 thread
->state
&= ~ThreadState_Suspended
;
2856 #ifndef ENABLE_NETCORE
2858 ves_icall_System_Threading_Thread_Resume (MonoThreadObjectHandle thread_handle
, MonoError
*error
)
2860 // Internal threads are pinned so shallow coop/handle.
2861 MonoInternalThread
* const internal_thread
= thread_handle_to_internal_ptr (thread_handle
);
2862 gboolean exception
= FALSE
;
2864 if (!internal_thread
) {
2867 LOCK_THREAD (internal_thread
);
2868 if (!mono_thread_resume (internal_thread
))
2870 UNLOCK_THREAD (internal_thread
);
2874 mono_error_set_exception_thread_not_started_or_dead (error
);
2879 mono_threads_is_critical_method (MonoMethod
*method
)
2881 switch (method
->wrapper_type
) {
2882 case MONO_WRAPPER_RUNTIME_INVOKE
:
2883 case MONO_WRAPPER_XDOMAIN_INVOKE
:
2884 case MONO_WRAPPER_XDOMAIN_DISPATCH
:
2891 find_wrapper (MonoMethod
*m
, gint no
, gint ilo
, gboolean managed
, gpointer data
)
2896 if (mono_threads_is_critical_method (m
)) {
2897 *((gboolean
*)data
) = TRUE
;
2904 is_running_protected_wrapper (void)
2906 gboolean found
= FALSE
;
2907 mono_stack_walk (find_wrapper
, &found
);
2915 mono_thread_stop (MonoThread
*thread
)
2917 MonoInternalThread
*internal
= thread
->internal_thread
;
2919 if (!request_thread_abort (internal
, NULL
, FALSE
))
2922 if (internal
== mono_thread_internal_current ()) {
2924 self_abort_internal (error
);
2926 This function is part of the embeding API and has no way to return the exception
2927 to be thrown. So what we do is keep the old behavior and raise the exception.
2929 mono_error_raise_exception_deprecated (error
); /* OK to throw, see note */
2931 async_abort_internal (internal
, TRUE
);
2936 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr
)
2938 gint8 tmp
= *(volatile gint8
*)ptr
;
2939 mono_memory_barrier ();
2944 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr
)
2946 gint16 tmp
= *(volatile gint16
*)ptr
;
2947 mono_memory_barrier ();
2952 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr
)
2954 gint32 tmp
= *(volatile gint32
*)ptr
;
2955 mono_memory_barrier ();
2960 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr
)
2962 gint64 tmp
= *(volatile gint64
*)ptr
;
2963 mono_memory_barrier ();
2968 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr
)
2970 volatile void *tmp
= *(volatile void **)ptr
;
2971 mono_memory_barrier ();
2972 return (void *) tmp
;
2976 ves_icall_System_Threading_Thread_VolatileReadObject (void *ptr
)
2978 volatile MonoObject
*tmp
= *(volatile MonoObject
**)ptr
;
2979 mono_memory_barrier ();
2980 return (MonoObject
*) tmp
;
2984 ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr
)
2986 double tmp
= *(volatile double *)ptr
;
2987 mono_memory_barrier ();
2992 ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr
)
2994 float tmp
= *(volatile float *)ptr
;
2995 mono_memory_barrier ();
3000 ves_icall_System_Threading_Volatile_Read8 (void *ptr
)
3002 #if SIZEOF_VOID_P == 4
3003 if (G_UNLIKELY ((size_t)ptr
& 0x7)) {
3005 mono_interlocked_lock ();
3006 val
= *(gint64
*)ptr
;
3007 mono_interlocked_unlock ();
3011 return mono_atomic_load_i64 ((volatile gint64
*)ptr
);
3015 ves_icall_System_Threading_Volatile_ReadU8 (void *ptr
)
3017 #if SIZEOF_VOID_P == 4
3018 if (G_UNLIKELY ((size_t)ptr
& 0x7)) {
3020 mono_interlocked_lock ();
3021 val
= *(guint64
*)ptr
;
3022 mono_interlocked_unlock ();
3026 return (guint64
)mono_atomic_load_i64 ((volatile gint64
*)ptr
);
3030 ves_icall_System_Threading_Volatile_ReadDouble (void *ptr
)
3034 #if SIZEOF_VOID_P == 4
3035 if (G_UNLIKELY ((size_t)ptr
& 0x7)) {
3037 mono_interlocked_lock ();
3038 val
= *(double*)ptr
;
3039 mono_interlocked_unlock ();
3044 u
.ival
= mono_atomic_load_i64 ((volatile gint64
*)ptr
);
3050 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr
, gint8 value
)
3052 mono_memory_barrier ();
3053 *(volatile gint8
*)ptr
= value
;
3057 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr
, gint16 value
)
3059 mono_memory_barrier ();
3060 *(volatile gint16
*)ptr
= value
;
3064 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr
, gint32 value
)
3066 mono_memory_barrier ();
3067 *(volatile gint32
*)ptr
= value
;
3071 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr
, gint64 value
)
3073 mono_memory_barrier ();
3074 *(volatile gint64
*)ptr
= value
;
3078 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr
, void *value
)
3080 mono_memory_barrier ();
3081 *(volatile void **)ptr
= value
;
3085 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr
, MonoObject
*value
)
3087 mono_memory_barrier ();
3088 mono_gc_wbarrier_generic_store_internal (ptr
, value
);
3092 ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr
, double value
)
3094 mono_memory_barrier ();
3095 *(volatile double *)ptr
= value
;
3099 ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr
, float value
)
3101 mono_memory_barrier ();
3102 *(volatile float *)ptr
= value
;
3106 ves_icall_System_Threading_Volatile_Write8 (void *ptr
, gint64 value
)
3108 #if SIZEOF_VOID_P == 4
3109 if (G_UNLIKELY ((size_t)ptr
& 0x7)) {
3110 mono_interlocked_lock ();
3111 *(gint64
*)ptr
= value
;
3112 mono_interlocked_unlock ();
3117 mono_atomic_store_i64 ((volatile gint64
*)ptr
, value
);
3121 ves_icall_System_Threading_Volatile_WriteU8 (void *ptr
, guint64 value
)
3123 #if SIZEOF_VOID_P == 4
3124 if (G_UNLIKELY ((size_t)ptr
& 0x7)) {
3125 mono_interlocked_lock ();
3126 *(guint64
*)ptr
= value
;
3127 mono_interlocked_unlock ();
3132 mono_atomic_store_i64 ((volatile gint64
*)ptr
, (gint64
)value
);
3136 ves_icall_System_Threading_Volatile_WriteDouble (void *ptr
, double value
)
3140 #if SIZEOF_VOID_P == 4
3141 if (G_UNLIKELY ((size_t)ptr
& 0x7)) {
3142 mono_interlocked_lock ();
3143 *(double*)ptr
= value
;
3144 mono_interlocked_unlock ();
3151 mono_atomic_store_i64 ((volatile gint64
*)ptr
, u
.ival
);
3155 free_context (void *user_data
)
3157 ContextStaticData
*data
= (ContextStaticData
*)user_data
;
3159 mono_threads_lock ();
3162 * There is no guarantee that, by the point this reference queue callback
3163 * has been invoked, the GC handle associated with the object will fail to
3164 * resolve as one might expect. So if we don't free and remove the GC
3165 * handle here, free_context_static_data_helper () could end up resolving
3166 * a GC handle to an actually-dead context which would contain a pointer
3167 * to an already-freed static data segment, resulting in a crash when
3170 g_hash_table_remove (contexts
, GUINT_TO_POINTER (data
->gc_handle
));
3172 mono_threads_unlock ();
3174 mono_gchandle_free_internal (data
->gc_handle
);
3175 mono_free_static_data (data
->static_data
);
3180 mono_threads_register_app_context (MonoAppContextHandle ctx
, MonoError
*error
)
3183 mono_threads_lock ();
3185 //g_print ("Registering context %d in domain %d\n", ctx->context_id, ctx->domain_id);
3188 contexts
= g_hash_table_new (NULL
, NULL
);
3191 context_queue
= mono_gc_reference_queue_new_internal (free_context
);
3193 gpointer gch
= GUINT_TO_POINTER (mono_gchandle_new_weakref_from_handle (MONO_HANDLE_CAST (MonoObject
, ctx
)));
3194 g_hash_table_insert (contexts
, gch
, gch
);
3197 * We use this intermediate structure to contain a duplicate pointer to
3198 * the static data because we can't rely on being able to resolve the GC
3199 * handle in the reference queue callback.
3201 ContextStaticData
*data
= g_new0 (ContextStaticData
, 1);
3202 data
->gc_handle
= GPOINTER_TO_UINT (gch
);
3203 MONO_HANDLE_SETVAL (ctx
, data
, ContextStaticData
*, data
);
3205 context_adjust_static_data (ctx
);
3206 mono_gc_reference_queue_add_handle (context_queue
, ctx
, data
);
3208 mono_threads_unlock ();
3210 MONO_PROFILER_RAISE (context_loaded
, (MONO_HANDLE_RAW (ctx
)));
3213 #ifndef ENABLE_NETCORE
3215 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (MonoAppContextHandle ctx
, MonoError
*error
)
3217 mono_threads_register_app_context (ctx
, error
);
3222 mono_threads_release_app_context (MonoAppContext
* ctx
, MonoError
*error
)
3225 * NOTE: Since finalizers are unreliable for the purposes of ensuring
3226 * cleanup in exceptional circumstances, we don't actually do any
3227 * cleanup work here. We instead do this via a reference queue.
3230 //g_print ("Releasing context %d in domain %d\n", ctx->context_id, ctx->domain_id);
3232 MONO_PROFILER_RAISE (context_unloaded
, (ctx
));
3235 #ifndef ENABLE_NETCORE
3237 ves_icall_System_Runtime_Remoting_Contexts_Context_ReleaseContext (MonoAppContextHandle ctx
, MonoError
*error
)
3239 mono_threads_release_app_context (MONO_HANDLE_RAW (ctx
), error
); /* FIXME use handles in mono_threads_release_app_context */
3243 void mono_thread_init (MonoThreadStartCB start_cb
,
3244 MonoThreadAttachCB attach_cb
)
3246 mono_coop_mutex_init_recursive (&threads_mutex
);
3248 #if SIZEOF_VOID_P == 4
3249 mono_os_mutex_init (&interlocked_mutex
);
3251 mono_coop_mutex_init_recursive(&joinable_threads_mutex
);
3253 mono_os_event_init (&background_change_event
, FALSE
);
3255 mono_coop_cond_init (&pending_native_thread_join_calls_event
);
3256 mono_coop_cond_init (&zero_pending_joinable_thread_event
);
3258 mono_init_static_data_info (&thread_static_info
);
3259 mono_init_static_data_info (&context_static_info
);
3261 mono_thread_start_cb
= start_cb
;
3262 mono_thread_attach_cb
= attach_cb
;
3267 thread_attach (MonoThreadInfo
*info
)
3269 return mono_gc_thread_attach (info
);
3273 thread_detach (MonoThreadInfo
*info
)
3275 MonoInternalThread
*internal
;
3278 /* If a delegate is passed to native code and invoked on a thread we dont
3279 * know about, marshal will register it with mono_threads_attach_coop, but
3280 * we have no way of knowing when that thread goes away. SGen has a TSD
3281 * so we assume that if the domain is still registered, we can detach
3285 g_assert (mono_thread_info_is_current (info
));
3287 if (!mono_thread_info_try_get_internal_thread_gchandle (info
, &gchandle
))
3290 internal
= (MonoInternalThread
*) mono_gchandle_get_target_internal (gchandle
);
3291 g_assert (internal
);
3293 mono_thread_detach_internal (internal
);
3297 thread_detach_with_lock (MonoThreadInfo
*info
)
3299 mono_gc_thread_detach_with_lock (info
);
3303 thread_in_critical_region (MonoThreadInfo
*info
)
3305 return mono_gc_thread_in_critical_region (info
);
3309 ip_in_critical_region (MonoDomain
*domain
, gpointer ip
)
3315 * We pass false for 'try_aot' so this becomes async safe.
3316 * It won't find aot methods whose jit info is not yet loaded,
3317 * so we preload their jit info in the JIT.
3319 ji
= mono_jit_info_table_find_internal (domain
, ip
, FALSE
, FALSE
);
3323 method
= mono_jit_info_get_method (ji
);
3326 return mono_gc_is_critical_method (method
);
3330 thread_flags_changing (MonoThreadInfoFlags old
, MonoThreadInfoFlags new_
)
3332 mono_gc_skip_thread_changing (!!(new_
& MONO_THREAD_INFO_FLAGS_NO_GC
));
3336 thread_flags_changed (MonoThreadInfoFlags old
, MonoThreadInfoFlags new_
)
3338 mono_gc_skip_thread_changed (!!(new_
& MONO_THREAD_INFO_FLAGS_NO_GC
));
3342 mono_thread_callbacks_init (void)
3344 MonoThreadInfoCallbacks cb
;
3346 memset (&cb
, 0, sizeof(cb
));
3347 cb
.thread_attach
= thread_attach
;
3348 cb
.thread_detach
= thread_detach
;
3349 cb
.thread_detach_with_lock
= thread_detach_with_lock
;
3350 cb
.ip_in_critical_region
= ip_in_critical_region
;
3351 cb
.thread_in_critical_region
= thread_in_critical_region
;
3352 cb
.thread_flags_changing
= thread_flags_changing
;
3353 cb
.thread_flags_changed
= thread_flags_changed
;
3354 mono_thread_info_callbacks_init (&cb
);
3358 * mono_thread_cleanup:
3361 mono_thread_cleanup (void)
3363 /* Wait for pending threads to park on joinable threads list */
3364 /* NOTE, waiting on this should be extremely rare and will only happen */
3365 /* under certain specific conditions. */
3366 gboolean wait_result
= threads_wait_pending_joinable_threads (2000);
3368 g_warning ("Waiting on threads to park on joinable thread list timed out.");
3370 mono_threads_join_threads ();
3372 #if !defined(HOST_WIN32)
3373 /* The main thread must abandon any held mutexes (particularly
3374 * important for named mutexes as they are shared across
3375 * processes, see bug 74680.) This will happen when the
3376 * thread exits, but if it's not running in a subthread it
3377 * won't exit in time.
3379 if (!mono_runtime_get_no_exec ())
3380 mono_w32mutex_abandon (mono_thread_internal_current ());
3384 /* This stuff needs more testing, it seems one of these
3385 * critical sections can be locked when mono_thread_cleanup is
3388 mono_coop_mutex_destroy (&threads_mutex
);
3389 mono_os_mutex_destroy (&interlocked_mutex
);
3390 mono_os_mutex_destroy (&delayed_free_table_mutex
);
3391 mono_os_mutex_destroy (&small_id_mutex
);
3392 mono_coop_cond_destroy (&zero_pending_joinable_thread_event
);
3393 mono_coop_cond_destroy (&pending_native_thread_join_calls_event
);
3394 mono_os_event_destroy (&background_change_event
);
3399 mono_threads_install_cleanup (MonoThreadCleanupFunc func
)
3401 mono_thread_cleanup_fn
= func
;
3405 * mono_thread_set_manage_callback:
3408 mono_thread_set_manage_callback (MonoThread
*thread
, MonoThreadManageCallback func
)
3410 thread
->internal_thread
->manage_callback
= func
;
3414 static void print_tids (gpointer key
, gpointer value
, gpointer user
)
3416 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
3417 * sizeof(uint) and a cast to uint would overflow
3419 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
3420 * print this as a pointer.
3422 g_message ("Waiting for: %p", key
);
3427 MonoThreadHandle
*handles
[MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
];
3428 MonoInternalThread
*threads
[MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
];
3433 wait_for_tids (struct wait_data
*wait
, guint32 timeout
, gboolean check_state_change
)
3436 MonoThreadInfoWaitRet ret
;
3438 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__
, wait
->num
));
3440 /* Add the thread state change event, so it wakes
3441 * up if a thread changes to background mode. */
3444 if (check_state_change
)
3445 ret
= mono_thread_info_wait_multiple_handle (wait
->handles
, wait
->num
, &background_change_event
, FALSE
, timeout
, TRUE
);
3447 ret
= mono_thread_info_wait_multiple_handle (wait
->handles
, wait
->num
, NULL
, TRUE
, timeout
, TRUE
);
3450 if (ret
== MONO_THREAD_INFO_WAIT_RET_FAILED
) {
3451 /* See the comment in build_wait_tids() */
3452 THREAD_DEBUG (g_message ("%s: Wait failed", __func__
));
3456 for( i
= 0; i
< wait
->num
; i
++)
3457 mono_threads_close_thread_handle (wait
->handles
[i
]);
3459 if (ret
>= MONO_THREAD_INFO_WAIT_RET_SUCCESS_0
&& ret
< (MONO_THREAD_INFO_WAIT_RET_SUCCESS_0
+ wait
->num
)) {
3460 MonoInternalThread
*internal
;
3462 internal
= wait
->threads
[ret
- MONO_THREAD_INFO_WAIT_RET_SUCCESS_0
];
3464 mono_threads_lock ();
3465 if (mono_g_hash_table_lookup (threads
, (gpointer
) internal
->tid
) == internal
)
3466 g_error ("%s: failed to call mono_thread_detach_internal on thread %p, InternalThread: %p", __func__
, internal
->tid
, internal
);
3467 mono_threads_unlock ();
3471 static void build_wait_tids (gpointer key
, gpointer value
, gpointer user
)
3473 struct wait_data
*wait
=(struct wait_data
*)user
;
3475 if(wait
->num
<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
- 1) {
3476 MonoInternalThread
*thread
=(MonoInternalThread
*)value
;
3478 /* Ignore background threads, we abort them later */
3479 /* Do not lock here since it is not needed and the caller holds threads_lock */
3480 if (thread
->state
& ThreadState_Background
) {
3481 THREAD_DEBUG (g_message ("%s: ignoring background thread %" G_GSIZE_FORMAT
, __func__
, (gsize
)thread
->tid
));
3482 return; /* just leave, ignore */
3485 if (mono_gc_is_finalizer_internal_thread (thread
)) {
3486 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %" G_GSIZE_FORMAT
, __func__
, (gsize
)thread
->tid
));
3490 if (thread
== mono_thread_internal_current ()) {
3491 THREAD_DEBUG (g_message ("%s: ignoring current thread %" G_GSIZE_FORMAT
, __func__
, (gsize
)thread
->tid
));
3495 if (mono_thread_get_main () && (thread
== mono_thread_get_main ()->internal_thread
)) {
3496 THREAD_DEBUG (g_message ("%s: ignoring main thread %" G_GSIZE_FORMAT
, __func__
, (gsize
)thread
->tid
));
3500 if (thread
->flags
& MONO_THREAD_FLAG_DONT_MANAGE
) {
3501 THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT
"with DONT_MANAGE flag set.", __func__
, (gsize
)thread
->tid
));
3505 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__
, thread
));
3506 if ((thread
->manage_callback
== NULL
) || (thread
->manage_callback (thread
->root_domain_thread
) == TRUE
)) {
3507 wait
->handles
[wait
->num
]=mono_threads_open_thread_handle (thread
->handle
);
3508 wait
->threads
[wait
->num
]=thread
;
3511 THREAD_DEBUG (g_message ("%s: adding thread %" G_GSIZE_FORMAT
, __func__
, (gsize
)thread
->tid
));
3513 THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %" G_GSIZE_FORMAT
, __func__
, (gsize
)thread
->tid
));
3518 /* Just ignore the rest, we can't do anything with
3525 abort_threads (gpointer key
, gpointer value
, gpointer user
)
3527 struct wait_data
*wait
=(struct wait_data
*)user
;
3528 MonoNativeThreadId self
= mono_native_thread_id_get ();
3529 MonoInternalThread
*thread
= (MonoInternalThread
*)value
;
3531 if (wait
->num
>= MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
)
3534 if (mono_native_thread_id_equals (thread_get_tid (thread
), self
))
3536 if (mono_gc_is_finalizer_internal_thread (thread
))
3539 if ((thread
->flags
& MONO_THREAD_FLAG_DONT_MANAGE
))
3542 wait
->handles
[wait
->num
] = mono_threads_open_thread_handle (thread
->handle
);
3543 wait
->threads
[wait
->num
] = thread
;
3546 THREAD_DEBUG (g_print ("%s: Aborting id: %" G_GSIZE_FORMAT
"\n", __func__
, (gsize
)thread
->tid
));
3547 mono_thread_internal_abort (thread
, FALSE
);
3551 * mono_threads_set_shutting_down:
3553 * Is called by a thread that wants to shut down Mono. If the runtime is already
3554 * shutting down, the calling thread is suspended/stopped, and this function never
3558 mono_threads_set_shutting_down (void)
3560 MonoInternalThread
*current_thread
= mono_thread_internal_current ();
3562 mono_threads_lock ();
3564 if (shutting_down
) {
3565 mono_threads_unlock ();
3567 /* Make sure we're properly suspended/stopped */
3569 LOCK_THREAD (current_thread
);
3571 if (current_thread
->state
& (ThreadState_SuspendRequested
| ThreadState_AbortRequested
)) {
3572 UNLOCK_THREAD (current_thread
);
3573 mono_thread_execute_interruption_void ();
3575 UNLOCK_THREAD (current_thread
);
3578 /*since we're killing the thread, detach it.*/
3579 mono_thread_detach_internal (current_thread
);
3581 /* Wake up other threads potentially waiting for us */
3582 mono_thread_info_exit (0);
3584 shutting_down
= TRUE
;
3586 /* Not really a background state change, but this will
3587 * interrupt the main thread if it is waiting for all
3588 * the other threads.
3591 mono_os_event_set (&background_change_event
);
3594 mono_threads_unlock ();
3599 * mono_thread_manage:
3602 mono_thread_manage (void)
3604 struct wait_data wait_data
;
3605 struct wait_data
*wait
= &wait_data
;
3607 memset (wait
, 0, sizeof (struct wait_data
));
3608 /* join each thread that's still running */
3609 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__
));
3611 mono_threads_lock ();
3613 THREAD_DEBUG (g_message("%s: No threads", __func__
));
3614 mono_threads_unlock ();
3618 mono_threads_unlock ();
3621 mono_threads_lock ();
3622 if (shutting_down
) {
3623 /* somebody else is shutting down */
3624 mono_threads_unlock ();
3627 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__
, mono_g_hash_table_size (threads
));
3628 mono_g_hash_table_foreach (threads
, print_tids
, NULL
));
3631 mono_os_event_reset (&background_change_event
);
3634 /* We must zero all InternalThread pointers to avoid making the GC unhappy. */
3635 memset (wait
->threads
, 0, sizeof (wait
->threads
));
3636 mono_g_hash_table_foreach (threads
, build_wait_tids
, wait
);
3637 mono_threads_unlock ();
3639 /* Something to wait for */
3640 wait_for_tids (wait
, MONO_INFINITE_WAIT
, TRUE
);
3641 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__
, wait
->num
));
3642 } while(wait
->num
>0);
3644 /* Mono is shutting down, so just wait for the end */
3645 if (!mono_runtime_try_shutdown ()) {
3646 /*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
3647 mono_thread_suspend (mono_thread_internal_current ());
3648 mono_thread_execute_interruption_void ();
3651 #ifndef ENABLE_NETCORE
3653 * Under netcore, we don't abort any threads, just exit.
3654 * This is not a problem since we don't do runtime cleanup either.
3657 * Remove everything but the finalizer thread and self.
3658 * Also abort all the background threads
3661 mono_threads_lock ();
3664 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3665 memset (wait
->threads
, 0, sizeof (wait
->threads
));
3666 mono_g_hash_table_foreach (threads
, abort_threads
, wait
);
3668 mono_threads_unlock ();
3670 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__
, wait
->num
));
3671 if (wait
->num
> 0) {
3672 /* Something to wait for */
3673 wait_for_tids (wait
, MONO_INFINITE_WAIT
, FALSE
);
3675 } while (wait
->num
> 0);
3679 * give the subthreads a chance to really quit (this is mainly needed
3680 * to get correct user and system times from getrusage/wait/time(1)).
3681 * This could be removed if we avoid pthread_detach() and use pthread_join().
3683 mono_thread_info_yield ();
3687 collect_threads_for_suspend (gpointer key
, gpointer value
, gpointer user_data
)
3689 MonoInternalThread
*thread
= (MonoInternalThread
*)value
;
3690 struct wait_data
*wait
= (struct wait_data
*)user_data
;
3693 * We try to exclude threads early, to avoid running into the MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
3695 * This needs no locking.
3697 if ((thread
->state
& ThreadState_Suspended
) != 0 ||
3698 (thread
->state
& ThreadState_Stopped
) != 0)
3701 if (wait
->num
<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
) {
3702 wait
->handles
[wait
->num
] = mono_threads_open_thread_handle (thread
->handle
);
3703 wait
->threads
[wait
->num
] = thread
;
3709 * mono_thread_suspend_all_other_threads:
3711 * Suspend all managed threads except the finalizer thread and this thread. It is
3712 * not possible to resume them later.
3714 void mono_thread_suspend_all_other_threads (void)
3716 struct wait_data wait_data
;
3717 struct wait_data
*wait
= &wait_data
;
3719 MonoNativeThreadId self
= mono_native_thread_id_get ();
3720 guint32 eventidx
= 0;
3721 gboolean starting
, finished
;
3723 memset (wait
, 0, sizeof (struct wait_data
));
3725 * The other threads could be in an arbitrary state at this point, i.e.
3726 * they could be starting up, shutting down etc. This means that there could be
3727 * threads which are not even in the threads hash table yet.
3731 * First we set a barrier which will be checked by all threads before they
3732 * are added to the threads hash table, and they will exit if the flag is set.
3733 * This ensures that no threads could be added to the hash later.
3734 * We will use shutting_down as the barrier for now.
3736 g_assert (shutting_down
);
3739 * We make multiple calls to WaitForMultipleObjects since:
3740 * - we can only wait for MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS threads
3741 * - some threads could exit without becoming suspended
3746 * Make a copy of the hashtable since we can't do anything with
3747 * threads while threads_mutex is held.
3750 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3751 memset (wait
->threads
, 0, sizeof (wait
->threads
));
3752 mono_threads_lock ();
3753 mono_g_hash_table_foreach (threads
, collect_threads_for_suspend
, wait
);
3754 mono_threads_unlock ();
3757 /* Get the suspended events that we'll be waiting for */
3758 for (i
= 0; i
< wait
->num
; ++i
) {
3759 MonoInternalThread
*thread
= wait
->threads
[i
];
3761 if (mono_native_thread_id_equals (thread_get_tid (thread
), self
)
3762 || mono_gc_is_finalizer_internal_thread (thread
)
3763 || (thread
->flags
& MONO_THREAD_FLAG_DONT_MANAGE
)
3765 mono_threads_close_thread_handle (wait
->handles
[i
]);
3766 wait
->threads
[i
] = NULL
;
3770 LOCK_THREAD (thread
);
3772 if (thread
->state
& (ThreadState_Suspended
| ThreadState_Stopped
)) {
3773 UNLOCK_THREAD (thread
);
3774 mono_threads_close_thread_handle (wait
->handles
[i
]);
3775 wait
->threads
[i
] = NULL
;
3781 /* Convert abort requests into suspend requests */
3782 if ((thread
->state
& ThreadState_AbortRequested
) != 0)
3783 thread
->state
&= ~ThreadState_AbortRequested
;
3785 thread
->state
|= ThreadState_SuspendRequested
;
3787 mono_os_event_reset (thread
->suspended
);
3790 /* Signal the thread to suspend + calls UNLOCK_THREAD (thread) */
3791 async_suspend_internal (thread
, TRUE
);
3793 mono_threads_close_thread_handle (wait
->handles
[i
]);
3794 wait
->threads
[i
] = NULL
;
3796 if (eventidx
<= 0) {
3798 * If there are threads which are starting up, we wait until they
3799 * are suspended when they try to register in the threads hash.
3800 * This is guaranteed to finish, since the threads which can create new
3801 * threads get suspended after a while.
3802 * FIXME: The finalizer thread can still create new threads.
3804 mono_threads_lock ();
3805 if (threads_starting_up
)
3806 starting
= mono_g_hash_table_size (threads_starting_up
) > 0;
3809 mono_threads_unlock ();
3811 mono_thread_info_sleep (100, NULL
);
3819 MonoInternalThread
*thread
;
3820 MonoStackFrameInfo
*frames
;
3821 int nframes
, max_frames
;
3822 int nthreads
, max_threads
;
3823 MonoInternalThread
**threads
;
3824 } ThreadDumpUserData
;
3826 static gboolean thread_dump_requested
;
3828 /* This needs to be async safe */
3830 collect_frame (MonoStackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
3832 ThreadDumpUserData
*ud
= (ThreadDumpUserData
*)data
;
3834 if (ud
->nframes
< ud
->max_frames
) {
3835 memcpy (&ud
->frames
[ud
->nframes
], frame
, sizeof (MonoStackFrameInfo
));
3842 /* This needs to be async safe */
3843 static SuspendThreadResult
3844 get_thread_dump (MonoThreadInfo
*info
, gpointer ud
)
3846 ThreadDumpUserData
*user_data
= (ThreadDumpUserData
*)ud
;
3847 MonoInternalThread
*thread
= user_data
->thread
;
3850 /* This no longer works with remote unwinding */
3851 g_string_append_printf (text
, " tid=0x%p this=0x%p ", (gpointer
)(gsize
)thread
->tid
, thread
);
3852 mono_thread_internal_describe (thread
, text
);
3853 g_string_append (text
, "\n");
3856 if (thread
== mono_thread_internal_current ())
3857 mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (collect_frame
, NULL
, MONO_UNWIND_SIGNAL_SAFE
, ud
);
3859 mono_get_eh_callbacks ()->mono_walk_stack_with_state (collect_frame
, mono_thread_info_get_suspend_state (info
), MONO_UNWIND_SIGNAL_SAFE
, ud
);
3861 return MonoResumeThread
;
3865 int nthreads
, max_threads
;
3868 } CollectThreadsUserData
;
3871 int nthreads
, max_threads
;
3872 MonoNativeThreadId
*threads
;
3873 } CollectThreadIdsUserData
;
3876 collect_thread (gpointer key
, gpointer value
, gpointer user
)
3878 CollectThreadsUserData
*ud
= (CollectThreadsUserData
*)user
;
3879 MonoInternalThread
*thread
= (MonoInternalThread
*)value
;
3881 if (ud
->nthreads
< ud
->max_threads
)
3882 ud
->threads
[ud
->nthreads
++] = mono_gchandle_new_internal (&thread
->obj
, TRUE
);
3886 * Collect running threads into the THREADS array.
3887 * THREADS should be an array allocated on the stack.
3890 collect_threads (guint32
*thread_handles
, int max_threads
)
3892 CollectThreadsUserData ud
;
3894 mono_memory_barrier ();
3898 memset (&ud
, 0, sizeof (ud
));
3899 /* This array contains refs, but its on the stack, so its ok */
3900 ud
.threads
= thread_handles
;
3901 ud
.max_threads
= max_threads
;
3903 mono_threads_lock ();
3904 mono_g_hash_table_foreach (threads
, collect_thread
, &ud
);
3905 mono_threads_unlock ();
3911 mono_gstring_append_thread_name (GString
* text
, MonoInternalThread
* thread
)
3913 // FIXME Conversion here is temporary. thread->name will change to UTF8.
3914 char* const name
= thread
->name
3915 ? g_utf16_to_utf8 (thread
->name
, thread
->name_len
, NULL
, NULL
, NULL
)
3917 g_string_append (text
, "\n\"");
3918 g_string_append (text
, name
? name
:
3919 thread
->threadpool_thread
? "<threadpool thread>" :
3920 "<unnamed thread>");
3921 g_string_append (text
, "\"");
3926 dump_thread (MonoInternalThread
*thread
, ThreadDumpUserData
*ud
, FILE* output_file
)
3928 GString
* text
= g_string_new (0);
3931 ud
->thread
= thread
;
3934 /* Collect frames for the thread */
3935 if (thread
== mono_thread_internal_current ()) {
3936 get_thread_dump (mono_thread_info_current (), ud
);
3938 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread
), FALSE
, get_thread_dump
, ud
);
3942 * Do all the non async-safe work outside of get_thread_dump.
3944 mono_gstring_append_thread_name (text
, thread
);
3946 for (i
= 0; i
< ud
->nframes
; ++i
) {
3947 MonoStackFrameInfo
*frame
= &ud
->frames
[i
];
3948 MonoMethod
*method
= NULL
;
3950 if (frame
->type
== FRAME_TYPE_MANAGED
)
3951 method
= mono_jit_info_get_method (frame
->ji
);
3954 gchar
*location
= mono_debug_print_stack_frame (method
, frame
->native_offset
, frame
->domain
);
3955 g_string_append_printf (text
, " %s\n", location
);
3958 g_string_append_printf (text
, " at <unknown> <0x%05x>\n", frame
->native_offset
);
3962 g_fprintf (output_file
, "%s", text
->str
);
3964 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3965 OutputDebugStringA(text
->str
);
3968 g_string_free (text
, TRUE
);
3969 fflush (output_file
);
3973 mono_get_time_of_day (struct timeval
*tv
) {
3977 tv
->tv_sec
= time
.time
;
3978 tv
->tv_usec
= time
.millitm
* 1000;
3980 if (gettimeofday (tv
, NULL
) == -1) {
3981 g_error ("gettimeofday() failed; errno is %d (%s)", errno
, strerror (errno
));
3987 mono_local_time (const struct timeval
*tv
, struct tm
*tm
) {
3988 #ifdef HAVE_LOCALTIME_R
3989 localtime_r(&tv
->tv_sec
, tm
);
3991 time_t const tv_sec
= tv
->tv_sec
; // Copy due to Win32/Posix contradiction.
3992 *tm
= *localtime (&tv_sec
);
3997 mono_threads_perform_thread_dump (void)
3999 FILE* output_file
= NULL
;
4000 ThreadDumpUserData ud
;
4001 guint32 thread_array
[128];
4002 int tindex
, nthreads
;
4004 if (!thread_dump_requested
)
4007 if (thread_dump_dir
!= NULL
) {
4008 GString
* path
= g_string_new (0);
4013 mono_get_time_of_day (&tv
);
4014 mono_local_time(&tv
, &tod
);
4015 strftime(time_str
, sizeof(time_str
), MONO_STRFTIME_F
"_" MONO_STRFTIME_T
, &tod
);
4016 ms
= tv
.tv_usec
/ 1000;
4017 g_string_append_printf (path
, "%s/%s.%03ld.tdump", thread_dump_dir
, time_str
, ms
);
4018 output_file
= fopen (path
->str
, "w");
4019 g_string_free (path
, TRUE
);
4021 if (output_file
== NULL
) {
4022 g_print ("Full thread dump:\n");
4025 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
4026 nthreads
= collect_threads (thread_array
, 128);
4028 memset (&ud
, 0, sizeof (ud
));
4029 ud
.frames
= g_new0 (MonoStackFrameInfo
, 256);
4030 ud
.max_frames
= 256;
4032 for (tindex
= 0; tindex
< nthreads
; ++tindex
) {
4033 guint32 handle
= thread_array
[tindex
];
4034 MonoInternalThread
*thread
= (MonoInternalThread
*) mono_gchandle_get_target_internal (handle
);
4035 dump_thread (thread
, &ud
, output_file
!= NULL
? output_file
: stdout
);
4036 mono_gchandle_free_internal (handle
);
4039 if (output_file
!= NULL
) {
4040 fclose (output_file
);
4044 thread_dump_requested
= FALSE
;
4047 /* Obtain the thread dump of all threads */
4049 mono_threads_get_thread_dump (MonoArray
**out_threads
, MonoArray
**out_stack_frames
, MonoError
*error
)
4052 ThreadDumpUserData ud
;
4053 guint32 thread_array
[128];
4054 MonoDomain
*domain
= mono_domain_get ();
4055 MonoDebugSourceLocation
*location
;
4056 int tindex
, nthreads
;
4060 *out_threads
= NULL
;
4061 *out_stack_frames
= NULL
;
4063 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
4064 nthreads
= collect_threads (thread_array
, 128);
4066 memset (&ud
, 0, sizeof (ud
));
4067 ud
.frames
= g_new0 (MonoStackFrameInfo
, 256);
4068 ud
.max_frames
= 256;
4070 *out_threads
= mono_array_new_checked (domain
, mono_defaults
.thread_class
, nthreads
, error
);
4071 goto_if_nok (error
, leave
);
4072 *out_stack_frames
= mono_array_new_checked (domain
, mono_defaults
.array_class
, nthreads
, error
);
4073 goto_if_nok (error
, leave
);
4075 for (tindex
= 0; tindex
< nthreads
; ++tindex
) {
4076 guint32 handle
= thread_array
[tindex
];
4077 MonoInternalThread
*thread
= (MonoInternalThread
*) mono_gchandle_get_target_internal (handle
);
4079 MonoArray
*thread_frames
;
4085 /* Collect frames for the thread */
4086 if (thread
== mono_thread_internal_current ()) {
4087 get_thread_dump (mono_thread_info_current (), &ud
);
4089 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread
), FALSE
, get_thread_dump
, &ud
);
4092 mono_array_setref_fast (*out_threads
, tindex
, mono_thread_current_for_thread (thread
));
4094 thread_frames
= mono_array_new_checked (domain
, mono_defaults
.stack_frame_class
, ud
.nframes
, error
);
4095 goto_if_nok (error
, leave
);
4096 mono_array_setref_fast (*out_stack_frames
, tindex
, thread_frames
);
4098 for (i
= 0; i
< ud
.nframes
; ++i
) {
4099 MonoStackFrameInfo
*frame
= &ud
.frames
[i
];
4100 MonoMethod
*method
= NULL
;
4101 MonoStackFrame
*sf
= (MonoStackFrame
*)mono_object_new_checked (domain
, mono_defaults
.stack_frame_class
, error
);
4102 goto_if_nok (error
, leave
);
4104 sf
->native_offset
= frame
->native_offset
;
4106 if (frame
->type
== FRAME_TYPE_MANAGED
)
4107 method
= mono_jit_info_get_method (frame
->ji
);
4110 sf
->method_address
= (gsize
) frame
->ji
->code_start
;
4112 MonoReflectionMethod
*rm
= mono_method_get_object_checked (domain
, method
, NULL
, error
);
4113 goto_if_nok (error
, leave
);
4114 MONO_OBJECT_SETREF_INTERNAL (sf
, method
, rm
);
4116 location
= mono_debug_lookup_source_location (method
, frame
->native_offset
, domain
);
4118 sf
->il_offset
= location
->il_offset
;
4120 if (location
->source_file
) {
4121 MonoString
*filename
= mono_string_new_checked (domain
, location
->source_file
, error
);
4122 goto_if_nok (error
, leave
);
4123 MONO_OBJECT_SETREF_INTERNAL (sf
, filename
, filename
);
4124 sf
->line
= location
->row
;
4125 sf
->column
= location
->column
;
4127 mono_debug_free_source_location (location
);
4132 mono_array_setref_internal (thread_frames
, i
, sf
);
4135 mono_gchandle_free_internal (handle
);
4140 return is_ok (error
);
4144 * mono_threads_request_thread_dump:
4146 * Ask all threads except the current to print their stacktrace to stdout.
4149 mono_threads_request_thread_dump (void)
4151 /*The new thread dump code runs out of the finalizer thread. */
4152 thread_dump_requested
= TRUE
;
4153 mono_gc_finalize_notify ();
4158 gint allocated
; /* +1 so that refs [allocated] == NULL */
4162 typedef struct ref_stack RefStack
;
4165 ref_stack_new (gint initial_size
)
4169 initial_size
= MAX (initial_size
, 16) + 1;
4170 rs
= g_new0 (RefStack
, 1);
4171 rs
->refs
= g_new0 (gpointer
, initial_size
);
4172 rs
->allocated
= initial_size
;
4177 ref_stack_destroy (gpointer ptr
)
4179 RefStack
*rs
= (RefStack
*)ptr
;
4188 ref_stack_push (RefStack
*rs
, gpointer ptr
)
4190 g_assert (rs
!= NULL
);
4192 if (rs
->bottom
>= rs
->allocated
) {
4193 rs
->refs
= (void **)g_realloc (rs
->refs
, rs
->allocated
* 2 * sizeof (gpointer
) + 1);
4194 rs
->allocated
<<= 1;
4195 rs
->refs
[rs
->allocated
] = NULL
;
4197 rs
->refs
[rs
->bottom
++] = ptr
;
4201 ref_stack_pop (RefStack
*rs
)
4203 if (rs
== NULL
|| rs
->bottom
== 0)
4207 rs
->refs
[rs
->bottom
] = NULL
;
4211 ref_stack_find (RefStack
*rs
, gpointer ptr
)
4218 for (refs
= rs
->refs
; refs
&& *refs
; refs
++) {
4226 * mono_thread_push_appdomain_ref:
4228 * Register that the current thread may have references to objects in domain
4229 * @domain on its stack. Each call to this function should be paired with a
4230 * call to pop_appdomain_ref.
4233 mono_thread_push_appdomain_ref (MonoDomain
*domain
)
4235 MonoInternalThread
*thread
= mono_thread_internal_current ();
4238 /* printf ("PUSH REF: %" G_GSIZE_FORMAT " -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
4239 SPIN_LOCK (thread
->lock_thread_id
);
4240 if (thread
->appdomain_refs
== NULL
)
4241 thread
->appdomain_refs
= ref_stack_new (16);
4242 ref_stack_push ((RefStack
*)thread
->appdomain_refs
, domain
);
4243 SPIN_UNLOCK (thread
->lock_thread_id
);
4248 mono_thread_pop_appdomain_ref (void)
4250 MonoInternalThread
*thread
= mono_thread_internal_current ();
4253 /* printf ("POP REF: %" G_GSIZE_FORMAT " -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
4254 SPIN_LOCK (thread
->lock_thread_id
);
4255 ref_stack_pop ((RefStack
*)thread
->appdomain_refs
);
4256 SPIN_UNLOCK (thread
->lock_thread_id
);
4261 mono_thread_internal_has_appdomain_ref (MonoInternalThread
*thread
, MonoDomain
*domain
)
4264 SPIN_LOCK (thread
->lock_thread_id
);
4265 res
= ref_stack_find ((RefStack
*)thread
->appdomain_refs
, domain
);
4266 SPIN_UNLOCK (thread
->lock_thread_id
);
4271 mono_thread_has_appdomain_ref (MonoThread
*thread
, MonoDomain
*domain
)
4273 return mono_thread_internal_has_appdomain_ref (thread
->internal_thread
, domain
);
4276 typedef struct abort_appdomain_data
{
4277 struct wait_data wait
;
4279 } abort_appdomain_data
;
4282 collect_appdomain_thread (gpointer key
, gpointer value
, gpointer user_data
)
4284 MonoInternalThread
*thread
= (MonoInternalThread
*)value
;
4285 abort_appdomain_data
*data
= (abort_appdomain_data
*)user_data
;
4286 MonoDomain
*domain
= data
->domain
;
4288 if (mono_thread_internal_has_appdomain_ref (thread
, domain
)) {
4289 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
4291 if(data
->wait
.num
<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
) {
4292 data
->wait
.handles
[data
->wait
.num
] = mono_threads_open_thread_handle (thread
->handle
);
4293 data
->wait
.threads
[data
->wait
.num
] = thread
;
4296 /* Just ignore the rest, we can't do anything with
4304 * mono_threads_abort_appdomain_threads:
4306 * Abort threads which has references to the given appdomain.
4309 mono_threads_abort_appdomain_threads (MonoDomain
*domain
, int timeout
)
4311 abort_appdomain_data user_data
;
4313 int orig_timeout
= timeout
;
4316 THREAD_DEBUG (g_message ("%s: starting abort", __func__
));
4318 start_time
= mono_msec_ticks ();
4320 mono_threads_lock ();
4322 user_data
.domain
= domain
;
4323 user_data
.wait
.num
= 0;
4324 /* This shouldn't take any locks */
4325 mono_g_hash_table_foreach (threads
, collect_appdomain_thread
, &user_data
);
4326 mono_threads_unlock ();
4328 if (user_data
.wait
.num
> 0) {
4329 /* Abort the threads outside the threads lock */
4330 for (i
= 0; i
< user_data
.wait
.num
; ++i
)
4331 mono_thread_internal_abort (user_data
.wait
.threads
[i
], TRUE
);
4334 * We should wait for the threads either to abort, or to leave the
4335 * domain. We can't do the latter, so we wait with a timeout.
4337 wait_for_tids (&user_data
.wait
, 100, FALSE
);
4340 /* Update remaining time */
4341 timeout
-= mono_msec_ticks () - start_time
;
4342 start_time
= mono_msec_ticks ();
4344 if (orig_timeout
!= -1 && timeout
< 0)
4347 while (user_data
.wait
.num
> 0);
4349 THREAD_DEBUG (g_message ("%s: abort done", __func__
));
4354 /* This is a JIT icall. This icall is called from a finally block when
4355 * mono_install_handler_block_guard called by another thread has flipped the
4356 * finally block's exvar (see mono_find_exvar_for_offset). In that case, if
4357 * the finally is in an abort protected block, we must defer the abort
4358 * exception until we leave the abort protected block. Otherwise we proceed
4359 * with a synchronous self-abort.
4362 ves_icall_thread_finish_async_abort (void)
4364 /* We were called from the handler block and are about to
4365 * leave it. (If we end up postponing the abort because we're
4366 * in an abort protected block, the unwinder won't run and
4367 * won't clear the handler block itself which will confuse the
4368 * unwinder if we're in a try {} catch {} and we throw again.
4370 * static Constructor () {
4374 * icall (); // Thread.Abort landed here,
4375 * // and caused the handler block to be installed
4377 * ves_icall_thread_finish_async_abort (); // we're here
4381 * // unwinder will get confused here and synthesize a self abort
4385 * More interestingly, this doesn't only happen with icalls - a JIT
4386 * trampoline is native code that will cause a handler to be installed.
4387 * So the above situation can happen with any code in a "finally"
4390 mono_get_eh_callbacks ()->mono_uninstall_current_handler_block_guard ();
4391 /* Just set the async interruption requested bit. Rely on the icall
4392 * wrapper of this icall to process the thread interruption, respecting
4393 * any abort protection blocks in our call stack.
4395 mono_thread_set_self_interruption_respect_abort_prot ();
4399 * mono_thread_get_undeniable_exception:
4401 * Return an exception which needs to be raised when leaving a catch clause.
4402 * This is used for undeniable exception propagation.
4405 mono_thread_get_undeniable_exception (void)
4407 MonoInternalThread
*thread
= mono_thread_internal_current ();
4409 if (!(thread
&& thread
->abort_exc
&& !is_running_protected_wrapper ()))
4412 // We don't want to have our exception effect calls made by
4413 // the catching block
4415 if (!mono_get_eh_callbacks ()->mono_above_abort_threshold ())
4419 * FIXME: Clear the abort exception and return an AppDomainUnloaded
4420 * exception if the thread no longer references a dying appdomain.
4422 thread
->abort_exc
->trace_ips
= NULL
;
4423 thread
->abort_exc
->stack_trace
= NULL
;
4424 return thread
->abort_exc
;
4427 #if MONO_SMALL_CONFIG
4428 #define NUM_STATIC_DATA_IDX 4
4429 static const int static_data_size
[NUM_STATIC_DATA_IDX
] = {
4433 #define NUM_STATIC_DATA_IDX 8
4434 static const int static_data_size
[NUM_STATIC_DATA_IDX
] = {
4435 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
4439 static MonoBitSet
*thread_reference_bitmaps
[NUM_STATIC_DATA_IDX
];
4440 static MonoBitSet
*context_reference_bitmaps
[NUM_STATIC_DATA_IDX
];
4443 mark_slots (void *addr
, MonoBitSet
**bitmaps
, MonoGCMarkFunc mark_func
, void *gc_data
)
4445 gpointer
*static_data
= (gpointer
*)addr
;
4447 for (int i
= 0; i
< NUM_STATIC_DATA_IDX
; ++i
) {
4448 void **ptr
= (void **)static_data
[i
];
4453 MONO_BITSET_FOREACH (bitmaps
[i
], idx
, {
4454 void **p
= ptr
+ idx
;
4457 mark_func ((MonoObject
**)p
, gc_data
);
4463 mark_tls_slots (void *addr
, MonoGCMarkFunc mark_func
, void *gc_data
)
4465 mark_slots (addr
, thread_reference_bitmaps
, mark_func
, gc_data
);
4469 mark_ctx_slots (void *addr
, MonoGCMarkFunc mark_func
, void *gc_data
)
4471 mark_slots (addr
, context_reference_bitmaps
, mark_func
, gc_data
);
4475 * mono_alloc_static_data
4477 * Allocate memory blocks for storing threads or context static data
4480 mono_alloc_static_data (gpointer
**static_data_ptr
, guint32 offset
, void *alloc_key
, gboolean threadlocal
)
4482 guint idx
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, index
);
4485 gpointer
* static_data
= *static_data_ptr
;
4487 static MonoGCDescriptor tls_desc
= MONO_GC_DESCRIPTOR_NULL
;
4488 static MonoGCDescriptor ctx_desc
= MONO_GC_DESCRIPTOR_NULL
;
4490 if (mono_gc_user_markers_supported ()) {
4491 if (tls_desc
== MONO_GC_DESCRIPTOR_NULL
)
4492 tls_desc
= mono_gc_make_root_descr_user (mark_tls_slots
);
4494 if (ctx_desc
== MONO_GC_DESCRIPTOR_NULL
)
4495 ctx_desc
= mono_gc_make_root_descr_user (mark_ctx_slots
);
4498 static_data
= (void **)mono_gc_alloc_fixed (static_data_size
[0], threadlocal
? tls_desc
: ctx_desc
,
4499 threadlocal
? MONO_ROOT_SOURCE_THREAD_STATIC
: MONO_ROOT_SOURCE_CONTEXT_STATIC
,
4501 threadlocal
? "ThreadStatic Fields" : "ContextStatic Fields");
4502 *static_data_ptr
= static_data
;
4503 static_data
[0] = static_data
;
4506 for (i
= 1; i
<= idx
; ++i
) {
4507 if (static_data
[i
])
4510 if (mono_gc_user_markers_supported ())
4511 static_data
[i
] = g_malloc0 (static_data_size
[i
]);
4513 static_data
[i
] = mono_gc_alloc_fixed (static_data_size
[i
], MONO_GC_DESCRIPTOR_NULL
,
4514 threadlocal
? MONO_ROOT_SOURCE_THREAD_STATIC
: MONO_ROOT_SOURCE_CONTEXT_STATIC
,
4516 threadlocal
? "ThreadStatic Fields" : "ContextStatic Fields");
4521 mono_free_static_data (gpointer
* static_data
)
4524 for (i
= 1; i
< NUM_STATIC_DATA_IDX
; ++i
) {
4525 gpointer p
= static_data
[i
];
4529 * At this point, the static data pointer array is still registered with the
4530 * GC, so must ensure that mark_tls_slots() will not encounter any invalid
4531 * data. Freeing the individual arrays without first nulling their slots
4532 * would make it possible for mark_tls/ctx_slots() to encounter a pointer to
4533 * such an already freed array. See bug #13813.
4535 static_data
[i
] = NULL
;
4536 mono_memory_write_barrier ();
4537 if (mono_gc_user_markers_supported ())
4540 mono_gc_free_fixed (p
);
4542 mono_gc_free_fixed (static_data
);
4546 * mono_init_static_data_info
4548 * Initializes static data counters
4550 static void mono_init_static_data_info (StaticDataInfo
*static_data
)
4552 static_data
->idx
= 0;
4553 static_data
->offset
= 0;
4554 static_data
->freelist
= NULL
;
4558 * mono_alloc_static_data_slot
4560 * Generates an offset for static data. static_data contains the counters
4561 * used to generate it.
4564 mono_alloc_static_data_slot (StaticDataInfo
*static_data
, guint32 size
, guint32 align
)
4566 if (!static_data
->idx
&& !static_data
->offset
) {
4568 * we use the first chunk of the first allocation also as
4569 * an array for the rest of the data
4571 static_data
->offset
= sizeof (gpointer
) * NUM_STATIC_DATA_IDX
;
4573 static_data
->offset
+= align
- 1;
4574 static_data
->offset
&= ~(align
- 1);
4575 if (static_data
->offset
+ size
>= static_data_size
[static_data
->idx
]) {
4576 static_data
->idx
++;
4577 g_assert (size
<= static_data_size
[static_data
->idx
]);
4578 g_assert (static_data
->idx
< NUM_STATIC_DATA_IDX
);
4579 static_data
->offset
= 0;
4581 guint32 offset
= MAKE_SPECIAL_STATIC_OFFSET (static_data
->idx
, static_data
->offset
, 0);
4582 static_data
->offset
+= size
;
4587 * LOCKING: requires that threads_mutex is held
4590 context_adjust_static_data (MonoAppContextHandle ctx_handle
)
4592 MonoAppContext
*ctx
= MONO_HANDLE_RAW (ctx_handle
);
4593 if (context_static_info
.offset
|| context_static_info
.idx
> 0) {
4594 guint32 offset
= MAKE_SPECIAL_STATIC_OFFSET (context_static_info
.idx
, context_static_info
.offset
, 0);
4595 mono_alloc_static_data (&ctx
->static_data
, offset
, ctx
, FALSE
);
4596 ctx
->data
->static_data
= ctx
->static_data
;
4601 * LOCKING: requires that threads_mutex is held
4604 alloc_thread_static_data_helper (gpointer key
, gpointer value
, gpointer user
)
4606 MonoInternalThread
*thread
= (MonoInternalThread
*)value
;
4607 guint32 offset
= GPOINTER_TO_UINT (user
);
4609 mono_alloc_static_data (&(thread
->static_data
), offset
, (void *) MONO_UINT_TO_NATIVE_THREAD_ID (thread
->tid
), TRUE
);
4613 * LOCKING: requires that threads_mutex is held
4616 alloc_context_static_data_helper (gpointer key
, gpointer value
, gpointer user
)
4618 MonoAppContext
*ctx
= (MonoAppContext
*) mono_gchandle_get_target_internal (GPOINTER_TO_INT (key
));
4623 guint32 offset
= GPOINTER_TO_UINT (user
);
4624 mono_alloc_static_data (&ctx
->static_data
, offset
, ctx
, FALSE
);
4625 ctx
->data
->static_data
= ctx
->static_data
;
4628 static StaticDataFreeList
*
4629 search_slot_in_freelist (StaticDataInfo
*static_data
, guint32 size
, guint32 align
)
4631 StaticDataFreeList
* prev
= NULL
;
4632 StaticDataFreeList
* tmp
= static_data
->freelist
;
4634 if (tmp
->size
== size
) {
4636 prev
->next
= tmp
->next
;
4638 static_data
->freelist
= tmp
->next
;
4647 #if SIZEOF_VOID_P == 4
4654 update_reference_bitmap (MonoBitSet
**sets
, guint32 offset
, uintptr_t *bitmap
, int numbits
)
4656 int idx
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, index
);
4658 sets
[idx
] = mono_bitset_new (static_data_size
[idx
] / sizeof (uintptr_t), 0);
4659 MonoBitSet
*rb
= sets
[idx
];
4660 offset
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, offset
);
4661 offset
/= sizeof (uintptr_t);
4662 /* offset is now the bitmap offset */
4663 for (int i
= 0; i
< numbits
; ++i
) {
4664 if (bitmap
[i
/ sizeof (uintptr_t)] & (ONE_P
<< (i
& (sizeof (uintptr_t) * 8 -1))))
4665 mono_bitset_set_fast (rb
, offset
+ i
);
4670 clear_reference_bitmap (MonoBitSet
**sets
, guint32 offset
, guint32 size
)
4672 int idx
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, index
);
4673 MonoBitSet
*rb
= sets
[idx
];
4674 offset
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, offset
);
4675 offset
/= sizeof (uintptr_t);
4676 /* offset is now the bitmap offset */
4677 for (int i
= 0; i
< size
/ sizeof (uintptr_t); i
++)
4678 mono_bitset_clear_fast (rb
, offset
+ i
);
4682 mono_alloc_special_static_data (guint32 static_type
, guint32 size
, guint32 align
, uintptr_t *bitmap
, int numbits
)
4684 g_assert (static_type
== SPECIAL_STATIC_THREAD
|| static_type
== SPECIAL_STATIC_CONTEXT
);
4686 StaticDataInfo
*info
;
4689 if (static_type
== SPECIAL_STATIC_THREAD
) {
4690 info
= &thread_static_info
;
4691 sets
= thread_reference_bitmaps
;
4693 info
= &context_static_info
;
4694 sets
= context_reference_bitmaps
;
4697 mono_threads_lock ();
4699 StaticDataFreeList
*item
= search_slot_in_freelist (info
, size
, align
);
4703 offset
= item
->offset
;
4706 offset
= mono_alloc_static_data_slot (info
, size
, align
);
4709 update_reference_bitmap (sets
, offset
, bitmap
, numbits
);
4711 if (static_type
== SPECIAL_STATIC_THREAD
) {
4712 /* This can be called during startup */
4713 if (threads
!= NULL
)
4714 mono_g_hash_table_foreach (threads
, alloc_thread_static_data_helper
, GUINT_TO_POINTER (offset
));
4716 if (contexts
!= NULL
)
4717 g_hash_table_foreach (contexts
, alloc_context_static_data_helper
, GUINT_TO_POINTER (offset
));
4719 ACCESS_SPECIAL_STATIC_OFFSET (offset
, type
) = SPECIAL_STATIC_OFFSET_TYPE_CONTEXT
;
4722 mono_threads_unlock ();
4728 mono_get_special_static_data_for_thread (MonoInternalThread
*thread
, guint32 offset
)
4730 guint32 static_type
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, type
);
4732 if (static_type
== SPECIAL_STATIC_OFFSET_TYPE_THREAD
) {
4733 return get_thread_static_data (thread
, offset
);
4735 return get_context_static_data (thread
->current_appcontext
, offset
);
4740 mono_get_special_static_data (guint32 offset
)
4742 return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset
);
4751 * LOCKING: requires that threads_mutex is held
4754 free_thread_static_data_helper (gpointer key
, gpointer value
, gpointer user
)
4756 MonoInternalThread
*thread
= (MonoInternalThread
*)value
;
4757 OffsetSize
*data
= (OffsetSize
*)user
;
4758 int idx
= ACCESS_SPECIAL_STATIC_OFFSET (data
->offset
, index
);
4759 int off
= ACCESS_SPECIAL_STATIC_OFFSET (data
->offset
, offset
);
4762 if (!thread
->static_data
|| !thread
->static_data
[idx
])
4764 ptr
= ((char*) thread
->static_data
[idx
]) + off
;
4765 mono_gc_bzero_atomic (ptr
, data
->size
);
4769 * LOCKING: requires that threads_mutex is held
4772 free_context_static_data_helper (gpointer key
, gpointer value
, gpointer user
)
4774 MonoAppContext
*ctx
= (MonoAppContext
*) mono_gchandle_get_target_internal (GPOINTER_TO_INT (key
));
4779 OffsetSize
*data
= (OffsetSize
*)user
;
4780 int idx
= ACCESS_SPECIAL_STATIC_OFFSET (data
->offset
, index
);
4781 int off
= ACCESS_SPECIAL_STATIC_OFFSET (data
->offset
, offset
);
4784 if (!ctx
->static_data
|| !ctx
->static_data
[idx
])
4787 ptr
= ((char*) ctx
->static_data
[idx
]) + off
;
4788 mono_gc_bzero_atomic (ptr
, data
->size
);
4792 do_free_special_slot (guint32 offset
, guint32 size
)
4794 guint32 static_type
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, type
);
4796 StaticDataInfo
*info
;
4798 if (static_type
== SPECIAL_STATIC_OFFSET_TYPE_THREAD
) {
4799 info
= &thread_static_info
;
4800 sets
= thread_reference_bitmaps
;
4802 info
= &context_static_info
;
4803 sets
= context_reference_bitmaps
;
4806 guint32 data_offset
= offset
;
4807 ACCESS_SPECIAL_STATIC_OFFSET (data_offset
, type
) = 0;
4808 OffsetSize data
= { data_offset
, size
};
4810 clear_reference_bitmap (sets
, data
.offset
, data
.size
);
4812 if (static_type
== SPECIAL_STATIC_OFFSET_TYPE_THREAD
) {
4813 if (threads
!= NULL
)
4814 mono_g_hash_table_foreach (threads
, free_thread_static_data_helper
, &data
);
4816 if (contexts
!= NULL
)
4817 g_hash_table_foreach (contexts
, free_context_static_data_helper
, &data
);
4820 if (!mono_runtime_is_shutting_down ()) {
4821 StaticDataFreeList
*item
= g_new0 (StaticDataFreeList
, 1);
4823 item
->offset
= offset
;
4826 item
->next
= info
->freelist
;
4827 info
->freelist
= item
;
4832 do_free_special (gpointer key
, gpointer value
, gpointer data
)
4834 MonoClassField
*field
= (MonoClassField
*)key
;
4835 guint32 offset
= GPOINTER_TO_UINT (value
);
4838 size
= mono_type_size (field
->type
, &align
);
4839 do_free_special_slot (offset
, size
);
4843 mono_alloc_special_static_data_free (GHashTable
*special_static_fields
)
4845 mono_threads_lock ();
4847 g_hash_table_foreach (special_static_fields
, do_free_special
, NULL
);
4849 mono_threads_unlock ();
4854 flush_thread_interrupt_queue (void)
4856 /* Consume pending APC calls for current thread.*/
4857 /* Since this function get's called from interrupt handler it must use a direct */
4858 /* Win32 API call and can't go through mono_coop_win32_wait_for_single_object_ex */
4859 /* or it will detect a pending interrupt and not entering the wait call needed */
4860 /* to consume pending APC's.*/
4862 WaitForSingleObjectEx (GetCurrentThread (), 0, TRUE
);
4867 flush_thread_interrupt_queue (void)
4873 * mono_thread_execute_interruption
4875 * Performs the operation that the requested thread state requires (abort,
4879 mono_thread_execute_interruption (MonoExceptionHandle
*pexc
)
4881 gboolean fexc
= FALSE
;
4883 // Optimize away frame if caller supplied one.
4885 HANDLE_FUNCTION_ENTER ();
4886 MonoExceptionHandle exc
= MONO_HANDLE_NEW (MonoException
, NULL
);
4887 fexc
= mono_thread_execute_interruption (&exc
);
4888 HANDLE_FUNCTION_RETURN_VAL (fexc
);
4891 MONO_REQ_GC_UNSAFE_MODE
;
4893 MonoInternalThreadHandle thread
= mono_thread_internal_current_handle ();
4894 MonoExceptionHandle exc
= MONO_HANDLE_NEW (MonoException
, NULL
);
4896 lock_thread_handle (thread
);
4897 gboolean unlock
= TRUE
;
4899 /* MonoThread::interruption_requested can only be changed with atomics */
4900 if (!mono_thread_clear_interruption_requested_handle (thread
))
4903 MonoThreadObjectHandle sys_thread
;
4904 sys_thread
= mono_thread_current_handle ();
4906 flush_thread_interrupt_queue ();
4908 /* Clear the interrupted flag of the thread so it can wait again */
4909 mono_thread_info_clear_self_interrupt ();
4911 /* If there's a pending exception and an AbortRequested, the pending exception takes precedence */
4912 MONO_HANDLE_GET (exc
, sys_thread
, pending_exception
);
4913 if (!MONO_HANDLE_IS_NULL (exc
)) {
4914 // sys_thread->pending_exception = NULL;
4915 MONO_HANDLE_SETRAW (sys_thread
, pending_exception
, NULL
);
4918 } else if (MONO_HANDLE_GETVAL (thread
, state
) & ThreadState_AbortRequested
) {
4919 // Does the thread already have an abort exception?
4920 // If not, create a new one and set it on demand.
4921 // exc = thread->abort_exc;
4922 MONO_HANDLE_GET (exc
, thread
, abort_exc
);
4923 if (MONO_HANDLE_IS_NULL (exc
)) {
4925 exc
= mono_exception_new_thread_abort (error
);
4926 mono_error_assert_ok (error
); // FIXME
4927 // thread->abort_exc = exc;
4928 MONO_HANDLE_SET (thread
, abort_exc
, exc
);
4931 } else if (MONO_HANDLE_GETVAL (thread
, state
) & ThreadState_SuspendRequested
) {
4932 /* calls UNLOCK_THREAD (thread) */
4933 self_suspend_internal ();
4935 } else if (MONO_HANDLE_GETVAL (thread
, thread_interrupt_requested
)) {
4936 // thread->thread_interrupt_requested = FALSE
4937 MONO_HANDLE_SETVAL (thread
, thread_interrupt_requested
, MonoBoolean
, FALSE
);
4938 unlock_thread_handle (thread
);
4941 exc
= mono_exception_new_thread_interrupted (error
);
4942 mono_error_assert_ok (error
); // FIXME
4947 unlock_thread_handle (thread
);
4950 MONO_HANDLE_ASSIGN (*pexc
, exc
);
4956 mono_thread_execute_interruption_void (void)
4958 (void)mono_thread_execute_interruption (NULL
);
4961 static MonoException
*
4962 mono_thread_execute_interruption_ptr (void)
4964 HANDLE_FUNCTION_ENTER ();
4965 MonoExceptionHandle exc
= MONO_HANDLE_NEW (MonoException
, NULL
);
4966 MonoException
* const exc_raw
= mono_thread_execute_interruption (&exc
) ? MONO_HANDLE_RAW (exc
) : NULL
;
4967 HANDLE_FUNCTION_RETURN_VAL (exc_raw
);
4971 * mono_thread_request_interruption_internal
4973 * A signal handler can call this method to request the interruption of a
4974 * thread. The result of the interruption will depend on the current state of
4975 * the thread. If the result is an exception that needs to be thrown, it is
4976 * provided as return value.
4979 mono_thread_request_interruption_internal (gboolean running_managed
, MonoExceptionHandle
*pexc
)
4981 MonoInternalThread
*thread
= mono_thread_internal_current ();
4983 /* The thread may already be stopping */
4987 if (!mono_thread_set_interruption_requested (thread
))
4990 if (!running_managed
|| is_running_protected_wrapper ()) {
4991 /* Can't stop while in unmanaged code. Increase the global interruption
4992 request count. When exiting the unmanaged method the count will be
4993 checked and the thread will be interrupted. */
4995 /* this will awake the thread if it is in WaitForSingleObject
4998 mono_win32_interrupt_wait (thread
->thread_info
, thread
->native_handle
, (DWORD
)thread
->tid
);
5000 mono_thread_info_self_interrupt ();
5004 return mono_thread_execute_interruption (pexc
);
5008 mono_thread_request_interruption_native (void)
5010 (void)mono_thread_request_interruption_internal (FALSE
, NULL
);
5014 mono_thread_request_interruption_managed (MonoExceptionHandle
*exc
)
5016 return mono_thread_request_interruption_internal (TRUE
, exc
);
5019 /*This function should be called by a thread after it has exited all of
5020 * its handle blocks at interruption time.*/
5022 mono_thread_resume_interruption (gboolean exec
)
5024 MonoInternalThread
*thread
= mono_thread_internal_current ();
5025 gboolean still_aborting
;
5027 /* The thread may already be stopping */
5031 LOCK_THREAD (thread
);
5032 still_aborting
= (thread
->state
& (ThreadState_AbortRequested
)) != 0;
5033 UNLOCK_THREAD (thread
);
5035 /*This can happen if the protected block called Thread::ResetAbort*/
5036 if (!still_aborting
)
5039 if (!mono_thread_set_interruption_requested (thread
))
5042 mono_thread_info_self_interrupt ();
5044 if (exec
) // Ignore the exception here, it will be raised later.
5045 mono_thread_execute_interruption_void ();
5049 mono_thread_interruption_requested (void)
5051 if (thread_interruption_requested
) {
5052 MonoInternalThread
*thread
= mono_thread_internal_current ();
5053 /* The thread may already be stopping */
5055 return mono_thread_get_interruption_requested (thread
);
5060 static MonoException
*
5061 mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection
)
5063 MonoInternalThread
*thread
= mono_thread_internal_current ();
5065 /* The thread may already be stopping */
5068 if (!mono_thread_get_interruption_requested (thread
))
5070 if (!bypass_abort_protection
&& !mono_thread_current ()->pending_exception
&& is_running_protected_wrapper ())
5073 return mono_thread_execute_interruption_ptr ();
5077 * Performs the interruption of the current thread, if one has been requested,
5078 * and the thread is not running a protected wrapper.
5079 * Return the exception which needs to be thrown, if any.
5082 mono_thread_interruption_checkpoint (void)
5084 return mono_thread_interruption_checkpoint_request (FALSE
);
5088 mono_thread_interruption_checkpoint_bool (void)
5090 return mono_thread_interruption_checkpoint () != NULL
;
5094 mono_thread_interruption_checkpoint_void (void)
5096 mono_thread_interruption_checkpoint ();
5100 * Performs the interruption of the current thread, if one has been requested.
5101 * Return the exception which needs to be thrown, if any.
5104 mono_thread_force_interruption_checkpoint_noraise (void)
5106 return mono_thread_interruption_checkpoint_request (TRUE
);
5110 * mono_set_pending_exception:
5112 * Set the pending exception of the current thread to EXC.
5113 * The exception will be thrown when execution returns to managed code.
5116 mono_set_pending_exception (MonoException
*exc
)
5118 MonoThread
*thread
= mono_thread_current ();
5120 /* The thread may already be stopping */
5124 MONO_OBJECT_SETREF_INTERNAL (thread
, pending_exception
, exc
);
5126 mono_thread_request_interruption_native ();
5130 * mono_runtime_set_pending_exception:
5132 * Set the pending exception of the current thread to \p exc.
5133 * The exception will be thrown when execution returns to managed code.
5134 * Can optionally \p overwrite any existing pending exceptions (it's not supported
5135 * to overwrite any pending exceptions if the runtime is processing a thread abort request,
5136 * in which case the behavior will be undefined).
5137 * Return whether the pending exception was set or not.
5138 * It will not be set if:
5139 * * The thread or runtime is stopping or shutting down
5140 * * There already is a pending exception (and \p overwrite is false)
5143 mono_runtime_set_pending_exception (MonoException
*exc
, mono_bool overwrite
)
5145 MonoThread
*thread
= mono_thread_current ();
5147 /* The thread may already be stopping */
5151 /* Don't overwrite any existing pending exceptions unless asked to */
5152 if (!overwrite
&& thread
->pending_exception
)
5155 MONO_OBJECT_SETREF_INTERNAL (thread
, pending_exception
, exc
);
5157 mono_thread_request_interruption_native ();
5164 * mono_set_pending_exception_handle:
5166 * Set the pending exception of the current thread to EXC.
5167 * The exception will be thrown when execution returns to managed code.
5170 mono_set_pending_exception_handle (MonoExceptionHandle exc
)
5172 MonoThread
*thread
= mono_thread_current ();
5174 /* The thread may already be stopping */
5178 MONO_OBJECT_SETREF_INTERNAL (thread
, pending_exception
, MONO_HANDLE_RAW (exc
));
5180 mono_thread_request_interruption_native ();
5184 * mono_thread_interruption_request_flag:
5186 * Returns the address of a flag that will be non-zero if an interruption has
5187 * been requested for a thread. The thread to interrupt may not be the current
5188 * thread, so an additional call to mono_thread_interruption_requested() or
5189 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
5193 mono_thread_interruption_request_flag (void)
5195 return &thread_interruption_requested
;
5199 mono_thread_init_apartment_state (void)
5202 MonoInternalThread
* thread
= mono_thread_internal_current ();
5204 /* Positive return value indicates success, either
5205 * S_OK if this is first CoInitialize call, or
5206 * S_FALSE if CoInitialize already called, but with same
5207 * threading model. A negative value indicates failure,
5208 * probably due to trying to change the threading model.
5210 if (CoInitializeEx(NULL
, (thread
->apartment_state
== ThreadApartmentState_STA
)
5211 ? COINIT_APARTMENTTHREADED
5212 : COINIT_MULTITHREADED
) < 0) {
5213 thread
->apartment_state
= ThreadApartmentState_Unknown
;
5219 mono_thread_cleanup_apartment_state (void)
5222 MonoInternalThread
* thread
= mono_thread_internal_current ();
5224 if (thread
&& thread
->apartment_state
!= ThreadApartmentState_Unknown
) {
5231 mono_thread_notify_change_state (MonoThreadState old_state
, MonoThreadState new_state
)
5233 MonoThreadState diff
= old_state
^ new_state
;
5234 if (diff
& ThreadState_Background
) {
5235 /* If the thread changes the background mode, the main thread has to
5236 * be notified, since it has to rebuild the list of threads to
5240 mono_os_event_set (&background_change_event
);
5246 mono_thread_clear_and_set_state (MonoInternalThread
*thread
, MonoThreadState clear
, MonoThreadState set
)
5248 LOCK_THREAD (thread
);
5250 MonoThreadState
const old_state
= (MonoThreadState
)thread
->state
;
5251 MonoThreadState
const new_state
= (old_state
& ~clear
) | set
;
5252 thread
->state
= new_state
;
5254 UNLOCK_THREAD (thread
);
5256 mono_thread_notify_change_state (old_state
, new_state
);
5260 mono_thread_set_state (MonoInternalThread
*thread
, MonoThreadState state
)
5262 mono_thread_clear_and_set_state (thread
, (MonoThreadState
)0, state
);
5266 * mono_thread_test_and_set_state:
5267 * Test if current state of \p thread include \p test. If it does not, OR \p set into the state.
5268 * \returns TRUE if \p set was OR'd in.
5271 mono_thread_test_and_set_state (MonoInternalThread
*thread
, MonoThreadState test
, MonoThreadState set
)
5273 LOCK_THREAD (thread
);
5275 MonoThreadState
const old_state
= (MonoThreadState
)thread
->state
;
5277 if ((old_state
& test
) != 0) {
5278 UNLOCK_THREAD (thread
);
5282 MonoThreadState
const new_state
= old_state
| set
;
5283 thread
->state
= new_state
;
5285 UNLOCK_THREAD (thread
);
5287 mono_thread_notify_change_state (old_state
, new_state
);
5293 mono_thread_clr_state (MonoInternalThread
*thread
, MonoThreadState state
)
5295 mono_thread_clear_and_set_state (thread
, state
, (MonoThreadState
)0);
5299 mono_thread_test_state (MonoInternalThread
*thread
, MonoThreadState test
)
5301 LOCK_THREAD (thread
);
5303 gboolean
const ret
= ((thread
->state
& test
) != 0);
5305 UNLOCK_THREAD (thread
);
5311 self_interrupt_thread (void *_unused
)
5314 MonoThreadInfo
*info
;
5317 exc
= mono_thread_execute_interruption_ptr ();
5319 if (mono_threads_are_safepoints_enabled ()) {
5320 /* We can return from an async call in coop, as
5321 * it's simply called when exiting the safepoint */
5322 /* If we're using hybrid suspend, we only self
5323 * interrupt if we were running, hence using
5328 g_error ("%s: we can't resume from an async call", __func__
);
5331 info
= mono_thread_info_current ();
5333 /* FIXME using thread_saved_state [ASYNC_SUSPEND_STATE_INDEX] can race with another suspend coming in. */
5334 ctx
= info
->thread_saved_state
[ASYNC_SUSPEND_STATE_INDEX
].ctx
;
5336 mono_raise_exception_with_context (exc
, &ctx
);
5340 mono_jit_info_match (MonoJitInfo
*ji
, gpointer ip
)
5344 return ji
->code_start
<= ip
&& (char*)ip
< (char*)ji
->code_start
+ ji
->code_size
;
5348 last_managed (MonoStackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
5350 MonoJitInfo
**dest
= (MonoJitInfo
**)data
;
5356 mono_thread_info_get_last_managed (MonoThreadInfo
*info
)
5358 MonoJitInfo
*ji
= NULL
;
5363 * The suspended thread might be holding runtime locks. Make sure we don't try taking
5364 * any runtime locks while unwinding.
5366 mono_thread_info_set_is_async_context (TRUE
);
5367 mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed
, mono_thread_info_get_suspend_state (info
), MONO_UNWIND_SIGNAL_SAFE
, &ji
);
5368 mono_thread_info_set_is_async_context (FALSE
);
5373 MonoInternalThread
*thread
;
5374 gboolean install_async_abort
;
5375 MonoThreadInfoInterruptToken
*interrupt_token
;
5378 static SuspendThreadResult
5379 async_abort_critical (MonoThreadInfo
*info
, gpointer ud
)
5381 AbortThreadData
*data
= (AbortThreadData
*)ud
;
5382 MonoInternalThread
*thread
= data
->thread
;
5383 MonoJitInfo
*ji
= NULL
;
5384 gboolean protected_wrapper
;
5385 gboolean running_managed
;
5387 if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info
)))
5388 return MonoResumeThread
;
5390 /*someone is already interrupting it*/
5391 if (!mono_thread_set_interruption_requested (thread
))
5392 return MonoResumeThread
;
5394 ji
= mono_thread_info_get_last_managed (info
);
5395 protected_wrapper
= ji
&& !ji
->is_trampoline
&& !ji
->async
&& mono_threads_is_critical_method (mono_jit_info_get_method (ji
));
5396 running_managed
= mono_jit_info_match (ji
, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info
)->ctx
));
5398 if (!protected_wrapper
&& running_managed
) {
5399 /*We are in managed code*/
5400 /*Set the thread to call */
5401 if (data
->install_async_abort
)
5402 mono_thread_info_setup_async_call (info
, self_interrupt_thread
, NULL
);
5403 return MonoResumeThread
;
5406 * This will cause waits to be broken.
5407 * It will also prevent the thread from entering a wait, so if the thread returns
5408 * from the wait before it receives the abort signal, it will just spin in the wait
5409 * functions in the io-layer until the signal handler calls QueueUserAPC which will
5412 data
->interrupt_token
= mono_thread_info_prepare_interrupt (info
);
5414 return MonoResumeThread
;
5419 async_abort_internal (MonoInternalThread
*thread
, gboolean install_async_abort
)
5421 AbortThreadData data
;
5423 g_assert (thread
!= mono_thread_internal_current ());
5425 data
.thread
= thread
;
5426 data
.install_async_abort
= install_async_abort
;
5427 data
.interrupt_token
= NULL
;
5429 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread
), TRUE
, async_abort_critical
, &data
);
5430 if (data
.interrupt_token
)
5431 mono_thread_info_finish_interrupt (data
.interrupt_token
);
5432 /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
5436 self_abort_internal (MonoError
*error
)
5438 HANDLE_FUNCTION_ENTER ();
5442 /* FIXME this is insanely broken, it doesn't cause interruption to happen synchronously
5443 * since passing FALSE to mono_thread_request_interruption makes sure it returns NULL */
5446 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.
5448 MonoExceptionHandle exc
= MONO_HANDLE_NEW (MonoException
, NULL
);
5449 if (mono_thread_request_interruption_managed (&exc
))
5450 mono_error_set_exception_handle (error
, exc
);
5452 mono_thread_info_self_interrupt ();
5454 HANDLE_FUNCTION_RETURN ();
5458 MonoInternalThread
*thread
;
5460 MonoThreadInfoInterruptToken
*interrupt_token
;
5461 } SuspendThreadData
;
5463 static SuspendThreadResult
5464 async_suspend_critical (MonoThreadInfo
*info
, gpointer ud
)
5466 SuspendThreadData
*data
= (SuspendThreadData
*)ud
;
5467 MonoInternalThread
*thread
= data
->thread
;
5468 MonoJitInfo
*ji
= NULL
;
5469 gboolean protected_wrapper
;
5470 gboolean running_managed
;
5472 ji
= mono_thread_info_get_last_managed (info
);
5473 protected_wrapper
= ji
&& !ji
->is_trampoline
&& !ji
->async
&& mono_threads_is_critical_method (mono_jit_info_get_method (ji
));
5474 running_managed
= mono_jit_info_match (ji
, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info
)->ctx
));
5476 if (running_managed
&& !protected_wrapper
) {
5477 if (mono_threads_are_safepoints_enabled ()) {
5478 mono_thread_info_setup_async_call (info
, self_interrupt_thread
, NULL
);
5479 return MonoResumeThread
;
5481 thread
->state
&= ~ThreadState_SuspendRequested
;
5482 thread
->state
|= ThreadState_Suspended
;
5483 return KeepSuspended
;
5486 mono_thread_set_interruption_requested (thread
);
5487 if (data
->interrupt
)
5488 data
->interrupt_token
= mono_thread_info_prepare_interrupt ((MonoThreadInfo
*)thread
->thread_info
);
5490 return MonoResumeThread
;
5494 /* LOCKING: called with @thread longlived->synch_cs held, and releases it */
5496 async_suspend_internal (MonoInternalThread
*thread
, gboolean interrupt
)
5498 SuspendThreadData data
;
5500 g_assert (thread
!= mono_thread_internal_current ());
5502 // g_async_safe_printf ("ASYNC SUSPEND thread %p\n", thread_get_tid (thread));
5504 thread
->self_suspended
= FALSE
;
5506 data
.thread
= thread
;
5507 data
.interrupt
= interrupt
;
5508 data
.interrupt_token
= NULL
;
5510 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread
), interrupt
, async_suspend_critical
, &data
);
5511 if (data
.interrupt_token
)
5512 mono_thread_info_finish_interrupt (data
.interrupt_token
);
5514 UNLOCK_THREAD (thread
);
5517 /* LOCKING: called with @thread longlived->synch_cs held, and releases it */
5519 self_suspend_internal (void)
5521 MonoInternalThread
*thread
;
5523 MonoOSEventWaitRet res
;
5525 thread
= mono_thread_internal_current ();
5527 // g_async_safe_printf ("SELF SUSPEND thread %p\n", thread_get_tid (thread));
5529 thread
->self_suspended
= TRUE
;
5531 thread
->state
&= ~ThreadState_SuspendRequested
;
5532 thread
->state
|= ThreadState_Suspended
;
5534 UNLOCK_THREAD (thread
);
5536 event
= thread
->suspended
;
5539 res
= mono_os_event_wait_one (event
, MONO_INFINITE_WAIT
, TRUE
);
5540 g_assert (res
== MONO_OS_EVENT_WAIT_RET_SUCCESS_0
|| res
== MONO_OS_EVENT_WAIT_RET_ALERTED
);
5545 suspend_for_shutdown_async_call (gpointer unused
)
5548 mono_thread_info_yield ();
5551 static SuspendThreadResult
5552 suspend_for_shutdown_critical (MonoThreadInfo
*info
, gpointer unused
)
5554 mono_thread_info_setup_async_call (info
, suspend_for_shutdown_async_call
, NULL
);
5555 return MonoResumeThread
;
5559 mono_thread_internal_suspend_for_shutdown (MonoInternalThread
*thread
)
5561 g_assert (thread
!= mono_thread_internal_current ());
5563 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread
), FALSE
, suspend_for_shutdown_critical
, NULL
);
5567 * mono_thread_is_foreign:
5568 * \param thread the thread to query
5570 * This function allows one to determine if a thread was created by the mono runtime and has
5571 * a well defined lifecycle or it's a foreign one, created by the native environment.
5573 * \returns TRUE if \p thread was not created by the runtime.
5576 mono_thread_is_foreign (MonoThread
*thread
)
5579 MONO_ENTER_GC_UNSAFE
;
5580 MonoThreadInfo
*info
= (MonoThreadInfo
*)thread
->internal_thread
->thread_info
;
5581 result
= (info
->runtime_thread
== FALSE
);
5582 MONO_EXIT_GC_UNSAFE
;
5588 threads_native_thread_join_lock (gpointer tid
, gpointer value
)
5590 pthread_t thread
= (pthread_t
)tid
;
5591 if (thread
!= pthread_self ()) {
5593 /* This shouldn't block */
5594 mono_threads_join_lock ();
5595 mono_native_thread_join (thread
);
5596 mono_threads_join_unlock ();
5601 threads_native_thread_join_nolock (gpointer tid
, gpointer value
)
5603 pthread_t thread
= (pthread_t
)tid
;
5605 mono_native_thread_join (thread
);
5610 threads_add_joinable_thread_nolock (gpointer tid
)
5612 g_hash_table_insert (joinable_threads
, tid
, tid
);
5616 threads_native_thread_join_lock (gpointer tid
, gpointer value
)
5618 MonoNativeThreadId thread_id
= (MonoNativeThreadId
)(guint64
)tid
;
5619 HANDLE thread_handle
= (HANDLE
)value
;
5620 if (thread_id
!= GetCurrentThreadId () && thread_handle
!= NULL
&& thread_handle
!= INVALID_HANDLE_VALUE
) {
5622 /* This shouldn't block */
5623 mono_threads_join_lock ();
5624 mono_native_thread_join_handle (thread_handle
, TRUE
);
5625 mono_threads_join_unlock ();
5631 threads_native_thread_join_nolock (gpointer tid
, gpointer value
)
5633 HANDLE thread_handle
= (HANDLE
)value
;
5635 mono_native_thread_join_handle (thread_handle
, TRUE
);
5640 threads_add_joinable_thread_nolock (gpointer tid
)
5642 g_hash_table_insert (joinable_threads
, tid
, (gpointer
)OpenThread (SYNCHRONIZE
, TRUE
, (MonoNativeThreadId
)(guint64
)tid
));
5647 threads_add_pending_joinable_thread (gpointer tid
)
5649 joinable_threads_lock ();
5651 if (!pending_joinable_threads
)
5652 pending_joinable_threads
= g_hash_table_new (NULL
, NULL
);
5657 if (!g_hash_table_lookup_extended (pending_joinable_threads
, tid
, &orig_key
, &value
)) {
5658 g_hash_table_insert (pending_joinable_threads
, tid
, tid
);
5659 UnlockedIncrement (&pending_joinable_thread_count
);
5662 joinable_threads_unlock ();
5666 threads_add_pending_joinable_runtime_thread (MonoThreadInfo
*mono_thread_info
)
5668 g_assert (mono_thread_info
);
5670 if (mono_thread_info
->runtime_thread
) {
5671 threads_add_pending_joinable_thread ((gpointer
)(MONO_UINT_TO_NATIVE_THREAD_ID (mono_thread_info_get_tid (mono_thread_info
))));
5676 threads_remove_pending_joinable_thread_nolock (gpointer tid
)
5681 if (pending_joinable_threads
&& g_hash_table_lookup_extended (pending_joinable_threads
, tid
, &orig_key
, &value
)) {
5682 g_hash_table_remove (pending_joinable_threads
, tid
);
5683 if (UnlockedDecrement (&pending_joinable_thread_count
) == 0)
5684 mono_coop_cond_broadcast (&zero_pending_joinable_thread_event
);
5689 threads_wait_pending_joinable_threads (uint32_t timeout
)
5691 if (UnlockedRead (&pending_joinable_thread_count
) > 0) {
5692 joinable_threads_lock ();
5693 if (timeout
== MONO_INFINITE_WAIT
) {
5694 while (UnlockedRead (&pending_joinable_thread_count
) > 0)
5695 mono_coop_cond_wait (&zero_pending_joinable_thread_event
, &joinable_threads_mutex
);
5697 gint64 start
= mono_msec_ticks ();
5699 while (UnlockedRead (&pending_joinable_thread_count
) > 0 && elapsed
< timeout
) {
5700 mono_coop_cond_timedwait (&zero_pending_joinable_thread_event
, &joinable_threads_mutex
, timeout
- (uint32_t)elapsed
);
5701 elapsed
= mono_msec_ticks () - start
;
5704 joinable_threads_unlock ();
5707 return UnlockedRead (&pending_joinable_thread_count
) == 0;
5711 threads_add_unique_joinable_thread_nolock (gpointer tid
)
5713 if (!joinable_threads
)
5714 joinable_threads
= g_hash_table_new (NULL
, NULL
);
5719 if (!g_hash_table_lookup_extended (joinable_threads
, tid
, &orig_key
, &value
)) {
5720 threads_add_joinable_thread_nolock (tid
);
5721 UnlockedIncrement (&joinable_thread_count
);
5726 mono_threads_add_joinable_runtime_thread (MonoThreadInfo
*thread_info
)
5728 g_assert (thread_info
);
5729 MonoThreadInfo
*mono_thread_info
= thread_info
;
5731 if (mono_thread_info
->runtime_thread
) {
5732 gpointer tid
= (gpointer
)(MONO_UINT_TO_NATIVE_THREAD_ID (mono_thread_info_get_tid (mono_thread_info
)));
5734 joinable_threads_lock ();
5736 // Add to joinable thread list, if not already included.
5737 threads_add_unique_joinable_thread_nolock (tid
);
5739 // Remove thread from pending joinable list, if present.
5740 threads_remove_pending_joinable_thread_nolock (tid
);
5742 joinable_threads_unlock ();
5744 mono_gc_finalize_notify ();
5749 threads_add_pending_native_thread_join_call_nolock (gpointer tid
)
5751 if (!pending_native_thread_join_calls
)
5752 pending_native_thread_join_calls
= g_hash_table_new (NULL
, NULL
);
5757 if (!g_hash_table_lookup_extended (pending_native_thread_join_calls
, tid
, &orig_key
, &value
))
5758 g_hash_table_insert (pending_native_thread_join_calls
, tid
, tid
);
5762 threads_remove_pending_native_thread_join_call_nolock (gpointer tid
)
5764 if (pending_native_thread_join_calls
)
5765 g_hash_table_remove (pending_native_thread_join_calls
, tid
);
5767 mono_coop_cond_broadcast (&pending_native_thread_join_calls_event
);
5771 threads_wait_pending_native_thread_join_call_nolock (gpointer tid
)
5776 while (g_hash_table_lookup_extended (pending_native_thread_join_calls
, tid
, &orig_key
, &value
)) {
5777 mono_coop_cond_wait (&pending_native_thread_join_calls_event
, &joinable_threads_mutex
);
5782 * mono_add_joinable_thread:
5784 * Add TID to the list of joinable threads.
5785 * LOCKING: Acquires the threads lock.
5788 mono_threads_add_joinable_thread (gpointer tid
)
5791 * We cannot detach from threads because it causes problems like
5792 * 2fd16f60/r114307. So we collect them and join them when
5793 * we have time (in the finalizer thread).
5795 joinable_threads_lock ();
5796 threads_add_unique_joinable_thread_nolock (tid
);
5797 joinable_threads_unlock ();
5799 mono_gc_finalize_notify ();
5803 * mono_threads_join_threads:
5805 * Join all joinable threads. This is called from the finalizer thread.
5806 * LOCKING: Acquires the threads lock.
5809 mono_threads_join_threads (void)
5811 GHashTableIter iter
;
5812 gpointer key
= NULL
;
5813 gpointer value
= NULL
;
5814 gboolean found
= FALSE
;
5817 if (!UnlockedRead (&joinable_thread_count
))
5821 joinable_threads_lock ();
5823 // Previous native thread join call completed.
5824 threads_remove_pending_native_thread_join_call_nolock (key
);
5827 if (g_hash_table_size (joinable_threads
)) {
5828 g_hash_table_iter_init (&iter
, joinable_threads
);
5829 g_hash_table_iter_next (&iter
, &key
, (void**)&value
);
5830 g_hash_table_remove (joinable_threads
, key
);
5831 UnlockedDecrement (&joinable_thread_count
);
5834 // Add to table of tid's with pending native thread join call.
5835 threads_add_pending_native_thread_join_call_nolock (key
);
5837 joinable_threads_unlock ();
5839 threads_native_thread_join_lock (key
, value
);
5848 * Wait for thread TID to exit.
5849 * LOCKING: Acquires the threads lock.
5852 mono_thread_join (gpointer tid
)
5854 gboolean found
= FALSE
;
5858 joinable_threads_lock ();
5859 if (!joinable_threads
)
5860 joinable_threads
= g_hash_table_new (NULL
, NULL
);
5862 if (g_hash_table_lookup_extended (joinable_threads
, tid
, &orig_key
, &value
)) {
5863 g_hash_table_remove (joinable_threads
, tid
);
5864 UnlockedDecrement (&joinable_thread_count
);
5867 // Add to table of tid's with pending native join call.
5868 threads_add_pending_native_thread_join_call_nolock (tid
);
5872 // Wait for any pending native thread join call not yet completed for this tid.
5873 threads_wait_pending_native_thread_join_call_nolock (tid
);
5876 joinable_threads_unlock ();
5881 threads_native_thread_join_nolock (tid
, value
);
5883 joinable_threads_lock ();
5884 // Native thread join call completed for this tid.
5885 threads_remove_pending_native_thread_join_call_nolock (tid
);
5886 joinable_threads_unlock ();
5890 mono_thread_internal_unhandled_exception (MonoObject
* exc
)
5892 MonoClass
*klass
= exc
->vtable
->klass
;
5893 if (is_threadabort_exception (klass
)) {
5894 mono_thread_internal_reset_abort (mono_thread_internal_current ());
5895 } else if (!is_appdomainunloaded_exception (klass
)
5896 && mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT
) {
5897 mono_unhandled_exception_internal (exc
);
5898 if (mono_environment_exitcode_get () == 1) {
5899 mono_environment_exitcode_set (255);
5900 mono_invoke_unhandled_exception_hook (exc
);
5901 g_assert_not_reached ();
5907 ves_icall_System_Threading_Thread_GetStackTraces (MonoArray
**out_threads
, MonoArray
**out_stack_traces
)
5910 mono_threads_get_thread_dump (out_threads
, out_stack_traces
, error
);
5911 mono_error_set_pending_exception (error
);
5915 * mono_threads_attach_coop_internal: called by native->managed wrappers
5918 * - blocking mode: contains gc unsafe transition cookie
5919 * - non-blocking mode: contains random data
5920 * - @stackdata: semi-opaque struct: stackpointer and function_name
5921 * - @return: the original domain which needs to be restored, or NULL.
5924 mono_threads_attach_coop_internal (MonoDomain
*domain
, gpointer
*cookie
, MonoStackData
*stackdata
)
5927 MonoThreadInfo
*info
;
5928 gboolean external
= FALSE
;
5930 orig
= mono_domain_get ();
5933 /* Happens when called from AOTed code which is only used in the root domain. */
5934 domain
= mono_get_root_domain ();
5938 /* On coop, when we detached, we moved the thread from RUNNING->BLOCKING.
5939 * If we try to reattach we do a BLOCKING->RUNNING transition. If the thread
5940 * is fresh, mono_thread_attach() will do a STARTING->RUNNING transition so
5941 * we're only responsible for making the cookie. */
5942 if (mono_threads_is_blocking_transition_enabled ())
5943 external
= !(info
= mono_thread_info_current_unchecked ()) || !mono_thread_info_is_live (info
);
5945 if (!mono_thread_internal_current ()) {
5946 mono_thread_attach (domain
);
5949 mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background
);
5952 if (mono_threads_is_blocking_transition_enabled ()) {
5954 /* mono_thread_attach put the thread in RUNNING mode from STARTING, but we need to
5955 * return the right cookie. */
5956 *cookie
= mono_threads_enter_gc_unsafe_region_cookie ();
5958 /* thread state (BLOCKING|RUNNING) -> RUNNING */
5959 *cookie
= mono_threads_enter_gc_unsafe_region_unbalanced_internal (stackdata
);
5964 mono_domain_set_fast (domain
, TRUE
);
5970 * mono_threads_attach_coop: called by native->managed wrappers
5973 * - blocking mode: contains gc unsafe transition cookie
5974 * - non-blocking mode: contains random data
5975 * - a pointer to stack, used for some checks
5976 * - @return: the original domain which needs to be restored, or NULL.
5979 mono_threads_attach_coop (MonoDomain
*domain
, gpointer
*dummy
)
5981 MONO_STACKDATA (stackdata
);
5982 stackdata
.stackpointer
= dummy
;
5983 return mono_threads_attach_coop_internal (domain
, dummy
, &stackdata
);
5987 * mono_threads_detach_coop_internal: called by native->managed wrappers
5989 * - @orig: the original domain which needs to be restored, or NULL.
5990 * - @stackdata: semi-opaque struct: stackpointer and function_name
5992 * - blocking mode: contains gc unsafe transition cookie
5993 * - non-blocking mode: contains random data
5996 mono_threads_detach_coop_internal (MonoDomain
*orig
, gpointer cookie
, MonoStackData
*stackdata
)
5998 MonoDomain
*domain
= mono_domain_get ();
6001 if (orig
!= domain
) {
6003 mono_domain_unset ();
6005 mono_domain_set_fast (orig
, TRUE
);
6008 if (mono_threads_is_blocking_transition_enabled ()) {
6009 /* it won't do anything if cookie is NULL
6010 * thread state RUNNING -> (RUNNING|BLOCKING) */
6011 mono_threads_exit_gc_unsafe_region_unbalanced_internal (cookie
, stackdata
);
6016 * mono_threads_detach_coop: called by native->managed wrappers
6018 * - @orig: the original domain which needs to be restored, or NULL.
6020 * - blocking mode: contains gc unsafe transition cookie
6021 * - non-blocking mode: contains random data
6022 * - a pointer to stack, used for some checks
6025 mono_threads_detach_coop (gpointer orig
, gpointer
*dummy
)
6027 MONO_STACKDATA (stackdata
);
6028 stackdata
.stackpointer
= dummy
;
6029 mono_threads_detach_coop_internal ((MonoDomain
*)orig
, *dummy
, &stackdata
);
6033 /* Returns TRUE if the current thread is ready to be interrupted. */
6035 mono_threads_is_ready_to_be_interrupted (void)
6037 MonoInternalThread
*thread
;
6039 thread
= mono_thread_internal_current ();
6040 LOCK_THREAD (thread
);
6041 if (thread
->state
& (ThreadState_SuspendRequested
| ThreadState_AbortRequested
)) {
6042 UNLOCK_THREAD (thread
);
6046 if (mono_thread_get_abort_prot_block_count (thread
) || mono_get_eh_callbacks ()->mono_current_thread_has_handle_block_guard ()) {
6047 UNLOCK_THREAD (thread
);
6051 UNLOCK_THREAD (thread
);
6057 mono_thread_internal_describe (MonoInternalThread
*internal
, GString
*text
)
6059 g_string_append_printf (text
, ", thread handle : %p", internal
->handle
);
6061 if (internal
->thread_info
) {
6062 g_string_append (text
, ", state : ");
6063 mono_thread_info_describe_interrupt_token (internal
->thread_info
, text
);
6066 if (internal
->owned_mutexes
) {
6069 g_string_append (text
, ", owns : [");
6070 for (i
= 0; i
< internal
->owned_mutexes
->len
; i
++)
6071 g_string_append_printf (text
, i
== 0 ? "%p" : ", %p", g_ptr_array_index (internal
->owned_mutexes
, i
));
6072 g_string_append (text
, "]");
6077 mono_thread_internal_is_current (MonoInternalThread
*internal
)
6079 g_assert (internal
);
6080 return mono_native_thread_id_equals (mono_native_thread_id_get (), MONO_UINT_TO_NATIVE_THREAD_ID (internal
->tid
));
6084 mono_set_thread_dump_dir (gchar
* dir
) {
6085 thread_dump_dir
= dir
;
6088 #ifdef DISABLE_CRASH_REPORTING
6090 mono_threads_summarize (MonoContext
*ctx
, gchar
**out
, MonoStackHash
*hashes
, gboolean silent
, gboolean signal_handler_controller
, gchar
*mem
, size_t provided_size
)
6096 mono_threads_summarize_one (MonoThreadSummary
*out
, MonoContext
*ctx
)
6104 mono_threads_summarize_native_self (MonoThreadSummary
*out
, MonoContext
*ctx
)
6106 if (!mono_get_eh_callbacks ()->mono_summarize_managed_stack
)
6109 memset (out
, 0, sizeof (MonoThreadSummary
));
6112 MonoNativeThreadId current
= mono_native_thread_id_get();
6113 out
->native_thread_id
= (intptr_t) current
;
6115 mono_get_eh_callbacks ()->mono_summarize_unmanaged_stack (out
);
6117 mono_native_thread_get_name (current
, out
->name
, MONO_MAX_SUMMARY_NAME_LEN
);
6122 // Not safe to call from signal handler
6124 mono_threads_summarize_one (MonoThreadSummary
*out
, MonoContext
*ctx
)
6126 gboolean success
= mono_threads_summarize_native_self (out
, ctx
);
6128 // Finish this on the same thread
6130 if (success
&& mono_get_eh_callbacks ()->mono_summarize_managed_stack
)
6131 mono_get_eh_callbacks ()->mono_summarize_managed_stack (out
);
6136 #define TIMEOUT_CRASH_REPORTER_FATAL 30
6137 #define MAX_NUM_THREADS 128
6139 gint32 has_owner
; // state of this memory
6141 MonoSemType update
; // notify of addition of threads
6144 MonoNativeThreadId thread_array
[MAX_NUM_THREADS
]; // ids of threads we're dumping
6146 int nthreads_attached
; // Number of threads self-registered
6147 MonoThreadSummary
*all_threads
[MAX_NUM_THREADS
];
6149 gboolean silent
; // print to stdout
6150 } SummarizerGlobalState
;
6152 #if defined(HAVE_KILL) && !defined(HOST_ANDROID) && defined(HAVE_WAITPID) && ((!defined(HOST_DARWIN) && defined(SYS_fork)) || HAVE_FORK)
6153 #define HAVE_MONO_SUMMARIZER_SUPERVISOR 1
6157 MonoSemType supervisor
;
6159 pid_t supervisor_pid
;
6160 } SummarizerSupervisorState
;
6162 #ifndef HAVE_MONO_SUMMARIZER_SUPERVISOR
6164 summarizer_supervisor_wait (SummarizerSupervisorState
*state
)
6170 summarizer_supervisor_start (SummarizerSupervisorState
*state
)
6172 // nonzero, so caller doesn't think it's the supervisor
6177 summarizer_supervisor_end (SummarizerSupervisorState
*state
)
6184 summarizer_supervisor_wait (SummarizerSupervisorState
*state
)
6186 sleep (TIMEOUT_CRASH_REPORTER_FATAL
);
6188 // If we haven't been SIGKILL'ed yet, we signal our parent
6191 g_async_safe_printf("Crash Reporter has timed out, sending SIGSEGV\n");
6192 kill (state
->pid
, SIGSEGV
);
6194 g_error ("kill () is not supported by this platform");
6201 summarizer_supervisor_start (SummarizerSupervisorState
*state
)
6203 memset (state
, 0, sizeof (*state
));
6206 state
->pid
= getpid();
6209 * glibc fork acquires some locks, so if the crash happened inside malloc/free,
6210 * it will deadlock. Call the syscall directly instead.
6212 #if defined(HOST_ANDROID)
6213 /* SYS_fork is defined to be __NR_fork which is not defined in some ndk versions */
6214 // We disable this when we set HAVE_MONO_SUMMARIZER_SUPERVISOR above
6215 g_assert_not_reached ();
6216 #elif !defined(HOST_DARWIN) && defined(SYS_fork)
6217 pid
= (pid_t
) syscall (SYS_fork
);
6219 pid
= (pid_t
) fork ();
6221 g_assert_not_reached ();
6225 state
->supervisor_pid
= pid
;
6231 summarizer_supervisor_end (SummarizerSupervisorState
*state
)
6234 kill (state
->supervisor_pid
, SIGKILL
);
6237 #if defined (HAVE_WAITPID)
6238 // Accessed on same thread that sets it.
6240 waitpid (state
->supervisor_pid
, &status
, 0);
6246 collect_thread_id (gpointer key
, gpointer value
, gpointer user
)
6248 CollectThreadIdsUserData
*ud
= (CollectThreadIdsUserData
*)user
;
6249 MonoInternalThread
*thread
= (MonoInternalThread
*)value
;
6251 if (ud
->nthreads
< ud
->max_threads
)
6252 ud
->threads
[ud
->nthreads
++] = thread_get_tid (thread
);
6256 collect_thread_ids (MonoNativeThreadId
*thread_ids
, int max_threads
)
6258 CollectThreadIdsUserData ud
;
6260 mono_memory_barrier ();
6264 memset (&ud
, 0, sizeof (ud
));
6265 /* This array contains refs, but its on the stack, so its ok */
6266 ud
.threads
= thread_ids
;
6267 ud
.max_threads
= max_threads
;
6269 mono_threads_lock ();
6270 mono_g_hash_table_foreach (threads
, collect_thread_id
, &ud
);
6271 mono_threads_unlock ();
6277 summarizer_state_init (SummarizerGlobalState
*state
, MonoNativeThreadId current
, int *my_index
)
6279 gint32 started_state
= mono_atomic_cas_i32 (&state
->has_owner
, 1 /* set */, 0 /* compare */);
6280 gboolean not_started
= started_state
== 0;
6282 state
->nthreads
= collect_thread_ids (state
->thread_array
, MAX_NUM_THREADS
);
6283 mono_os_sem_init (&state
->update
, 0);
6286 for (int i
= 0; i
< state
->nthreads
; i
++) {
6287 if (state
->thread_array
[i
] == current
) {
6297 summarizer_signal_other_threads (SummarizerGlobalState
*state
, MonoNativeThreadId current
, int current_idx
)
6299 sigset_t sigset
, old_sigset
;
6300 sigemptyset(&sigset
);
6301 sigaddset(&sigset
, SIGTERM
);
6303 for (int i
=0; i
< state
->nthreads
; i
++) {
6304 sigprocmask (SIG_UNBLOCK
, &sigset
, &old_sigset
);
6306 if (i
== current_idx
)
6309 #ifdef HAVE_PTHREAD_KILL
6310 pthread_kill (state
->thread_array
[i
], SIGTERM
);
6313 g_async_safe_printf("Pkilling 0x%zx from 0x%zx\n", MONO_NATIVE_THREAD_ID_TO_UINT (state
->thread_array
[i
]), MONO_NATIVE_THREAD_ID_TO_UINT (current
));
6315 g_error ("pthread_kill () is not supported by this platform");
6320 // Returns true when there are shared global references to "this_thread"
6322 summarizer_post_dump (SummarizerGlobalState
*state
, MonoThreadSummary
*this_thread
, int current_idx
)
6324 mono_memory_barrier ();
6326 gpointer old
= mono_atomic_cas_ptr ((volatile gpointer
*)&state
->all_threads
[current_idx
], this_thread
, NULL
);
6328 if (old
== GINT_TO_POINTER (-1)) {
6329 g_async_safe_printf ("Trying to register response after dumping period ended");
6331 } else if (old
!= NULL
) {
6332 g_async_safe_printf ("Thread dump raced for thread slot.");
6336 // We added our pointer
6337 gint32 count
= mono_atomic_inc_i32 ((volatile gint32
*) &state
->nthreads_attached
);
6338 if (count
== state
->nthreads
)
6339 mono_os_sem_post (&state
->update
);
6344 // A lockless spinwait with a timeout
6345 // Used in environments where locks are unsafe
6347 // If set_pos is true, we wait until the expected number of threads have
6348 // responded and then count that the expected number are set. If it is not true,
6349 // then we wait for them to be unset.
6351 summary_timedwait (SummarizerGlobalState
*state
, int timeout_seconds
)
6353 const gint64 milliseconds_in_second
= 1000;
6354 gint64 timeout_total
= milliseconds_in_second
* timeout_seconds
;
6356 gint64 end
= mono_msec_ticks () + timeout_total
;
6359 if (mono_atomic_load_i32 ((volatile gint32
*) &state
->nthreads_attached
) == state
->nthreads
)
6362 gint64 now
= mono_msec_ticks ();
6363 gint64 remaining
= end
- now
;
6367 mono_os_sem_timedwait (&state
->update
, remaining
, MONO_SEM_FLAGS_NONE
);
6373 static MonoThreadSummary
*
6374 summarizer_try_read_thread (SummarizerGlobalState
*state
, int index
)
6376 gpointer old_value
= NULL
;
6377 gpointer new_value
= GINT_TO_POINTER(-1);
6380 old_value
= state
->all_threads
[index
];
6381 } while (mono_atomic_cas_ptr ((volatile gpointer
*) &state
->all_threads
[index
], new_value
, old_value
) != old_value
);
6383 MonoThreadSummary
*thread
= (MonoThreadSummary
*) old_value
;
6388 summarizer_state_term (SummarizerGlobalState
*state
, gchar
**out
, gchar
*mem
, size_t provided_size
, MonoThreadSummary
*controlling
)
6390 // See the array writes
6391 mono_memory_barrier ();
6393 MonoThreadSummary
*threads
[MAX_NUM_THREADS
];
6394 memset (threads
, 0, sizeof(threads
));
6396 mono_summarize_timeline_phase_log (MonoSummaryManagedStacks
);
6397 for (int i
=0; i
< state
->nthreads
; i
++) {
6398 threads
[i
] = summarizer_try_read_thread (state
, i
);
6402 // We are doing this dump on the controlling thread because this isn't
6403 // an async context sometimes. There's still some reliance on malloc here, but it's
6404 // much more stable to do it all from the controlling thread.
6406 // This is non-null, checked in mono_threads_summarize
6407 // with early exit there
6408 mono_get_eh_callbacks ()->mono_summarize_managed_stack (threads
[i
]);
6411 MonoStateWriter writer
;
6412 memset (&writer
, 0, sizeof (writer
));
6414 mono_summarize_timeline_phase_log (MonoSummaryStateWriter
);
6415 mono_summarize_native_state_begin (&writer
, mem
, provided_size
);
6416 for (int i
=0; i
< state
->nthreads
; i
++) {
6417 MonoThreadSummary
*thread
= threads
[i
];
6421 mono_summarize_native_state_add_thread (&writer
, thread
, thread
->ctx
, thread
== controlling
);
6422 // Set non-shared state to notify the waiting thread to clean up
6423 // without having to keep our shared state alive
6424 mono_atomic_store_i32 (&thread
->done
, 0x1);
6425 mono_os_sem_post (&thread
->done_wait
);
6427 *out
= mono_summarize_native_state_end (&writer
);
6428 mono_summarize_timeline_phase_log (MonoSummaryStateWriterDone
);
6430 mono_os_sem_destroy (&state
->update
);
6432 memset (state
, 0, sizeof (*state
));
6433 mono_atomic_store_i32 ((volatile gint32
*)&state
->has_owner
, 0);
6437 summarizer_state_wait (MonoThreadSummary
*thread
)
6439 gint64 milliseconds_in_second
= 1000;
6441 // cond_wait can spuriously wake up, so we need to check
6443 while (!mono_atomic_load_i32 (&thread
->done
))
6444 mono_os_sem_timedwait (&thread
->done_wait
, milliseconds_in_second
, MONO_SEM_FLAGS_NONE
);
6448 mono_threads_summarize_execute_internal (MonoContext
*ctx
, gchar
**out
, MonoStackHash
*hashes
, gboolean silent
, gchar
*working_mem
, size_t provided_size
, gboolean this_thread_controls
)
6450 static SummarizerGlobalState state
;
6453 MonoNativeThreadId current
= mono_native_thread_id_get ();
6454 gboolean thread_given_control
= summarizer_state_init (&state
, current
, ¤t_idx
);
6456 g_assert (this_thread_controls
== thread_given_control
);
6458 if (state
.nthreads
== 0) {
6460 g_async_safe_printf("No threads attached to runtime.\n");
6461 memset (&state
, 0, sizeof (state
));
6465 if (this_thread_controls
) {
6466 g_assert (working_mem
);
6468 mono_summarize_timeline_phase_log (MonoSummarySuspendHandshake
);
6469 state
.silent
= silent
;
6470 summarizer_signal_other_threads (&state
, current
, current_idx
);
6471 mono_summarize_timeline_phase_log (MonoSummaryUnmanagedStacks
);
6475 gboolean success
= mono_state_alloc_mem (&mem
, (long) current
, sizeof (MonoThreadSummary
));
6479 MonoThreadSummary
*this_thread
= (MonoThreadSummary
*) mem
.mem
;
6481 if (mono_threads_summarize_native_self (this_thread
, ctx
)) {
6482 // Init the synchronization between the controlling thread and the
6484 mono_os_sem_init (&this_thread
->done_wait
, 0);
6486 // Store a reference to our stack memory into global state
6487 gboolean success
= summarizer_post_dump (&state
, this_thread
, current_idx
);
6488 if (!success
&& !state
.silent
)
6489 g_async_safe_printf("Thread 0x%zx reported itself.\n", MONO_NATIVE_THREAD_ID_TO_UINT (current
));
6490 } else if (!state
.silent
) {
6491 g_async_safe_printf("Thread 0x%zx couldn't report itself.\n", MONO_NATIVE_THREAD_ID_TO_UINT (current
));
6494 // From summarizer, wait and dump.
6495 if (this_thread_controls
) {
6497 g_async_safe_printf("Entering thread summarizer pause from 0x%zx\n", MONO_NATIVE_THREAD_ID_TO_UINT (current
));
6499 // Wait up to 2 seconds for all of the other threads to catch up
6500 summary_timedwait (&state
, 2);
6503 g_async_safe_printf("Finished thread summarizer pause from 0x%zx.\n", MONO_NATIVE_THREAD_ID_TO_UINT (current
));
6505 // Dump and cleanup all the stack memory
6506 summarizer_state_term (&state
, out
, working_mem
, provided_size
, this_thread
);
6508 // Wait here, keeping our stack memory alive
6510 summarizer_state_wait (this_thread
);
6513 // FIXME: How many threads should be counted?
6515 *hashes
= this_thread
->hashes
;
6517 mono_state_free_mem (&mem
);
6523 mono_threads_summarize_execute (MonoContext
*ctx
, gchar
**out
, MonoStackHash
*hashes
, gboolean silent
, gchar
*working_mem
, size_t provided_size
)
6525 return mono_threads_summarize_execute_internal (ctx
, out
, hashes
, silent
, working_mem
, provided_size
, FALSE
);
6529 mono_threads_summarize (MonoContext
*ctx
, gchar
**out
, MonoStackHash
*hashes
, gboolean silent
, gboolean signal_handler_controller
, gchar
*mem
, size_t provided_size
)
6531 if (!mono_get_eh_callbacks ()->mono_summarize_managed_stack
)
6534 // The staggered values are due to the need to use inc_i64 for the first value
6535 static gint64 next_pending_request_id
= 0;
6536 static gint64 request_available_to_run
= 1;
6537 gint64 this_request_id
= mono_atomic_inc_i64 ((volatile gint64
*) &next_pending_request_id
);
6539 // This is a global queue of summary requests.
6540 // It's not safe to signal a thread while they're in the
6541 // middle of a dump. Dladdr is not reentrant. It's the one lock
6542 // we rely on being able to take.
6544 // We don't use it in almost any other place in managed code, so
6545 // our problem is in the stack dumping code racing with the signalling code.
6547 // A dump is wait-free to the degree that it's not going to loop indefinitely.
6548 // If we're running from a crash handler block, we're not in any position to
6549 // wait for an in-flight dump to finish. If we crashed while dumping, we cannot dump.
6550 // We should simply return so we can die cleanly.
6552 // signal_handler_controller should be set only from a handler that expects itself to be the only
6553 // entry point, where the runtime already being dumping means we should just give up
6555 gboolean success
= FALSE
;
6558 gint64 next_request_id
= mono_atomic_load_i64 ((volatile gint64
*) &request_available_to_run
);
6560 if (next_request_id
== this_request_id
) {
6561 gboolean already_async
= mono_thread_info_is_async_context ();
6563 mono_thread_info_set_is_async_context (TRUE
);
6565 SummarizerSupervisorState synch
;
6566 if (summarizer_supervisor_start (&synch
)) {
6568 success
= mono_threads_summarize_execute_internal (ctx
, out
, hashes
, silent
, mem
, provided_size
, TRUE
);
6569 summarizer_supervisor_end (&synch
);
6571 summarizer_supervisor_wait (&synch
);
6575 mono_thread_info_set_is_async_context (FALSE
);
6577 // Only the thread that gets the ticket can unblock future dumpers.
6578 mono_atomic_inc_i64 ((volatile gint64
*) &request_available_to_run
);
6580 } else if (signal_handler_controller
) {
6581 // We're done. We can't do anything.
6582 g_async_safe_printf ("Attempted to dump for critical failure when already in dump. Error reporting crashed?");
6583 mono_summarize_double_fault_log ();
6587 g_async_safe_printf ("Waiting for in-flight dump to complete.");
6597 #ifdef ENABLE_NETCORE
6599 ves_icall_System_Threading_Thread_StartInternal (MonoThreadObjectHandle thread_handle
, MonoError
*error
)
6601 MonoThread
*internal
= MONO_HANDLE_RAW (thread_handle
);
6604 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p)", __func__
, internal
));
6606 LOCK_THREAD (internal
);
6608 if ((internal
->state
& ThreadState_Unstarted
) == 0) {
6609 UNLOCK_THREAD (internal
);
6610 mono_error_set_exception_thread_state (error
, "Thread has already been started.");
6614 if ((internal
->state
& ThreadState_Aborted
) != 0) {
6615 UNLOCK_THREAD (internal
);
6619 res
= create_thread (internal
, internal
, NULL
, NULL
, NULL
, MONO_THREAD_CREATE_FLAGS_NONE
, error
);
6621 UNLOCK_THREAD (internal
);
6625 internal
->state
&= ~ThreadState_Unstarted
;
6627 THREAD_DEBUG (g_message ("%s: Started thread ID %" G_GSIZE_FORMAT
" (handle %p)", __func__
, (gsize
)internal
->tid
, internal
->handle
));
6629 UNLOCK_THREAD (internal
);
6633 ves_icall_System_Threading_Thread_InitInternal (MonoThreadObjectHandle thread_handle
, MonoError
*error
)
6635 MonoThread
*internal
= MONO_HANDLE_RAW (thread_handle
);
6637 // Need to initialize thread objects created from managed code
6638 init_internal_thread_object (internal
);
6639 internal
->state
= ThreadState_Unstarted
;
6640 MONO_OBJECT_SETREF_INTERNAL (internal
, internal_thread
, internal
);
6644 ves_icall_System_Threading_Thread_GetCurrentOSThreadId (MonoError
*error
)
6646 return mono_native_thread_os_id_get ();