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>
61 #include <mono/metadata/mono-config.h>
62 #include <mono/utils/mono-tls-inline.h>
63 #include <mono/utils/lifo-semaphore.h>
65 #ifdef HAVE_SYS_WAIT_H
72 #pragma warning(disable:4312) // FIXME pointer cast to different size
75 #if defined(HOST_WIN32)
77 #include <sys/timeb.h>
79 mono_native_thread_join_handle (HANDLE thread_handle
, gboolean close_handle
);
82 #if defined(HOST_FUCHSIA)
83 #include <zircon/syscalls.h>
86 #if defined(HOST_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64)
87 #define USE_TKILL_ON_ANDROID 1
93 #ifdef USE_TKILL_ON_ANDROID
94 extern int tkill (pid_t tid
, int signal
);
98 #include "icall-decl.h"
100 /*#define THREAD_DEBUG(a) do { a; } while (0)*/
101 #define THREAD_DEBUG(a)
102 /*#define THREAD_WAIT_DEBUG(a) do { a; } while (0)*/
103 #define THREAD_WAIT_DEBUG(a)
104 /*#define LIBGC_DEBUG(a) do { a; } while (0)*/
105 #define LIBGC_DEBUG(a)
107 #define SPIN_TRYLOCK(i) (mono_atomic_cas_i32 (&(i), 1, 0) == 0)
108 #define SPIN_LOCK(i) do { \
109 if (SPIN_TRYLOCK (i)) \
113 #define SPIN_UNLOCK(i) i = 0
115 #define LOCK_THREAD(thread) lock_thread((thread))
116 #define UNLOCK_THREAD(thread) unlock_thread((thread))
128 typedef struct _StaticDataFreeList StaticDataFreeList
;
129 struct _StaticDataFreeList
{
130 StaticDataFreeList
*next
;
138 StaticDataFreeList
*freelist
;
141 /* Controls access to the 'threads' hash table */
142 static void mono_threads_lock (void);
143 static void mono_threads_unlock (void);
144 static MonoCoopMutex threads_mutex
;
146 /* Controls access to the 'joinable_threads' hash table */
147 #define joinable_threads_lock() mono_coop_mutex_lock (&joinable_threads_mutex)
148 #define joinable_threads_unlock() mono_coop_mutex_unlock (&joinable_threads_mutex)
149 static MonoCoopMutex joinable_threads_mutex
;
151 /* Holds current status of static data heap */
152 static StaticDataInfo thread_static_info
;
153 static StaticDataInfo context_static_info
;
155 /* The hash of existing threads (key is thread ID, value is
156 * MonoInternalThread*) that need joining before exit
158 static MonoGHashTable
*threads
=NULL
;
160 /* List of app context GC handles.
161 * Added to from mono_threads_register_app_context ().
163 static GHashTable
*contexts
= NULL
;
165 /* Cleanup queue for contexts. */
166 static MonoReferenceQueue
*context_queue
;
169 * Threads which are starting up and they are not in the 'threads' hash yet.
170 * When mono_thread_attach_internal is called for a thread, it will be removed from this hash table.
171 * Protected by mono_threads_lock ().
173 static MonoGHashTable
*threads_starting_up
= NULL
;
176 /* Protected by the threads lock */
177 static GHashTable
*joinable_threads
;
178 static gint32 joinable_thread_count
;
180 /* mono_threads_join_threads will take threads from joinable_threads list and wait for them. */
181 /* When this happens, the tid is not on the list anymore so mono_thread_join assumes the thread has complete */
182 /* and will return back to the caller. This could cause a race since caller of join assumes thread has completed */
183 /* and on some OS it could cause errors. Keeping the tid's currently pending a native thread join call */
184 /* in a separate table (only affecting callers interested in this internal join detail) and look at that table in mono_thread_join */
185 /* will close this race. */
186 static GHashTable
*pending_native_thread_join_calls
;
187 static MonoCoopCond pending_native_thread_join_calls_event
;
189 static GHashTable
*pending_joinable_threads
;
190 static gint32 pending_joinable_thread_count
;
192 static MonoCoopCond zero_pending_joinable_thread_event
;
194 static void threads_add_pending_joinable_runtime_thread (MonoThreadInfo
*mono_thread_info
);
195 static gboolean
threads_wait_pending_joinable_threads (uint32_t timeout
);
196 static gchar
* thread_dump_dir
= NULL
;
198 #define SET_CURRENT_OBJECT mono_tls_set_thread
199 #define GET_CURRENT_OBJECT mono_tls_get_thread
201 /* function called at thread start */
202 static MonoThreadStartCB mono_thread_start_cb
= NULL
;
204 /* function called at thread attach */
205 static MonoThreadAttachCB mono_thread_attach_cb
= NULL
;
207 /* function called at thread cleanup */
208 static MonoThreadCleanupFunc mono_thread_cleanup_fn
= NULL
;
210 /* The default stack size for each thread */
211 static guint32 default_stacksize
= 0;
212 #define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize)
214 static void context_adjust_static_data (MonoAppContextHandle ctx
);
215 static void mono_free_static_data (gpointer
* static_data
);
216 static void mono_init_static_data_info (StaticDataInfo
*static_data
);
217 static guint32
mono_alloc_static_data_slot (StaticDataInfo
*static_data
, guint32 size
, guint32 align
);
218 static gboolean
mono_thread_resume (MonoInternalThread
* thread
);
219 static void async_abort_internal (MonoInternalThread
*thread
, gboolean install_async_abort
);
220 static void self_abort_internal (MonoError
*error
);
221 static void async_suspend_internal (MonoInternalThread
*thread
, gboolean interrupt
);
222 static void self_suspend_internal (void);
225 mono_thread_set_interruption_requested_flags (MonoInternalThread
*thread
, gboolean sync
);
228 mono_set_pending_exception_handle (MonoExceptionHandle exc
);
230 static MonoException
*
231 mono_thread_execute_interruption_ptr (void);
234 mono_thread_execute_interruption_void (void);
237 mono_thread_execute_interruption (MonoExceptionHandle
*pexc
);
239 static void ref_stack_destroy (gpointer rs
);
241 #if SIZEOF_VOID_P == 4
242 /* Spin lock for unaligned InterlockedXXX 64 bit functions on 32bit platforms. */
243 #define mono_interlocked_lock() mono_os_mutex_lock (&interlocked_mutex)
244 #define mono_interlocked_unlock() mono_os_mutex_unlock (&interlocked_mutex)
245 static mono_mutex_t interlocked_mutex
;
248 /* global count of thread interruptions requested */
249 gint32 mono_thread_interruption_request_flag
;
251 /* Event signaled when a thread changes its background mode */
252 static MonoOSEvent background_change_event
;
254 static gboolean shutting_down
= FALSE
;
256 static gint32 managed_thread_id_counter
= 0;
259 mono_threads_lock (void)
261 mono_locks_coop_acquire (&threads_mutex
, ThreadsLock
);
265 mono_threads_unlock (void)
267 mono_locks_coop_release (&threads_mutex
, ThreadsLock
);
272 get_next_managed_thread_id (void)
274 return mono_atomic_inc_i32 (&managed_thread_id_counter
);
278 * We separate interruptions/exceptions into either sync (they can be processed anytime,
279 * normally as soon as they are set, and are set by the same thread) and async (they can't
280 * be processed inside abort protected blocks and are normally set by other threads). We
281 * can have both a pending sync and async interruption. In this case, the sync exception is
282 * processed first. Since we clean sync flag first, mono_thread_execute_interruption must
283 * also handle all sync type exceptions before the async type exceptions.
286 INTERRUPT_SYNC_REQUESTED_BIT
= 0x1,
287 INTERRUPT_ASYNC_REQUESTED_BIT
= 0x2,
288 INTERRUPT_REQUESTED_MASK
= 0x3,
289 ABORT_PROT_BLOCK_SHIFT
= 2,
290 ABORT_PROT_BLOCK_BITS
= 8,
291 ABORT_PROT_BLOCK_MASK
= (((1 << ABORT_PROT_BLOCK_BITS
) - 1) << ABORT_PROT_BLOCK_SHIFT
)
295 mono_thread_get_abort_prot_block_count (MonoInternalThread
*thread
)
297 gsize state
= thread
->thread_state
;
298 return (state
& ABORT_PROT_BLOCK_MASK
) >> ABORT_PROT_BLOCK_SHIFT
;
302 mono_threads_is_current_thread_in_protected_block (void)
304 MonoInternalThread
*thread
= mono_thread_internal_current ();
306 return mono_thread_get_abort_prot_block_count (thread
) > 0;
310 mono_threads_begin_abort_protected_block (void)
312 MonoInternalThread
*thread
= mono_thread_internal_current ();
313 gsize old_state
, new_state
;
316 old_state
= thread
->thread_state
;
318 new_val
= ((old_state
& ABORT_PROT_BLOCK_MASK
) >> ABORT_PROT_BLOCK_SHIFT
) + 1;
319 //bounds check abort_prot_count
320 g_assert (new_val
> 0);
321 g_assert (new_val
< (1 << ABORT_PROT_BLOCK_BITS
));
323 new_state
= old_state
+ (1 << ABORT_PROT_BLOCK_SHIFT
);
324 } while (mono_atomic_cas_ptr ((volatile gpointer
*)&thread
->thread_state
, (gpointer
)new_state
, (gpointer
)old_state
) != (gpointer
)old_state
);
326 /* Defer async request since we won't be able to process until exiting the block */
327 if (new_val
== 1 && (new_state
& INTERRUPT_ASYNC_REQUESTED_BIT
)) {
328 mono_atomic_dec_i32 (&mono_thread_interruption_request_flag
);
329 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
, mono_thread_interruption_request_flag
);
330 if (mono_thread_interruption_request_flag
< 0)
331 g_warning ("bad mono_thread_interruption_request_flag state");
333 THREADS_INTERRUPT_DEBUG ("[%d] begin abort protected block old_state %ld new_state %ld, tir %d\n", thread
->small_id
, old_state
, new_state
, mono_thread_interruption_request_flag
);
338 mono_thread_state_has_interruption (gsize state
)
340 /* pending exception, self abort */
341 if (state
& INTERRUPT_SYNC_REQUESTED_BIT
)
344 /* abort, interruption, suspend */
345 if ((state
& INTERRUPT_ASYNC_REQUESTED_BIT
) && !(state
& ABORT_PROT_BLOCK_MASK
))
352 mono_threads_end_abort_protected_block (void)
354 MonoInternalThread
*thread
= mono_thread_internal_current ();
355 gsize old_state
, new_state
;
358 old_state
= thread
->thread_state
;
360 //bounds check abort_prot_count
361 new_val
= ((old_state
& ABORT_PROT_BLOCK_MASK
) >> ABORT_PROT_BLOCK_SHIFT
) - 1;
362 g_assert (new_val
>= 0);
363 g_assert (new_val
< (1 << ABORT_PROT_BLOCK_BITS
));
365 new_state
= old_state
- (1 << ABORT_PROT_BLOCK_SHIFT
);
366 } while (mono_atomic_cas_ptr ((volatile gpointer
*)&thread
->thread_state
, (gpointer
)new_state
, (gpointer
)old_state
) != (gpointer
)old_state
);
368 if (new_val
== 0 && (new_state
& INTERRUPT_ASYNC_REQUESTED_BIT
)) {
369 mono_atomic_inc_i32 (&mono_thread_interruption_request_flag
);
370 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
, mono_thread_interruption_request_flag
);
372 THREADS_INTERRUPT_DEBUG ("[%d] end abort protected block old_state %ld new_state %ld, tir %d\n", thread
->small_id
, old_state
, new_state
, mono_thread_interruption_request_flag
);
375 return mono_thread_state_has_interruption (new_state
);
379 mono_thread_get_interruption_requested (MonoInternalThread
*thread
)
381 gsize state
= thread
->thread_state
;
383 return mono_thread_state_has_interruption (state
);
387 * Returns TRUE is there was a state change
388 * We clear a single interruption request, sync has priority.
391 mono_thread_clear_interruption_requested (MonoInternalThread
*thread
)
393 gsize old_state
, new_state
;
395 old_state
= thread
->thread_state
;
397 // no interruption to process
398 if (!(old_state
& INTERRUPT_SYNC_REQUESTED_BIT
) &&
399 (!(old_state
& INTERRUPT_ASYNC_REQUESTED_BIT
) || (old_state
& ABORT_PROT_BLOCK_MASK
)))
402 if (old_state
& INTERRUPT_SYNC_REQUESTED_BIT
)
403 new_state
= old_state
& ~INTERRUPT_SYNC_REQUESTED_BIT
;
405 new_state
= old_state
& ~INTERRUPT_ASYNC_REQUESTED_BIT
;
406 } while (mono_atomic_cas_ptr ((volatile gpointer
*)&thread
->thread_state
, (gpointer
)new_state
, (gpointer
)old_state
) != (gpointer
)old_state
);
408 mono_atomic_dec_i32 (&mono_thread_interruption_request_flag
);
409 THREADS_INTERRUPT_DEBUG ("[%d] clear interruption old_state %ld new_state %ld, tir %d\n", thread
->small_id
, old_state
, new_state
, mono_thread_interruption_request_flag
);
410 if (mono_thread_interruption_request_flag
< 0)
411 g_warning ("bad mono_thread_interruption_request_flag state");
416 mono_thread_clear_interruption_requested_handle (MonoInternalThreadHandle thread
)
418 // Internal threads are pinned so shallow coop/handle.
419 return mono_thread_clear_interruption_requested (mono_internal_thread_handle_ptr (thread
));
422 /* Returns TRUE is there was a state change and the interruption can be processed */
424 mono_thread_set_interruption_requested (MonoInternalThread
*thread
)
426 //always force when the current thread is doing it to itself.
427 gboolean sync
= thread
== mono_thread_internal_current ();
428 /* Normally synchronous interruptions can bypass abort protection. */
429 return mono_thread_set_interruption_requested_flags (thread
, sync
);
432 /* Returns TRUE if there was a state change and the interruption can be
433 * processed. This variant defers a self abort when inside an abort protected
434 * block. Normally this should only be done when a thread has received an
435 * outside indication that it should abort. (For example when the JIT sets a
436 * flag in an finally block.)
440 mono_thread_set_self_interruption_respect_abort_prot (void)
442 MonoInternalThread
*thread
= mono_thread_internal_current ();
443 /* N.B. Sets the ASYNC_REQUESTED_BIT for current this thread,
444 * which is unusual. */
445 return mono_thread_set_interruption_requested_flags (thread
, FALSE
);
448 /* Returns TRUE if there was a state change and the interruption can be processed. */
450 mono_thread_set_interruption_requested_flags (MonoInternalThread
*thread
, gboolean sync
)
452 gsize old_state
, new_state
;
454 old_state
= thread
->thread_state
;
457 if ((sync
&& (old_state
& INTERRUPT_SYNC_REQUESTED_BIT
)) ||
458 (!sync
&& (old_state
& INTERRUPT_ASYNC_REQUESTED_BIT
)))
462 new_state
= old_state
| INTERRUPT_SYNC_REQUESTED_BIT
;
464 new_state
= old_state
| INTERRUPT_ASYNC_REQUESTED_BIT
;
465 } while (mono_atomic_cas_ptr ((volatile gpointer
*)&thread
->thread_state
, (gpointer
)new_state
, (gpointer
)old_state
) != (gpointer
)old_state
);
467 if (sync
|| !(new_state
& ABORT_PROT_BLOCK_MASK
)) {
468 mono_atomic_inc_i32 (&mono_thread_interruption_request_flag
);
469 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
, mono_thread_interruption_request_flag
);
471 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
, mono_thread_interruption_request_flag
);
474 return sync
|| !(new_state
& ABORT_PROT_BLOCK_MASK
);
477 static MonoNativeThreadId
478 thread_get_tid (MonoInternalThread
*thread
)
480 /* We store the tid as a guint64 to keep the object layout constant between platforms */
481 return MONO_UINT_TO_NATIVE_THREAD_ID (thread
->tid
);
485 free_synch_cs (MonoCoopMutex
*synch_cs
)
488 mono_coop_mutex_destroy (synch_cs
);
493 free_longlived_thread_data (void *user_data
)
495 MonoLongLivedThreadData
*lltd
= (MonoLongLivedThreadData
*)user_data
;
496 free_synch_cs (lltd
->synch_cs
);
502 init_longlived_thread_data (MonoLongLivedThreadData
*lltd
)
504 mono_refcount_init (lltd
, free_longlived_thread_data
);
505 mono_refcount_inc (lltd
);
506 /* Initial refcount is 2: decremented once by
507 * mono_thread_detach_internal and once by the MonoInternalThread
508 * finalizer - whichever one happens later will deallocate. */
510 lltd
->synch_cs
= g_new0 (MonoCoopMutex
, 1);
511 mono_coop_mutex_init_recursive (lltd
->synch_cs
);
513 mono_memory_barrier ();
517 dec_longlived_thread_data (MonoLongLivedThreadData
*lltd
)
519 mono_refcount_dec (lltd
);
523 lock_thread (MonoInternalThread
*thread
)
525 g_assert (thread
->longlived
);
526 g_assert (thread
->longlived
->synch_cs
);
528 mono_coop_mutex_lock (thread
->longlived
->synch_cs
);
532 unlock_thread (MonoInternalThread
*thread
)
534 mono_coop_mutex_unlock (thread
->longlived
->synch_cs
);
538 lock_thread_handle (MonoInternalThreadHandle thread
)
540 lock_thread (mono_internal_thread_handle_ptr (thread
));
544 unlock_thread_handle (MonoInternalThreadHandle thread
)
546 unlock_thread (mono_internal_thread_handle_ptr (thread
));
550 is_appdomainunloaded_exception (MonoClass
*klass
)
552 #ifdef ENABLE_NETCORE
555 return klass
== mono_class_get_appdomain_unloaded_exception_class ();
560 is_threadabort_exception (MonoClass
*klass
)
562 return klass
== mono_defaults
.threadabortexception_class
;
566 * A special static data offset (guint32) consists of 3 parts:
568 * [0] 6-bit index into the array of chunks.
569 * [6] 25-bit offset into the array.
570 * [31] Bit indicating thread or context static.
575 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
586 } SpecialStaticOffset
;
588 #define SPECIAL_STATIC_OFFSET_TYPE_THREAD 0
589 #define SPECIAL_STATIC_OFFSET_TYPE_CONTEXT 1
592 MAKE_SPECIAL_STATIC_OFFSET (guint32 index
, guint32 offset
, guint32 type
)
594 SpecialStaticOffset special_static_offset
;
595 memset (&special_static_offset
, 0, sizeof (special_static_offset
));
596 special_static_offset
.fields
.index
= index
;
597 special_static_offset
.fields
.offset
= offset
;
598 special_static_offset
.fields
.type
= type
;
599 return special_static_offset
.raw
;
602 #define ACCESS_SPECIAL_STATIC_OFFSET(x,f) \
603 (((SpecialStaticOffset *) &(x))->fields.f)
606 get_thread_static_data (MonoInternalThread
*thread
, guint32 offset
)
608 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset
, type
) == SPECIAL_STATIC_OFFSET_TYPE_THREAD
);
610 int idx
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, index
);
611 int off
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, offset
);
613 return ((char *) thread
->static_data
[idx
]) + off
;
617 get_context_static_data (MonoAppContext
*ctx
, guint32 offset
)
619 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset
, type
) == SPECIAL_STATIC_OFFSET_TYPE_CONTEXT
);
621 int idx
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, index
);
622 int off
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, offset
);
624 return ((char *) ctx
->static_data
[idx
]) + off
;
628 get_current_thread_ptr_for_domain (MonoDomain
*domain
, MonoInternalThread
*thread
)
632 MONO_STATIC_POINTER_INIT (MonoClassField
, current_thread_field
)
634 current_thread_field
= mono_class_get_field_from_name_full (mono_defaults
.thread_class
, "current_thread", NULL
);
635 g_assert (current_thread_field
);
637 MONO_STATIC_POINTER_INIT_END (MonoClassField
, current_thread_field
)
639 ERROR_DECL (thread_vt_error
);
640 mono_class_vtable_checked (domain
, mono_defaults
.thread_class
, thread_vt_error
);
641 mono_error_assert_ok (thread_vt_error
);
642 mono_domain_lock (domain
);
643 offset
= GPOINTER_TO_UINT (g_hash_table_lookup (domain
->special_static_fields
, current_thread_field
));
644 mono_domain_unlock (domain
);
647 return (MonoThread
**)get_thread_static_data (thread
, offset
);
651 set_current_thread_for_domain (MonoDomain
*domain
, MonoInternalThread
*thread
, MonoThread
*current
)
653 #ifndef ENABLE_NETCORE
654 MonoThread
**current_thread_ptr
= get_current_thread_ptr_for_domain (domain
, thread
);
656 g_assert (current
->obj
.vtable
->domain
== domain
);
658 g_assert (!*current_thread_ptr
);
659 *current_thread_ptr
= current
;
664 create_thread_object (MonoDomain
*domain
, MonoInternalThread
*internal
)
666 #ifdef ENABLE_NETCORE
667 MONO_OBJECT_SETREF_INTERNAL (internal
, internal_thread
, internal
);
674 vtable
= mono_class_vtable_checked (domain
, mono_defaults
.thread_class
, error
);
675 mono_error_assert_ok (error
);
677 thread
= (MonoThread
*)mono_object_new_mature (vtable
, error
);
678 /* only possible failure mode is OOM, from which we don't expect to recover. */
679 mono_error_assert_ok (error
);
681 MONO_OBJECT_SETREF_INTERNAL (thread
, internal_thread
, internal
);
688 init_internal_thread_object (MonoInternalThread
*thread
)
690 thread
->longlived
= g_new0 (MonoLongLivedThreadData
, 1);
691 init_longlived_thread_data (thread
->longlived
);
693 thread
->apartment_state
= ThreadApartmentState_Unknown
;
694 thread
->managed_id
= get_next_managed_thread_id ();
695 if (mono_gc_is_moving ()) {
696 thread
->thread_pinning_ref
= thread
;
697 MONO_GC_REGISTER_ROOT_PINNING (thread
->thread_pinning_ref
, MONO_ROOT_SOURCE_THREADING
, NULL
, "Thread Pinning Reference");
700 thread
->priority
= MONO_THREAD_PRIORITY_NORMAL
;
702 thread
->suspended
= g_new0 (MonoOSEvent
, 1);
703 mono_os_event_init (thread
->suspended
, TRUE
);
706 static MonoInternalThread
*
707 create_internal_thread_object (void)
710 MonoInternalThread
*thread
;
713 vt
= mono_class_vtable_checked (mono_get_root_domain (), mono_defaults
.internal_thread_class
, error
);
714 mono_error_assert_ok (error
);
715 thread
= (MonoInternalThread
*) mono_object_new_mature (vt
, error
);
716 /* only possible failure mode is OOM, from which we don't exect to recover */
717 mono_error_assert_ok (error
);
719 init_internal_thread_object (thread
);
725 mono_thread_internal_set_priority (MonoInternalThread
*internal
, MonoThreadPriority priority
)
729 g_assert (priority
>= MONO_THREAD_PRIORITY_LOWEST
);
730 g_assert (priority
<= MONO_THREAD_PRIORITY_HIGHEST
);
731 g_assert (MONO_THREAD_PRIORITY_LOWEST
< MONO_THREAD_PRIORITY_HIGHEST
);
737 g_assert (internal
->native_handle
);
740 res
= SetThreadPriority (internal
->native_handle
, (int)priority
- 2);
741 last_error
= GetLastError ();
744 g_error ("%s: SetThreadPriority failed, error %d", __func__
, last_error
);
745 #elif defined(HOST_FUCHSIA)
748 if (priority
== MONO_THREAD_PRIORITY_LOWEST
)
749 z_priority
= ZX_PRIORITY_LOWEST
;
750 else if (priority
== MONO_THREAD_PRIORITY_BELOW_NORMAL
)
751 z_priority
= ZX_PRIORITY_LOW
;
752 else if (priority
== MONO_THREAD_PRIORITY_NORMAL
)
753 z_priority
= ZX_PRIORITY_DEFAULT
;
754 else if (priority
== MONO_THREAD_PRIORITY_ABOVE_NORMAL
)
755 z_priority
= ZX_PRIORITY_HIGH
;
756 else if (priority
== MONO_THREAD_PRIORITY_HIGHEST
)
757 z_priority
= ZX_PRIORITY_HIGHEST
;
762 // When this API becomes available on an arbitrary thread, we can use it,
763 // not available on current Zircon
765 #else /* !HOST_WIN32 and not HOST_FUCHSIA */
768 struct sched_param param
;
771 tid
= thread_get_tid (internal
);
774 res
= pthread_getschedparam (tid
, &policy
, ¶m
);
777 g_error ("%s: pthread_getschedparam failed, error: \"%s\" (%d)", __func__
, g_strerror (res
), res
);
779 #ifdef _POSIX_PRIORITY_SCHEDULING
782 /* Necessary to get valid priority range */
785 #if defined(__PASE__)
786 /* only priorities allowed by IBM i */
790 min
= sched_get_priority_min (policy
);
791 max
= sched_get_priority_max (policy
);
795 /* Not tunable. Bail out */
796 if ((min
== -1) || (max
== -1))
799 if (max
> 0 && min
>= 0 && max
> min
) {
800 double srange
, drange
, sposition
, dposition
;
801 srange
= MONO_THREAD_PRIORITY_HIGHEST
- MONO_THREAD_PRIORITY_LOWEST
;
803 sposition
= priority
- MONO_THREAD_PRIORITY_LOWEST
;
804 dposition
= (sposition
/ srange
) * drange
;
805 param
.sched_priority
= (int)(dposition
+ min
);
812 param
.sched_priority
= 50;
818 param
.sched_priority
= 0;
821 g_warning ("%s: unknown policy %d", __func__
, policy
);
827 #if defined(__PASE__)
828 /* only scheduling param allowed by IBM i */
829 res
= pthread_setschedparam (tid
, SCHED_OTHER
, ¶m
);
831 res
= pthread_setschedparam (tid
, policy
, ¶m
);
837 /* AIX doesn't like doing this and will spam this every time;
838 * weirdly, i doesn't complain
840 g_warning ("%s: pthread_setschedparam failed, error: \"%s\" (%d)", __func__
, g_strerror (res
), res
);
844 g_error ("%s: pthread_setschedparam failed, error: \"%s\" (%d)", __func__
, g_strerror (res
), res
);
846 #endif /* HOST_WIN32 */
850 mono_alloc_static_data (gpointer
**static_data_ptr
, guint32 offset
, void *alloc_key
, gboolean threadlocal
);
853 mono_thread_attach_internal (MonoThread
*thread
, gboolean force_attach
, gboolean force_domain
)
855 MonoThreadInfo
*info
;
856 MonoInternalThread
*internal
;
857 MonoDomain
*domain
, *root_domain
;
862 info
= mono_thread_info_current ();
865 internal
= thread
->internal_thread
;
868 /* It is needed to store the MonoInternalThread on the MonoThreadInfo, because of the following case:
869 * - the MonoInternalThread TLS key is destroyed: set it to NULL
870 * - the MonoThreadInfo TLS key is destroyed: calls mono_thread_info_detach
871 * - it calls MonoThreadInfoCallbacks.thread_detach
872 * - mono_thread_internal_current returns NULL -> fails to detach the MonoInternalThread. */
873 mono_thread_info_set_internal_thread_gchandle (info
, mono_gchandle_new_internal ((MonoObject
*) internal
, FALSE
));
875 internal
->handle
= mono_threads_open_thread_handle (info
->handle
);
876 internal
->native_handle
= MONO_NATIVE_THREAD_HANDLE_TO_GPOINTER (mono_threads_open_native_thread_handle (info
->native_handle
));
877 internal
->tid
= MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ());
878 internal
->thread_info
= info
;
879 internal
->small_id
= info
->small_id
;
881 THREAD_DEBUG (g_message ("%s: (%" G_GSIZE_FORMAT
") Setting current_object_key to %p", __func__
, mono_native_thread_id_get (), internal
));
883 SET_CURRENT_OBJECT (internal
);
885 domain
= mono_object_domain (thread
);
887 mono_thread_push_appdomain_ref (domain
);
888 if (!mono_domain_set_fast (domain
, force_domain
)) {
889 mono_thread_pop_appdomain_ref ();
893 mono_threads_lock ();
895 if (shutting_down
&& !force_attach
) {
896 mono_threads_unlock ();
897 mono_thread_pop_appdomain_ref ();
901 if (threads_starting_up
)
902 mono_g_hash_table_remove (threads_starting_up
, thread
);
905 threads
= mono_g_hash_table_new_type_internal (NULL
, NULL
, MONO_HASH_VALUE_GC
, MONO_ROOT_SOURCE_THREADING
, NULL
, "Thread Table");
908 /* We don't need to duplicate thread->handle, because it is
909 * only closed when the thread object is finalized by the GC. */
910 mono_g_hash_table_insert_internal (threads
, (gpointer
)(gsize
)(internal
->tid
), internal
);
912 /* We have to do this here because mono_thread_start_cb
913 * requires that root_domain_thread is set up. */
914 if (thread_static_info
.offset
|| thread_static_info
.idx
> 0) {
915 /* get the current allocated size */
916 guint32 offset
= MAKE_SPECIAL_STATIC_OFFSET (thread_static_info
.idx
, thread_static_info
.offset
, 0);
917 mono_alloc_static_data (&internal
->static_data
, offset
, (void*)(gsize
)MONO_UINT_TO_NATIVE_THREAD_ID (internal
->tid
), TRUE
);
920 mono_threads_unlock ();
922 root_domain
= mono_get_root_domain ();
924 g_assert (!internal
->root_domain_thread
);
925 if (domain
!= root_domain
)
926 MONO_OBJECT_SETREF_INTERNAL (internal
, root_domain_thread
, create_thread_object (root_domain
, internal
));
928 MONO_OBJECT_SETREF_INTERNAL (internal
, root_domain_thread
, thread
);
930 if (domain
!= root_domain
)
931 set_current_thread_for_domain (root_domain
, internal
, internal
->root_domain_thread
);
933 set_current_thread_for_domain (domain
, internal
, thread
);
935 THREAD_DEBUG (g_message ("%s: Attached thread ID %" G_GSIZE_FORMAT
" (handle %p)", __func__
, internal
->tid
, internal
->handle
));
940 mono_threads_lock ();
941 if (threads_starting_up
)
942 mono_g_hash_table_remove (threads_starting_up
, thread
);
943 mono_threads_unlock ();
945 if (!mono_thread_info_try_get_internal_thread_gchandle (info
, &gchandle
))
946 g_error ("%s: failed to get gchandle, info %p", __func__
, info
);
948 mono_gchandle_free_internal (gchandle
);
950 mono_thread_info_unset_internal_thread_gchandle (info
);
952 SET_CURRENT_OBJECT(NULL
);
958 mono_thread_detach_internal (MonoInternalThread
*thread
)
960 MonoThreadInfo
*info
;
961 MonoInternalThread
*value
;
965 g_assert (mono_thread_internal_is_current (thread
));
967 g_assert (thread
!= NULL
);
968 SET_CURRENT_OBJECT (thread
);
970 info
= thread
->thread_info
;
973 THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%" G_GSIZE_FORMAT
")", __func__
, thread
, (gsize
)thread
->tid
));
975 MONO_PROFILER_RAISE (thread_stopping
, (thread
->tid
));
978 * Prevent race condition between thread shutdown and runtime shutdown.
979 * Including all runtime threads in the pending joinable count will make
980 * sure shutdown will wait for it to get onto the joinable thread list before
981 * critical resources have been cleanup (like GC memory). Threads getting onto
982 * the joinable thread list should just about to exit and not blocking a potential
983 * join call. Owner of threads attached to the runtime but not identified as runtime
984 * threads needs to make sure thread detach calls won't race with runtime shutdown.
986 threads_add_pending_joinable_runtime_thread (info
);
989 mono_w32mutex_abandon (thread
);
992 mono_gchandle_free_internal (thread
->abort_state_handle
);
993 thread
->abort_state_handle
= 0;
995 thread
->abort_exc
= NULL
;
996 thread
->current_appcontext
= NULL
;
998 LOCK_THREAD (thread
);
1000 thread
->state
|= ThreadState_Stopped
;
1001 thread
->state
&= ~ThreadState_Background
;
1003 UNLOCK_THREAD (thread
);
1006 An interruption request has leaked to cleanup. Adjust the global counter.
1008 This can happen is the abort source thread finds the abortee (this) thread
1009 in unmanaged code. If this thread never trips back to managed code or check
1010 the local flag it will be left set and positively unbalance the global counter.
1012 Leaving the counter unbalanced will cause a performance degradation since all threads
1013 will now keep checking their local flags all the time.
1015 mono_thread_clear_interruption_requested (thread
);
1017 mono_threads_lock ();
1021 if (!mono_g_hash_table_lookup_extended (threads
, (gpointer
)thread
->tid
, NULL
, (gpointer
*) &value
)) {
1022 g_error ("%s: thread %p (tid: %p) should not have been removed yet from threads", __func__
, thread
, thread
->tid
);
1023 } else if (thread
!= value
) {
1024 /* We have to check whether the thread object for the tid is still the same in the table because the
1025 * thread might have been destroyed and the tid reused in the meantime, in which case the tid would be in
1026 * the table, but with another thread object. */
1027 g_error ("%s: thread %p (tid: %p) do not match with value %p (tid: %p)", __func__
, thread
, thread
->tid
, value
, value
->tid
);
1030 removed
= mono_g_hash_table_remove (threads
, (gpointer
)thread
->tid
);
1033 mono_threads_unlock ();
1035 /* Don't close the handle here, wait for the object finalizer
1036 * to do it. Otherwise, the following race condition applies:
1038 * 1) Thread exits (and mono_thread_detach_internal() closes the handle)
1040 * 2) Some other handle is reassigned the same slot
1042 * 3) Another thread tries to join the first thread, and
1043 * blocks waiting for the reassigned handle to be signalled
1044 * (which might never happen). This is possible, because the
1045 * thread calling Join() still has a reference to the first
1049 mono_release_type_locks (thread
);
1051 MONO_PROFILER_RAISE (thread_stopped
, (thread
->tid
));
1052 MONO_PROFILER_RAISE (gc_root_unregister
, ((const mono_byte
*)(info
->stack_start_limit
)));
1053 MONO_PROFILER_RAISE (gc_root_unregister
, ((const mono_byte
*)(info
->handle_stack
)));
1056 * This will signal async signal handlers that the thread has exited.
1057 * The profiler callback needs this to be set, so it cannot be done earlier.
1059 mono_domain_unset ();
1060 mono_memory_barrier ();
1062 mono_thread_pop_appdomain_ref ();
1064 mono_free_static_data (thread
->static_data
);
1065 thread
->static_data
= NULL
;
1066 ref_stack_destroy (thread
->appdomain_refs
);
1067 thread
->appdomain_refs
= NULL
;
1069 g_assert (thread
->suspended
);
1070 mono_os_event_destroy (thread
->suspended
);
1071 g_free (thread
->suspended
);
1072 thread
->suspended
= NULL
;
1074 if (mono_thread_cleanup_fn
)
1075 mono_thread_cleanup_fn (thread_get_tid (thread
));
1077 mono_memory_barrier ();
1079 if (mono_gc_is_moving ()) {
1080 MONO_GC_UNREGISTER_ROOT (thread
->thread_pinning_ref
);
1081 thread
->thread_pinning_ref
= NULL
;
1084 /* There is no more any guarantee that `thread` is alive */
1085 mono_memory_barrier ();
1087 SET_CURRENT_OBJECT (NULL
);
1088 mono_domain_unset ();
1090 if (!mono_thread_info_try_get_internal_thread_gchandle (info
, &gchandle
))
1091 g_error ("%s: failed to get gchandle, info = %p", __func__
, info
);
1093 mono_gchandle_free_internal (gchandle
);
1095 mono_thread_info_unset_internal_thread_gchandle (info
);
1097 /* Possibly free synch_cs, if the finalizer for InternalThread already
1099 dec_longlived_thread_data (thread
->longlived
);
1101 MONO_PROFILER_RAISE (thread_exited
, (thread
->tid
));
1103 /* Don't need to close the handle to this thread, even though we took a
1104 * reference in mono_thread_attach (), because the GC will do it
1105 * when the Thread object is finalised.
1112 MonoObject
*start_delegate
;
1113 MonoObject
*start_delegate_arg
;
1114 MonoThreadStart start_func
;
1115 gpointer start_func_arg
;
1116 gboolean force_attach
;
1118 MonoCoopSem registered
;
1122 fire_attach_profiler_events (MonoNativeThreadId tid
)
1124 MONO_PROFILER_RAISE (thread_started
, ((uintptr_t) tid
));
1126 MonoThreadInfo
*info
= mono_thread_info_current ();
1128 MONO_PROFILER_RAISE (gc_root_register
, (
1129 (const mono_byte
*)(info
->stack_start_limit
),
1130 (char *) info
->stack_end
- (char *) info
->stack_start_limit
,
1131 MONO_ROOT_SOURCE_STACK
,
1135 // The handle stack is a pseudo-root similar to the finalizer queues.
1136 MONO_PROFILER_RAISE (gc_root_register
, (
1137 (const mono_byte
*)info
->handle_stack
,
1139 MONO_ROOT_SOURCE_HANDLE
,
1144 static guint32 WINAPI
1145 start_wrapper_internal (StartInfo
*start_info
, gsize
*stack_ptr
)
1148 MonoThreadStart start_func
;
1149 void *start_func_arg
;
1152 * We don't create a local to hold start_info->thread, so hopefully it won't get pinned during a
1156 MonoInternalThread
*internal
;
1157 MonoObject
*start_delegate
;
1158 MonoObject
*start_delegate_arg
;
1160 thread
= start_info
->thread
;
1161 internal
= thread
->internal_thread
;
1163 THREAD_DEBUG (g_message ("%s: (%" G_GSIZE_FORMAT
") Start wrapper", __func__
, mono_native_thread_id_get ()));
1165 if (!mono_thread_attach_internal (thread
, start_info
->force_attach
, FALSE
)) {
1166 start_info
->failed
= TRUE
;
1168 mono_coop_sem_post (&start_info
->registered
);
1170 if (mono_atomic_dec_i32 (&start_info
->ref
) == 0) {
1171 mono_coop_sem_destroy (&start_info
->registered
);
1172 g_free (start_info
);
1178 mono_thread_internal_set_priority (internal
, (MonoThreadPriority
)internal
->priority
);
1180 tid
= internal
->tid
;
1182 start_delegate
= start_info
->start_delegate
;
1183 start_delegate_arg
= start_info
->start_delegate_arg
;
1184 start_func
= start_info
->start_func
;
1185 start_func_arg
= start_info
->start_func_arg
;
1187 /* This MUST be called before any managed code can be
1188 * executed, as it calls the callback function that (for the
1189 * jit) sets the lmf marker.
1192 if (mono_thread_start_cb
)
1193 mono_thread_start_cb (tid
, stack_ptr
, (gpointer
)start_func
);
1195 /* On 2.0 profile (and higher), set explicitly since state might have been
1197 if (internal
->apartment_state
== ThreadApartmentState_Unknown
)
1198 internal
->apartment_state
= ThreadApartmentState_MTA
;
1200 mono_thread_init_apartment_state ();
1202 /* Let the thread that called Start() know we're ready */
1203 mono_coop_sem_post (&start_info
->registered
);
1205 if (mono_atomic_dec_i32 (&start_info
->ref
) == 0) {
1206 mono_coop_sem_destroy (&start_info
->registered
);
1207 g_free (start_info
);
1210 /* start_info is not valid anymore */
1214 * Call this after calling start_notify, since the profiler callback might want
1215 * to lock the thread, and the lock is held by thread_start () which waits for
1218 fire_attach_profiler_events ((MonoNativeThreadId
) tid
);
1220 /* if the name was set before starting, we didn't invoke the profiler callback */
1221 // This is a little racy, ok.
1223 if (internal
->name
.chars
) {
1225 LOCK_THREAD (internal
);
1227 if (internal
->name
.chars
) {
1228 MONO_PROFILER_RAISE (thread_name
, (internal
->tid
, internal
->name
.chars
));
1229 mono_native_thread_set_name (MONO_UINT_TO_NATIVE_THREAD_ID (internal
->tid
), internal
->name
.chars
);
1232 UNLOCK_THREAD (internal
);
1235 /* start_func is set only for unmanaged start functions */
1237 start_func (start_func_arg
);
1239 #ifdef ENABLE_NETCORE
1240 /* Call a callback in the RuntimeThread class */
1241 g_assert (start_delegate
== NULL
);
1243 MONO_STATIC_POINTER_INIT (MonoMethod
, cb
)
1245 cb
= mono_class_get_method_from_name_checked (internal
->obj
.vtable
->klass
, "StartCallback", 0, 0, error
);
1247 mono_error_assert_ok (error
);
1249 MONO_STATIC_POINTER_INIT_END (MonoMethod
, cb
)
1251 mono_runtime_invoke_checked (cb
, internal
, NULL
, error
);
1255 g_assert (start_delegate
!= NULL
);
1257 /* we may want to handle the exception here. See comment below on unhandled exceptions */
1258 args
[0] = (gpointer
) start_delegate_arg
;
1259 mono_runtime_delegate_invoke_checked (start_delegate
, args
, error
);
1262 if (!is_ok (error
)) {
1263 MonoException
*ex
= mono_error_convert_to_exception (error
);
1265 g_assert (ex
!= NULL
);
1266 MonoClass
*klass
= mono_object_class (ex
);
1267 if ((mono_runtime_unhandled_exception_policy_get () != MONO_UNHANDLED_POLICY_LEGACY
) &&
1268 !is_threadabort_exception (klass
)) {
1269 mono_unhandled_exception_internal (&ex
->object
);
1270 mono_invoke_unhandled_exception_hook (&ex
->object
);
1271 g_assert_not_reached ();
1274 mono_error_cleanup (error
);
1278 /* If the thread calls ExitThread at all, this remaining code
1279 * will not be executed, but the main thread will eventually
1280 * call mono_thread_detach_internal() on this thread's behalf.
1283 THREAD_DEBUG (g_message ("%s: (%" G_GSIZE_FORMAT
") Start wrapper terminating", __func__
, mono_native_thread_id_get ()));
1285 /* Do any cleanup needed for apartment state. This
1286 * cannot be done in mono_thread_detach_internal since
1287 * mono_thread_detach_internal could be called for a
1288 * thread other than the current thread.
1289 * mono_thread_cleanup_apartment_state cleans up apartment
1290 * for the current thead */
1291 mono_thread_cleanup_apartment_state ();
1293 mono_thread_detach_internal (internal
);
1298 static mono_thread_start_return_t WINAPI
1299 start_wrapper (gpointer data
)
1301 StartInfo
*start_info
;
1302 MonoThreadInfo
*info
;
1305 start_info
= (StartInfo
*) data
;
1306 g_assert (start_info
);
1308 info
= mono_thread_info_attach ();
1309 info
->runtime_thread
= TRUE
;
1311 /* Run the actual main function of the thread */
1312 res
= start_wrapper_internal (start_info
, (gsize
*)info
->stack_end
);
1314 mono_thread_info_exit (res
);
1316 g_assert_not_reached ();
1322 * Common thread creation code.
1323 * LOCKING: Acquires the threads lock.
1326 create_thread (MonoThread
*thread
, MonoInternalThread
*internal
, MonoObject
*start_delegate
, MonoThreadStart start_func
, gpointer start_func_arg
,
1327 MonoThreadCreateFlags flags
, MonoError
*error
)
1329 StartInfo
*start_info
= NULL
;
1330 MonoNativeThreadId tid
;
1332 gsize stack_set_size
;
1335 g_assert (!start_func
&& !start_func_arg
);
1337 g_assert (!start_delegate
);
1339 if (flags
& MONO_THREAD_CREATE_FLAGS_THREADPOOL
) {
1340 g_assert (!(flags
& MONO_THREAD_CREATE_FLAGS_DEBUGGER
));
1341 g_assert (!(flags
& MONO_THREAD_CREATE_FLAGS_FORCE_CREATE
));
1343 if (flags
& MONO_THREAD_CREATE_FLAGS_DEBUGGER
) {
1344 g_assert (!(flags
& MONO_THREAD_CREATE_FLAGS_THREADPOOL
));
1345 g_assert (!(flags
& MONO_THREAD_CREATE_FLAGS_FORCE_CREATE
));
1349 * Join joinable threads to prevent running out of threads since the finalizer
1350 * thread might be blocked/backlogged.
1352 mono_threads_join_threads ();
1356 mono_threads_lock ();
1357 if (shutting_down
&& !(flags
& MONO_THREAD_CREATE_FLAGS_FORCE_CREATE
)) {
1358 mono_threads_unlock ();
1359 mono_error_set_execution_engine (error
, "Couldn't create thread. Runtime is shutting down.");
1362 if (threads_starting_up
== NULL
) {
1363 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");
1365 mono_g_hash_table_insert_internal (threads_starting_up
, thread
, thread
);
1366 mono_threads_unlock ();
1368 #ifndef ENABLE_NETCORE
1369 internal
->threadpool_thread
= flags
& MONO_THREAD_CREATE_FLAGS_THREADPOOL
;
1370 if (internal
->threadpool_thread
)
1371 mono_thread_set_state (internal
, ThreadState_Background
);
1374 internal
->debugger_thread
= flags
& MONO_THREAD_CREATE_FLAGS_DEBUGGER
;
1376 start_info
= g_new0 (StartInfo
, 1);
1377 start_info
->ref
= 2;
1378 start_info
->thread
= thread
;
1379 start_info
->start_delegate
= start_delegate
;
1380 start_info
->start_delegate_arg
= thread
->start_obj
;
1381 start_info
->start_func
= start_func
;
1382 start_info
->start_func_arg
= start_func_arg
;
1383 start_info
->force_attach
= flags
& MONO_THREAD_CREATE_FLAGS_FORCE_CREATE
;
1384 start_info
->failed
= FALSE
;
1385 mono_coop_sem_init (&start_info
->registered
, 0);
1387 if (flags
!= MONO_THREAD_CREATE_FLAGS_SMALL_STACK
)
1388 stack_set_size
= default_stacksize_for_thread (internal
);
1392 if (!mono_thread_platform_create_thread (start_wrapper
, start_info
, &stack_set_size
, &tid
)) {
1393 /* The thread couldn't be created, so set an exception */
1394 mono_threads_lock ();
1395 mono_g_hash_table_remove (threads_starting_up
, thread
);
1396 mono_threads_unlock ();
1397 mono_error_set_execution_engine (error
, "Couldn't create thread. Error 0x%x", mono_w32error_get_last());
1398 /* ref is not going to be decremented in start_wrapper_internal */
1399 mono_atomic_dec_i32 (&start_info
->ref
);
1404 internal
->stack_size
= (int) stack_set_size
;
1406 THREAD_DEBUG (g_message ("%s: (%" G_GSIZE_FORMAT
") Launching thread %p (%" G_GSIZE_FORMAT
")", __func__
, mono_native_thread_id_get (), internal
, (gsize
)internal
->tid
));
1409 * Wait for the thread to set up its TLS data etc, so
1410 * theres no potential race condition if someone tries
1411 * to look up the data believing the thread has
1415 mono_coop_sem_wait (&start_info
->registered
, MONO_SEM_FLAGS_NONE
);
1417 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
));
1419 ret
= !start_info
->failed
;
1422 if (mono_atomic_dec_i32 (&start_info
->ref
) == 0) {
1423 mono_coop_sem_destroy (&start_info
->registered
);
1424 g_free (start_info
);
1431 * mono_thread_new_init:
1434 mono_thread_new_init (intptr_t tid
, gpointer stack_start
, gpointer func
)
1436 if (mono_thread_start_cb
) {
1437 mono_thread_start_cb (tid
, stack_start
, func
);
1442 * mono_threads_set_default_stacksize:
1445 mono_threads_set_default_stacksize (guint32 stacksize
)
1447 default_stacksize
= stacksize
;
1451 * mono_threads_get_default_stacksize:
1454 mono_threads_get_default_stacksize (void)
1456 return default_stacksize
;
1460 * mono_thread_create_internal:
1462 * ARG should not be a GC reference.
1465 mono_thread_create_internal (MonoDomain
*domain
, gpointer func
, gpointer arg
, MonoThreadCreateFlags flags
, MonoError
*error
)
1468 MonoInternalThread
*internal
;
1473 internal
= create_internal_thread_object ();
1475 thread
= create_thread_object (domain
, internal
);
1477 LOCK_THREAD (internal
);
1479 res
= create_thread (thread
, internal
, NULL
, (MonoThreadStart
) func
, arg
, flags
, error
);
1482 UNLOCK_THREAD (internal
);
1484 return_val_if_nok (error
, NULL
);
1488 MonoInternalThreadHandle
1489 mono_thread_create_internal_handle (MonoDomain
*domain
, gpointer func
, gpointer arg
, MonoThreadCreateFlags flags
, MonoError
*error
)
1492 return MONO_HANDLE_NEW (MonoInternalThread
, mono_thread_create_internal (domain
, func
, arg
, flags
, error
));
1496 * mono_thread_create:
1499 mono_thread_create (MonoDomain
*domain
, gpointer func
, gpointer arg
)
1501 MONO_ENTER_GC_UNSAFE
;
1503 if (!mono_thread_create_checked (domain
, func
, arg
, error
))
1504 mono_error_cleanup (error
);
1505 MONO_EXIT_GC_UNSAFE
;
1509 mono_thread_create_checked (MonoDomain
*domain
, gpointer func
, gpointer arg
, MonoError
*error
)
1511 return (NULL
!= mono_thread_create_internal (domain
, func
, arg
, MONO_THREAD_CREATE_FLAGS_NONE
, error
));
1515 * mono_thread_attach:
1518 mono_thread_attach (MonoDomain
*domain
)
1520 MonoInternalThread
*internal
;
1522 MonoThreadInfo
*info
;
1523 MonoNativeThreadId tid
;
1525 if (mono_thread_internal_current_is_attached ()) {
1526 if (domain
!= mono_domain_get ())
1527 mono_domain_set_fast (domain
, TRUE
);
1528 /* Already attached */
1529 return mono_thread_current ();
1532 info
= mono_thread_info_attach ();
1535 tid
=mono_native_thread_id_get ();
1537 if (mono_runtime_get_no_exec ())
1540 internal
= create_internal_thread_object ();
1542 thread
= create_thread_object (domain
, internal
);
1544 if (!mono_thread_attach_internal (thread
, FALSE
, TRUE
)) {
1545 /* Mono is shutting down, so just wait for the end */
1547 mono_thread_info_sleep (10000, NULL
);
1550 THREAD_DEBUG (g_message ("%s: Attached thread ID %" G_GSIZE_FORMAT
" (handle %p)", __func__
, tid
, internal
->handle
));
1552 if (mono_thread_attach_cb
)
1553 mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid
), info
->stack_end
);
1555 fire_attach_profiler_events (tid
);
1561 * mono_threads_attach_tools_thread:
1563 * Attach the current thread as a tool thread. DON'T USE THIS FUNCTION WITHOUT READING ALL DISCLAIMERS.
1565 * A tools thread is a very special kind of thread that needs access to core
1566 * runtime facilities but should not be counted as a regular thread for high
1567 * order facilities such as executing managed code or accessing the managed
1570 * This is intended only for low-level utilities than need to be able to use
1571 * some low-level runtime facilities when doing things like resolving
1572 * backtraces in their background processing thread.
1574 * Note in particular that the thread is not fully attached - it does not have
1575 * a "current domain" because it cannot run managed code or interact with
1576 * managed objects. However it can act on some metadata, and use our low-level
1577 * locks and the coop thread state machine (ie GC Safe and GC Unsafe
1578 * transitions make sense).
1581 mono_threads_attach_tools_thread (void)
1583 MonoThreadInfo
*info
= mono_thread_info_attach ();
1585 mono_thread_info_set_flags (MONO_THREAD_INFO_FLAGS_NO_GC
| MONO_THREAD_INFO_FLAGS_NO_SAMPLE
);
1589 * mono_thread_detach:
1592 mono_thread_detach (MonoThread
*thread
)
1595 mono_thread_detach_internal (thread
->internal_thread
);
1601 * mono_thread_detach_if_exiting:
1603 * Detach the current thread from the runtime if it is exiting, i.e. it is running pthread dtors.
1604 * This should be used at the end of embedding code which calls into managed code, and which
1605 * can be called from pthread dtors, like <code>dealloc:</code> implementations in Objective-C.
1608 mono_thread_detach_if_exiting (void)
1610 if (mono_thread_info_is_exiting ()) {
1611 MonoInternalThread
*thread
;
1613 thread
= mono_thread_internal_current ();
1615 // Switch to GC Unsafe thread state before detaching;
1616 // don't expect to undo this switch, hence unbalanced.
1618 (void) mono_threads_enter_gc_unsafe_region_unbalanced (&dummy
);
1620 mono_thread_detach_internal (thread
);
1621 mono_thread_info_detach ();
1629 mono_thread_internal_current_is_attached (void)
1631 MonoInternalThread
*internal
;
1633 internal
= GET_CURRENT_OBJECT ();
1644 mono_thread_exit (void)
1646 MonoInternalThread
*thread
= mono_thread_internal_current ();
1648 THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%" G_GSIZE_FORMAT
")", __func__
, thread
, (gsize
)thread
->tid
));
1650 mono_thread_detach_internal (thread
);
1652 /* we could add a callback here for embedders to use. */
1653 if (mono_thread_get_main () && (thread
== mono_thread_get_main ()->internal_thread
))
1654 exit (mono_environment_exitcode_get ());
1656 mono_thread_info_exit (0);
1660 mono_thread_construct_internal (MonoThreadObjectHandle this_obj_handle
)
1662 MonoInternalThread
* const internal
= create_internal_thread_object ();
1664 internal
->state
= ThreadState_Unstarted
;
1666 int const thread_gchandle
= mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject
, this_obj_handle
), TRUE
);
1668 MonoThreadObject
*this_obj
= MONO_HANDLE_RAW (this_obj_handle
);
1670 mono_atomic_cas_ptr ((volatile gpointer
*)&this_obj
->internal_thread
, internal
, NULL
);
1672 mono_gchandle_free_internal (thread_gchandle
);
1675 #ifndef ENABLE_NETCORE
1677 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThreadObjectHandle this_obj_handle
, MonoError
*error
)
1679 mono_thread_construct_internal (this_obj_handle
);
1684 ves_icall_System_Threading_Thread_GetCurrentThread (MonoThread
*volatile* thread
)
1686 *thread
= mono_thread_current ();
1689 static MonoInternalThread
*
1690 thread_handle_to_internal_ptr (MonoThreadObjectHandle thread_handle
)
1692 return MONO_HANDLE_GETVAL(thread_handle
, internal_thread
); // InternalThreads are always pinned.
1696 mono_error_set_exception_thread_state (MonoError
*error
, const char *exception_message
)
1698 mono_error_set_generic_error (error
, "System.Threading", "ThreadStateException", "%s", exception_message
);
1702 mono_error_set_exception_thread_not_started_or_dead (MonoError
*error
)
1704 mono_error_set_exception_thread_state (error
, "Thread has not been started, or is dead.");
1707 #ifndef ENABLE_NETCORE
1709 ves_icall_System_Threading_Thread_Thread_internal (MonoThreadObjectHandle thread_handle
, MonoObjectHandle start_handle
, MonoError
*error
)
1711 MonoInternalThread
*internal
;
1713 MonoThread
*this_obj
= MONO_HANDLE_RAW (thread_handle
);
1714 MonoObject
*start
= MONO_HANDLE_RAW (start_handle
);
1716 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__
, this_obj
, start
));
1718 internal
= thread_handle_to_internal_ptr (thread_handle
);
1721 mono_thread_construct_internal (thread_handle
);
1722 internal
= thread_handle_to_internal_ptr (thread_handle
);
1723 g_assert (internal
);
1726 LOCK_THREAD (internal
);
1728 if ((internal
->state
& ThreadState_Unstarted
) == 0) {
1729 UNLOCK_THREAD (internal
);
1730 mono_error_set_exception_thread_state (error
, "Thread has already been started.");
1734 if ((internal
->state
& ThreadState_Aborted
) != 0) {
1735 UNLOCK_THREAD (internal
);
1739 res
= create_thread (this_obj
, internal
, start
, NULL
, NULL
, MONO_THREAD_CREATE_FLAGS_NONE
, error
);
1741 UNLOCK_THREAD (internal
);
1745 internal
->state
&= ~ThreadState_Unstarted
;
1747 THREAD_DEBUG (g_message ("%s: Started thread ID %" G_GSIZE_FORMAT
" (handle %p)", __func__
, tid
, thread
));
1749 UNLOCK_THREAD (internal
);
1756 mono_thread_name_cleanup (MonoThreadName
* name
)
1758 MonoThreadName
const old_name
= *name
;
1759 memset (name
, 0, sizeof (*name
));
1761 g_free (old_name
.chars
);
1765 * This is called from the finalizer of the internal thread object.
1768 ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThreadHandle this_obj_handle
, MonoError
*error
)
1770 MonoInternalThread
*this_obj
= mono_internal_thread_handle_ptr (this_obj_handle
);
1771 THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__
, this_obj
, this_obj
->handle
));
1774 * Since threads keep a reference to their thread object while running, by
1775 * the time this function is called, the thread has already exited/detached,
1776 * i.e. mono_thread_detach_internal () has ran. The exception is during
1777 * shutdown, when mono_thread_detach_internal () can be called after this.
1779 if (this_obj
->handle
) {
1780 mono_threads_close_thread_handle (this_obj
->handle
);
1781 this_obj
->handle
= NULL
;
1784 mono_threads_close_native_thread_handle (MONO_GPOINTER_TO_NATIVE_THREAD_HANDLE (this_obj
->native_handle
));
1785 this_obj
->native_handle
= NULL
;
1787 /* Possibly free synch_cs, if the thread already detached also. */
1788 dec_longlived_thread_data (this_obj
->longlived
);
1790 mono_thread_name_cleanup (&this_obj
->name
);
1794 mono_sleep_internal (gint32 ms
, MonoBoolean allow_interruption
, MonoError
*error
)
1796 THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__
, ms
));
1798 if (mono_thread_current_check_pending_interrupt ())
1801 MonoInternalThread
* const thread
= mono_thread_internal_current ();
1803 HANDLE_LOOP_PREPARE
;
1806 gboolean alerted
= FALSE
;
1808 mono_thread_set_state (thread
, ThreadState_WaitSleepJoin
);
1810 (void)mono_thread_info_sleep (ms
, &alerted
);
1812 mono_thread_clr_state (thread
, ThreadState_WaitSleepJoin
);
1817 if (allow_interruption
) {
1820 MonoExceptionHandle exc
= MONO_HANDLE_NEW (MonoException
, NULL
);
1822 const gboolean interrupt
= mono_thread_execute_interruption (&exc
);
1825 mono_set_pending_exception_handle (exc
);
1833 if (ms
== MONO_INFINITE_WAIT
) // FIXME: !MONO_INFINITE_WAIT
1839 #ifdef ENABLE_NETCORE
1841 ves_icall_System_Threading_Thread_Sleep_internal (gint32 ms
, MonoBoolean allow_interruption
, MonoError
*error
)
1843 mono_sleep_internal (ms
, allow_interruption
, error
);
1847 ves_icall_System_Threading_Thread_Sleep_internal (gint32 ms
, MonoError
*error
)
1849 mono_sleep_internal (ms
, TRUE
, error
);
1853 ves_icall_System_Threading_Thread_SpinWait_nop (MonoError
*error
)
1858 #ifndef ENABLE_NETCORE
1860 ves_icall_System_Threading_Thread_GetDomainID (MonoError
*error
)
1862 return mono_domain_get()->domain_id
;
1867 * mono_thread_get_name_utf8:
1868 * \returns the name of the thread in UTF-8.
1869 * Return NULL if the thread has no name.
1870 * The returned memory is owned by the caller (g_free it).
1873 mono_thread_get_name_utf8 (MonoThread
*thread
)
1878 MonoInternalThread
*internal
= thread
->internal_thread
;
1880 // This is a little racy, ok.
1882 if (internal
== NULL
|| !internal
->name
.chars
)
1885 LOCK_THREAD (internal
);
1887 char *tname
= (char*)g_memdup (internal
->name
.chars
, internal
->name
.length
+ 1);
1889 UNLOCK_THREAD (internal
);
1895 * mono_thread_get_managed_id:
1896 * \returns the \c Thread.ManagedThreadId value of \p thread.
1897 * Returns \c -1 if \p thread is NULL.
1900 mono_thread_get_managed_id (MonoThread
*thread
)
1905 MonoInternalThread
*internal
= thread
->internal_thread
;
1906 if (internal
== NULL
)
1909 int32_t id
= internal
->managed_id
;
1914 #ifndef ENABLE_NETCORE
1916 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThreadHandle thread_handle
, MonoError
*error
)
1918 // InternalThreads are always pinned, so shallowly coop-handleize.
1919 MonoInternalThread
* const this_obj
= mono_internal_thread_handle_ptr (thread_handle
);
1921 MonoStringHandle str
= NULL_HANDLE_STRING
;
1923 // This is a little racy, ok.
1925 if (this_obj
->name
.chars
) {
1926 LOCK_THREAD (this_obj
);
1928 if (this_obj
->name
.chars
)
1929 str
= mono_string_new_utf8_len (mono_domain_get (), this_obj
->name
.chars
, this_obj
->name
.length
, error
);
1931 UNLOCK_THREAD (this_obj
);
1939 // - MonoError is optional -- failure is usually not interesting, except the documented failure mode for managed callers.
1940 // - name16 only used on Windows.
1941 // - name8 is either constant, or g_free'able -- this function always takes ownership and never copies.
1944 mono_thread_set_name (MonoInternalThread
*this_obj
,
1945 const char* name8
, size_t name8_length
, const gunichar2
* name16
,
1946 MonoSetThreadNameFlags flags
, MonoError
*error
)
1948 // A special case for the threadpool worker.
1949 // It sets the name repeatedly, in case it has changed, per-spec,
1950 // and if not done carefully, this can be a performance problem.
1952 // This is racy but ok. The name will always be valid (or absent).
1953 // In an unusual race, the name might briefly not revert to what the spec requires.
1955 if ((flags
& MonoSetThreadNameFlag_RepeatedlyButOptimized
) && name8
== this_obj
->name
.chars
) {
1956 // Length is presumed to match.
1960 MonoNativeThreadId tid
= 0;
1962 const gboolean constant
= !!(flags
& MonoSetThreadNameFlag_Constant
);
1964 #if HOST_WIN32 // On Windows, if name8 is supplied, then name16 must be also.
1965 g_assert (!name8
|| name16
);
1968 LOCK_THREAD (this_obj
);
1970 if (flags
& MonoSetThreadNameFlag_Reset
) {
1971 this_obj
->flags
&= ~MONO_THREAD_FLAG_NAME_SET
;
1972 } else if (this_obj
->flags
& MONO_THREAD_FLAG_NAME_SET
) {
1973 UNLOCK_THREAD (this_obj
);
1976 mono_error_set_invalid_operation (error
, "%s", "Thread.Name can only be set once.");
1979 g_free ((char*)name8
);
1983 mono_thread_name_cleanup (&this_obj
->name
);
1986 this_obj
->name
.chars
= (char*)name8
;
1987 this_obj
->name
.length
= name8_length
;
1988 this_obj
->name
.free
= !constant
;
1989 if (flags
& MonoSetThreadNameFlag_Permanent
)
1990 this_obj
->flags
|= MONO_THREAD_FLAG_NAME_SET
;
1993 if (!(this_obj
->state
& ThreadState_Stopped
))
1994 tid
= thread_get_tid (this_obj
);
1996 UNLOCK_THREAD (this_obj
);
1999 MONO_PROFILER_RAISE (thread_name
, ((uintptr_t)tid
, name8
));
2000 mono_native_thread_set_name (tid
, name8
);
2003 mono_thread_set_name_windows (this_obj
->native_handle
, name16
);
2005 mono_free (0); // FIXME keep mono-publib.c in use and its functions exported
2009 ves_icall_System_Threading_Thread_SetName_icall (MonoInternalThreadHandle thread_handle
, const gunichar2
* name16
, gint32 name16_length
, MonoError
* error
)
2011 long name8_length
= 0;
2013 char* name8
= name16
? g_utf16_to_utf8 (name16
, name16_length
, NULL
, &name8_length
, NULL
) : NULL
;
2015 mono_thread_set_name (mono_internal_thread_handle_ptr (thread_handle
),
2016 name8
, (gint32
)name8_length
, name16
, MonoSetThreadNameFlag_Permanent
, error
);
2019 #ifndef ENABLE_NETCORE
2021 * ves_icall_System_Threading_Thread_GetPriority_internal:
2022 * @param this_obj: The MonoInternalThread on which to operate.
2024 * Gets the priority of the given thread.
2025 * @return: The priority of the given thread.
2028 ves_icall_System_Threading_Thread_GetPriority (MonoThreadObjectHandle this_obj
, MonoError
*error
)
2032 MonoInternalThread
*internal
= thread_handle_to_internal_ptr (this_obj
);
2034 LOCK_THREAD (internal
);
2035 priority
= internal
->priority
;
2036 UNLOCK_THREAD (internal
);
2043 * ves_icall_System_Threading_Thread_SetPriority_internal:
2044 * @param this_obj: The MonoInternalThread on which to operate.
2045 * @param priority: The priority to set.
2047 * Sets the priority of the given thread.
2050 ves_icall_System_Threading_Thread_SetPriority (MonoThreadObjectHandle this_obj
, int priority
, MonoError
*error
)
2052 MonoInternalThread
*internal
= thread_handle_to_internal_ptr (this_obj
);
2054 LOCK_THREAD (internal
);
2055 internal
->priority
= priority
;
2056 if (internal
->thread_info
!= NULL
)
2057 mono_thread_internal_set_priority (internal
, (MonoThreadPriority
)priority
);
2058 UNLOCK_THREAD (internal
);
2061 /* If the array is already in the requested domain, we just return it,
2062 otherwise we return a copy in that domain. */
2063 static MonoArrayHandle
2064 byte_array_to_domain (MonoArrayHandle arr
, MonoDomain
*domain
, MonoError
*error
)
2066 HANDLE_FUNCTION_ENTER ()
2068 if (MONO_HANDLE_IS_NULL (arr
))
2069 return MONO_HANDLE_NEW (MonoArray
, NULL
);
2071 if (MONO_HANDLE_DOMAIN (arr
) == domain
)
2074 size_t const size
= mono_array_handle_length (arr
);
2076 // Capture arrays into common representation for repetitious code.
2077 // These two variables could also be an array of size 2 and
2078 // repetition implemented with a loop.
2080 MonoArrayHandle handle
;
2085 dest
= { mono_array_new_handle (domain
, mono_defaults
.byte_class
, size
, error
) };
2086 goto_if_nok (error
, exit
);
2089 source
.p
= mono_array_handle_pin_with_size (source
.handle
, size
, 0, &source
.gchandle
);
2090 dest
.p
= mono_array_handle_pin_with_size (dest
.handle
, size
, 0, &dest
.gchandle
);
2092 memmove (dest
.p
, source
.p
, size
);
2094 // Unpin both arrays.
2095 mono_gchandle_free_internal (source
.gchandle
);
2096 mono_gchandle_free_internal (dest
.gchandle
);
2098 HANDLE_FUNCTION_RETURN_REF (MonoArray
, dest
.handle
)
2101 #ifndef ENABLE_NETCORE
2103 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArrayHandle arr
, MonoError
*error
)
2105 return byte_array_to_domain (arr
, mono_get_root_domain (), error
);
2109 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArrayHandle arr
, MonoError
*error
)
2111 return byte_array_to_domain (arr
, mono_domain_get (), error
);
2116 * mono_thread_current:
2119 mono_thread_current (void)
2121 #ifdef ENABLE_NETCORE
2122 return mono_thread_internal_current ();
2124 MonoDomain
*domain
= mono_domain_get ();
2125 MonoInternalThread
*internal
= mono_thread_internal_current ();
2126 MonoThread
**current_thread_ptr
;
2128 g_assert (internal
);
2129 current_thread_ptr
= get_current_thread_ptr_for_domain (domain
, internal
);
2131 if (!*current_thread_ptr
) {
2132 g_assert (domain
!= mono_get_root_domain ());
2133 *current_thread_ptr
= create_thread_object (domain
, internal
);
2135 return *current_thread_ptr
;
2139 static MonoThreadObjectHandle
2140 mono_thread_current_handle (void)
2142 return MONO_HANDLE_NEW (MonoThreadObject
, mono_thread_current ());
2145 /* Return the thread object belonging to INTERNAL in the current domain */
2147 mono_thread_current_for_thread (MonoInternalThread
*internal
)
2149 #ifdef ENABLE_NETCORE
2150 return mono_thread_internal_current ();
2152 MonoDomain
*domain
= mono_domain_get ();
2153 MonoThread
**current_thread_ptr
;
2155 g_assert (internal
);
2156 current_thread_ptr
= get_current_thread_ptr_for_domain (domain
, internal
);
2158 if (!*current_thread_ptr
) {
2159 g_assert (domain
!= mono_get_root_domain ());
2160 *current_thread_ptr
= create_thread_object (domain
, internal
);
2162 return *current_thread_ptr
;
2167 mono_thread_internal_current (void)
2169 MonoInternalThread
*res
= GET_CURRENT_OBJECT ();
2170 THREAD_DEBUG (g_message ("%s: returning %p", __func__
, res
));
2174 MonoInternalThreadHandle
2175 mono_thread_internal_current_handle (void)
2177 return MONO_HANDLE_NEW (MonoInternalThread
, mono_thread_internal_current ());
2180 static MonoThreadInfoWaitRet
2181 mono_join_uninterrupted (MonoThreadHandle
* thread_to_join
, gint32 ms
, MonoError
*error
)
2183 MonoThreadInfoWaitRet ret
;
2186 const gint64 start
= (ms
== -1) ? 0 : mono_msec_ticks ();
2189 ret
= mono_thread_info_wait_one_handle (thread_to_join
, wait
, TRUE
);
2192 if (ret
!= MONO_THREAD_INFO_WAIT_RET_ALERTED
)
2195 MonoException
*exc
= mono_thread_execute_interruption_ptr ();
2197 mono_error_set_exception_instance (error
, exc
);
2204 /* Re-calculate ms according to the time passed */
2205 const gint32 diff_ms
= (gint32
)(mono_msec_ticks () - start
);
2206 if (diff_ms
>= ms
) {
2207 ret
= MONO_THREAD_INFO_WAIT_RET_TIMEOUT
;
2210 wait
= ms
- diff_ms
;
2217 ves_icall_System_Threading_Thread_Join_internal (MonoThreadObjectHandle thread_handle
, int ms
, MonoError
*error
)
2219 if (mono_thread_current_check_pending_interrupt ())
2222 // Internal threads are pinned so shallow coop/handle.
2223 MonoInternalThread
* const thread
= thread_handle_to_internal_ptr (thread_handle
);
2224 MonoThreadHandle
*handle
= thread
->handle
;
2225 MonoInternalThread
*cur_thread
= mono_thread_internal_current ();
2226 gboolean ret
= FALSE
;
2228 LOCK_THREAD (thread
);
2230 if ((thread
->state
& ThreadState_Unstarted
) != 0) {
2231 UNLOCK_THREAD (thread
);
2233 mono_error_set_exception_thread_state (error
, "Thread has not been started.");
2237 UNLOCK_THREAD (thread
);
2240 ms
= MONO_INFINITE_WAIT
;
2241 THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__
, handle
, ms
));
2243 mono_thread_set_state (cur_thread
, ThreadState_WaitSleepJoin
);
2245 ret
= mono_join_uninterrupted (handle
, ms
, error
);
2247 mono_thread_clr_state (cur_thread
, ThreadState_WaitSleepJoin
);
2249 if (ret
== MONO_THREAD_INFO_WAIT_RET_SUCCESS_0
) {
2250 THREAD_DEBUG (g_message ("%s: join successful", __func__
));
2252 mono_error_assert_ok (error
);
2254 /* Wait for the thread to really exit */
2255 MonoNativeThreadId tid
= thread_get_tid (thread
);
2256 mono_thread_join ((gpointer
)(gsize
)tid
);
2261 THREAD_DEBUG (g_message ("%s: join failed", __func__
));
2266 #define MANAGED_WAIT_FAILED 0x7fffffff
2269 map_native_wait_result_to_managed (MonoW32HandleWaitRet val
, gsize numobjects
)
2271 if (val
>= MONO_W32HANDLE_WAIT_RET_SUCCESS_0
&& val
< MONO_W32HANDLE_WAIT_RET_SUCCESS_0
+ numobjects
) {
2272 return WAIT_OBJECT_0
+ (val
- MONO_W32HANDLE_WAIT_RET_SUCCESS_0
);
2273 } else if (val
>= MONO_W32HANDLE_WAIT_RET_ABANDONED_0
&& val
< MONO_W32HANDLE_WAIT_RET_ABANDONED_0
+ numobjects
) {
2274 return WAIT_ABANDONED_0
+ (val
- MONO_W32HANDLE_WAIT_RET_ABANDONED_0
);
2275 } else if (val
== MONO_W32HANDLE_WAIT_RET_ALERTED
) {
2276 return WAIT_IO_COMPLETION
;
2277 } else if (val
== MONO_W32HANDLE_WAIT_RET_TIMEOUT
) {
2278 return WAIT_TIMEOUT
;
2279 } else if (val
== MONO_W32HANDLE_WAIT_RET_TOO_MANY_POSTS
) {
2280 return WAIT_TOO_MANY_POSTS
;
2281 } else if (val
== MONO_W32HANDLE_WAIT_RET_NOT_OWNED_BY_CALLER
) {
2282 return WAIT_NOT_OWNED_BY_CALLER
;
2283 } else if (val
== MONO_W32HANDLE_WAIT_RET_FAILED
) {
2284 /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
2285 return MANAGED_WAIT_FAILED
;
2287 g_error ("%s: unknown val value %d", __func__
, val
);
2292 ves_icall_System_Threading_WaitHandle_Wait_internal (gpointer
*handles
, gint32 numhandles
, MonoBoolean waitall
, gint32 timeout
, MonoError
*error
)
2294 /* Do this WaitSleepJoin check before creating objects */
2295 if (mono_thread_current_check_pending_interrupt ())
2296 return map_native_wait_result_to_managed (MONO_W32HANDLE_WAIT_RET_FAILED
, 0);
2298 MonoInternalThread
* const thread
= mono_thread_internal_current ();
2300 mono_thread_set_state (thread
, ThreadState_WaitSleepJoin
);
2305 timeout
= MONO_INFINITE_WAIT
;
2306 if (timeout
!= MONO_INFINITE_WAIT
)
2307 start
= mono_msec_ticks ();
2309 guint32 timeoutLeft
= timeout
;
2311 MonoW32HandleWaitRet ret
;
2313 HANDLE_LOOP_PREPARE
;
2317 /* mono_w32handle_wait_multiple optimizes the case for numhandles == 1 */
2318 ret
= mono_w32handle_wait_multiple (handles
, numhandles
, waitall
, timeoutLeft
, TRUE
, error
);
2320 if (ret
!= MONO_W32HANDLE_WAIT_RET_ALERTED
)
2325 MonoExceptionHandle exc
= MONO_HANDLE_NEW (MonoException
, NULL
);
2327 const gboolean interrupt
= mono_thread_execute_interruption (&exc
);
2330 mono_error_set_exception_handle (error
, exc
);
2337 if (timeout
!= MONO_INFINITE_WAIT
) {
2338 gint64
const elapsed
= mono_msec_ticks () - start
;
2339 if (elapsed
>= timeout
) {
2340 ret
= MONO_W32HANDLE_WAIT_RET_TIMEOUT
;
2344 timeoutLeft
= timeout
- elapsed
;
2348 mono_thread_clr_state (thread
, ThreadState_WaitSleepJoin
);
2350 return map_native_wait_result_to_managed (ret
, numhandles
);
2353 #if HAVE_API_SUPPORT_WIN32_SIGNAL_OBJECT_AND_WAIT
2355 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (gpointer toSignal
, gpointer toWait
, gint32 ms
, MonoError
*error
)
2357 MonoW32HandleWaitRet ret
;
2358 MonoInternalThread
*thread
= mono_thread_internal_current ();
2361 ms
= MONO_INFINITE_WAIT
;
2363 if (mono_thread_current_check_pending_interrupt ())
2364 return map_native_wait_result_to_managed (MONO_W32HANDLE_WAIT_RET_FAILED
, 0);
2366 mono_thread_set_state (thread
, ThreadState_WaitSleepJoin
);
2368 ret
= mono_w32handle_signal_and_wait (toSignal
, toWait
, ms
, TRUE
);
2370 mono_thread_clr_state (thread
, ThreadState_WaitSleepJoin
);
2372 return map_native_wait_result_to_managed (ret
, 1);
2377 gint32
ves_icall_System_Threading_Interlocked_Increment_Int (gint32
*location
)
2379 return mono_atomic_inc_i32 (location
);
2382 gint64
ves_icall_System_Threading_Interlocked_Increment_Long (gint64
*location
)
2384 #if SIZEOF_VOID_P == 4
2385 if (G_UNLIKELY ((size_t)location
& 0x7)) {
2387 mono_interlocked_lock ();
2390 mono_interlocked_unlock ();
2394 return mono_atomic_inc_i64 (location
);
2397 gint32
ves_icall_System_Threading_Interlocked_Decrement_Int (gint32
*location
)
2399 return mono_atomic_dec_i32(location
);
2402 gint64
ves_icall_System_Threading_Interlocked_Decrement_Long (gint64
* location
)
2404 #if SIZEOF_VOID_P == 4
2405 if (G_UNLIKELY ((size_t)location
& 0x7)) {
2407 mono_interlocked_lock ();
2410 mono_interlocked_unlock ();
2414 return mono_atomic_dec_i64 (location
);
2417 gint32
ves_icall_System_Threading_Interlocked_Exchange_Int (gint32
*location
, gint32 value
)
2419 return mono_atomic_xchg_i32(location
, value
);
2423 ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject
*volatile*location
, MonoObject
*volatile*value
, MonoObject
*volatile*res
)
2425 // Coop-equivalency here via pointers to pointers.
2426 // value and res are to managed frames, location ought to be (or member or global) but it cannot be guaranteed.
2428 // This also handles generic T case, T constrained to a class.
2430 // This is not entirely convincing due to lack of volatile in the caller, however coop also
2431 // presently breaks identity of location and would therefore never work.
2433 *res
= (MonoObject
*)mono_atomic_xchg_ptr ((volatile gpointer
*)location
, *value
);
2434 mono_gc_wbarrier_generic_nostore_internal ((gpointer
)location
); // FIXME volatile
2437 gpointer
ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer
*location
, gpointer value
)
2439 return mono_atomic_xchg_ptr(location
, value
);
2442 gfloat
ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat
*location
, gfloat value
)
2444 IntFloatUnion val
, ret
;
2447 ret
.ival
= mono_atomic_xchg_i32((gint32
*) location
, val
.ival
);
2453 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64
*location
, gint64 value
)
2455 #if SIZEOF_VOID_P == 4
2456 if (G_UNLIKELY ((size_t)location
& 0x7)) {
2458 mono_interlocked_lock ();
2461 mono_interlocked_unlock ();
2465 return mono_atomic_xchg_i64 (location
, value
);
2469 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble
*location
, gdouble value
)
2471 LongDoubleUnion val
, ret
;
2474 ret
.ival
= (gint64
)mono_atomic_xchg_i64((gint64
*) location
, val
.ival
);
2479 gint32
ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32
*location
, gint32 value
, gint32 comparand
)
2481 return mono_atomic_cas_i32(location
, value
, comparand
);
2484 gint32
ves_icall_System_Threading_Interlocked_CompareExchange_Int_Success(gint32
*location
, gint32 value
, gint32 comparand
, MonoBoolean
*success
)
2486 gint32 r
= mono_atomic_cas_i32(location
, value
, comparand
);
2487 *success
= r
== comparand
;
2492 ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject
*volatile*location
, MonoObject
*volatile*value
, MonoObject
*volatile*comparand
, MonoObject
*volatile* res
)
2494 // Coop-equivalency here via pointers to pointers.
2495 // value and comparand and res are to managed frames, location ought to be (or member or global) but it cannot be guaranteed.
2497 // This also handles generic T case, T constrained to a class.
2499 // This is not entirely convincing due to lack of volatile in the caller, however coop also
2500 // presently breaks identity of location and would therefore never work.
2502 *res
= (MonoObject
*)mono_atomic_cas_ptr ((volatile gpointer
*)location
, *value
, *comparand
);
2503 mono_gc_wbarrier_generic_nostore_internal ((gpointer
)location
); // FIXME volatile
2506 gpointer
ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer
*location
, gpointer value
, gpointer comparand
)
2508 return mono_atomic_cas_ptr(location
, value
, comparand
);
2511 gfloat
ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat
*location
, gfloat value
, gfloat comparand
)
2513 IntFloatUnion val
, ret
, cmp
;
2516 cmp
.fval
= comparand
;
2517 ret
.ival
= mono_atomic_cas_i32((gint32
*) location
, val
.ival
, cmp
.ival
);
2523 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble
*location
, gdouble value
, gdouble comparand
)
2525 #if SIZEOF_VOID_P == 8
2526 LongDoubleUnion val
, comp
, ret
;
2529 comp
.fval
= comparand
;
2530 ret
.ival
= (gint64
)mono_atomic_cas_ptr((gpointer
*) location
, (gpointer
)val
.ival
, (gpointer
)comp
.ival
);
2536 mono_interlocked_lock ();
2538 if (old
== comparand
)
2540 mono_interlocked_unlock ();
2547 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64
*location
, gint64 value
, gint64 comparand
)
2549 #if SIZEOF_VOID_P == 4
2550 if (G_UNLIKELY ((size_t)location
& 0x7)) {
2552 mono_interlocked_lock ();
2554 if (old
== comparand
)
2556 mono_interlocked_unlock ();
2560 return mono_atomic_cas_i64 (location
, value
, comparand
);
2564 ves_icall_System_Threading_Interlocked_Add_Int (gint32
*location
, gint32 value
)
2566 return mono_atomic_add_i32 (location
, value
);
2570 ves_icall_System_Threading_Interlocked_Add_Long (gint64
*location
, gint64 value
)
2572 #if SIZEOF_VOID_P == 4
2573 if (G_UNLIKELY ((size_t)location
& 0x7)) {
2575 mono_interlocked_lock ();
2578 mono_interlocked_unlock ();
2582 return mono_atomic_add_i64 (location
, value
);
2586 ves_icall_System_Threading_Interlocked_Read_Long (gint64
*location
)
2588 #if SIZEOF_VOID_P == 4
2589 if (G_UNLIKELY ((size_t)location
& 0x7)) {
2591 mono_interlocked_lock ();
2593 mono_interlocked_unlock ();
2597 return mono_atomic_load_i64 (location
);
2601 ves_icall_System_Threading_Interlocked_MemoryBarrierProcessWide (void)
2603 mono_memory_barrier_process_wide ();
2607 ves_icall_System_Threading_Thread_MemoryBarrier (void)
2609 mono_memory_barrier ();
2613 ves_icall_System_Threading_Thread_ClrState (MonoInternalThreadHandle this_obj
, guint32 state
, MonoError
*error
)
2615 // InternalThreads are always pinned, so shallowly coop-handleize.
2616 mono_thread_clr_state (mono_internal_thread_handle_ptr (this_obj
), (MonoThreadState
)state
);
2620 ves_icall_System_Threading_Thread_SetState (MonoInternalThreadHandle thread_handle
, guint32 state
, MonoError
*error
)
2622 // InternalThreads are always pinned, so shallowly coop-handleize.
2623 mono_thread_set_state (mono_internal_thread_handle_ptr (thread_handle
), (MonoThreadState
)state
);
2627 ves_icall_System_Threading_Thread_GetState (MonoInternalThreadHandle thread_handle
, MonoError
*error
)
2629 // InternalThreads are always pinned, so shallowly coop-handleize.
2630 MonoInternalThread
*this_obj
= mono_internal_thread_handle_ptr (thread_handle
);
2634 LOCK_THREAD (this_obj
);
2636 state
= this_obj
->state
;
2638 UNLOCK_THREAD (this_obj
);
2644 ves_icall_System_Threading_Thread_Interrupt_internal (MonoThreadObjectHandle thread_handle
, MonoError
*error
)
2646 // Internal threads are pinned so shallow coop/handle.
2647 MonoInternalThread
* const thread
= thread_handle_to_internal_ptr (thread_handle
);
2648 MonoInternalThread
* const current
= mono_thread_internal_current ();
2650 LOCK_THREAD (thread
);
2652 thread
->thread_interrupt_requested
= TRUE
;
2653 gboolean
const throw_
= current
!= thread
&& (thread
->state
& ThreadState_WaitSleepJoin
);
2655 UNLOCK_THREAD (thread
);
2658 async_abort_internal (thread
, FALSE
);
2662 * mono_thread_current_check_pending_interrupt:
2663 * Checks if there's a interruption request and set the pending exception if so.
2664 * \returns true if a pending exception was set
2667 mono_thread_current_check_pending_interrupt (void)
2669 MonoInternalThread
*thread
= mono_thread_internal_current ();
2670 gboolean throw_
= FALSE
;
2672 LOCK_THREAD (thread
);
2674 if (thread
->thread_interrupt_requested
) {
2676 thread
->thread_interrupt_requested
= FALSE
;
2679 UNLOCK_THREAD (thread
);
2683 mono_error_set_thread_interrupted (error
);
2684 mono_error_set_pending_exception (error
);
2690 request_thread_abort (MonoInternalThread
*thread
, MonoObjectHandle
*state
, gboolean appdomain_unload
)
2691 // state is a pointer to a handle in order to be optional,
2692 // and be passed unspecified from functions not using handles.
2693 // When raw pointers is gone, it need not be a pointer,
2694 // though this would still work efficiently.
2696 LOCK_THREAD (thread
);
2698 /* With self abort we always throw a new exception */
2699 if (thread
== mono_thread_internal_current ())
2700 thread
->abort_exc
= NULL
;
2702 if (thread
->state
& (ThreadState_AbortRequested
| ThreadState_Stopped
))
2704 UNLOCK_THREAD (thread
);
2708 if ((thread
->state
& ThreadState_Unstarted
) != 0) {
2709 thread
->state
|= ThreadState_Aborted
;
2710 UNLOCK_THREAD (thread
);
2714 thread
->state
|= ThreadState_AbortRequested
;
2715 if (appdomain_unload
)
2716 thread
->flags
|= MONO_THREAD_FLAG_APPDOMAIN_ABORT
;
2718 thread
->flags
&= ~MONO_THREAD_FLAG_APPDOMAIN_ABORT
;
2720 mono_gchandle_free_internal (thread
->abort_state_handle
);
2721 thread
->abort_state_handle
= 0;
2724 if (state
&& !MONO_HANDLE_IS_NULL (*state
)) {
2725 thread
->abort_state_handle
= mono_gchandle_from_handle (*state
, FALSE
);
2726 g_assert (thread
->abort_state_handle
);
2729 thread
->abort_exc
= NULL
;
2731 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
));
2733 /* During shutdown, we can't wait for other threads */
2735 /* Make sure the thread is awake */
2736 mono_thread_resume (thread
);
2738 UNLOCK_THREAD (thread
);
2742 #ifndef ENABLE_NETCORE
2744 ves_icall_System_Threading_Thread_Abort (MonoInternalThreadHandle thread_handle
, MonoObjectHandle state
, MonoError
*error
)
2746 // InternalThreads are always pinned, so shallowly coop-handleize.
2747 MonoInternalThread
* const thread
= mono_internal_thread_handle_ptr (thread_handle
);
2748 gboolean is_self
= thread
== mono_thread_internal_current ();
2750 /* For self aborts we always process the abort */
2751 if (!request_thread_abort (thread
, &state
, FALSE
) && !is_self
)
2755 self_abort_internal (error
);
2757 async_abort_internal (thread
, TRUE
);
2763 * mono_thread_internal_abort:
2764 * Request thread \p thread to be aborted.
2765 * \p thread MUST NOT be the current thread.
2768 mono_thread_internal_abort (MonoInternalThread
*thread
, gboolean appdomain_unload
)
2770 g_assert (thread
!= mono_thread_internal_current ());
2772 if (!request_thread_abort (thread
, NULL
, appdomain_unload
))
2774 async_abort_internal (thread
, TRUE
);
2777 #ifndef ENABLE_NETCORE
2779 ves_icall_System_Threading_Thread_ResetAbort (MonoThreadObjectHandle this_obj
, MonoError
*error
)
2781 MonoInternalThread
*thread
= mono_thread_internal_current ();
2782 gboolean was_aborting
, is_domain_abort
;
2784 LOCK_THREAD (thread
);
2785 was_aborting
= thread
->state
& ThreadState_AbortRequested
;
2786 is_domain_abort
= thread
->flags
& MONO_THREAD_FLAG_APPDOMAIN_ABORT
;
2788 if (was_aborting
&& !is_domain_abort
)
2789 thread
->state
&= ~ThreadState_AbortRequested
;
2790 UNLOCK_THREAD (thread
);
2792 if (!was_aborting
) {
2793 mono_error_set_exception_thread_state (error
, "Unable to reset abort because no abort was requested");
2795 } else if (is_domain_abort
) {
2796 /* Silently ignore abort resets in unloading appdomains */
2800 mono_get_eh_callbacks ()->mono_clear_abort_threshold ();
2801 thread
->abort_exc
= NULL
;
2802 mono_gchandle_free_internal (thread
->abort_state_handle
);
2803 /* This is actually not necessary - the handle
2804 only counts if the exception is set */
2805 thread
->abort_state_handle
= 0;
2810 mono_thread_internal_reset_abort (MonoInternalThread
*thread
)
2812 LOCK_THREAD (thread
);
2814 thread
->state
&= ~ThreadState_AbortRequested
;
2816 if (thread
->abort_exc
) {
2817 mono_get_eh_callbacks ()->mono_clear_abort_threshold ();
2818 thread
->abort_exc
= NULL
;
2819 mono_gchandle_free_internal (thread
->abort_state_handle
);
2820 /* This is actually not necessary - the handle
2821 only counts if the exception is set */
2822 thread
->abort_state_handle
= 0;
2825 UNLOCK_THREAD (thread
);
2828 #ifndef ENABLE_NETCORE
2830 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThreadObjectHandle this_obj
, MonoError
*error
)
2832 MonoInternalThread
*thread
= thread_handle_to_internal_ptr (this_obj
);
2834 if (!thread
->abort_state_handle
)
2835 return NULL_HANDLE
; // No state. No error.
2837 // Convert gc handle to coop handle.
2838 MonoObjectHandle state
= mono_gchandle_get_target_handle (thread
->abort_state_handle
);
2839 g_assert (MONO_HANDLE_BOOL (state
));
2841 MonoDomain
*domain
= mono_domain_get ();
2842 if (MONO_HANDLE_DOMAIN (state
) == domain
)
2843 return state
; // No need to cross domain, return state directly.
2845 // Attempt move state cross-domain.
2846 MonoObjectHandle deserialized
= mono_object_xdomain_representation (state
, domain
, error
);
2848 // If deserialized is null, there must be an error, and vice versa.
2849 g_assert (is_ok (error
) == MONO_HANDLE_BOOL (deserialized
));
2851 if (MONO_HANDLE_BOOL (deserialized
))
2852 return deserialized
; // Cross-domain serialization succeeded. Return it.
2854 // Wrap error in InvalidOperationException.
2855 ERROR_DECL (error_creating_exception
);
2856 MonoExceptionHandle invalid_op_exc
= mono_exception_new_invalid_operation (
2857 "Thread.ExceptionState cannot access an ExceptionState from a different AppDomain", error_creating_exception
);
2858 mono_error_assert_ok (error_creating_exception
);
2859 g_assert (!is_ok (error
) && 1);
2860 MONO_HANDLE_SET (invalid_op_exc
, inner_ex
, mono_error_convert_to_exception_handle (error
));
2861 error_init_reuse (error
);
2862 mono_error_set_exception_handle (error
, invalid_op_exc
);
2863 g_assert (!is_ok (error
) && 2);
2865 // There is state, but we failed to return it.
2871 mono_thread_suspend (MonoInternalThread
*thread
)
2873 LOCK_THREAD (thread
);
2875 if (thread
->state
& (ThreadState_Unstarted
| ThreadState_Aborted
| ThreadState_Stopped
))
2877 UNLOCK_THREAD (thread
);
2881 if (thread
->state
& (ThreadState_Suspended
| ThreadState_SuspendRequested
| ThreadState_AbortRequested
))
2883 UNLOCK_THREAD (thread
);
2887 thread
->state
|= ThreadState_SuspendRequested
;
2889 mono_os_event_reset (thread
->suspended
);
2892 if (thread
== mono_thread_internal_current ()) {
2893 /* calls UNLOCK_THREAD (thread) */
2894 self_suspend_internal ();
2896 /* calls UNLOCK_THREAD (thread) */
2897 async_suspend_internal (thread
, FALSE
);
2903 #ifndef ENABLE_NETCORE
2905 ves_icall_System_Threading_Thread_Suspend (MonoThreadObjectHandle this_obj
, MonoError
*error
)
2907 if (!mono_thread_suspend (thread_handle_to_internal_ptr (this_obj
)))
2908 mono_error_set_exception_thread_not_started_or_dead (error
);
2913 /* LOCKING: LOCK_THREAD(thread) must be held */
2915 mono_thread_resume (MonoInternalThread
*thread
)
2917 if ((thread
->state
& ThreadState_SuspendRequested
) != 0) {
2918 // g_async_safe_printf ("RESUME (1) thread %p\n", thread_get_tid (thread));
2919 thread
->state
&= ~ThreadState_SuspendRequested
;
2921 mono_os_event_set (thread
->suspended
);
2926 if ((thread
->state
& ThreadState_Suspended
) == 0 ||
2927 (thread
->state
& ThreadState_Unstarted
) != 0 ||
2928 (thread
->state
& ThreadState_Aborted
) != 0 ||
2929 (thread
->state
& ThreadState_Stopped
) != 0)
2931 // g_async_safe_printf ("RESUME (2) thread %p\n", thread_get_tid (thread));
2935 // g_async_safe_printf ("RESUME (3) thread %p\n", thread_get_tid (thread));
2938 mono_os_event_set (thread
->suspended
);
2941 if (!thread
->self_suspended
) {
2942 UNLOCK_THREAD (thread
);
2944 /* Awake the thread */
2945 if (!mono_thread_info_resume (thread_get_tid (thread
)))
2948 LOCK_THREAD (thread
);
2951 thread
->state
&= ~ThreadState_Suspended
;
2956 #ifndef ENABLE_NETCORE
2958 ves_icall_System_Threading_Thread_Resume (MonoThreadObjectHandle thread_handle
, MonoError
*error
)
2960 // Internal threads are pinned so shallow coop/handle.
2961 MonoInternalThread
* const internal_thread
= thread_handle_to_internal_ptr (thread_handle
);
2962 gboolean exception
= FALSE
;
2964 if (!internal_thread
) {
2967 LOCK_THREAD (internal_thread
);
2968 if (!mono_thread_resume (internal_thread
))
2970 UNLOCK_THREAD (internal_thread
);
2974 mono_error_set_exception_thread_not_started_or_dead (error
);
2979 mono_threads_is_critical_method (MonoMethod
*method
)
2981 switch (method
->wrapper_type
) {
2982 case MONO_WRAPPER_RUNTIME_INVOKE
:
2983 case MONO_WRAPPER_XDOMAIN_INVOKE
:
2984 case MONO_WRAPPER_XDOMAIN_DISPATCH
:
2991 find_wrapper (MonoMethod
*m
, gint no
, gint ilo
, gboolean managed
, gpointer data
)
2996 if (mono_threads_is_critical_method (m
)) {
2997 *((gboolean
*)data
) = TRUE
;
3004 is_running_protected_wrapper (void)
3006 gboolean found
= FALSE
;
3007 mono_stack_walk (find_wrapper
, &found
);
3015 mono_thread_stop (MonoThread
*thread
)
3017 MonoInternalThread
*internal
= thread
->internal_thread
;
3019 if (!request_thread_abort (internal
, NULL
, FALSE
))
3022 if (internal
== mono_thread_internal_current ()) {
3024 self_abort_internal (error
);
3026 This function is part of the embeding API and has no way to return the exception
3027 to be thrown. So what we do is keep the old behavior and raise the exception.
3029 mono_error_raise_exception_deprecated (error
); /* OK to throw, see note */
3031 async_abort_internal (internal
, TRUE
);
3036 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr
)
3038 gint8 tmp
= *(volatile gint8
*)ptr
;
3039 mono_memory_barrier ();
3044 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr
)
3046 gint16 tmp
= *(volatile gint16
*)ptr
;
3047 mono_memory_barrier ();
3052 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr
)
3054 gint32 tmp
= *(volatile gint32
*)ptr
;
3055 mono_memory_barrier ();
3060 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr
)
3062 gint64 tmp
= *(volatile gint64
*)ptr
;
3063 mono_memory_barrier ();
3068 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr
)
3070 volatile void *tmp
= *(volatile void **)ptr
;
3071 mono_memory_barrier ();
3072 return (void *) tmp
;
3076 ves_icall_System_Threading_Thread_VolatileReadObject (void *ptr
)
3078 volatile MonoObject
*tmp
= *(volatile MonoObject
**)ptr
;
3079 mono_memory_barrier ();
3080 return (MonoObject
*) tmp
;
3084 ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr
)
3086 double tmp
= *(volatile double *)ptr
;
3087 mono_memory_barrier ();
3092 ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr
)
3094 float tmp
= *(volatile float *)ptr
;
3095 mono_memory_barrier ();
3100 ves_icall_System_Threading_Volatile_Read8 (void *ptr
)
3102 #if SIZEOF_VOID_P == 4
3103 if (G_UNLIKELY ((size_t)ptr
& 0x7)) {
3105 mono_interlocked_lock ();
3106 val
= *(gint64
*)ptr
;
3107 mono_interlocked_unlock ();
3111 return mono_atomic_load_i64 ((volatile gint64
*)ptr
);
3115 ves_icall_System_Threading_Volatile_ReadU8 (void *ptr
)
3117 #if SIZEOF_VOID_P == 4
3118 if (G_UNLIKELY ((size_t)ptr
& 0x7)) {
3120 mono_interlocked_lock ();
3121 val
= *(guint64
*)ptr
;
3122 mono_interlocked_unlock ();
3126 return (guint64
)mono_atomic_load_i64 ((volatile gint64
*)ptr
);
3130 ves_icall_System_Threading_Volatile_ReadDouble (void *ptr
)
3134 #if SIZEOF_VOID_P == 4
3135 if (G_UNLIKELY ((size_t)ptr
& 0x7)) {
3137 mono_interlocked_lock ();
3138 val
= *(double*)ptr
;
3139 mono_interlocked_unlock ();
3144 u
.ival
= mono_atomic_load_i64 ((volatile gint64
*)ptr
);
3150 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr
, gint8 value
)
3152 mono_memory_barrier ();
3153 *(volatile gint8
*)ptr
= value
;
3157 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr
, gint16 value
)
3159 mono_memory_barrier ();
3160 *(volatile gint16
*)ptr
= value
;
3164 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr
, gint32 value
)
3166 mono_memory_barrier ();
3167 *(volatile gint32
*)ptr
= value
;
3171 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr
, gint64 value
)
3173 mono_memory_barrier ();
3174 *(volatile gint64
*)ptr
= value
;
3178 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr
, void *value
)
3180 mono_memory_barrier ();
3181 *(volatile void **)ptr
= value
;
3185 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr
, MonoObject
*value
)
3187 mono_memory_barrier ();
3188 mono_gc_wbarrier_generic_store_internal (ptr
, value
);
3192 ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr
, double value
)
3194 mono_memory_barrier ();
3195 *(volatile double *)ptr
= value
;
3199 ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr
, float value
)
3201 mono_memory_barrier ();
3202 *(volatile float *)ptr
= value
;
3206 ves_icall_System_Threading_Volatile_Write8 (void *ptr
, gint64 value
)
3208 #if SIZEOF_VOID_P == 4
3209 if (G_UNLIKELY ((size_t)ptr
& 0x7)) {
3210 mono_interlocked_lock ();
3211 *(gint64
*)ptr
= value
;
3212 mono_interlocked_unlock ();
3217 mono_atomic_store_i64 ((volatile gint64
*)ptr
, value
);
3221 ves_icall_System_Threading_Volatile_WriteU8 (void *ptr
, guint64 value
)
3223 #if SIZEOF_VOID_P == 4
3224 if (G_UNLIKELY ((size_t)ptr
& 0x7)) {
3225 mono_interlocked_lock ();
3226 *(guint64
*)ptr
= value
;
3227 mono_interlocked_unlock ();
3232 mono_atomic_store_i64 ((volatile gint64
*)ptr
, (gint64
)value
);
3236 ves_icall_System_Threading_Volatile_WriteDouble (void *ptr
, double value
)
3240 #if SIZEOF_VOID_P == 4
3241 if (G_UNLIKELY ((size_t)ptr
& 0x7)) {
3242 mono_interlocked_lock ();
3243 *(double*)ptr
= value
;
3244 mono_interlocked_unlock ();
3251 mono_atomic_store_i64 ((volatile gint64
*)ptr
, u
.ival
);
3255 free_context (void *user_data
)
3257 ContextStaticData
*data
= (ContextStaticData
*)user_data
;
3259 mono_threads_lock ();
3262 * There is no guarantee that, by the point this reference queue callback
3263 * has been invoked, the GC handle associated with the object will fail to
3264 * resolve as one might expect. So if we don't free and remove the GC
3265 * handle here, free_context_static_data_helper () could end up resolving
3266 * a GC handle to an actually-dead context which would contain a pointer
3267 * to an already-freed static data segment, resulting in a crash when
3270 g_hash_table_remove (contexts
, GUINT_TO_POINTER (data
->gc_handle
));
3272 mono_threads_unlock ();
3274 mono_gchandle_free_internal (data
->gc_handle
);
3275 mono_free_static_data (data
->static_data
);
3280 mono_threads_register_app_context (MonoAppContextHandle ctx
, MonoError
*error
)
3283 mono_threads_lock ();
3285 //g_print ("Registering context %d in domain %d\n", ctx->context_id, ctx->domain_id);
3288 contexts
= g_hash_table_new (NULL
, NULL
);
3291 context_queue
= mono_gc_reference_queue_new_internal (free_context
);
3293 gpointer gch
= GUINT_TO_POINTER (mono_gchandle_new_weakref_from_handle (MONO_HANDLE_CAST (MonoObject
, ctx
)));
3294 g_hash_table_insert (contexts
, gch
, gch
);
3297 * We use this intermediate structure to contain a duplicate pointer to
3298 * the static data because we can't rely on being able to resolve the GC
3299 * handle in the reference queue callback.
3301 ContextStaticData
*data
= g_new0 (ContextStaticData
, 1);
3302 data
->gc_handle
= GPOINTER_TO_UINT (gch
);
3303 MONO_HANDLE_SETVAL (ctx
, data
, ContextStaticData
*, data
);
3305 context_adjust_static_data (ctx
);
3306 mono_gc_reference_queue_add_handle (context_queue
, ctx
, data
);
3308 mono_threads_unlock ();
3310 MONO_PROFILER_RAISE (context_loaded
, (MONO_HANDLE_RAW (ctx
)));
3313 #ifndef ENABLE_NETCORE
3315 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (MonoAppContextHandle ctx
, MonoError
*error
)
3317 mono_threads_register_app_context (ctx
, error
);
3322 mono_threads_release_app_context (MonoAppContext
* ctx
, MonoError
*error
)
3325 * NOTE: Since finalizers are unreliable for the purposes of ensuring
3326 * cleanup in exceptional circumstances, we don't actually do any
3327 * cleanup work here. We instead do this via a reference queue.
3330 //g_print ("Releasing context %d in domain %d\n", ctx->context_id, ctx->domain_id);
3332 MONO_PROFILER_RAISE (context_unloaded
, (ctx
));
3335 #ifndef ENABLE_NETCORE
3337 ves_icall_System_Runtime_Remoting_Contexts_Context_ReleaseContext (MonoAppContextHandle ctx
, MonoError
*error
)
3339 mono_threads_release_app_context (MONO_HANDLE_RAW (ctx
), error
); /* FIXME use handles in mono_threads_release_app_context */
3343 void mono_thread_init (MonoThreadStartCB start_cb
,
3344 MonoThreadAttachCB attach_cb
)
3346 mono_coop_mutex_init_recursive (&threads_mutex
);
3348 #if SIZEOF_VOID_P == 4
3349 mono_os_mutex_init (&interlocked_mutex
);
3351 mono_coop_mutex_init_recursive(&joinable_threads_mutex
);
3353 mono_os_event_init (&background_change_event
, FALSE
);
3355 mono_coop_cond_init (&pending_native_thread_join_calls_event
);
3356 mono_coop_cond_init (&zero_pending_joinable_thread_event
);
3358 mono_init_static_data_info (&thread_static_info
);
3359 mono_init_static_data_info (&context_static_info
);
3361 mono_thread_start_cb
= start_cb
;
3362 mono_thread_attach_cb
= attach_cb
;
3367 thread_attach (MonoThreadInfo
*info
)
3369 return mono_gc_thread_attach (info
);
3373 thread_detach (MonoThreadInfo
*info
)
3375 MonoInternalThread
*internal
;
3378 /* If a delegate is passed to native code and invoked on a thread we dont
3379 * know about, marshal will register it with mono_threads_attach_coop, but
3380 * we have no way of knowing when that thread goes away. SGen has a TSD
3381 * so we assume that if the domain is still registered, we can detach
3385 g_assert (mono_thread_info_is_current (info
));
3387 if (!mono_thread_info_try_get_internal_thread_gchandle (info
, &gchandle
))
3390 internal
= (MonoInternalThread
*) mono_gchandle_get_target_internal (gchandle
);
3391 g_assert (internal
);
3393 mono_thread_detach_internal (internal
);
3395 mono_gc_thread_detach (info
);
3399 thread_detach_with_lock (MonoThreadInfo
*info
)
3401 mono_gc_thread_detach_with_lock (info
);
3405 thread_in_critical_region (MonoThreadInfo
*info
)
3407 return mono_gc_thread_in_critical_region (info
);
3411 ip_in_critical_region (MonoDomain
*domain
, gpointer ip
)
3417 * We pass false for 'try_aot' so this becomes async safe.
3418 * It won't find aot methods whose jit info is not yet loaded,
3419 * so we preload their jit info in the JIT.
3421 ji
= mono_jit_info_table_find_internal (domain
, ip
, FALSE
, FALSE
);
3425 method
= mono_jit_info_get_method (ji
);
3428 return mono_gc_is_critical_method (method
);
3432 thread_flags_changing (MonoThreadInfoFlags old
, MonoThreadInfoFlags new_
)
3434 mono_gc_skip_thread_changing (!!(new_
& MONO_THREAD_INFO_FLAGS_NO_GC
));
3438 thread_flags_changed (MonoThreadInfoFlags old
, MonoThreadInfoFlags new_
)
3440 mono_gc_skip_thread_changed (!!(new_
& MONO_THREAD_INFO_FLAGS_NO_GC
));
3444 mono_thread_callbacks_init (void)
3446 MonoThreadInfoCallbacks cb
;
3448 memset (&cb
, 0, sizeof(cb
));
3449 cb
.thread_attach
= thread_attach
;
3450 cb
.thread_detach
= thread_detach
;
3451 cb
.thread_detach_with_lock
= thread_detach_with_lock
;
3452 cb
.ip_in_critical_region
= ip_in_critical_region
;
3453 cb
.thread_in_critical_region
= thread_in_critical_region
;
3454 cb
.thread_flags_changing
= thread_flags_changing
;
3455 cb
.thread_flags_changed
= thread_flags_changed
;
3456 mono_thread_info_callbacks_init (&cb
);
3460 * mono_thread_cleanup:
3463 mono_thread_cleanup (void)
3465 /* Wait for pending threads to park on joinable threads list */
3466 /* NOTE, waiting on this should be extremely rare and will only happen */
3467 /* under certain specific conditions. */
3468 gboolean wait_result
= threads_wait_pending_joinable_threads (2000);
3470 g_warning ("Waiting on threads to park on joinable thread list timed out.");
3472 mono_threads_join_threads ();
3474 #if !defined(HOST_WIN32)
3475 /* The main thread must abandon any held mutexes (particularly
3476 * important for named mutexes as they are shared across
3477 * processes, see bug 74680.) This will happen when the
3478 * thread exits, but if it's not running in a subthread it
3479 * won't exit in time.
3481 if (!mono_runtime_get_no_exec ())
3482 mono_w32mutex_abandon (mono_thread_internal_current ());
3486 /* This stuff needs more testing, it seems one of these
3487 * critical sections can be locked when mono_thread_cleanup is
3490 mono_coop_mutex_destroy (&threads_mutex
);
3491 mono_os_mutex_destroy (&interlocked_mutex
);
3492 mono_os_mutex_destroy (&delayed_free_table_mutex
);
3493 mono_os_mutex_destroy (&small_id_mutex
);
3494 mono_coop_cond_destroy (&zero_pending_joinable_thread_event
);
3495 mono_coop_cond_destroy (&pending_native_thread_join_calls_event
);
3496 mono_os_event_destroy (&background_change_event
);
3501 mono_threads_install_cleanup (MonoThreadCleanupFunc func
)
3503 mono_thread_cleanup_fn
= func
;
3507 * mono_thread_set_manage_callback:
3510 mono_thread_set_manage_callback (MonoThread
*thread
, MonoThreadManageCallback func
)
3512 thread
->internal_thread
->manage_callback
= func
;
3516 static void print_tids (gpointer key
, gpointer value
, gpointer user
)
3518 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
3519 * sizeof(uint) and a cast to uint would overflow
3521 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
3522 * print this as a pointer.
3524 g_message ("Waiting for: %p", key
);
3529 MonoThreadHandle
*handles
[MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
];
3530 MonoInternalThread
*threads
[MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
];
3535 wait_for_tids (struct wait_data
*wait
, guint32 timeout
, gboolean check_state_change
)
3538 MonoThreadInfoWaitRet ret
;
3540 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__
, wait
->num
));
3542 /* Add the thread state change event, so it wakes
3543 * up if a thread changes to background mode. */
3546 if (check_state_change
)
3547 ret
= mono_thread_info_wait_multiple_handle (wait
->handles
, wait
->num
, &background_change_event
, FALSE
, timeout
, TRUE
);
3549 ret
= mono_thread_info_wait_multiple_handle (wait
->handles
, wait
->num
, NULL
, TRUE
, timeout
, TRUE
);
3552 if (ret
== MONO_THREAD_INFO_WAIT_RET_FAILED
) {
3553 /* See the comment in build_wait_tids() */
3554 THREAD_DEBUG (g_message ("%s: Wait failed", __func__
));
3558 for( i
= 0; i
< wait
->num
; i
++)
3559 mono_threads_close_thread_handle (wait
->handles
[i
]);
3561 if (ret
>= MONO_THREAD_INFO_WAIT_RET_SUCCESS_0
&& ret
< (MONO_THREAD_INFO_WAIT_RET_SUCCESS_0
+ wait
->num
)) {
3562 MonoInternalThread
*internal
;
3564 internal
= wait
->threads
[ret
- MONO_THREAD_INFO_WAIT_RET_SUCCESS_0
];
3566 mono_threads_lock ();
3567 if (mono_g_hash_table_lookup (threads
, (gpointer
) internal
->tid
) == internal
)
3568 g_error ("%s: failed to call mono_thread_detach_internal on thread %p, InternalThread: %p", __func__
, internal
->tid
, internal
);
3569 mono_threads_unlock ();
3573 static void build_wait_tids (gpointer key
, gpointer value
, gpointer user
)
3575 struct wait_data
*wait
=(struct wait_data
*)user
;
3577 if(wait
->num
<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
- 1) {
3578 MonoInternalThread
*thread
=(MonoInternalThread
*)value
;
3580 /* Ignore background threads, we abort them later */
3581 /* Do not lock here since it is not needed and the caller holds threads_lock */
3582 if (thread
->state
& ThreadState_Background
) {
3583 THREAD_DEBUG (g_message ("%s: ignoring background thread %" G_GSIZE_FORMAT
, __func__
, (gsize
)thread
->tid
));
3584 return; /* just leave, ignore */
3587 if (mono_gc_is_finalizer_internal_thread (thread
)) {
3588 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %" G_GSIZE_FORMAT
, __func__
, (gsize
)thread
->tid
));
3592 if (thread
== mono_thread_internal_current ()) {
3593 THREAD_DEBUG (g_message ("%s: ignoring current thread %" G_GSIZE_FORMAT
, __func__
, (gsize
)thread
->tid
));
3597 if (mono_thread_get_main () && (thread
== mono_thread_get_main ()->internal_thread
)) {
3598 THREAD_DEBUG (g_message ("%s: ignoring main thread %" G_GSIZE_FORMAT
, __func__
, (gsize
)thread
->tid
));
3602 if (thread
->flags
& MONO_THREAD_FLAG_DONT_MANAGE
) {
3603 THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT
"with DONT_MANAGE flag set.", __func__
, (gsize
)thread
->tid
));
3607 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__
, thread
));
3608 if ((thread
->manage_callback
== NULL
) || (thread
->manage_callback (thread
->root_domain_thread
) == TRUE
)) {
3609 wait
->handles
[wait
->num
]=mono_threads_open_thread_handle (thread
->handle
);
3610 wait
->threads
[wait
->num
]=thread
;
3613 THREAD_DEBUG (g_message ("%s: adding thread %" G_GSIZE_FORMAT
, __func__
, (gsize
)thread
->tid
));
3615 THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %" G_GSIZE_FORMAT
, __func__
, (gsize
)thread
->tid
));
3620 /* Just ignore the rest, we can't do anything with
3627 abort_threads (gpointer key
, gpointer value
, gpointer user
)
3629 struct wait_data
*wait
=(struct wait_data
*)user
;
3630 MonoNativeThreadId self
= mono_native_thread_id_get ();
3631 MonoInternalThread
*thread
= (MonoInternalThread
*)value
;
3633 if (wait
->num
>= MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
)
3636 if (mono_native_thread_id_equals (thread_get_tid (thread
), self
))
3638 if (mono_gc_is_finalizer_internal_thread (thread
))
3641 if ((thread
->flags
& MONO_THREAD_FLAG_DONT_MANAGE
))
3644 wait
->handles
[wait
->num
] = mono_threads_open_thread_handle (thread
->handle
);
3645 wait
->threads
[wait
->num
] = thread
;
3648 THREAD_DEBUG (g_print ("%s: Aborting id: %" G_GSIZE_FORMAT
"\n", __func__
, (gsize
)thread
->tid
));
3649 mono_thread_internal_abort (thread
, FALSE
);
3653 * mono_threads_set_shutting_down:
3655 * Is called by a thread that wants to shut down Mono. If the runtime is already
3656 * shutting down, the calling thread is suspended/stopped, and this function never
3660 mono_threads_set_shutting_down (void)
3662 MonoInternalThread
*current_thread
= mono_thread_internal_current ();
3664 mono_threads_lock ();
3666 if (shutting_down
) {
3667 mono_threads_unlock ();
3669 /* Make sure we're properly suspended/stopped */
3671 LOCK_THREAD (current_thread
);
3673 if (current_thread
->state
& (ThreadState_SuspendRequested
| ThreadState_AbortRequested
)) {
3674 UNLOCK_THREAD (current_thread
);
3675 mono_thread_execute_interruption_void ();
3677 UNLOCK_THREAD (current_thread
);
3680 /*since we're killing the thread, detach it.*/
3681 mono_thread_detach_internal (current_thread
);
3683 /* Wake up other threads potentially waiting for us */
3684 mono_thread_info_exit (0);
3686 shutting_down
= TRUE
;
3688 /* Not really a background state change, but this will
3689 * interrupt the main thread if it is waiting for all
3690 * the other threads.
3693 mono_os_event_set (&background_change_event
);
3696 mono_threads_unlock ();
3701 * mono_thread_manage_internal:
3704 mono_thread_manage_internal (void)
3706 MONO_REQ_GC_UNSAFE_MODE
;
3708 struct wait_data wait_data
;
3709 struct wait_data
*wait
= &wait_data
;
3711 memset (wait
, 0, sizeof (struct wait_data
));
3712 /* join each thread that's still running */
3713 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__
));
3715 mono_threads_lock ();
3717 THREAD_DEBUG (g_message("%s: No threads", __func__
));
3718 mono_threads_unlock ();
3722 mono_threads_unlock ();
3725 mono_threads_lock ();
3726 if (shutting_down
) {
3727 /* somebody else is shutting down */
3728 mono_threads_unlock ();
3731 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__
, mono_g_hash_table_size (threads
));
3732 mono_g_hash_table_foreach (threads
, print_tids
, NULL
));
3735 mono_os_event_reset (&background_change_event
);
3738 /* We must zero all InternalThread pointers to avoid making the GC unhappy. */
3739 memset (wait
->threads
, 0, sizeof (wait
->threads
));
3740 mono_g_hash_table_foreach (threads
, build_wait_tids
, wait
);
3741 mono_threads_unlock ();
3743 /* Something to wait for */
3744 wait_for_tids (wait
, MONO_INFINITE_WAIT
, TRUE
);
3745 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__
, wait
->num
));
3746 } while(wait
->num
>0);
3748 /* Mono is shutting down, so just wait for the end */
3749 if (!mono_runtime_try_shutdown ()) {
3750 /*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
3751 mono_thread_suspend (mono_thread_internal_current ());
3752 mono_thread_execute_interruption_void ();
3755 #ifndef ENABLE_NETCORE
3757 * Under netcore, we don't abort any threads, just exit.
3758 * This is not a problem since we don't do runtime cleanup either.
3761 * Remove everything but the finalizer thread and self.
3762 * Also abort all the background threads
3765 mono_threads_lock ();
3768 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3769 memset (wait
->threads
, 0, sizeof (wait
->threads
));
3770 mono_g_hash_table_foreach (threads
, abort_threads
, wait
);
3772 mono_threads_unlock ();
3774 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__
, wait
->num
));
3775 if (wait
->num
> 0) {
3776 /* Something to wait for */
3777 wait_for_tids (wait
, MONO_INFINITE_WAIT
, FALSE
);
3779 } while (wait
->num
> 0);
3783 * give the subthreads a chance to really quit (this is mainly needed
3784 * to get correct user and system times from getrusage/wait/time(1)).
3785 * This could be removed if we avoid pthread_detach() and use pthread_join().
3787 mono_thread_info_yield ();
3790 #ifndef ENABLE_NETCORE
3792 collect_threads_for_suspend (gpointer key
, gpointer value
, gpointer user_data
)
3794 MonoInternalThread
*thread
= (MonoInternalThread
*)value
;
3795 struct wait_data
*wait
= (struct wait_data
*)user_data
;
3798 * We try to exclude threads early, to avoid running into the MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
3800 * This needs no locking.
3802 if ((thread
->state
& ThreadState_Suspended
) != 0 ||
3803 (thread
->state
& ThreadState_Stopped
) != 0)
3806 if (wait
->num
<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
) {
3807 wait
->handles
[wait
->num
] = mono_threads_open_thread_handle (thread
->handle
);
3808 wait
->threads
[wait
->num
] = thread
;
3814 * mono_thread_suspend_all_other_threads:
3816 * Suspend all managed threads except the finalizer thread and this thread. It is
3817 * not possible to resume them later.
3819 void mono_thread_suspend_all_other_threads (void)
3821 struct wait_data wait_data
;
3822 struct wait_data
*wait
= &wait_data
;
3824 MonoNativeThreadId self
= mono_native_thread_id_get ();
3825 guint32 eventidx
= 0;
3826 gboolean starting
, finished
;
3828 memset (wait
, 0, sizeof (struct wait_data
));
3830 * The other threads could be in an arbitrary state at this point, i.e.
3831 * they could be starting up, shutting down etc. This means that there could be
3832 * threads which are not even in the threads hash table yet.
3836 * First we set a barrier which will be checked by all threads before they
3837 * are added to the threads hash table, and they will exit if the flag is set.
3838 * This ensures that no threads could be added to the hash later.
3839 * We will use shutting_down as the barrier for now.
3841 g_assert (shutting_down
);
3844 * We make multiple calls to WaitForMultipleObjects since:
3845 * - we can only wait for MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS threads
3846 * - some threads could exit without becoming suspended
3851 * Make a copy of the hashtable since we can't do anything with
3852 * threads while threads_mutex is held.
3855 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3856 memset (wait
->threads
, 0, sizeof (wait
->threads
));
3857 mono_threads_lock ();
3858 mono_g_hash_table_foreach (threads
, collect_threads_for_suspend
, wait
);
3859 mono_threads_unlock ();
3862 /* Get the suspended events that we'll be waiting for */
3863 for (i
= 0; i
< wait
->num
; ++i
) {
3864 MonoInternalThread
*thread
= wait
->threads
[i
];
3866 if (mono_native_thread_id_equals (thread_get_tid (thread
), self
)
3867 || mono_gc_is_finalizer_internal_thread (thread
)
3868 || (thread
->flags
& MONO_THREAD_FLAG_DONT_MANAGE
)
3870 mono_threads_close_thread_handle (wait
->handles
[i
]);
3871 wait
->threads
[i
] = NULL
;
3875 LOCK_THREAD (thread
);
3877 if (thread
->state
& (ThreadState_Suspended
| ThreadState_Stopped
)) {
3878 UNLOCK_THREAD (thread
);
3879 mono_threads_close_thread_handle (wait
->handles
[i
]);
3880 wait
->threads
[i
] = NULL
;
3886 /* Convert abort requests into suspend requests */
3887 if ((thread
->state
& ThreadState_AbortRequested
) != 0)
3888 thread
->state
&= ~ThreadState_AbortRequested
;
3890 thread
->state
|= ThreadState_SuspendRequested
;
3892 mono_os_event_reset (thread
->suspended
);
3895 /* Signal the thread to suspend + calls UNLOCK_THREAD (thread) */
3896 async_suspend_internal (thread
, TRUE
);
3898 mono_threads_close_thread_handle (wait
->handles
[i
]);
3899 wait
->threads
[i
] = NULL
;
3901 if (eventidx
<= 0) {
3903 * If there are threads which are starting up, we wait until they
3904 * are suspended when they try to register in the threads hash.
3905 * This is guaranteed to finish, since the threads which can create new
3906 * threads get suspended after a while.
3907 * FIXME: The finalizer thread can still create new threads.
3909 mono_threads_lock ();
3910 if (threads_starting_up
)
3911 starting
= mono_g_hash_table_size (threads_starting_up
) > 0;
3914 mono_threads_unlock ();
3916 mono_thread_info_sleep (100, NULL
);
3925 MonoInternalThread
*thread
;
3926 MonoStackFrameInfo
*frames
;
3927 int nframes
, max_frames
;
3928 int nthreads
, max_threads
;
3929 MonoInternalThread
**threads
;
3930 } ThreadDumpUserData
;
3932 static gboolean thread_dump_requested
;
3934 /* This needs to be async safe */
3936 collect_frame (MonoStackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
3938 ThreadDumpUserData
*ud
= (ThreadDumpUserData
*)data
;
3940 if (ud
->nframes
< ud
->max_frames
) {
3941 memcpy (&ud
->frames
[ud
->nframes
], frame
, sizeof (MonoStackFrameInfo
));
3948 /* This needs to be async safe */
3949 static SuspendThreadResult
3950 get_thread_dump (MonoThreadInfo
*info
, gpointer ud
)
3952 ThreadDumpUserData
*user_data
= (ThreadDumpUserData
*)ud
;
3953 MonoInternalThread
*thread
= user_data
->thread
;
3956 /* This no longer works with remote unwinding */
3957 g_string_append_printf (text
, " tid=0x%p this=0x%p ", (gpointer
)(gsize
)thread
->tid
, thread
);
3958 mono_thread_internal_describe (thread
, text
);
3959 g_string_append (text
, "\n");
3962 if (thread
== mono_thread_internal_current ())
3963 mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (collect_frame
, NULL
, MONO_UNWIND_SIGNAL_SAFE
, ud
);
3965 mono_get_eh_callbacks ()->mono_walk_stack_with_state (collect_frame
, mono_thread_info_get_suspend_state (info
), MONO_UNWIND_SIGNAL_SAFE
, ud
);
3967 return MonoResumeThread
;
3971 int nthreads
, max_threads
;
3974 } CollectThreadsUserData
;
3977 int nthreads
, max_threads
;
3978 MonoNativeThreadId
*threads
;
3979 } CollectThreadIdsUserData
;
3982 collect_thread (gpointer key
, gpointer value
, gpointer user
)
3984 CollectThreadsUserData
*ud
= (CollectThreadsUserData
*)user
;
3985 MonoInternalThread
*thread
= (MonoInternalThread
*)value
;
3987 if (ud
->nthreads
< ud
->max_threads
)
3988 ud
->threads
[ud
->nthreads
++] = mono_gchandle_new_internal (&thread
->obj
, TRUE
);
3992 * Collect running threads into the THREADS array.
3993 * THREADS should be an array allocated on the stack.
3996 collect_threads (guint32
*thread_handles
, int max_threads
)
3998 CollectThreadsUserData ud
;
4000 mono_memory_barrier ();
4004 memset (&ud
, 0, sizeof (ud
));
4005 /* This array contains refs, but its on the stack, so its ok */
4006 ud
.threads
= thread_handles
;
4007 ud
.max_threads
= max_threads
;
4009 mono_threads_lock ();
4010 mono_g_hash_table_foreach (threads
, collect_thread
, &ud
);
4011 mono_threads_unlock ();
4017 mono_gstring_append_thread_name (GString
* text
, MonoInternalThread
* thread
)
4019 g_string_append (text
, "\n\"");
4020 char const * const name
= thread
->name
.chars
;
4021 g_string_append (text
, name
? name
:
4022 thread
->threadpool_thread
? "<threadpool thread>" :
4023 "<unnamed thread>");
4024 g_string_append (text
, "\"");
4028 dump_thread (MonoInternalThread
*thread
, ThreadDumpUserData
*ud
, FILE* output_file
)
4030 GString
* text
= g_string_new (0);
4033 ud
->thread
= thread
;
4036 /* Collect frames for the thread */
4037 if (thread
== mono_thread_internal_current ()) {
4038 get_thread_dump (mono_thread_info_current (), ud
);
4040 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread
), FALSE
, get_thread_dump
, ud
);
4044 * Do all the non async-safe work outside of get_thread_dump.
4046 mono_gstring_append_thread_name (text
, thread
);
4048 for (i
= 0; i
< ud
->nframes
; ++i
) {
4049 MonoStackFrameInfo
*frame
= &ud
->frames
[i
];
4050 MonoMethod
*method
= NULL
;
4052 if (frame
->type
== FRAME_TYPE_MANAGED
)
4053 method
= mono_jit_info_get_method (frame
->ji
);
4056 gchar
*location
= mono_debug_print_stack_frame (method
, frame
->native_offset
, frame
->domain
);
4057 g_string_append_printf (text
, " %s\n", location
);
4060 g_string_append_printf (text
, " at <unknown> <0x%05x>\n", frame
->native_offset
);
4064 g_fprintf (output_file
, "%s", text
->str
);
4066 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
4067 OutputDebugStringA(text
->str
);
4070 g_string_free (text
, TRUE
);
4071 fflush (output_file
);
4075 mono_get_time_of_day (struct timeval
*tv
) {
4079 tv
->tv_sec
= time
.time
;
4080 tv
->tv_usec
= time
.millitm
* 1000;
4082 if (gettimeofday (tv
, NULL
) == -1) {
4083 g_error ("gettimeofday() failed; errno is %d (%s)", errno
, strerror (errno
));
4089 mono_local_time (const struct timeval
*tv
, struct tm
*tm
) {
4090 #ifdef HAVE_LOCALTIME_R
4091 localtime_r(&tv
->tv_sec
, tm
);
4093 time_t const tv_sec
= tv
->tv_sec
; // Copy due to Win32/Posix contradiction.
4094 *tm
= *localtime (&tv_sec
);
4099 mono_threads_perform_thread_dump (void)
4101 FILE* output_file
= NULL
;
4102 ThreadDumpUserData ud
;
4103 guint32 thread_array
[128];
4104 int tindex
, nthreads
;
4106 if (!thread_dump_requested
)
4109 if (thread_dump_dir
!= NULL
) {
4110 GString
* path
= g_string_new (0);
4115 mono_get_time_of_day (&tv
);
4116 mono_local_time(&tv
, &tod
);
4117 strftime(time_str
, sizeof(time_str
), MONO_STRFTIME_F
"_" MONO_STRFTIME_T
, &tod
);
4118 ms
= tv
.tv_usec
/ 1000;
4119 g_string_append_printf (path
, "%s/%s.%03ld.tdump", thread_dump_dir
, time_str
, ms
);
4120 output_file
= fopen (path
->str
, "w");
4121 g_string_free (path
, TRUE
);
4123 if (output_file
== NULL
) {
4124 g_print ("Full thread dump:\n");
4127 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
4128 nthreads
= collect_threads (thread_array
, 128);
4130 memset (&ud
, 0, sizeof (ud
));
4131 ud
.frames
= g_new0 (MonoStackFrameInfo
, 256);
4132 ud
.max_frames
= 256;
4134 for (tindex
= 0; tindex
< nthreads
; ++tindex
) {
4135 guint32 handle
= thread_array
[tindex
];
4136 MonoInternalThread
*thread
= (MonoInternalThread
*) mono_gchandle_get_target_internal (handle
);
4137 dump_thread (thread
, &ud
, output_file
!= NULL
? output_file
: stdout
);
4138 mono_gchandle_free_internal (handle
);
4141 if (output_file
!= NULL
) {
4142 fclose (output_file
);
4146 thread_dump_requested
= FALSE
;
4149 #ifndef ENABLE_NETCORE
4150 /* Obtain the thread dump of all threads */
4152 ves_icall_System_Threading_Thread_GetStackTraces (MonoArrayHandleOut out_threads_handle
, MonoArrayHandleOut out_stack_frames_handle
, MonoError
*error
)
4154 MONO_HANDLE_ASSIGN_RAW (out_threads_handle
, NULL
);
4155 MONO_HANDLE_ASSIGN_RAW (out_stack_frames_handle
, NULL
);
4159 MonoStackFrameHandle stack_frame_handle
= MONO_HANDLE_NEW (MonoStackFrame
, NULL
);
4160 MonoReflectionMethodHandle reflection_method_handle
= MONO_HANDLE_NEW (MonoReflectionMethod
, NULL
);
4161 MonoStringHandle filename_handle
= MONO_HANDLE_NEW (MonoString
, NULL
);
4162 MonoArrayHandle thread_frames_handle
= MONO_HANDLE_NEW (MonoArray
, NULL
);
4164 ThreadDumpUserData ud
;
4165 guint32 thread_array
[128];
4166 MonoDomain
*domain
= mono_domain_get ();
4167 MonoDebugSourceLocation
*location
;
4168 int tindex
, nthreads
;
4170 MonoArray
* out_threads
= NULL
;
4171 MonoArray
* out_stack_frames
= NULL
;
4173 MONO_HANDLE_ASSIGN_RAW (out_threads_handle
, NULL
);
4174 MONO_HANDLE_ASSIGN_RAW (out_stack_frames_handle
, NULL
);
4176 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
4177 nthreads
= collect_threads (thread_array
, 128);
4179 memset (&ud
, 0, sizeof (ud
));
4180 ud
.frames
= g_new0 (MonoStackFrameInfo
, 256);
4181 ud
.max_frames
= 256;
4183 out_threads
= mono_array_new_checked (domain
, mono_defaults
.thread_class
, nthreads
, error
);
4184 goto_if_nok (error
, leave
);
4185 MONO_HANDLE_ASSIGN_RAW (out_threads_handle
, out_threads
);
4186 out_stack_frames
= mono_array_new_checked (domain
, mono_defaults
.array_class
, nthreads
, error
);
4187 goto_if_nok (error
, leave
);
4188 MONO_HANDLE_ASSIGN_RAW (out_stack_frames_handle
, out_stack_frames
);
4190 for (tindex
= 0; tindex
< nthreads
; ++tindex
) {
4192 mono_gchandle_free_internal (handle
);
4193 handle
= thread_array
[tindex
];
4194 MonoInternalThread
*thread
= (MonoInternalThread
*) mono_gchandle_get_target_internal (handle
);
4196 MonoArray
*thread_frames
;
4202 /* Collect frames for the thread */
4203 if (thread
== mono_thread_internal_current ()) {
4204 get_thread_dump (mono_thread_info_current (), &ud
);
4206 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread
), FALSE
, get_thread_dump
, &ud
);
4209 mono_array_setref_fast (out_threads
, tindex
, mono_thread_current_for_thread (thread
));
4211 thread_frames
= mono_array_new_checked (domain
, mono_defaults
.stack_frame_class
, ud
.nframes
, error
);
4212 MONO_HANDLE_ASSIGN_RAW (thread_frames_handle
, thread_frames
);
4213 goto_if_nok (error
, leave
);
4214 mono_array_setref_fast (out_stack_frames
, tindex
, thread_frames
);
4216 for (i
= 0; i
< ud
.nframes
; ++i
) {
4217 MonoStackFrameInfo
*frame
= &ud
.frames
[i
];
4218 MonoMethod
*method
= NULL
;
4219 MonoStackFrame
*sf
= (MonoStackFrame
*)mono_object_new_checked (domain
, mono_defaults
.stack_frame_class
, error
);
4220 MONO_HANDLE_ASSIGN_RAW (stack_frame_handle
, sf
);
4221 goto_if_nok (error
, leave
);
4223 sf
->native_offset
= frame
->native_offset
;
4225 if (frame
->type
== FRAME_TYPE_MANAGED
)
4226 method
= mono_jit_info_get_method (frame
->ji
);
4229 sf
->method_address
= (gsize
) frame
->ji
->code_start
;
4231 MonoReflectionMethod
*rm
= mono_method_get_object_checked (domain
, method
, NULL
, error
);
4232 MONO_HANDLE_ASSIGN_RAW (reflection_method_handle
, rm
);
4233 goto_if_nok (error
, leave
);
4234 MONO_OBJECT_SETREF_INTERNAL (sf
, method
, rm
);
4236 location
= mono_debug_lookup_source_location (method
, frame
->native_offset
, domain
);
4238 sf
->il_offset
= location
->il_offset
;
4240 if (location
->source_file
) {
4241 MonoString
*filename
= mono_string_new_checked (domain
, location
->source_file
, error
);
4242 MONO_HANDLE_ASSIGN_RAW (filename_handle
, filename
);
4243 goto_if_nok (error
, leave
);
4244 MONO_OBJECT_SETREF_INTERNAL (sf
, filename
, filename
);
4245 sf
->line
= location
->row
;
4246 sf
->column
= location
->column
;
4248 mono_debug_free_source_location (location
);
4253 mono_array_setref_internal (thread_frames
, i
, sf
);
4256 mono_gchandle_free_internal (handle
);
4261 mono_gchandle_free_internal (handle
);
4267 * mono_threads_request_thread_dump:
4269 * Ask all threads except the current to print their stacktrace to stdout.
4272 mono_threads_request_thread_dump (void)
4274 /*The new thread dump code runs out of the finalizer thread. */
4275 thread_dump_requested
= TRUE
;
4276 mono_gc_finalize_notify ();
4281 gint allocated
; /* +1 so that refs [allocated] == NULL */
4285 typedef struct ref_stack RefStack
;
4288 ref_stack_new (gint initial_size
)
4292 initial_size
= MAX (initial_size
, 16) + 1;
4293 rs
= g_new0 (RefStack
, 1);
4294 rs
->refs
= g_new0 (gpointer
, initial_size
);
4295 rs
->allocated
= initial_size
;
4300 ref_stack_destroy (gpointer ptr
)
4302 RefStack
*rs
= (RefStack
*)ptr
;
4311 ref_stack_push (RefStack
*rs
, gpointer ptr
)
4313 g_assert (rs
!= NULL
);
4315 if (rs
->bottom
>= rs
->allocated
) {
4316 rs
->refs
= (void **)g_realloc (rs
->refs
, rs
->allocated
* 2 * sizeof (gpointer
) + 1);
4317 rs
->allocated
<<= 1;
4318 rs
->refs
[rs
->allocated
] = NULL
;
4320 rs
->refs
[rs
->bottom
++] = ptr
;
4324 ref_stack_pop (RefStack
*rs
)
4326 if (rs
== NULL
|| rs
->bottom
== 0)
4330 rs
->refs
[rs
->bottom
] = NULL
;
4334 ref_stack_find (RefStack
*rs
, gpointer ptr
)
4341 for (refs
= rs
->refs
; refs
&& *refs
; refs
++) {
4349 * mono_thread_push_appdomain_ref:
4351 * Register that the current thread may have references to objects in domain
4352 * @domain on its stack. Each call to this function should be paired with a
4353 * call to pop_appdomain_ref.
4356 mono_thread_push_appdomain_ref (MonoDomain
*domain
)
4358 MonoInternalThread
*thread
= mono_thread_internal_current ();
4361 /* printf ("PUSH REF: %" G_GSIZE_FORMAT " -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
4362 SPIN_LOCK (thread
->lock_thread_id
);
4363 if (thread
->appdomain_refs
== NULL
)
4364 thread
->appdomain_refs
= ref_stack_new (16);
4365 ref_stack_push ((RefStack
*)thread
->appdomain_refs
, domain
);
4366 SPIN_UNLOCK (thread
->lock_thread_id
);
4371 mono_thread_pop_appdomain_ref (void)
4373 MonoInternalThread
*thread
= mono_thread_internal_current ();
4376 /* printf ("POP REF: %" G_GSIZE_FORMAT " -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
4377 SPIN_LOCK (thread
->lock_thread_id
);
4378 ref_stack_pop ((RefStack
*)thread
->appdomain_refs
);
4379 SPIN_UNLOCK (thread
->lock_thread_id
);
4384 mono_thread_internal_has_appdomain_ref (MonoInternalThread
*thread
, MonoDomain
*domain
)
4387 SPIN_LOCK (thread
->lock_thread_id
);
4388 res
= ref_stack_find ((RefStack
*)thread
->appdomain_refs
, domain
);
4389 SPIN_UNLOCK (thread
->lock_thread_id
);
4394 mono_thread_has_appdomain_ref (MonoThread
*thread
, MonoDomain
*domain
)
4396 return mono_thread_internal_has_appdomain_ref (thread
->internal_thread
, domain
);
4399 typedef struct abort_appdomain_data
{
4400 struct wait_data wait
;
4402 } abort_appdomain_data
;
4405 collect_appdomain_thread (gpointer key
, gpointer value
, gpointer user_data
)
4407 MonoInternalThread
*thread
= (MonoInternalThread
*)value
;
4408 abort_appdomain_data
*data
= (abort_appdomain_data
*)user_data
;
4409 MonoDomain
*domain
= data
->domain
;
4411 if (mono_thread_internal_has_appdomain_ref (thread
, domain
)) {
4412 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
4414 if(data
->wait
.num
<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
) {
4415 data
->wait
.handles
[data
->wait
.num
] = mono_threads_open_thread_handle (thread
->handle
);
4416 data
->wait
.threads
[data
->wait
.num
] = thread
;
4419 /* Just ignore the rest, we can't do anything with
4427 * mono_threads_abort_appdomain_threads:
4429 * Abort threads which has references to the given appdomain.
4432 mono_threads_abort_appdomain_threads (MonoDomain
*domain
, int timeout
)
4434 abort_appdomain_data user_data
;
4436 int orig_timeout
= timeout
;
4439 THREAD_DEBUG (g_message ("%s: starting abort", __func__
));
4441 start_time
= mono_msec_ticks ();
4443 mono_threads_lock ();
4445 user_data
.domain
= domain
;
4446 user_data
.wait
.num
= 0;
4447 /* This shouldn't take any locks */
4448 mono_g_hash_table_foreach (threads
, collect_appdomain_thread
, &user_data
);
4449 mono_threads_unlock ();
4451 if (user_data
.wait
.num
> 0) {
4452 /* Abort the threads outside the threads lock */
4453 for (i
= 0; i
< user_data
.wait
.num
; ++i
)
4454 mono_thread_internal_abort (user_data
.wait
.threads
[i
], TRUE
);
4457 * We should wait for the threads either to abort, or to leave the
4458 * domain. We can't do the latter, so we wait with a timeout.
4460 wait_for_tids (&user_data
.wait
, 100, FALSE
);
4463 /* Update remaining time */
4464 timeout
-= mono_msec_ticks () - start_time
;
4465 start_time
= mono_msec_ticks ();
4467 if (orig_timeout
!= -1 && timeout
< 0)
4470 while (user_data
.wait
.num
> 0);
4472 THREAD_DEBUG (g_message ("%s: abort done", __func__
));
4477 /* This is a JIT icall. This icall is called from a finally block when
4478 * mono_install_handler_block_guard called by another thread has flipped the
4479 * finally block's exvar (see mono_find_exvar_for_offset). In that case, if
4480 * the finally is in an abort protected block, we must defer the abort
4481 * exception until we leave the abort protected block. Otherwise we proceed
4482 * with a synchronous self-abort.
4485 ves_icall_thread_finish_async_abort (void)
4487 /* We were called from the handler block and are about to
4488 * leave it. (If we end up postponing the abort because we're
4489 * in an abort protected block, the unwinder won't run and
4490 * won't clear the handler block itself which will confuse the
4491 * unwinder if we're in a try {} catch {} and we throw again.
4493 * static Constructor () {
4497 * icall (); // Thread.Abort landed here,
4498 * // and caused the handler block to be installed
4500 * ves_icall_thread_finish_async_abort (); // we're here
4504 * // unwinder will get confused here and synthesize a self abort
4508 * More interestingly, this doesn't only happen with icalls - a JIT
4509 * trampoline is native code that will cause a handler to be installed.
4510 * So the above situation can happen with any code in a "finally"
4513 mono_get_eh_callbacks ()->mono_uninstall_current_handler_block_guard ();
4514 /* Just set the async interruption requested bit. Rely on the icall
4515 * wrapper of this icall to process the thread interruption, respecting
4516 * any abort protection blocks in our call stack.
4518 mono_thread_set_self_interruption_respect_abort_prot ();
4522 * mono_thread_get_undeniable_exception:
4524 * Return an exception which needs to be raised when leaving a catch clause.
4525 * This is used for undeniable exception propagation.
4528 mono_thread_get_undeniable_exception (void)
4530 MonoInternalThread
*thread
= mono_thread_internal_current ();
4532 if (!(thread
&& thread
->abort_exc
&& !is_running_protected_wrapper ()))
4535 // We don't want to have our exception effect calls made by
4536 // the catching block
4538 if (!mono_get_eh_callbacks ()->mono_above_abort_threshold ())
4542 * FIXME: Clear the abort exception and return an AppDomainUnloaded
4543 * exception if the thread no longer references a dying appdomain.
4545 thread
->abort_exc
->trace_ips
= NULL
;
4546 thread
->abort_exc
->stack_trace
= NULL
;
4547 return thread
->abort_exc
;
4550 #if MONO_SMALL_CONFIG
4551 #define NUM_STATIC_DATA_IDX 4
4552 static const int static_data_size
[NUM_STATIC_DATA_IDX
] = {
4556 #define NUM_STATIC_DATA_IDX 8
4557 static const int static_data_size
[NUM_STATIC_DATA_IDX
] = {
4558 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
4562 static MonoBitSet
*thread_reference_bitmaps
[NUM_STATIC_DATA_IDX
];
4563 static MonoBitSet
*context_reference_bitmaps
[NUM_STATIC_DATA_IDX
];
4566 mark_slots (void *addr
, MonoBitSet
**bitmaps
, MonoGCMarkFunc mark_func
, void *gc_data
)
4568 gpointer
*static_data
= (gpointer
*)addr
;
4570 for (int i
= 0; i
< NUM_STATIC_DATA_IDX
; ++i
) {
4571 void **ptr
= (void **)static_data
[i
];
4576 MONO_BITSET_FOREACH (bitmaps
[i
], idx
, {
4577 void **p
= ptr
+ idx
;
4580 mark_func ((MonoObject
**)p
, gc_data
);
4586 mark_tls_slots (void *addr
, MonoGCMarkFunc mark_func
, void *gc_data
)
4588 mark_slots (addr
, thread_reference_bitmaps
, mark_func
, gc_data
);
4592 mark_ctx_slots (void *addr
, MonoGCMarkFunc mark_func
, void *gc_data
)
4594 mark_slots (addr
, context_reference_bitmaps
, mark_func
, gc_data
);
4598 * mono_alloc_static_data
4600 * Allocate memory blocks for storing threads or context static data
4603 mono_alloc_static_data (gpointer
**static_data_ptr
, guint32 offset
, void *alloc_key
, gboolean threadlocal
)
4605 guint idx
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, index
);
4608 gpointer
* static_data
= *static_data_ptr
;
4610 static MonoGCDescriptor tls_desc
= MONO_GC_DESCRIPTOR_NULL
;
4611 static MonoGCDescriptor ctx_desc
= MONO_GC_DESCRIPTOR_NULL
;
4613 if (mono_gc_user_markers_supported ()) {
4614 if (tls_desc
== MONO_GC_DESCRIPTOR_NULL
)
4615 tls_desc
= mono_gc_make_root_descr_user (mark_tls_slots
);
4617 if (ctx_desc
== MONO_GC_DESCRIPTOR_NULL
)
4618 ctx_desc
= mono_gc_make_root_descr_user (mark_ctx_slots
);
4621 static_data
= (void **)mono_gc_alloc_fixed (static_data_size
[0], threadlocal
? tls_desc
: ctx_desc
,
4622 threadlocal
? MONO_ROOT_SOURCE_THREAD_STATIC
: MONO_ROOT_SOURCE_CONTEXT_STATIC
,
4624 threadlocal
? "ThreadStatic Fields" : "ContextStatic Fields");
4625 *static_data_ptr
= static_data
;
4626 static_data
[0] = static_data
;
4629 for (i
= 1; i
<= idx
; ++i
) {
4630 if (static_data
[i
])
4633 if (mono_gc_user_markers_supported ())
4634 static_data
[i
] = g_malloc0 (static_data_size
[i
]);
4636 static_data
[i
] = mono_gc_alloc_fixed (static_data_size
[i
], MONO_GC_DESCRIPTOR_NULL
,
4637 threadlocal
? MONO_ROOT_SOURCE_THREAD_STATIC
: MONO_ROOT_SOURCE_CONTEXT_STATIC
,
4639 threadlocal
? "ThreadStatic Fields" : "ContextStatic Fields");
4644 mono_free_static_data (gpointer
* static_data
)
4647 for (i
= 1; i
< NUM_STATIC_DATA_IDX
; ++i
) {
4648 gpointer p
= static_data
[i
];
4652 * At this point, the static data pointer array is still registered with the
4653 * GC, so must ensure that mark_tls_slots() will not encounter any invalid
4654 * data. Freeing the individual arrays without first nulling their slots
4655 * would make it possible for mark_tls/ctx_slots() to encounter a pointer to
4656 * such an already freed array. See bug #13813.
4658 static_data
[i
] = NULL
;
4659 mono_memory_write_barrier ();
4660 if (mono_gc_user_markers_supported ())
4663 mono_gc_free_fixed (p
);
4665 mono_gc_free_fixed (static_data
);
4669 * mono_init_static_data_info
4671 * Initializes static data counters
4673 static void mono_init_static_data_info (StaticDataInfo
*static_data
)
4675 static_data
->idx
= 0;
4676 static_data
->offset
= 0;
4677 static_data
->freelist
= NULL
;
4681 * mono_alloc_static_data_slot
4683 * Generates an offset for static data. static_data contains the counters
4684 * used to generate it.
4687 mono_alloc_static_data_slot (StaticDataInfo
*static_data
, guint32 size
, guint32 align
)
4689 if (!static_data
->idx
&& !static_data
->offset
) {
4691 * we use the first chunk of the first allocation also as
4692 * an array for the rest of the data
4694 static_data
->offset
= sizeof (gpointer
) * NUM_STATIC_DATA_IDX
;
4696 static_data
->offset
+= align
- 1;
4697 static_data
->offset
&= ~(align
- 1);
4698 if (static_data
->offset
+ size
>= static_data_size
[static_data
->idx
]) {
4699 static_data
->idx
++;
4700 g_assert (size
<= static_data_size
[static_data
->idx
]);
4701 g_assert (static_data
->idx
< NUM_STATIC_DATA_IDX
);
4702 static_data
->offset
= 0;
4704 guint32 offset
= MAKE_SPECIAL_STATIC_OFFSET (static_data
->idx
, static_data
->offset
, 0);
4705 static_data
->offset
+= size
;
4710 * LOCKING: requires that threads_mutex is held
4713 context_adjust_static_data (MonoAppContextHandle ctx_handle
)
4715 MonoAppContext
*ctx
= MONO_HANDLE_RAW (ctx_handle
);
4716 if (context_static_info
.offset
|| context_static_info
.idx
> 0) {
4717 guint32 offset
= MAKE_SPECIAL_STATIC_OFFSET (context_static_info
.idx
, context_static_info
.offset
, 0);
4718 mono_alloc_static_data (&ctx
->static_data
, offset
, ctx
, FALSE
);
4719 ctx
->data
->static_data
= ctx
->static_data
;
4724 * LOCKING: requires that threads_mutex is held
4727 alloc_thread_static_data_helper (gpointer key
, gpointer value
, gpointer user
)
4729 MonoInternalThread
*thread
= (MonoInternalThread
*)value
;
4730 guint32 offset
= GPOINTER_TO_UINT (user
);
4732 mono_alloc_static_data (&(thread
->static_data
), offset
, (void *) MONO_UINT_TO_NATIVE_THREAD_ID (thread
->tid
), TRUE
);
4736 * LOCKING: requires that threads_mutex is held
4739 alloc_context_static_data_helper (gpointer key
, gpointer value
, gpointer user
)
4741 MonoAppContext
*ctx
= (MonoAppContext
*) mono_gchandle_get_target_internal (GPOINTER_TO_INT (key
));
4746 guint32 offset
= GPOINTER_TO_UINT (user
);
4747 mono_alloc_static_data (&ctx
->static_data
, offset
, ctx
, FALSE
);
4748 ctx
->data
->static_data
= ctx
->static_data
;
4751 static StaticDataFreeList
*
4752 search_slot_in_freelist (StaticDataInfo
*static_data
, guint32 size
, guint32 align
)
4754 StaticDataFreeList
* prev
= NULL
;
4755 StaticDataFreeList
* tmp
= static_data
->freelist
;
4757 if (tmp
->size
== size
) {
4759 prev
->next
= tmp
->next
;
4761 static_data
->freelist
= tmp
->next
;
4770 #if SIZEOF_VOID_P == 4
4777 update_reference_bitmap (MonoBitSet
**sets
, guint32 offset
, uintptr_t *bitmap
, int numbits
)
4779 int idx
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, index
);
4781 sets
[idx
] = mono_bitset_new (static_data_size
[idx
] / sizeof (uintptr_t), 0);
4782 MonoBitSet
*rb
= sets
[idx
];
4783 offset
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, offset
);
4784 offset
/= sizeof (uintptr_t);
4785 /* offset is now the bitmap offset */
4786 for (int i
= 0; i
< numbits
; ++i
) {
4787 if (bitmap
[i
/ sizeof (uintptr_t)] & (ONE_P
<< (i
& (sizeof (uintptr_t) * 8 -1))))
4788 mono_bitset_set_fast (rb
, offset
+ i
);
4793 clear_reference_bitmap (MonoBitSet
**sets
, guint32 offset
, guint32 size
)
4795 int idx
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, index
);
4796 MonoBitSet
*rb
= sets
[idx
];
4797 offset
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, offset
);
4798 offset
/= sizeof (uintptr_t);
4799 /* offset is now the bitmap offset */
4800 for (int i
= 0; i
< size
/ sizeof (uintptr_t); i
++)
4801 mono_bitset_clear_fast (rb
, offset
+ i
);
4805 mono_alloc_special_static_data (guint32 static_type
, guint32 size
, guint32 align
, uintptr_t *bitmap
, int numbits
)
4807 g_assert (static_type
== SPECIAL_STATIC_THREAD
|| static_type
== SPECIAL_STATIC_CONTEXT
);
4809 StaticDataInfo
*info
;
4812 if (static_type
== SPECIAL_STATIC_THREAD
) {
4813 info
= &thread_static_info
;
4814 sets
= thread_reference_bitmaps
;
4816 info
= &context_static_info
;
4817 sets
= context_reference_bitmaps
;
4820 mono_threads_lock ();
4822 StaticDataFreeList
*item
= search_slot_in_freelist (info
, size
, align
);
4826 offset
= item
->offset
;
4829 offset
= mono_alloc_static_data_slot (info
, size
, align
);
4832 update_reference_bitmap (sets
, offset
, bitmap
, numbits
);
4834 if (static_type
== SPECIAL_STATIC_THREAD
) {
4835 /* This can be called during startup */
4836 if (threads
!= NULL
)
4837 mono_g_hash_table_foreach (threads
, alloc_thread_static_data_helper
, GUINT_TO_POINTER (offset
));
4839 if (contexts
!= NULL
)
4840 g_hash_table_foreach (contexts
, alloc_context_static_data_helper
, GUINT_TO_POINTER (offset
));
4842 ACCESS_SPECIAL_STATIC_OFFSET (offset
, type
) = SPECIAL_STATIC_OFFSET_TYPE_CONTEXT
;
4845 mono_threads_unlock ();
4851 mono_get_special_static_data_for_thread (MonoInternalThread
*thread
, guint32 offset
)
4853 guint32 static_type
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, type
);
4855 if (static_type
== SPECIAL_STATIC_OFFSET_TYPE_THREAD
) {
4856 return get_thread_static_data (thread
, offset
);
4858 return get_context_static_data (thread
->current_appcontext
, offset
);
4863 mono_get_special_static_data (guint32 offset
)
4865 return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset
);
4874 * LOCKING: requires that threads_mutex is held
4877 free_thread_static_data_helper (gpointer key
, gpointer value
, gpointer user
)
4879 MonoInternalThread
*thread
= (MonoInternalThread
*)value
;
4880 OffsetSize
*data
= (OffsetSize
*)user
;
4881 int idx
= ACCESS_SPECIAL_STATIC_OFFSET (data
->offset
, index
);
4882 int off
= ACCESS_SPECIAL_STATIC_OFFSET (data
->offset
, offset
);
4885 if (!thread
->static_data
|| !thread
->static_data
[idx
])
4887 ptr
= ((char*) thread
->static_data
[idx
]) + off
;
4888 mono_gc_bzero_atomic (ptr
, data
->size
);
4892 * LOCKING: requires that threads_mutex is held
4895 free_context_static_data_helper (gpointer key
, gpointer value
, gpointer user
)
4897 MonoAppContext
*ctx
= (MonoAppContext
*) mono_gchandle_get_target_internal (GPOINTER_TO_INT (key
));
4902 OffsetSize
*data
= (OffsetSize
*)user
;
4903 int idx
= ACCESS_SPECIAL_STATIC_OFFSET (data
->offset
, index
);
4904 int off
= ACCESS_SPECIAL_STATIC_OFFSET (data
->offset
, offset
);
4907 if (!ctx
->static_data
|| !ctx
->static_data
[idx
])
4910 ptr
= ((char*) ctx
->static_data
[idx
]) + off
;
4911 mono_gc_bzero_atomic (ptr
, data
->size
);
4915 do_free_special_slot (guint32 offset
, guint32 size
)
4917 guint32 static_type
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, type
);
4919 StaticDataInfo
*info
;
4921 if (static_type
== SPECIAL_STATIC_OFFSET_TYPE_THREAD
) {
4922 info
= &thread_static_info
;
4923 sets
= thread_reference_bitmaps
;
4925 info
= &context_static_info
;
4926 sets
= context_reference_bitmaps
;
4929 guint32 data_offset
= offset
;
4930 ACCESS_SPECIAL_STATIC_OFFSET (data_offset
, type
) = 0;
4931 OffsetSize data
= { data_offset
, size
};
4933 clear_reference_bitmap (sets
, data
.offset
, data
.size
);
4935 if (static_type
== SPECIAL_STATIC_OFFSET_TYPE_THREAD
) {
4936 if (threads
!= NULL
)
4937 mono_g_hash_table_foreach (threads
, free_thread_static_data_helper
, &data
);
4939 if (contexts
!= NULL
)
4940 g_hash_table_foreach (contexts
, free_context_static_data_helper
, &data
);
4943 if (!mono_runtime_is_shutting_down ()) {
4944 StaticDataFreeList
*item
= g_new0 (StaticDataFreeList
, 1);
4946 item
->offset
= offset
;
4949 item
->next
= info
->freelist
;
4950 info
->freelist
= item
;
4955 do_free_special (gpointer key
, gpointer value
, gpointer data
)
4957 MonoClassField
*field
= (MonoClassField
*)key
;
4958 guint32 offset
= GPOINTER_TO_UINT (value
);
4961 size
= mono_type_size (field
->type
, &align
);
4962 do_free_special_slot (offset
, size
);
4966 mono_alloc_special_static_data_free (GHashTable
*special_static_fields
)
4968 mono_threads_lock ();
4970 g_hash_table_foreach (special_static_fields
, do_free_special
, NULL
);
4972 mono_threads_unlock ();
4977 flush_thread_interrupt_queue (void)
4979 /* Consume pending APC calls for current thread.*/
4980 /* Since this function get's called from interrupt handler it must use a direct */
4981 /* Win32 API call and can't go through mono_coop_win32_wait_for_single_object_ex */
4982 /* or it will detect a pending interrupt and not entering the wait call needed */
4983 /* to consume pending APC's.*/
4985 WaitForSingleObjectEx (GetCurrentThread (), 0, TRUE
);
4990 flush_thread_interrupt_queue (void)
4996 * mono_thread_execute_interruption
4998 * Performs the operation that the requested thread state requires (abort,
5002 mono_thread_execute_interruption (MonoExceptionHandle
*pexc
)
5004 gboolean fexc
= FALSE
;
5006 // Optimize away frame if caller supplied one.
5008 HANDLE_FUNCTION_ENTER ();
5009 MonoExceptionHandle exc
= MONO_HANDLE_NEW (MonoException
, NULL
);
5010 fexc
= mono_thread_execute_interruption (&exc
);
5011 HANDLE_FUNCTION_RETURN_VAL (fexc
);
5014 MONO_REQ_GC_UNSAFE_MODE
;
5016 MonoInternalThreadHandle thread
= mono_thread_internal_current_handle ();
5017 MonoExceptionHandle exc
= MONO_HANDLE_NEW (MonoException
, NULL
);
5019 lock_thread_handle (thread
);
5020 gboolean unlock
= TRUE
;
5022 /* MonoThread::interruption_requested can only be changed with atomics */
5023 if (!mono_thread_clear_interruption_requested_handle (thread
))
5026 MonoThreadObjectHandle sys_thread
;
5027 sys_thread
= mono_thread_current_handle ();
5029 flush_thread_interrupt_queue ();
5031 /* Clear the interrupted flag of the thread so it can wait again */
5032 mono_thread_info_clear_self_interrupt ();
5034 /* If there's a pending exception and an AbortRequested, the pending exception takes precedence */
5035 MONO_HANDLE_GET (exc
, sys_thread
, pending_exception
);
5036 if (!MONO_HANDLE_IS_NULL (exc
)) {
5037 // sys_thread->pending_exception = NULL;
5038 MONO_HANDLE_SETRAW (sys_thread
, pending_exception
, NULL
);
5041 } else if (MONO_HANDLE_GETVAL (thread
, state
) & ThreadState_AbortRequested
) {
5042 // Does the thread already have an abort exception?
5043 // If not, create a new one and set it on demand.
5044 // exc = thread->abort_exc;
5045 MONO_HANDLE_GET (exc
, thread
, abort_exc
);
5046 if (MONO_HANDLE_IS_NULL (exc
)) {
5048 exc
= mono_exception_new_thread_abort (error
);
5049 mono_error_assert_ok (error
); // FIXME
5050 // thread->abort_exc = exc;
5051 MONO_HANDLE_SET (thread
, abort_exc
, exc
);
5054 } else if (MONO_HANDLE_GETVAL (thread
, state
) & ThreadState_SuspendRequested
) {
5055 /* calls UNLOCK_THREAD (thread) */
5056 self_suspend_internal ();
5058 } else if (MONO_HANDLE_GETVAL (thread
, thread_interrupt_requested
)) {
5059 // thread->thread_interrupt_requested = FALSE
5060 MONO_HANDLE_SETVAL (thread
, thread_interrupt_requested
, MonoBoolean
, FALSE
);
5061 unlock_thread_handle (thread
);
5064 exc
= mono_exception_new_thread_interrupted (error
);
5065 mono_error_assert_ok (error
); // FIXME
5070 unlock_thread_handle (thread
);
5073 MONO_HANDLE_ASSIGN (*pexc
, exc
);
5079 mono_thread_execute_interruption_void (void)
5081 (void)mono_thread_execute_interruption (NULL
);
5084 static MonoException
*
5085 mono_thread_execute_interruption_ptr (void)
5087 HANDLE_FUNCTION_ENTER ();
5088 MonoExceptionHandle exc
= MONO_HANDLE_NEW (MonoException
, NULL
);
5089 MonoException
* const exc_raw
= mono_thread_execute_interruption (&exc
) ? MONO_HANDLE_RAW (exc
) : NULL
;
5090 HANDLE_FUNCTION_RETURN_VAL (exc_raw
);
5094 * mono_thread_request_interruption_internal
5096 * A signal handler can call this method to request the interruption of a
5097 * thread. The result of the interruption will depend on the current state of
5098 * the thread. If the result is an exception that needs to be thrown, it is
5099 * provided as return value.
5102 mono_thread_request_interruption_internal (gboolean running_managed
, MonoExceptionHandle
*pexc
)
5104 MonoInternalThread
*thread
= mono_thread_internal_current ();
5106 /* The thread may already be stopping */
5110 if (!mono_thread_set_interruption_requested (thread
))
5113 if (!running_managed
|| is_running_protected_wrapper ()) {
5114 /* Can't stop while in unmanaged code. Increase the global interruption
5115 request count. When exiting the unmanaged method the count will be
5116 checked and the thread will be interrupted. */
5118 /* this will awake the thread if it is in WaitForSingleObject
5121 mono_win32_interrupt_wait (thread
->thread_info
, thread
->native_handle
, (DWORD
)thread
->tid
);
5123 mono_thread_info_self_interrupt ();
5127 return mono_thread_execute_interruption (pexc
);
5131 mono_thread_request_interruption_native (void)
5133 (void)mono_thread_request_interruption_internal (FALSE
, NULL
);
5137 mono_thread_request_interruption_managed (MonoExceptionHandle
*exc
)
5139 return mono_thread_request_interruption_internal (TRUE
, exc
);
5142 /*This function should be called by a thread after it has exited all of
5143 * its handle blocks at interruption time.*/
5145 mono_thread_resume_interruption (gboolean exec
)
5147 MonoInternalThread
*thread
= mono_thread_internal_current ();
5148 gboolean still_aborting
;
5150 /* The thread may already be stopping */
5154 LOCK_THREAD (thread
);
5155 still_aborting
= (thread
->state
& (ThreadState_AbortRequested
)) != 0;
5156 UNLOCK_THREAD (thread
);
5158 /*This can happen if the protected block called Thread::ResetAbort*/
5159 if (!still_aborting
)
5162 if (!mono_thread_set_interruption_requested (thread
))
5165 mono_thread_info_self_interrupt ();
5167 if (exec
) // Ignore the exception here, it will be raised later.
5168 mono_thread_execute_interruption_void ();
5172 mono_thread_interruption_requested (void)
5174 if (mono_thread_interruption_request_flag
) {
5175 MonoInternalThread
*thread
= mono_thread_internal_current ();
5176 /* The thread may already be stopping */
5178 return mono_thread_get_interruption_requested (thread
);
5183 static MonoException
*
5184 mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection
)
5186 MonoInternalThread
*thread
= mono_thread_internal_current ();
5188 /* The thread may already be stopping */
5191 if (!mono_thread_get_interruption_requested (thread
))
5193 if (!bypass_abort_protection
&& !mono_thread_current ()->pending_exception
&& is_running_protected_wrapper ())
5196 return mono_thread_execute_interruption_ptr ();
5200 * Performs the interruption of the current thread, if one has been requested,
5201 * and the thread is not running a protected wrapper.
5202 * Return the exception which needs to be thrown, if any.
5205 mono_thread_interruption_checkpoint (void)
5207 return mono_thread_interruption_checkpoint_request (FALSE
);
5211 mono_thread_interruption_checkpoint_bool (void)
5213 return mono_thread_interruption_checkpoint () != NULL
;
5217 mono_thread_interruption_checkpoint_void (void)
5219 mono_thread_interruption_checkpoint ();
5223 * Performs the interruption of the current thread, if one has been requested.
5224 * Return the exception which needs to be thrown, if any.
5227 mono_thread_force_interruption_checkpoint_noraise (void)
5229 return mono_thread_interruption_checkpoint_request (TRUE
);
5233 * mono_set_pending_exception:
5235 * Set the pending exception of the current thread to EXC.
5236 * The exception will be thrown when execution returns to managed code.
5239 mono_set_pending_exception (MonoException
*exc
)
5241 MonoThread
*thread
= mono_thread_current ();
5243 /* The thread may already be stopping */
5247 MONO_OBJECT_SETREF_INTERNAL (thread
, pending_exception
, exc
);
5249 mono_thread_request_interruption_native ();
5253 * mono_runtime_set_pending_exception:
5255 * Set the pending exception of the current thread to \p exc.
5256 * The exception will be thrown when execution returns to managed code.
5257 * Can optionally \p overwrite any existing pending exceptions (it's not supported
5258 * to overwrite any pending exceptions if the runtime is processing a thread abort request,
5259 * in which case the behavior will be undefined).
5260 * Return whether the pending exception was set or not.
5261 * It will not be set if:
5262 * * The thread or runtime is stopping or shutting down
5263 * * There already is a pending exception (and \p overwrite is false)
5266 mono_runtime_set_pending_exception (MonoException
*exc
, mono_bool overwrite
)
5268 MonoThread
*thread
= mono_thread_current ();
5270 /* The thread may already be stopping */
5274 /* Don't overwrite any existing pending exceptions unless asked to */
5275 if (!overwrite
&& thread
->pending_exception
)
5278 MONO_OBJECT_SETREF_INTERNAL (thread
, pending_exception
, exc
);
5280 mono_thread_request_interruption_native ();
5287 * mono_set_pending_exception_handle:
5289 * Set the pending exception of the current thread to EXC.
5290 * The exception will be thrown when execution returns to managed code.
5293 mono_set_pending_exception_handle (MonoExceptionHandle exc
)
5295 MonoThread
*thread
= mono_thread_current ();
5297 /* The thread may already be stopping */
5301 MONO_OBJECT_SETREF_INTERNAL (thread
, pending_exception
, MONO_HANDLE_RAW (exc
));
5303 mono_thread_request_interruption_native ();
5307 mono_thread_init_apartment_state (void)
5310 MonoInternalThread
* thread
= mono_thread_internal_current ();
5312 /* Positive return value indicates success, either
5313 * S_OK if this is first CoInitialize call, or
5314 * S_FALSE if CoInitialize already called, but with same
5315 * threading model. A negative value indicates failure,
5316 * probably due to trying to change the threading model.
5318 if (CoInitializeEx(NULL
, (thread
->apartment_state
== ThreadApartmentState_STA
)
5319 ? COINIT_APARTMENTTHREADED
5320 : COINIT_MULTITHREADED
) < 0) {
5321 thread
->apartment_state
= ThreadApartmentState_Unknown
;
5327 mono_thread_cleanup_apartment_state (void)
5330 MonoInternalThread
* thread
= mono_thread_internal_current ();
5332 if (thread
&& thread
->apartment_state
!= ThreadApartmentState_Unknown
) {
5339 mono_thread_notify_change_state (MonoThreadState old_state
, MonoThreadState new_state
)
5341 MonoThreadState diff
= old_state
^ new_state
;
5342 if (diff
& ThreadState_Background
) {
5343 /* If the thread changes the background mode, the main thread has to
5344 * be notified, since it has to rebuild the list of threads to
5348 mono_os_event_set (&background_change_event
);
5354 mono_thread_clear_and_set_state (MonoInternalThread
*thread
, MonoThreadState clear
, MonoThreadState set
)
5356 LOCK_THREAD (thread
);
5358 MonoThreadState
const old_state
= (MonoThreadState
)thread
->state
;
5359 MonoThreadState
const new_state
= (old_state
& ~clear
) | set
;
5360 thread
->state
= new_state
;
5362 UNLOCK_THREAD (thread
);
5364 mono_thread_notify_change_state (old_state
, new_state
);
5368 mono_thread_set_state (MonoInternalThread
*thread
, MonoThreadState state
)
5370 mono_thread_clear_and_set_state (thread
, (MonoThreadState
)0, state
);
5374 * mono_thread_test_and_set_state:
5375 * Test if current state of \p thread include \p test. If it does not, OR \p set into the state.
5376 * \returns TRUE if \p set was OR'd in.
5379 mono_thread_test_and_set_state (MonoInternalThread
*thread
, MonoThreadState test
, MonoThreadState set
)
5381 LOCK_THREAD (thread
);
5383 MonoThreadState
const old_state
= (MonoThreadState
)thread
->state
;
5385 if ((old_state
& test
) != 0) {
5386 UNLOCK_THREAD (thread
);
5390 MonoThreadState
const new_state
= old_state
| set
;
5391 thread
->state
= new_state
;
5393 UNLOCK_THREAD (thread
);
5395 mono_thread_notify_change_state (old_state
, new_state
);
5401 mono_thread_clr_state (MonoInternalThread
*thread
, MonoThreadState state
)
5403 mono_thread_clear_and_set_state (thread
, state
, (MonoThreadState
)0);
5407 mono_thread_test_state (MonoInternalThread
*thread
, MonoThreadState test
)
5409 LOCK_THREAD (thread
);
5411 gboolean
const ret
= ((thread
->state
& test
) != 0);
5413 UNLOCK_THREAD (thread
);
5419 self_interrupt_thread (void *_unused
)
5422 MonoThreadInfo
*info
;
5425 exc
= mono_thread_execute_interruption_ptr ();
5427 if (mono_threads_are_safepoints_enabled ()) {
5428 /* We can return from an async call in coop, as
5429 * it's simply called when exiting the safepoint */
5430 /* If we're using hybrid suspend, we only self
5431 * interrupt if we were running, hence using
5436 g_error ("%s: we can't resume from an async call", __func__
);
5439 info
= mono_thread_info_current ();
5441 /* FIXME using thread_saved_state [ASYNC_SUSPEND_STATE_INDEX] can race with another suspend coming in. */
5442 ctx
= info
->thread_saved_state
[ASYNC_SUSPEND_STATE_INDEX
].ctx
;
5444 mono_raise_exception_with_context (exc
, &ctx
);
5448 mono_jit_info_match (MonoJitInfo
*ji
, gpointer ip
)
5452 return ji
->code_start
<= ip
&& (char*)ip
< (char*)ji
->code_start
+ ji
->code_size
;
5456 last_managed (MonoStackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
5458 MonoJitInfo
**dest
= (MonoJitInfo
**)data
;
5464 mono_thread_info_get_last_managed (MonoThreadInfo
*info
)
5466 MonoJitInfo
*ji
= NULL
;
5471 * The suspended thread might be holding runtime locks. Make sure we don't try taking
5472 * any runtime locks while unwinding.
5474 mono_thread_info_set_is_async_context (TRUE
);
5475 mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed
, mono_thread_info_get_suspend_state (info
), MONO_UNWIND_SIGNAL_SAFE
, &ji
);
5476 mono_thread_info_set_is_async_context (FALSE
);
5481 MonoInternalThread
*thread
;
5482 gboolean install_async_abort
;
5483 MonoThreadInfoInterruptToken
*interrupt_token
;
5486 static SuspendThreadResult
5487 async_abort_critical (MonoThreadInfo
*info
, gpointer ud
)
5489 AbortThreadData
*data
= (AbortThreadData
*)ud
;
5490 MonoInternalThread
*thread
= data
->thread
;
5491 MonoJitInfo
*ji
= NULL
;
5492 gboolean protected_wrapper
;
5493 gboolean running_managed
;
5495 if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info
)))
5496 return MonoResumeThread
;
5498 /*someone is already interrupting it*/
5499 if (!mono_thread_set_interruption_requested (thread
))
5500 return MonoResumeThread
;
5502 ji
= mono_thread_info_get_last_managed (info
);
5503 protected_wrapper
= ji
&& !ji
->is_trampoline
&& !ji
->async
&& mono_threads_is_critical_method (mono_jit_info_get_method (ji
));
5504 running_managed
= mono_jit_info_match (ji
, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info
)->ctx
));
5506 if (!protected_wrapper
&& running_managed
) {
5507 /*We are in managed code*/
5508 /*Set the thread to call */
5509 if (data
->install_async_abort
)
5510 mono_thread_info_setup_async_call (info
, self_interrupt_thread
, NULL
);
5511 return MonoResumeThread
;
5514 * This will cause waits to be broken.
5515 * It will also prevent the thread from entering a wait, so if the thread returns
5516 * from the wait before it receives the abort signal, it will just spin in the wait
5517 * functions in the io-layer until the signal handler calls QueueUserAPC which will
5520 data
->interrupt_token
= mono_thread_info_prepare_interrupt (info
);
5522 return MonoResumeThread
;
5527 async_abort_internal (MonoInternalThread
*thread
, gboolean install_async_abort
)
5529 AbortThreadData data
;
5531 g_assert (thread
!= mono_thread_internal_current ());
5533 data
.thread
= thread
;
5534 data
.install_async_abort
= install_async_abort
;
5535 data
.interrupt_token
= NULL
;
5537 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread
), TRUE
, async_abort_critical
, &data
);
5538 if (data
.interrupt_token
)
5539 mono_thread_info_finish_interrupt (data
.interrupt_token
);
5540 /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
5544 self_abort_internal (MonoError
*error
)
5546 HANDLE_FUNCTION_ENTER ();
5550 /* FIXME this is insanely broken, it doesn't cause interruption to happen synchronously
5551 * since passing FALSE to mono_thread_request_interruption makes sure it returns NULL */
5554 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.
5556 MonoExceptionHandle exc
= MONO_HANDLE_NEW (MonoException
, NULL
);
5557 if (mono_thread_request_interruption_managed (&exc
))
5558 mono_error_set_exception_handle (error
, exc
);
5560 mono_thread_info_self_interrupt ();
5562 HANDLE_FUNCTION_RETURN ();
5566 MonoInternalThread
*thread
;
5568 MonoThreadInfoInterruptToken
*interrupt_token
;
5569 } SuspendThreadData
;
5571 static SuspendThreadResult
5572 async_suspend_critical (MonoThreadInfo
*info
, gpointer ud
)
5574 SuspendThreadData
*data
= (SuspendThreadData
*)ud
;
5575 MonoInternalThread
*thread
= data
->thread
;
5576 MonoJitInfo
*ji
= NULL
;
5577 gboolean protected_wrapper
;
5578 gboolean running_managed
;
5580 ji
= mono_thread_info_get_last_managed (info
);
5581 protected_wrapper
= ji
&& !ji
->is_trampoline
&& !ji
->async
&& mono_threads_is_critical_method (mono_jit_info_get_method (ji
));
5582 running_managed
= mono_jit_info_match (ji
, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info
)->ctx
));
5584 if (running_managed
&& !protected_wrapper
) {
5585 if (mono_threads_are_safepoints_enabled ()) {
5586 mono_thread_info_setup_async_call (info
, self_interrupt_thread
, NULL
);
5587 return MonoResumeThread
;
5589 thread
->state
&= ~ThreadState_SuspendRequested
;
5590 thread
->state
|= ThreadState_Suspended
;
5591 return KeepSuspended
;
5594 mono_thread_set_interruption_requested (thread
);
5595 if (data
->interrupt
)
5596 data
->interrupt_token
= mono_thread_info_prepare_interrupt ((MonoThreadInfo
*)thread
->thread_info
);
5598 return MonoResumeThread
;
5602 /* LOCKING: called with @thread longlived->synch_cs held, and releases it */
5604 async_suspend_internal (MonoInternalThread
*thread
, gboolean interrupt
)
5606 SuspendThreadData data
;
5608 g_assert (thread
!= mono_thread_internal_current ());
5610 // g_async_safe_printf ("ASYNC SUSPEND thread %p\n", thread_get_tid (thread));
5612 thread
->self_suspended
= FALSE
;
5614 data
.thread
= thread
;
5615 data
.interrupt
= interrupt
;
5616 data
.interrupt_token
= NULL
;
5618 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread
), interrupt
, async_suspend_critical
, &data
);
5619 if (data
.interrupt_token
)
5620 mono_thread_info_finish_interrupt (data
.interrupt_token
);
5622 UNLOCK_THREAD (thread
);
5625 /* LOCKING: called with @thread longlived->synch_cs held, and releases it */
5627 self_suspend_internal (void)
5629 MonoInternalThread
*thread
;
5631 MonoOSEventWaitRet res
;
5633 thread
= mono_thread_internal_current ();
5635 // g_async_safe_printf ("SELF SUSPEND thread %p\n", thread_get_tid (thread));
5637 thread
->self_suspended
= TRUE
;
5639 thread
->state
&= ~ThreadState_SuspendRequested
;
5640 thread
->state
|= ThreadState_Suspended
;
5642 UNLOCK_THREAD (thread
);
5644 event
= thread
->suspended
;
5647 res
= mono_os_event_wait_one (event
, MONO_INFINITE_WAIT
, TRUE
);
5648 g_assert (res
== MONO_OS_EVENT_WAIT_RET_SUCCESS_0
|| res
== MONO_OS_EVENT_WAIT_RET_ALERTED
);
5653 suspend_for_shutdown_async_call (gpointer unused
)
5656 mono_thread_info_yield ();
5659 static SuspendThreadResult
5660 suspend_for_shutdown_critical (MonoThreadInfo
*info
, gpointer unused
)
5662 mono_thread_info_setup_async_call (info
, suspend_for_shutdown_async_call
, NULL
);
5663 return MonoResumeThread
;
5667 mono_thread_internal_suspend_for_shutdown (MonoInternalThread
*thread
)
5669 g_assert (thread
!= mono_thread_internal_current ());
5671 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread
), FALSE
, suspend_for_shutdown_critical
, NULL
);
5675 * mono_thread_is_foreign:
5676 * \param thread the thread to query
5678 * This function allows one to determine if a thread was created by the mono runtime and has
5679 * a well defined lifecycle or it's a foreign one, created by the native environment.
5681 * \returns TRUE if \p thread was not created by the runtime.
5684 mono_thread_is_foreign (MonoThread
*thread
)
5687 MONO_ENTER_GC_UNSAFE
;
5688 MonoThreadInfo
*info
= (MonoThreadInfo
*)thread
->internal_thread
->thread_info
;
5689 result
= (info
->runtime_thread
== FALSE
);
5690 MONO_EXIT_GC_UNSAFE
;
5696 threads_native_thread_join_lock (gpointer tid
, gpointer value
)
5699 * Have to cast to a pointer-sized integer first, as we can't narrow
5700 * from a pointer if pthread_t is an integer smaller than a pointer.
5702 pthread_t thread
= (pthread_t
)(intptr_t)tid
;
5703 if (thread
!= pthread_self ()) {
5705 /* This shouldn't block */
5706 mono_threads_join_lock ();
5707 mono_native_thread_join (thread
);
5708 mono_threads_join_unlock ();
5713 threads_native_thread_join_nolock (gpointer tid
, gpointer value
)
5715 pthread_t thread
= (pthread_t
)(intptr_t)tid
;
5717 mono_native_thread_join (thread
);
5722 threads_add_joinable_thread_nolock (gpointer tid
)
5724 g_hash_table_insert (joinable_threads
, tid
, tid
);
5728 threads_native_thread_join_lock (gpointer tid
, gpointer value
)
5730 MonoNativeThreadId thread_id
= (MonoNativeThreadId
)(guint64
)tid
;
5731 HANDLE thread_handle
= (HANDLE
)value
;
5732 if (thread_id
!= GetCurrentThreadId () && thread_handle
!= NULL
&& thread_handle
!= INVALID_HANDLE_VALUE
) {
5734 /* This shouldn't block */
5735 mono_threads_join_lock ();
5736 mono_native_thread_join_handle (thread_handle
, TRUE
);
5737 mono_threads_join_unlock ();
5743 threads_native_thread_join_nolock (gpointer tid
, gpointer value
)
5745 HANDLE thread_handle
= (HANDLE
)value
;
5747 mono_native_thread_join_handle (thread_handle
, TRUE
);
5752 threads_add_joinable_thread_nolock (gpointer tid
)
5754 g_hash_table_insert (joinable_threads
, tid
, (gpointer
)OpenThread (SYNCHRONIZE
, TRUE
, (MonoNativeThreadId
)(guint64
)tid
));
5759 threads_add_pending_joinable_thread (gpointer tid
)
5761 joinable_threads_lock ();
5763 if (!pending_joinable_threads
)
5764 pending_joinable_threads
= g_hash_table_new (NULL
, NULL
);
5769 if (!g_hash_table_lookup_extended (pending_joinable_threads
, tid
, &orig_key
, &value
)) {
5770 g_hash_table_insert (pending_joinable_threads
, tid
, tid
);
5771 UnlockedIncrement (&pending_joinable_thread_count
);
5774 joinable_threads_unlock ();
5778 threads_add_pending_joinable_runtime_thread (MonoThreadInfo
*mono_thread_info
)
5780 g_assert (mono_thread_info
);
5782 if (mono_thread_info
->runtime_thread
) {
5783 threads_add_pending_joinable_thread ((gpointer
)(MONO_UINT_TO_NATIVE_THREAD_ID (mono_thread_info_get_tid (mono_thread_info
))));
5788 threads_remove_pending_joinable_thread_nolock (gpointer tid
)
5793 if (pending_joinable_threads
&& g_hash_table_lookup_extended (pending_joinable_threads
, tid
, &orig_key
, &value
)) {
5794 g_hash_table_remove (pending_joinable_threads
, tid
);
5795 if (UnlockedDecrement (&pending_joinable_thread_count
) == 0)
5796 mono_coop_cond_broadcast (&zero_pending_joinable_thread_event
);
5801 threads_wait_pending_joinable_threads (uint32_t timeout
)
5803 if (UnlockedRead (&pending_joinable_thread_count
) > 0) {
5804 joinable_threads_lock ();
5805 if (timeout
== MONO_INFINITE_WAIT
) {
5806 while (UnlockedRead (&pending_joinable_thread_count
) > 0)
5807 mono_coop_cond_wait (&zero_pending_joinable_thread_event
, &joinable_threads_mutex
);
5809 gint64 start
= mono_msec_ticks ();
5811 while (UnlockedRead (&pending_joinable_thread_count
) > 0 && elapsed
< timeout
) {
5812 mono_coop_cond_timedwait (&zero_pending_joinable_thread_event
, &joinable_threads_mutex
, timeout
- (uint32_t)elapsed
);
5813 elapsed
= mono_msec_ticks () - start
;
5816 joinable_threads_unlock ();
5819 return UnlockedRead (&pending_joinable_thread_count
) == 0;
5823 threads_add_unique_joinable_thread_nolock (gpointer tid
)
5825 if (!joinable_threads
)
5826 joinable_threads
= g_hash_table_new (NULL
, NULL
);
5831 if (!g_hash_table_lookup_extended (joinable_threads
, tid
, &orig_key
, &value
)) {
5832 threads_add_joinable_thread_nolock (tid
);
5833 UnlockedIncrement (&joinable_thread_count
);
5838 mono_threads_add_joinable_runtime_thread (MonoThreadInfo
*thread_info
)
5840 g_assert (thread_info
);
5841 MonoThreadInfo
*mono_thread_info
= thread_info
;
5843 if (mono_thread_info
->runtime_thread
) {
5844 gpointer tid
= (gpointer
)(MONO_UINT_TO_NATIVE_THREAD_ID (mono_thread_info_get_tid (mono_thread_info
)));
5846 joinable_threads_lock ();
5848 // Add to joinable thread list, if not already included.
5849 threads_add_unique_joinable_thread_nolock (tid
);
5851 // Remove thread from pending joinable list, if present.
5852 threads_remove_pending_joinable_thread_nolock (tid
);
5854 joinable_threads_unlock ();
5856 mono_gc_finalize_notify ();
5861 threads_add_pending_native_thread_join_call_nolock (gpointer tid
)
5863 if (!pending_native_thread_join_calls
)
5864 pending_native_thread_join_calls
= g_hash_table_new (NULL
, NULL
);
5869 if (!g_hash_table_lookup_extended (pending_native_thread_join_calls
, tid
, &orig_key
, &value
))
5870 g_hash_table_insert (pending_native_thread_join_calls
, tid
, tid
);
5874 threads_remove_pending_native_thread_join_call_nolock (gpointer tid
)
5876 if (pending_native_thread_join_calls
)
5877 g_hash_table_remove (pending_native_thread_join_calls
, tid
);
5879 mono_coop_cond_broadcast (&pending_native_thread_join_calls_event
);
5883 threads_wait_pending_native_thread_join_call_nolock (gpointer tid
)
5888 while (g_hash_table_lookup_extended (pending_native_thread_join_calls
, tid
, &orig_key
, &value
)) {
5889 mono_coop_cond_wait (&pending_native_thread_join_calls_event
, &joinable_threads_mutex
);
5894 * mono_add_joinable_thread:
5896 * Add TID to the list of joinable threads.
5897 * LOCKING: Acquires the threads lock.
5900 mono_threads_add_joinable_thread (gpointer tid
)
5903 * We cannot detach from threads because it causes problems like
5904 * 2fd16f60/r114307. So we collect them and join them when
5905 * we have time (in the finalizer thread).
5907 joinable_threads_lock ();
5908 threads_add_unique_joinable_thread_nolock (tid
);
5909 joinable_threads_unlock ();
5911 mono_gc_finalize_notify ();
5915 * mono_threads_join_threads:
5917 * Join all joinable threads. This is called from the finalizer thread.
5918 * LOCKING: Acquires the threads lock.
5921 mono_threads_join_threads (void)
5923 GHashTableIter iter
;
5924 gpointer key
= NULL
;
5925 gpointer value
= NULL
;
5926 gboolean found
= FALSE
;
5929 if (!UnlockedRead (&joinable_thread_count
))
5933 joinable_threads_lock ();
5935 // Previous native thread join call completed.
5936 threads_remove_pending_native_thread_join_call_nolock (key
);
5939 if (g_hash_table_size (joinable_threads
)) {
5940 g_hash_table_iter_init (&iter
, joinable_threads
);
5941 g_hash_table_iter_next (&iter
, &key
, (void**)&value
);
5942 g_hash_table_remove (joinable_threads
, key
);
5943 UnlockedDecrement (&joinable_thread_count
);
5946 // Add to table of tid's with pending native thread join call.
5947 threads_add_pending_native_thread_join_call_nolock (key
);
5949 joinable_threads_unlock ();
5951 threads_native_thread_join_lock (key
, value
);
5960 * Wait for thread TID to exit.
5961 * LOCKING: Acquires the threads lock.
5964 mono_thread_join (gpointer tid
)
5966 gboolean found
= FALSE
;
5970 joinable_threads_lock ();
5971 if (!joinable_threads
)
5972 joinable_threads
= g_hash_table_new (NULL
, NULL
);
5974 if (g_hash_table_lookup_extended (joinable_threads
, tid
, &orig_key
, &value
)) {
5975 g_hash_table_remove (joinable_threads
, tid
);
5976 UnlockedDecrement (&joinable_thread_count
);
5979 // Add to table of tid's with pending native join call.
5980 threads_add_pending_native_thread_join_call_nolock (tid
);
5984 // Wait for any pending native thread join call not yet completed for this tid.
5985 threads_wait_pending_native_thread_join_call_nolock (tid
);
5988 joinable_threads_unlock ();
5993 threads_native_thread_join_nolock (tid
, value
);
5995 joinable_threads_lock ();
5996 // Native thread join call completed for this tid.
5997 threads_remove_pending_native_thread_join_call_nolock (tid
);
5998 joinable_threads_unlock ();
6002 mono_thread_internal_unhandled_exception (MonoObject
* exc
)
6004 MonoClass
*klass
= exc
->vtable
->klass
;
6005 if (is_threadabort_exception (klass
)) {
6006 mono_thread_internal_reset_abort (mono_thread_internal_current ());
6007 } else if (!is_appdomainunloaded_exception (klass
)
6008 && mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT
) {
6009 mono_unhandled_exception_internal (exc
);
6010 if (mono_environment_exitcode_get () == 1) {
6011 mono_environment_exitcode_set (255);
6012 mono_invoke_unhandled_exception_hook (exc
);
6013 g_assert_not_reached ();
6019 * mono_threads_attach_coop_internal: called by native->managed wrappers
6022 * - blocking mode: contains gc unsafe transition cookie
6023 * - non-blocking mode: contains random data
6024 * - @stackdata: semi-opaque struct: stackpointer and function_name
6025 * - @return: the original domain which needs to be restored, or NULL.
6028 mono_threads_attach_coop_internal (MonoDomain
*domain
, gpointer
*cookie
, MonoStackData
*stackdata
)
6031 MonoThreadInfo
*info
;
6032 gboolean external
= FALSE
;
6034 orig
= mono_domain_get ();
6037 /* Happens when called from AOTed code which is only used in the root domain. */
6038 domain
= mono_get_root_domain ();
6042 /* On coop, when we detached, we moved the thread from RUNNING->BLOCKING.
6043 * If we try to reattach we do a BLOCKING->RUNNING transition. If the thread
6044 * is fresh, mono_thread_attach() will do a STARTING->RUNNING transition so
6045 * we're only responsible for making the cookie. */
6046 if (mono_threads_is_blocking_transition_enabled ())
6047 external
= !(info
= mono_thread_info_current_unchecked ()) || !mono_thread_info_is_live (info
);
6049 if (!mono_thread_internal_current ()) {
6050 mono_thread_attach (domain
);
6053 mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background
);
6056 if (mono_threads_is_blocking_transition_enabled ()) {
6058 /* mono_thread_attach put the thread in RUNNING mode from STARTING, but we need to
6059 * return the right cookie. */
6060 *cookie
= mono_threads_enter_gc_unsafe_region_cookie ();
6062 /* thread state (BLOCKING|RUNNING) -> RUNNING */
6063 *cookie
= mono_threads_enter_gc_unsafe_region_unbalanced_internal (stackdata
);
6068 mono_domain_set_fast (domain
, TRUE
);
6074 * mono_threads_attach_coop: called by native->managed wrappers
6077 * - blocking mode: contains gc unsafe transition cookie
6078 * - non-blocking mode: contains random data
6079 * - a pointer to stack, used for some checks
6080 * - @return: the original domain which needs to be restored, or NULL.
6083 mono_threads_attach_coop (MonoDomain
*domain
, gpointer
*dummy
)
6085 MONO_STACKDATA (stackdata
);
6086 stackdata
.stackpointer
= dummy
;
6087 return mono_threads_attach_coop_internal (domain
, dummy
, &stackdata
);
6091 * mono_threads_detach_coop_internal: called by native->managed wrappers
6093 * - @orig: the original domain which needs to be restored, or NULL.
6094 * - @stackdata: semi-opaque struct: stackpointer and function_name
6096 * - blocking mode: contains gc unsafe transition cookie
6097 * - non-blocking mode: contains random data
6100 mono_threads_detach_coop_internal (MonoDomain
*orig
, gpointer cookie
, MonoStackData
*stackdata
)
6102 MonoDomain
*domain
= mono_domain_get ();
6105 if (orig
!= domain
) {
6107 mono_domain_unset ();
6109 mono_domain_set_fast (orig
, TRUE
);
6112 if (mono_threads_is_blocking_transition_enabled ()) {
6113 /* it won't do anything if cookie is NULL
6114 * thread state RUNNING -> (RUNNING|BLOCKING) */
6115 mono_threads_exit_gc_unsafe_region_unbalanced_internal (cookie
, stackdata
);
6120 * mono_threads_detach_coop: called by native->managed wrappers
6122 * - @orig: the original domain which needs to be restored, or NULL.
6124 * - blocking mode: contains gc unsafe transition cookie
6125 * - non-blocking mode: contains random data
6126 * - a pointer to stack, used for some checks
6129 mono_threads_detach_coop (gpointer orig
, gpointer
*dummy
)
6131 MONO_STACKDATA (stackdata
);
6132 stackdata
.stackpointer
= dummy
;
6133 mono_threads_detach_coop_internal ((MonoDomain
*)orig
, *dummy
, &stackdata
);
6137 /* Returns TRUE if the current thread is ready to be interrupted. */
6139 mono_threads_is_ready_to_be_interrupted (void)
6141 MonoInternalThread
*thread
;
6143 thread
= mono_thread_internal_current ();
6144 LOCK_THREAD (thread
);
6145 if (thread
->state
& (ThreadState_SuspendRequested
| ThreadState_AbortRequested
)) {
6146 UNLOCK_THREAD (thread
);
6150 if (mono_thread_get_abort_prot_block_count (thread
) || mono_get_eh_callbacks ()->mono_current_thread_has_handle_block_guard ()) {
6151 UNLOCK_THREAD (thread
);
6155 UNLOCK_THREAD (thread
);
6161 mono_thread_internal_describe (MonoInternalThread
*internal
, GString
*text
)
6163 g_string_append_printf (text
, ", thread handle : %p", internal
->handle
);
6165 if (internal
->thread_info
) {
6166 g_string_append (text
, ", state : ");
6167 mono_thread_info_describe_interrupt_token (internal
->thread_info
, text
);
6170 if (internal
->owned_mutexes
) {
6173 g_string_append (text
, ", owns : [");
6174 for (i
= 0; i
< internal
->owned_mutexes
->len
; i
++)
6175 g_string_append_printf (text
, i
== 0 ? "%p" : ", %p", g_ptr_array_index (internal
->owned_mutexes
, i
));
6176 g_string_append (text
, "]");
6181 mono_thread_internal_is_current (MonoInternalThread
*internal
)
6183 g_assert (internal
);
6184 return mono_native_thread_id_equals (mono_native_thread_id_get (), MONO_UINT_TO_NATIVE_THREAD_ID (internal
->tid
));
6188 mono_set_thread_dump_dir (gchar
* dir
) {
6189 thread_dump_dir
= dir
;
6192 #ifdef DISABLE_CRASH_REPORTING
6194 mono_threads_summarize_init (void)
6199 mono_threads_summarize (MonoContext
*ctx
, gchar
**out
, MonoStackHash
*hashes
, gboolean silent
, gboolean signal_handler_controller
, gchar
*mem
, size_t provided_size
)
6205 mono_threads_summarize_one (MonoThreadSummary
*out
, MonoContext
*ctx
)
6213 mono_threads_summarize_native_self (MonoThreadSummary
*out
, MonoContext
*ctx
)
6215 if (!mono_get_eh_callbacks ()->mono_summarize_managed_stack
)
6218 memset (out
, 0, sizeof (MonoThreadSummary
));
6221 MonoNativeThreadId current
= mono_native_thread_id_get();
6222 out
->native_thread_id
= (intptr_t) current
;
6224 mono_get_eh_callbacks ()->mono_summarize_unmanaged_stack (out
);
6226 mono_native_thread_get_name (current
, out
->name
, MONO_MAX_SUMMARY_NAME_LEN
);
6231 // Not safe to call from signal handler
6233 mono_threads_summarize_one (MonoThreadSummary
*out
, MonoContext
*ctx
)
6235 gboolean success
= mono_threads_summarize_native_self (out
, ctx
);
6237 // Finish this on the same thread
6239 if (success
&& mono_get_eh_callbacks ()->mono_summarize_managed_stack
)
6240 mono_get_eh_callbacks ()->mono_summarize_managed_stack (out
);
6245 #define MAX_NUM_THREADS 128
6247 gint32 has_owner
; // state of this memory
6249 MonoSemType update
; // notify of addition of threads
6252 MonoNativeThreadId thread_array
[MAX_NUM_THREADS
]; // ids of threads we're dumping
6254 int nthreads_attached
; // Number of threads self-registered
6255 MonoThreadSummary
*all_threads
[MAX_NUM_THREADS
];
6257 gboolean silent
; // print to stdout
6258 } SummarizerGlobalState
;
6260 #if defined(HAVE_KILL) && !defined(HOST_ANDROID) && defined(HAVE_WAITPID) && defined(HAVE_EXECVE) && ((!defined(HOST_DARWIN) && defined(SYS_fork)) || HAVE_FORK)
6261 #define HAVE_MONO_SUMMARIZER_SUPERVISOR 1
6265 summarizer_supervisor_init (void);
6268 MonoSemType supervisor
;
6270 pid_t supervisor_pid
;
6271 } SummarizerSupervisorState
;
6273 #ifndef HAVE_MONO_SUMMARIZER_SUPERVISOR
6276 summarizer_supervisor_init (void)
6282 summarizer_supervisor_start (SummarizerSupervisorState
*state
)
6284 // nonzero, so caller doesn't think it's the supervisor
6289 summarizer_supervisor_end (SummarizerSupervisorState
*state
)
6295 static const char *hang_watchdog_path
;
6298 summarizer_supervisor_init (void)
6300 hang_watchdog_path
= g_build_filename (mono_get_config_dir (), "..", "bin", "mono-hang-watchdog", NULL
);
6301 g_assert (hang_watchdog_path
);
6305 summarizer_supervisor_start (SummarizerSupervisorState
*state
)
6307 memset (state
, 0, sizeof (*state
));
6310 state
->pid
= getpid();
6313 * glibc fork acquires some locks, so if the crash happened inside malloc/free,
6314 * it will deadlock. Call the syscall directly instead.
6316 #if defined(HOST_ANDROID)
6317 /* SYS_fork is defined to be __NR_fork which is not defined in some ndk versions */
6318 // We disable this when we set HAVE_MONO_SUMMARIZER_SUPERVISOR above
6319 g_assert_not_reached ();
6320 #elif !defined(HOST_DARWIN) && defined(SYS_fork)
6321 pid
= (pid_t
) syscall (SYS_fork
);
6323 pid
= (pid_t
) fork ();
6325 g_assert_not_reached ();
6329 state
->supervisor_pid
= pid
;
6331 char pid_str
[20]; // pid is a uint64_t, 20 digits max in decimal form
6332 sprintf (pid_str
, "%" PRIu64
, (uint64_t)state
->pid
);
6333 const char *const args
[] = { hang_watchdog_path
, pid_str
, NULL
};
6334 execve (args
[0], (char * const*)args
, NULL
); // run 'mono-hang-watchdog [pid]'
6335 g_async_safe_printf ("Could not exec mono-hang-watchdog, expected on path '%s' (errno %d)\n", hang_watchdog_path
, errno
);
6343 summarizer_supervisor_end (SummarizerSupervisorState
*state
)
6346 kill (state
->supervisor_pid
, SIGKILL
);
6349 #if defined (HAVE_WAITPID)
6350 // Accessed on same thread that sets it.
6352 waitpid (state
->supervisor_pid
, &status
, 0);
6358 collect_thread_id (gpointer key
, gpointer value
, gpointer user
)
6360 CollectThreadIdsUserData
*ud
= (CollectThreadIdsUserData
*)user
;
6361 MonoInternalThread
*thread
= (MonoInternalThread
*)value
;
6363 if (ud
->nthreads
< ud
->max_threads
)
6364 ud
->threads
[ud
->nthreads
++] = thread_get_tid (thread
);
6368 collect_thread_ids (MonoNativeThreadId
*thread_ids
, int max_threads
)
6370 CollectThreadIdsUserData ud
;
6372 mono_memory_barrier ();
6376 memset (&ud
, 0, sizeof (ud
));
6377 /* This array contains refs, but its on the stack, so its ok */
6378 ud
.threads
= thread_ids
;
6379 ud
.max_threads
= max_threads
;
6381 mono_threads_lock ();
6382 mono_g_hash_table_foreach (threads
, collect_thread_id
, &ud
);
6383 mono_threads_unlock ();
6389 summarizer_state_init (SummarizerGlobalState
*state
, MonoNativeThreadId current
, int *my_index
)
6391 gint32 started_state
= mono_atomic_cas_i32 (&state
->has_owner
, 1 /* set */, 0 /* compare */);
6392 gboolean not_started
= started_state
== 0;
6394 state
->nthreads
= collect_thread_ids (state
->thread_array
, MAX_NUM_THREADS
);
6395 mono_os_sem_init (&state
->update
, 0);
6398 for (int i
= 0; i
< state
->nthreads
; i
++) {
6399 if (state
->thread_array
[i
] == current
) {
6409 summarizer_signal_other_threads (SummarizerGlobalState
*state
, MonoNativeThreadId current
, int current_idx
)
6411 sigset_t sigset
, old_sigset
;
6412 sigemptyset(&sigset
);
6413 sigaddset(&sigset
, SIGTERM
);
6415 for (int i
=0; i
< state
->nthreads
; i
++) {
6416 sigprocmask (SIG_UNBLOCK
, &sigset
, &old_sigset
);
6418 if (i
== current_idx
)
6420 #ifdef HAVE_PTHREAD_KILL
6421 pthread_kill (state
->thread_array
[i
], SIGTERM
);
6424 g_async_safe_printf("Pkilling 0x%" G_GSIZE_FORMAT
"x from 0x%" G_GSIZE_FORMAT
"x\n", (gsize
)MONO_NATIVE_THREAD_ID_TO_UINT (state
->thread_array
[i
]), (gsize
)MONO_NATIVE_THREAD_ID_TO_UINT (current
));
6426 g_error ("pthread_kill () is not supported by this platform");
6431 // Returns true when there are shared global references to "this_thread"
6433 summarizer_post_dump (SummarizerGlobalState
*state
, MonoThreadSummary
*this_thread
, int current_idx
)
6435 mono_memory_barrier ();
6437 gpointer old
= mono_atomic_cas_ptr ((volatile gpointer
*)&state
->all_threads
[current_idx
], this_thread
, NULL
);
6439 if (old
== GINT_TO_POINTER (-1)) {
6440 g_async_safe_printf ("Trying to register response after dumping period ended");
6442 } else if (old
!= NULL
) {
6443 g_async_safe_printf ("Thread dump raced for thread slot.");
6447 // We added our pointer
6448 gint32 count
= mono_atomic_inc_i32 ((volatile gint32
*) &state
->nthreads_attached
);
6449 if (count
== state
->nthreads
)
6450 mono_os_sem_post (&state
->update
);
6455 // A lockless spinwait with a timeout
6456 // Used in environments where locks are unsafe
6458 // If set_pos is true, we wait until the expected number of threads have
6459 // responded and then count that the expected number are set. If it is not true,
6460 // then we wait for them to be unset.
6462 summary_timedwait (SummarizerGlobalState
*state
, int timeout_seconds
)
6464 const gint64 milliseconds_in_second
= 1000;
6465 gint64 timeout_total
= milliseconds_in_second
* timeout_seconds
;
6467 gint64 end
= mono_msec_ticks () + timeout_total
;
6470 if (mono_atomic_load_i32 ((volatile gint32
*) &state
->nthreads_attached
) == state
->nthreads
)
6473 gint64 now
= mono_msec_ticks ();
6474 gint64 remaining
= end
- now
;
6478 mono_os_sem_timedwait (&state
->update
, remaining
, MONO_SEM_FLAGS_NONE
);
6484 static MonoThreadSummary
*
6485 summarizer_try_read_thread (SummarizerGlobalState
*state
, int index
)
6487 gpointer old_value
= NULL
;
6488 gpointer new_value
= GINT_TO_POINTER(-1);
6491 old_value
= state
->all_threads
[index
];
6492 } while (mono_atomic_cas_ptr ((volatile gpointer
*) &state
->all_threads
[index
], new_value
, old_value
) != old_value
);
6494 MonoThreadSummary
*thread
= (MonoThreadSummary
*) old_value
;
6499 summarizer_state_term (SummarizerGlobalState
*state
, gchar
**out
, gchar
*mem
, size_t provided_size
, MonoThreadSummary
*controlling
)
6501 // See the array writes
6502 mono_memory_barrier ();
6504 MonoThreadSummary
*threads
[MAX_NUM_THREADS
];
6505 memset (threads
, 0, sizeof(threads
));
6507 mono_summarize_timeline_phase_log (MonoSummaryManagedStacks
);
6508 for (int i
=0; i
< state
->nthreads
; i
++) {
6509 threads
[i
] = summarizer_try_read_thread (state
, i
);
6513 // We are doing this dump on the controlling thread because this isn't
6514 // an async context sometimes. There's still some reliance on malloc here, but it's
6515 // much more stable to do it all from the controlling thread.
6517 // This is non-null, checked in mono_threads_summarize
6518 // with early exit there
6519 mono_get_eh_callbacks ()->mono_summarize_managed_stack (threads
[i
]);
6522 MonoStateWriter writer
;
6523 memset (&writer
, 0, sizeof (writer
));
6525 mono_summarize_timeline_phase_log (MonoSummaryStateWriter
);
6526 mono_summarize_native_state_begin (&writer
, mem
, provided_size
);
6527 for (int i
=0; i
< state
->nthreads
; i
++) {
6528 MonoThreadSummary
*thread
= threads
[i
];
6532 mono_summarize_native_state_add_thread (&writer
, thread
, thread
->ctx
, thread
== controlling
);
6533 // Set non-shared state to notify the waiting thread to clean up
6534 // without having to keep our shared state alive
6535 mono_atomic_store_i32 (&thread
->done
, 0x1);
6536 mono_os_sem_post (&thread
->done_wait
);
6538 *out
= mono_summarize_native_state_end (&writer
);
6539 mono_summarize_timeline_phase_log (MonoSummaryStateWriterDone
);
6541 mono_os_sem_destroy (&state
->update
);
6543 memset (state
, 0, sizeof (*state
));
6544 mono_atomic_store_i32 ((volatile gint32
*)&state
->has_owner
, 0);
6548 summarizer_state_wait (MonoThreadSummary
*thread
)
6550 gint64 milliseconds_in_second
= 1000;
6552 // cond_wait can spuriously wake up, so we need to check
6554 while (!mono_atomic_load_i32 (&thread
->done
))
6555 mono_os_sem_timedwait (&thread
->done_wait
, milliseconds_in_second
, MONO_SEM_FLAGS_NONE
);
6559 mono_threads_summarize_execute_internal (MonoContext
*ctx
, gchar
**out
, MonoStackHash
*hashes
, gboolean silent
, gchar
*working_mem
, size_t provided_size
, gboolean this_thread_controls
)
6561 static SummarizerGlobalState state
;
6564 MonoNativeThreadId current
= mono_native_thread_id_get ();
6565 gboolean thread_given_control
= summarizer_state_init (&state
, current
, ¤t_idx
);
6567 g_assert (this_thread_controls
== thread_given_control
);
6569 if (state
.nthreads
== 0) {
6571 g_async_safe_printf("No threads attached to runtime.\n");
6572 memset (&state
, 0, sizeof (state
));
6576 if (this_thread_controls
) {
6577 g_assert (working_mem
);
6579 mono_summarize_timeline_phase_log (MonoSummarySuspendHandshake
);
6580 state
.silent
= silent
;
6581 summarizer_signal_other_threads (&state
, current
, current_idx
);
6582 mono_summarize_timeline_phase_log (MonoSummaryUnmanagedStacks
);
6586 gboolean success
= mono_state_alloc_mem (&mem
, (long) current
, sizeof (MonoThreadSummary
));
6590 MonoThreadSummary
*this_thread
= (MonoThreadSummary
*) mem
.mem
;
6592 if (mono_threads_summarize_native_self (this_thread
, ctx
)) {
6593 // Init the synchronization between the controlling thread and the
6595 mono_os_sem_init (&this_thread
->done_wait
, 0);
6597 // Store a reference to our stack memory into global state
6598 gboolean success
= summarizer_post_dump (&state
, this_thread
, current_idx
);
6599 if (!success
&& !state
.silent
)
6600 g_async_safe_printf("Thread 0x%" G_GSIZE_FORMAT
"x reported itself.\n", (gsize
)MONO_NATIVE_THREAD_ID_TO_UINT (current
));
6601 } else if (!state
.silent
) {
6602 g_async_safe_printf("Thread 0x%" G_GSIZE_FORMAT
"x couldn't report itself.\n", (gsize
)MONO_NATIVE_THREAD_ID_TO_UINT (current
));
6605 // From summarizer, wait and dump.
6606 if (this_thread_controls
) {
6608 g_async_safe_printf("Entering thread summarizer pause from 0x%" G_GSIZE_FORMAT
"x\n", (gsize
)MONO_NATIVE_THREAD_ID_TO_UINT (current
));
6610 // Wait up to 2 seconds for all of the other threads to catch up
6611 summary_timedwait (&state
, 2);
6614 g_async_safe_printf("Finished thread summarizer pause from 0x%" G_GSIZE_FORMAT
"x.\n", (gsize
)MONO_NATIVE_THREAD_ID_TO_UINT (current
));
6616 // Dump and cleanup all the stack memory
6617 summarizer_state_term (&state
, out
, working_mem
, provided_size
, this_thread
);
6619 // Wait here, keeping our stack memory alive
6621 summarizer_state_wait (this_thread
);
6624 // FIXME: How many threads should be counted?
6626 *hashes
= this_thread
->hashes
;
6628 mono_state_free_mem (&mem
);
6634 mono_threads_summarize_init (void)
6636 summarizer_supervisor_init ();
6640 mono_threads_summarize_execute (MonoContext
*ctx
, gchar
**out
, MonoStackHash
*hashes
, gboolean silent
, gchar
*working_mem
, size_t provided_size
)
6643 gboolean already_async
= mono_thread_info_is_async_context ();
6645 mono_thread_info_set_is_async_context (TRUE
);
6646 result
= mono_threads_summarize_execute_internal (ctx
, out
, hashes
, silent
, working_mem
, provided_size
, FALSE
);
6648 mono_thread_info_set_is_async_context (FALSE
);
6653 mono_threads_summarize (MonoContext
*ctx
, gchar
**out
, MonoStackHash
*hashes
, gboolean silent
, gboolean signal_handler_controller
, gchar
*mem
, size_t provided_size
)
6655 if (!mono_get_eh_callbacks ()->mono_summarize_managed_stack
)
6658 // The staggered values are due to the need to use inc_i64 for the first value
6659 static gint64 next_pending_request_id
= 0;
6660 static gint64 request_available_to_run
= 1;
6661 gint64 this_request_id
= mono_atomic_inc_i64 ((volatile gint64
*) &next_pending_request_id
);
6663 // This is a global queue of summary requests.
6664 // It's not safe to signal a thread while they're in the
6665 // middle of a dump. Dladdr is not reentrant. It's the one lock
6666 // we rely on being able to take.
6668 // We don't use it in almost any other place in managed code, so
6669 // our problem is in the stack dumping code racing with the signalling code.
6671 // A dump is wait-free to the degree that it's not going to loop indefinitely.
6672 // If we're running from a crash handler block, we're not in any position to
6673 // wait for an in-flight dump to finish. If we crashed while dumping, we cannot dump.
6674 // We should simply return so we can die cleanly.
6676 // signal_handler_controller should be set only from a handler that expects itself to be the only
6677 // entry point, where the runtime already being dumping means we should just give up
6679 gboolean success
= FALSE
;
6682 gint64 next_request_id
= mono_atomic_load_i64 ((volatile gint64
*) &request_available_to_run
);
6684 if (next_request_id
== this_request_id
) {
6685 gboolean already_async
= mono_thread_info_is_async_context ();
6687 mono_thread_info_set_is_async_context (TRUE
);
6689 SummarizerSupervisorState synch
;
6690 if (summarizer_supervisor_start (&synch
)) {
6692 success
= mono_threads_summarize_execute_internal (ctx
, out
, hashes
, silent
, mem
, provided_size
, TRUE
);
6693 summarizer_supervisor_end (&synch
);
6697 mono_thread_info_set_is_async_context (FALSE
);
6699 // Only the thread that gets the ticket can unblock future dumpers.
6700 mono_atomic_inc_i64 ((volatile gint64
*) &request_available_to_run
);
6702 } else if (signal_handler_controller
) {
6703 // We're done. We can't do anything.
6704 g_async_safe_printf ("Attempted to dump for critical failure when already in dump. Error reporting crashed?");
6705 mono_summarize_double_fault_log ();
6709 g_async_safe_printf ("Waiting for in-flight dump to complete.");
6719 #ifdef ENABLE_NETCORE
6721 ves_icall_System_Threading_Thread_StartInternal (MonoThreadObjectHandle thread_handle
, MonoError
*error
)
6723 MonoThread
*internal
= MONO_HANDLE_RAW (thread_handle
);
6726 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p)", __func__
, internal
));
6728 #ifdef DISABLE_THREADS
6729 mono_error_set_not_supported (error
, NULL
);
6733 LOCK_THREAD (internal
);
6735 if ((internal
->state
& ThreadState_Unstarted
) == 0) {
6736 UNLOCK_THREAD (internal
);
6737 mono_error_set_exception_thread_state (error
, "Thread has already been started.");
6741 if ((internal
->state
& ThreadState_Aborted
) != 0) {
6742 UNLOCK_THREAD (internal
);
6746 res
= create_thread (internal
, internal
, NULL
, NULL
, NULL
, MONO_THREAD_CREATE_FLAGS_NONE
, error
);
6748 UNLOCK_THREAD (internal
);
6752 internal
->state
&= ~ThreadState_Unstarted
;
6754 THREAD_DEBUG (g_message ("%s: Started thread ID %" G_GSIZE_FORMAT
" (handle %p)", __func__
, (gsize
)internal
->tid
, internal
->handle
));
6756 UNLOCK_THREAD (internal
);
6760 ves_icall_System_Threading_Thread_InitInternal (MonoThreadObjectHandle thread_handle
, MonoError
*error
)
6762 MonoThread
*internal
= MONO_HANDLE_RAW (thread_handle
);
6764 // Need to initialize thread objects created from managed code
6765 init_internal_thread_object (internal
);
6766 internal
->state
= ThreadState_Unstarted
;
6767 MONO_OBJECT_SETREF_INTERNAL (internal
, internal_thread
, internal
);
6771 ves_icall_System_Threading_Thread_GetCurrentOSThreadId (MonoError
*error
)
6773 return mono_native_thread_os_id_get ();
6777 ves_icall_System_Threading_Thread_GetCurrentProcessorNumber (MonoError
*error
)
6779 return mono_native_thread_processor_id_get ();
6783 ves_icall_System_Threading_LowLevelLifoSemaphore_InitInternal (void)
6785 return (gpointer
)mono_lifo_semaphore_init ();
6789 ves_icall_System_Threading_LowLevelLifoSemaphore_DeleteInternal (gpointer sem_ptr
)
6791 LifoSemaphore
*sem
= (LifoSemaphore
*)sem_ptr
;
6792 mono_lifo_semaphore_delete (sem
);
6796 ves_icall_System_Threading_LowLevelLifoSemaphore_TimedWaitInternal (gpointer sem_ptr
, gint32 timeout_ms
)
6798 LifoSemaphore
*sem
= (LifoSemaphore
*)sem_ptr
;
6799 return mono_lifo_semaphore_timed_wait (sem
, timeout_ms
);
6803 ves_icall_System_Threading_LowLevelLifoSemaphore_ReleaseInternal (gpointer sem_ptr
, gint32 count
)
6805 LifoSemaphore
*sem
= (LifoSemaphore
*)sem_ptr
;
6806 mono_lifo_semaphore_release (sem
, count
);