2 * threads.c: Thread support internal calls
5 * Dick Porter (dick@ximian.com)
6 * Paolo Molaro (lupus@ximian.com)
7 * Patrik Torstensson (patrik.torstensson@labs2.com)
9 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
12 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
20 #include <mono/metadata/object.h>
21 #include <mono/metadata/domain-internals.h>
22 #include <mono/metadata/profiler-private.h>
23 #include <mono/metadata/threads.h>
24 #include <mono/metadata/threads-types.h>
25 #include <mono/metadata/exception.h>
26 #include <mono/metadata/environment.h>
27 #include <mono/metadata/monitor.h>
28 #include <mono/metadata/gc-internals.h>
29 #include <mono/metadata/marshal.h>
30 #include <mono/metadata/runtime.h>
31 #include <mono/metadata/object-internals.h>
32 #include <mono/metadata/debug-internals.h>
33 #include <mono/utils/monobitset.h>
34 #include <mono/utils/mono-compiler.h>
35 #include <mono/utils/mono-mmap.h>
36 #include <mono/utils/mono-membar.h>
37 #include <mono/utils/mono-time.h>
38 #include <mono/utils/mono-threads.h>
39 #include <mono/utils/mono-threads-coop.h>
40 #include <mono/utils/hazard-pointer.h>
41 #include <mono/utils/mono-tls.h>
42 #include <mono/utils/atomic.h>
43 #include <mono/utils/mono-memory-model.h>
44 #include <mono/utils/mono-error-internals.h>
45 #include <mono/utils/os-event.h>
46 #include <mono/utils/mono-threads-debug.h>
47 #include <mono/metadata/w32handle.h>
48 #include <mono/metadata/w32event.h>
49 #include <mono/metadata/w32mutex.h>
51 #include <mono/metadata/reflection-internals.h>
52 #include <mono/metadata/abi-details.h>
53 #include <mono/metadata/w32error.h>
54 #include <mono/utils/w32api.h>
60 #if defined(HOST_WIN32)
64 #if defined(PLATFORM_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64)
65 #define USE_TKILL_ON_ANDROID 1
68 #ifdef PLATFORM_ANDROID
71 #ifdef USE_TKILL_ON_ANDROID
72 extern int tkill (pid_t tid
, int signal
);
76 /*#define THREAD_DEBUG(a) do { a; } while (0)*/
77 #define THREAD_DEBUG(a)
78 /*#define THREAD_WAIT_DEBUG(a) do { a; } while (0)*/
79 #define THREAD_WAIT_DEBUG(a)
80 /*#define LIBGC_DEBUG(a) do { a; } while (0)*/
81 #define LIBGC_DEBUG(a)
83 #define SPIN_TRYLOCK(i) (InterlockedCompareExchange (&(i), 1, 0) == 0)
84 #define SPIN_LOCK(i) do { \
85 if (SPIN_TRYLOCK (i)) \
89 #define SPIN_UNLOCK(i) i = 0
91 #define LOCK_THREAD(thread) lock_thread((thread))
92 #define UNLOCK_THREAD(thread) unlock_thread((thread))
104 typedef struct _StaticDataFreeList StaticDataFreeList
;
105 struct _StaticDataFreeList
{
106 StaticDataFreeList
*next
;
114 StaticDataFreeList
*freelist
;
117 /* Controls access to the 'threads' hash table */
118 static void mono_threads_lock (void);
119 static void mono_threads_unlock (void);
120 static MonoCoopMutex threads_mutex
;
122 /* Controls access to the 'joinable_threads' hash table */
123 #define joinable_threads_lock() mono_os_mutex_lock (&joinable_threads_mutex)
124 #define joinable_threads_unlock() mono_os_mutex_unlock (&joinable_threads_mutex)
125 static mono_mutex_t joinable_threads_mutex
;
127 /* Holds current status of static data heap */
128 static StaticDataInfo thread_static_info
;
129 static StaticDataInfo context_static_info
;
131 /* The hash of existing threads (key is thread ID, value is
132 * MonoInternalThread*) that need joining before exit
134 static MonoGHashTable
*threads
=NULL
;
136 /* List of app context GC handles.
137 * Added to from ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext ().
139 static GHashTable
*contexts
= NULL
;
141 /* Cleanup queue for contexts. */
142 static MonoReferenceQueue
*context_queue
;
145 * Threads which are starting up and they are not in the 'threads' hash yet.
146 * When mono_thread_attach_internal is called for a thread, it will be removed from this hash table.
147 * Protected by mono_threads_lock ().
149 static MonoGHashTable
*threads_starting_up
= NULL
;
152 /* Protected by the threads lock */
153 static GHashTable
*joinable_threads
;
154 static int joinable_thread_count
;
156 #define SET_CURRENT_OBJECT(x) mono_tls_set_thread (x)
157 #define GET_CURRENT_OBJECT() (MonoInternalThread*) mono_tls_get_thread ()
159 /* function called at thread start */
160 static MonoThreadStartCB mono_thread_start_cb
= NULL
;
162 /* function called at thread attach */
163 static MonoThreadAttachCB mono_thread_attach_cb
= NULL
;
165 /* function called at thread cleanup */
166 static MonoThreadCleanupFunc mono_thread_cleanup_fn
= NULL
;
168 /* The default stack size for each thread */
169 static guint32 default_stacksize
= 0;
170 #define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize)
172 static void context_adjust_static_data (MonoAppContext
*ctx
);
173 static void mono_free_static_data (gpointer
* static_data
);
174 static void mono_init_static_data_info (StaticDataInfo
*static_data
);
175 static guint32
mono_alloc_static_data_slot (StaticDataInfo
*static_data
, guint32 size
, guint32 align
);
176 static gboolean
mono_thread_resume (MonoInternalThread
* thread
);
177 static void async_abort_internal (MonoInternalThread
*thread
, gboolean install_async_abort
);
178 static void self_abort_internal (MonoError
*error
);
179 static void async_suspend_internal (MonoInternalThread
*thread
, gboolean interrupt
);
180 static void self_suspend_internal (void);
182 static MonoException
* mono_thread_execute_interruption (void);
183 static void ref_stack_destroy (gpointer rs
);
185 /* Spin lock for InterlockedXXX 64 bit functions */
186 #define mono_interlocked_lock() mono_os_mutex_lock (&interlocked_mutex)
187 #define mono_interlocked_unlock() mono_os_mutex_unlock (&interlocked_mutex)
188 static mono_mutex_t interlocked_mutex
;
190 /* global count of thread interruptions requested */
191 static gint32 thread_interruption_requested
= 0;
193 /* Event signaled when a thread changes its background mode */
194 static MonoOSEvent background_change_event
;
196 static gboolean shutting_down
= FALSE
;
198 static gint32 managed_thread_id_counter
= 0;
200 /* Class lazy loading functions */
201 static GENERATE_GET_CLASS_WITH_CACHE (appdomain_unloaded_exception
, "System", "AppDomainUnloadedException")
204 mono_threads_lock (void)
206 mono_locks_coop_acquire (&threads_mutex
, ThreadsLock
);
210 mono_threads_unlock (void)
212 mono_locks_coop_release (&threads_mutex
, ThreadsLock
);
217 get_next_managed_thread_id (void)
219 return InterlockedIncrement (&managed_thread_id_counter
);
223 * We separate interruptions/exceptions into either sync (they can be processed anytime,
224 * normally as soon as they are set, and are set by the same thread) and async (they can't
225 * be processed inside abort protected blocks and are normally set by other threads). We
226 * can have both a pending sync and async interruption. In this case, the sync exception is
227 * processed first. Since we clean sync flag first, mono_thread_execute_interruption must
228 * also handle all sync type exceptions before the async type exceptions.
231 INTERRUPT_SYNC_REQUESTED_BIT
= 0x1,
232 INTERRUPT_ASYNC_REQUESTED_BIT
= 0x2,
233 INTERRUPT_REQUESTED_MASK
= 0x3,
234 ABORT_PROT_BLOCK_SHIFT
= 2,
235 ABORT_PROT_BLOCK_BITS
= 8,
236 ABORT_PROT_BLOCK_MASK
= (((1 << ABORT_PROT_BLOCK_BITS
) - 1) << ABORT_PROT_BLOCK_SHIFT
)
240 mono_thread_get_abort_prot_block_count (MonoInternalThread
*thread
)
242 gsize state
= thread
->thread_state
;
243 return (state
& ABORT_PROT_BLOCK_MASK
) >> ABORT_PROT_BLOCK_SHIFT
;
247 mono_threads_begin_abort_protected_block (void)
249 MonoInternalThread
*thread
= mono_thread_internal_current ();
250 gsize old_state
, new_state
;
253 old_state
= thread
->thread_state
;
255 new_val
= ((old_state
& ABORT_PROT_BLOCK_MASK
) >> ABORT_PROT_BLOCK_SHIFT
) + 1;
256 //bounds check abort_prot_count
257 g_assert (new_val
> 0);
258 g_assert (new_val
< (1 << ABORT_PROT_BLOCK_BITS
));
260 new_state
= old_state
+ (1 << ABORT_PROT_BLOCK_SHIFT
);
261 } while (InterlockedCompareExchangePointer ((volatile gpointer
)&thread
->thread_state
, (gpointer
)new_state
, (gpointer
)old_state
) != (gpointer
)old_state
);
265 mono_thread_state_has_interruption (gsize state
)
267 /* pending exception, self abort */
268 if (state
& INTERRUPT_SYNC_REQUESTED_BIT
)
271 /* abort, interruption, suspend */
272 if ((state
& INTERRUPT_ASYNC_REQUESTED_BIT
) && !(state
& ABORT_PROT_BLOCK_MASK
))
279 mono_threads_end_abort_protected_block (void)
281 MonoInternalThread
*thread
= mono_thread_internal_current ();
282 gsize old_state
, new_state
;
284 old_state
= thread
->thread_state
;
286 //bounds check abort_prot_count
287 int new_val
= ((old_state
& ABORT_PROT_BLOCK_MASK
) >> ABORT_PROT_BLOCK_SHIFT
) - 1;
288 g_assert (new_val
>= 0);
289 g_assert (new_val
< (1 << ABORT_PROT_BLOCK_BITS
));
291 new_state
= old_state
- (1 << ABORT_PROT_BLOCK_SHIFT
);
292 } while (InterlockedCompareExchangePointer ((volatile gpointer
)&thread
->thread_state
, (gpointer
)new_state
, (gpointer
)old_state
) != (gpointer
)old_state
);
294 return mono_thread_state_has_interruption (new_state
);
298 mono_thread_get_interruption_requested (MonoInternalThread
*thread
)
300 gsize state
= thread
->thread_state
;
302 return mono_thread_state_has_interruption (state
);
306 * Returns TRUE is there was a state change
307 * We clear a single interruption request, sync has priority.
310 mono_thread_clear_interruption_requested (MonoInternalThread
*thread
)
312 gsize old_state
, new_state
;
314 old_state
= thread
->thread_state
;
316 // no interruption to process
317 if (!(old_state
& INTERRUPT_SYNC_REQUESTED_BIT
) &&
318 (!(old_state
& INTERRUPT_ASYNC_REQUESTED_BIT
) || (old_state
& ABORT_PROT_BLOCK_MASK
)))
321 if (old_state
& INTERRUPT_SYNC_REQUESTED_BIT
)
322 new_state
= old_state
& ~INTERRUPT_SYNC_REQUESTED_BIT
;
324 new_state
= old_state
& ~INTERRUPT_ASYNC_REQUESTED_BIT
;
325 } while (InterlockedCompareExchangePointer ((volatile gpointer
)&thread
->thread_state
, (gpointer
)new_state
, (gpointer
)old_state
) != (gpointer
)old_state
);
329 /* Returns TRUE is there was a state change and the interruption can be processed */
331 mono_thread_set_interruption_requested (MonoInternalThread
*thread
)
333 //always force when the current thread is doing it to itself.
334 gboolean sync
= thread
== mono_thread_internal_current ();
335 gsize old_state
, new_state
;
337 old_state
= thread
->thread_state
;
340 if ((sync
&& (old_state
& INTERRUPT_SYNC_REQUESTED_BIT
)) ||
341 (!sync
&& (old_state
& INTERRUPT_ASYNC_REQUESTED_BIT
)))
345 new_state
= old_state
| INTERRUPT_SYNC_REQUESTED_BIT
;
347 new_state
= old_state
| INTERRUPT_ASYNC_REQUESTED_BIT
;
348 } while (InterlockedCompareExchangePointer ((volatile gpointer
)&thread
->thread_state
, (gpointer
)new_state
, (gpointer
)old_state
) != (gpointer
)old_state
);
350 return sync
|| !(new_state
& ABORT_PROT_BLOCK_MASK
);
353 static inline MonoNativeThreadId
354 thread_get_tid (MonoInternalThread
*thread
)
356 /* We store the tid as a guint64 to keep the object layout constant between platforms */
357 return MONO_UINT_TO_NATIVE_THREAD_ID (thread
->tid
);
360 static void ensure_synch_cs_set (MonoInternalThread
*thread
)
362 MonoCoopMutex
*synch_cs
;
364 if (thread
->synch_cs
!= NULL
) {
368 synch_cs
= g_new0 (MonoCoopMutex
, 1);
369 mono_coop_mutex_init_recursive (synch_cs
);
371 if (InterlockedCompareExchangePointer ((gpointer
*)&thread
->synch_cs
,
372 synch_cs
, NULL
) != NULL
) {
373 /* Another thread must have installed this CS */
374 mono_coop_mutex_destroy (synch_cs
);
380 lock_thread (MonoInternalThread
*thread
)
382 if (!thread
->synch_cs
)
383 ensure_synch_cs_set (thread
);
385 g_assert (thread
->synch_cs
);
387 mono_coop_mutex_lock (thread
->synch_cs
);
391 unlock_thread (MonoInternalThread
*thread
)
393 mono_coop_mutex_unlock (thread
->synch_cs
);
396 static inline gboolean
397 is_appdomainunloaded_exception (MonoClass
*klass
)
399 return klass
== mono_class_get_appdomain_unloaded_exception_class ();
402 static inline gboolean
403 is_threadabort_exception (MonoClass
*klass
)
405 return klass
== mono_defaults
.threadabortexception_class
;
409 * A special static data offset (guint32) consists of 3 parts:
411 * [0] 6-bit index into the array of chunks.
412 * [6] 25-bit offset into the array.
413 * [31] Bit indicating thread or context static.
418 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
429 } SpecialStaticOffset
;
431 #define SPECIAL_STATIC_OFFSET_TYPE_THREAD 0
432 #define SPECIAL_STATIC_OFFSET_TYPE_CONTEXT 1
434 #define MAKE_SPECIAL_STATIC_OFFSET(index, offset, type) \
435 ((SpecialStaticOffset) { .fields = { (index), (offset), (type) } }.raw)
436 #define ACCESS_SPECIAL_STATIC_OFFSET(x,f) \
437 (((SpecialStaticOffset *) &(x))->fields.f)
440 get_thread_static_data (MonoInternalThread
*thread
, guint32 offset
)
442 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset
, type
) == SPECIAL_STATIC_OFFSET_TYPE_THREAD
);
444 int idx
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, index
);
445 int off
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, offset
);
447 return ((char *) thread
->static_data
[idx
]) + off
;
451 get_context_static_data (MonoAppContext
*ctx
, guint32 offset
)
453 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset
, type
) == SPECIAL_STATIC_OFFSET_TYPE_CONTEXT
);
455 int idx
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, index
);
456 int off
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, offset
);
458 return ((char *) ctx
->static_data
[idx
]) + off
;
462 get_current_thread_ptr_for_domain (MonoDomain
*domain
, MonoInternalThread
*thread
)
464 static MonoClassField
*current_thread_field
= NULL
;
468 if (!current_thread_field
) {
469 current_thread_field
= mono_class_get_field_from_name (mono_defaults
.thread_class
, "current_thread");
470 g_assert (current_thread_field
);
473 mono_class_vtable (domain
, mono_defaults
.thread_class
);
474 mono_domain_lock (domain
);
475 offset
= GPOINTER_TO_UINT (g_hash_table_lookup (domain
->special_static_fields
, current_thread_field
));
476 mono_domain_unlock (domain
);
479 return (MonoThread
**)get_thread_static_data (thread
, offset
);
483 set_current_thread_for_domain (MonoDomain
*domain
, MonoInternalThread
*thread
, MonoThread
*current
)
485 MonoThread
**current_thread_ptr
= get_current_thread_ptr_for_domain (domain
, thread
);
487 g_assert (current
->obj
.vtable
->domain
== domain
);
489 g_assert (!*current_thread_ptr
);
490 *current_thread_ptr
= current
;
494 create_thread_object (MonoDomain
*domain
, MonoInternalThread
*internal
)
500 vtable
= mono_class_vtable (domain
, mono_defaults
.thread_class
);
503 thread
= (MonoThread
*)mono_object_new_mature (vtable
, &error
);
504 /* only possible failure mode is OOM, from which we don't expect to recover. */
505 mono_error_assert_ok (&error
);
507 MONO_OBJECT_SETREF (thread
, internal_thread
, internal
);
512 static MonoInternalThread
*
513 create_internal_thread_object (void)
516 MonoInternalThread
*thread
;
519 vt
= mono_class_vtable (mono_get_root_domain (), mono_defaults
.internal_thread_class
);
520 thread
= (MonoInternalThread
*) mono_object_new_mature (vt
, &error
);
521 /* only possible failure mode is OOM, from which we don't exect to recover */
522 mono_error_assert_ok (&error
);
524 thread
->synch_cs
= g_new0 (MonoCoopMutex
, 1);
525 mono_coop_mutex_init_recursive (thread
->synch_cs
);
527 thread
->apartment_state
= ThreadApartmentState_Unknown
;
528 thread
->managed_id
= get_next_managed_thread_id ();
529 if (mono_gc_is_moving ()) {
530 thread
->thread_pinning_ref
= thread
;
531 MONO_GC_REGISTER_ROOT_PINNING (thread
->thread_pinning_ref
, MONO_ROOT_SOURCE_THREADING
, "thread pinning reference");
534 thread
->priority
= MONO_THREAD_PRIORITY_NORMAL
;
536 thread
->suspended
= g_new0 (MonoOSEvent
, 1);
537 mono_os_event_init (thread
->suspended
, TRUE
);
543 mono_thread_internal_set_priority (MonoInternalThread
*internal
, MonoThreadPriority priority
)
547 g_assert (priority
>= MONO_THREAD_PRIORITY_LOWEST
);
548 g_assert (priority
<= MONO_THREAD_PRIORITY_HIGHEST
);
549 g_assert (MONO_THREAD_PRIORITY_LOWEST
< MONO_THREAD_PRIORITY_HIGHEST
);
554 g_assert (internal
->native_handle
);
556 res
= SetThreadPriority (internal
->native_handle
, priority
- 2);
558 g_error ("%s: SetThreadPriority failed, error %d", __func__
, GetLastError ());
559 #else /* HOST_WIN32 */
562 struct sched_param param
;
565 tid
= thread_get_tid (internal
);
567 res
= pthread_getschedparam (tid
, &policy
, ¶m
);
569 g_error ("%s: pthread_getschedparam failed, error: \"%s\" (%d)", __func__
, g_strerror (res
), res
);
571 #ifdef _POSIX_PRIORITY_SCHEDULING
574 /* Necessary to get valid priority range */
576 min
= sched_get_priority_min (policy
);
577 max
= sched_get_priority_max (policy
);
579 if (max
> 0 && min
>= 0 && max
> min
) {
580 double srange
, drange
, sposition
, dposition
;
581 srange
= MONO_THREAD_PRIORITY_HIGHEST
- MONO_THREAD_PRIORITY_LOWEST
;
583 sposition
= priority
- MONO_THREAD_PRIORITY_LOWEST
;
584 dposition
= (sposition
/ srange
) * drange
;
585 param
.sched_priority
= (int)(dposition
+ min
);
592 param
.sched_priority
= 50;
598 param
.sched_priority
= 0;
601 g_warning ("%s: unknown policy %d", __func__
, policy
);
606 res
= pthread_setschedparam (tid
, policy
, ¶m
);
609 g_warning ("%s: pthread_setschedparam failed, error: \"%s\" (%d)", __func__
, g_strerror (res
), res
);
612 g_error ("%s: pthread_setschedparam failed, error: \"%s\" (%d)", __func__
, g_strerror (res
), res
);
614 #endif /* HOST_WIN32 */
618 mono_alloc_static_data (gpointer
**static_data_ptr
, guint32 offset
, gboolean threadlocal
);
621 mono_thread_attach_internal (MonoThread
*thread
, gboolean force_attach
, gboolean force_domain
)
623 MonoThreadInfo
*info
;
624 MonoInternalThread
*internal
;
625 MonoDomain
*domain
, *root_domain
;
629 info
= mono_thread_info_current ();
631 internal
= thread
->internal_thread
;
632 internal
->handle
= mono_threads_open_thread_handle (info
->handle
);
634 internal
->native_handle
= OpenThread (THREAD_ALL_ACCESS
, FALSE
, GetCurrentThreadId ());
636 internal
->tid
= MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ());
637 internal
->thread_info
= info
;
638 internal
->small_id
= info
->small_id
;
640 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT
") Setting current_object_key to %p", __func__
, mono_native_thread_id_get (), internal
));
642 SET_CURRENT_OBJECT (internal
);
644 domain
= mono_object_domain (thread
);
646 mono_thread_push_appdomain_ref (domain
);
647 if (!mono_domain_set (domain
, force_domain
)) {
648 mono_thread_pop_appdomain_ref ();
652 mono_threads_lock ();
654 if (threads_starting_up
)
655 mono_g_hash_table_remove (threads_starting_up
, thread
);
657 if (shutting_down
&& !force_attach
) {
658 mono_threads_unlock ();
659 mono_thread_pop_appdomain_ref ();
664 threads
= mono_g_hash_table_new_type (NULL
, NULL
, MONO_HASH_VALUE_GC
, MONO_ROOT_SOURCE_THREADING
, "threads table");
667 /* We don't need to duplicate thread->handle, because it is
668 * only closed when the thread object is finalized by the GC. */
669 mono_g_hash_table_insert (threads
, (gpointer
)(gsize
)(internal
->tid
), internal
);
671 /* We have to do this here because mono_thread_start_cb
672 * requires that root_domain_thread is set up. */
673 if (thread_static_info
.offset
|| thread_static_info
.idx
> 0) {
674 /* get the current allocated size */
675 guint32 offset
= MAKE_SPECIAL_STATIC_OFFSET (thread_static_info
.idx
, thread_static_info
.offset
, 0);
676 mono_alloc_static_data (&internal
->static_data
, offset
, TRUE
);
679 mono_threads_unlock ();
681 root_domain
= mono_get_root_domain ();
683 g_assert (!internal
->root_domain_thread
);
684 if (domain
!= root_domain
)
685 MONO_OBJECT_SETREF (internal
, root_domain_thread
, create_thread_object (root_domain
, internal
));
687 MONO_OBJECT_SETREF (internal
, root_domain_thread
, thread
);
689 if (domain
!= root_domain
)
690 set_current_thread_for_domain (root_domain
, internal
, internal
->root_domain_thread
);
692 set_current_thread_for_domain (domain
, internal
, thread
);
694 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT
" (handle %p)", __func__
, internal
->tid
, internal
->handle
));
702 MonoObject
*start_delegate
;
703 MonoObject
*start_delegate_arg
;
704 MonoThreadStart start_func
;
705 gpointer start_func_arg
;
706 gboolean force_attach
;
708 MonoCoopSem registered
;
711 static guint32 WINAPI
start_wrapper_internal(StartInfo
*start_info
, gsize
*stack_ptr
)
714 MonoThreadStart start_func
;
715 void *start_func_arg
;
718 * We don't create a local to hold start_info->thread, so hopefully it won't get pinned during a
722 MonoInternalThread
*internal
;
723 MonoObject
*start_delegate
;
724 MonoObject
*start_delegate_arg
;
727 thread
= start_info
->thread
;
728 internal
= thread
->internal_thread
;
729 domain
= mono_object_domain (start_info
->thread
);
731 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT
") Start wrapper", __func__
, mono_native_thread_id_get ()));
733 if (!mono_thread_attach_internal (thread
, start_info
->force_attach
, FALSE
)) {
734 start_info
->failed
= TRUE
;
736 mono_coop_sem_post (&start_info
->registered
);
738 if (InterlockedDecrement (&start_info
->ref
) == 0) {
739 mono_coop_sem_destroy (&start_info
->registered
);
746 mono_thread_internal_set_priority (internal
, internal
->priority
);
750 start_delegate
= start_info
->start_delegate
;
751 start_delegate_arg
= start_info
->start_delegate_arg
;
752 start_func
= start_info
->start_func
;
753 start_func_arg
= start_info
->start_func_arg
;
755 /* This MUST be called before any managed code can be
756 * executed, as it calls the callback function that (for the
757 * jit) sets the lmf marker.
760 if (mono_thread_start_cb
)
761 mono_thread_start_cb (tid
, stack_ptr
, start_func
);
763 /* On 2.0 profile (and higher), set explicitly since state might have been
765 if (internal
->apartment_state
== ThreadApartmentState_Unknown
)
766 internal
->apartment_state
= ThreadApartmentState_MTA
;
768 mono_thread_init_apartment_state ();
770 /* Let the thread that called Start() know we're ready */
771 mono_coop_sem_post (&start_info
->registered
);
773 if (InterlockedDecrement (&start_info
->ref
) == 0) {
774 mono_coop_sem_destroy (&start_info
->registered
);
778 /* start_info is not valid anymore */
782 * Call this after calling start_notify, since the profiler callback might want
783 * to lock the thread, and the lock is held by thread_start () which waits for
786 mono_profiler_thread_start (tid
);
788 /* if the name was set before starting, we didn't invoke the profiler callback */
789 if (internal
->name
) {
790 char *tname
= g_utf16_to_utf8 (internal
->name
, internal
->name_len
, NULL
, NULL
, NULL
);
791 mono_profiler_thread_name (internal
->tid
, tname
);
792 mono_native_thread_set_name (MONO_UINT_TO_NATIVE_THREAD_ID (internal
->tid
), tname
);
796 /* start_func is set only for unmanaged start functions */
798 start_func (start_func_arg
);
802 g_assert (start_delegate
!= NULL
);
804 /* we may want to handle the exception here. See comment below on unhandled exceptions */
805 args
[0] = (gpointer
) start_delegate_arg
;
806 mono_runtime_delegate_invoke_checked (start_delegate
, args
, &error
);
808 if (!mono_error_ok (&error
)) {
809 MonoException
*ex
= mono_error_convert_to_exception (&error
);
811 g_assert (ex
!= NULL
);
812 MonoClass
*klass
= mono_object_get_class (&ex
->object
);
813 if ((mono_runtime_unhandled_exception_policy_get () != MONO_UNHANDLED_POLICY_LEGACY
) &&
814 !is_threadabort_exception (klass
)) {
815 mono_unhandled_exception (&ex
->object
);
816 mono_invoke_unhandled_exception_hook (&ex
->object
);
817 g_assert_not_reached ();
820 mono_error_cleanup (&error
);
824 /* If the thread calls ExitThread at all, this remaining code
825 * will not be executed, but the main thread will eventually
826 * call mono_thread_detach_internal() on this thread's behalf.
829 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT
") Start wrapper terminating", __func__
, mono_native_thread_id_get ()));
831 /* Do any cleanup needed for apartment state. This
832 * cannot be done in mono_thread_detach_internal since
833 * mono_thread_detach_internal could be called for a
834 * thread other than the current thread.
835 * mono_thread_cleanup_apartment_state cleans up apartment
836 * for the current thead */
837 mono_thread_cleanup_apartment_state ();
839 mono_thread_detach_internal (internal
);
847 start_wrapper (gpointer data
)
849 StartInfo
*start_info
;
850 MonoThreadInfo
*info
;
853 start_info
= (StartInfo
*) data
;
854 g_assert (start_info
);
856 info
= mono_thread_info_attach (&res
);
857 info
->runtime_thread
= TRUE
;
859 /* Run the actual main function of the thread */
860 res
= start_wrapper_internal (start_info
, &res
);
862 mono_thread_info_exit (res
);
864 g_assert_not_reached ();
870 * Common thread creation code.
871 * LOCKING: Acquires the threads lock.
874 create_thread (MonoThread
*thread
, MonoInternalThread
*internal
, MonoObject
*start_delegate
, MonoThreadStart start_func
, gpointer start_func_arg
,
875 MonoThreadCreateFlags flags
, MonoError
*error
)
877 StartInfo
*start_info
= NULL
;
878 MonoNativeThreadId tid
;
880 gsize stack_set_size
;
883 g_assert (!start_func
&& !start_func_arg
);
885 g_assert (!start_delegate
);
887 if (flags
& MONO_THREAD_CREATE_FLAGS_THREADPOOL
) {
888 g_assert (!(flags
& MONO_THREAD_CREATE_FLAGS_DEBUGGER
));
889 g_assert (!(flags
& MONO_THREAD_CREATE_FLAGS_FORCE_CREATE
));
891 if (flags
& MONO_THREAD_CREATE_FLAGS_DEBUGGER
) {
892 g_assert (!(flags
& MONO_THREAD_CREATE_FLAGS_THREADPOOL
));
893 g_assert (!(flags
& MONO_THREAD_CREATE_FLAGS_FORCE_CREATE
));
897 * Join joinable threads to prevent running out of threads since the finalizer
898 * thread might be blocked/backlogged.
900 mono_threads_join_threads ();
904 mono_threads_lock ();
905 if (shutting_down
&& !(flags
& MONO_THREAD_CREATE_FLAGS_FORCE_CREATE
)) {
906 mono_threads_unlock ();
909 if (threads_starting_up
== NULL
) {
910 threads_starting_up
= mono_g_hash_table_new_type (NULL
, NULL
, MONO_HASH_KEY_VALUE_GC
, MONO_ROOT_SOURCE_THREADING
, "starting threads table");
912 mono_g_hash_table_insert (threads_starting_up
, thread
, thread
);
913 mono_threads_unlock ();
915 internal
->threadpool_thread
= flags
& MONO_THREAD_CREATE_FLAGS_THREADPOOL
;
916 if (internal
->threadpool_thread
)
917 mono_thread_set_state (internal
, ThreadState_Background
);
919 internal
->debugger_thread
= flags
& MONO_THREAD_CREATE_FLAGS_DEBUGGER
;
921 start_info
= g_new0 (StartInfo
, 1);
923 start_info
->thread
= thread
;
924 start_info
->start_delegate
= start_delegate
;
925 start_info
->start_delegate_arg
= thread
->start_obj
;
926 start_info
->start_func
= start_func
;
927 start_info
->start_func_arg
= start_func_arg
;
928 start_info
->force_attach
= flags
& MONO_THREAD_CREATE_FLAGS_FORCE_CREATE
;
929 start_info
->failed
= FALSE
;
930 mono_coop_sem_init (&start_info
->registered
, 0);
932 if (flags
!= MONO_THREAD_CREATE_FLAGS_SMALL_STACK
)
933 stack_set_size
= default_stacksize_for_thread (internal
);
937 if (!mono_thread_platform_create_thread (start_wrapper
, start_info
, &stack_set_size
, &tid
)) {
938 /* The thread couldn't be created, so set an exception */
939 mono_threads_lock ();
940 mono_g_hash_table_remove (threads_starting_up
, thread
);
941 mono_threads_unlock ();
942 mono_error_set_execution_engine (error
, "Couldn't create thread. Error 0x%x", mono_w32error_get_last());
943 /* ref is not going to be decremented in start_wrapper_internal */
944 InterlockedDecrement (&start_info
->ref
);
949 internal
->stack_size
= (int) stack_set_size
;
951 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT
") Launching thread %p (%"G_GSIZE_FORMAT
")", __func__
, mono_native_thread_id_get (), internal
, (gsize
)internal
->tid
));
954 * Wait for the thread to set up its TLS data etc, so
955 * theres no potential race condition if someone tries
956 * to look up the data believing the thread has
960 mono_coop_sem_wait (&start_info
->registered
, MONO_SEM_FLAGS_NONE
);
962 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
));
964 ret
= !start_info
->failed
;
967 if (InterlockedDecrement (&start_info
->ref
) == 0) {
968 mono_coop_sem_destroy (&start_info
->registered
);
975 void mono_thread_new_init (intptr_t tid
, gpointer stack_start
, gpointer func
)
977 if (mono_thread_start_cb
) {
978 mono_thread_start_cb (tid
, stack_start
, func
);
982 void mono_threads_set_default_stacksize (guint32 stacksize
)
984 default_stacksize
= stacksize
;
987 guint32
mono_threads_get_default_stacksize (void)
989 return default_stacksize
;
993 * mono_thread_create_internal:
995 * ARG should not be a GC reference.
998 mono_thread_create_internal (MonoDomain
*domain
, gpointer func
, gpointer arg
, MonoThreadCreateFlags flags
, MonoError
*error
)
1001 MonoInternalThread
*internal
;
1006 internal
= create_internal_thread_object ();
1008 thread
= create_thread_object (domain
, internal
);
1010 LOCK_THREAD (internal
);
1012 res
= create_thread (thread
, internal
, NULL
, (MonoThreadStart
) func
, arg
, flags
, error
);
1014 UNLOCK_THREAD (internal
);
1016 return_val_if_nok (error
, NULL
);
1021 mono_thread_create (MonoDomain
*domain
, gpointer func
, gpointer arg
)
1024 if (!mono_thread_create_checked (domain
, func
, arg
, &error
))
1025 mono_error_cleanup (&error
);
1029 mono_thread_create_checked (MonoDomain
*domain
, gpointer func
, gpointer arg
, MonoError
*error
)
1031 return (NULL
!= mono_thread_create_internal (domain
, func
, arg
, MONO_THREAD_CREATE_FLAGS_NONE
, error
));
1035 mono_thread_attach (MonoDomain
*domain
)
1037 MonoThread
*thread
= mono_thread_attach_full (domain
, FALSE
);
1043 mono_thread_attach_full (MonoDomain
*domain
, gboolean force_attach
)
1045 MonoInternalThread
*internal
;
1047 MonoThreadInfo
*info
;
1048 MonoNativeThreadId tid
;
1051 if (mono_thread_internal_current_is_attached ()) {
1052 if (domain
!= mono_domain_get ())
1053 mono_domain_set (domain
, TRUE
);
1054 /* Already attached */
1055 return mono_thread_current ();
1058 info
= mono_thread_info_attach (&stack_ptr
);
1061 tid
=mono_native_thread_id_get ();
1063 internal
= create_internal_thread_object ();
1065 thread
= create_thread_object (domain
, internal
);
1067 if (!mono_thread_attach_internal (thread
, force_attach
, TRUE
)) {
1068 /* Mono is shutting down, so just wait for the end */
1070 mono_thread_info_sleep (10000, NULL
);
1073 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT
" (handle %p)", __func__
, tid
, internal
->handle
));
1075 if (mono_thread_attach_cb
) {
1079 mono_thread_info_get_stack_bounds (&staddr
, &stsize
);
1082 mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid
), &stack_ptr
);
1084 mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid
), staddr
+ stsize
);
1087 /* Can happen when we attach the profiler helper thread in order to heapshot. */
1088 if (!mono_thread_info_current ()->tools_thread
)
1089 // FIXME: Need a separate callback
1090 mono_profiler_thread_start (MONO_NATIVE_THREAD_ID_TO_UINT (tid
));
1096 mono_thread_detach_internal (MonoInternalThread
*thread
)
1100 g_assert (thread
!= NULL
);
1102 THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT
")", __func__
, thread
, (gsize
)thread
->tid
));
1105 mono_w32mutex_abandon ();
1108 if (thread
->abort_state_handle
) {
1109 mono_gchandle_free (thread
->abort_state_handle
);
1110 thread
->abort_state_handle
= 0;
1113 thread
->abort_exc
= NULL
;
1114 thread
->current_appcontext
= NULL
;
1117 * thread->synch_cs can be NULL if this was called after
1118 * ves_icall_System_Threading_InternalThread_Thread_free_internal.
1119 * This can happen only during shutdown.
1120 * The shutting_down flag is not always set, so we can't assert on it.
1122 if (thread
->synch_cs
)
1123 LOCK_THREAD (thread
);
1125 thread
->state
|= ThreadState_Stopped
;
1126 thread
->state
&= ~ThreadState_Background
;
1128 if (thread
->synch_cs
)
1129 UNLOCK_THREAD (thread
);
1132 An interruption request has leaked to cleanup. Adjust the global counter.
1134 This can happen is the abort source thread finds the abortee (this) thread
1135 in unmanaged code. If this thread never trips back to managed code or check
1136 the local flag it will be left set and positively unbalance the global counter.
1138 Leaving the counter unbalanced will cause a performance degradation since all threads
1139 will now keep checking their local flags all the time.
1141 if (mono_thread_clear_interruption_requested (thread
))
1142 InterlockedDecrement (&thread_interruption_requested
);
1144 mono_threads_lock ();
1148 } else if (mono_g_hash_table_lookup (threads
, (gpointer
)thread
->tid
) != thread
) {
1149 /* We have to check whether the thread object for the
1150 * tid is still the same in the table because the
1151 * thread might have been destroyed and the tid reused
1152 * in the meantime, in which case the tid would be in
1153 * the table, but with another thread object.
1157 mono_g_hash_table_remove (threads
, (gpointer
)thread
->tid
);
1161 mono_threads_unlock ();
1163 /* Don't close the handle here, wait for the object finalizer
1164 * to do it. Otherwise, the following race condition applies:
1166 * 1) Thread exits (and mono_thread_detach_internal() closes the handle)
1168 * 2) Some other handle is reassigned the same slot
1170 * 3) Another thread tries to join the first thread, and
1171 * blocks waiting for the reassigned handle to be signalled
1172 * (which might never happen). This is possible, because the
1173 * thread calling Join() still has a reference to the first
1177 /* if the thread is not in the hash it has been removed already */
1179 mono_domain_unset ();
1180 mono_memory_barrier ();
1182 if (mono_thread_cleanup_fn
)
1183 mono_thread_cleanup_fn (thread_get_tid (thread
));
1188 mono_release_type_locks (thread
);
1190 /* Can happen when we attach the profiler helper thread in order to heapshot. */
1191 if (!mono_thread_info_lookup (MONO_UINT_TO_NATIVE_THREAD_ID (thread
->tid
))->tools_thread
)
1192 mono_profiler_thread_end (thread
->tid
);
1194 mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
1197 * This will signal async signal handlers that the thread has exited.
1198 * The profiler callback needs this to be set, so it cannot be done earlier.
1200 mono_domain_unset ();
1201 mono_memory_barrier ();
1203 if (thread
== mono_thread_internal_current ())
1204 mono_thread_pop_appdomain_ref ();
1206 mono_free_static_data (thread
->static_data
);
1207 thread
->static_data
= NULL
;
1208 ref_stack_destroy (thread
->appdomain_refs
);
1209 thread
->appdomain_refs
= NULL
;
1211 g_assert (thread
->suspended
);
1212 mono_os_event_destroy (thread
->suspended
);
1213 g_free (thread
->suspended
);
1214 thread
->suspended
= NULL
;
1216 if (mono_thread_cleanup_fn
)
1217 mono_thread_cleanup_fn (thread_get_tid (thread
));
1219 mono_memory_barrier ();
1221 if (mono_gc_is_moving ()) {
1222 MONO_GC_UNREGISTER_ROOT (thread
->thread_pinning_ref
);
1223 thread
->thread_pinning_ref
= NULL
;
1227 SET_CURRENT_OBJECT (NULL
);
1228 mono_domain_unset ();
1230 /* Don't need to close the handle to this thread, even though we took a
1231 * reference in mono_thread_attach (), because the GC will do it
1232 * when the Thread object is finalised.
1237 mono_thread_detach (MonoThread
*thread
)
1240 mono_thread_detach_internal (thread
->internal_thread
);
1244 * mono_thread_detach_if_exiting:
1246 * Detach the current thread from the runtime if it is exiting, i.e. it is running pthread dtors.
1247 * This should be used at the end of embedding code which calls into managed code, and which
1248 * can be called from pthread dtors, like dealloc: implementations in objective-c.
1251 mono_thread_detach_if_exiting (void)
1253 if (mono_thread_info_is_exiting ()) {
1254 MonoInternalThread
*thread
;
1256 thread
= mono_thread_internal_current ();
1258 mono_thread_detach_internal (thread
);
1259 mono_thread_info_detach ();
1267 mono_thread_internal_current_is_attached (void)
1269 MonoInternalThread
*internal
;
1271 internal
= GET_CURRENT_OBJECT ();
1279 mono_thread_exit (void)
1281 MonoInternalThread
*thread
= mono_thread_internal_current ();
1283 THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT
")", __func__
, thread
, (gsize
)thread
->tid
));
1285 mono_thread_detach_internal (thread
);
1287 /* we could add a callback here for embedders to use. */
1288 if (mono_thread_get_main () && (thread
== mono_thread_get_main ()->internal_thread
))
1289 exit (mono_environment_exitcode_get ());
1291 mono_thread_info_exit (0);
1295 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread
*this_obj
)
1297 MonoInternalThread
*internal
;
1299 internal
= create_internal_thread_object ();
1301 internal
->state
= ThreadState_Unstarted
;
1303 InterlockedCompareExchangePointer ((volatile gpointer
*)&this_obj
->internal_thread
, internal
, NULL
);
1307 ves_icall_System_Threading_Thread_GetCurrentThread (void)
1309 return mono_thread_current ();
1313 ves_icall_System_Threading_Thread_Thread_internal (MonoThread
*this_obj
,
1317 MonoInternalThread
*internal
;
1320 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__
, this_obj
, start
));
1322 if (!this_obj
->internal_thread
)
1323 ves_icall_System_Threading_Thread_ConstructInternalThread (this_obj
);
1324 internal
= this_obj
->internal_thread
;
1326 LOCK_THREAD (internal
);
1328 if ((internal
->state
& ThreadState_Unstarted
) == 0) {
1329 UNLOCK_THREAD (internal
);
1330 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has already been started."));
1334 if ((internal
->state
& ThreadState_Aborted
) != 0) {
1335 UNLOCK_THREAD (internal
);
1339 res
= create_thread (this_obj
, internal
, start
, NULL
, NULL
, MONO_THREAD_CREATE_FLAGS_NONE
, &error
);
1341 mono_error_cleanup (&error
);
1342 UNLOCK_THREAD (internal
);
1346 internal
->state
&= ~ThreadState_Unstarted
;
1348 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT
" (handle %p)", __func__
, tid
, thread
));
1350 UNLOCK_THREAD (internal
);
1351 return internal
->handle
;
1355 * This is called from the finalizer of the internal thread object.
1358 ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread
*this_obj
)
1360 THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__
, this, this_obj
->handle
));
1363 * Since threads keep a reference to their thread object while running, by
1364 * the time this function is called, the thread has already exited/detached,
1365 * i.e. mono_thread_detach_internal () has ran. The exception is during
1366 * shutdown, when mono_thread_detach_internal () can be called after this.
1368 if (this_obj
->handle
) {
1369 mono_threads_close_thread_handle (this_obj
->handle
);
1370 this_obj
->handle
= NULL
;
1374 CloseHandle (this_obj
->native_handle
);
1377 if (this_obj
->synch_cs
) {
1378 MonoCoopMutex
*synch_cs
= this_obj
->synch_cs
;
1379 this_obj
->synch_cs
= NULL
;
1380 mono_coop_mutex_destroy (synch_cs
);
1384 if (this_obj
->name
) {
1385 void *name
= this_obj
->name
;
1386 this_obj
->name
= NULL
;
1392 ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms
)
1395 MonoInternalThread
*thread
= mono_thread_internal_current ();
1397 THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__
, ms
));
1399 if (mono_thread_current_check_pending_interrupt ())
1403 gboolean alerted
= FALSE
;
1405 mono_thread_set_state (thread
, ThreadState_WaitSleepJoin
);
1407 res
= mono_thread_info_sleep (ms
, &alerted
);
1409 mono_thread_clr_state (thread
, ThreadState_WaitSleepJoin
);
1412 MonoException
* exc
= mono_thread_execute_interruption ();
1414 mono_raise_exception (exc
);
1416 // FIXME: !MONO_INFINITE_WAIT
1417 if (ms
!= MONO_INFINITE_WAIT
)
1426 void ves_icall_System_Threading_Thread_SpinWait_nop (void)
1431 ves_icall_System_Threading_Thread_GetDomainID (void)
1433 return mono_domain_get()->domain_id
;
1437 ves_icall_System_Threading_Thread_Yield (void)
1439 return mono_thread_info_yield ();
1443 * mono_thread_get_name:
1445 * Return the name of the thread. NAME_LEN is set to the length of the name.
1446 * Return NULL if the thread has no name. The returned memory is owned by the
1450 mono_thread_get_name (MonoInternalThread
*this_obj
, guint32
*name_len
)
1454 LOCK_THREAD (this_obj
);
1456 if (!this_obj
->name
) {
1460 *name_len
= this_obj
->name_len
;
1461 res
= g_new (gunichar2
, this_obj
->name_len
);
1462 memcpy (res
, this_obj
->name
, sizeof (gunichar2
) * this_obj
->name_len
);
1465 UNLOCK_THREAD (this_obj
);
1471 * mono_thread_get_name_utf8:
1473 * Return the name of the thread in UTF-8.
1474 * Return NULL if the thread has no name.
1475 * The returned memory is owned by the caller.
1478 mono_thread_get_name_utf8 (MonoThread
*thread
)
1483 MonoInternalThread
*internal
= thread
->internal_thread
;
1484 if (internal
== NULL
)
1487 LOCK_THREAD (internal
);
1489 char *tname
= g_utf16_to_utf8 (internal
->name
, internal
->name_len
, NULL
, NULL
, NULL
);
1491 UNLOCK_THREAD (internal
);
1497 * mono_thread_get_managed_id:
1499 * Return the Thread.ManagedThreadId value of `thread`.
1500 * Returns -1 if `thread` is NULL.
1503 mono_thread_get_managed_id (MonoThread
*thread
)
1508 MonoInternalThread
*internal
= thread
->internal_thread
;
1509 if (internal
== NULL
)
1512 int32_t id
= internal
->managed_id
;
1518 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread
*this_obj
)
1523 error_init (&error
);
1525 LOCK_THREAD (this_obj
);
1527 if (!this_obj
->name
)
1530 str
= mono_string_new_utf16_checked (mono_domain_get (), this_obj
->name
, this_obj
->name_len
, &error
);
1532 UNLOCK_THREAD (this_obj
);
1534 if (mono_error_set_pending_exception (&error
))
1541 mono_thread_set_name_internal (MonoInternalThread
*this_obj
, MonoString
*name
, gboolean permanent
, gboolean reset
, MonoError
*error
)
1543 LOCK_THREAD (this_obj
);
1548 this_obj
->flags
&= ~MONO_THREAD_FLAG_NAME_SET
;
1549 } else if (this_obj
->flags
& MONO_THREAD_FLAG_NAME_SET
) {
1550 UNLOCK_THREAD (this_obj
);
1552 mono_error_set_invalid_operation (error
, "Thread.Name can only be set once.");
1555 if (this_obj
->name
) {
1556 g_free (this_obj
->name
);
1557 this_obj
->name_len
= 0;
1560 this_obj
->name
= g_memdup (mono_string_chars (name
), mono_string_length (name
) * sizeof (gunichar2
));
1561 this_obj
->name_len
= mono_string_length (name
);
1564 this_obj
->flags
|= MONO_THREAD_FLAG_NAME_SET
;
1567 this_obj
->name
= NULL
;
1570 UNLOCK_THREAD (this_obj
);
1572 if (this_obj
->name
&& this_obj
->tid
) {
1573 char *tname
= mono_string_to_utf8_checked (name
, error
);
1574 return_if_nok (error
);
1575 mono_profiler_thread_name (this_obj
->tid
, tname
);
1576 mono_native_thread_set_name (thread_get_tid (this_obj
), tname
);
1582 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread
*this_obj
, MonoString
*name
)
1585 mono_thread_set_name_internal (this_obj
, name
, TRUE
, FALSE
, &error
);
1586 mono_error_set_pending_exception (&error
);
1590 * ves_icall_System_Threading_Thread_GetPriority_internal:
1591 * @param this_obj: The MonoInternalThread on which to operate.
1593 * Gets the priority of the given thread.
1594 * @return: The priority of the given thread.
1597 ves_icall_System_Threading_Thread_GetPriority (MonoThread
*this_obj
)
1600 MonoInternalThread
*internal
= this_obj
->internal_thread
;
1602 LOCK_THREAD (internal
);
1603 priority
= internal
->priority
;
1604 UNLOCK_THREAD (internal
);
1610 * ves_icall_System_Threading_Thread_SetPriority_internal:
1611 * @param this_obj: The MonoInternalThread on which to operate.
1612 * @param priority: The priority to set.
1614 * Sets the priority of the given thread.
1617 ves_icall_System_Threading_Thread_SetPriority (MonoThread
*this_obj
, int priority
)
1619 MonoInternalThread
*internal
= this_obj
->internal_thread
;
1621 LOCK_THREAD (internal
);
1622 internal
->priority
= priority
;
1623 if (internal
->thread_info
!= NULL
)
1624 mono_thread_internal_set_priority (internal
, priority
);
1625 UNLOCK_THREAD (internal
);
1628 /* If the array is already in the requested domain, we just return it,
1629 otherwise we return a copy in that domain. */
1631 byte_array_to_domain (MonoArray
*arr
, MonoDomain
*domain
, MonoError
*error
)
1639 if (mono_object_domain (arr
) == domain
)
1642 copy
= mono_array_new_checked (domain
, mono_defaults
.byte_class
, arr
->max_length
, error
);
1643 memmove (mono_array_addr (copy
, guint8
, 0), mono_array_addr (arr
, guint8
, 0), arr
->max_length
);
1648 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray
*arr
)
1651 MonoArray
*result
= byte_array_to_domain (arr
, mono_get_root_domain (), &error
);
1652 mono_error_set_pending_exception (&error
);
1657 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray
*arr
)
1660 MonoArray
*result
= byte_array_to_domain (arr
, mono_domain_get (), &error
);
1661 mono_error_set_pending_exception (&error
);
1666 mono_thread_current (void)
1668 MonoDomain
*domain
= mono_domain_get ();
1669 MonoInternalThread
*internal
= mono_thread_internal_current ();
1670 MonoThread
**current_thread_ptr
;
1672 g_assert (internal
);
1673 current_thread_ptr
= get_current_thread_ptr_for_domain (domain
, internal
);
1675 if (!*current_thread_ptr
) {
1676 g_assert (domain
!= mono_get_root_domain ());
1677 *current_thread_ptr
= create_thread_object (domain
, internal
);
1679 return *current_thread_ptr
;
1682 /* Return the thread object belonging to INTERNAL in the current domain */
1684 mono_thread_current_for_thread (MonoInternalThread
*internal
)
1686 MonoDomain
*domain
= mono_domain_get ();
1687 MonoThread
**current_thread_ptr
;
1689 g_assert (internal
);
1690 current_thread_ptr
= get_current_thread_ptr_for_domain (domain
, internal
);
1692 if (!*current_thread_ptr
) {
1693 g_assert (domain
!= mono_get_root_domain ());
1694 *current_thread_ptr
= create_thread_object (domain
, internal
);
1696 return *current_thread_ptr
;
1700 mono_thread_internal_current (void)
1702 MonoInternalThread
*res
= GET_CURRENT_OBJECT ();
1703 THREAD_DEBUG (g_message ("%s: returning %p", __func__
, res
));
1707 static MonoThreadInfoWaitRet
1708 mono_join_uninterrupted (MonoThreadHandle
* thread_to_join
, gint32 ms
, MonoError
*error
)
1711 MonoThreadInfoWaitRet ret
;
1718 start
= (ms
== -1) ? 0 : mono_msec_ticks ();
1721 ret
= mono_thread_info_wait_one_handle (thread_to_join
, ms
, TRUE
);
1724 if (ret
!= MONO_THREAD_INFO_WAIT_RET_ALERTED
)
1727 exc
= mono_thread_execute_interruption ();
1729 mono_error_set_exception_instance (error
, exc
);
1736 /* Re-calculate ms according to the time passed */
1737 diff_ms
= (gint32
)(mono_msec_ticks () - start
);
1738 if (diff_ms
>= ms
) {
1739 ret
= MONO_THREAD_INFO_WAIT_RET_TIMEOUT
;
1742 wait
= ms
- diff_ms
;
1749 ves_icall_System_Threading_Thread_Join_internal(MonoThread
*this_obj
, int ms
)
1751 MonoInternalThread
*thread
= this_obj
->internal_thread
;
1752 MonoThreadHandle
*handle
= thread
->handle
;
1753 MonoInternalThread
*cur_thread
= mono_thread_internal_current ();
1757 if (mono_thread_current_check_pending_interrupt ())
1760 LOCK_THREAD (thread
);
1762 if ((thread
->state
& ThreadState_Unstarted
) != 0) {
1763 UNLOCK_THREAD (thread
);
1765 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started."));
1769 UNLOCK_THREAD (thread
);
1772 ms
=MONO_INFINITE_WAIT
;
1774 THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__
, handle
, ms
));
1776 mono_thread_set_state (cur_thread
, ThreadState_WaitSleepJoin
);
1778 ret
=mono_join_uninterrupted (handle
, ms
, &error
);
1780 mono_thread_clr_state (cur_thread
, ThreadState_WaitSleepJoin
);
1782 mono_error_set_pending_exception (&error
);
1784 if(ret
==MONO_THREAD_INFO_WAIT_RET_SUCCESS_0
) {
1785 THREAD_DEBUG (g_message ("%s: join successful", __func__
));
1790 THREAD_DEBUG (g_message ("%s: join failed", __func__
));
1795 #define MANAGED_WAIT_FAILED 0x7fffffff
1798 map_native_wait_result_to_managed (MonoW32HandleWaitRet val
, gsize numobjects
)
1800 if (val
>= MONO_W32HANDLE_WAIT_RET_SUCCESS_0
&& val
< MONO_W32HANDLE_WAIT_RET_SUCCESS_0
+ numobjects
) {
1801 return WAIT_OBJECT_0
+ (val
- MONO_W32HANDLE_WAIT_RET_SUCCESS_0
);
1802 } else if (val
>= MONO_W32HANDLE_WAIT_RET_ABANDONED_0
&& val
< MONO_W32HANDLE_WAIT_RET_ABANDONED_0
+ numobjects
) {
1803 return WAIT_ABANDONED_0
+ (val
- MONO_W32HANDLE_WAIT_RET_ABANDONED_0
);
1804 } else if (val
== MONO_W32HANDLE_WAIT_RET_ALERTED
) {
1805 return WAIT_IO_COMPLETION
;
1806 } else if (val
== MONO_W32HANDLE_WAIT_RET_TIMEOUT
) {
1807 return WAIT_TIMEOUT
;
1808 } else if (val
== MONO_W32HANDLE_WAIT_RET_FAILED
) {
1809 /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1810 return MANAGED_WAIT_FAILED
;
1812 g_error ("%s: unknown val value %d", __func__
, val
);
1816 static MonoW32HandleWaitRet
1817 mono_wait_uninterrupted (MonoInternalThread
*thread
, guint32 numhandles
, gpointer
*handles
, gboolean waitall
, gint32 ms
, MonoError
*error
)
1820 MonoW32HandleWaitRet ret
;
1827 start
= (ms
== -1) ? 0 : mono_100ns_ticks ();
1831 if (numhandles
!= 1)
1832 ret
= mono_w32handle_convert_wait_ret (WaitForMultipleObjectsEx (numhandles
, handles
, waitall
, wait
, TRUE
), numhandles
);
1834 ret
= mono_w32handle_convert_wait_ret (WaitForSingleObjectEx (handles
[0], ms
, TRUE
), 1);
1836 /* mono_w32handle_wait_multiple optimizes the case for numhandles == 1 */
1837 ret
= mono_w32handle_wait_multiple (handles
, numhandles
, waitall
, wait
, TRUE
);
1838 #endif /* HOST_WIN32 */
1841 if (ret
!= MONO_W32HANDLE_WAIT_RET_ALERTED
)
1844 exc
= mono_thread_execute_interruption ();
1846 mono_error_set_exception_instance (error
, exc
);
1853 /* Re-calculate ms according to the time passed */
1854 diff_ms
= (gint32
)((mono_100ns_ticks () - start
) / 10000);
1855 if (diff_ms
>= ms
) {
1856 ret
= MONO_W32HANDLE_WAIT_RET_TIMEOUT
;
1859 wait
= ms
- diff_ms
;
1865 gint32
ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray
*mono_handles
, gint32 ms
)
1870 MonoW32HandleWaitRet ret
;
1872 MonoObject
*waitHandle
;
1873 MonoInternalThread
*thread
= mono_thread_internal_current ();
1875 /* Do this WaitSleepJoin check before creating objects */
1876 if (mono_thread_current_check_pending_interrupt ())
1877 return map_native_wait_result_to_managed (MONO_W32HANDLE_WAIT_RET_FAILED
, 0);
1879 /* We fail in managed if the array has more than 64 elements */
1880 numhandles
= (guint32
)mono_array_length(mono_handles
);
1881 handles
= g_new0(HANDLE
, numhandles
);
1883 for(i
= 0; i
< numhandles
; i
++) {
1884 waitHandle
= mono_array_get(mono_handles
, MonoObject
*, i
);
1885 handles
[i
] = mono_wait_handle_get_handle ((MonoWaitHandle
*) waitHandle
);
1889 ms
=MONO_INFINITE_WAIT
;
1892 mono_thread_set_state (thread
, ThreadState_WaitSleepJoin
);
1894 ret
= mono_wait_uninterrupted (thread
, numhandles
, handles
, TRUE
, ms
, &error
);
1896 mono_thread_clr_state (thread
, ThreadState_WaitSleepJoin
);
1900 mono_error_set_pending_exception (&error
);
1902 return map_native_wait_result_to_managed (ret
, numhandles
);
1905 gint32
ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray
*mono_handles
, gint32 ms
)
1908 HANDLE handles
[MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
];
1909 uintptr_t numhandles
;
1910 MonoW32HandleWaitRet ret
;
1912 MonoObject
*waitHandle
;
1913 MonoInternalThread
*thread
= mono_thread_internal_current ();
1915 /* Do this WaitSleepJoin check before creating objects */
1916 if (mono_thread_current_check_pending_interrupt ())
1917 return map_native_wait_result_to_managed (MONO_W32HANDLE_WAIT_RET_FAILED
, 0);
1919 numhandles
= mono_array_length(mono_handles
);
1920 if (numhandles
> MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
)
1921 return map_native_wait_result_to_managed (MONO_W32HANDLE_WAIT_RET_FAILED
, 0);
1923 for(i
= 0; i
< numhandles
; i
++) {
1924 waitHandle
= mono_array_get(mono_handles
, MonoObject
*, i
);
1925 handles
[i
] = mono_wait_handle_get_handle ((MonoWaitHandle
*) waitHandle
);
1929 ms
=MONO_INFINITE_WAIT
;
1932 mono_thread_set_state (thread
, ThreadState_WaitSleepJoin
);
1934 ret
= mono_wait_uninterrupted (thread
, numhandles
, handles
, FALSE
, ms
, &error
);
1936 mono_thread_clr_state (thread
, ThreadState_WaitSleepJoin
);
1938 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT
") returning %d", __func__
, mono_native_thread_id_get (), ret
));
1940 mono_error_set_pending_exception (&error
);
1942 return map_native_wait_result_to_managed (ret
, numhandles
);
1945 gint32
ves_icall_System_Threading_WaitHandle_WaitOne_internal(HANDLE handle
, gint32 ms
)
1948 MonoW32HandleWaitRet ret
;
1949 MonoInternalThread
*thread
= mono_thread_internal_current ();
1951 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT
") waiting for %p, %d ms", __func__
, mono_native_thread_id_get (), handle
, ms
));
1954 ms
=MONO_INFINITE_WAIT
;
1957 if (mono_thread_current_check_pending_interrupt ())
1958 return map_native_wait_result_to_managed (MONO_W32HANDLE_WAIT_RET_FAILED
, 0);
1960 mono_thread_set_state (thread
, ThreadState_WaitSleepJoin
);
1962 ret
= mono_wait_uninterrupted (thread
, 1, &handle
, FALSE
, ms
, &error
);
1964 mono_thread_clr_state (thread
, ThreadState_WaitSleepJoin
);
1966 mono_error_set_pending_exception (&error
);
1967 return map_native_wait_result_to_managed (ret
, 1);
1971 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal
, HANDLE toWait
, gint32 ms
)
1973 MonoW32HandleWaitRet ret
;
1974 MonoInternalThread
*thread
= mono_thread_internal_current ();
1977 ms
= MONO_INFINITE_WAIT
;
1979 if (mono_thread_current_check_pending_interrupt ())
1980 return map_native_wait_result_to_managed (MONO_W32HANDLE_WAIT_RET_FAILED
, 0);
1982 mono_thread_set_state (thread
, ThreadState_WaitSleepJoin
);
1986 ret
= mono_w32handle_convert_wait_ret (SignalObjectAndWait (toSignal
, toWait
, ms
, TRUE
), 1);
1988 ret
= mono_w32handle_signal_and_wait (toSignal
, toWait
, ms
, TRUE
);
1992 mono_thread_clr_state (thread
, ThreadState_WaitSleepJoin
);
1994 return map_native_wait_result_to_managed (ret
, 1);
1997 gint32
ves_icall_System_Threading_Interlocked_Increment_Int (gint32
*location
)
1999 return InterlockedIncrement (location
);
2002 gint64
ves_icall_System_Threading_Interlocked_Increment_Long (gint64
*location
)
2004 #if SIZEOF_VOID_P == 4
2005 if (G_UNLIKELY ((size_t)location
& 0x7)) {
2007 mono_interlocked_lock ();
2010 mono_interlocked_unlock ();
2014 return InterlockedIncrement64 (location
);
2017 gint32
ves_icall_System_Threading_Interlocked_Decrement_Int (gint32
*location
)
2019 return InterlockedDecrement(location
);
2022 gint64
ves_icall_System_Threading_Interlocked_Decrement_Long (gint64
* location
)
2024 #if SIZEOF_VOID_P == 4
2025 if (G_UNLIKELY ((size_t)location
& 0x7)) {
2027 mono_interlocked_lock ();
2030 mono_interlocked_unlock ();
2034 return InterlockedDecrement64 (location
);
2037 gint32
ves_icall_System_Threading_Interlocked_Exchange_Int (gint32
*location
, gint32 value
)
2039 return InterlockedExchange(location
, value
);
2042 MonoObject
* ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject
**location
, MonoObject
*value
)
2045 res
= (MonoObject
*) InterlockedExchangePointer((gpointer
*) location
, value
);
2046 mono_gc_wbarrier_generic_nostore (location
);
2050 gpointer
ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer
*location
, gpointer value
)
2052 return InterlockedExchangePointer(location
, value
);
2055 gfloat
ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat
*location
, gfloat value
)
2057 IntFloatUnion val
, ret
;
2060 ret
.ival
= InterlockedExchange((gint32
*) location
, val
.ival
);
2066 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64
*location
, gint64 value
)
2068 #if SIZEOF_VOID_P == 4
2069 if (G_UNLIKELY ((size_t)location
& 0x7)) {
2071 mono_interlocked_lock ();
2074 mono_interlocked_unlock ();
2078 return InterlockedExchange64 (location
, value
);
2082 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble
*location
, gdouble value
)
2084 LongDoubleUnion val
, ret
;
2087 ret
.ival
= (gint64
)InterlockedExchange64((gint64
*) location
, val
.ival
);
2092 gint32
ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32
*location
, gint32 value
, gint32 comparand
)
2094 return InterlockedCompareExchange(location
, value
, comparand
);
2097 gint32
ves_icall_System_Threading_Interlocked_CompareExchange_Int_Success(gint32
*location
, gint32 value
, gint32 comparand
, MonoBoolean
*success
)
2099 gint32 r
= InterlockedCompareExchange(location
, value
, comparand
);
2100 *success
= r
== comparand
;
2104 MonoObject
* ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject
**location
, MonoObject
*value
, MonoObject
*comparand
)
2107 res
= (MonoObject
*) InterlockedCompareExchangePointer((gpointer
*) location
, value
, comparand
);
2108 mono_gc_wbarrier_generic_nostore (location
);
2112 gpointer
ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer
*location
, gpointer value
, gpointer comparand
)
2114 return InterlockedCompareExchangePointer(location
, value
, comparand
);
2117 gfloat
ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat
*location
, gfloat value
, gfloat comparand
)
2119 IntFloatUnion val
, ret
, cmp
;
2122 cmp
.fval
= comparand
;
2123 ret
.ival
= InterlockedCompareExchange((gint32
*) location
, val
.ival
, cmp
.ival
);
2129 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble
*location
, gdouble value
, gdouble comparand
)
2131 #if SIZEOF_VOID_P == 8
2132 LongDoubleUnion val
, comp
, ret
;
2135 comp
.fval
= comparand
;
2136 ret
.ival
= (gint64
)InterlockedCompareExchangePointer((gpointer
*) location
, (gpointer
)val
.ival
, (gpointer
)comp
.ival
);
2142 mono_interlocked_lock ();
2144 if (old
== comparand
)
2146 mono_interlocked_unlock ();
2153 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64
*location
, gint64 value
, gint64 comparand
)
2155 #if SIZEOF_VOID_P == 4
2156 if (G_UNLIKELY ((size_t)location
& 0x7)) {
2158 mono_interlocked_lock ();
2160 if (old
== comparand
)
2162 mono_interlocked_unlock ();
2166 return InterlockedCompareExchange64 (location
, value
, comparand
);
2170 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject
**location
, MonoObject
*value
, MonoObject
*comparand
)
2173 res
= (MonoObject
*)InterlockedCompareExchangePointer ((volatile gpointer
*)location
, value
, comparand
);
2174 mono_gc_wbarrier_generic_nostore (location
);
2179 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject
**location
, MonoObject
*value
)
2182 MONO_CHECK_NULL (location
, NULL
);
2183 res
= (MonoObject
*)InterlockedExchangePointer ((volatile gpointer
*)location
, value
);
2184 mono_gc_wbarrier_generic_nostore (location
);
2189 ves_icall_System_Threading_Interlocked_Add_Int (gint32
*location
, gint32 value
)
2191 return InterlockedAdd (location
, value
);
2195 ves_icall_System_Threading_Interlocked_Add_Long (gint64
*location
, gint64 value
)
2197 #if SIZEOF_VOID_P == 4
2198 if (G_UNLIKELY ((size_t)location
& 0x7)) {
2200 mono_interlocked_lock ();
2203 mono_interlocked_unlock ();
2207 return InterlockedAdd64 (location
, value
);
2211 ves_icall_System_Threading_Interlocked_Read_Long (gint64
*location
)
2213 #if SIZEOF_VOID_P == 4
2214 if (G_UNLIKELY ((size_t)location
& 0x7)) {
2216 mono_interlocked_lock ();
2218 mono_interlocked_unlock ();
2222 return InterlockedRead64 (location
);
2226 ves_icall_System_Threading_Thread_MemoryBarrier (void)
2228 mono_memory_barrier ();
2232 ves_icall_System_Threading_Thread_ClrState (MonoInternalThread
* this_obj
, guint32 state
)
2234 mono_thread_clr_state (this_obj
, (MonoThreadState
)state
);
2236 if (state
& ThreadState_Background
) {
2237 /* If the thread changes the background mode, the main thread has to
2238 * be notified, since it has to rebuild the list of threads to
2241 mono_os_event_set (&background_change_event
);
2246 ves_icall_System_Threading_Thread_SetState (MonoInternalThread
* this_obj
, guint32 state
)
2248 mono_thread_set_state (this_obj
, (MonoThreadState
)state
);
2250 if (state
& ThreadState_Background
) {
2251 /* If the thread changes the background mode, the main thread has to
2252 * be notified, since it has to rebuild the list of threads to
2255 mono_os_event_set (&background_change_event
);
2260 ves_icall_System_Threading_Thread_GetState (MonoInternalThread
* this_obj
)
2264 LOCK_THREAD (this_obj
);
2266 state
= this_obj
->state
;
2268 UNLOCK_THREAD (this_obj
);
2273 void ves_icall_System_Threading_Thread_Interrupt_internal (MonoThread
*this_obj
)
2275 MonoInternalThread
*current
;
2277 MonoInternalThread
*thread
= this_obj
->internal_thread
;
2279 LOCK_THREAD (thread
);
2281 current
= mono_thread_internal_current ();
2283 thread
->thread_interrupt_requested
= TRUE
;
2284 throw_
= current
!= thread
&& (thread
->state
& ThreadState_WaitSleepJoin
);
2286 UNLOCK_THREAD (thread
);
2289 async_abort_internal (thread
, FALSE
);
2294 * mono_thread_current_check_pending_interrupt:
2296 * Checks if there's a interruption request and set the pending exception if so.
2298 * @returns true if a pending exception was set
2301 mono_thread_current_check_pending_interrupt (void)
2303 MonoInternalThread
*thread
= mono_thread_internal_current ();
2304 gboolean throw_
= FALSE
;
2306 LOCK_THREAD (thread
);
2308 if (thread
->thread_interrupt_requested
) {
2310 thread
->thread_interrupt_requested
= FALSE
;
2313 UNLOCK_THREAD (thread
);
2316 mono_set_pending_exception (mono_get_exception_thread_interrupted ());
2321 request_thread_abort (MonoInternalThread
*thread
, MonoObject
*state
)
2323 LOCK_THREAD (thread
);
2325 if (thread
->state
& (ThreadState_AbortRequested
| ThreadState_Stopped
))
2327 UNLOCK_THREAD (thread
);
2331 if ((thread
->state
& ThreadState_Unstarted
) != 0) {
2332 thread
->state
|= ThreadState_Aborted
;
2333 UNLOCK_THREAD (thread
);
2337 thread
->state
|= ThreadState_AbortRequested
;
2338 if (thread
->abort_state_handle
)
2339 mono_gchandle_free (thread
->abort_state_handle
);
2341 thread
->abort_state_handle
= mono_gchandle_new (state
, FALSE
);
2342 g_assert (thread
->abort_state_handle
);
2344 thread
->abort_state_handle
= 0;
2346 thread
->abort_exc
= NULL
;
2348 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
));
2350 /* During shutdown, we can't wait for other threads */
2352 /* Make sure the thread is awake */
2353 mono_thread_resume (thread
);
2355 UNLOCK_THREAD (thread
);
2360 ves_icall_System_Threading_Thread_Abort (MonoInternalThread
*thread
, MonoObject
*state
)
2362 if (!request_thread_abort (thread
, state
))
2365 if (thread
== mono_thread_internal_current ()) {
2367 self_abort_internal (&error
);
2368 mono_error_set_pending_exception (&error
);
2370 async_abort_internal (thread
, TRUE
);
2375 * mono_thread_internal_abort:
2377 * Request thread @thread to be aborted.
2379 * @thread MUST NOT be the current thread.
2382 mono_thread_internal_abort (MonoInternalThread
*thread
)
2384 g_assert (thread
!= mono_thread_internal_current ());
2386 if (!request_thread_abort (thread
, NULL
))
2388 async_abort_internal (thread
, TRUE
);
2392 ves_icall_System_Threading_Thread_ResetAbort (MonoThread
*this_obj
)
2394 MonoInternalThread
*thread
= mono_thread_internal_current ();
2395 gboolean was_aborting
;
2397 LOCK_THREAD (thread
);
2398 was_aborting
= thread
->state
& ThreadState_AbortRequested
;
2399 thread
->state
&= ~ThreadState_AbortRequested
;
2400 UNLOCK_THREAD (thread
);
2402 if (!was_aborting
) {
2403 const char *msg
= "Unable to reset abort because no abort was requested";
2404 mono_set_pending_exception (mono_get_exception_thread_state (msg
));
2408 mono_get_eh_callbacks ()->mono_clear_abort_threshold ();
2409 thread
->abort_exc
= NULL
;
2410 if (thread
->abort_state_handle
) {
2411 mono_gchandle_free (thread
->abort_state_handle
);
2412 /* This is actually not necessary - the handle
2413 only counts if the exception is set */
2414 thread
->abort_state_handle
= 0;
2419 mono_thread_internal_reset_abort (MonoInternalThread
*thread
)
2421 LOCK_THREAD (thread
);
2423 thread
->state
&= ~ThreadState_AbortRequested
;
2425 if (thread
->abort_exc
) {
2426 mono_get_eh_callbacks ()->mono_clear_abort_threshold ();
2427 thread
->abort_exc
= NULL
;
2428 if (thread
->abort_state_handle
) {
2429 mono_gchandle_free (thread
->abort_state_handle
);
2430 /* This is actually not necessary - the handle
2431 only counts if the exception is set */
2432 thread
->abort_state_handle
= 0;
2436 UNLOCK_THREAD (thread
);
2440 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread
*this_obj
)
2443 MonoInternalThread
*thread
= this_obj
->internal_thread
;
2444 MonoObject
*state
, *deserialized
= NULL
;
2447 if (!thread
->abort_state_handle
)
2450 state
= mono_gchandle_get_target (thread
->abort_state_handle
);
2453 domain
= mono_domain_get ();
2454 if (mono_object_domain (state
) == domain
)
2457 deserialized
= mono_object_xdomain_representation (state
, domain
, &error
);
2459 if (!deserialized
) {
2460 MonoException
*invalid_op_exc
= mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
2461 if (!is_ok (&error
)) {
2462 MonoObject
*exc
= (MonoObject
*)mono_error_convert_to_exception (&error
);
2463 MONO_OBJECT_SETREF (invalid_op_exc
, inner_ex
, exc
);
2465 mono_set_pending_exception (invalid_op_exc
);
2469 return deserialized
;
2473 mono_thread_suspend (MonoInternalThread
*thread
)
2475 LOCK_THREAD (thread
);
2477 if (thread
->state
& (ThreadState_Unstarted
| ThreadState_Aborted
| ThreadState_Stopped
))
2479 UNLOCK_THREAD (thread
);
2483 if (thread
->state
& (ThreadState_Suspended
| ThreadState_SuspendRequested
| ThreadState_AbortRequested
))
2485 UNLOCK_THREAD (thread
);
2489 thread
->state
|= ThreadState_SuspendRequested
;
2490 mono_os_event_reset (thread
->suspended
);
2492 if (thread
== mono_thread_internal_current ()) {
2493 /* calls UNLOCK_THREAD (thread) */
2494 self_suspend_internal ();
2496 /* calls UNLOCK_THREAD (thread) */
2497 async_suspend_internal (thread
, FALSE
);
2504 ves_icall_System_Threading_Thread_Suspend (MonoThread
*this_obj
)
2506 if (!mono_thread_suspend (this_obj
->internal_thread
)) {
2507 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2512 /* LOCKING: LOCK_THREAD(thread) must be held */
2514 mono_thread_resume (MonoInternalThread
*thread
)
2516 if ((thread
->state
& ThreadState_SuspendRequested
) != 0) {
2517 // MOSTLY_ASYNC_SAFE_PRINTF ("RESUME (1) thread %p\n", thread_get_tid (thread));
2518 thread
->state
&= ~ThreadState_SuspendRequested
;
2519 mono_os_event_set (thread
->suspended
);
2523 if ((thread
->state
& ThreadState_Suspended
) == 0 ||
2524 (thread
->state
& ThreadState_Unstarted
) != 0 ||
2525 (thread
->state
& ThreadState_Aborted
) != 0 ||
2526 (thread
->state
& ThreadState_Stopped
) != 0)
2528 // MOSTLY_ASYNC_SAFE_PRINTF ("RESUME (2) thread %p\n", thread_get_tid (thread));
2532 // MOSTLY_ASYNC_SAFE_PRINTF ("RESUME (3) thread %p\n", thread_get_tid (thread));
2534 mono_os_event_set (thread
->suspended
);
2536 if (!thread
->self_suspended
) {
2537 UNLOCK_THREAD (thread
);
2539 /* Awake the thread */
2540 if (!mono_thread_info_resume (thread_get_tid (thread
)))
2543 LOCK_THREAD (thread
);
2546 thread
->state
&= ~ThreadState_Suspended
;
2552 ves_icall_System_Threading_Thread_Resume (MonoThread
*thread
)
2554 if (!thread
->internal_thread
) {
2555 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2557 LOCK_THREAD (thread
->internal_thread
);
2558 if (!mono_thread_resume (thread
->internal_thread
))
2559 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2560 UNLOCK_THREAD (thread
->internal_thread
);
2565 mono_threads_is_critical_method (MonoMethod
*method
)
2567 switch (method
->wrapper_type
) {
2568 case MONO_WRAPPER_RUNTIME_INVOKE
:
2569 case MONO_WRAPPER_XDOMAIN_INVOKE
:
2570 case MONO_WRAPPER_XDOMAIN_DISPATCH
:
2577 find_wrapper (MonoMethod
*m
, gint no
, gint ilo
, gboolean managed
, gpointer data
)
2582 if (mono_threads_is_critical_method (m
)) {
2583 *((gboolean
*)data
) = TRUE
;
2590 is_running_protected_wrapper (void)
2592 gboolean found
= FALSE
;
2593 mono_stack_walk (find_wrapper
, &found
);
2598 mono_thread_stop (MonoThread
*thread
)
2600 MonoInternalThread
*internal
= thread
->internal_thread
;
2602 if (!request_thread_abort (internal
, NULL
))
2605 if (internal
== mono_thread_internal_current ()) {
2607 self_abort_internal (&error
);
2609 This function is part of the embeding API and has no way to return the exception
2610 to be thrown. So what we do is keep the old behavior and raise the exception.
2612 mono_error_raise_exception (&error
); /* OK to throw, see note */
2614 async_abort_internal (internal
, TRUE
);
2619 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr
)
2621 gint8 tmp
= *(volatile gint8
*)ptr
;
2622 mono_memory_barrier ();
2627 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr
)
2629 gint16 tmp
= *(volatile gint16
*)ptr
;
2630 mono_memory_barrier ();
2635 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr
)
2637 gint32 tmp
= *(volatile gint32
*)ptr
;
2638 mono_memory_barrier ();
2643 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr
)
2645 gint64 tmp
= *(volatile gint64
*)ptr
;
2646 mono_memory_barrier ();
2651 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr
)
2653 volatile void *tmp
= *(volatile void **)ptr
;
2654 mono_memory_barrier ();
2655 return (void *) tmp
;
2659 ves_icall_System_Threading_Thread_VolatileReadObject (void *ptr
)
2661 volatile MonoObject
*tmp
= *(volatile MonoObject
**)ptr
;
2662 mono_memory_barrier ();
2663 return (MonoObject
*) tmp
;
2667 ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr
)
2669 double tmp
= *(volatile double *)ptr
;
2670 mono_memory_barrier ();
2675 ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr
)
2677 float tmp
= *(volatile float *)ptr
;
2678 mono_memory_barrier ();
2683 ves_icall_System_Threading_Volatile_Read1 (void *ptr
)
2685 return InterlockedRead8 ((volatile gint8
*)ptr
);
2689 ves_icall_System_Threading_Volatile_Read2 (void *ptr
)
2691 return InterlockedRead16 ((volatile gint16
*)ptr
);
2695 ves_icall_System_Threading_Volatile_Read4 (void *ptr
)
2697 return InterlockedRead ((volatile gint32
*)ptr
);
2701 ves_icall_System_Threading_Volatile_Read8 (void *ptr
)
2703 #if SIZEOF_VOID_P == 4
2704 if (G_UNLIKELY ((size_t)ptr
& 0x7)) {
2706 mono_interlocked_lock ();
2707 val
= *(gint64
*)ptr
;
2708 mono_interlocked_unlock ();
2712 return InterlockedRead64 ((volatile gint64
*)ptr
);
2716 ves_icall_System_Threading_Volatile_ReadIntPtr (void *ptr
)
2718 return InterlockedReadPointer ((volatile gpointer
*)ptr
);
2722 ves_icall_System_Threading_Volatile_ReadDouble (void *ptr
)
2726 #if SIZEOF_VOID_P == 4
2727 if (G_UNLIKELY ((size_t)ptr
& 0x7)) {
2729 mono_interlocked_lock ();
2730 val
= *(double*)ptr
;
2731 mono_interlocked_unlock ();
2736 u
.ival
= InterlockedRead64 ((volatile gint64
*)ptr
);
2742 ves_icall_System_Threading_Volatile_ReadFloat (void *ptr
)
2746 u
.ival
= InterlockedRead ((volatile gint32
*)ptr
);
2752 ves_icall_System_Threading_Volatile_Read_T (void *ptr
)
2754 return (MonoObject
*)InterlockedReadPointer ((volatile gpointer
*)ptr
);
2758 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr
, gint8 value
)
2760 mono_memory_barrier ();
2761 *(volatile gint8
*)ptr
= value
;
2765 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr
, gint16 value
)
2767 mono_memory_barrier ();
2768 *(volatile gint16
*)ptr
= value
;
2772 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr
, gint32 value
)
2774 mono_memory_barrier ();
2775 *(volatile gint32
*)ptr
= value
;
2779 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr
, gint64 value
)
2781 mono_memory_barrier ();
2782 *(volatile gint64
*)ptr
= value
;
2786 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr
, void *value
)
2788 mono_memory_barrier ();
2789 *(volatile void **)ptr
= value
;
2793 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr
, MonoObject
*value
)
2795 mono_memory_barrier ();
2796 mono_gc_wbarrier_generic_store (ptr
, value
);
2800 ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr
, double value
)
2802 mono_memory_barrier ();
2803 *(volatile double *)ptr
= value
;
2807 ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr
, float value
)
2809 mono_memory_barrier ();
2810 *(volatile float *)ptr
= value
;
2814 ves_icall_System_Threading_Volatile_Write1 (void *ptr
, gint8 value
)
2816 InterlockedWrite8 ((volatile gint8
*)ptr
, value
);
2820 ves_icall_System_Threading_Volatile_Write2 (void *ptr
, gint16 value
)
2822 InterlockedWrite16 ((volatile gint16
*)ptr
, value
);
2826 ves_icall_System_Threading_Volatile_Write4 (void *ptr
, gint32 value
)
2828 InterlockedWrite ((volatile gint32
*)ptr
, value
);
2832 ves_icall_System_Threading_Volatile_Write8 (void *ptr
, gint64 value
)
2834 #if SIZEOF_VOID_P == 4
2835 if (G_UNLIKELY ((size_t)ptr
& 0x7)) {
2836 mono_interlocked_lock ();
2837 *(gint64
*)ptr
= value
;
2838 mono_interlocked_unlock ();
2843 InterlockedWrite64 ((volatile gint64
*)ptr
, value
);
2847 ves_icall_System_Threading_Volatile_WriteIntPtr (void *ptr
, void *value
)
2849 InterlockedWritePointer ((volatile gpointer
*)ptr
, value
);
2853 ves_icall_System_Threading_Volatile_WriteDouble (void *ptr
, double value
)
2857 #if SIZEOF_VOID_P == 4
2858 if (G_UNLIKELY ((size_t)ptr
& 0x7)) {
2859 mono_interlocked_lock ();
2860 *(double*)ptr
= value
;
2861 mono_interlocked_unlock ();
2868 InterlockedWrite64 ((volatile gint64
*)ptr
, u
.ival
);
2872 ves_icall_System_Threading_Volatile_WriteFloat (void *ptr
, float value
)
2878 InterlockedWrite ((volatile gint32
*)ptr
, u
.ival
);
2882 ves_icall_System_Threading_Volatile_Write_T (void *ptr
, MonoObject
*value
)
2884 mono_gc_wbarrier_generic_store_atomic (ptr
, value
);
2888 free_context (void *user_data
)
2890 ContextStaticData
*data
= user_data
;
2892 mono_threads_lock ();
2895 * There is no guarantee that, by the point this reference queue callback
2896 * has been invoked, the GC handle associated with the object will fail to
2897 * resolve as one might expect. So if we don't free and remove the GC
2898 * handle here, free_context_static_data_helper () could end up resolving
2899 * a GC handle to an actually-dead context which would contain a pointer
2900 * to an already-freed static data segment, resulting in a crash when
2903 g_hash_table_remove (contexts
, GUINT_TO_POINTER (data
->gc_handle
));
2905 mono_threads_unlock ();
2907 mono_gchandle_free (data
->gc_handle
);
2908 mono_free_static_data (data
->static_data
);
2913 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (MonoAppContext
*ctx
)
2915 mono_threads_lock ();
2917 //g_print ("Registering context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2920 contexts
= g_hash_table_new (NULL
, NULL
);
2923 context_queue
= mono_gc_reference_queue_new (free_context
);
2925 gpointer gch
= GUINT_TO_POINTER (mono_gchandle_new_weakref (&ctx
->obj
, FALSE
));
2926 g_hash_table_insert (contexts
, gch
, gch
);
2929 * We use this intermediate structure to contain a duplicate pointer to
2930 * the static data because we can't rely on being able to resolve the GC
2931 * handle in the reference queue callback.
2933 ContextStaticData
*data
= g_new0 (ContextStaticData
, 1);
2934 data
->gc_handle
= GPOINTER_TO_UINT (gch
);
2937 context_adjust_static_data (ctx
);
2938 mono_gc_reference_queue_add (context_queue
, &ctx
->obj
, data
);
2940 mono_threads_unlock ();
2942 mono_profiler_context_loaded (ctx
);
2946 ves_icall_System_Runtime_Remoting_Contexts_Context_ReleaseContext (MonoAppContext
*ctx
)
2949 * NOTE: Since finalizers are unreliable for the purposes of ensuring
2950 * cleanup in exceptional circumstances, we don't actually do any
2951 * cleanup work here. We instead do this via a reference queue.
2954 //g_print ("Releasing context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2956 mono_profiler_context_unloaded (ctx
);
2959 void mono_thread_init (MonoThreadStartCB start_cb
,
2960 MonoThreadAttachCB attach_cb
)
2962 mono_coop_mutex_init_recursive (&threads_mutex
);
2964 mono_os_mutex_init_recursive(&interlocked_mutex
);
2965 mono_os_mutex_init_recursive(&joinable_threads_mutex
);
2967 mono_os_event_init (&background_change_event
, FALSE
);
2969 mono_init_static_data_info (&thread_static_info
);
2970 mono_init_static_data_info (&context_static_info
);
2972 mono_thread_start_cb
= start_cb
;
2973 mono_thread_attach_cb
= attach_cb
;
2976 void mono_thread_cleanup (void)
2978 #if !defined(RUN_IN_SUBTHREAD) && !defined(HOST_WIN32)
2979 /* The main thread must abandon any held mutexes (particularly
2980 * important for named mutexes as they are shared across
2981 * processes, see bug 74680.) This will happen when the
2982 * thread exits, but if it's not running in a subthread it
2983 * won't exit in time.
2985 mono_w32mutex_abandon ();
2989 /* This stuff needs more testing, it seems one of these
2990 * critical sections can be locked when mono_thread_cleanup is
2993 mono_coop_mutex_destroy (&threads_mutex
);
2994 mono_os_mutex_destroy (&interlocked_mutex
);
2995 mono_os_mutex_destroy (&delayed_free_table_mutex
);
2996 mono_os_mutex_destroy (&small_id_mutex
);
2997 mono_os_event_destroy (&background_change_event
);
3002 mono_threads_install_cleanup (MonoThreadCleanupFunc func
)
3004 mono_thread_cleanup_fn
= func
;
3008 mono_thread_set_manage_callback (MonoThread
*thread
, MonoThreadManageCallback func
)
3010 thread
->internal_thread
->manage_callback
= func
;
3014 static void print_tids (gpointer key
, gpointer value
, gpointer user
)
3016 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
3017 * sizeof(uint) and a cast to uint would overflow
3019 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
3020 * print this as a pointer.
3022 g_message ("Waiting for: %p", key
);
3027 MonoThreadHandle
*handles
[MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
];
3028 MonoInternalThread
*threads
[MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
];
3033 wait_for_tids (struct wait_data
*wait
, guint32 timeout
, gboolean check_state_change
)
3036 MonoThreadInfoWaitRet ret
;
3038 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__
, wait
->num
));
3040 /* Add the thread state change event, so it wakes
3041 * up if a thread changes to background mode. */
3044 if (check_state_change
)
3045 ret
= mono_thread_info_wait_multiple_handle (wait
->handles
, wait
->num
, &background_change_event
, FALSE
, timeout
, TRUE
);
3047 ret
= mono_thread_info_wait_multiple_handle (wait
->handles
, wait
->num
, NULL
, TRUE
, timeout
, TRUE
);
3050 if (ret
== MONO_THREAD_INFO_WAIT_RET_FAILED
) {
3051 /* See the comment in build_wait_tids() */
3052 THREAD_DEBUG (g_message ("%s: Wait failed", __func__
));
3056 for( i
= 0; i
< wait
->num
; i
++)
3057 mono_threads_close_thread_handle (wait
->handles
[i
]);
3059 if (ret
== MONO_THREAD_INFO_WAIT_RET_TIMEOUT
)
3062 if (ret
< wait
->num
) {
3063 MonoInternalThread
*internal
;
3065 internal
= wait
->threads
[ret
];
3067 mono_threads_lock ();
3068 if (mono_g_hash_table_lookup (threads
, (gpointer
) internal
->tid
) == internal
)
3069 g_error ("%s: failed to call mono_thread_detach_internal on thread %p, InternalThread: %p", __func__
, internal
->tid
, internal
);
3070 mono_threads_unlock ();
3074 static void build_wait_tids (gpointer key
, gpointer value
, gpointer user
)
3076 struct wait_data
*wait
=(struct wait_data
*)user
;
3078 if(wait
->num
<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
- 1) {
3079 MonoInternalThread
*thread
=(MonoInternalThread
*)value
;
3081 /* Ignore background threads, we abort them later */
3082 /* Do not lock here since it is not needed and the caller holds threads_lock */
3083 if (thread
->state
& ThreadState_Background
) {
3084 THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT
, __func__
, (gsize
)thread
->tid
));
3085 return; /* just leave, ignore */
3088 if (mono_gc_is_finalizer_internal_thread (thread
)) {
3089 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT
, __func__
, (gsize
)thread
->tid
));
3093 if (thread
== mono_thread_internal_current ()) {
3094 THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT
, __func__
, (gsize
)thread
->tid
));
3098 if (mono_thread_get_main () && (thread
== mono_thread_get_main ()->internal_thread
)) {
3099 THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT
, __func__
, (gsize
)thread
->tid
));
3103 if (thread
->flags
& MONO_THREAD_FLAG_DONT_MANAGE
) {
3104 THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT
"with DONT_MANAGE flag set.", __func__
, (gsize
)thread
->tid
));
3108 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__
, thread
));
3109 if ((thread
->manage_callback
== NULL
) || (thread
->manage_callback (thread
->root_domain_thread
) == TRUE
)) {
3110 wait
->handles
[wait
->num
]=mono_threads_open_thread_handle (thread
->handle
);
3111 wait
->threads
[wait
->num
]=thread
;
3114 THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT
, __func__
, (gsize
)thread
->tid
));
3116 THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT
, __func__
, (gsize
)thread
->tid
));
3121 /* Just ignore the rest, we can't do anything with
3128 remove_and_abort_threads (gpointer key
, gpointer value
, gpointer user
)
3130 struct wait_data
*wait
=(struct wait_data
*)user
;
3131 MonoNativeThreadId self
= mono_native_thread_id_get ();
3132 MonoInternalThread
*thread
= (MonoInternalThread
*)value
;
3134 if (wait
->num
>= MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
)
3137 if (mono_native_thread_id_equals (thread_get_tid (thread
), self
))
3139 if (mono_gc_is_finalizer_internal_thread (thread
))
3142 if ((thread
->state
& ThreadState_Background
) && !(thread
->flags
& MONO_THREAD_FLAG_DONT_MANAGE
)) {
3143 wait
->handles
[wait
->num
] = mono_threads_open_thread_handle (thread
->handle
);
3144 wait
->threads
[wait
->num
] = thread
;
3147 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT
"\n", __func__
, (gsize
)thread
->tid
));
3148 mono_thread_internal_abort (thread
);
3155 * mono_threads_set_shutting_down:
3157 * Is called by a thread that wants to shut down Mono. If the runtime is already
3158 * shutting down, the calling thread is suspended/stopped, and this function never
3162 mono_threads_set_shutting_down (void)
3164 MonoInternalThread
*current_thread
= mono_thread_internal_current ();
3166 mono_threads_lock ();
3168 if (shutting_down
) {
3169 mono_threads_unlock ();
3171 /* Make sure we're properly suspended/stopped */
3173 LOCK_THREAD (current_thread
);
3175 if (current_thread
->state
& (ThreadState_SuspendRequested
| ThreadState_AbortRequested
)) {
3176 UNLOCK_THREAD (current_thread
);
3177 mono_thread_execute_interruption ();
3179 UNLOCK_THREAD (current_thread
);
3182 /*since we're killing the thread, detach it.*/
3183 mono_thread_detach_internal (current_thread
);
3185 /* Wake up other threads potentially waiting for us */
3186 mono_thread_info_exit (0);
3188 shutting_down
= TRUE
;
3190 /* Not really a background state change, but this will
3191 * interrupt the main thread if it is waiting for all
3192 * the other threads.
3194 mono_os_event_set (&background_change_event
);
3196 mono_threads_unlock ();
3200 void mono_thread_manage (void)
3202 struct wait_data wait_data
;
3203 struct wait_data
*wait
= &wait_data
;
3205 memset (wait
, 0, sizeof (struct wait_data
));
3206 /* join each thread that's still running */
3207 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__
));
3209 mono_threads_lock ();
3211 THREAD_DEBUG (g_message("%s: No threads", __func__
));
3212 mono_threads_unlock ();
3215 mono_threads_unlock ();
3218 mono_threads_lock ();
3219 if (shutting_down
) {
3220 /* somebody else is shutting down */
3221 mono_threads_unlock ();
3224 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__
, mono_g_hash_table_size (threads
));
3225 mono_g_hash_table_foreach (threads
, print_tids
, NULL
));
3227 mono_os_event_reset (&background_change_event
);
3229 /* We must zero all InternalThread pointers to avoid making the GC unhappy. */
3230 memset (wait
->threads
, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
* SIZEOF_VOID_P
);
3231 mono_g_hash_table_foreach (threads
, build_wait_tids
, wait
);
3232 mono_threads_unlock ();
3234 /* Something to wait for */
3235 wait_for_tids (wait
, MONO_INFINITE_WAIT
, TRUE
);
3236 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__
, wait
->num
));
3237 } while(wait
->num
>0);
3239 /* Mono is shutting down, so just wait for the end */
3240 if (!mono_runtime_try_shutdown ()) {
3241 /*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
3242 mono_thread_suspend (mono_thread_internal_current ());
3243 mono_thread_execute_interruption ();
3247 * Remove everything but the finalizer thread and self.
3248 * Also abort all the background threads
3251 mono_threads_lock ();
3254 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3255 memset (wait
->threads
, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
* SIZEOF_VOID_P
);
3256 mono_g_hash_table_foreach_remove (threads
, remove_and_abort_threads
, wait
);
3258 mono_threads_unlock ();
3260 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__
, wait
->num
));
3261 if (wait
->num
> 0) {
3262 /* Something to wait for */
3263 wait_for_tids (wait
, MONO_INFINITE_WAIT
, FALSE
);
3265 } while (wait
->num
> 0);
3268 * give the subthreads a chance to really quit (this is mainly needed
3269 * to get correct user and system times from getrusage/wait/time(1)).
3270 * This could be removed if we avoid pthread_detach() and use pthread_join().
3272 mono_thread_info_yield ();
3276 collect_threads_for_suspend (gpointer key
, gpointer value
, gpointer user_data
)
3278 MonoInternalThread
*thread
= (MonoInternalThread
*)value
;
3279 struct wait_data
*wait
= (struct wait_data
*)user_data
;
3282 * We try to exclude threads early, to avoid running into the MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
3284 * This needs no locking.
3286 if ((thread
->state
& ThreadState_Suspended
) != 0 ||
3287 (thread
->state
& ThreadState_Stopped
) != 0)
3290 if (wait
->num
<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
) {
3291 wait
->handles
[wait
->num
] = mono_threads_open_thread_handle (thread
->handle
);
3292 wait
->threads
[wait
->num
] = thread
;
3298 * mono_thread_suspend_all_other_threads:
3300 * Suspend all managed threads except the finalizer thread and this thread. It is
3301 * not possible to resume them later.
3303 void mono_thread_suspend_all_other_threads (void)
3305 struct wait_data wait_data
;
3306 struct wait_data
*wait
= &wait_data
;
3308 MonoNativeThreadId self
= mono_native_thread_id_get ();
3309 guint32 eventidx
= 0;
3310 gboolean starting
, finished
;
3312 memset (wait
, 0, sizeof (struct wait_data
));
3314 * The other threads could be in an arbitrary state at this point, i.e.
3315 * they could be starting up, shutting down etc. This means that there could be
3316 * threads which are not even in the threads hash table yet.
3320 * First we set a barrier which will be checked by all threads before they
3321 * are added to the threads hash table, and they will exit if the flag is set.
3322 * This ensures that no threads could be added to the hash later.
3323 * We will use shutting_down as the barrier for now.
3325 g_assert (shutting_down
);
3328 * We make multiple calls to WaitForMultipleObjects since:
3329 * - we can only wait for MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS threads
3330 * - some threads could exit without becoming suspended
3335 * Make a copy of the hashtable since we can't do anything with
3336 * threads while threads_mutex is held.
3339 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3340 memset (wait
->threads
, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
* SIZEOF_VOID_P
);
3341 mono_threads_lock ();
3342 mono_g_hash_table_foreach (threads
, collect_threads_for_suspend
, wait
);
3343 mono_threads_unlock ();
3346 /* Get the suspended events that we'll be waiting for */
3347 for (i
= 0; i
< wait
->num
; ++i
) {
3348 MonoInternalThread
*thread
= wait
->threads
[i
];
3350 if (mono_native_thread_id_equals (thread_get_tid (thread
), self
)
3351 || mono_gc_is_finalizer_internal_thread (thread
)
3352 || (thread
->flags
& MONO_THREAD_FLAG_DONT_MANAGE
)
3354 mono_threads_close_thread_handle (wait
->handles
[i
]);
3355 wait
->threads
[i
] = NULL
;
3359 LOCK_THREAD (thread
);
3361 if (thread
->state
& (ThreadState_Suspended
| ThreadState_Stopped
)) {
3362 UNLOCK_THREAD (thread
);
3363 mono_threads_close_thread_handle (wait
->handles
[i
]);
3364 wait
->threads
[i
] = NULL
;
3370 /* Convert abort requests into suspend requests */
3371 if ((thread
->state
& ThreadState_AbortRequested
) != 0)
3372 thread
->state
&= ~ThreadState_AbortRequested
;
3374 thread
->state
|= ThreadState_SuspendRequested
;
3375 mono_os_event_reset (thread
->suspended
);
3377 /* Signal the thread to suspend + calls UNLOCK_THREAD (thread) */
3378 async_suspend_internal (thread
, TRUE
);
3380 mono_threads_close_thread_handle (wait
->handles
[i
]);
3381 wait
->threads
[i
] = NULL
;
3383 if (eventidx
<= 0) {
3385 * If there are threads which are starting up, we wait until they
3386 * are suspended when they try to register in the threads hash.
3387 * This is guaranteed to finish, since the threads which can create new
3388 * threads get suspended after a while.
3389 * FIXME: The finalizer thread can still create new threads.
3391 mono_threads_lock ();
3392 if (threads_starting_up
)
3393 starting
= mono_g_hash_table_size (threads_starting_up
) > 0;
3396 mono_threads_unlock ();
3398 mono_thread_info_sleep (100, NULL
);
3406 MonoInternalThread
*thread
;
3407 MonoStackFrameInfo
*frames
;
3408 int nframes
, max_frames
;
3409 int nthreads
, max_threads
;
3410 MonoInternalThread
**threads
;
3411 } ThreadDumpUserData
;
3413 static gboolean thread_dump_requested
;
3415 /* This needs to be async safe */
3417 collect_frame (MonoStackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
3419 ThreadDumpUserData
*ud
= (ThreadDumpUserData
*)data
;
3421 if (ud
->nframes
< ud
->max_frames
) {
3422 memcpy (&ud
->frames
[ud
->nframes
], frame
, sizeof (MonoStackFrameInfo
));
3429 /* This needs to be async safe */
3430 static SuspendThreadResult
3431 get_thread_dump (MonoThreadInfo
*info
, gpointer ud
)
3433 ThreadDumpUserData
*user_data
= (ThreadDumpUserData
*)ud
;
3434 MonoInternalThread
*thread
= user_data
->thread
;
3437 /* This no longer works with remote unwinding */
3438 g_string_append_printf (text
, " tid=0x%p this=0x%p ", (gpointer
)(gsize
)thread
->tid
, thread
);
3439 mono_thread_internal_describe (thread
, text
);
3440 g_string_append (text
, "\n");
3443 if (thread
== mono_thread_internal_current ())
3444 mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (collect_frame
, NULL
, MONO_UNWIND_SIGNAL_SAFE
, ud
);
3446 mono_get_eh_callbacks ()->mono_walk_stack_with_state (collect_frame
, mono_thread_info_get_suspend_state (info
), MONO_UNWIND_SIGNAL_SAFE
, ud
);
3448 return MonoResumeThread
;
3452 int nthreads
, max_threads
;
3453 MonoInternalThread
**threads
;
3454 } CollectThreadsUserData
;
3457 collect_thread (gpointer key
, gpointer value
, gpointer user
)
3459 CollectThreadsUserData
*ud
= (CollectThreadsUserData
*)user
;
3460 MonoInternalThread
*thread
= (MonoInternalThread
*)value
;
3462 if (ud
->nthreads
< ud
->max_threads
)
3463 ud
->threads
[ud
->nthreads
++] = thread
;
3467 * Collect running threads into the THREADS array.
3468 * THREADS should be an array allocated on the stack.
3471 collect_threads (MonoInternalThread
**thread_array
, int max_threads
)
3473 CollectThreadsUserData ud
;
3475 memset (&ud
, 0, sizeof (ud
));
3476 /* This array contains refs, but its on the stack, so its ok */
3477 ud
.threads
= thread_array
;
3478 ud
.max_threads
= max_threads
;
3480 mono_threads_lock ();
3481 mono_g_hash_table_foreach (threads
, collect_thread
, &ud
);
3482 mono_threads_unlock ();
3488 dump_thread (MonoInternalThread
*thread
, ThreadDumpUserData
*ud
)
3490 GString
* text
= g_string_new (0);
3492 GError
*error
= NULL
;
3495 ud
->thread
= thread
;
3498 /* Collect frames for the thread */
3499 if (thread
== mono_thread_internal_current ()) {
3500 get_thread_dump (mono_thread_info_current (), ud
);
3502 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread
), FALSE
, get_thread_dump
, ud
);
3506 * Do all the non async-safe work outside of get_thread_dump.
3509 name
= g_utf16_to_utf8 (thread
->name
, thread
->name_len
, NULL
, NULL
, &error
);
3511 g_string_append_printf (text
, "\n\"%s\"", name
);
3514 else if (thread
->threadpool_thread
) {
3515 g_string_append (text
, "\n\"<threadpool thread>\"");
3517 g_string_append (text
, "\n\"<unnamed thread>\"");
3520 for (i
= 0; i
< ud
->nframes
; ++i
) {
3521 MonoStackFrameInfo
*frame
= &ud
->frames
[i
];
3522 MonoMethod
*method
= NULL
;
3524 if (frame
->type
== FRAME_TYPE_MANAGED
)
3525 method
= mono_jit_info_get_method (frame
->ji
);
3528 gchar
*location
= mono_debug_print_stack_frame (method
, frame
->native_offset
, frame
->domain
);
3529 g_string_append_printf (text
, " %s\n", location
);
3532 g_string_append_printf (text
, " at <unknown> <0x%05x>\n", frame
->native_offset
);
3536 fprintf (stdout
, "%s", text
->str
);
3538 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3539 OutputDebugStringA(text
->str
);
3542 g_string_free (text
, TRUE
);
3547 mono_threads_perform_thread_dump (void)
3549 ThreadDumpUserData ud
;
3550 MonoInternalThread
*thread_array
[128];
3551 int tindex
, nthreads
;
3553 if (!thread_dump_requested
)
3556 printf ("Full thread dump:\n");
3558 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3559 nthreads
= collect_threads (thread_array
, 128);
3561 memset (&ud
, 0, sizeof (ud
));
3562 ud
.frames
= g_new0 (MonoStackFrameInfo
, 256);
3563 ud
.max_frames
= 256;
3565 for (tindex
= 0; tindex
< nthreads
; ++tindex
)
3566 dump_thread (thread_array
[tindex
], &ud
);
3570 thread_dump_requested
= FALSE
;
3573 /* Obtain the thread dump of all threads */
3575 mono_threads_get_thread_dump (MonoArray
**out_threads
, MonoArray
**out_stack_frames
, MonoError
*error
)
3578 ThreadDumpUserData ud
;
3579 MonoInternalThread
*thread_array
[128];
3580 MonoDomain
*domain
= mono_domain_get ();
3581 MonoDebugSourceLocation
*location
;
3582 int tindex
, nthreads
;
3586 *out_threads
= NULL
;
3587 *out_stack_frames
= NULL
;
3589 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3590 nthreads
= collect_threads (thread_array
, 128);
3592 memset (&ud
, 0, sizeof (ud
));
3593 ud
.frames
= g_new0 (MonoStackFrameInfo
, 256);
3594 ud
.max_frames
= 256;
3596 *out_threads
= mono_array_new_checked (domain
, mono_defaults
.thread_class
, nthreads
, error
);
3599 *out_stack_frames
= mono_array_new_checked (domain
, mono_defaults
.array_class
, nthreads
, error
);
3603 for (tindex
= 0; tindex
< nthreads
; ++tindex
) {
3604 MonoInternalThread
*thread
= thread_array
[tindex
];
3605 MonoArray
*thread_frames
;
3611 /* Collect frames for the thread */
3612 if (thread
== mono_thread_internal_current ()) {
3613 get_thread_dump (mono_thread_info_current (), &ud
);
3615 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread
), FALSE
, get_thread_dump
, &ud
);
3618 mono_array_setref_fast (*out_threads
, tindex
, mono_thread_current_for_thread (thread
));
3620 thread_frames
= mono_array_new_checked (domain
, mono_defaults
.stack_frame_class
, ud
.nframes
, error
);
3623 mono_array_setref_fast (*out_stack_frames
, tindex
, thread_frames
);
3625 for (i
= 0; i
< ud
.nframes
; ++i
) {
3626 MonoStackFrameInfo
*frame
= &ud
.frames
[i
];
3627 MonoMethod
*method
= NULL
;
3628 MonoStackFrame
*sf
= (MonoStackFrame
*)mono_object_new_checked (domain
, mono_defaults
.stack_frame_class
, error
);
3632 sf
->native_offset
= frame
->native_offset
;
3634 if (frame
->type
== FRAME_TYPE_MANAGED
)
3635 method
= mono_jit_info_get_method (frame
->ji
);
3638 sf
->method_address
= (gsize
) frame
->ji
->code_start
;
3640 MonoReflectionMethod
*rm
= mono_method_get_object_checked (domain
, method
, NULL
, error
);
3643 MONO_OBJECT_SETREF (sf
, method
, rm
);
3645 location
= mono_debug_lookup_source_location (method
, frame
->native_offset
, domain
);
3647 sf
->il_offset
= location
->il_offset
;
3649 if (location
&& location
->source_file
) {
3650 MONO_OBJECT_SETREF (sf
, filename
, mono_string_new (domain
, location
->source_file
));
3651 sf
->line
= location
->row
;
3652 sf
->column
= location
->column
;
3654 mono_debug_free_source_location (location
);
3659 mono_array_setref (thread_frames
, i
, sf
);
3665 return is_ok (error
);
3669 * mono_threads_request_thread_dump:
3671 * Ask all threads except the current to print their stacktrace to stdout.
3674 mono_threads_request_thread_dump (void)
3676 /*The new thread dump code runs out of the finalizer thread. */
3677 thread_dump_requested
= TRUE
;
3678 mono_gc_finalize_notify ();
3683 gint allocated
; /* +1 so that refs [allocated] == NULL */
3687 typedef struct ref_stack RefStack
;
3690 ref_stack_new (gint initial_size
)
3694 initial_size
= MAX (initial_size
, 16) + 1;
3695 rs
= g_new0 (RefStack
, 1);
3696 rs
->refs
= g_new0 (gpointer
, initial_size
);
3697 rs
->allocated
= initial_size
;
3702 ref_stack_destroy (gpointer ptr
)
3704 RefStack
*rs
= (RefStack
*)ptr
;
3713 ref_stack_push (RefStack
*rs
, gpointer ptr
)
3715 g_assert (rs
!= NULL
);
3717 if (rs
->bottom
>= rs
->allocated
) {
3718 rs
->refs
= (void **)g_realloc (rs
->refs
, rs
->allocated
* 2 * sizeof (gpointer
) + 1);
3719 rs
->allocated
<<= 1;
3720 rs
->refs
[rs
->allocated
] = NULL
;
3722 rs
->refs
[rs
->bottom
++] = ptr
;
3726 ref_stack_pop (RefStack
*rs
)
3728 if (rs
== NULL
|| rs
->bottom
== 0)
3732 rs
->refs
[rs
->bottom
] = NULL
;
3736 ref_stack_find (RefStack
*rs
, gpointer ptr
)
3743 for (refs
= rs
->refs
; refs
&& *refs
; refs
++) {
3751 * mono_thread_push_appdomain_ref:
3753 * Register that the current thread may have references to objects in domain
3754 * @domain on its stack. Each call to this function should be paired with a
3755 * call to pop_appdomain_ref.
3758 mono_thread_push_appdomain_ref (MonoDomain
*domain
)
3760 MonoInternalThread
*thread
= mono_thread_internal_current ();
3763 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3764 SPIN_LOCK (thread
->lock_thread_id
);
3765 if (thread
->appdomain_refs
== NULL
)
3766 thread
->appdomain_refs
= ref_stack_new (16);
3767 ref_stack_push ((RefStack
*)thread
->appdomain_refs
, domain
);
3768 SPIN_UNLOCK (thread
->lock_thread_id
);
3773 mono_thread_pop_appdomain_ref (void)
3775 MonoInternalThread
*thread
= mono_thread_internal_current ();
3778 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3779 SPIN_LOCK (thread
->lock_thread_id
);
3780 ref_stack_pop ((RefStack
*)thread
->appdomain_refs
);
3781 SPIN_UNLOCK (thread
->lock_thread_id
);
3786 mono_thread_internal_has_appdomain_ref (MonoInternalThread
*thread
, MonoDomain
*domain
)
3789 SPIN_LOCK (thread
->lock_thread_id
);
3790 res
= ref_stack_find ((RefStack
*)thread
->appdomain_refs
, domain
);
3791 SPIN_UNLOCK (thread
->lock_thread_id
);
3796 mono_thread_has_appdomain_ref (MonoThread
*thread
, MonoDomain
*domain
)
3798 return mono_thread_internal_has_appdomain_ref (thread
->internal_thread
, domain
);
3801 typedef struct abort_appdomain_data
{
3802 struct wait_data wait
;
3804 } abort_appdomain_data
;
3807 collect_appdomain_thread (gpointer key
, gpointer value
, gpointer user_data
)
3809 MonoInternalThread
*thread
= (MonoInternalThread
*)value
;
3810 abort_appdomain_data
*data
= (abort_appdomain_data
*)user_data
;
3811 MonoDomain
*domain
= data
->domain
;
3813 if (mono_thread_internal_has_appdomain_ref (thread
, domain
)) {
3814 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3816 if(data
->wait
.num
<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
) {
3817 data
->wait
.handles
[data
->wait
.num
] = mono_threads_open_thread_handle (thread
->handle
);
3818 data
->wait
.threads
[data
->wait
.num
] = thread
;
3821 /* Just ignore the rest, we can't do anything with
3829 * mono_threads_abort_appdomain_threads:
3831 * Abort threads which has references to the given appdomain.
3834 mono_threads_abort_appdomain_threads (MonoDomain
*domain
, int timeout
)
3836 #ifdef __native_client__
3840 abort_appdomain_data user_data
;
3842 int orig_timeout
= timeout
;
3845 THREAD_DEBUG (g_message ("%s: starting abort", __func__
));
3847 start_time
= mono_msec_ticks ();
3849 mono_threads_lock ();
3851 user_data
.domain
= domain
;
3852 user_data
.wait
.num
= 0;
3853 /* This shouldn't take any locks */
3854 mono_g_hash_table_foreach (threads
, collect_appdomain_thread
, &user_data
);
3855 mono_threads_unlock ();
3857 if (user_data
.wait
.num
> 0) {
3858 /* Abort the threads outside the threads lock */
3859 for (i
= 0; i
< user_data
.wait
.num
; ++i
)
3860 mono_thread_internal_abort (user_data
.wait
.threads
[i
]);
3863 * We should wait for the threads either to abort, or to leave the
3864 * domain. We can't do the latter, so we wait with a timeout.
3866 wait_for_tids (&user_data
.wait
, 100, FALSE
);
3869 /* Update remaining time */
3870 timeout
-= mono_msec_ticks () - start_time
;
3871 start_time
= mono_msec_ticks ();
3873 if (orig_timeout
!= -1 && timeout
< 0)
3876 while (user_data
.wait
.num
> 0);
3878 THREAD_DEBUG (g_message ("%s: abort done", __func__
));
3884 * mono_thread_get_undeniable_exception:
3886 * Return an exception which needs to be raised when leaving a catch clause.
3887 * This is used for undeniable exception propagation.
3890 mono_thread_get_undeniable_exception (void)
3892 MonoInternalThread
*thread
= mono_thread_internal_current ();
3894 if (!(thread
&& thread
->abort_exc
&& !is_running_protected_wrapper ()))
3897 // We don't want to have our exception effect calls made by
3898 // the catching block
3900 if (!mono_get_eh_callbacks ()->mono_above_abort_threshold ())
3904 * FIXME: Clear the abort exception and return an AppDomainUnloaded
3905 * exception if the thread no longer references a dying appdomain.
3907 thread
->abort_exc
->trace_ips
= NULL
;
3908 thread
->abort_exc
->stack_trace
= NULL
;
3909 return thread
->abort_exc
;
3912 #if MONO_SMALL_CONFIG
3913 #define NUM_STATIC_DATA_IDX 4
3914 static const int static_data_size
[NUM_STATIC_DATA_IDX
] = {
3918 #define NUM_STATIC_DATA_IDX 8
3919 static const int static_data_size
[NUM_STATIC_DATA_IDX
] = {
3920 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
3924 static MonoBitSet
*thread_reference_bitmaps
[NUM_STATIC_DATA_IDX
];
3925 static MonoBitSet
*context_reference_bitmaps
[NUM_STATIC_DATA_IDX
];
3928 mark_slots (void *addr
, MonoBitSet
**bitmaps
, MonoGCMarkFunc mark_func
, void *gc_data
)
3930 gpointer
*static_data
= (gpointer
*)addr
;
3932 for (int i
= 0; i
< NUM_STATIC_DATA_IDX
; ++i
) {
3933 void **ptr
= (void **)static_data
[i
];
3938 MONO_BITSET_FOREACH (bitmaps
[i
], idx
, {
3939 void **p
= ptr
+ idx
;
3942 mark_func ((MonoObject
**)p
, gc_data
);
3948 mark_tls_slots (void *addr
, MonoGCMarkFunc mark_func
, void *gc_data
)
3950 mark_slots (addr
, thread_reference_bitmaps
, mark_func
, gc_data
);
3954 mark_ctx_slots (void *addr
, MonoGCMarkFunc mark_func
, void *gc_data
)
3956 mark_slots (addr
, context_reference_bitmaps
, mark_func
, gc_data
);
3960 * mono_alloc_static_data
3962 * Allocate memory blocks for storing threads or context static data
3965 mono_alloc_static_data (gpointer
**static_data_ptr
, guint32 offset
, gboolean threadlocal
)
3967 guint idx
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, index
);
3970 gpointer
* static_data
= *static_data_ptr
;
3972 static MonoGCDescriptor tls_desc
= MONO_GC_DESCRIPTOR_NULL
;
3973 static MonoGCDescriptor ctx_desc
= MONO_GC_DESCRIPTOR_NULL
;
3975 if (mono_gc_user_markers_supported ()) {
3976 if (tls_desc
== MONO_GC_DESCRIPTOR_NULL
)
3977 tls_desc
= mono_gc_make_root_descr_user (mark_tls_slots
);
3979 if (ctx_desc
== MONO_GC_DESCRIPTOR_NULL
)
3980 ctx_desc
= mono_gc_make_root_descr_user (mark_ctx_slots
);
3983 static_data
= (void **)mono_gc_alloc_fixed (static_data_size
[0], threadlocal
? tls_desc
: ctx_desc
,
3984 threadlocal
? MONO_ROOT_SOURCE_THREAD_STATIC
: MONO_ROOT_SOURCE_CONTEXT_STATIC
,
3985 threadlocal
? "managed thread-static variables" : "managed context-static variables");
3986 *static_data_ptr
= static_data
;
3987 static_data
[0] = static_data
;
3990 for (i
= 1; i
<= idx
; ++i
) {
3991 if (static_data
[i
])
3994 if (mono_gc_user_markers_supported ())
3995 static_data
[i
] = g_malloc0 (static_data_size
[i
]);
3997 static_data
[i
] = mono_gc_alloc_fixed (static_data_size
[i
], MONO_GC_DESCRIPTOR_NULL
,
3998 threadlocal
? MONO_ROOT_SOURCE_THREAD_STATIC
: MONO_ROOT_SOURCE_CONTEXT_STATIC
,
3999 threadlocal
? "managed thread-static variables" : "managed context-static variables");
4004 mono_free_static_data (gpointer
* static_data
)
4007 for (i
= 1; i
< NUM_STATIC_DATA_IDX
; ++i
) {
4008 gpointer p
= static_data
[i
];
4012 * At this point, the static data pointer array is still registered with the
4013 * GC, so must ensure that mark_tls_slots() will not encounter any invalid
4014 * data. Freeing the individual arrays without first nulling their slots
4015 * would make it possible for mark_tls/ctx_slots() to encounter a pointer to
4016 * such an already freed array. See bug #13813.
4018 static_data
[i
] = NULL
;
4019 mono_memory_write_barrier ();
4020 if (mono_gc_user_markers_supported ())
4023 mono_gc_free_fixed (p
);
4025 mono_gc_free_fixed (static_data
);
4029 * mono_init_static_data_info
4031 * Initializes static data counters
4033 static void mono_init_static_data_info (StaticDataInfo
*static_data
)
4035 static_data
->idx
= 0;
4036 static_data
->offset
= 0;
4037 static_data
->freelist
= NULL
;
4041 * mono_alloc_static_data_slot
4043 * Generates an offset for static data. static_data contains the counters
4044 * used to generate it.
4047 mono_alloc_static_data_slot (StaticDataInfo
*static_data
, guint32 size
, guint32 align
)
4049 if (!static_data
->idx
&& !static_data
->offset
) {
4051 * we use the first chunk of the first allocation also as
4052 * an array for the rest of the data
4054 static_data
->offset
= sizeof (gpointer
) * NUM_STATIC_DATA_IDX
;
4056 static_data
->offset
+= align
- 1;
4057 static_data
->offset
&= ~(align
- 1);
4058 if (static_data
->offset
+ size
>= static_data_size
[static_data
->idx
]) {
4059 static_data
->idx
++;
4060 g_assert (size
<= static_data_size
[static_data
->idx
]);
4061 g_assert (static_data
->idx
< NUM_STATIC_DATA_IDX
);
4062 static_data
->offset
= 0;
4064 guint32 offset
= MAKE_SPECIAL_STATIC_OFFSET (static_data
->idx
, static_data
->offset
, 0);
4065 static_data
->offset
+= size
;
4070 * LOCKING: requires that threads_mutex is held
4073 context_adjust_static_data (MonoAppContext
*ctx
)
4075 if (context_static_info
.offset
|| context_static_info
.idx
> 0) {
4076 guint32 offset
= MAKE_SPECIAL_STATIC_OFFSET (context_static_info
.idx
, context_static_info
.offset
, 0);
4077 mono_alloc_static_data (&ctx
->static_data
, offset
, FALSE
);
4078 ctx
->data
->static_data
= ctx
->static_data
;
4083 * LOCKING: requires that threads_mutex is held
4086 alloc_thread_static_data_helper (gpointer key
, gpointer value
, gpointer user
)
4088 MonoInternalThread
*thread
= (MonoInternalThread
*)value
;
4089 guint32 offset
= GPOINTER_TO_UINT (user
);
4091 mono_alloc_static_data (&(thread
->static_data
), offset
, TRUE
);
4095 * LOCKING: requires that threads_mutex is held
4098 alloc_context_static_data_helper (gpointer key
, gpointer value
, gpointer user
)
4100 MonoAppContext
*ctx
= (MonoAppContext
*) mono_gchandle_get_target (GPOINTER_TO_INT (key
));
4105 guint32 offset
= GPOINTER_TO_UINT (user
);
4106 mono_alloc_static_data (&ctx
->static_data
, offset
, FALSE
);
4107 ctx
->data
->static_data
= ctx
->static_data
;
4110 static StaticDataFreeList
*
4111 search_slot_in_freelist (StaticDataInfo
*static_data
, guint32 size
, guint32 align
)
4113 StaticDataFreeList
* prev
= NULL
;
4114 StaticDataFreeList
* tmp
= static_data
->freelist
;
4116 if (tmp
->size
== size
) {
4118 prev
->next
= tmp
->next
;
4120 static_data
->freelist
= tmp
->next
;
4129 #if SIZEOF_VOID_P == 4
4136 update_reference_bitmap (MonoBitSet
**sets
, guint32 offset
, uintptr_t *bitmap
, int numbits
)
4138 int idx
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, index
);
4140 sets
[idx
] = mono_bitset_new (static_data_size
[idx
] / sizeof (uintptr_t), 0);
4141 MonoBitSet
*rb
= sets
[idx
];
4142 offset
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, offset
);
4143 offset
/= sizeof (uintptr_t);
4144 /* offset is now the bitmap offset */
4145 for (int i
= 0; i
< numbits
; ++i
) {
4146 if (bitmap
[i
/ sizeof (uintptr_t)] & (ONE_P
<< (i
& (sizeof (uintptr_t) * 8 -1))))
4147 mono_bitset_set_fast (rb
, offset
+ i
);
4152 clear_reference_bitmap (MonoBitSet
**sets
, guint32 offset
, guint32 size
)
4154 int idx
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, index
);
4155 MonoBitSet
*rb
= sets
[idx
];
4156 offset
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, offset
);
4157 offset
/= sizeof (uintptr_t);
4158 /* offset is now the bitmap offset */
4159 for (int i
= 0; i
< size
/ sizeof (uintptr_t); i
++)
4160 mono_bitset_clear_fast (rb
, offset
+ i
);
4164 mono_alloc_special_static_data (guint32 static_type
, guint32 size
, guint32 align
, uintptr_t *bitmap
, int numbits
)
4166 g_assert (static_type
== SPECIAL_STATIC_THREAD
|| static_type
== SPECIAL_STATIC_CONTEXT
);
4168 StaticDataInfo
*info
;
4171 if (static_type
== SPECIAL_STATIC_THREAD
) {
4172 info
= &thread_static_info
;
4173 sets
= thread_reference_bitmaps
;
4175 info
= &context_static_info
;
4176 sets
= context_reference_bitmaps
;
4179 mono_threads_lock ();
4181 StaticDataFreeList
*item
= search_slot_in_freelist (info
, size
, align
);
4185 offset
= item
->offset
;
4188 offset
= mono_alloc_static_data_slot (info
, size
, align
);
4191 update_reference_bitmap (sets
, offset
, bitmap
, numbits
);
4193 if (static_type
== SPECIAL_STATIC_THREAD
) {
4194 /* This can be called during startup */
4195 if (threads
!= NULL
)
4196 mono_g_hash_table_foreach (threads
, alloc_thread_static_data_helper
, GUINT_TO_POINTER (offset
));
4198 if (contexts
!= NULL
)
4199 g_hash_table_foreach (contexts
, alloc_context_static_data_helper
, GUINT_TO_POINTER (offset
));
4201 ACCESS_SPECIAL_STATIC_OFFSET (offset
, type
) = SPECIAL_STATIC_OFFSET_TYPE_CONTEXT
;
4204 mono_threads_unlock ();
4210 mono_get_special_static_data_for_thread (MonoInternalThread
*thread
, guint32 offset
)
4212 guint32 static_type
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, type
);
4214 if (static_type
== SPECIAL_STATIC_OFFSET_TYPE_THREAD
) {
4215 return get_thread_static_data (thread
, offset
);
4217 return get_context_static_data (thread
->current_appcontext
, offset
);
4222 mono_get_special_static_data (guint32 offset
)
4224 return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset
);
4233 * LOCKING: requires that threads_mutex is held
4236 free_thread_static_data_helper (gpointer key
, gpointer value
, gpointer user
)
4238 MonoInternalThread
*thread
= (MonoInternalThread
*)value
;
4239 OffsetSize
*data
= (OffsetSize
*)user
;
4240 int idx
= ACCESS_SPECIAL_STATIC_OFFSET (data
->offset
, index
);
4241 int off
= ACCESS_SPECIAL_STATIC_OFFSET (data
->offset
, offset
);
4244 if (!thread
->static_data
|| !thread
->static_data
[idx
])
4246 ptr
= ((char*) thread
->static_data
[idx
]) + off
;
4247 mono_gc_bzero_atomic (ptr
, data
->size
);
4251 * LOCKING: requires that threads_mutex is held
4254 free_context_static_data_helper (gpointer key
, gpointer value
, gpointer user
)
4256 MonoAppContext
*ctx
= (MonoAppContext
*) mono_gchandle_get_target (GPOINTER_TO_INT (key
));
4261 OffsetSize
*data
= (OffsetSize
*)user
;
4262 int idx
= ACCESS_SPECIAL_STATIC_OFFSET (data
->offset
, index
);
4263 int off
= ACCESS_SPECIAL_STATIC_OFFSET (data
->offset
, offset
);
4266 if (!ctx
->static_data
|| !ctx
->static_data
[idx
])
4269 ptr
= ((char*) ctx
->static_data
[idx
]) + off
;
4270 mono_gc_bzero_atomic (ptr
, data
->size
);
4274 do_free_special_slot (guint32 offset
, guint32 size
)
4276 guint32 static_type
= ACCESS_SPECIAL_STATIC_OFFSET (offset
, type
);
4278 StaticDataInfo
*info
;
4280 if (static_type
== SPECIAL_STATIC_OFFSET_TYPE_THREAD
) {
4281 info
= &thread_static_info
;
4282 sets
= thread_reference_bitmaps
;
4284 info
= &context_static_info
;
4285 sets
= context_reference_bitmaps
;
4288 guint32 data_offset
= offset
;
4289 ACCESS_SPECIAL_STATIC_OFFSET (data_offset
, type
) = 0;
4290 OffsetSize data
= { data_offset
, size
};
4292 clear_reference_bitmap (sets
, data
.offset
, data
.size
);
4294 if (static_type
== SPECIAL_STATIC_OFFSET_TYPE_THREAD
) {
4295 if (threads
!= NULL
)
4296 mono_g_hash_table_foreach (threads
, free_thread_static_data_helper
, &data
);
4298 if (contexts
!= NULL
)
4299 g_hash_table_foreach (contexts
, free_context_static_data_helper
, &data
);
4302 if (!mono_runtime_is_shutting_down ()) {
4303 StaticDataFreeList
*item
= g_new0 (StaticDataFreeList
, 1);
4305 item
->offset
= offset
;
4308 item
->next
= info
->freelist
;
4309 info
->freelist
= item
;
4314 do_free_special (gpointer key
, gpointer value
, gpointer data
)
4316 MonoClassField
*field
= (MonoClassField
*)key
;
4317 guint32 offset
= GPOINTER_TO_UINT (value
);
4320 size
= mono_type_size (field
->type
, &align
);
4321 do_free_special_slot (offset
, size
);
4325 mono_alloc_special_static_data_free (GHashTable
*special_static_fields
)
4327 mono_threads_lock ();
4329 g_hash_table_foreach (special_static_fields
, do_free_special
, NULL
);
4331 mono_threads_unlock ();
4335 static void CALLBACK
dummy_apc (ULONG_PTR param
)
4341 * mono_thread_execute_interruption
4343 * Performs the operation that the requested thread state requires (abort,
4346 static MonoException
*
4347 mono_thread_execute_interruption (void)
4349 MonoInternalThread
*thread
= mono_thread_internal_current ();
4350 MonoThread
*sys_thread
= mono_thread_current ();
4352 LOCK_THREAD (thread
);
4354 /* MonoThread::interruption_requested can only be changed with atomics */
4355 if (mono_thread_clear_interruption_requested (thread
)) {
4356 /* this will consume pending APC calls */
4358 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE
);
4360 InterlockedDecrement (&thread_interruption_requested
);
4362 /* Clear the interrupted flag of the thread so it can wait again */
4363 mono_thread_info_clear_self_interrupt ();
4366 /* If there's a pending exception and an AbortRequested, the pending exception takes precedence */
4367 if (sys_thread
->pending_exception
) {
4370 exc
= sys_thread
->pending_exception
;
4371 sys_thread
->pending_exception
= NULL
;
4373 UNLOCK_THREAD (thread
);
4375 } else if (thread
->state
& (ThreadState_AbortRequested
)) {
4376 UNLOCK_THREAD (thread
);
4377 g_assert (sys_thread
->pending_exception
== NULL
);
4378 if (thread
->abort_exc
== NULL
) {
4380 * This might be racy, but it has to be called outside the lock
4381 * since it calls managed code.
4383 MONO_OBJECT_SETREF (thread
, abort_exc
, mono_get_exception_thread_abort ());
4385 return thread
->abort_exc
;
4386 } else if (thread
->state
& (ThreadState_SuspendRequested
)) {
4387 /* calls UNLOCK_THREAD (thread) */
4388 self_suspend_internal ();
4390 } else if (thread
->thread_interrupt_requested
) {
4392 thread
->thread_interrupt_requested
= FALSE
;
4393 UNLOCK_THREAD (thread
);
4395 return(mono_get_exception_thread_interrupted ());
4398 UNLOCK_THREAD (thread
);
4404 * mono_thread_request_interruption
4406 * A signal handler can call this method to request the interruption of a
4407 * thread. The result of the interruption will depend on the current state of
4408 * the thread. If the result is an exception that needs to be throw, it is
4409 * provided as return value.
4412 mono_thread_request_interruption (gboolean running_managed
)
4414 MonoInternalThread
*thread
= mono_thread_internal_current ();
4416 /* The thread may already be stopping */
4420 if (!mono_thread_set_interruption_requested (thread
))
4422 InterlockedIncrement (&thread_interruption_requested
);
4424 if (!running_managed
|| is_running_protected_wrapper ()) {
4425 /* Can't stop while in unmanaged code. Increase the global interruption
4426 request count. When exiting the unmanaged method the count will be
4427 checked and the thread will be interrupted. */
4429 /* this will awake the thread if it is in WaitForSingleObject
4431 /* Our implementation of this function ignores the func argument */
4433 QueueUserAPC ((PAPCFUNC
)dummy_apc
, thread
->native_handle
, (ULONG_PTR
)NULL
);
4435 mono_thread_info_self_interrupt ();
4440 return mono_thread_execute_interruption ();
4444 /*This function should be called by a thread after it has exited all of
4445 * its handle blocks at interruption time.*/
4447 mono_thread_resume_interruption (void)
4449 MonoInternalThread
*thread
= mono_thread_internal_current ();
4450 gboolean still_aborting
;
4452 /* The thread may already be stopping */
4456 LOCK_THREAD (thread
);
4457 still_aborting
= (thread
->state
& (ThreadState_AbortRequested
)) != 0;
4458 UNLOCK_THREAD (thread
);
4460 /*This can happen if the protected block called Thread::ResetAbort*/
4461 if (!still_aborting
)
4464 if (!mono_thread_set_interruption_requested (thread
))
4466 InterlockedIncrement (&thread_interruption_requested
);
4468 mono_thread_info_self_interrupt ();
4470 return mono_thread_execute_interruption ();
4473 gboolean
mono_thread_interruption_requested ()
4475 if (thread_interruption_requested
) {
4476 MonoInternalThread
*thread
= mono_thread_internal_current ();
4477 /* The thread may already be stopping */
4479 return mono_thread_get_interruption_requested (thread
);
4484 static MonoException
*
4485 mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection
)
4487 MonoInternalThread
*thread
= mono_thread_internal_current ();
4489 /* The thread may already be stopping */
4492 if (!mono_thread_get_interruption_requested (thread
))
4494 if (!bypass_abort_protection
&& is_running_protected_wrapper ())
4497 return mono_thread_execute_interruption ();
4501 * Performs the interruption of the current thread, if one has been requested,
4502 * and the thread is not running a protected wrapper.
4503 * Return the exception which needs to be thrown, if any.
4506 mono_thread_interruption_checkpoint (void)
4508 return mono_thread_interruption_checkpoint_request (FALSE
);
4512 * Performs the interruption of the current thread, if one has been requested.
4513 * Return the exception which needs to be thrown, if any.
4516 mono_thread_force_interruption_checkpoint_noraise (void)
4518 return mono_thread_interruption_checkpoint_request (TRUE
);
4522 * mono_set_pending_exception:
4524 * Set the pending exception of the current thread to EXC.
4525 * The exception will be thrown when execution returns to managed code.
4528 mono_set_pending_exception (MonoException
*exc
)
4530 MonoThread
*thread
= mono_thread_current ();
4532 /* The thread may already be stopping */
4536 MONO_OBJECT_SETREF (thread
, pending_exception
, exc
);
4538 mono_thread_request_interruption (FALSE
);
4542 * mono_thread_interruption_request_flag:
4544 * Returns the address of a flag that will be non-zero if an interruption has
4545 * been requested for a thread. The thread to interrupt may not be the current
4546 * thread, so an additional call to mono_thread_interruption_requested() or
4547 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4550 gint32
* mono_thread_interruption_request_flag ()
4552 return &thread_interruption_requested
;
4556 mono_thread_init_apartment_state (void)
4559 MonoInternalThread
* thread
= mono_thread_internal_current ();
4561 /* Positive return value indicates success, either
4562 * S_OK if this is first CoInitialize call, or
4563 * S_FALSE if CoInitialize already called, but with same
4564 * threading model. A negative value indicates failure,
4565 * probably due to trying to change the threading model.
4567 if (CoInitializeEx(NULL
, (thread
->apartment_state
== ThreadApartmentState_STA
)
4568 ? COINIT_APARTMENTTHREADED
4569 : COINIT_MULTITHREADED
) < 0) {
4570 thread
->apartment_state
= ThreadApartmentState_Unknown
;
4576 mono_thread_cleanup_apartment_state (void)
4579 MonoInternalThread
* thread
= mono_thread_internal_current ();
4581 if (thread
&& thread
->apartment_state
!= ThreadApartmentState_Unknown
) {
4588 mono_thread_set_state (MonoInternalThread
*thread
, MonoThreadState state
)
4590 LOCK_THREAD (thread
);
4591 thread
->state
|= state
;
4592 UNLOCK_THREAD (thread
);
4596 * mono_thread_test_and_set_state:
4598 * Test if current state of @thread include @test. If it does not, OR @set into the state.
4600 * Returns TRUE is @set was OR'd in.
4603 mono_thread_test_and_set_state (MonoInternalThread
*thread
, MonoThreadState test
, MonoThreadState set
)
4605 LOCK_THREAD (thread
);
4607 if ((thread
->state
& test
) != 0) {
4608 UNLOCK_THREAD (thread
);
4612 thread
->state
|= set
;
4613 UNLOCK_THREAD (thread
);
4619 mono_thread_clr_state (MonoInternalThread
*thread
, MonoThreadState state
)
4621 LOCK_THREAD (thread
);
4622 thread
->state
&= ~state
;
4623 UNLOCK_THREAD (thread
);
4627 mono_thread_test_state (MonoInternalThread
*thread
, MonoThreadState test
)
4629 gboolean ret
= FALSE
;
4631 LOCK_THREAD (thread
);
4633 if ((thread
->state
& test
) != 0) {
4637 UNLOCK_THREAD (thread
);
4643 self_interrupt_thread (void *_unused
)
4646 MonoThreadInfo
*info
;
4648 exc
= mono_thread_execute_interruption ();
4650 if (mono_threads_is_coop_enabled ()) {
4651 /* We can return from an async call in coop, as
4652 * it's simply called when exiting the safepoint */
4656 g_error ("%s: we can't resume from an async call", __func__
);
4659 info
= mono_thread_info_current ();
4661 /* We must use _with_context since we didn't trampoline into the runtime */
4662 mono_raise_exception_with_context (exc
, &info
->thread_saved_state
[ASYNC_SUSPEND_STATE_INDEX
].ctx
); /* FIXME using thread_saved_state [ASYNC_SUSPEND_STATE_INDEX] can race with another suspend coming in. */
4666 mono_jit_info_match (MonoJitInfo
*ji
, gpointer ip
)
4670 return ji
->code_start
<= ip
&& (char*)ip
< (char*)ji
->code_start
+ ji
->code_size
;
4674 last_managed (MonoStackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
4676 MonoJitInfo
**dest
= (MonoJitInfo
**)data
;
4682 mono_thread_info_get_last_managed (MonoThreadInfo
*info
)
4684 MonoJitInfo
*ji
= NULL
;
4689 * The suspended thread might be holding runtime locks. Make sure we don't try taking
4690 * any runtime locks while unwinding. In coop case we shouldn't safepoint in regions
4691 * where we hold runtime locks.
4693 if (!mono_threads_is_coop_enabled ())
4694 mono_thread_info_set_is_async_context (TRUE
);
4695 mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed
, mono_thread_info_get_suspend_state (info
), MONO_UNWIND_SIGNAL_SAFE
, &ji
);
4696 if (!mono_threads_is_coop_enabled ())
4697 mono_thread_info_set_is_async_context (FALSE
);
4702 MonoInternalThread
*thread
;
4703 gboolean install_async_abort
;
4704 MonoThreadInfoInterruptToken
*interrupt_token
;
4707 static SuspendThreadResult
4708 async_abort_critical (MonoThreadInfo
*info
, gpointer ud
)
4710 AbortThreadData
*data
= (AbortThreadData
*)ud
;
4711 MonoInternalThread
*thread
= data
->thread
;
4712 MonoJitInfo
*ji
= NULL
;
4713 gboolean protected_wrapper
;
4714 gboolean running_managed
;
4716 if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info
)))
4717 return MonoResumeThread
;
4719 /*someone is already interrupting it*/
4720 if (!mono_thread_set_interruption_requested (thread
))
4721 return MonoResumeThread
;
4723 InterlockedIncrement (&thread_interruption_requested
);
4725 ji
= mono_thread_info_get_last_managed (info
);
4726 protected_wrapper
= ji
&& !ji
->is_trampoline
&& !ji
->async
&& mono_threads_is_critical_method (mono_jit_info_get_method (ji
));
4727 running_managed
= mono_jit_info_match (ji
, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info
)->ctx
));
4729 if (!protected_wrapper
&& running_managed
) {
4730 /*We are in managed code*/
4731 /*Set the thread to call */
4732 if (data
->install_async_abort
)
4733 mono_thread_info_setup_async_call (info
, self_interrupt_thread
, NULL
);
4734 return MonoResumeThread
;
4737 * This will cause waits to be broken.
4738 * It will also prevent the thread from entering a wait, so if the thread returns
4739 * from the wait before it receives the abort signal, it will just spin in the wait
4740 * functions in the io-layer until the signal handler calls QueueUserAPC which will
4743 data
->interrupt_token
= mono_thread_info_prepare_interrupt (info
);
4745 return MonoResumeThread
;
4750 async_abort_internal (MonoInternalThread
*thread
, gboolean install_async_abort
)
4752 AbortThreadData data
;
4754 g_assert (thread
!= mono_thread_internal_current ());
4756 data
.thread
= thread
;
4757 data
.install_async_abort
= install_async_abort
;
4758 data
.interrupt_token
= NULL
;
4760 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread
), TRUE
, async_abort_critical
, &data
);
4761 if (data
.interrupt_token
)
4762 mono_thread_info_finish_interrupt (data
.interrupt_token
);
4763 /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4767 self_abort_internal (MonoError
*error
)
4773 /* FIXME this is insanely broken, it doesn't cause interruption to happen synchronously
4774 * since passing FALSE to mono_thread_request_interruption makes sure it returns NULL */
4777 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.
4779 exc
= mono_thread_request_interruption (TRUE
);
4781 mono_error_set_exception_instance (error
, exc
);
4783 mono_thread_info_self_interrupt ();
4787 MonoInternalThread
*thread
;
4789 MonoThreadInfoInterruptToken
*interrupt_token
;
4790 } SuspendThreadData
;
4792 static SuspendThreadResult
4793 async_suspend_critical (MonoThreadInfo
*info
, gpointer ud
)
4795 SuspendThreadData
*data
= (SuspendThreadData
*)ud
;
4796 MonoInternalThread
*thread
= data
->thread
;
4797 MonoJitInfo
*ji
= NULL
;
4798 gboolean protected_wrapper
;
4799 gboolean running_managed
;
4801 ji
= mono_thread_info_get_last_managed (info
);
4802 protected_wrapper
= ji
&& !ji
->is_trampoline
&& !ji
->async
&& mono_threads_is_critical_method (mono_jit_info_get_method (ji
));
4803 running_managed
= mono_jit_info_match (ji
, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info
)->ctx
));
4805 if (running_managed
&& !protected_wrapper
) {
4806 if (mono_threads_is_coop_enabled ()) {
4807 mono_thread_info_setup_async_call (info
, self_interrupt_thread
, NULL
);
4808 return MonoResumeThread
;
4810 thread
->state
&= ~ThreadState_SuspendRequested
;
4811 thread
->state
|= ThreadState_Suspended
;
4812 return KeepSuspended
;
4815 if (mono_thread_set_interruption_requested (thread
))
4816 InterlockedIncrement (&thread_interruption_requested
);
4817 if (data
->interrupt
)
4818 data
->interrupt_token
= mono_thread_info_prepare_interrupt ((MonoThreadInfo
*)thread
->thread_info
);
4820 return MonoResumeThread
;
4824 /* LOCKING: called with @thread synch_cs held, and releases it */
4826 async_suspend_internal (MonoInternalThread
*thread
, gboolean interrupt
)
4828 SuspendThreadData data
;
4830 g_assert (thread
!= mono_thread_internal_current ());
4832 // MOSTLY_ASYNC_SAFE_PRINTF ("ASYNC SUSPEND thread %p\n", thread_get_tid (thread));
4834 thread
->self_suspended
= FALSE
;
4836 data
.thread
= thread
;
4837 data
.interrupt
= interrupt
;
4838 data
.interrupt_token
= NULL
;
4840 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread
), interrupt
, async_suspend_critical
, &data
);
4841 if (data
.interrupt_token
)
4842 mono_thread_info_finish_interrupt (data
.interrupt_token
);
4844 UNLOCK_THREAD (thread
);
4847 /* LOCKING: called with @thread synch_cs held, and releases it */
4849 self_suspend_internal (void)
4851 MonoInternalThread
*thread
;
4853 MonoOSEventWaitRet res
;
4855 thread
= mono_thread_internal_current ();
4857 // MOSTLY_ASYNC_SAFE_PRINTF ("SELF SUSPEND thread %p\n", thread_get_tid (thread));
4859 thread
->self_suspended
= TRUE
;
4861 thread
->state
&= ~ThreadState_SuspendRequested
;
4862 thread
->state
|= ThreadState_Suspended
;
4864 UNLOCK_THREAD (thread
);
4866 event
= thread
->suspended
;
4869 res
= mono_os_event_wait_one (event
, MONO_INFINITE_WAIT
, TRUE
);
4870 g_assert (res
== MONO_OS_EVENT_WAIT_RET_SUCCESS_0
|| res
== MONO_OS_EVENT_WAIT_RET_ALERTED
);
4875 suspend_for_shutdown_async_call (gpointer unused
)
4878 mono_thread_info_yield ();
4881 static SuspendThreadResult
4882 suspend_for_shutdown_critical (MonoThreadInfo
*info
, gpointer unused
)
4884 mono_thread_info_setup_async_call (info
, suspend_for_shutdown_async_call
, NULL
);
4885 return MonoResumeThread
;
4889 mono_thread_internal_suspend_for_shutdown (MonoInternalThread
*thread
)
4891 g_assert (thread
!= mono_thread_internal_current ());
4893 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread
), FALSE
, suspend_for_shutdown_critical
, NULL
);
4897 * mono_thread_is_foreign:
4898 * @thread: the thread to query
4900 * This function allows one to determine if a thread was created by the mono runtime and has
4901 * a well defined lifecycle or it's a foreigh one, created by the native environment.
4903 * Returns: TRUE if @thread was not created by the runtime.
4906 mono_thread_is_foreign (MonoThread
*thread
)
4908 MonoThreadInfo
*info
= (MonoThreadInfo
*)thread
->internal_thread
->thread_info
;
4909 return info
->runtime_thread
== FALSE
;
4913 * mono_add_joinable_thread:
4915 * Add TID to the list of joinable threads.
4916 * LOCKING: Acquires the threads lock.
4919 mono_threads_add_joinable_thread (gpointer tid
)
4923 * We cannot detach from threads because it causes problems like
4924 * 2fd16f60/r114307. So we collect them and join them when
4925 * we have time (in he finalizer thread).
4927 joinable_threads_lock ();
4928 if (!joinable_threads
)
4929 joinable_threads
= g_hash_table_new (NULL
, NULL
);
4930 g_hash_table_insert (joinable_threads
, tid
, tid
);
4931 joinable_thread_count
++;
4932 joinable_threads_unlock ();
4934 mono_gc_finalize_notify ();
4939 * mono_threads_join_threads:
4941 * Join all joinable threads. This is called from the finalizer thread.
4942 * LOCKING: Acquires the threads lock.
4945 mono_threads_join_threads (void)
4948 GHashTableIter iter
;
4955 if (!joinable_thread_count
)
4959 joinable_threads_lock ();
4961 if (g_hash_table_size (joinable_threads
)) {
4962 g_hash_table_iter_init (&iter
, joinable_threads
);
4963 g_hash_table_iter_next (&iter
, &key
, (void**)&tid
);
4964 thread
= (pthread_t
)tid
;
4965 g_hash_table_remove (joinable_threads
, key
);
4966 joinable_thread_count
--;
4969 joinable_threads_unlock ();
4971 if (thread
!= pthread_self ()) {
4973 /* This shouldn't block */
4974 mono_threads_join_lock ();
4975 mono_native_thread_join (thread
);
4976 mono_threads_join_unlock ();
4989 * Wait for thread TID to exit.
4990 * LOCKING: Acquires the threads lock.
4993 mono_thread_join (gpointer tid
)
4997 gboolean found
= FALSE
;
4999 joinable_threads_lock ();
5000 if (!joinable_threads
)
5001 joinable_threads
= g_hash_table_new (NULL
, NULL
);
5002 if (g_hash_table_lookup (joinable_threads
, tid
)) {
5003 g_hash_table_remove (joinable_threads
, tid
);
5004 joinable_thread_count
--;
5007 joinable_threads_unlock ();
5010 thread
= (pthread_t
)tid
;
5012 mono_native_thread_join (thread
);
5018 mono_thread_internal_unhandled_exception (MonoObject
* exc
)
5020 MonoClass
*klass
= exc
->vtable
->klass
;
5021 if (is_threadabort_exception (klass
)) {
5022 mono_thread_internal_reset_abort (mono_thread_internal_current ());
5023 } else if (!is_appdomainunloaded_exception (klass
)
5024 && mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT
) {
5025 mono_unhandled_exception (exc
);
5026 if (mono_environment_exitcode_get () == 1) {
5027 mono_environment_exitcode_set (255);
5028 mono_invoke_unhandled_exception_hook (exc
);
5029 g_assert_not_reached ();
5035 ves_icall_System_Threading_Thread_GetStackTraces (MonoArray
**out_threads
, MonoArray
**out_stack_traces
)
5038 mono_threads_get_thread_dump (out_threads
, out_stack_traces
, &error
);
5039 mono_error_set_pending_exception (&error
);
5043 * mono_threads_attach_coop: called by native->managed wrappers
5047 * - @return: the original domain which needs to be restored, or NULL.
5050 * - @dummy: contains the original domain
5051 * - @return: a cookie containing current MonoThreadInfo*.
5054 mono_threads_attach_coop (MonoDomain
*domain
, gpointer
*dummy
)
5057 gboolean fresh_thread
= FALSE
;
5060 /* Happens when called from AOTed code which is only used in the root domain. */
5061 domain
= mono_get_root_domain ();
5066 /* On coop, when we detached, we moved the thread from RUNNING->BLOCKING.
5067 * If we try to reattach we do a BLOCKING->RUNNING transition. If the thread
5068 * is fresh, mono_thread_attach() will do a STARTING->RUNNING transition so
5069 * we're only responsible for making the cookie. */
5070 if (mono_threads_is_coop_enabled ()) {
5071 MonoThreadInfo
*info
= mono_thread_info_current_unchecked ();
5072 fresh_thread
= !info
|| !mono_thread_info_is_live (info
);
5075 if (!mono_thread_internal_current ()) {
5076 mono_thread_attach_full (domain
, FALSE
);
5079 mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background
);
5082 orig
= mono_domain_get ();
5084 mono_domain_set (domain
, TRUE
);
5086 if (!mono_threads_is_coop_enabled ())
5087 return orig
!= domain
? orig
: NULL
;
5091 /* mono_thread_attach put the thread in RUNNING mode from STARTING, but we need to
5092 * return the right cookie. */
5093 return mono_threads_enter_gc_unsafe_region_cookie ();
5096 /* thread state (BLOCKING|RUNNING) -> RUNNING */
5097 return mono_threads_enter_gc_unsafe_region (dummy
);
5102 * mono_threads_detach_coop: called by native->managed wrappers
5105 * - @cookie: the original domain which needs to be restored, or NULL.
5109 * - @cookie: contains current MonoThreadInfo* if it was in BLOCKING mode, NULL otherwise
5110 * - @dummy: contains the original domain
5113 mono_threads_detach_coop (gpointer cookie
, gpointer
*dummy
)
5115 MonoDomain
*domain
, *orig
;
5117 if (!mono_threads_is_coop_enabled ()) {
5118 orig
= (MonoDomain
*) cookie
;
5120 mono_domain_set (orig
, TRUE
);
5122 orig
= (MonoDomain
*) *dummy
;
5124 domain
= mono_domain_get ();
5127 /* it won't do anything if cookie is NULL
5128 * thread state RUNNING -> (RUNNING|BLOCKING) */
5129 mono_threads_exit_gc_unsafe_region (cookie
, dummy
);
5131 if (orig
!= domain
) {
5133 mono_domain_unset ();
5135 mono_domain_set (orig
, TRUE
);
5141 mono_thread_try_resume_interruption (void)
5143 MonoInternalThread
*thread
;
5145 thread
= mono_thread_internal_current ();
5146 if (!mono_get_eh_callbacks ()->mono_above_abort_threshold ())
5148 if (mono_thread_get_abort_prot_block_count (thread
) > 0 || mono_get_eh_callbacks ()->mono_current_thread_has_handle_block_guard ())
5151 return mono_thread_resume_interruption ();
5155 /* Returns TRUE if the current thread is ready to be interrupted. */
5157 mono_threads_is_ready_to_be_interrupted (void)
5159 MonoInternalThread
*thread
;
5161 thread
= mono_thread_internal_current ();
5162 LOCK_THREAD (thread
);
5163 if (thread
->state
& (ThreadState_SuspendRequested
| ThreadState_AbortRequested
)) {
5164 UNLOCK_THREAD (thread
);
5168 if (mono_thread_get_abort_prot_block_count (thread
) || mono_get_eh_callbacks ()->mono_current_thread_has_handle_block_guard ()) {
5169 UNLOCK_THREAD (thread
);
5173 UNLOCK_THREAD (thread
);
5179 mono_thread_internal_describe (MonoInternalThread
*internal
, GString
*text
)
5181 g_string_append_printf (text
, ", thread handle : %p", internal
->handle
);
5183 if (internal
->thread_info
) {
5184 g_string_append (text
, ", state : ");
5185 mono_thread_info_describe_interrupt_token ((MonoThreadInfo
*) internal
->thread_info
, text
);
5188 if (internal
->owned_mutexes
) {
5191 g_string_append (text
, ", owns : [");
5192 for (i
= 0; i
< internal
->owned_mutexes
->len
; i
++)
5193 g_string_append_printf (text
, i
== 0 ? "%p" : ", %p", g_ptr_array_index (internal
->owned_mutexes
, i
));
5194 g_string_append (text
, "]");
5199 mono_thread_internal_is_current (MonoInternalThread
*internal
)
5201 g_assert (internal
);
5202 return mono_native_thread_id_equals (mono_native_thread_id_get (), MONO_UINT_TO_NATIVE_THREAD_ID (internal
->tid
));