1 /**
2  * \file
3  * Thread support internal calls
4  *
5  * Author:
6  *	Dick Porter (dick@ximian.com)
7  *	Paolo Molaro (lupus@ximian.com)
8  *	Patrik Torstensson (patrik.torstensson@labs2.com)
9  *
10  * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
11  * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
12  * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
13  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
14  */
15 
16 #include <config.h>
17 
18 #include <glib.h>
19 #include <string.h>
20 
21 #include <mono/metadata/object.h>
22 #include <mono/metadata/domain-internals.h>
23 #include <mono/metadata/profiler-private.h>
24 #include <mono/metadata/threads.h>
25 #include <mono/metadata/threads-types.h>
26 #include <mono/metadata/exception.h>
27 #include <mono/metadata/environment.h>
28 #include <mono/metadata/monitor.h>
29 #include <mono/metadata/gc-internals.h>
30 #include <mono/metadata/marshal.h>
31 #include <mono/metadata/runtime.h>
32 #include <mono/metadata/object-internals.h>
33 #include <mono/metadata/debug-internals.h>
34 #include <mono/utils/monobitset.h>
35 #include <mono/utils/mono-compiler.h>
36 #include <mono/utils/mono-mmap.h>
37 #include <mono/utils/mono-membar.h>
38 #include <mono/utils/mono-time.h>
39 #include <mono/utils/mono-threads.h>
40 #include <mono/utils/mono-threads-coop.h>
41 #include <mono/utils/mono-tls.h>
42 #include <mono/utils/atomic.h>
43 #include <mono/utils/mono-memory-model.h>
44 #include <mono/utils/mono-error-internals.h>
45 #include <mono/utils/os-event.h>
46 #include <mono/utils/mono-threads-debug.h>
47 #include <mono/utils/unlocked.h>
48 #include <mono/metadata/w32handle.h>
49 #include <mono/metadata/w32event.h>
50 #include <mono/metadata/w32mutex.h>
51 
52 #include <mono/metadata/reflection-internals.h>
53 #include <mono/metadata/abi-details.h>
54 #include <mono/metadata/w32error.h>
55 #include <mono/utils/w32api.h>
56 #include <mono/utils/mono-os-wait.h>
57 
58 #ifdef HAVE_SIGNAL_H
59 #include <signal.h>
60 #endif
61 
62 #if defined(HOST_WIN32)
63 #include <objbase.h>
64 
65 extern gboolean
66 mono_native_thread_join_handle (HANDLE thread_handle, gboolean close_handle);
67 #endif
68 
69 #if defined(HOST_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64)
70 #define USE_TKILL_ON_ANDROID 1
71 #endif
72 
73 #ifdef HOST_ANDROID
74 #include <errno.h>
75 
76 #ifdef USE_TKILL_ON_ANDROID
77 extern int tkill (pid_t tid, int signal);
78 #endif
79 #endif
80 
81 /*#define THREAD_DEBUG(a) do { a; } while (0)*/
82 #define THREAD_DEBUG(a)
83 /*#define THREAD_WAIT_DEBUG(a) do { a; } while (0)*/
84 #define THREAD_WAIT_DEBUG(a)
85 /*#define LIBGC_DEBUG(a) do { a; } while (0)*/
86 #define LIBGC_DEBUG(a)
87 
88 #define SPIN_TRYLOCK(i) (mono_atomic_cas_i32 (&(i), 1, 0) == 0)
89 #define SPIN_LOCK(i) do { \
90 				if (SPIN_TRYLOCK (i)) \
91 					break; \
92 			} while (1)
93 
94 #define SPIN_UNLOCK(i) i = 0
95 
96 #define LOCK_THREAD(thread) lock_thread((thread))
97 #define UNLOCK_THREAD(thread) unlock_thread((thread))
98 
99 typedef union {
100 	gint32 ival;
101 	gfloat fval;
102 } IntFloatUnion;
103 
104 typedef union {
105 	gint64 ival;
106 	gdouble fval;
107 } LongDoubleUnion;
108 
109 typedef struct _StaticDataFreeList StaticDataFreeList;
110 struct _StaticDataFreeList {
111 	StaticDataFreeList *next;
112 	guint32 offset;
113 	guint32 size;
114 };
115 
116 typedef struct {
117 	int idx;
118 	int offset;
119 	StaticDataFreeList *freelist;
120 } StaticDataInfo;
121 
122 /* Controls access to the 'threads' hash table */
123 static void mono_threads_lock (void);
124 static void mono_threads_unlock (void);
125 static MonoCoopMutex threads_mutex;
126 
127 /* Controls access to the 'joinable_threads' hash table */
128 #define joinable_threads_lock() mono_os_mutex_lock (&joinable_threads_mutex)
129 #define joinable_threads_unlock() mono_os_mutex_unlock (&joinable_threads_mutex)
130 static mono_mutex_t joinable_threads_mutex;
131 
132 /* Holds current status of static data heap */
133 static StaticDataInfo thread_static_info;
134 static StaticDataInfo context_static_info;
135 
136 /* The hash of existing threads (key is thread ID, value is
137  * MonoInternalThread*) that need joining before exit
138  */
139 static MonoGHashTable *threads=NULL;
140 
141 /* List of app context GC handles.
142  * Added to from mono_threads_register_app_context ().
143  */
144 static GHashTable *contexts = NULL;
145 
146 /* Cleanup queue for contexts. */
147 static MonoReferenceQueue *context_queue;
148 
149 /*
150  * Threads which are starting up and they are not in the 'threads' hash yet.
151  * When mono_thread_attach_internal is called for a thread, it will be removed from this hash table.
152  * Protected by mono_threads_lock ().
153  */
154 static MonoGHashTable *threads_starting_up = NULL;
155 
156 /* Contains tids */
157 /* Protected by the threads lock */
158 static GHashTable *joinable_threads;
159 static gint32 joinable_thread_count;
160 
161 #define SET_CURRENT_OBJECT(x) mono_tls_set_thread (x)
162 #define GET_CURRENT_OBJECT() (MonoInternalThread*) mono_tls_get_thread ()
163 
164 /* function called at thread start */
165 static MonoThreadStartCB mono_thread_start_cb = NULL;
166 
167 /* function called at thread attach */
168 static MonoThreadAttachCB mono_thread_attach_cb = NULL;
169 
170 /* function called at thread cleanup */
171 static MonoThreadCleanupFunc mono_thread_cleanup_fn = NULL;
172 
173 /* The default stack size for each thread */
174 static guint32 default_stacksize = 0;
175 #define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize)
176 
177 static void context_adjust_static_data (MonoAppContext *ctx);
178 static void mono_free_static_data (gpointer* static_data);
179 static void mono_init_static_data_info (StaticDataInfo *static_data);
180 static guint32 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align);
181 static gboolean mono_thread_resume (MonoInternalThread* thread);
182 static void async_abort_internal (MonoInternalThread *thread, gboolean install_async_abort);
183 static void self_abort_internal (MonoError *error);
184 static void async_suspend_internal (MonoInternalThread *thread, gboolean interrupt);
185 static void self_suspend_internal (void);
186 
187 static MonoException* mono_thread_execute_interruption (void);
188 static void ref_stack_destroy (gpointer rs);
189 
190 /* Spin lock for InterlockedXXX 64 bit functions */
191 #define mono_interlocked_lock() mono_os_mutex_lock (&interlocked_mutex)
192 #define mono_interlocked_unlock() mono_os_mutex_unlock (&interlocked_mutex)
193 static mono_mutex_t interlocked_mutex;
194 
195 /* global count of thread interruptions requested */
196 static gint32 thread_interruption_requested = 0;
197 
198 /* Event signaled when a thread changes its background mode */
199 static MonoOSEvent background_change_event;
200 
201 static gboolean shutting_down = FALSE;
202 
203 static gint32 managed_thread_id_counter = 0;
204 
205 static void
mono_threads_lock(void)206 mono_threads_lock (void)
207 {
208 	mono_locks_coop_acquire (&threads_mutex, ThreadsLock);
209 }
210 
211 static void
mono_threads_unlock(void)212 mono_threads_unlock (void)
213 {
214 	mono_locks_coop_release (&threads_mutex, ThreadsLock);
215 }
216 
217 
218 static guint32
get_next_managed_thread_id(void)219 get_next_managed_thread_id (void)
220 {
221 	return mono_atomic_inc_i32 (&managed_thread_id_counter);
222 }
223 
224 /*
225  * We separate interruptions/exceptions into either sync (they can be processed anytime,
226  * normally as soon as they are set, and are set by the same thread) and async (they can't
227  * be processed inside abort protected blocks and are normally set by other threads). We
228  * can have both a pending sync and async interruption. In this case, the sync exception is
229  * processed first. Since we clean sync flag first, mono_thread_execute_interruption must
230  * also handle all sync type exceptions before the async type exceptions.
231  */
232 enum {
233 	INTERRUPT_SYNC_REQUESTED_BIT = 0x1,
234 	INTERRUPT_ASYNC_REQUESTED_BIT = 0x2,
235 	INTERRUPT_REQUESTED_MASK = 0x3,
236 	ABORT_PROT_BLOCK_SHIFT = 2,
237 	ABORT_PROT_BLOCK_BITS = 8,
238 	ABORT_PROT_BLOCK_MASK = (((1 << ABORT_PROT_BLOCK_BITS) - 1) << ABORT_PROT_BLOCK_SHIFT)
239 };
240 
241 static int
mono_thread_get_abort_prot_block_count(MonoInternalThread * thread)242 mono_thread_get_abort_prot_block_count (MonoInternalThread *thread)
243 {
244 	gsize state = thread->thread_state;
245 	return (state & ABORT_PROT_BLOCK_MASK) >> ABORT_PROT_BLOCK_SHIFT;
246 }
247 
248 void
mono_threads_begin_abort_protected_block(void)249 mono_threads_begin_abort_protected_block (void)
250 {
251 	MonoInternalThread *thread = mono_thread_internal_current ();
252 	gsize old_state, new_state;
253 	int new_val;
254 	do {
255 		old_state = thread->thread_state;
256 
257 		new_val = ((old_state & ABORT_PROT_BLOCK_MASK) >> ABORT_PROT_BLOCK_SHIFT) + 1;
258 		//bounds check abort_prot_count
259 		g_assert (new_val > 0);
260 		g_assert (new_val < (1 << ABORT_PROT_BLOCK_BITS));
261 
262 		new_state = old_state + (1 << ABORT_PROT_BLOCK_SHIFT);
263 	} while (mono_atomic_cas_ptr ((volatile gpointer *)&thread->thread_state, (gpointer)new_state, (gpointer)old_state) != (gpointer)old_state);
264 
265 	/* Defer async request since we won't be able to process until exiting the block */
266 	if (new_val == 1 && (new_state & INTERRUPT_ASYNC_REQUESTED_BIT)) {
267 		mono_atomic_dec_i32 (&thread_interruption_requested);
268 		THREADS_INTERRUPT_DEBUG ("[%d] begin abort protected block old_state %ld new_state %ld, defer tir %d\n", thread->small_id, old_state, new_state, thread_interruption_requested);
269 		if (thread_interruption_requested < 0)
270 			g_warning ("bad thread_interruption_requested state");
271 	} else {
272 		THREADS_INTERRUPT_DEBUG ("[%d] begin abort protected block old_state %ld new_state %ld, tir %d\n", thread->small_id, old_state, new_state, thread_interruption_requested);
273 	}
274 }
275 
276 static gboolean
mono_thread_state_has_interruption(gsize state)277 mono_thread_state_has_interruption (gsize state)
278 {
279 	/* pending exception, self abort */
280 	if (state & INTERRUPT_SYNC_REQUESTED_BIT)
281 		return TRUE;
282 
283 	/* abort, interruption, suspend */
284 	if ((state & INTERRUPT_ASYNC_REQUESTED_BIT) && !(state & ABORT_PROT_BLOCK_MASK))
285 		return TRUE;
286 
287 	return FALSE;
288 }
289 
290 gboolean
mono_threads_end_abort_protected_block(void)291 mono_threads_end_abort_protected_block (void)
292 {
293 	MonoInternalThread *thread = mono_thread_internal_current ();
294 	gsize old_state, new_state;
295 	int new_val;
296 	do {
297 		old_state = thread->thread_state;
298 
299 		//bounds check abort_prot_count
300 		new_val = ((old_state & ABORT_PROT_BLOCK_MASK) >> ABORT_PROT_BLOCK_SHIFT) - 1;
301 		g_assert (new_val >= 0);
302 		g_assert (new_val < (1 << ABORT_PROT_BLOCK_BITS));
303 
304 		new_state = old_state - (1 << ABORT_PROT_BLOCK_SHIFT);
305 	} while (mono_atomic_cas_ptr ((volatile gpointer *)&thread->thread_state, (gpointer)new_state, (gpointer)old_state) != (gpointer)old_state);
306 
307 	if (new_val == 0 && (new_state & INTERRUPT_ASYNC_REQUESTED_BIT)) {
308 		mono_atomic_inc_i32 (&thread_interruption_requested);
309 		THREADS_INTERRUPT_DEBUG ("[%d] end abort protected block old_state %ld new_state %ld, restore tir %d\n", thread->small_id, old_state, new_state, thread_interruption_requested);
310 	} else {
311 		THREADS_INTERRUPT_DEBUG ("[%d] end abort protected block old_state %ld new_state %ld, tir %d\n", thread->small_id, old_state, new_state, thread_interruption_requested);
312 	}
313 
314 	return mono_thread_state_has_interruption (new_state);
315 }
316 
317 static gboolean
mono_thread_get_interruption_requested(MonoInternalThread * thread)318 mono_thread_get_interruption_requested (MonoInternalThread *thread)
319 {
320 	gsize state = thread->thread_state;
321 
322 	return mono_thread_state_has_interruption (state);
323 }
324 
325 /*
326  * Returns TRUE is there was a state change
327  * We clear a single interruption request, sync has priority.
328  */
329 static gboolean
mono_thread_clear_interruption_requested(MonoInternalThread * thread)330 mono_thread_clear_interruption_requested (MonoInternalThread *thread)
331 {
332 	gsize old_state, new_state;
333 	do {
334 		old_state = thread->thread_state;
335 
336 		// no interruption to process
337 		if (!(old_state & INTERRUPT_SYNC_REQUESTED_BIT) &&
338 				(!(old_state & INTERRUPT_ASYNC_REQUESTED_BIT) || (old_state & ABORT_PROT_BLOCK_MASK)))
339 			return FALSE;
340 
341 		if (old_state & INTERRUPT_SYNC_REQUESTED_BIT)
342 			new_state = old_state & ~INTERRUPT_SYNC_REQUESTED_BIT;
343 		else
344 			new_state = old_state & ~INTERRUPT_ASYNC_REQUESTED_BIT;
345 	} while (mono_atomic_cas_ptr ((volatile gpointer *)&thread->thread_state, (gpointer)new_state, (gpointer)old_state) != (gpointer)old_state);
346 
347 	mono_atomic_dec_i32 (&thread_interruption_requested);
348 	THREADS_INTERRUPT_DEBUG ("[%d] clear interruption old_state %ld new_state %ld, tir %d\n", thread->small_id, old_state, new_state, thread_interruption_requested);
349 	if (thread_interruption_requested < 0)
350 		g_warning ("bad thread_interruption_requested state");
351 	return TRUE;
352 }
353 
354 /* Returns TRUE is there was a state change and the interruption can be processed */
355 static gboolean
mono_thread_set_interruption_requested(MonoInternalThread * thread)356 mono_thread_set_interruption_requested (MonoInternalThread *thread)
357 {
358 	//always force when the current thread is doing it to itself.
359 	gboolean sync = thread == mono_thread_internal_current ();
360 	gsize old_state, new_state;
361 	do {
362 		old_state = thread->thread_state;
363 
364 		//Already set
365 		if ((sync && (old_state & INTERRUPT_SYNC_REQUESTED_BIT)) ||
366 				(!sync && (old_state & INTERRUPT_ASYNC_REQUESTED_BIT)))
367 			return FALSE;
368 
369 		if (sync)
370 			new_state = old_state | INTERRUPT_SYNC_REQUESTED_BIT;
371 		else
372 			new_state = old_state | INTERRUPT_ASYNC_REQUESTED_BIT;
373 	} while (mono_atomic_cas_ptr ((volatile gpointer *)&thread->thread_state, (gpointer)new_state, (gpointer)old_state) != (gpointer)old_state);
374 
375 	if (sync || !(new_state & ABORT_PROT_BLOCK_MASK)) {
376 		mono_atomic_inc_i32 (&thread_interruption_requested);
377 		THREADS_INTERRUPT_DEBUG ("[%d] set interruption on [%d] old_state %ld new_state %ld, tir %d\n", mono_thread_internal_current ()->small_id, thread->small_id, old_state, new_state, thread_interruption_requested);
378 	} else {
379 		THREADS_INTERRUPT_DEBUG ("[%d] set interruption on [%d] old_state %ld new_state %ld, tir deferred %d\n", mono_thread_internal_current ()->small_id, thread->small_id, old_state, new_state, thread_interruption_requested);
380 	}
381 
382 	return sync || !(new_state & ABORT_PROT_BLOCK_MASK);
383 }
384 
385 static inline MonoNativeThreadId
thread_get_tid(MonoInternalThread * thread)386 thread_get_tid (MonoInternalThread *thread)
387 {
388 	/* We store the tid as a guint64 to keep the object layout constant between platforms */
389 	return MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid);
390 }
391 
ensure_synch_cs_set(MonoInternalThread * thread)392 static void ensure_synch_cs_set (MonoInternalThread *thread)
393 {
394 	MonoCoopMutex *synch_cs;
395 
396 	if (thread->synch_cs != NULL) {
397 		return;
398 	}
399 
400 	synch_cs = g_new0 (MonoCoopMutex, 1);
401 	mono_coop_mutex_init_recursive (synch_cs);
402 
403 	if (mono_atomic_cas_ptr ((gpointer *)&thread->synch_cs,
404 					       synch_cs, NULL) != NULL) {
405 		/* Another thread must have installed this CS */
406 		mono_coop_mutex_destroy (synch_cs);
407 		g_free (synch_cs);
408 	}
409 }
410 
411 static inline void
lock_thread(MonoInternalThread * thread)412 lock_thread (MonoInternalThread *thread)
413 {
414 	if (!thread->synch_cs)
415 		ensure_synch_cs_set (thread);
416 
417 	g_assert (thread->synch_cs);
418 
419 	mono_coop_mutex_lock (thread->synch_cs);
420 }
421 
422 static inline void
unlock_thread(MonoInternalThread * thread)423 unlock_thread (MonoInternalThread *thread)
424 {
425 	mono_coop_mutex_unlock (thread->synch_cs);
426 }
427 
428 static inline gboolean
is_appdomainunloaded_exception(MonoClass * klass)429 is_appdomainunloaded_exception (MonoClass *klass)
430 {
431 	return klass == mono_class_get_appdomain_unloaded_exception_class ();
432 }
433 
434 static inline gboolean
is_threadabort_exception(MonoClass * klass)435 is_threadabort_exception (MonoClass *klass)
436 {
437 	return klass == mono_defaults.threadabortexception_class;
438 }
439 
440 /*
441  * A special static data offset (guint32) consists of 3 parts:
442  *
443  * [0]   6-bit index into the array of chunks.
444  * [6]   25-bit offset into the array.
445  * [31]  Bit indicating thread or context static.
446  */
447 
448 typedef union {
449 	struct {
450 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
451 		guint32 type : 1;
452 		guint32 offset : 25;
453 		guint32 index : 6;
454 #else
455 		guint32 index : 6;
456 		guint32 offset : 25;
457 		guint32 type : 1;
458 #endif
459 	} fields;
460 	guint32 raw;
461 } SpecialStaticOffset;
462 
463 #define SPECIAL_STATIC_OFFSET_TYPE_THREAD 0
464 #define SPECIAL_STATIC_OFFSET_TYPE_CONTEXT 1
465 
466 #define MAKE_SPECIAL_STATIC_OFFSET(idx, off, ty) \
467 	((SpecialStaticOffset) { .fields = { .index = (idx), .offset = (off), .type = (ty) } }.raw)
468 #define ACCESS_SPECIAL_STATIC_OFFSET(x,f) \
469 	(((SpecialStaticOffset *) &(x))->fields.f)
470 
471 static gpointer
get_thread_static_data(MonoInternalThread * thread,guint32 offset)472 get_thread_static_data (MonoInternalThread *thread, guint32 offset)
473 {
474 	g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_THREAD);
475 
476 	int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
477 	int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
478 
479 	return ((char *) thread->static_data [idx]) + off;
480 }
481 
482 static gpointer
get_context_static_data(MonoAppContext * ctx,guint32 offset)483 get_context_static_data (MonoAppContext *ctx, guint32 offset)
484 {
485 	g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_CONTEXT);
486 
487 	int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
488 	int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
489 
490 	return ((char *) ctx->static_data [idx]) + off;
491 }
492 
493 static MonoThread**
get_current_thread_ptr_for_domain(MonoDomain * domain,MonoInternalThread * thread)494 get_current_thread_ptr_for_domain (MonoDomain *domain, MonoInternalThread *thread)
495 {
496 	static MonoClassField *current_thread_field = NULL;
497 
498 	guint32 offset;
499 
500 	if (!current_thread_field) {
501 		current_thread_field = mono_class_get_field_from_name (mono_defaults.thread_class, "current_thread");
502 		g_assert (current_thread_field);
503 	}
504 
505 	mono_class_vtable (domain, mono_defaults.thread_class);
506 	mono_domain_lock (domain);
507 	offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, current_thread_field));
508 	mono_domain_unlock (domain);
509 	g_assert (offset);
510 
511 	return (MonoThread **)get_thread_static_data (thread, offset);
512 }
513 
514 static void
set_current_thread_for_domain(MonoDomain * domain,MonoInternalThread * thread,MonoThread * current)515 set_current_thread_for_domain (MonoDomain *domain, MonoInternalThread *thread, MonoThread *current)
516 {
517 	MonoThread **current_thread_ptr = get_current_thread_ptr_for_domain (domain, thread);
518 
519 	g_assert (current->obj.vtable->domain == domain);
520 
521 	g_assert (!*current_thread_ptr);
522 	*current_thread_ptr = current;
523 }
524 
525 static MonoThread*
create_thread_object(MonoDomain * domain,MonoInternalThread * internal)526 create_thread_object (MonoDomain *domain, MonoInternalThread *internal)
527 {
528 	MonoThread *thread;
529 	MonoVTable *vtable;
530 	MonoError error;
531 
532 	vtable = mono_class_vtable (domain, mono_defaults.thread_class);
533 	g_assert (vtable);
534 
535 	thread = (MonoThread*)mono_object_new_mature (vtable, &error);
536 	/* only possible failure mode is OOM, from which we don't expect to recover. */
537 	mono_error_assert_ok (&error);
538 
539 	MONO_OBJECT_SETREF (thread, internal_thread, internal);
540 
541 	return thread;
542 }
543 
544 static MonoInternalThread*
create_internal_thread_object(void)545 create_internal_thread_object (void)
546 {
547 	MonoError error;
548 	MonoInternalThread *thread;
549 	MonoVTable *vt;
550 
551 	vt = mono_class_vtable (mono_get_root_domain (), mono_defaults.internal_thread_class);
552 	thread = (MonoInternalThread*) mono_object_new_mature (vt, &error);
553 	/* only possible failure mode is OOM, from which we don't exect to recover */
554 	mono_error_assert_ok (&error);
555 
556 	thread->synch_cs = g_new0 (MonoCoopMutex, 1);
557 	mono_coop_mutex_init_recursive (thread->synch_cs);
558 
559 	thread->apartment_state = ThreadApartmentState_Unknown;
560 	thread->managed_id = get_next_managed_thread_id ();
561 	if (mono_gc_is_moving ()) {
562 		thread->thread_pinning_ref = thread;
563 		MONO_GC_REGISTER_ROOT_PINNING (thread->thread_pinning_ref, MONO_ROOT_SOURCE_THREADING, "thread pinning reference");
564 	}
565 
566 	thread->priority = MONO_THREAD_PRIORITY_NORMAL;
567 
568 	thread->suspended = g_new0 (MonoOSEvent, 1);
569 	mono_os_event_init (thread->suspended, TRUE);
570 
571 	return thread;
572 }
573 
574 static void
mono_thread_internal_set_priority(MonoInternalThread * internal,MonoThreadPriority priority)575 mono_thread_internal_set_priority (MonoInternalThread *internal, MonoThreadPriority priority)
576 {
577 	g_assert (internal);
578 
579 	g_assert (priority >= MONO_THREAD_PRIORITY_LOWEST);
580 	g_assert (priority <= MONO_THREAD_PRIORITY_HIGHEST);
581 	g_assert (MONO_THREAD_PRIORITY_LOWEST < MONO_THREAD_PRIORITY_HIGHEST);
582 
583 #ifdef HOST_WIN32
584 	BOOL res;
585 
586 	g_assert (internal->native_handle);
587 
588 	res = SetThreadPriority (internal->native_handle, priority - 2);
589 	if (!res)
590 		g_error ("%s: SetThreadPriority failed, error %d", __func__, GetLastError ());
591 #else /* HOST_WIN32 */
592 	pthread_t tid;
593 	int policy;
594 	struct sched_param param;
595 	gint res;
596 
597 	tid = thread_get_tid (internal);
598 
599 	res = pthread_getschedparam (tid, &policy, &param);
600 	if (res != 0)
601 		g_error ("%s: pthread_getschedparam failed, error: \"%s\" (%d)", __func__, g_strerror (res), res);
602 
603 #ifdef _POSIX_PRIORITY_SCHEDULING
604 	int max, min;
605 
606 	/* Necessary to get valid priority range */
607 
608 	min = sched_get_priority_min (policy);
609 	max = sched_get_priority_max (policy);
610 
611 	if (max > 0 && min >= 0 && max > min) {
612 		double srange, drange, sposition, dposition;
613 		srange = MONO_THREAD_PRIORITY_HIGHEST - MONO_THREAD_PRIORITY_LOWEST;
614 		drange = max - min;
615 		sposition = priority - MONO_THREAD_PRIORITY_LOWEST;
616 		dposition = (sposition / srange) * drange;
617 		param.sched_priority = (int)(dposition + min);
618 	} else
619 #endif
620 	{
621 		switch (policy) {
622 		case SCHED_FIFO:
623 		case SCHED_RR:
624 			param.sched_priority = 50;
625 			break;
626 #ifdef SCHED_BATCH
627 		case SCHED_BATCH:
628 #endif
629 		case SCHED_OTHER:
630 			param.sched_priority = 0;
631 			break;
632 		default:
633 			g_warning ("%s: unknown policy %d", __func__, policy);
634 			return;
635 		}
636 	}
637 
638 	res = pthread_setschedparam (tid, policy, &param);
639 	if (res != 0) {
640 		if (res == EPERM) {
641 			g_warning ("%s: pthread_setschedparam failed, error: \"%s\" (%d)", __func__, g_strerror (res), res);
642 			return;
643 		}
644 		g_error ("%s: pthread_setschedparam failed, error: \"%s\" (%d)", __func__, g_strerror (res), res);
645 	}
646 #endif /* HOST_WIN32 */
647 }
648 
649 static void
650 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal);
651 
652 static gboolean
mono_thread_attach_internal(MonoThread * thread,gboolean force_attach,gboolean force_domain)653 mono_thread_attach_internal (MonoThread *thread, gboolean force_attach, gboolean force_domain)
654 {
655 	MonoThreadInfo *info;
656 	MonoInternalThread *internal;
657 	MonoDomain *domain, *root_domain;
658 
659 	g_assert (thread);
660 
661 	info = mono_thread_info_current ();
662 	g_assert (info);
663 
664 	internal = thread->internal_thread;
665 	g_assert (internal);
666 
667 	/* It is needed to store the MonoInternalThread on the MonoThreadInfo, because of the following case:
668 	 *  - the MonoInternalThread TLS key is destroyed: set it to NULL
669 	 *  - the MonoThreadInfo TLS key is destroyed: calls mono_thread_info_detach
670 	 *    - it calls MonoThreadInfoCallbacks.thread_detach
671 	 *      - mono_thread_internal_current returns NULL -> fails to detach the MonoInternalThread. */
672 	mono_thread_info_set_internal_thread_gchandle (info, mono_gchandle_new ((MonoObject*) internal, FALSE));
673 
674 	internal->handle = mono_threads_open_thread_handle (info->handle);
675 #ifdef HOST_WIN32
676 	internal->native_handle = OpenThread (THREAD_ALL_ACCESS, FALSE, GetCurrentThreadId ());
677 #endif
678 	internal->tid = MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ());
679 	internal->thread_info = info;
680 	internal->small_id = info->small_id;
681 
682 	THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, mono_native_thread_id_get (), internal));
683 
684 	SET_CURRENT_OBJECT (internal);
685 
686 	domain = mono_object_domain (thread);
687 
688 	mono_thread_push_appdomain_ref (domain);
689 	if (!mono_domain_set (domain, force_domain)) {
690 		mono_thread_pop_appdomain_ref ();
691 		return FALSE;
692 	}
693 
694 	mono_threads_lock ();
695 
696 	if (threads_starting_up)
697 		mono_g_hash_table_remove (threads_starting_up, thread);
698 
699 	if (shutting_down && !force_attach) {
700 		mono_threads_unlock ();
701 		mono_thread_pop_appdomain_ref ();
702 		return FALSE;
703 	}
704 
705 	if (!threads) {
706 		threads = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "threads table");
707 	}
708 
709 	/* We don't need to duplicate thread->handle, because it is
710 	 * only closed when the thread object is finalized by the GC. */
711 	mono_g_hash_table_insert (threads, (gpointer)(gsize)(internal->tid), internal);
712 
713 	/* We have to do this here because mono_thread_start_cb
714 	 * requires that root_domain_thread is set up. */
715 	if (thread_static_info.offset || thread_static_info.idx > 0) {
716 		/* get the current allocated size */
717 		guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (thread_static_info.idx, thread_static_info.offset, 0);
718 		mono_alloc_static_data (&internal->static_data, offset, TRUE);
719 	}
720 
721 	mono_threads_unlock ();
722 
723 	root_domain = mono_get_root_domain ();
724 
725 	g_assert (!internal->root_domain_thread);
726 	if (domain != root_domain)
727 		MONO_OBJECT_SETREF (internal, root_domain_thread, create_thread_object (root_domain, internal));
728 	else
729 		MONO_OBJECT_SETREF (internal, root_domain_thread, thread);
730 
731 	if (domain != root_domain)
732 		set_current_thread_for_domain (root_domain, internal, internal->root_domain_thread);
733 
734 	set_current_thread_for_domain (domain, internal, thread);
735 
736 	THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, internal->tid, internal->handle));
737 
738 	return TRUE;
739 }
740 
741 static void
mono_thread_detach_internal(MonoInternalThread * thread)742 mono_thread_detach_internal (MonoInternalThread *thread)
743 {
744 	MonoThreadInfo *info;
745 	gboolean removed;
746 	guint32 gchandle;
747 
748 	g_assert (thread != NULL);
749 	SET_CURRENT_OBJECT (thread);
750 
751 	info = (MonoThreadInfo*) thread->thread_info;
752 	g_assert (info);
753 
754 	THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
755 
756 	MONO_PROFILER_RAISE (thread_stopping, (thread->tid));
757 
758 #ifndef HOST_WIN32
759 	mono_w32mutex_abandon ();
760 #endif
761 
762 	if (thread->abort_state_handle) {
763 		mono_gchandle_free (thread->abort_state_handle);
764 		thread->abort_state_handle = 0;
765 	}
766 
767 	thread->abort_exc = NULL;
768 	thread->current_appcontext = NULL;
769 
770 	/*
771 	* Prevent race condition between execution of this method and runtime shutdown.
772 	* Adding runtime thread to the joinable threads list will make sure runtime shutdown
773 	* won't complete until added runtime thread have exited. Owner of threads attached to the
774 	* runtime but not identified as runtime threads needs to make sure thread detach calls won't
775 	* race with runtime shutdown.
776 	*/
777 #ifdef HOST_WIN32
778 	mono_threads_add_joinable_runtime_thread (info);
779 #endif
780 
781 	/*
782 	 * thread->synch_cs can be NULL if this was called after
783 	 * ves_icall_System_Threading_InternalThread_Thread_free_internal.
784 	 * This can happen only during shutdown.
785 	 * The shutting_down flag is not always set, so we can't assert on it.
786 	 */
787 	if (thread->synch_cs)
788 		LOCK_THREAD (thread);
789 
790 	thread->state |= ThreadState_Stopped;
791 	thread->state &= ~ThreadState_Background;
792 
793 	if (thread->synch_cs)
794 		UNLOCK_THREAD (thread);
795 
796 	/*
797 	An interruption request has leaked to cleanup. Adjust the global counter.
798 
799 	This can happen is the abort source thread finds the abortee (this) thread
800 	in unmanaged code. If this thread never trips back to managed code or check
801 	the local flag it will be left set and positively unbalance the global counter.
802 
803 	Leaving the counter unbalanced will cause a performance degradation since all threads
804 	will now keep checking their local flags all the time.
805 	*/
806 	mono_thread_clear_interruption_requested (thread);
807 
808 	mono_threads_lock ();
809 
810 	if (!threads) {
811 		removed = FALSE;
812 	} else if (mono_g_hash_table_lookup (threads, (gpointer)thread->tid) != thread) {
813 		/* We have to check whether the thread object for the
814 		 * tid is still the same in the table because the
815 		 * thread might have been destroyed and the tid reused
816 		 * in the meantime, in which case the tid would be in
817 		 * the table, but with another thread object.
818 		 */
819 		removed = FALSE;
820 	} else {
821 		mono_g_hash_table_remove (threads, (gpointer)thread->tid);
822 		removed = TRUE;
823 	}
824 
825 	mono_threads_unlock ();
826 
827 	/* Don't close the handle here, wait for the object finalizer
828 	 * to do it. Otherwise, the following race condition applies:
829 	 *
830 	 * 1) Thread exits (and mono_thread_detach_internal() closes the handle)
831 	 *
832 	 * 2) Some other handle is reassigned the same slot
833 	 *
834 	 * 3) Another thread tries to join the first thread, and
835 	 * blocks waiting for the reassigned handle to be signalled
836 	 * (which might never happen).  This is possible, because the
837 	 * thread calling Join() still has a reference to the first
838 	 * thread's object.
839 	 */
840 
841 	/* if the thread is not in the hash it has been removed already */
842 	if (!removed) {
843 		mono_domain_unset ();
844 		mono_memory_barrier ();
845 
846 		if (mono_thread_cleanup_fn)
847 			mono_thread_cleanup_fn (thread_get_tid (thread));
848 
849 		goto done;
850 	}
851 
852 	mono_release_type_locks (thread);
853 
854 	MONO_PROFILER_RAISE (thread_stopped, (thread->tid));
855 
856 	/*
857 	 * This will signal async signal handlers that the thread has exited.
858 	 * The profiler callback needs this to be set, so it cannot be done earlier.
859 	 */
860 	mono_domain_unset ();
861 	mono_memory_barrier ();
862 
863 	if (thread == mono_thread_internal_current ())
864 		mono_thread_pop_appdomain_ref ();
865 
866 	mono_free_static_data (thread->static_data);
867 	thread->static_data = NULL;
868 	ref_stack_destroy (thread->appdomain_refs);
869 	thread->appdomain_refs = NULL;
870 
871 	g_assert (thread->suspended);
872 	mono_os_event_destroy (thread->suspended);
873 	g_free (thread->suspended);
874 	thread->suspended = NULL;
875 
876 	if (mono_thread_cleanup_fn)
877 		mono_thread_cleanup_fn (thread_get_tid (thread));
878 
879 	mono_memory_barrier ();
880 
881 	if (mono_gc_is_moving ()) {
882 		MONO_GC_UNREGISTER_ROOT (thread->thread_pinning_ref);
883 		thread->thread_pinning_ref = NULL;
884 	}
885 
886 done:
887 	SET_CURRENT_OBJECT (NULL);
888 	mono_domain_unset ();
889 
890 	if (!mono_thread_info_try_get_internal_thread_gchandle (info, &gchandle))
891 		g_error ("%s: failed to get gchandle, info = %p", __func__, info);
892 
893 	mono_gchandle_free (gchandle);
894 
895 	mono_thread_info_unset_internal_thread_gchandle (info);
896 
897 	MONO_PROFILER_RAISE (thread_exited, (thread->tid));
898 
899 	/* Don't need to close the handle to this thread, even though we took a
900 	 * reference in mono_thread_attach (), because the GC will do it
901 	 * when the Thread object is finalised.
902 	 */
903 }
904 
905 typedef struct {
906 	gint32 ref;
907 	MonoThread *thread;
908 	MonoObject *start_delegate;
909 	MonoObject *start_delegate_arg;
910 	MonoThreadStart start_func;
911 	gpointer start_func_arg;
912 	gboolean force_attach;
913 	gboolean failed;
914 	MonoCoopSem registered;
915 } StartInfo;
916 
start_wrapper_internal(StartInfo * start_info,gsize * stack_ptr)917 static guint32 WINAPI start_wrapper_internal(StartInfo *start_info, gsize *stack_ptr)
918 {
919 	MonoError error;
920 	MonoThreadStart start_func;
921 	void *start_func_arg;
922 	gsize tid;
923 	/*
924 	 * We don't create a local to hold start_info->thread, so hopefully it won't get pinned during a
925 	 * GC stack walk.
926 	 */
927 	MonoThread *thread;
928 	MonoInternalThread *internal;
929 	MonoObject *start_delegate;
930 	MonoObject *start_delegate_arg;
931 	MonoDomain *domain;
932 
933 	thread = start_info->thread;
934 	internal = thread->internal_thread;
935 	domain = mono_object_domain (start_info->thread);
936 
937 	THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper", __func__, mono_native_thread_id_get ()));
938 
939 	if (!mono_thread_attach_internal (thread, start_info->force_attach, FALSE)) {
940 		start_info->failed = TRUE;
941 
942 		mono_coop_sem_post (&start_info->registered);
943 
944 		if (mono_atomic_dec_i32 (&start_info->ref) == 0) {
945 			mono_coop_sem_destroy (&start_info->registered);
946 			g_free (start_info);
947 		}
948 
949 		return 0;
950 	}
951 
952 	mono_thread_internal_set_priority (internal, internal->priority);
953 
954 	tid = internal->tid;
955 
956 	start_delegate = start_info->start_delegate;
957 	start_delegate_arg = start_info->start_delegate_arg;
958 	start_func = start_info->start_func;
959 	start_func_arg = start_info->start_func_arg;
960 
961 	/* This MUST be called before any managed code can be
962 	 * executed, as it calls the callback function that (for the
963 	 * jit) sets the lmf marker.
964 	 */
965 
966 	if (mono_thread_start_cb)
967 		mono_thread_start_cb (tid, stack_ptr, start_func);
968 
969 	/* On 2.0 profile (and higher), set explicitly since state might have been
970 	   Unknown */
971 	if (internal->apartment_state == ThreadApartmentState_Unknown)
972 		internal->apartment_state = ThreadApartmentState_MTA;
973 
974 	mono_thread_init_apartment_state ();
975 
976 	/* Let the thread that called Start() know we're ready */
977 	mono_coop_sem_post (&start_info->registered);
978 
979 	if (mono_atomic_dec_i32 (&start_info->ref) == 0) {
980 		mono_coop_sem_destroy (&start_info->registered);
981 		g_free (start_info);
982 	}
983 
984 	/* start_info is not valid anymore */
985 	start_info = NULL;
986 
987 	/*
988 	 * Call this after calling start_notify, since the profiler callback might want
989 	 * to lock the thread, and the lock is held by thread_start () which waits for
990 	 * start_notify.
991 	 */
992 	MONO_PROFILER_RAISE (thread_started, (tid));
993 
994 	/* if the name was set before starting, we didn't invoke the profiler callback */
995 	if (internal->name) {
996 		char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
997 		MONO_PROFILER_RAISE (thread_name, (internal->tid, tname));
998 		mono_native_thread_set_name (MONO_UINT_TO_NATIVE_THREAD_ID (internal->tid), tname);
999 		g_free (tname);
1000 	}
1001 
1002 	/* start_func is set only for unmanaged start functions */
1003 	if (start_func) {
1004 		start_func (start_func_arg);
1005 	} else {
1006 		void *args [1];
1007 
1008 		g_assert (start_delegate != NULL);
1009 
1010 		/* we may want to handle the exception here. See comment below on unhandled exceptions */
1011 		args [0] = (gpointer) start_delegate_arg;
1012 		mono_runtime_delegate_invoke_checked (start_delegate, args, &error);
1013 
1014 		if (!mono_error_ok (&error)) {
1015 			MonoException *ex = mono_error_convert_to_exception (&error);
1016 
1017 			g_assert (ex != NULL);
1018 			MonoClass *klass = mono_object_get_class (&ex->object);
1019 			if ((mono_runtime_unhandled_exception_policy_get () != MONO_UNHANDLED_POLICY_LEGACY) &&
1020 			    !is_threadabort_exception (klass)) {
1021 				mono_unhandled_exception (&ex->object);
1022 				mono_invoke_unhandled_exception_hook (&ex->object);
1023 				g_assert_not_reached ();
1024 			}
1025 		} else {
1026 			mono_error_cleanup (&error);
1027 		}
1028 	}
1029 
1030 	/* If the thread calls ExitThread at all, this remaining code
1031 	 * will not be executed, but the main thread will eventually
1032 	 * call mono_thread_detach_internal() on this thread's behalf.
1033 	 */
1034 
1035 	THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper terminating", __func__, mono_native_thread_id_get ()));
1036 
1037 	/* Do any cleanup needed for apartment state. This
1038 	 * cannot be done in mono_thread_detach_internal since
1039 	 * mono_thread_detach_internal could be  called for a
1040 	 * thread other than the current thread.
1041 	 * mono_thread_cleanup_apartment_state cleans up apartment
1042 	 * for the current thead */
1043 	mono_thread_cleanup_apartment_state ();
1044 
1045 	mono_thread_detach_internal (internal);
1046 
1047 	return 0;
1048 }
1049 
1050 static gsize WINAPI
start_wrapper(gpointer data)1051 start_wrapper (gpointer data)
1052 {
1053 	StartInfo *start_info;
1054 	MonoThreadInfo *info;
1055 	gsize res;
1056 
1057 	start_info = (StartInfo*) data;
1058 	g_assert (start_info);
1059 
1060 	info = mono_thread_info_attach ();
1061 	info->runtime_thread = TRUE;
1062 
1063 	/* Run the actual main function of the thread */
1064 	res = start_wrapper_internal (start_info, info->stack_end);
1065 
1066 	mono_thread_info_exit (res);
1067 
1068 	g_assert_not_reached ();
1069 }
1070 
1071 /*
1072  * create_thread:
1073  *
1074  *   Common thread creation code.
1075  * LOCKING: Acquires the threads lock.
1076  */
1077 static gboolean
create_thread(MonoThread * thread,MonoInternalThread * internal,MonoObject * start_delegate,MonoThreadStart start_func,gpointer start_func_arg,MonoThreadCreateFlags flags,MonoError * error)1078 create_thread (MonoThread *thread, MonoInternalThread *internal, MonoObject *start_delegate, MonoThreadStart start_func, gpointer start_func_arg,
1079 	MonoThreadCreateFlags flags, MonoError *error)
1080 {
1081 	StartInfo *start_info = NULL;
1082 	MonoNativeThreadId tid;
1083 	gboolean ret;
1084 	gsize stack_set_size;
1085 
1086 	if (start_delegate)
1087 		g_assert (!start_func && !start_func_arg);
1088 	if (start_func)
1089 		g_assert (!start_delegate);
1090 
1091 	if (flags & MONO_THREAD_CREATE_FLAGS_THREADPOOL) {
1092 		g_assert (!(flags & MONO_THREAD_CREATE_FLAGS_DEBUGGER));
1093 		g_assert (!(flags & MONO_THREAD_CREATE_FLAGS_FORCE_CREATE));
1094 	}
1095 	if (flags & MONO_THREAD_CREATE_FLAGS_DEBUGGER) {
1096 		g_assert (!(flags & MONO_THREAD_CREATE_FLAGS_THREADPOOL));
1097 		g_assert (!(flags & MONO_THREAD_CREATE_FLAGS_FORCE_CREATE));
1098 	}
1099 
1100 	/*
1101 	 * Join joinable threads to prevent running out of threads since the finalizer
1102 	 * thread might be blocked/backlogged.
1103 	 */
1104 	mono_threads_join_threads ();
1105 
1106 	error_init (error);
1107 
1108 	mono_threads_lock ();
1109 	if (shutting_down && !(flags & MONO_THREAD_CREATE_FLAGS_FORCE_CREATE)) {
1110 		mono_threads_unlock ();
1111 		return FALSE;
1112 	}
1113 	if (threads_starting_up == NULL) {
1114 		threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "starting threads table");
1115 	}
1116 	mono_g_hash_table_insert (threads_starting_up, thread, thread);
1117 	mono_threads_unlock ();
1118 
1119 	internal->threadpool_thread = flags & MONO_THREAD_CREATE_FLAGS_THREADPOOL;
1120 	if (internal->threadpool_thread)
1121 		mono_thread_set_state (internal, ThreadState_Background);
1122 
1123 	internal->debugger_thread = flags & MONO_THREAD_CREATE_FLAGS_DEBUGGER;
1124 
1125 	start_info = g_new0 (StartInfo, 1);
1126 	start_info->ref = 2;
1127 	start_info->thread = thread;
1128 	start_info->start_delegate = start_delegate;
1129 	start_info->start_delegate_arg = thread->start_obj;
1130 	start_info->start_func = start_func;
1131 	start_info->start_func_arg = start_func_arg;
1132 	start_info->force_attach = flags & MONO_THREAD_CREATE_FLAGS_FORCE_CREATE;
1133 	start_info->failed = FALSE;
1134 	mono_coop_sem_init (&start_info->registered, 0);
1135 
1136 	if (flags != MONO_THREAD_CREATE_FLAGS_SMALL_STACK)
1137 		stack_set_size = default_stacksize_for_thread (internal);
1138 	else
1139 		stack_set_size = 0;
1140 
1141 	if (!mono_thread_platform_create_thread ((MonoThreadStart)start_wrapper, start_info, &stack_set_size, &tid)) {
1142 		/* The thread couldn't be created, so set an exception */
1143 		mono_threads_lock ();
1144 		mono_g_hash_table_remove (threads_starting_up, thread);
1145 		mono_threads_unlock ();
1146 		mono_error_set_execution_engine (error, "Couldn't create thread. Error 0x%x", mono_w32error_get_last());
1147 		/* ref is not going to be decremented in start_wrapper_internal */
1148 		mono_atomic_dec_i32 (&start_info->ref);
1149 		ret = FALSE;
1150 		goto done;
1151 	}
1152 
1153 	internal->stack_size = (int) stack_set_size;
1154 
1155 	THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, mono_native_thread_id_get (), internal, (gsize)internal->tid));
1156 
1157 	/*
1158 	 * Wait for the thread to set up its TLS data etc, so
1159 	 * theres no potential race condition if someone tries
1160 	 * to look up the data believing the thread has
1161 	 * started
1162 	 */
1163 
1164 	mono_coop_sem_wait (&start_info->registered, MONO_SEM_FLAGS_NONE);
1165 
1166 	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));
1167 
1168 	ret = !start_info->failed;
1169 
1170 done:
1171 	if (mono_atomic_dec_i32 (&start_info->ref) == 0) {
1172 		mono_coop_sem_destroy (&start_info->registered);
1173 		g_free (start_info);
1174 	}
1175 
1176 	return ret;
1177 }
1178 
1179 /**
1180  * mono_thread_new_init:
1181  */
1182 void
mono_thread_new_init(intptr_t tid,gpointer stack_start,gpointer func)1183 mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func)
1184 {
1185 	if (mono_thread_start_cb) {
1186 		mono_thread_start_cb (tid, stack_start, func);
1187 	}
1188 }
1189 
1190 /**
1191  * mono_threads_set_default_stacksize:
1192  */
1193 void
mono_threads_set_default_stacksize(guint32 stacksize)1194 mono_threads_set_default_stacksize (guint32 stacksize)
1195 {
1196 	default_stacksize = stacksize;
1197 }
1198 
1199 /**
1200  * mono_threads_get_default_stacksize:
1201  */
1202 guint32
mono_threads_get_default_stacksize(void)1203 mono_threads_get_default_stacksize (void)
1204 {
1205 	return default_stacksize;
1206 }
1207 
1208 /*
1209  * mono_thread_create_internal:
1210  *
1211  *   ARG should not be a GC reference.
1212  */
1213 MonoInternalThread*
mono_thread_create_internal(MonoDomain * domain,gpointer func,gpointer arg,MonoThreadCreateFlags flags,MonoError * error)1214 mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, MonoThreadCreateFlags flags, MonoError *error)
1215 {
1216 	MonoThread *thread;
1217 	MonoInternalThread *internal;
1218 	gboolean res;
1219 
1220 	error_init (error);
1221 
1222 	internal = create_internal_thread_object ();
1223 
1224 	thread = create_thread_object (domain, internal);
1225 
1226 	LOCK_THREAD (internal);
1227 
1228 	res = create_thread (thread, internal, NULL, (MonoThreadStart) func, arg, flags, error);
1229 
1230 	UNLOCK_THREAD (internal);
1231 
1232 	return_val_if_nok (error, NULL);
1233 	return internal;
1234 }
1235 
1236 /**
1237  * mono_thread_create:
1238  */
1239 void
mono_thread_create(MonoDomain * domain,gpointer func,gpointer arg)1240 mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
1241 {
1242 	MonoError error;
1243 	if (!mono_thread_create_checked (domain, func, arg, &error))
1244 		mono_error_cleanup (&error);
1245 }
1246 
1247 gboolean
mono_thread_create_checked(MonoDomain * domain,gpointer func,gpointer arg,MonoError * error)1248 mono_thread_create_checked (MonoDomain *domain, gpointer func, gpointer arg, MonoError *error)
1249 {
1250 	return (NULL != mono_thread_create_internal (domain, func, arg, MONO_THREAD_CREATE_FLAGS_NONE, error));
1251 }
1252 
1253 static MonoThread *
mono_thread_attach_full(MonoDomain * domain,gboolean force_attach)1254 mono_thread_attach_full (MonoDomain *domain, gboolean force_attach)
1255 {
1256 	MonoInternalThread *internal;
1257 	MonoThread *thread;
1258 	MonoThreadInfo *info;
1259 	MonoNativeThreadId tid;
1260 
1261 	if (mono_thread_internal_current_is_attached ()) {
1262 		if (domain != mono_domain_get ())
1263 			mono_domain_set (domain, TRUE);
1264 		/* Already attached */
1265 		return mono_thread_current ();
1266 	}
1267 
1268 	info = mono_thread_info_attach ();
1269 	g_assert (info);
1270 
1271 	tid=mono_native_thread_id_get ();
1272 
1273 	internal = create_internal_thread_object ();
1274 
1275 	thread = create_thread_object (domain, internal);
1276 
1277 	if (!mono_thread_attach_internal (thread, force_attach, TRUE)) {
1278 		/* Mono is shutting down, so just wait for the end */
1279 		for (;;)
1280 			mono_thread_info_sleep (10000, NULL);
1281 	}
1282 
1283 	THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, internal->handle));
1284 
1285 	if (mono_thread_attach_cb)
1286 		mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), info->stack_end);
1287 
1288 	MONO_PROFILER_RAISE (thread_started, (MONO_NATIVE_THREAD_ID_TO_UINT (tid)));
1289 
1290 	return thread;
1291 }
1292 
1293 /**
1294  * mono_thread_attach:
1295  */
1296 MonoThread *
mono_thread_attach(MonoDomain * domain)1297 mono_thread_attach (MonoDomain *domain)
1298 {
1299 	return mono_thread_attach_full (domain, FALSE);
1300 }
1301 
1302 /**
1303  * mono_thread_detach:
1304  */
1305 void
mono_thread_detach(MonoThread * thread)1306 mono_thread_detach (MonoThread *thread)
1307 {
1308 	if (thread)
1309 		mono_thread_detach_internal (thread->internal_thread);
1310 }
1311 
1312 /**
1313  * mono_thread_detach_if_exiting:
1314  *
1315  * Detach the current thread from the runtime if it is exiting, i.e. it is running pthread dtors.
1316  * This should be used at the end of embedding code which calls into managed code, and which
1317  * can be called from pthread dtors, like <code>dealloc:</code> implementations in Objective-C.
1318  */
1319 mono_bool
mono_thread_detach_if_exiting(void)1320 mono_thread_detach_if_exiting (void)
1321 {
1322 	if (mono_thread_info_is_exiting ()) {
1323 		MonoInternalThread *thread;
1324 
1325 		thread = mono_thread_internal_current ();
1326 		if (thread) {
1327 			mono_thread_detach_internal (thread);
1328 			mono_thread_info_detach ();
1329 			return TRUE;
1330 		}
1331 	}
1332 	return FALSE;
1333 }
1334 
1335 gboolean
mono_thread_internal_current_is_attached(void)1336 mono_thread_internal_current_is_attached (void)
1337 {
1338 	MonoInternalThread *internal;
1339 
1340 	internal = GET_CURRENT_OBJECT ();
1341 	if (!internal)
1342 		return FALSE;
1343 
1344 	return TRUE;
1345 }
1346 
1347 /**
1348  * mono_thread_exit:
1349  */
1350 void
mono_thread_exit(void)1351 mono_thread_exit (void)
1352 {
1353 	MonoInternalThread *thread = mono_thread_internal_current ();
1354 
1355 	THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1356 
1357 	mono_thread_detach_internal (thread);
1358 
1359 	/* we could add a callback here for embedders to use. */
1360 	if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread))
1361 		exit (mono_environment_exitcode_get ());
1362 
1363 	mono_thread_info_exit (0);
1364 }
1365 
1366 void
ves_icall_System_Threading_Thread_ConstructInternalThread(MonoThread * this_obj)1367 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this_obj)
1368 {
1369 	MonoInternalThread *internal;
1370 
1371 	internal = create_internal_thread_object ();
1372 
1373 	internal->state = ThreadState_Unstarted;
1374 
1375 	mono_atomic_cas_ptr ((volatile gpointer *)&this_obj->internal_thread, internal, NULL);
1376 }
1377 
1378 MonoThread *
ves_icall_System_Threading_Thread_GetCurrentThread(void)1379 ves_icall_System_Threading_Thread_GetCurrentThread (void)
1380 {
1381 	return mono_thread_current ();
1382 }
1383 
1384 HANDLE
ves_icall_System_Threading_Thread_Thread_internal(MonoThread * this_obj,MonoObject * start)1385 ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this_obj,
1386 												   MonoObject *start)
1387 {
1388 	MonoError error;
1389 	MonoInternalThread *internal;
1390 	gboolean res;
1391 
1392 	THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this_obj, start));
1393 
1394 	if (!this_obj->internal_thread)
1395 		ves_icall_System_Threading_Thread_ConstructInternalThread (this_obj);
1396 	internal = this_obj->internal_thread;
1397 
1398 	LOCK_THREAD (internal);
1399 
1400 	if ((internal->state & ThreadState_Unstarted) == 0) {
1401 		UNLOCK_THREAD (internal);
1402 		mono_set_pending_exception (mono_get_exception_thread_state ("Thread has already been started."));
1403 		return NULL;
1404 	}
1405 
1406 	if ((internal->state & ThreadState_Aborted) != 0) {
1407 		UNLOCK_THREAD (internal);
1408 		return this_obj;
1409 	}
1410 
1411 	res = create_thread (this_obj, internal, start, NULL, NULL, MONO_THREAD_CREATE_FLAGS_NONE, &error);
1412 	if (!res) {
1413 		mono_error_cleanup (&error);
1414 		UNLOCK_THREAD (internal);
1415 		return NULL;
1416 	}
1417 
1418 	internal->state &= ~ThreadState_Unstarted;
1419 
1420 	THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread));
1421 
1422 	UNLOCK_THREAD (internal);
1423 	return internal->handle;
1424 }
1425 
1426 /*
1427  * This is called from the finalizer of the internal thread object.
1428  */
1429 void
ves_icall_System_Threading_InternalThread_Thread_free_internal(MonoInternalThread * this_obj)1430 ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this_obj)
1431 {
1432 	THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, this_obj->handle));
1433 
1434 	/*
1435 	 * Since threads keep a reference to their thread object while running, by
1436 	 * the time this function is called, the thread has already exited/detached,
1437 	 * i.e. mono_thread_detach_internal () has ran. The exception is during
1438 	 * shutdown, when mono_thread_detach_internal () can be called after this.
1439 	 */
1440 	if (this_obj->handle) {
1441 		mono_threads_close_thread_handle (this_obj->handle);
1442 		this_obj->handle = NULL;
1443 	}
1444 
1445 #if HOST_WIN32
1446 	CloseHandle (this_obj->native_handle);
1447 #endif
1448 
1449 	if (this_obj->synch_cs) {
1450 		MonoCoopMutex *synch_cs = this_obj->synch_cs;
1451 		this_obj->synch_cs = NULL;
1452 		mono_coop_mutex_destroy (synch_cs);
1453 		g_free (synch_cs);
1454 	}
1455 
1456 	if (this_obj->name) {
1457 		void *name = this_obj->name;
1458 		this_obj->name = NULL;
1459 		g_free (name);
1460 	}
1461 }
1462 
1463 void
ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)1464 ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
1465 {
1466 	guint32 res;
1467 	MonoInternalThread *thread = mono_thread_internal_current ();
1468 
1469 	THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
1470 
1471 	if (mono_thread_current_check_pending_interrupt ())
1472 		return;
1473 
1474 	while (TRUE) {
1475 		gboolean alerted = FALSE;
1476 
1477 		mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1478 
1479 		res = mono_thread_info_sleep (ms, &alerted);
1480 
1481 		mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1482 
1483 		if (alerted) {
1484 			MonoException* exc = mono_thread_execute_interruption ();
1485 			if (exc) {
1486 				mono_set_pending_exception (exc);
1487 				return;
1488 			} else {
1489 				// FIXME: !MONO_INFINITE_WAIT
1490 				if (ms != MONO_INFINITE_WAIT)
1491 					break;
1492 			}
1493 		} else {
1494 			break;
1495 		}
1496 	}
1497 }
1498 
ves_icall_System_Threading_Thread_SpinWait_nop(void)1499 void ves_icall_System_Threading_Thread_SpinWait_nop (void)
1500 {
1501 }
1502 
1503 gint32
ves_icall_System_Threading_Thread_GetDomainID(void)1504 ves_icall_System_Threading_Thread_GetDomainID (void)
1505 {
1506 	return mono_domain_get()->domain_id;
1507 }
1508 
1509 gboolean
ves_icall_System_Threading_Thread_Yield(void)1510 ves_icall_System_Threading_Thread_Yield (void)
1511 {
1512 	return mono_thread_info_yield ();
1513 }
1514 
1515 /*
1516  * mono_thread_get_name:
1517  *
1518  *   Return the name of the thread. NAME_LEN is set to the length of the name.
1519  * Return NULL if the thread has no name. The returned memory is owned by the
1520  * caller.
1521  */
1522 gunichar2*
mono_thread_get_name(MonoInternalThread * this_obj,guint32 * name_len)1523 mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len)
1524 {
1525 	gunichar2 *res;
1526 
1527 	LOCK_THREAD (this_obj);
1528 
1529 	if (!this_obj->name) {
1530 		*name_len = 0;
1531 		res = NULL;
1532 	} else {
1533 		*name_len = this_obj->name_len;
1534 		res = g_new (gunichar2, this_obj->name_len);
1535 		memcpy (res, this_obj->name, sizeof (gunichar2) * this_obj->name_len);
1536 	}
1537 
1538 	UNLOCK_THREAD (this_obj);
1539 
1540 	return res;
1541 }
1542 
1543 /**
1544  * mono_thread_get_name_utf8:
1545  * \returns the name of the thread in UTF-8.
1546  * Return NULL if the thread has no name.
1547  * The returned memory is owned by the caller.
1548  */
1549 char *
mono_thread_get_name_utf8(MonoThread * thread)1550 mono_thread_get_name_utf8 (MonoThread *thread)
1551 {
1552 	if (thread == NULL)
1553 		return NULL;
1554 
1555 	MonoInternalThread *internal = thread->internal_thread;
1556 	if (internal == NULL)
1557 		return NULL;
1558 
1559 	LOCK_THREAD (internal);
1560 
1561 	char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
1562 
1563 	UNLOCK_THREAD (internal);
1564 
1565 	return tname;
1566 }
1567 
1568 /**
1569  * mono_thread_get_managed_id:
1570  * \returns the \c Thread.ManagedThreadId value of \p thread.
1571  * Returns \c -1 if \p thread is NULL.
1572  */
1573 int32_t
mono_thread_get_managed_id(MonoThread * thread)1574 mono_thread_get_managed_id (MonoThread *thread)
1575 {
1576 	if (thread == NULL)
1577 		return -1;
1578 
1579 	MonoInternalThread *internal = thread->internal_thread;
1580 	if (internal == NULL)
1581 		return -1;
1582 
1583 	int32_t id = internal->managed_id;
1584 
1585 	return id;
1586 }
1587 
1588 MonoString*
ves_icall_System_Threading_Thread_GetName_internal(MonoInternalThread * this_obj)1589 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj)
1590 {
1591 	MonoError error;
1592 	MonoString* str;
1593 
1594 	error_init (&error);
1595 
1596 	LOCK_THREAD (this_obj);
1597 
1598 	if (!this_obj->name)
1599 		str = NULL;
1600 	else
1601 		str = mono_string_new_utf16_checked (mono_domain_get (), this_obj->name, this_obj->name_len, &error);
1602 
1603 	UNLOCK_THREAD (this_obj);
1604 
1605 	if (mono_error_set_pending_exception (&error))
1606 		return NULL;
1607 
1608 	return str;
1609 }
1610 
1611 void
mono_thread_set_name_internal(MonoInternalThread * this_obj,MonoString * name,gboolean permanent,gboolean reset,MonoError * error)1612 mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean permanent, gboolean reset, MonoError *error)
1613 {
1614 	MonoNativeThreadId tid = 0;
1615 
1616 	LOCK_THREAD (this_obj);
1617 
1618 	error_init (error);
1619 
1620 	if (reset) {
1621 		this_obj->flags &= ~MONO_THREAD_FLAG_NAME_SET;
1622 	} else if (this_obj->flags & MONO_THREAD_FLAG_NAME_SET) {
1623 		UNLOCK_THREAD (this_obj);
1624 
1625 		mono_error_set_invalid_operation (error, "Thread.Name can only be set once.");
1626 		return;
1627 	}
1628 	if (this_obj->name) {
1629 		g_free (this_obj->name);
1630 		this_obj->name_len = 0;
1631 	}
1632 	if (name) {
1633 		this_obj->name = g_memdup (mono_string_chars (name), mono_string_length (name) * sizeof (gunichar2));
1634 		this_obj->name_len = mono_string_length (name);
1635 
1636 		if (permanent)
1637 			this_obj->flags |= MONO_THREAD_FLAG_NAME_SET;
1638 	}
1639 	else
1640 		this_obj->name = NULL;
1641 
1642 	if (!(this_obj->state & ThreadState_Stopped))
1643 		tid = thread_get_tid (this_obj);
1644 
1645 	UNLOCK_THREAD (this_obj);
1646 
1647 	if (this_obj->name && tid) {
1648 		char *tname = mono_string_to_utf8_checked (name, error);
1649 		return_if_nok (error);
1650 		MONO_PROFILER_RAISE (thread_name, ((uintptr_t)tid, tname));
1651 		mono_native_thread_set_name (tid, tname);
1652 		mono_free (tname);
1653 	}
1654 }
1655 
1656 void
ves_icall_System_Threading_Thread_SetName_internal(MonoInternalThread * this_obj,MonoString * name)1657 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name)
1658 {
1659 	MonoError error;
1660 	mono_thread_set_name_internal (this_obj, name, TRUE, FALSE, &error);
1661 	mono_error_set_pending_exception (&error);
1662 }
1663 
1664 /*
1665  * ves_icall_System_Threading_Thread_GetPriority_internal:
1666  * @param this_obj: The MonoInternalThread on which to operate.
1667  *
1668  * Gets the priority of the given thread.
1669  * @return: The priority of the given thread.
1670  */
1671 int
ves_icall_System_Threading_Thread_GetPriority(MonoThread * this_obj)1672 ves_icall_System_Threading_Thread_GetPriority (MonoThread *this_obj)
1673 {
1674 	gint32 priority;
1675 	MonoInternalThread *internal = this_obj->internal_thread;
1676 
1677 	LOCK_THREAD (internal);
1678 	priority = internal->priority;
1679 	UNLOCK_THREAD (internal);
1680 
1681 	return priority;
1682 }
1683 
1684 /*
1685  * ves_icall_System_Threading_Thread_SetPriority_internal:
1686  * @param this_obj: The MonoInternalThread on which to operate.
1687  * @param priority: The priority to set.
1688  *
1689  * Sets the priority of the given thread.
1690  */
1691 void
ves_icall_System_Threading_Thread_SetPriority(MonoThread * this_obj,int priority)1692 ves_icall_System_Threading_Thread_SetPriority (MonoThread *this_obj, int priority)
1693 {
1694 	MonoInternalThread *internal = this_obj->internal_thread;
1695 
1696 	LOCK_THREAD (internal);
1697 	internal->priority = priority;
1698 	if (internal->thread_info != NULL)
1699 		mono_thread_internal_set_priority (internal, priority);
1700 	UNLOCK_THREAD (internal);
1701 }
1702 
1703 /* If the array is already in the requested domain, we just return it,
1704    otherwise we return a copy in that domain. */
1705 static MonoArray*
byte_array_to_domain(MonoArray * arr,MonoDomain * domain,MonoError * error)1706 byte_array_to_domain (MonoArray *arr, MonoDomain *domain, MonoError *error)
1707 {
1708 	MonoArray *copy;
1709 
1710 	error_init (error);
1711 	if (!arr)
1712 		return NULL;
1713 
1714 	if (mono_object_domain (arr) == domain)
1715 		return arr;
1716 
1717 	copy = mono_array_new_checked (domain, mono_defaults.byte_class, arr->max_length, error);
1718 	memmove (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length);
1719 	return copy;
1720 }
1721 
1722 MonoArray*
ves_icall_System_Threading_Thread_ByteArrayToRootDomain(MonoArray * arr)1723 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray *arr)
1724 {
1725 	MonoError error;
1726 	MonoArray *result = byte_array_to_domain (arr, mono_get_root_domain (), &error);
1727 	mono_error_set_pending_exception (&error);
1728 	return result;
1729 }
1730 
1731 MonoArray*
ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain(MonoArray * arr)1732 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr)
1733 {
1734 	MonoError error;
1735 	MonoArray *result = byte_array_to_domain (arr, mono_domain_get (), &error);
1736 	mono_error_set_pending_exception (&error);
1737 	return result;
1738 }
1739 
1740 /**
1741  * mono_thread_current:
1742  */
1743 MonoThread *
mono_thread_current(void)1744 mono_thread_current (void)
1745 {
1746 	MonoDomain *domain = mono_domain_get ();
1747 	MonoInternalThread *internal = mono_thread_internal_current ();
1748 	MonoThread **current_thread_ptr;
1749 
1750 	g_assert (internal);
1751 	current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1752 
1753 	if (!*current_thread_ptr) {
1754 		g_assert (domain != mono_get_root_domain ());
1755 		*current_thread_ptr = create_thread_object (domain, internal);
1756 	}
1757 	return *current_thread_ptr;
1758 }
1759 
1760 /* Return the thread object belonging to INTERNAL in the current domain */
1761 static MonoThread *
mono_thread_current_for_thread(MonoInternalThread * internal)1762 mono_thread_current_for_thread (MonoInternalThread *internal)
1763 {
1764 	MonoDomain *domain = mono_domain_get ();
1765 	MonoThread **current_thread_ptr;
1766 
1767 	g_assert (internal);
1768 	current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1769 
1770 	if (!*current_thread_ptr) {
1771 		g_assert (domain != mono_get_root_domain ());
1772 		*current_thread_ptr = create_thread_object (domain, internal);
1773 	}
1774 	return *current_thread_ptr;
1775 }
1776 
1777 MonoInternalThread*
mono_thread_internal_current(void)1778 mono_thread_internal_current (void)
1779 {
1780 	MonoInternalThread *res = GET_CURRENT_OBJECT ();
1781 	THREAD_DEBUG (g_message ("%s: returning %p", __func__, res));
1782 	return res;
1783 }
1784 
1785 static MonoThreadInfoWaitRet
mono_join_uninterrupted(MonoThreadHandle * thread_to_join,gint32 ms,MonoError * error)1786 mono_join_uninterrupted (MonoThreadHandle* thread_to_join, gint32 ms, MonoError *error)
1787 {
1788 	MonoException *exc;
1789 	MonoThreadInfoWaitRet ret;
1790 	gint64 start;
1791 	gint32 diff_ms;
1792 	gint32 wait = ms;
1793 
1794 	error_init (error);
1795 
1796 	start = (ms == -1) ? 0 : mono_msec_ticks ();
1797 	for (;;) {
1798 		MONO_ENTER_GC_SAFE;
1799 		ret = mono_thread_info_wait_one_handle (thread_to_join, ms, TRUE);
1800 		MONO_EXIT_GC_SAFE;
1801 
1802 		if (ret != MONO_THREAD_INFO_WAIT_RET_ALERTED)
1803 			return ret;
1804 
1805 		exc = mono_thread_execute_interruption ();
1806 		if (exc) {
1807 			mono_error_set_exception_instance (error, exc);
1808 			return ret;
1809 		}
1810 
1811 		if (ms == -1)
1812 			continue;
1813 
1814 		/* Re-calculate ms according to the time passed */
1815 		diff_ms = (gint32)(mono_msec_ticks () - start);
1816 		if (diff_ms >= ms) {
1817 			ret = MONO_THREAD_INFO_WAIT_RET_TIMEOUT;
1818 			return ret;
1819 		}
1820 		wait = ms - diff_ms;
1821 	}
1822 
1823 	return ret;
1824 }
1825 
1826 gboolean
ves_icall_System_Threading_Thread_Join_internal(MonoThread * this_obj,int ms)1827 ves_icall_System_Threading_Thread_Join_internal (MonoThread *this_obj, int ms)
1828 {
1829 	MonoInternalThread *thread = this_obj->internal_thread;
1830 	MonoThreadHandle *handle = thread->handle;
1831 	MonoInternalThread *cur_thread = mono_thread_internal_current ();
1832 	gboolean ret;
1833 	MonoError error;
1834 
1835 	if (mono_thread_current_check_pending_interrupt ())
1836 		return FALSE;
1837 
1838 	LOCK_THREAD (thread);
1839 
1840 	if ((thread->state & ThreadState_Unstarted) != 0) {
1841 		UNLOCK_THREAD (thread);
1842 
1843 		mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started."));
1844 		return FALSE;
1845 	}
1846 
1847 	UNLOCK_THREAD (thread);
1848 
1849 	if (ms == -1)
1850 		ms = MONO_INFINITE_WAIT;
1851 	THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, handle, ms));
1852 
1853 	mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin);
1854 
1855 	ret = mono_join_uninterrupted (handle, ms, &error);
1856 
1857 	mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin);
1858 
1859 	mono_error_set_pending_exception (&error);
1860 
1861 	if (ret == MONO_THREAD_INFO_WAIT_RET_SUCCESS_0) {
1862 		THREAD_DEBUG (g_message ("%s: join successful", __func__));
1863 
1864 		/* Wait for the thread to really exit */
1865 		MonoNativeThreadId tid = thread_get_tid (thread);
1866 		mono_thread_join (tid);
1867 
1868 		return TRUE;
1869 	}
1870 
1871 	THREAD_DEBUG (g_message ("%s: join failed", __func__));
1872 
1873 	return FALSE;
1874 }
1875 
1876 #define MANAGED_WAIT_FAILED 0x7fffffff
1877 
1878 static gint32
map_native_wait_result_to_managed(MonoW32HandleWaitRet val,gsize numobjects)1879 map_native_wait_result_to_managed (MonoW32HandleWaitRet val, gsize numobjects)
1880 {
1881 	if (val >= MONO_W32HANDLE_WAIT_RET_SUCCESS_0 && val < MONO_W32HANDLE_WAIT_RET_SUCCESS_0 + numobjects) {
1882 		return WAIT_OBJECT_0 + (val - MONO_W32HANDLE_WAIT_RET_SUCCESS_0);
1883 	} else if (val >= MONO_W32HANDLE_WAIT_RET_ABANDONED_0 && val < MONO_W32HANDLE_WAIT_RET_ABANDONED_0 + numobjects) {
1884 		return WAIT_ABANDONED_0 + (val - MONO_W32HANDLE_WAIT_RET_ABANDONED_0);
1885 	} else if (val == MONO_W32HANDLE_WAIT_RET_ALERTED) {
1886 		return WAIT_IO_COMPLETION;
1887 	} else if (val == MONO_W32HANDLE_WAIT_RET_TIMEOUT) {
1888 		return WAIT_TIMEOUT;
1889 	} else if (val == MONO_W32HANDLE_WAIT_RET_FAILED) {
1890 		/* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1891 		return MANAGED_WAIT_FAILED;
1892 	} else {
1893 		g_error ("%s: unknown val value %d", __func__, val);
1894 	}
1895 }
1896 
1897 gint32
ves_icall_System_Threading_WaitHandle_Wait_internal(gpointer * handles,gint32 numhandles,MonoBoolean waitall,gint32 timeout,MonoError * error)1898 ves_icall_System_Threading_WaitHandle_Wait_internal (gpointer *handles, gint32 numhandles, MonoBoolean waitall, gint32 timeout, MonoError *error)
1899 {
1900 	MonoW32HandleWaitRet ret;
1901 	MonoInternalThread *thread;
1902 	MonoException *exc;
1903 	gint64 start;
1904 	guint32 timeoutLeft;
1905 
1906 	/* Do this WaitSleepJoin check before creating objects */
1907 	if (mono_thread_current_check_pending_interrupt ())
1908 		return map_native_wait_result_to_managed (MONO_W32HANDLE_WAIT_RET_FAILED, 0);
1909 
1910 	thread = mono_thread_internal_current ();
1911 
1912 	mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1913 
1914 	if (timeout == -1)
1915 		timeout = MONO_INFINITE_WAIT;
1916 	if (timeout != MONO_INFINITE_WAIT)
1917 		start = mono_msec_ticks ();
1918 
1919 	timeoutLeft = timeout;
1920 
1921 	for (;;) {
1922 #ifdef HOST_WIN32
1923 		MONO_ENTER_GC_SAFE;
1924 		if (numhandles != 1)
1925 			ret = mono_w32handle_convert_wait_ret (mono_win32_wait_for_multiple_objects_ex(numhandles, handles, waitall, timeoutLeft, TRUE), numhandles);
1926 		else
1927 			ret = mono_w32handle_convert_wait_ret (mono_win32_wait_for_single_object_ex (handles [0], timeoutLeft, TRUE), 1);
1928 		MONO_EXIT_GC_SAFE;
1929 #else
1930 		/* mono_w32handle_wait_multiple optimizes the case for numhandles == 1 */
1931 		ret = mono_w32handle_wait_multiple (handles, numhandles, waitall, timeoutLeft, TRUE);
1932 #endif /* HOST_WIN32 */
1933 
1934 		if (ret != MONO_W32HANDLE_WAIT_RET_ALERTED)
1935 			break;
1936 
1937 		exc = mono_thread_execute_interruption ();
1938 		if (exc) {
1939 			mono_error_set_exception_instance (error, exc);
1940 			break;
1941 		}
1942 
1943 		if (timeout != MONO_INFINITE_WAIT) {
1944 			gint64 elapsed;
1945 
1946 			elapsed = mono_msec_ticks () - start;
1947 			if (elapsed >= timeout) {
1948 				ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT;
1949 				break;
1950 			}
1951 
1952 			timeoutLeft = timeout - elapsed;
1953 		}
1954 	}
1955 
1956 	mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1957 
1958 	return map_native_wait_result_to_managed (ret, numhandles);
1959 }
1960 
1961 gint32
ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal(gpointer toSignal,gpointer toWait,gint32 ms,MonoError * error)1962 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (gpointer toSignal, gpointer toWait, gint32 ms, MonoError *error)
1963 {
1964 	MonoW32HandleWaitRet ret;
1965 	MonoInternalThread *thread = mono_thread_internal_current ();
1966 
1967 	if (ms == -1)
1968 		ms = MONO_INFINITE_WAIT;
1969 
1970 	if (mono_thread_current_check_pending_interrupt ())
1971 		return map_native_wait_result_to_managed (MONO_W32HANDLE_WAIT_RET_FAILED, 0);
1972 
1973 	mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1974 
1975 	MONO_ENTER_GC_SAFE;
1976 #ifdef HOST_WIN32
1977 	ret = mono_w32handle_convert_wait_ret (mono_win32_signal_object_and_wait (toSignal, toWait, ms, TRUE), 1);
1978 #else
1979 	ret = mono_w32handle_signal_and_wait (toSignal, toWait, ms, TRUE);
1980 #endif
1981 	MONO_EXIT_GC_SAFE;
1982 
1983 	mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1984 
1985 	return map_native_wait_result_to_managed (ret, 1);
1986 }
1987 
ves_icall_System_Threading_Interlocked_Increment_Int(gint32 * location)1988 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
1989 {
1990 	return mono_atomic_inc_i32 (location);
1991 }
1992 
ves_icall_System_Threading_Interlocked_Increment_Long(gint64 * location)1993 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
1994 {
1995 #if SIZEOF_VOID_P == 4
1996 	if (G_UNLIKELY ((size_t)location & 0x7)) {
1997 		gint64 ret;
1998 		mono_interlocked_lock ();
1999 		(*location)++;
2000 		ret = *location;
2001 		mono_interlocked_unlock ();
2002 		return ret;
2003 	}
2004 #endif
2005 	return mono_atomic_inc_i64 (location);
2006 }
2007 
ves_icall_System_Threading_Interlocked_Decrement_Int(gint32 * location)2008 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
2009 {
2010 	return mono_atomic_dec_i32(location);
2011 }
2012 
ves_icall_System_Threading_Interlocked_Decrement_Long(gint64 * location)2013 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
2014 {
2015 #if SIZEOF_VOID_P == 4
2016 	if (G_UNLIKELY ((size_t)location & 0x7)) {
2017 		gint64 ret;
2018 		mono_interlocked_lock ();
2019 		(*location)--;
2020 		ret = *location;
2021 		mono_interlocked_unlock ();
2022 		return ret;
2023 	}
2024 #endif
2025 	return mono_atomic_dec_i64 (location);
2026 }
2027 
ves_icall_System_Threading_Interlocked_Exchange_Int(gint32 * location,gint32 value)2028 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location, gint32 value)
2029 {
2030 	return mono_atomic_xchg_i32(location, value);
2031 }
2032 
ves_icall_System_Threading_Interlocked_Exchange_Object(MonoObject ** location,MonoObject * value)2033 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location, MonoObject *value)
2034 {
2035 	MonoObject *res;
2036 	res = (MonoObject *) mono_atomic_xchg_ptr((gpointer *) location, value);
2037 	mono_gc_wbarrier_generic_nostore (location);
2038 	return res;
2039 }
2040 
ves_icall_System_Threading_Interlocked_Exchange_IntPtr(gpointer * location,gpointer value)2041 gpointer ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer *location, gpointer value)
2042 {
2043 	return mono_atomic_xchg_ptr(location, value);
2044 }
2045 
ves_icall_System_Threading_Interlocked_Exchange_Single(gfloat * location,gfloat value)2046 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, gfloat value)
2047 {
2048 	IntFloatUnion val, ret;
2049 
2050 	val.fval = value;
2051 	ret.ival = mono_atomic_xchg_i32((gint32 *) location, val.ival);
2052 
2053 	return ret.fval;
2054 }
2055 
2056 gint64
ves_icall_System_Threading_Interlocked_Exchange_Long(gint64 * location,gint64 value)2057 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64 *location, gint64 value)
2058 {
2059 #if SIZEOF_VOID_P == 4
2060 	if (G_UNLIKELY ((size_t)location & 0x7)) {
2061 		gint64 ret;
2062 		mono_interlocked_lock ();
2063 		ret = *location;
2064 		*location = value;
2065 		mono_interlocked_unlock ();
2066 		return ret;
2067 	}
2068 #endif
2069 	return mono_atomic_xchg_i64 (location, value);
2070 }
2071 
2072 gdouble
ves_icall_System_Threading_Interlocked_Exchange_Double(gdouble * location,gdouble value)2073 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location, gdouble value)
2074 {
2075 	LongDoubleUnion val, ret;
2076 
2077 	val.fval = value;
2078 	ret.ival = (gint64)mono_atomic_xchg_i64((gint64 *) location, val.ival);
2079 
2080 	return ret.fval;
2081 }
2082 
ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 * location,gint32 value,gint32 comparand)2083 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location, gint32 value, gint32 comparand)
2084 {
2085 	return mono_atomic_cas_i32(location, value, comparand);
2086 }
2087 
ves_icall_System_Threading_Interlocked_CompareExchange_Int_Success(gint32 * location,gint32 value,gint32 comparand,MonoBoolean * success)2088 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int_Success(gint32 *location, gint32 value, gint32 comparand, MonoBoolean *success)
2089 {
2090 	gint32 r = mono_atomic_cas_i32(location, value, comparand);
2091 	*success = r == comparand;
2092 	return r;
2093 }
2094 
ves_icall_System_Threading_Interlocked_CompareExchange_Object(MonoObject ** location,MonoObject * value,MonoObject * comparand)2095 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location, MonoObject *value, MonoObject *comparand)
2096 {
2097 	MonoObject *res;
2098 	res = (MonoObject *) mono_atomic_cas_ptr((gpointer *) location, value, comparand);
2099 	mono_gc_wbarrier_generic_nostore (location);
2100 	return res;
2101 }
2102 
ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer * location,gpointer value,gpointer comparand)2103 gpointer ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer *location, gpointer value, gpointer comparand)
2104 {
2105 	return mono_atomic_cas_ptr(location, value, comparand);
2106 }
2107 
ves_icall_System_Threading_Interlocked_CompareExchange_Single(gfloat * location,gfloat value,gfloat comparand)2108 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location, gfloat value, gfloat comparand)
2109 {
2110 	IntFloatUnion val, ret, cmp;
2111 
2112 	val.fval = value;
2113 	cmp.fval = comparand;
2114 	ret.ival = mono_atomic_cas_i32((gint32 *) location, val.ival, cmp.ival);
2115 
2116 	return ret.fval;
2117 }
2118 
2119 gdouble
ves_icall_System_Threading_Interlocked_CompareExchange_Double(gdouble * location,gdouble value,gdouble comparand)2120 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble *location, gdouble value, gdouble comparand)
2121 {
2122 #if SIZEOF_VOID_P == 8
2123 	LongDoubleUnion val, comp, ret;
2124 
2125 	val.fval = value;
2126 	comp.fval = comparand;
2127 	ret.ival = (gint64)mono_atomic_cas_ptr((gpointer *) location, (gpointer)val.ival, (gpointer)comp.ival);
2128 
2129 	return ret.fval;
2130 #else
2131 	gdouble old;
2132 
2133 	mono_interlocked_lock ();
2134 	old = *location;
2135 	if (old == comparand)
2136 		*location = value;
2137 	mono_interlocked_unlock ();
2138 
2139 	return old;
2140 #endif
2141 }
2142 
2143 gint64
ves_icall_System_Threading_Interlocked_CompareExchange_Long(gint64 * location,gint64 value,gint64 comparand)2144 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location, gint64 value, gint64 comparand)
2145 {
2146 #if SIZEOF_VOID_P == 4
2147 	if (G_UNLIKELY ((size_t)location & 0x7)) {
2148 		gint64 old;
2149 		mono_interlocked_lock ();
2150 		old = *location;
2151 		if (old == comparand)
2152 			*location = value;
2153 		mono_interlocked_unlock ();
2154 		return old;
2155 	}
2156 #endif
2157 	return mono_atomic_cas_i64 (location, value, comparand);
2158 }
2159 
2160 MonoObject*
ves_icall_System_Threading_Interlocked_CompareExchange_T(MonoObject ** location,MonoObject * value,MonoObject * comparand)2161 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject **location, MonoObject *value, MonoObject *comparand)
2162 {
2163 	MonoObject *res;
2164 	res = (MonoObject *)mono_atomic_cas_ptr ((volatile gpointer *)location, value, comparand);
2165 	mono_gc_wbarrier_generic_nostore (location);
2166 	return res;
2167 }
2168 
2169 MonoObject*
ves_icall_System_Threading_Interlocked_Exchange_T(MonoObject ** location,MonoObject * value)2170 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject **location, MonoObject *value)
2171 {
2172 	MonoObject *res;
2173 	MONO_CHECK_NULL (location, NULL);
2174 	res = (MonoObject *)mono_atomic_xchg_ptr ((volatile gpointer *)location, value);
2175 	mono_gc_wbarrier_generic_nostore (location);
2176 	return res;
2177 }
2178 
2179 gint32
ves_icall_System_Threading_Interlocked_Add_Int(gint32 * location,gint32 value)2180 ves_icall_System_Threading_Interlocked_Add_Int (gint32 *location, gint32 value)
2181 {
2182 	return mono_atomic_add_i32 (location, value);
2183 }
2184 
2185 gint64
ves_icall_System_Threading_Interlocked_Add_Long(gint64 * location,gint64 value)2186 ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location, gint64 value)
2187 {
2188 #if SIZEOF_VOID_P == 4
2189 	if (G_UNLIKELY ((size_t)location & 0x7)) {
2190 		gint64 ret;
2191 		mono_interlocked_lock ();
2192 		*location += value;
2193 		ret = *location;
2194 		mono_interlocked_unlock ();
2195 		return ret;
2196 	}
2197 #endif
2198 	return mono_atomic_add_i64 (location, value);
2199 }
2200 
2201 gint64
ves_icall_System_Threading_Interlocked_Read_Long(gint64 * location)2202 ves_icall_System_Threading_Interlocked_Read_Long (gint64 *location)
2203 {
2204 #if SIZEOF_VOID_P == 4
2205 	if (G_UNLIKELY ((size_t)location & 0x7)) {
2206 		gint64 ret;
2207 		mono_interlocked_lock ();
2208 		ret = *location;
2209 		mono_interlocked_unlock ();
2210 		return ret;
2211 	}
2212 #endif
2213 	return mono_atomic_load_i64 (location);
2214 }
2215 
2216 void
ves_icall_System_Threading_Thread_MemoryBarrier(void)2217 ves_icall_System_Threading_Thread_MemoryBarrier (void)
2218 {
2219 	mono_memory_barrier ();
2220 }
2221 
2222 void
ves_icall_System_Threading_Thread_ClrState(MonoInternalThread * this_obj,guint32 state)2223 ves_icall_System_Threading_Thread_ClrState (MonoInternalThread* this_obj, guint32 state)
2224 {
2225 	mono_thread_clr_state (this_obj, (MonoThreadState)state);
2226 
2227 	if (state & ThreadState_Background) {
2228 		/* If the thread changes the background mode, the main thread has to
2229 		 * be notified, since it has to rebuild the list of threads to
2230 		 * wait for.
2231 		 */
2232 		mono_os_event_set (&background_change_event);
2233 	}
2234 }
2235 
2236 void
ves_icall_System_Threading_Thread_SetState(MonoInternalThread * this_obj,guint32 state)2237 ves_icall_System_Threading_Thread_SetState (MonoInternalThread* this_obj, guint32 state)
2238 {
2239 	mono_thread_set_state (this_obj, (MonoThreadState)state);
2240 
2241 	if (state & ThreadState_Background) {
2242 		/* If the thread changes the background mode, the main thread has to
2243 		 * be notified, since it has to rebuild the list of threads to
2244 		 * wait for.
2245 		 */
2246 		mono_os_event_set (&background_change_event);
2247 	}
2248 }
2249 
2250 guint32
ves_icall_System_Threading_Thread_GetState(MonoInternalThread * this_obj)2251 ves_icall_System_Threading_Thread_GetState (MonoInternalThread* this_obj)
2252 {
2253 	guint32 state;
2254 
2255 	LOCK_THREAD (this_obj);
2256 
2257 	state = this_obj->state;
2258 
2259 	UNLOCK_THREAD (this_obj);
2260 
2261 	return state;
2262 }
2263 
ves_icall_System_Threading_Thread_Interrupt_internal(MonoThread * this_obj)2264 void ves_icall_System_Threading_Thread_Interrupt_internal (MonoThread *this_obj)
2265 {
2266 	MonoInternalThread *current;
2267 	gboolean throw_;
2268 	MonoInternalThread *thread = this_obj->internal_thread;
2269 
2270 	LOCK_THREAD (thread);
2271 
2272 	current = mono_thread_internal_current ();
2273 
2274 	thread->thread_interrupt_requested = TRUE;
2275 	throw_ = current != thread && (thread->state & ThreadState_WaitSleepJoin);
2276 
2277 	UNLOCK_THREAD (thread);
2278 
2279 	if (throw_) {
2280 		async_abort_internal (thread, FALSE);
2281 	}
2282 }
2283 
2284 /**
2285  * mono_thread_current_check_pending_interrupt:
2286  * Checks if there's a interruption request and set the pending exception if so.
2287  * \returns true if a pending exception was set
2288  */
2289 gboolean
mono_thread_current_check_pending_interrupt(void)2290 mono_thread_current_check_pending_interrupt (void)
2291 {
2292 	MonoInternalThread *thread = mono_thread_internal_current ();
2293 	gboolean throw_ = FALSE;
2294 
2295 	LOCK_THREAD (thread);
2296 
2297 	if (thread->thread_interrupt_requested) {
2298 		throw_ = TRUE;
2299 		thread->thread_interrupt_requested = FALSE;
2300 	}
2301 
2302 	UNLOCK_THREAD (thread);
2303 
2304 	if (throw_)
2305 		mono_set_pending_exception (mono_get_exception_thread_interrupted ());
2306 	return throw_;
2307 }
2308 
2309 static gboolean
request_thread_abort(MonoInternalThread * thread,MonoObject * state,gboolean appdomain_unload)2310 request_thread_abort (MonoInternalThread *thread, MonoObject *state, gboolean appdomain_unload)
2311 {
2312 	LOCK_THREAD (thread);
2313 
2314 	if (thread->state & (ThreadState_AbortRequested | ThreadState_Stopped))
2315 	{
2316 		UNLOCK_THREAD (thread);
2317 		return FALSE;
2318 	}
2319 
2320 	if ((thread->state & ThreadState_Unstarted) != 0) {
2321 		thread->state |= ThreadState_Aborted;
2322 		UNLOCK_THREAD (thread);
2323 		return FALSE;
2324 	}
2325 
2326 	thread->state |= ThreadState_AbortRequested;
2327 	if (appdomain_unload)
2328 		thread->flags |= MONO_THREAD_FLAG_APPDOMAIN_ABORT;
2329 	else
2330 		thread->flags &= ~MONO_THREAD_FLAG_APPDOMAIN_ABORT;
2331 
2332 	if (thread->abort_state_handle)
2333 		mono_gchandle_free (thread->abort_state_handle);
2334 	if (state) {
2335 		thread->abort_state_handle = mono_gchandle_new (state, FALSE);
2336 		g_assert (thread->abort_state_handle);
2337 	} else {
2338 		thread->abort_state_handle = 0;
2339 	}
2340 	thread->abort_exc = NULL;
2341 
2342 	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));
2343 
2344 	/* During shutdown, we can't wait for other threads */
2345 	if (!shutting_down)
2346 		/* Make sure the thread is awake */
2347 		mono_thread_resume (thread);
2348 
2349 	UNLOCK_THREAD (thread);
2350 	return TRUE;
2351 }
2352 
2353 void
ves_icall_System_Threading_Thread_Abort(MonoInternalThread * thread,MonoObject * state)2354 ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
2355 {
2356 	if (!request_thread_abort (thread, state, FALSE))
2357 		return;
2358 
2359 	if (thread == mono_thread_internal_current ()) {
2360 		MonoError error;
2361 		self_abort_internal (&error);
2362 		mono_error_set_pending_exception (&error);
2363 	} else {
2364 		async_abort_internal (thread, TRUE);
2365 	}
2366 }
2367 
2368 /**
2369  * mono_thread_internal_abort:
2370  * Request thread \p thread to be aborted.
2371  * \p thread MUST NOT be the current thread.
2372  */
2373 void
mono_thread_internal_abort(MonoInternalThread * thread,gboolean appdomain_unload)2374 mono_thread_internal_abort (MonoInternalThread *thread, gboolean appdomain_unload)
2375 {
2376 	g_assert (thread != mono_thread_internal_current ());
2377 
2378 	if (!request_thread_abort (thread, NULL, appdomain_unload))
2379 		return;
2380 	async_abort_internal (thread, TRUE);
2381 }
2382 
2383 void
ves_icall_System_Threading_Thread_ResetAbort(MonoThread * this_obj)2384 ves_icall_System_Threading_Thread_ResetAbort (MonoThread *this_obj)
2385 {
2386 	MonoInternalThread *thread = mono_thread_internal_current ();
2387 	gboolean was_aborting, is_domain_abort;
2388 
2389 	LOCK_THREAD (thread);
2390 	was_aborting = thread->state & ThreadState_AbortRequested;
2391 	is_domain_abort = thread->flags & MONO_THREAD_FLAG_APPDOMAIN_ABORT;
2392 
2393 	if (was_aborting && !is_domain_abort)
2394 		thread->state &= ~ThreadState_AbortRequested;
2395 	UNLOCK_THREAD (thread);
2396 
2397 	if (!was_aborting) {
2398 		const char *msg = "Unable to reset abort because no abort was requested";
2399 		mono_set_pending_exception (mono_get_exception_thread_state (msg));
2400 		return;
2401 	} else if (is_domain_abort) {
2402 		/* Silently ignore abort resets in unloading appdomains */
2403 		return;
2404 	}
2405 
2406 	mono_get_eh_callbacks ()->mono_clear_abort_threshold ();
2407 	thread->abort_exc = NULL;
2408 	if (thread->abort_state_handle) {
2409 		mono_gchandle_free (thread->abort_state_handle);
2410 		/* This is actually not necessary - the handle
2411 		   only counts if the exception is set */
2412 		thread->abort_state_handle = 0;
2413 	}
2414 }
2415 
2416 void
mono_thread_internal_reset_abort(MonoInternalThread * thread)2417 mono_thread_internal_reset_abort (MonoInternalThread *thread)
2418 {
2419 	LOCK_THREAD (thread);
2420 
2421 	thread->state &= ~ThreadState_AbortRequested;
2422 
2423 	if (thread->abort_exc) {
2424 		mono_get_eh_callbacks ()->mono_clear_abort_threshold ();
2425 		thread->abort_exc = NULL;
2426 		if (thread->abort_state_handle) {
2427 			mono_gchandle_free (thread->abort_state_handle);
2428 			/* This is actually not necessary - the handle
2429 			   only counts if the exception is set */
2430 			thread->abort_state_handle = 0;
2431 		}
2432 	}
2433 
2434 	UNLOCK_THREAD (thread);
2435 }
2436 
2437 MonoObject*
ves_icall_System_Threading_Thread_GetAbortExceptionState(MonoThread * this_obj)2438 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this_obj)
2439 {
2440 	MonoError error;
2441 	MonoInternalThread *thread = this_obj->internal_thread;
2442 	MonoObject *state, *deserialized = NULL;
2443 	MonoDomain *domain;
2444 
2445 	if (!thread->abort_state_handle)
2446 		return NULL;
2447 
2448 	state = mono_gchandle_get_target (thread->abort_state_handle);
2449 	g_assert (state);
2450 
2451 	domain = mono_domain_get ();
2452 	if (mono_object_domain (state) == domain)
2453 		return state;
2454 
2455 	deserialized = mono_object_xdomain_representation (state, domain, &error);
2456 
2457 	if (!deserialized) {
2458 		MonoException *invalid_op_exc = mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
2459 		if (!is_ok (&error)) {
2460 			MonoObject *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2461 			MONO_OBJECT_SETREF (invalid_op_exc, inner_ex, exc);
2462 		}
2463 		mono_set_pending_exception (invalid_op_exc);
2464 		return NULL;
2465 	}
2466 
2467 	return deserialized;
2468 }
2469 
2470 static gboolean
mono_thread_suspend(MonoInternalThread * thread)2471 mono_thread_suspend (MonoInternalThread *thread)
2472 {
2473 	LOCK_THREAD (thread);
2474 
2475 	if (thread->state & (ThreadState_Unstarted | ThreadState_Aborted | ThreadState_Stopped))
2476 	{
2477 		UNLOCK_THREAD (thread);
2478 		return FALSE;
2479 	}
2480 
2481 	if (thread->state & (ThreadState_Suspended | ThreadState_SuspendRequested | ThreadState_AbortRequested))
2482 	{
2483 		UNLOCK_THREAD (thread);
2484 		return TRUE;
2485 	}
2486 
2487 	thread->state |= ThreadState_SuspendRequested;
2488 	mono_os_event_reset (thread->suspended);
2489 
2490 	if (thread == mono_thread_internal_current ()) {
2491 		/* calls UNLOCK_THREAD (thread) */
2492 		self_suspend_internal ();
2493 	} else {
2494 		/* calls UNLOCK_THREAD (thread) */
2495 		async_suspend_internal (thread, FALSE);
2496 	}
2497 
2498 	return TRUE;
2499 }
2500 
2501 void
ves_icall_System_Threading_Thread_Suspend(MonoThread * this_obj)2502 ves_icall_System_Threading_Thread_Suspend (MonoThread *this_obj)
2503 {
2504 	if (!mono_thread_suspend (this_obj->internal_thread)) {
2505 		mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2506 		return;
2507 	}
2508 }
2509 
2510 /* LOCKING: LOCK_THREAD(thread) must be held */
2511 static gboolean
mono_thread_resume(MonoInternalThread * thread)2512 mono_thread_resume (MonoInternalThread *thread)
2513 {
2514 	if ((thread->state & ThreadState_SuspendRequested) != 0) {
2515 		// MOSTLY_ASYNC_SAFE_PRINTF ("RESUME (1) thread %p\n", thread_get_tid (thread));
2516 		thread->state &= ~ThreadState_SuspendRequested;
2517 		mono_os_event_set (thread->suspended);
2518 		return TRUE;
2519 	}
2520 
2521 	if ((thread->state & ThreadState_Suspended) == 0 ||
2522 		(thread->state & ThreadState_Unstarted) != 0 ||
2523 		(thread->state & ThreadState_Aborted) != 0 ||
2524 		(thread->state & ThreadState_Stopped) != 0)
2525 	{
2526 		// MOSTLY_ASYNC_SAFE_PRINTF ("RESUME (2) thread %p\n", thread_get_tid (thread));
2527 		return FALSE;
2528 	}
2529 
2530 	// MOSTLY_ASYNC_SAFE_PRINTF ("RESUME (3) thread %p\n", thread_get_tid (thread));
2531 
2532 	mono_os_event_set (thread->suspended);
2533 
2534 	if (!thread->self_suspended) {
2535 		UNLOCK_THREAD (thread);
2536 
2537 		/* Awake the thread */
2538 		if (!mono_thread_info_resume (thread_get_tid (thread)))
2539 			return FALSE;
2540 
2541 		LOCK_THREAD (thread);
2542 	}
2543 
2544 	thread->state &= ~ThreadState_Suspended;
2545 
2546 	return TRUE;
2547 }
2548 
2549 void
ves_icall_System_Threading_Thread_Resume(MonoThread * thread)2550 ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
2551 {
2552 	if (!thread->internal_thread) {
2553 		mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2554 	} else {
2555 		LOCK_THREAD (thread->internal_thread);
2556 		if (!mono_thread_resume (thread->internal_thread))
2557 			mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2558 		UNLOCK_THREAD (thread->internal_thread);
2559 	}
2560 }
2561 
2562 static gboolean
mono_threads_is_critical_method(MonoMethod * method)2563 mono_threads_is_critical_method (MonoMethod *method)
2564 {
2565 	switch (method->wrapper_type) {
2566 	case MONO_WRAPPER_RUNTIME_INVOKE:
2567 	case MONO_WRAPPER_XDOMAIN_INVOKE:
2568 	case MONO_WRAPPER_XDOMAIN_DISPATCH:
2569 		return TRUE;
2570 	}
2571 	return FALSE;
2572 }
2573 
2574 static gboolean
find_wrapper(MonoMethod * m,gint no,gint ilo,gboolean managed,gpointer data)2575 find_wrapper (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
2576 {
2577 	if (managed)
2578 		return TRUE;
2579 
2580 	if (mono_threads_is_critical_method (m)) {
2581 		*((gboolean*)data) = TRUE;
2582 		return TRUE;
2583 	}
2584 	return FALSE;
2585 }
2586 
2587 static gboolean
is_running_protected_wrapper(void)2588 is_running_protected_wrapper (void)
2589 {
2590 	gboolean found = FALSE;
2591 	mono_stack_walk (find_wrapper, &found);
2592 	return found;
2593 }
2594 
2595 /**
2596  * mono_thread_stop:
2597  */
2598 void
mono_thread_stop(MonoThread * thread)2599 mono_thread_stop (MonoThread *thread)
2600 {
2601 	MonoInternalThread *internal = thread->internal_thread;
2602 
2603 	if (!request_thread_abort (internal, NULL, FALSE))
2604 		return;
2605 
2606 	if (internal == mono_thread_internal_current ()) {
2607 		MonoError error;
2608 		self_abort_internal (&error);
2609 		/*
2610 		This function is part of the embeding API and has no way to return the exception
2611 		to be thrown. So what we do is keep the old behavior and raise the exception.
2612 		*/
2613 		mono_error_raise_exception_deprecated (&error); /* OK to throw, see note */
2614 	} else {
2615 		async_abort_internal (internal, TRUE);
2616 	}
2617 }
2618 
2619 gint8
ves_icall_System_Threading_Thread_VolatileRead1(void * ptr)2620 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
2621 {
2622 	gint8 tmp = *(volatile gint8 *)ptr;
2623 	mono_memory_barrier ();
2624 	return tmp;
2625 }
2626 
2627 gint16
ves_icall_System_Threading_Thread_VolatileRead2(void * ptr)2628 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
2629 {
2630 	gint16 tmp = *(volatile gint16 *)ptr;
2631 	mono_memory_barrier ();
2632 	return tmp;
2633 }
2634 
2635 gint32
ves_icall_System_Threading_Thread_VolatileRead4(void * ptr)2636 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
2637 {
2638 	gint32 tmp = *(volatile gint32 *)ptr;
2639 	mono_memory_barrier ();
2640 	return tmp;
2641 }
2642 
2643 gint64
ves_icall_System_Threading_Thread_VolatileRead8(void * ptr)2644 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
2645 {
2646 	gint64 tmp = *(volatile gint64 *)ptr;
2647 	mono_memory_barrier ();
2648 	return tmp;
2649 }
2650 
2651 void *
ves_icall_System_Threading_Thread_VolatileReadIntPtr(void * ptr)2652 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
2653 {
2654 	volatile void *tmp = *(volatile void **)ptr;
2655 	mono_memory_barrier ();
2656 	return (void *) tmp;
2657 }
2658 
2659 void *
ves_icall_System_Threading_Thread_VolatileReadObject(void * ptr)2660 ves_icall_System_Threading_Thread_VolatileReadObject (void *ptr)
2661 {
2662 	volatile MonoObject *tmp = *(volatile MonoObject **)ptr;
2663 	mono_memory_barrier ();
2664 	return (MonoObject *) tmp;
2665 }
2666 
2667 double
ves_icall_System_Threading_Thread_VolatileReadDouble(void * ptr)2668 ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr)
2669 {
2670 	double tmp = *(volatile double *)ptr;
2671 	mono_memory_barrier ();
2672 	return tmp;
2673 }
2674 
2675 float
ves_icall_System_Threading_Thread_VolatileReadFloat(void * ptr)2676 ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr)
2677 {
2678 	float tmp = *(volatile float *)ptr;
2679 	mono_memory_barrier ();
2680 	return tmp;
2681 }
2682 
2683 gint8
ves_icall_System_Threading_Volatile_Read1(void * ptr)2684 ves_icall_System_Threading_Volatile_Read1 (void *ptr)
2685 {
2686 	return mono_atomic_load_i8 ((volatile gint8 *)ptr);
2687 }
2688 
2689 gint16
ves_icall_System_Threading_Volatile_Read2(void * ptr)2690 ves_icall_System_Threading_Volatile_Read2 (void *ptr)
2691 {
2692 	return mono_atomic_load_i16 ((volatile gint16 *)ptr);
2693 }
2694 
2695 gint32
ves_icall_System_Threading_Volatile_Read4(void * ptr)2696 ves_icall_System_Threading_Volatile_Read4 (void *ptr)
2697 {
2698 	return mono_atomic_load_i32 ((volatile gint32 *)ptr);
2699 }
2700 
2701 gint64
ves_icall_System_Threading_Volatile_Read8(void * ptr)2702 ves_icall_System_Threading_Volatile_Read8 (void *ptr)
2703 {
2704 #if SIZEOF_VOID_P == 4
2705 	if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2706 		gint64 val;
2707 		mono_interlocked_lock ();
2708 		val = *(gint64*)ptr;
2709 		mono_interlocked_unlock ();
2710 		return val;
2711 	}
2712 #endif
2713 	return mono_atomic_load_i64 ((volatile gint64 *)ptr);
2714 }
2715 
2716 void *
ves_icall_System_Threading_Volatile_ReadIntPtr(void * ptr)2717 ves_icall_System_Threading_Volatile_ReadIntPtr (void *ptr)
2718 {
2719 	return mono_atomic_load_ptr ((volatile gpointer *)ptr);
2720 }
2721 
2722 double
ves_icall_System_Threading_Volatile_ReadDouble(void * ptr)2723 ves_icall_System_Threading_Volatile_ReadDouble (void *ptr)
2724 {
2725 	LongDoubleUnion u;
2726 
2727 #if SIZEOF_VOID_P == 4
2728 	if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2729 		double val;
2730 		mono_interlocked_lock ();
2731 		val = *(double*)ptr;
2732 		mono_interlocked_unlock ();
2733 		return val;
2734 	}
2735 #endif
2736 
2737 	u.ival = mono_atomic_load_i64 ((volatile gint64 *)ptr);
2738 
2739 	return u.fval;
2740 }
2741 
2742 float
ves_icall_System_Threading_Volatile_ReadFloat(void * ptr)2743 ves_icall_System_Threading_Volatile_ReadFloat (void *ptr)
2744 {
2745 	IntFloatUnion u;
2746 
2747 	u.ival = mono_atomic_load_i32 ((volatile gint32 *)ptr);
2748 
2749 	return u.fval;
2750 }
2751 
2752 MonoObject*
ves_icall_System_Threading_Volatile_Read_T(void * ptr)2753 ves_icall_System_Threading_Volatile_Read_T (void *ptr)
2754 {
2755 	return (MonoObject *)mono_atomic_load_ptr ((volatile gpointer *)ptr);
2756 }
2757 
2758 void
ves_icall_System_Threading_Thread_VolatileWrite1(void * ptr,gint8 value)2759 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
2760 {
2761 	mono_memory_barrier ();
2762 	*(volatile gint8 *)ptr = value;
2763 }
2764 
2765 void
ves_icall_System_Threading_Thread_VolatileWrite2(void * ptr,gint16 value)2766 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
2767 {
2768 	mono_memory_barrier ();
2769 	*(volatile gint16 *)ptr = value;
2770 }
2771 
2772 void
ves_icall_System_Threading_Thread_VolatileWrite4(void * ptr,gint32 value)2773 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
2774 {
2775 	mono_memory_barrier ();
2776 	*(volatile gint32 *)ptr = value;
2777 }
2778 
2779 void
ves_icall_System_Threading_Thread_VolatileWrite8(void * ptr,gint64 value)2780 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
2781 {
2782 	mono_memory_barrier ();
2783 	*(volatile gint64 *)ptr = value;
2784 }
2785 
2786 void
ves_icall_System_Threading_Thread_VolatileWriteIntPtr(void * ptr,void * value)2787 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
2788 {
2789 	mono_memory_barrier ();
2790 	*(volatile void **)ptr = value;
2791 }
2792 
2793 void
ves_icall_System_Threading_Thread_VolatileWriteObject(void * ptr,MonoObject * value)2794 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr, MonoObject *value)
2795 {
2796 	mono_memory_barrier ();
2797 	mono_gc_wbarrier_generic_store (ptr, value);
2798 }
2799 
2800 void
ves_icall_System_Threading_Thread_VolatileWriteDouble(void * ptr,double value)2801 ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr, double value)
2802 {
2803 	mono_memory_barrier ();
2804 	*(volatile double *)ptr = value;
2805 }
2806 
2807 void
ves_icall_System_Threading_Thread_VolatileWriteFloat(void * ptr,float value)2808 ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr, float value)
2809 {
2810 	mono_memory_barrier ();
2811 	*(volatile float *)ptr = value;
2812 }
2813 
2814 void
ves_icall_System_Threading_Volatile_Write1(void * ptr,gint8 value)2815 ves_icall_System_Threading_Volatile_Write1 (void *ptr, gint8 value)
2816 {
2817 	mono_atomic_store_i8 ((volatile gint8 *)ptr, value);
2818 }
2819 
2820 void
ves_icall_System_Threading_Volatile_Write2(void * ptr,gint16 value)2821 ves_icall_System_Threading_Volatile_Write2 (void *ptr, gint16 value)
2822 {
2823 	mono_atomic_store_i16 ((volatile gint16 *)ptr, value);
2824 }
2825 
2826 void
ves_icall_System_Threading_Volatile_Write4(void * ptr,gint32 value)2827 ves_icall_System_Threading_Volatile_Write4 (void *ptr, gint32 value)
2828 {
2829 	mono_atomic_store_i32 ((volatile gint32 *)ptr, value);
2830 }
2831 
2832 void
ves_icall_System_Threading_Volatile_Write8(void * ptr,gint64 value)2833 ves_icall_System_Threading_Volatile_Write8 (void *ptr, gint64 value)
2834 {
2835 #if SIZEOF_VOID_P == 4
2836 	if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2837 		mono_interlocked_lock ();
2838 		*(gint64*)ptr = value;
2839 		mono_interlocked_unlock ();
2840 		return;
2841 	}
2842 #endif
2843 
2844 	mono_atomic_store_i64 ((volatile gint64 *)ptr, value);
2845 }
2846 
2847 void
ves_icall_System_Threading_Volatile_WriteIntPtr(void * ptr,void * value)2848 ves_icall_System_Threading_Volatile_WriteIntPtr (void *ptr, void *value)
2849 {
2850 	mono_atomic_store_ptr ((volatile gpointer *)ptr, value);
2851 }
2852 
2853 void
ves_icall_System_Threading_Volatile_WriteDouble(void * ptr,double value)2854 ves_icall_System_Threading_Volatile_WriteDouble (void *ptr, double value)
2855 {
2856 	LongDoubleUnion u;
2857 
2858 #if SIZEOF_VOID_P == 4
2859 	if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2860 		mono_interlocked_lock ();
2861 		*(double*)ptr = value;
2862 		mono_interlocked_unlock ();
2863 		return;
2864 	}
2865 #endif
2866 
2867 	u.fval = value;
2868 
2869 	mono_atomic_store_i64 ((volatile gint64 *)ptr, u.ival);
2870 }
2871 
2872 void
ves_icall_System_Threading_Volatile_WriteFloat(void * ptr,float value)2873 ves_icall_System_Threading_Volatile_WriteFloat (void *ptr, float value)
2874 {
2875 	IntFloatUnion u;
2876 
2877 	u.fval = value;
2878 
2879 	mono_atomic_store_i32 ((volatile gint32 *)ptr, u.ival);
2880 }
2881 
2882 void
ves_icall_System_Threading_Volatile_Write_T(void * ptr,MonoObject * value)2883 ves_icall_System_Threading_Volatile_Write_T (void *ptr, MonoObject *value)
2884 {
2885 	mono_gc_wbarrier_generic_store_atomic (ptr, value);
2886 }
2887 
2888 static void
free_context(void * user_data)2889 free_context (void *user_data)
2890 {
2891 	ContextStaticData *data = user_data;
2892 
2893 	mono_threads_lock ();
2894 
2895 	/*
2896 	 * There is no guarantee that, by the point this reference queue callback
2897 	 * has been invoked, the GC handle associated with the object will fail to
2898 	 * resolve as one might expect. So if we don't free and remove the GC
2899 	 * handle here, free_context_static_data_helper () could end up resolving
2900 	 * a GC handle to an actually-dead context which would contain a pointer
2901 	 * to an already-freed static data segment, resulting in a crash when
2902 	 * accessing it.
2903 	 */
2904 	g_hash_table_remove (contexts, GUINT_TO_POINTER (data->gc_handle));
2905 
2906 	mono_threads_unlock ();
2907 
2908 	mono_gchandle_free (data->gc_handle);
2909 	mono_free_static_data (data->static_data);
2910 	g_free (data);
2911 }
2912 
2913 void
mono_threads_register_app_context(MonoAppContext * ctx,MonoError * error)2914 mono_threads_register_app_context (MonoAppContext *ctx, MonoError *error)
2915 {
2916 	error_init (error);
2917 	mono_threads_lock ();
2918 
2919 	//g_print ("Registering context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2920 
2921 	if (!contexts)
2922 		contexts = g_hash_table_new (NULL, NULL);
2923 
2924 	if (!context_queue)
2925 		context_queue = mono_gc_reference_queue_new (free_context);
2926 
2927 	gpointer gch = GUINT_TO_POINTER (mono_gchandle_new_weakref (&ctx->obj, FALSE));
2928 	g_hash_table_insert (contexts, gch, gch);
2929 
2930 	/*
2931 	 * We use this intermediate structure to contain a duplicate pointer to
2932 	 * the static data because we can't rely on being able to resolve the GC
2933 	 * handle in the reference queue callback.
2934 	 */
2935 	ContextStaticData *data = g_new0 (ContextStaticData, 1);
2936 	data->gc_handle = GPOINTER_TO_UINT (gch);
2937 	ctx->data = data;
2938 
2939 	context_adjust_static_data (ctx);
2940 	mono_gc_reference_queue_add (context_queue, &ctx->obj, data);
2941 
2942 	mono_threads_unlock ();
2943 
2944 	MONO_PROFILER_RAISE (context_loaded, (ctx));
2945 }
2946 
2947 void
ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext(MonoAppContextHandle ctx,MonoError * error)2948 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (MonoAppContextHandle ctx, MonoError *error)
2949 {
2950 	error_init (error);
2951 	mono_threads_register_app_context (MONO_HANDLE_RAW (ctx), error); /* FIXME use handles in mono_threads_register_app_context */
2952 }
2953 
2954 void
mono_threads_release_app_context(MonoAppContext * ctx,MonoError * error)2955 mono_threads_release_app_context (MonoAppContext* ctx, MonoError *error)
2956 {
2957 	/*
2958 	 * NOTE: Since finalizers are unreliable for the purposes of ensuring
2959 	 * cleanup in exceptional circumstances, we don't actually do any
2960 	 * cleanup work here. We instead do this via a reference queue.
2961 	 */
2962 
2963 	//g_print ("Releasing context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2964 
2965 	MONO_PROFILER_RAISE (context_unloaded, (ctx));
2966 }
2967 
2968 void
ves_icall_System_Runtime_Remoting_Contexts_Context_ReleaseContext(MonoAppContextHandle ctx,MonoError * error)2969 ves_icall_System_Runtime_Remoting_Contexts_Context_ReleaseContext (MonoAppContextHandle ctx, MonoError *error)
2970 {
2971 	error_init (error);
2972 	mono_threads_release_app_context (MONO_HANDLE_RAW (ctx), error); /* FIXME use handles in mono_threads_release_app_context */
2973 }
2974 
mono_thread_init(MonoThreadStartCB start_cb,MonoThreadAttachCB attach_cb)2975 void mono_thread_init (MonoThreadStartCB start_cb,
2976 		       MonoThreadAttachCB attach_cb)
2977 {
2978 	mono_coop_mutex_init_recursive (&threads_mutex);
2979 
2980 	mono_os_mutex_init_recursive(&interlocked_mutex);
2981 	mono_os_mutex_init_recursive(&joinable_threads_mutex);
2982 
2983 	mono_os_event_init (&background_change_event, FALSE);
2984 
2985 	mono_init_static_data_info (&thread_static_info);
2986 	mono_init_static_data_info (&context_static_info);
2987 
2988 	mono_thread_start_cb = start_cb;
2989 	mono_thread_attach_cb = attach_cb;
2990 }
2991 
2992 static gpointer
thread_attach(MonoThreadInfo * info)2993 thread_attach (MonoThreadInfo *info)
2994 {
2995 	return mono_gc_thread_attach (info);
2996 }
2997 
2998 static void
thread_detach(MonoThreadInfo * info)2999 thread_detach (MonoThreadInfo *info)
3000 {
3001 	MonoInternalThread *internal;
3002 	guint32 gchandle;
3003 
3004 	/* If a delegate is passed to native code and invoked on a thread we dont
3005 	 * know about, marshal will register it with mono_threads_attach_coop, but
3006 	 * we have no way of knowing when that thread goes away.  SGen has a TSD
3007 	 * so we assume that if the domain is still registered, we can detach
3008 	 * the thread */
3009 
3010 	g_assert (info);
3011 	g_assert (mono_thread_info_is_current (info));
3012 
3013 	if (!mono_thread_info_try_get_internal_thread_gchandle (info, &gchandle))
3014 		return;
3015 
3016 	internal = (MonoInternalThread*) mono_gchandle_get_target (gchandle);
3017 	g_assert (internal);
3018 
3019 	mono_thread_detach_internal (internal);
3020 }
3021 
3022 static void
thread_detach_with_lock(MonoThreadInfo * info)3023 thread_detach_with_lock (MonoThreadInfo *info)
3024 {
3025 	mono_gc_thread_detach_with_lock (info);
3026 }
3027 
3028 static gboolean
thread_in_critical_region(MonoThreadInfo * info)3029 thread_in_critical_region (MonoThreadInfo *info)
3030 {
3031 	return mono_gc_thread_in_critical_region (info);
3032 }
3033 
3034 static gboolean
ip_in_critical_region(MonoDomain * domain,gpointer ip)3035 ip_in_critical_region (MonoDomain *domain, gpointer ip)
3036 {
3037 	MonoJitInfo *ji;
3038 	MonoMethod *method;
3039 
3040 	/*
3041 	 * We pass false for 'try_aot' so this becomes async safe.
3042 	 * It won't find aot methods whose jit info is not yet loaded,
3043 	 * so we preload their jit info in the JIT.
3044 	 */
3045 	ji = mono_jit_info_table_find_internal (domain, ip, FALSE, FALSE);
3046 	if (!ji)
3047 		return FALSE;
3048 
3049 	method = mono_jit_info_get_method (ji);
3050 	g_assert (method);
3051 
3052 	return mono_gc_is_critical_method (method);
3053 }
3054 
3055 void
mono_thread_callbacks_init(void)3056 mono_thread_callbacks_init (void)
3057 {
3058 	MonoThreadInfoCallbacks cb;
3059 
3060 	memset (&cb, 0, sizeof(cb));
3061 	cb.thread_attach = thread_attach;
3062 	cb.thread_detach = thread_detach;
3063 	cb.thread_detach_with_lock = thread_detach_with_lock;
3064 	cb.ip_in_critical_region = ip_in_critical_region;
3065 	cb.thread_in_critical_region = thread_in_critical_region;
3066 	mono_thread_info_callbacks_init (&cb);
3067 }
3068 
3069 /**
3070  * mono_thread_cleanup:
3071  */
3072 void
mono_thread_cleanup(void)3073 mono_thread_cleanup (void)
3074 {
3075 	mono_threads_join_threads ();
3076 
3077 #if !defined(RUN_IN_SUBTHREAD) && !defined(HOST_WIN32)
3078 	/* The main thread must abandon any held mutexes (particularly
3079 	 * important for named mutexes as they are shared across
3080 	 * processes, see bug 74680.)  This will happen when the
3081 	 * thread exits, but if it's not running in a subthread it
3082 	 * won't exit in time.
3083 	 */
3084 	mono_w32mutex_abandon ();
3085 #endif
3086 
3087 #if 0
3088 	/* This stuff needs more testing, it seems one of these
3089 	 * critical sections can be locked when mono_thread_cleanup is
3090 	 * called.
3091 	 */
3092 	mono_coop_mutex_destroy (&threads_mutex);
3093 	mono_os_mutex_destroy (&interlocked_mutex);
3094 	mono_os_mutex_destroy (&delayed_free_table_mutex);
3095 	mono_os_mutex_destroy (&small_id_mutex);
3096 	mono_os_event_destroy (&background_change_event);
3097 #endif
3098 }
3099 
3100 void
mono_threads_install_cleanup(MonoThreadCleanupFunc func)3101 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
3102 {
3103 	mono_thread_cleanup_fn = func;
3104 }
3105 
3106 /**
3107  * mono_thread_set_manage_callback:
3108  */
3109 void
mono_thread_set_manage_callback(MonoThread * thread,MonoThreadManageCallback func)3110 mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
3111 {
3112 	thread->internal_thread->manage_callback = func;
3113 }
3114 
3115 G_GNUC_UNUSED
print_tids(gpointer key,gpointer value,gpointer user)3116 static void print_tids (gpointer key, gpointer value, gpointer user)
3117 {
3118 	/* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
3119 	 * sizeof(uint) and a cast to uint would overflow
3120 	 */
3121 	/* Older versions of glib don't have G_GSIZE_FORMAT, so just
3122 	 * print this as a pointer.
3123 	 */
3124 	g_message ("Waiting for: %p", key);
3125 }
3126 
3127 struct wait_data
3128 {
3129 	MonoThreadHandle *handles[MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
3130 	MonoInternalThread *threads[MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
3131 	guint32 num;
3132 };
3133 
3134 static void
wait_for_tids(struct wait_data * wait,guint32 timeout,gboolean check_state_change)3135 wait_for_tids (struct wait_data *wait, guint32 timeout, gboolean check_state_change)
3136 {
3137 	guint32 i;
3138 	MonoThreadInfoWaitRet ret;
3139 
3140 	THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
3141 
3142 	/* Add the thread state change event, so it wakes
3143 	 * up if a thread changes to background mode. */
3144 
3145 	MONO_ENTER_GC_SAFE;
3146 	if (check_state_change)
3147 		ret = mono_thread_info_wait_multiple_handle (wait->handles, wait->num, &background_change_event, FALSE, timeout, TRUE);
3148 	else
3149 		ret = mono_thread_info_wait_multiple_handle (wait->handles, wait->num, NULL, TRUE, timeout, TRUE);
3150 	MONO_EXIT_GC_SAFE;
3151 
3152 	if (ret == MONO_THREAD_INFO_WAIT_RET_FAILED) {
3153 		/* See the comment in build_wait_tids() */
3154 		THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
3155 		return;
3156 	}
3157 
3158 	for( i = 0; i < wait->num; i++)
3159 		mono_threads_close_thread_handle (wait->handles [i]);
3160 
3161 	if (ret == MONO_THREAD_INFO_WAIT_RET_TIMEOUT)
3162 		return;
3163 
3164 	if (ret < wait->num) {
3165 		MonoInternalThread *internal;
3166 
3167 		internal = wait->threads [ret];
3168 
3169 		mono_threads_lock ();
3170 		if (mono_g_hash_table_lookup (threads, (gpointer) internal->tid) == internal)
3171 			g_error ("%s: failed to call mono_thread_detach_internal on thread %p, InternalThread: %p", __func__, internal->tid, internal);
3172 		mono_threads_unlock ();
3173 	}
3174 }
3175 
build_wait_tids(gpointer key,gpointer value,gpointer user)3176 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
3177 {
3178 	struct wait_data *wait=(struct wait_data *)user;
3179 
3180 	if(wait->num<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS - 1) {
3181 		MonoInternalThread *thread=(MonoInternalThread *)value;
3182 
3183 		/* Ignore background threads, we abort them later */
3184 		/* Do not lock here since it is not needed and the caller holds threads_lock */
3185 		if (thread->state & ThreadState_Background) {
3186 			THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3187 			return; /* just leave, ignore */
3188 		}
3189 
3190 		if (mono_gc_is_finalizer_internal_thread (thread)) {
3191 			THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3192 			return;
3193 		}
3194 
3195 		if (thread == mono_thread_internal_current ()) {
3196 			THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3197 			return;
3198 		}
3199 
3200 		if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
3201 			THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3202 			return;
3203 		}
3204 
3205 		if (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) {
3206 			THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT "with DONT_MANAGE flag set.", __func__, (gsize)thread->tid));
3207 			return;
3208 		}
3209 
3210 		THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
3211 		if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) {
3212 			wait->handles[wait->num]=mono_threads_open_thread_handle (thread->handle);
3213 			wait->threads[wait->num]=thread;
3214 			wait->num++;
3215 
3216 			THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3217 		} else {
3218 			THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3219 		}
3220 
3221 
3222 	} else {
3223 		/* Just ignore the rest, we can't do anything with
3224 		 * them yet
3225 		 */
3226 	}
3227 }
3228 
3229 static void
abort_threads(gpointer key,gpointer value,gpointer user)3230 abort_threads (gpointer key, gpointer value, gpointer user)
3231 {
3232 	struct wait_data *wait=(struct wait_data *)user;
3233 	MonoNativeThreadId self = mono_native_thread_id_get ();
3234 	MonoInternalThread *thread = (MonoInternalThread *)value;
3235 
3236 	if (wait->num >= MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS)
3237 		return;
3238 
3239 	if (mono_native_thread_id_equals (thread_get_tid (thread), self))
3240 		return;
3241 	if (mono_gc_is_finalizer_internal_thread (thread))
3242 		return;
3243 
3244 	if ((thread->flags & MONO_THREAD_FLAG_DONT_MANAGE))
3245 		return;
3246 
3247 	wait->handles[wait->num] = mono_threads_open_thread_handle (thread->handle);
3248 	wait->threads[wait->num] = thread;
3249 	wait->num++;
3250 
3251 	THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
3252 	mono_thread_internal_abort (thread, FALSE);
3253 }
3254 
3255 /**
3256  * mono_threads_set_shutting_down:
3257  *
3258  * Is called by a thread that wants to shut down Mono. If the runtime is already
3259  * shutting down, the calling thread is suspended/stopped, and this function never
3260  * returns.
3261  */
3262 void
mono_threads_set_shutting_down(void)3263 mono_threads_set_shutting_down (void)
3264 {
3265 	MonoInternalThread *current_thread = mono_thread_internal_current ();
3266 
3267 	mono_threads_lock ();
3268 
3269 	if (shutting_down) {
3270 		mono_threads_unlock ();
3271 
3272 		/* Make sure we're properly suspended/stopped */
3273 
3274 		LOCK_THREAD (current_thread);
3275 
3276 		if (current_thread->state & (ThreadState_SuspendRequested | ThreadState_AbortRequested)) {
3277 			UNLOCK_THREAD (current_thread);
3278 			mono_thread_execute_interruption ();
3279 		} else {
3280 			UNLOCK_THREAD (current_thread);
3281 		}
3282 
3283 		/*since we're killing the thread, detach it.*/
3284 		mono_thread_detach_internal (current_thread);
3285 
3286 		/* Wake up other threads potentially waiting for us */
3287 		mono_thread_info_exit (0);
3288 	} else {
3289 		shutting_down = TRUE;
3290 
3291 		/* Not really a background state change, but this will
3292 		 * interrupt the main thread if it is waiting for all
3293 		 * the other threads.
3294 		 */
3295 		mono_os_event_set (&background_change_event);
3296 
3297 		mono_threads_unlock ();
3298 	}
3299 }
3300 
3301 /**
3302  * mono_thread_manage:
3303  */
3304 void
mono_thread_manage(void)3305 mono_thread_manage (void)
3306 {
3307 	struct wait_data wait_data;
3308 	struct wait_data *wait = &wait_data;
3309 
3310 	memset (wait, 0, sizeof (struct wait_data));
3311 	/* join each thread that's still running */
3312 	THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
3313 
3314 	mono_threads_lock ();
3315 	if(threads==NULL) {
3316 		THREAD_DEBUG (g_message("%s: No threads", __func__));
3317 		mono_threads_unlock ();
3318 		return;
3319 	}
3320 	mono_threads_unlock ();
3321 
3322 	do {
3323 		mono_threads_lock ();
3324 		if (shutting_down) {
3325 			/* somebody else is shutting down */
3326 			mono_threads_unlock ();
3327 			break;
3328 		}
3329 		THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
3330 			mono_g_hash_table_foreach (threads, print_tids, NULL));
3331 
3332 		mono_os_event_reset (&background_change_event);
3333 		wait->num=0;
3334 		/* We must zero all InternalThread pointers to avoid making the GC unhappy. */
3335 		memset (wait->threads, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3336 		mono_g_hash_table_foreach (threads, build_wait_tids, wait);
3337 		mono_threads_unlock ();
3338 		if (wait->num > 0)
3339 			/* Something to wait for */
3340 			wait_for_tids (wait, MONO_INFINITE_WAIT, TRUE);
3341 		THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
3342 	} while(wait->num>0);
3343 
3344 	/* Mono is shutting down, so just wait for the end */
3345 	if (!mono_runtime_try_shutdown ()) {
3346 		/*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
3347 		mono_thread_suspend (mono_thread_internal_current ());
3348 		mono_thread_execute_interruption ();
3349 	}
3350 
3351 	/*
3352 	 * Remove everything but the finalizer thread and self.
3353 	 * Also abort all the background threads
3354 	 * */
3355 	do {
3356 		mono_threads_lock ();
3357 
3358 		wait->num = 0;
3359 		/*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3360 		memset (wait->threads, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3361 		mono_g_hash_table_foreach (threads, abort_threads, wait);
3362 
3363 		mono_threads_unlock ();
3364 
3365 		THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
3366 		if (wait->num > 0) {
3367 			/* Something to wait for */
3368 			wait_for_tids (wait, MONO_INFINITE_WAIT, FALSE);
3369 		}
3370 	} while (wait->num > 0);
3371 
3372 	/*
3373 	 * give the subthreads a chance to really quit (this is mainly needed
3374 	 * to get correct user and system times from getrusage/wait/time(1)).
3375 	 * This could be removed if we avoid pthread_detach() and use pthread_join().
3376 	 */
3377 	mono_thread_info_yield ();
3378 }
3379 
3380 static void
collect_threads_for_suspend(gpointer key,gpointer value,gpointer user_data)3381 collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
3382 {
3383 	MonoInternalThread *thread = (MonoInternalThread*)value;
3384 	struct wait_data *wait = (struct wait_data*)user_data;
3385 
3386 	/*
3387 	 * We try to exclude threads early, to avoid running into the MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
3388 	 * limitation.
3389 	 * This needs no locking.
3390 	 */
3391 	if ((thread->state & ThreadState_Suspended) != 0 ||
3392 		(thread->state & ThreadState_Stopped) != 0)
3393 		return;
3394 
3395 	if (wait->num<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
3396 		wait->handles [wait->num] = mono_threads_open_thread_handle (thread->handle);
3397 		wait->threads [wait->num] = thread;
3398 		wait->num++;
3399 	}
3400 }
3401 
3402 /*
3403  * mono_thread_suspend_all_other_threads:
3404  *
3405  *  Suspend all managed threads except the finalizer thread and this thread. It is
3406  * not possible to resume them later.
3407  */
mono_thread_suspend_all_other_threads(void)3408 void mono_thread_suspend_all_other_threads (void)
3409 {
3410 	struct wait_data wait_data;
3411 	struct wait_data *wait = &wait_data;
3412 	int i;
3413 	MonoNativeThreadId self = mono_native_thread_id_get ();
3414 	guint32 eventidx = 0;
3415 	gboolean starting, finished;
3416 
3417 	memset (wait, 0, sizeof (struct wait_data));
3418 	/*
3419 	 * The other threads could be in an arbitrary state at this point, i.e.
3420 	 * they could be starting up, shutting down etc. This means that there could be
3421 	 * threads which are not even in the threads hash table yet.
3422 	 */
3423 
3424 	/*
3425 	 * First we set a barrier which will be checked by all threads before they
3426 	 * are added to the threads hash table, and they will exit if the flag is set.
3427 	 * This ensures that no threads could be added to the hash later.
3428 	 * We will use shutting_down as the barrier for now.
3429 	 */
3430 	g_assert (shutting_down);
3431 
3432 	/*
3433 	 * We make multiple calls to WaitForMultipleObjects since:
3434 	 * - we can only wait for MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS threads
3435 	 * - some threads could exit without becoming suspended
3436 	 */
3437 	finished = FALSE;
3438 	while (!finished) {
3439 		/*
3440 		 * Make a copy of the hashtable since we can't do anything with
3441 		 * threads while threads_mutex is held.
3442 		 */
3443 		wait->num = 0;
3444 		/*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3445 		memset (wait->threads, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3446 		mono_threads_lock ();
3447 		mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
3448 		mono_threads_unlock ();
3449 
3450 		eventidx = 0;
3451 		/* Get the suspended events that we'll be waiting for */
3452 		for (i = 0; i < wait->num; ++i) {
3453 			MonoInternalThread *thread = wait->threads [i];
3454 
3455 			if (mono_native_thread_id_equals (thread_get_tid (thread), self)
3456 			     || mono_gc_is_finalizer_internal_thread (thread)
3457 			     || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)
3458 			) {
3459 				mono_threads_close_thread_handle (wait->handles [i]);
3460 				wait->threads [i] = NULL;
3461 				continue;
3462 			}
3463 
3464 			LOCK_THREAD (thread);
3465 
3466 			if (thread->state & (ThreadState_Suspended | ThreadState_Stopped)) {
3467 				UNLOCK_THREAD (thread);
3468 				mono_threads_close_thread_handle (wait->handles [i]);
3469 				wait->threads [i] = NULL;
3470 				continue;
3471 			}
3472 
3473 			++eventidx;
3474 
3475 			/* Convert abort requests into suspend requests */
3476 			if ((thread->state & ThreadState_AbortRequested) != 0)
3477 				thread->state &= ~ThreadState_AbortRequested;
3478 
3479 			thread->state |= ThreadState_SuspendRequested;
3480 			mono_os_event_reset (thread->suspended);
3481 
3482 			/* Signal the thread to suspend + calls UNLOCK_THREAD (thread) */
3483 			async_suspend_internal (thread, TRUE);
3484 
3485 			mono_threads_close_thread_handle (wait->handles [i]);
3486 			wait->threads [i] = NULL;
3487 		}
3488 		if (eventidx <= 0) {
3489 			/*
3490 			 * If there are threads which are starting up, we wait until they
3491 			 * are suspended when they try to register in the threads hash.
3492 			 * This is guaranteed to finish, since the threads which can create new
3493 			 * threads get suspended after a while.
3494 			 * FIXME: The finalizer thread can still create new threads.
3495 			 */
3496 			mono_threads_lock ();
3497 			if (threads_starting_up)
3498 				starting = mono_g_hash_table_size (threads_starting_up) > 0;
3499 			else
3500 				starting = FALSE;
3501 			mono_threads_unlock ();
3502 			if (starting)
3503 				mono_thread_info_sleep (100, NULL);
3504 			else
3505 				finished = TRUE;
3506 		}
3507 	}
3508 }
3509 
3510 typedef struct {
3511 	MonoInternalThread *thread;
3512 	MonoStackFrameInfo *frames;
3513 	int nframes, max_frames;
3514 	int nthreads, max_threads;
3515 	MonoInternalThread **threads;
3516 } ThreadDumpUserData;
3517 
3518 static gboolean thread_dump_requested;
3519 
3520 /* This needs to be async safe */
3521 static gboolean
collect_frame(MonoStackFrameInfo * frame,MonoContext * ctx,gpointer data)3522 collect_frame (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
3523 {
3524 	ThreadDumpUserData *ud = (ThreadDumpUserData *)data;
3525 
3526 	if (ud->nframes < ud->max_frames) {
3527 		memcpy (&ud->frames [ud->nframes], frame, sizeof (MonoStackFrameInfo));
3528 		ud->nframes ++;
3529 	}
3530 
3531 	return FALSE;
3532 }
3533 
3534 /* This needs to be async safe */
3535 static SuspendThreadResult
get_thread_dump(MonoThreadInfo * info,gpointer ud)3536 get_thread_dump (MonoThreadInfo *info, gpointer ud)
3537 {
3538 	ThreadDumpUserData *user_data = (ThreadDumpUserData *)ud;
3539 	MonoInternalThread *thread = user_data->thread;
3540 
3541 #if 0
3542 /* This no longer works with remote unwinding */
3543 	g_string_append_printf (text, " tid=0x%p this=0x%p ", (gpointer)(gsize)thread->tid, thread);
3544 	mono_thread_internal_describe (thread, text);
3545 	g_string_append (text, "\n");
3546 #endif
3547 
3548 	if (thread == mono_thread_internal_current ())
3549 		mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (collect_frame, NULL, MONO_UNWIND_SIGNAL_SAFE, ud);
3550 	else
3551 		mono_get_eh_callbacks ()->mono_walk_stack_with_state (collect_frame, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, ud);
3552 
3553 	return MonoResumeThread;
3554 }
3555 
3556 typedef struct {
3557 	int nthreads, max_threads;
3558 	MonoInternalThread **threads;
3559 } CollectThreadsUserData;
3560 
3561 static void
collect_thread(gpointer key,gpointer value,gpointer user)3562 collect_thread (gpointer key, gpointer value, gpointer user)
3563 {
3564 	CollectThreadsUserData *ud = (CollectThreadsUserData *)user;
3565 	MonoInternalThread *thread = (MonoInternalThread *)value;
3566 
3567 	if (ud->nthreads < ud->max_threads)
3568 		ud->threads [ud->nthreads ++] = thread;
3569 }
3570 
3571 /*
3572  * Collect running threads into the THREADS array.
3573  * THREADS should be an array allocated on the stack.
3574  */
3575 static int
collect_threads(MonoInternalThread ** thread_array,int max_threads)3576 collect_threads (MonoInternalThread **thread_array, int max_threads)
3577 {
3578 	CollectThreadsUserData ud;
3579 
3580 	memset (&ud, 0, sizeof (ud));
3581 	/* This array contains refs, but its on the stack, so its ok */
3582 	ud.threads = thread_array;
3583 	ud.max_threads = max_threads;
3584 
3585 	mono_threads_lock ();
3586 	mono_g_hash_table_foreach (threads, collect_thread, &ud);
3587 	mono_threads_unlock ();
3588 
3589 	return ud.nthreads;
3590 }
3591 
3592 static void
dump_thread(MonoInternalThread * thread,ThreadDumpUserData * ud)3593 dump_thread (MonoInternalThread *thread, ThreadDumpUserData *ud)
3594 {
3595 	GString* text = g_string_new (0);
3596 	char *name;
3597 	GError *error = NULL;
3598 	int i;
3599 
3600 	ud->thread = thread;
3601 	ud->nframes = 0;
3602 
3603 	/* Collect frames for the thread */
3604 	if (thread == mono_thread_internal_current ()) {
3605 		get_thread_dump (mono_thread_info_current (), ud);
3606 	} else {
3607 		mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, ud);
3608 	}
3609 
3610 	/*
3611 	 * Do all the non async-safe work outside of get_thread_dump.
3612 	 */
3613 	if (thread->name) {
3614 		name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
3615 		g_assert (!error);
3616 		g_string_append_printf (text, "\n\"%s\"", name);
3617 		g_free (name);
3618 	}
3619 	else if (thread->threadpool_thread) {
3620 		g_string_append (text, "\n\"<threadpool thread>\"");
3621 	} else {
3622 		g_string_append (text, "\n\"<unnamed thread>\"");
3623 	}
3624 
3625 	for (i = 0; i < ud->nframes; ++i) {
3626 		MonoStackFrameInfo *frame = &ud->frames [i];
3627 		MonoMethod *method = NULL;
3628 
3629 		if (frame->type == FRAME_TYPE_MANAGED)
3630 			method = mono_jit_info_get_method (frame->ji);
3631 
3632 		if (method) {
3633 			gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3634 			g_string_append_printf (text, "  %s\n", location);
3635 			g_free (location);
3636 		} else {
3637 			g_string_append_printf (text, "  at <unknown> <0x%05x>\n", frame->native_offset);
3638 		}
3639 	}
3640 
3641 	fprintf (stdout, "%s", text->str);
3642 
3643 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3644 	OutputDebugStringA(text->str);
3645 #endif
3646 
3647 	g_string_free (text, TRUE);
3648 	fflush (stdout);
3649 }
3650 
3651 void
mono_threads_perform_thread_dump(void)3652 mono_threads_perform_thread_dump (void)
3653 {
3654 	ThreadDumpUserData ud;
3655 	MonoInternalThread *thread_array [128];
3656 	int tindex, nthreads;
3657 
3658 	if (!thread_dump_requested)
3659 		return;
3660 
3661 	printf ("Full thread dump:\n");
3662 
3663 	/* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3664 	nthreads = collect_threads (thread_array, 128);
3665 
3666 	memset (&ud, 0, sizeof (ud));
3667 	ud.frames = g_new0 (MonoStackFrameInfo, 256);
3668 	ud.max_frames = 256;
3669 
3670 	for (tindex = 0; tindex < nthreads; ++tindex)
3671 		dump_thread (thread_array [tindex], &ud);
3672 
3673 	g_free (ud.frames);
3674 
3675 	thread_dump_requested = FALSE;
3676 }
3677 
3678 /* Obtain the thread dump of all threads */
3679 static gboolean
mono_threads_get_thread_dump(MonoArray ** out_threads,MonoArray ** out_stack_frames,MonoError * error)3680 mono_threads_get_thread_dump (MonoArray **out_threads, MonoArray **out_stack_frames, MonoError *error)
3681 {
3682 
3683 	ThreadDumpUserData ud;
3684 	MonoInternalThread *thread_array [128];
3685 	MonoDomain *domain = mono_domain_get ();
3686 	MonoDebugSourceLocation *location;
3687 	int tindex, nthreads;
3688 
3689 	error_init (error);
3690 
3691 	*out_threads = NULL;
3692 	*out_stack_frames = NULL;
3693 
3694 	/* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3695 	nthreads = collect_threads (thread_array, 128);
3696 
3697 	memset (&ud, 0, sizeof (ud));
3698 	ud.frames = g_new0 (MonoStackFrameInfo, 256);
3699 	ud.max_frames = 256;
3700 
3701 	*out_threads = mono_array_new_checked (domain, mono_defaults.thread_class, nthreads, error);
3702 	goto_if_nok (error, leave);
3703 	*out_stack_frames = mono_array_new_checked (domain, mono_defaults.array_class, nthreads, error);
3704 	goto_if_nok (error, leave);
3705 
3706 	for (tindex = 0; tindex < nthreads; ++tindex) {
3707 		MonoInternalThread *thread = thread_array [tindex];
3708 		MonoArray *thread_frames;
3709 		int i;
3710 
3711 		ud.thread = thread;
3712 		ud.nframes = 0;
3713 
3714 		/* Collect frames for the thread */
3715 		if (thread == mono_thread_internal_current ()) {
3716 			get_thread_dump (mono_thread_info_current (), &ud);
3717 		} else {
3718 			mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, &ud);
3719 		}
3720 
3721 		mono_array_setref_fast (*out_threads, tindex, mono_thread_current_for_thread (thread));
3722 
3723 		thread_frames = mono_array_new_checked (domain, mono_defaults.stack_frame_class, ud.nframes, error);
3724 		goto_if_nok (error, leave);
3725 		mono_array_setref_fast (*out_stack_frames, tindex, thread_frames);
3726 
3727 		for (i = 0; i < ud.nframes; ++i) {
3728 			MonoStackFrameInfo *frame = &ud.frames [i];
3729 			MonoMethod *method = NULL;
3730 			MonoStackFrame *sf = (MonoStackFrame *)mono_object_new_checked (domain, mono_defaults.stack_frame_class, error);
3731 			goto_if_nok (error, leave);
3732 
3733 			sf->native_offset = frame->native_offset;
3734 
3735 			if (frame->type == FRAME_TYPE_MANAGED)
3736 				method = mono_jit_info_get_method (frame->ji);
3737 
3738 			if (method) {
3739 				sf->method_address = (gsize) frame->ji->code_start;
3740 
3741 				MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
3742 				goto_if_nok (error, leave);
3743 				MONO_OBJECT_SETREF (sf, method, rm);
3744 
3745 				location = mono_debug_lookup_source_location (method, frame->native_offset, domain);
3746 				if (location) {
3747 					sf->il_offset = location->il_offset;
3748 
3749 					if (location && location->source_file) {
3750 						MonoString *filename = mono_string_new_checked (domain, location->source_file, error);
3751 						goto_if_nok (error, leave);
3752 						MONO_OBJECT_SETREF (sf, filename, filename);
3753 						sf->line = location->row;
3754 						sf->column = location->column;
3755 					}
3756 					mono_debug_free_source_location (location);
3757 				} else {
3758 					sf->il_offset = -1;
3759 				}
3760 			}
3761 			mono_array_setref (thread_frames, i, sf);
3762 		}
3763 	}
3764 
3765 leave:
3766 	g_free (ud.frames);
3767 	return is_ok (error);
3768 }
3769 
3770 /**
3771  * mono_threads_request_thread_dump:
3772  *
3773  *   Ask all threads except the current to print their stacktrace to stdout.
3774  */
3775 void
mono_threads_request_thread_dump(void)3776 mono_threads_request_thread_dump (void)
3777 {
3778 	/*The new thread dump code runs out of the finalizer thread. */
3779 	thread_dump_requested = TRUE;
3780 	mono_gc_finalize_notify ();
3781 }
3782 
3783 struct ref_stack {
3784 	gpointer *refs;
3785 	gint allocated; /* +1 so that refs [allocated] == NULL */
3786 	gint bottom;
3787 };
3788 
3789 typedef struct ref_stack RefStack;
3790 
3791 static RefStack *
ref_stack_new(gint initial_size)3792 ref_stack_new (gint initial_size)
3793 {
3794 	RefStack *rs;
3795 
3796 	initial_size = MAX (initial_size, 16) + 1;
3797 	rs = g_new0 (RefStack, 1);
3798 	rs->refs = g_new0 (gpointer, initial_size);
3799 	rs->allocated = initial_size;
3800 	return rs;
3801 }
3802 
3803 static void
ref_stack_destroy(gpointer ptr)3804 ref_stack_destroy (gpointer ptr)
3805 {
3806 	RefStack *rs = (RefStack *)ptr;
3807 
3808 	if (rs != NULL) {
3809 		g_free (rs->refs);
3810 		g_free (rs);
3811 	}
3812 }
3813 
3814 static void
ref_stack_push(RefStack * rs,gpointer ptr)3815 ref_stack_push (RefStack *rs, gpointer ptr)
3816 {
3817 	g_assert (rs != NULL);
3818 
3819 	if (rs->bottom >= rs->allocated) {
3820 		rs->refs = (void **)g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
3821 		rs->allocated <<= 1;
3822 		rs->refs [rs->allocated] = NULL;
3823 	}
3824 	rs->refs [rs->bottom++] = ptr;
3825 }
3826 
3827 static void
ref_stack_pop(RefStack * rs)3828 ref_stack_pop (RefStack *rs)
3829 {
3830 	if (rs == NULL || rs->bottom == 0)
3831 		return;
3832 
3833 	rs->bottom--;
3834 	rs->refs [rs->bottom] = NULL;
3835 }
3836 
3837 static gboolean
ref_stack_find(RefStack * rs,gpointer ptr)3838 ref_stack_find (RefStack *rs, gpointer ptr)
3839 {
3840 	gpointer *refs;
3841 
3842 	if (rs == NULL)
3843 		return FALSE;
3844 
3845 	for (refs = rs->refs; refs && *refs; refs++) {
3846 		if (*refs == ptr)
3847 			return TRUE;
3848 	}
3849 	return FALSE;
3850 }
3851 
3852 /*
3853  * mono_thread_push_appdomain_ref:
3854  *
3855  *   Register that the current thread may have references to objects in domain
3856  * @domain on its stack. Each call to this function should be paired with a
3857  * call to pop_appdomain_ref.
3858  */
3859 void
mono_thread_push_appdomain_ref(MonoDomain * domain)3860 mono_thread_push_appdomain_ref (MonoDomain *domain)
3861 {
3862 	MonoInternalThread *thread = mono_thread_internal_current ();
3863 
3864 	if (thread) {
3865 		/* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3866 		SPIN_LOCK (thread->lock_thread_id);
3867 		if (thread->appdomain_refs == NULL)
3868 			thread->appdomain_refs = ref_stack_new (16);
3869 		ref_stack_push ((RefStack *)thread->appdomain_refs, domain);
3870 		SPIN_UNLOCK (thread->lock_thread_id);
3871 	}
3872 }
3873 
3874 void
mono_thread_pop_appdomain_ref(void)3875 mono_thread_pop_appdomain_ref (void)
3876 {
3877 	MonoInternalThread *thread = mono_thread_internal_current ();
3878 
3879 	if (thread) {
3880 		/* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3881 		SPIN_LOCK (thread->lock_thread_id);
3882 		ref_stack_pop ((RefStack *)thread->appdomain_refs);
3883 		SPIN_UNLOCK (thread->lock_thread_id);
3884 	}
3885 }
3886 
3887 gboolean
mono_thread_internal_has_appdomain_ref(MonoInternalThread * thread,MonoDomain * domain)3888 mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
3889 {
3890 	gboolean res;
3891 	SPIN_LOCK (thread->lock_thread_id);
3892 	res = ref_stack_find ((RefStack *)thread->appdomain_refs, domain);
3893 	SPIN_UNLOCK (thread->lock_thread_id);
3894 	return res;
3895 }
3896 
3897 gboolean
mono_thread_has_appdomain_ref(MonoThread * thread,MonoDomain * domain)3898 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
3899 {
3900 	return mono_thread_internal_has_appdomain_ref (thread->internal_thread, domain);
3901 }
3902 
3903 typedef struct abort_appdomain_data {
3904 	struct wait_data wait;
3905 	MonoDomain *domain;
3906 } abort_appdomain_data;
3907 
3908 static void
collect_appdomain_thread(gpointer key,gpointer value,gpointer user_data)3909 collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
3910 {
3911 	MonoInternalThread *thread = (MonoInternalThread*)value;
3912 	abort_appdomain_data *data = (abort_appdomain_data*)user_data;
3913 	MonoDomain *domain = data->domain;
3914 
3915 	if (mono_thread_internal_has_appdomain_ref (thread, domain)) {
3916 		/* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3917 
3918 		if(data->wait.num<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
3919 			data->wait.handles [data->wait.num] = mono_threads_open_thread_handle (thread->handle);
3920 			data->wait.threads [data->wait.num] = thread;
3921 			data->wait.num++;
3922 		} else {
3923 			/* Just ignore the rest, we can't do anything with
3924 			 * them yet
3925 			 */
3926 		}
3927 	}
3928 }
3929 
3930 /*
3931  * mono_threads_abort_appdomain_threads:
3932  *
3933  *   Abort threads which has references to the given appdomain.
3934  */
3935 gboolean
mono_threads_abort_appdomain_threads(MonoDomain * domain,int timeout)3936 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
3937 {
3938 	abort_appdomain_data user_data;
3939 	gint64 start_time;
3940 	int orig_timeout = timeout;
3941 	int i;
3942 
3943 	THREAD_DEBUG (g_message ("%s: starting abort", __func__));
3944 
3945 	start_time = mono_msec_ticks ();
3946 	do {
3947 		mono_threads_lock ();
3948 
3949 		user_data.domain = domain;
3950 		user_data.wait.num = 0;
3951 		/* This shouldn't take any locks */
3952 		mono_g_hash_table_foreach (threads, collect_appdomain_thread, &user_data);
3953 		mono_threads_unlock ();
3954 
3955 		if (user_data.wait.num > 0) {
3956 			/* Abort the threads outside the threads lock */
3957 			for (i = 0; i < user_data.wait.num; ++i)
3958 				mono_thread_internal_abort (user_data.wait.threads [i], TRUE);
3959 
3960 			/*
3961 			 * We should wait for the threads either to abort, or to leave the
3962 			 * domain. We can't do the latter, so we wait with a timeout.
3963 			 */
3964 			wait_for_tids (&user_data.wait, 100, FALSE);
3965 		}
3966 
3967 		/* Update remaining time */
3968 		timeout -= mono_msec_ticks () - start_time;
3969 		start_time = mono_msec_ticks ();
3970 
3971 		if (orig_timeout != -1 && timeout < 0)
3972 			return FALSE;
3973 	}
3974 	while (user_data.wait.num > 0);
3975 
3976 	THREAD_DEBUG (g_message ("%s: abort done", __func__));
3977 
3978 	return TRUE;
3979 }
3980 
3981 void
mono_thread_self_abort(void)3982 mono_thread_self_abort (void)
3983 {
3984 	MonoError error;
3985 	self_abort_internal (&error);
3986 	mono_error_set_pending_exception (&error);
3987 }
3988 
3989 /*
3990  * mono_thread_get_undeniable_exception:
3991  *
3992  *   Return an exception which needs to be raised when leaving a catch clause.
3993  * This is used for undeniable exception propagation.
3994  */
3995 MonoException*
mono_thread_get_undeniable_exception(void)3996 mono_thread_get_undeniable_exception (void)
3997 {
3998 	MonoInternalThread *thread = mono_thread_internal_current ();
3999 
4000 	if (!(thread && thread->abort_exc && !is_running_protected_wrapper ()))
4001 		return NULL;
4002 
4003 	// We don't want to have our exception effect calls made by
4004 	// the catching block
4005 
4006 	if (!mono_get_eh_callbacks ()->mono_above_abort_threshold ())
4007 		return NULL;
4008 
4009 	/*
4010 	 * FIXME: Clear the abort exception and return an AppDomainUnloaded
4011 	 * exception if the thread no longer references a dying appdomain.
4012 	 */
4013 	thread->abort_exc->trace_ips = NULL;
4014 	thread->abort_exc->stack_trace = NULL;
4015 	return thread->abort_exc;
4016 }
4017 
4018 #if MONO_SMALL_CONFIG
4019 #define NUM_STATIC_DATA_IDX 4
4020 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
4021 	64, 256, 1024, 4096
4022 };
4023 #else
4024 #define NUM_STATIC_DATA_IDX 8
4025 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
4026 	1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
4027 };
4028 #endif
4029 
4030 static MonoBitSet *thread_reference_bitmaps [NUM_STATIC_DATA_IDX];
4031 static MonoBitSet *context_reference_bitmaps [NUM_STATIC_DATA_IDX];
4032 
4033 static void
mark_slots(void * addr,MonoBitSet ** bitmaps,MonoGCMarkFunc mark_func,void * gc_data)4034 mark_slots (void *addr, MonoBitSet **bitmaps, MonoGCMarkFunc mark_func, void *gc_data)
4035 {
4036 	gpointer *static_data = (gpointer *)addr;
4037 
4038 	for (int i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
4039 		void **ptr = (void **)static_data [i];
4040 
4041 		if (!ptr)
4042 			continue;
4043 
4044 		MONO_BITSET_FOREACH (bitmaps [i], idx, {
4045 			void **p = ptr + idx;
4046 
4047 			if (*p)
4048 				mark_func ((MonoObject**)p, gc_data);
4049 		});
4050 	}
4051 }
4052 
4053 static void
mark_tls_slots(void * addr,MonoGCMarkFunc mark_func,void * gc_data)4054 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
4055 {
4056 	mark_slots (addr, thread_reference_bitmaps, mark_func, gc_data);
4057 }
4058 
4059 static void
mark_ctx_slots(void * addr,MonoGCMarkFunc mark_func,void * gc_data)4060 mark_ctx_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
4061 {
4062 	mark_slots (addr, context_reference_bitmaps, mark_func, gc_data);
4063 }
4064 
4065 /*
4066  *  mono_alloc_static_data
4067  *
4068  *   Allocate memory blocks for storing threads or context static data
4069  */
4070 static void
mono_alloc_static_data(gpointer ** static_data_ptr,guint32 offset,gboolean threadlocal)4071 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
4072 {
4073 	guint idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4074 	int i;
4075 
4076 	gpointer* static_data = *static_data_ptr;
4077 	if (!static_data) {
4078 		static MonoGCDescriptor tls_desc = MONO_GC_DESCRIPTOR_NULL;
4079 		static MonoGCDescriptor ctx_desc = MONO_GC_DESCRIPTOR_NULL;
4080 
4081 		if (mono_gc_user_markers_supported ()) {
4082 			if (tls_desc == MONO_GC_DESCRIPTOR_NULL)
4083 				tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
4084 
4085 			if (ctx_desc == MONO_GC_DESCRIPTOR_NULL)
4086 				ctx_desc = mono_gc_make_root_descr_user (mark_ctx_slots);
4087 		}
4088 
4089 		static_data = (void **)mono_gc_alloc_fixed (static_data_size [0], threadlocal ? tls_desc : ctx_desc,
4090 			threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
4091 			threadlocal ? "managed thread-static variables" : "managed context-static variables");
4092 		*static_data_ptr = static_data;
4093 		static_data [0] = static_data;
4094 	}
4095 
4096 	for (i = 1; i <= idx; ++i) {
4097 		if (static_data [i])
4098 			continue;
4099 
4100 		if (mono_gc_user_markers_supported ())
4101 			static_data [i] = g_malloc0 (static_data_size [i]);
4102 		else
4103 			static_data [i] = mono_gc_alloc_fixed (static_data_size [i], MONO_GC_DESCRIPTOR_NULL,
4104 				threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
4105 				threadlocal ? "managed thread-static variables" : "managed context-static variables");
4106 	}
4107 }
4108 
4109 static void
mono_free_static_data(gpointer * static_data)4110 mono_free_static_data (gpointer* static_data)
4111 {
4112 	int i;
4113 	for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
4114 		gpointer p = static_data [i];
4115 		if (!p)
4116 			continue;
4117 		/*
4118 		 * At this point, the static data pointer array is still registered with the
4119 		 * GC, so must ensure that mark_tls_slots() will not encounter any invalid
4120 		 * data.  Freeing the individual arrays without first nulling their slots
4121 		 * would make it possible for mark_tls/ctx_slots() to encounter a pointer to
4122 		 * such an already freed array.  See bug #13813.
4123 		 */
4124 		static_data [i] = NULL;
4125 		mono_memory_write_barrier ();
4126 		if (mono_gc_user_markers_supported ())
4127 			g_free (p);
4128 		else
4129 			mono_gc_free_fixed (p);
4130 	}
4131 	mono_gc_free_fixed (static_data);
4132 }
4133 
4134 /*
4135  *  mono_init_static_data_info
4136  *
4137  *   Initializes static data counters
4138  */
mono_init_static_data_info(StaticDataInfo * static_data)4139 static void mono_init_static_data_info (StaticDataInfo *static_data)
4140 {
4141 	static_data->idx = 0;
4142 	static_data->offset = 0;
4143 	static_data->freelist = NULL;
4144 }
4145 
4146 /*
4147  *  mono_alloc_static_data_slot
4148  *
4149  *   Generates an offset for static data. static_data contains the counters
4150  *  used to generate it.
4151  */
4152 static guint32
mono_alloc_static_data_slot(StaticDataInfo * static_data,guint32 size,guint32 align)4153 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
4154 {
4155 	if (!static_data->idx && !static_data->offset) {
4156 		/*
4157 		 * we use the first chunk of the first allocation also as
4158 		 * an array for the rest of the data
4159 		 */
4160 		static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
4161 	}
4162 	static_data->offset += align - 1;
4163 	static_data->offset &= ~(align - 1);
4164 	if (static_data->offset + size >= static_data_size [static_data->idx]) {
4165 		static_data->idx ++;
4166 		g_assert (size <= static_data_size [static_data->idx]);
4167 		g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
4168 		static_data->offset = 0;
4169 	}
4170 	guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (static_data->idx, static_data->offset, 0);
4171 	static_data->offset += size;
4172 	return offset;
4173 }
4174 
4175 /*
4176  * LOCKING: requires that threads_mutex is held
4177  */
4178 static void
context_adjust_static_data(MonoAppContext * ctx)4179 context_adjust_static_data (MonoAppContext *ctx)
4180 {
4181 	if (context_static_info.offset || context_static_info.idx > 0) {
4182 		guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (context_static_info.idx, context_static_info.offset, 0);
4183 		mono_alloc_static_data (&ctx->static_data, offset, FALSE);
4184 		ctx->data->static_data = ctx->static_data;
4185 	}
4186 }
4187 
4188 /*
4189  * LOCKING: requires that threads_mutex is held
4190  */
4191 static void
alloc_thread_static_data_helper(gpointer key,gpointer value,gpointer user)4192 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4193 {
4194 	MonoInternalThread *thread = (MonoInternalThread *)value;
4195 	guint32 offset = GPOINTER_TO_UINT (user);
4196 
4197 	mono_alloc_static_data (&(thread->static_data), offset, TRUE);
4198 }
4199 
4200 /*
4201  * LOCKING: requires that threads_mutex is held
4202  */
4203 static void
alloc_context_static_data_helper(gpointer key,gpointer value,gpointer user)4204 alloc_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4205 {
4206 	MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4207 
4208 	if (!ctx)
4209 		return;
4210 
4211 	guint32 offset = GPOINTER_TO_UINT (user);
4212 	mono_alloc_static_data (&ctx->static_data, offset, FALSE);
4213 	ctx->data->static_data = ctx->static_data;
4214 }
4215 
4216 static StaticDataFreeList*
search_slot_in_freelist(StaticDataInfo * static_data,guint32 size,guint32 align)4217 search_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
4218 {
4219 	StaticDataFreeList* prev = NULL;
4220 	StaticDataFreeList* tmp = static_data->freelist;
4221 	while (tmp) {
4222 		if (tmp->size == size) {
4223 			if (prev)
4224 				prev->next = tmp->next;
4225 			else
4226 				static_data->freelist = tmp->next;
4227 			return tmp;
4228 		}
4229 		prev = tmp;
4230 		tmp = tmp->next;
4231 	}
4232 	return NULL;
4233 }
4234 
4235 #if SIZEOF_VOID_P == 4
4236 #define ONE_P 1
4237 #else
4238 #define ONE_P 1ll
4239 #endif
4240 
4241 static void
update_reference_bitmap(MonoBitSet ** sets,guint32 offset,uintptr_t * bitmap,int numbits)4242 update_reference_bitmap (MonoBitSet **sets, guint32 offset, uintptr_t *bitmap, int numbits)
4243 {
4244 	int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4245 	if (!sets [idx])
4246 		sets [idx] = mono_bitset_new (static_data_size [idx] / sizeof (uintptr_t), 0);
4247 	MonoBitSet *rb = sets [idx];
4248 	offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
4249 	offset /= sizeof (uintptr_t);
4250 	/* offset is now the bitmap offset */
4251 	for (int i = 0; i < numbits; ++i) {
4252 		if (bitmap [i / sizeof (uintptr_t)] & (ONE_P << (i & (sizeof (uintptr_t) * 8 -1))))
4253 			mono_bitset_set_fast (rb, offset + i);
4254 	}
4255 }
4256 
4257 static void
clear_reference_bitmap(MonoBitSet ** sets,guint32 offset,guint32 size)4258 clear_reference_bitmap (MonoBitSet **sets, guint32 offset, guint32 size)
4259 {
4260 	int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4261 	MonoBitSet *rb = sets [idx];
4262 	offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
4263 	offset /= sizeof (uintptr_t);
4264 	/* offset is now the bitmap offset */
4265 	for (int i = 0; i < size / sizeof (uintptr_t); i++)
4266 		mono_bitset_clear_fast (rb, offset + i);
4267 }
4268 
4269 guint32
mono_alloc_special_static_data(guint32 static_type,guint32 size,guint32 align,uintptr_t * bitmap,int numbits)4270 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
4271 {
4272 	g_assert (static_type == SPECIAL_STATIC_THREAD || static_type == SPECIAL_STATIC_CONTEXT);
4273 
4274 	StaticDataInfo *info;
4275 	MonoBitSet **sets;
4276 
4277 	if (static_type == SPECIAL_STATIC_THREAD) {
4278 		info = &thread_static_info;
4279 		sets = thread_reference_bitmaps;
4280 	} else {
4281 		info = &context_static_info;
4282 		sets = context_reference_bitmaps;
4283 	}
4284 
4285 	mono_threads_lock ();
4286 
4287 	StaticDataFreeList *item = search_slot_in_freelist (info, size, align);
4288 	guint32 offset;
4289 
4290 	if (item) {
4291 		offset = item->offset;
4292 		g_free (item);
4293 	} else {
4294 		offset = mono_alloc_static_data_slot (info, size, align);
4295 	}
4296 
4297 	update_reference_bitmap (sets, offset, bitmap, numbits);
4298 
4299 	if (static_type == SPECIAL_STATIC_THREAD) {
4300 		/* This can be called during startup */
4301 		if (threads != NULL)
4302 			mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
4303 	} else {
4304 		if (contexts != NULL)
4305 			g_hash_table_foreach (contexts, alloc_context_static_data_helper, GUINT_TO_POINTER (offset));
4306 
4307 		ACCESS_SPECIAL_STATIC_OFFSET (offset, type) = SPECIAL_STATIC_OFFSET_TYPE_CONTEXT;
4308 	}
4309 
4310 	mono_threads_unlock ();
4311 
4312 	return offset;
4313 }
4314 
4315 gpointer
mono_get_special_static_data_for_thread(MonoInternalThread * thread,guint32 offset)4316 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
4317 {
4318 	guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4319 
4320 	if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4321 		return get_thread_static_data (thread, offset);
4322 	} else {
4323 		return get_context_static_data (thread->current_appcontext, offset);
4324 	}
4325 }
4326 
4327 gpointer
mono_get_special_static_data(guint32 offset)4328 mono_get_special_static_data (guint32 offset)
4329 {
4330 	return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
4331 }
4332 
4333 typedef struct {
4334 	guint32 offset;
4335 	guint32 size;
4336 } OffsetSize;
4337 
4338 /*
4339  * LOCKING: requires that threads_mutex is held
4340  */
4341 static void
free_thread_static_data_helper(gpointer key,gpointer value,gpointer user)4342 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4343 {
4344 	MonoInternalThread *thread = (MonoInternalThread *)value;
4345 	OffsetSize *data = (OffsetSize *)user;
4346 	int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4347 	int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4348 	char *ptr;
4349 
4350 	if (!thread->static_data || !thread->static_data [idx])
4351 		return;
4352 	ptr = ((char*) thread->static_data [idx]) + off;
4353 	mono_gc_bzero_atomic (ptr, data->size);
4354 }
4355 
4356 /*
4357  * LOCKING: requires that threads_mutex is held
4358  */
4359 static void
free_context_static_data_helper(gpointer key,gpointer value,gpointer user)4360 free_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4361 {
4362 	MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4363 
4364 	if (!ctx)
4365 		return;
4366 
4367 	OffsetSize *data = (OffsetSize *)user;
4368 	int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4369 	int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4370 	char *ptr;
4371 
4372 	if (!ctx->static_data || !ctx->static_data [idx])
4373 		return;
4374 
4375 	ptr = ((char*) ctx->static_data [idx]) + off;
4376 	mono_gc_bzero_atomic (ptr, data->size);
4377 }
4378 
4379 static void
do_free_special_slot(guint32 offset,guint32 size)4380 do_free_special_slot (guint32 offset, guint32 size)
4381 {
4382 	guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4383 	MonoBitSet **sets;
4384 	StaticDataInfo *info;
4385 
4386 	if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4387 		info = &thread_static_info;
4388 		sets = thread_reference_bitmaps;
4389 	} else {
4390 		info = &context_static_info;
4391 		sets = context_reference_bitmaps;
4392 	}
4393 
4394 	guint32 data_offset = offset;
4395 	ACCESS_SPECIAL_STATIC_OFFSET (data_offset, type) = 0;
4396 	OffsetSize data = { data_offset, size };
4397 
4398 	clear_reference_bitmap (sets, data.offset, data.size);
4399 
4400 	if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4401 		if (threads != NULL)
4402 			mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
4403 	} else {
4404 		if (contexts != NULL)
4405 			g_hash_table_foreach (contexts, free_context_static_data_helper, &data);
4406 	}
4407 
4408 	if (!mono_runtime_is_shutting_down ()) {
4409 		StaticDataFreeList *item = g_new0 (StaticDataFreeList, 1);
4410 
4411 		item->offset = offset;
4412 		item->size = size;
4413 
4414 		item->next = info->freelist;
4415 		info->freelist = item;
4416 	}
4417 }
4418 
4419 static void
do_free_special(gpointer key,gpointer value,gpointer data)4420 do_free_special (gpointer key, gpointer value, gpointer data)
4421 {
4422 	MonoClassField *field = (MonoClassField *)key;
4423 	guint32 offset = GPOINTER_TO_UINT (value);
4424 	gint32 align;
4425 	guint32 size;
4426 	size = mono_type_size (field->type, &align);
4427 	do_free_special_slot (offset, size);
4428 }
4429 
4430 void
mono_alloc_special_static_data_free(GHashTable * special_static_fields)4431 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
4432 {
4433 	mono_threads_lock ();
4434 
4435 	g_hash_table_foreach (special_static_fields, do_free_special, NULL);
4436 
4437 	mono_threads_unlock ();
4438 }
4439 
4440 #ifdef HOST_WIN32
dummy_apc(ULONG_PTR param)4441 static void CALLBACK dummy_apc (ULONG_PTR param)
4442 {
4443 }
4444 #endif
4445 
4446 /*
4447  * mono_thread_execute_interruption
4448  *
4449  * Performs the operation that the requested thread state requires (abort,
4450  * suspend or stop)
4451  */
4452 static MonoException*
mono_thread_execute_interruption(void)4453 mono_thread_execute_interruption (void)
4454 {
4455 	MonoInternalThread *thread = mono_thread_internal_current ();
4456 	MonoThread *sys_thread = mono_thread_current ();
4457 
4458 	LOCK_THREAD (thread);
4459 
4460 	/* MonoThread::interruption_requested can only be changed with atomics */
4461 	if (!mono_thread_clear_interruption_requested (thread)) {
4462 		UNLOCK_THREAD (thread);
4463 		return NULL;
4464 	}
4465 
4466 	/* this will consume pending APC calls */
4467 #ifdef HOST_WIN32
4468 	MONO_ENTER_GC_SAFE;
4469 	mono_win32_wait_for_single_object_ex (GetCurrentThread (), 0, TRUE);
4470 	MONO_EXIT_GC_SAFE;
4471 #endif
4472 
4473 	/* Clear the interrupted flag of the thread so it can wait again */
4474 	mono_thread_info_clear_self_interrupt ();
4475 
4476 	/* If there's a pending exception and an AbortRequested, the pending exception takes precedence */
4477 	if (sys_thread->pending_exception) {
4478 		MonoException *exc;
4479 
4480 		exc = sys_thread->pending_exception;
4481 		sys_thread->pending_exception = NULL;
4482 
4483 		UNLOCK_THREAD (thread);
4484 		return exc;
4485 	} else if (thread->state & (ThreadState_AbortRequested)) {
4486 		UNLOCK_THREAD (thread);
4487 		g_assert (sys_thread->pending_exception == NULL);
4488 		if (thread->abort_exc == NULL) {
4489 			/*
4490 			 * This might be racy, but it has to be called outside the lock
4491 			 * since it calls managed code.
4492 			 */
4493 			MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4494 		}
4495 		return thread->abort_exc;
4496 	} else if (thread->state & (ThreadState_SuspendRequested)) {
4497 		/* calls UNLOCK_THREAD (thread) */
4498 		self_suspend_internal ();
4499 		return NULL;
4500 	} else if (thread->thread_interrupt_requested) {
4501 
4502 		thread->thread_interrupt_requested = FALSE;
4503 		UNLOCK_THREAD (thread);
4504 
4505 		return(mono_get_exception_thread_interrupted ());
4506 	}
4507 
4508 	UNLOCK_THREAD (thread);
4509 
4510 	return NULL;
4511 }
4512 
4513 /*
4514  * mono_thread_request_interruption
4515  *
4516  * A signal handler can call this method to request the interruption of a
4517  * thread. The result of the interruption will depend on the current state of
4518  * the thread. If the result is an exception that needs to be throw, it is
4519  * provided as return value.
4520  */
4521 MonoException*
mono_thread_request_interruption(gboolean running_managed)4522 mono_thread_request_interruption (gboolean running_managed)
4523 {
4524 	MonoInternalThread *thread = mono_thread_internal_current ();
4525 
4526 	/* The thread may already be stopping */
4527 	if (thread == NULL)
4528 		return NULL;
4529 
4530 	if (!mono_thread_set_interruption_requested (thread))
4531 		return NULL;
4532 
4533 	if (!running_managed || is_running_protected_wrapper ()) {
4534 		/* Can't stop while in unmanaged code. Increase the global interruption
4535 		   request count. When exiting the unmanaged method the count will be
4536 		   checked and the thread will be interrupted. */
4537 
4538 		/* this will awake the thread if it is in WaitForSingleObject
4539 		   or similar */
4540 #ifdef HOST_WIN32
4541 		mono_win32_interrupt_wait (thread->thread_info, thread->native_handle, (DWORD)thread->tid);
4542 #else
4543 		mono_thread_info_self_interrupt ();
4544 #endif
4545 		return NULL;
4546 	}
4547 	else {
4548 		return mono_thread_execute_interruption ();
4549 	}
4550 }
4551 
4552 /*This function should be called by a thread after it has exited all of
4553  * its handle blocks at interruption time.*/
4554 MonoException*
mono_thread_resume_interruption(gboolean exec)4555 mono_thread_resume_interruption (gboolean exec)
4556 {
4557 	MonoInternalThread *thread = mono_thread_internal_current ();
4558 	gboolean still_aborting;
4559 
4560 	/* The thread may already be stopping */
4561 	if (thread == NULL)
4562 		return NULL;
4563 
4564 	LOCK_THREAD (thread);
4565 	still_aborting = (thread->state & (ThreadState_AbortRequested)) != 0;
4566 	UNLOCK_THREAD (thread);
4567 
4568 	/*This can happen if the protected block called Thread::ResetAbort*/
4569 	if (!still_aborting)
4570 		return NULL;
4571 
4572 	if (!mono_thread_set_interruption_requested (thread))
4573 		return NULL;
4574 
4575 	mono_thread_info_self_interrupt ();
4576 
4577 	if (exec)
4578 		return mono_thread_execute_interruption ();
4579 	else
4580 		return NULL;
4581 }
4582 
mono_thread_interruption_requested()4583 gboolean mono_thread_interruption_requested ()
4584 {
4585 	if (thread_interruption_requested) {
4586 		MonoInternalThread *thread = mono_thread_internal_current ();
4587 		/* The thread may already be stopping */
4588 		if (thread != NULL)
4589 			return mono_thread_get_interruption_requested (thread);
4590 	}
4591 	return FALSE;
4592 }
4593 
4594 static MonoException*
mono_thread_interruption_checkpoint_request(gboolean bypass_abort_protection)4595 mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4596 {
4597 	MonoInternalThread *thread = mono_thread_internal_current ();
4598 
4599 	/* The thread may already be stopping */
4600 	if (!thread)
4601 		return NULL;
4602 	if (!mono_thread_get_interruption_requested (thread))
4603 		return NULL;
4604 	if (!bypass_abort_protection && !mono_thread_current ()->pending_exception && is_running_protected_wrapper ())
4605 		return NULL;
4606 
4607 	return mono_thread_execute_interruption ();
4608 }
4609 
4610 /*
4611  * Performs the interruption of the current thread, if one has been requested,
4612  * and the thread is not running a protected wrapper.
4613  * Return the exception which needs to be thrown, if any.
4614  */
4615 MonoException*
mono_thread_interruption_checkpoint(void)4616 mono_thread_interruption_checkpoint (void)
4617 {
4618 	return mono_thread_interruption_checkpoint_request (FALSE);
4619 }
4620 
4621 /*
4622  * Performs the interruption of the current thread, if one has been requested.
4623  * Return the exception which needs to be thrown, if any.
4624  */
4625 MonoException*
mono_thread_force_interruption_checkpoint_noraise(void)4626 mono_thread_force_interruption_checkpoint_noraise (void)
4627 {
4628 	return mono_thread_interruption_checkpoint_request (TRUE);
4629 }
4630 
4631 /*
4632  * mono_set_pending_exception:
4633  *
4634  *   Set the pending exception of the current thread to EXC.
4635  * The exception will be thrown when execution returns to managed code.
4636  */
4637 void
mono_set_pending_exception(MonoException * exc)4638 mono_set_pending_exception (MonoException *exc)
4639 {
4640 	MonoThread *thread = mono_thread_current ();
4641 
4642 	/* The thread may already be stopping */
4643 	if (thread == NULL)
4644 		return;
4645 
4646 	MONO_OBJECT_SETREF (thread, pending_exception, exc);
4647 
4648     mono_thread_request_interruption (FALSE);
4649 }
4650 
4651 /**
4652  * mono_thread_interruption_request_flag:
4653  *
4654  * Returns the address of a flag that will be non-zero if an interruption has
4655  * been requested for a thread. The thread to interrupt may not be the current
4656  * thread, so an additional call to mono_thread_interruption_requested() or
4657  * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4658  * zero.
4659  */
mono_thread_interruption_request_flag()4660 gint32* mono_thread_interruption_request_flag ()
4661 {
4662 	return &thread_interruption_requested;
4663 }
4664 
4665 void
mono_thread_init_apartment_state(void)4666 mono_thread_init_apartment_state (void)
4667 {
4668 #ifdef HOST_WIN32
4669 	MonoInternalThread* thread = mono_thread_internal_current ();
4670 
4671 	/* Positive return value indicates success, either
4672 	 * S_OK if this is first CoInitialize call, or
4673 	 * S_FALSE if CoInitialize already called, but with same
4674 	 * threading model. A negative value indicates failure,
4675 	 * probably due to trying to change the threading model.
4676 	 */
4677 	if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA)
4678 			? COINIT_APARTMENTTHREADED
4679 			: COINIT_MULTITHREADED) < 0) {
4680 		thread->apartment_state = ThreadApartmentState_Unknown;
4681 	}
4682 #endif
4683 }
4684 
4685 void
mono_thread_cleanup_apartment_state(void)4686 mono_thread_cleanup_apartment_state (void)
4687 {
4688 #ifdef HOST_WIN32
4689 	MonoInternalThread* thread = mono_thread_internal_current ();
4690 
4691 	if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4692 		CoUninitialize ();
4693 	}
4694 #endif
4695 }
4696 
4697 void
mono_thread_set_state(MonoInternalThread * thread,MonoThreadState state)4698 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4699 {
4700 	LOCK_THREAD (thread);
4701 	thread->state |= state;
4702 	UNLOCK_THREAD (thread);
4703 }
4704 
4705 /**
4706  * mono_thread_test_and_set_state:
4707  * Test if current state of \p thread include \p test. If it does not, OR \p set into the state.
4708  * \returns TRUE if \p set was OR'd in.
4709  */
4710 gboolean
mono_thread_test_and_set_state(MonoInternalThread * thread,MonoThreadState test,MonoThreadState set)4711 mono_thread_test_and_set_state (MonoInternalThread *thread, MonoThreadState test, MonoThreadState set)
4712 {
4713 	LOCK_THREAD (thread);
4714 
4715 	if ((thread->state & test) != 0) {
4716 		UNLOCK_THREAD (thread);
4717 		return FALSE;
4718 	}
4719 
4720 	thread->state |= set;
4721 	UNLOCK_THREAD (thread);
4722 
4723 	return TRUE;
4724 }
4725 
4726 void
mono_thread_clr_state(MonoInternalThread * thread,MonoThreadState state)4727 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4728 {
4729 	LOCK_THREAD (thread);
4730 	thread->state &= ~state;
4731 	UNLOCK_THREAD (thread);
4732 }
4733 
4734 gboolean
mono_thread_test_state(MonoInternalThread * thread,MonoThreadState test)4735 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4736 {
4737 	gboolean ret = FALSE;
4738 
4739 	LOCK_THREAD (thread);
4740 
4741 	if ((thread->state & test) != 0) {
4742 		ret = TRUE;
4743 	}
4744 
4745 	UNLOCK_THREAD (thread);
4746 
4747 	return ret;
4748 }
4749 
4750 static void
self_interrupt_thread(void * _unused)4751 self_interrupt_thread (void *_unused)
4752 {
4753 	MonoException *exc;
4754 	MonoThreadInfo *info;
4755 
4756 	exc = mono_thread_execute_interruption ();
4757 	if (!exc) {
4758 		if (mono_threads_is_coop_enabled ()) {
4759 			/* We can return from an async call in coop, as
4760 			 * it's simply called when exiting the safepoint */
4761 			return;
4762 		}
4763 
4764 		g_error ("%s: we can't resume from an async call", __func__);
4765 	}
4766 
4767 	info = mono_thread_info_current ();
4768 
4769 	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. */
4770 }
4771 
4772 static gboolean
mono_jit_info_match(MonoJitInfo * ji,gpointer ip)4773 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4774 {
4775 	if (!ji)
4776 		return FALSE;
4777 	return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4778 }
4779 
4780 static gboolean
last_managed(MonoStackFrameInfo * frame,MonoContext * ctx,gpointer data)4781 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4782 {
4783 	MonoJitInfo **dest = (MonoJitInfo **)data;
4784 	*dest = frame->ji;
4785 	return TRUE;
4786 }
4787 
4788 static MonoJitInfo*
mono_thread_info_get_last_managed(MonoThreadInfo * info)4789 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4790 {
4791 	MonoJitInfo *ji = NULL;
4792 	if (!info)
4793 		return NULL;
4794 
4795 	/*
4796 	 * The suspended thread might be holding runtime locks. Make sure we don't try taking
4797 	 * any runtime locks while unwinding. In coop case we shouldn't safepoint in regions
4798 	 * where we hold runtime locks.
4799 	 */
4800 	if (!mono_threads_is_coop_enabled ())
4801 		mono_thread_info_set_is_async_context (TRUE);
4802 	mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, &ji);
4803 	if (!mono_threads_is_coop_enabled ())
4804 		mono_thread_info_set_is_async_context (FALSE);
4805 	return ji;
4806 }
4807 
4808 typedef struct {
4809 	MonoInternalThread *thread;
4810 	gboolean install_async_abort;
4811 	MonoThreadInfoInterruptToken *interrupt_token;
4812 } AbortThreadData;
4813 
4814 static SuspendThreadResult
async_abort_critical(MonoThreadInfo * info,gpointer ud)4815 async_abort_critical (MonoThreadInfo *info, gpointer ud)
4816 {
4817 	AbortThreadData *data = (AbortThreadData *)ud;
4818 	MonoInternalThread *thread = data->thread;
4819 	MonoJitInfo *ji = NULL;
4820 	gboolean protected_wrapper;
4821 	gboolean running_managed;
4822 
4823 	if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info)))
4824 		return MonoResumeThread;
4825 
4826 	/*someone is already interrupting it*/
4827 	if (!mono_thread_set_interruption_requested (thread))
4828 		return MonoResumeThread;
4829 
4830 	ji = mono_thread_info_get_last_managed (info);
4831 	protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4832 	running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4833 
4834 	if (!protected_wrapper && running_managed) {
4835 		/*We are in managed code*/
4836 		/*Set the thread to call */
4837 		if (data->install_async_abort)
4838 			mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4839 		return MonoResumeThread;
4840 	} else {
4841 		/*
4842 		 * This will cause waits to be broken.
4843 		 * It will also prevent the thread from entering a wait, so if the thread returns
4844 		 * from the wait before it receives the abort signal, it will just spin in the wait
4845 		 * functions in the io-layer until the signal handler calls QueueUserAPC which will
4846 		 * make it return.
4847 		 */
4848 		data->interrupt_token = mono_thread_info_prepare_interrupt (info);
4849 
4850 		return MonoResumeThread;
4851 	}
4852 }
4853 
4854 static void
async_abort_internal(MonoInternalThread * thread,gboolean install_async_abort)4855 async_abort_internal (MonoInternalThread *thread, gboolean install_async_abort)
4856 {
4857 	AbortThreadData data;
4858 
4859 	g_assert (thread != mono_thread_internal_current ());
4860 
4861 	data.thread = thread;
4862 	data.install_async_abort = install_async_abort;
4863 	data.interrupt_token = NULL;
4864 
4865 	mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), TRUE, async_abort_critical, &data);
4866 	if (data.interrupt_token)
4867 		mono_thread_info_finish_interrupt (data.interrupt_token);
4868 	/*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4869 }
4870 
4871 static void
self_abort_internal(MonoError * error)4872 self_abort_internal (MonoError *error)
4873 {
4874 	MonoException *exc;
4875 
4876 	error_init (error);
4877 
4878 	/* FIXME this is insanely broken, it doesn't cause interruption to happen synchronously
4879 	 * since passing FALSE to mono_thread_request_interruption makes sure it returns NULL */
4880 
4881 	/*
4882 	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.
4883 	*/
4884 	exc = mono_thread_request_interruption (TRUE);
4885 	if (exc)
4886 		mono_error_set_exception_instance (error, exc);
4887 	else
4888 		mono_thread_info_self_interrupt ();
4889 }
4890 
4891 typedef struct {
4892 	MonoInternalThread *thread;
4893 	gboolean interrupt;
4894 	MonoThreadInfoInterruptToken *interrupt_token;
4895 } SuspendThreadData;
4896 
4897 static SuspendThreadResult
async_suspend_critical(MonoThreadInfo * info,gpointer ud)4898 async_suspend_critical (MonoThreadInfo *info, gpointer ud)
4899 {
4900 	SuspendThreadData *data = (SuspendThreadData *)ud;
4901 	MonoInternalThread *thread = data->thread;
4902 	MonoJitInfo *ji = NULL;
4903 	gboolean protected_wrapper;
4904 	gboolean running_managed;
4905 
4906 	ji = mono_thread_info_get_last_managed (info);
4907 	protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4908 	running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4909 
4910 	if (running_managed && !protected_wrapper) {
4911 		if (mono_threads_is_coop_enabled ()) {
4912 			mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4913 			return MonoResumeThread;
4914 		} else {
4915 			thread->state &= ~ThreadState_SuspendRequested;
4916 			thread->state |= ThreadState_Suspended;
4917 			return KeepSuspended;
4918 		}
4919 	} else {
4920 		mono_thread_set_interruption_requested (thread);
4921 		if (data->interrupt)
4922 			data->interrupt_token = mono_thread_info_prepare_interrupt ((MonoThreadInfo *)thread->thread_info);
4923 
4924 		return MonoResumeThread;
4925 	}
4926 }
4927 
4928 /* LOCKING: called with @thread synch_cs held, and releases it */
4929 static void
async_suspend_internal(MonoInternalThread * thread,gboolean interrupt)4930 async_suspend_internal (MonoInternalThread *thread, gboolean interrupt)
4931 {
4932 	SuspendThreadData data;
4933 
4934 	g_assert (thread != mono_thread_internal_current ());
4935 
4936 	// MOSTLY_ASYNC_SAFE_PRINTF ("ASYNC SUSPEND thread %p\n", thread_get_tid (thread));
4937 
4938 	thread->self_suspended = FALSE;
4939 
4940 	data.thread = thread;
4941 	data.interrupt = interrupt;
4942 	data.interrupt_token = NULL;
4943 
4944 	mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), interrupt, async_suspend_critical, &data);
4945 	if (data.interrupt_token)
4946 		mono_thread_info_finish_interrupt (data.interrupt_token);
4947 
4948 	UNLOCK_THREAD (thread);
4949 }
4950 
4951 /* LOCKING: called with @thread synch_cs held, and releases it */
4952 static void
self_suspend_internal(void)4953 self_suspend_internal (void)
4954 {
4955 	MonoInternalThread *thread;
4956 	MonoOSEvent *event;
4957 	MonoOSEventWaitRet res;
4958 
4959 	thread = mono_thread_internal_current ();
4960 
4961 	// MOSTLY_ASYNC_SAFE_PRINTF ("SELF SUSPEND thread %p\n", thread_get_tid (thread));
4962 
4963 	thread->self_suspended = TRUE;
4964 
4965 	thread->state &= ~ThreadState_SuspendRequested;
4966 	thread->state |= ThreadState_Suspended;
4967 
4968 	UNLOCK_THREAD (thread);
4969 
4970 	event = thread->suspended;
4971 
4972 	MONO_ENTER_GC_SAFE;
4973 	res = mono_os_event_wait_one (event, MONO_INFINITE_WAIT, TRUE);
4974 	g_assert (res == MONO_OS_EVENT_WAIT_RET_SUCCESS_0 || res == MONO_OS_EVENT_WAIT_RET_ALERTED);
4975 	MONO_EXIT_GC_SAFE;
4976 }
4977 
4978 static void
suspend_for_shutdown_async_call(gpointer unused)4979 suspend_for_shutdown_async_call (gpointer unused)
4980 {
4981 	for (;;)
4982 		mono_thread_info_yield ();
4983 }
4984 
4985 static SuspendThreadResult
suspend_for_shutdown_critical(MonoThreadInfo * info,gpointer unused)4986 suspend_for_shutdown_critical (MonoThreadInfo *info, gpointer unused)
4987 {
4988 	mono_thread_info_setup_async_call (info, suspend_for_shutdown_async_call, NULL);
4989 	return MonoResumeThread;
4990 }
4991 
4992 void
mono_thread_internal_suspend_for_shutdown(MonoInternalThread * thread)4993 mono_thread_internal_suspend_for_shutdown (MonoInternalThread *thread)
4994 {
4995 	g_assert (thread != mono_thread_internal_current ());
4996 
4997 	mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, suspend_for_shutdown_critical, NULL);
4998 }
4999 
5000 /**
5001  * mono_thread_is_foreign:
5002  * \param thread the thread to query
5003  *
5004  * This function allows one to determine if a thread was created by the mono runtime and has
5005  * a well defined lifecycle or it's a foreign one, created by the native environment.
5006  *
5007  * \returns TRUE if \p thread was not created by the runtime.
5008  */
5009 mono_bool
mono_thread_is_foreign(MonoThread * thread)5010 mono_thread_is_foreign (MonoThread *thread)
5011 {
5012 	MonoThreadInfo *info = (MonoThreadInfo *)thread->internal_thread->thread_info;
5013 	return info->runtime_thread == FALSE;
5014 }
5015 
5016 #ifndef HOST_WIN32
5017 static void
threads_native_thread_join_lock(gpointer tid,gpointer value)5018 threads_native_thread_join_lock (gpointer tid, gpointer value)
5019 {
5020 	pthread_t thread = (pthread_t)tid;
5021 	if (thread != pthread_self ()) {
5022 		MONO_ENTER_GC_SAFE;
5023 		/* This shouldn't block */
5024 		mono_threads_join_lock ();
5025 		mono_native_thread_join (thread);
5026 		mono_threads_join_unlock ();
5027 		MONO_EXIT_GC_SAFE;
5028 	}
5029 }
5030 static void
threads_native_thread_join_nolock(gpointer tid,gpointer value)5031 threads_native_thread_join_nolock (gpointer tid, gpointer value)
5032 {
5033 	pthread_t thread = (pthread_t)tid;
5034 	MONO_ENTER_GC_SAFE;
5035 	mono_native_thread_join (thread);
5036 	MONO_EXIT_GC_SAFE;
5037 }
5038 
5039 static void
threads_add_joinable_thread_nolock(gpointer tid)5040 threads_add_joinable_thread_nolock (gpointer tid)
5041 {
5042 	g_hash_table_insert (joinable_threads, tid, tid);
5043 }
5044 #else
5045 static void
threads_native_thread_join_lock(gpointer tid,gpointer value)5046 threads_native_thread_join_lock (gpointer tid, gpointer value)
5047 {
5048 	MonoNativeThreadId thread_id = (MonoNativeThreadId)(guint64)tid;
5049 	HANDLE thread_handle = (HANDLE)value;
5050 	if (thread_id != GetCurrentThreadId () && thread_handle != NULL && thread_handle != INVALID_HANDLE_VALUE) {
5051 		MONO_ENTER_GC_SAFE;
5052 		/* This shouldn't block */
5053 		mono_threads_join_lock ();
5054 		mono_native_thread_join_handle (thread_handle, TRUE);
5055 		mono_threads_join_unlock ();
5056 		MONO_EXIT_GC_SAFE;
5057 	}
5058 }
5059 
5060 static void
threads_native_thread_join_nolock(gpointer tid,gpointer value)5061 threads_native_thread_join_nolock (gpointer tid, gpointer value)
5062 {
5063 	HANDLE thread_handle = (HANDLE)value;
5064 	MONO_ENTER_GC_SAFE;
5065 	mono_native_thread_join_handle (thread_handle, TRUE);
5066 	MONO_EXIT_GC_SAFE;
5067 }
5068 
5069 static void
threads_add_joinable_thread_nolock(gpointer tid)5070 threads_add_joinable_thread_nolock (gpointer tid)
5071 {
5072 	g_hash_table_insert (joinable_threads, tid, (gpointer)OpenThread (SYNCHRONIZE, TRUE, (MonoNativeThreadId)(guint64)tid));
5073 }
5074 #endif
5075 
5076 void
mono_threads_add_joinable_runtime_thread(gpointer thread_info)5077 mono_threads_add_joinable_runtime_thread (gpointer thread_info)
5078 {
5079 	g_assert (thread_info);
5080 	MonoThreadInfo *mono_thread_info = (MonoThreadInfo*)thread_info;
5081 
5082 	if (mono_thread_info->runtime_thread) {
5083 		if (mono_atomic_cas_i32 (&mono_thread_info->thread_pending_native_join, TRUE, FALSE) == FALSE)
5084 			mono_threads_add_joinable_thread ((gpointer)(MONO_UINT_TO_NATIVE_THREAD_ID (mono_thread_info_get_tid (mono_thread_info))));
5085 	}
5086 }
5087 
5088 /*
5089  * mono_add_joinable_thread:
5090  *
5091  *   Add TID to the list of joinable threads.
5092  * LOCKING: Acquires the threads lock.
5093  */
5094 void
mono_threads_add_joinable_thread(gpointer tid)5095 mono_threads_add_joinable_thread (gpointer tid)
5096 {
5097 	/*
5098 	 * We cannot detach from threads because it causes problems like
5099 	 * 2fd16f60/r114307. So we collect them and join them when
5100 	 * we have time (in the finalizer thread).
5101 	 */
5102 	joinable_threads_lock ();
5103 	if (!joinable_threads)
5104 		joinable_threads = g_hash_table_new (NULL, NULL);
5105 
5106 	gpointer orig_key;
5107 	gpointer value;
5108 	if (!g_hash_table_lookup_extended (joinable_threads, tid, &orig_key, &value)) {
5109 		threads_add_joinable_thread_nolock (tid);
5110 		UnlockedIncrement (&joinable_thread_count);
5111 	}
5112 	joinable_threads_unlock ();
5113 
5114 	mono_gc_finalize_notify ();
5115 }
5116 
5117 /*
5118  * mono_threads_join_threads:
5119  *
5120  *   Join all joinable threads. This is called from the finalizer thread.
5121  * LOCKING: Acquires the threads lock.
5122  */
5123 void
mono_threads_join_threads(void)5124 mono_threads_join_threads (void)
5125 {
5126 	GHashTableIter iter;
5127 	gpointer key;
5128 	gpointer value;
5129 	gboolean found;
5130 
5131 	/* Fastpath */
5132 	if (!UnlockedRead (&joinable_thread_count))
5133 		return;
5134 
5135 	while (TRUE) {
5136 		joinable_threads_lock ();
5137 		found = FALSE;
5138 		if (g_hash_table_size (joinable_threads)) {
5139 			g_hash_table_iter_init (&iter, joinable_threads);
5140 			g_hash_table_iter_next (&iter, &key, (void**)&value);
5141 			g_hash_table_remove (joinable_threads, key);
5142 			UnlockedDecrement (&joinable_thread_count);
5143 			found = TRUE;
5144 		}
5145 		joinable_threads_unlock ();
5146 		if (found)
5147 			threads_native_thread_join_lock (key, value);
5148 		else
5149 			break;
5150 	}
5151 }
5152 
5153 /*
5154  * mono_thread_join:
5155  *
5156  *   Wait for thread TID to exit.
5157  * LOCKING: Acquires the threads lock.
5158  */
5159 void
mono_thread_join(gpointer tid)5160 mono_thread_join (gpointer tid)
5161 {
5162 	gboolean found = FALSE;
5163 	gpointer orig_key;
5164 	gpointer value;
5165 
5166 	joinable_threads_lock ();
5167 	if (!joinable_threads)
5168 		joinable_threads = g_hash_table_new (NULL, NULL);
5169 
5170 	if (g_hash_table_lookup_extended (joinable_threads, tid, &orig_key, &value)) {
5171 		g_hash_table_remove (joinable_threads, tid);
5172 		UnlockedDecrement (&joinable_thread_count);
5173 		found = TRUE;
5174 	}
5175 	joinable_threads_unlock ();
5176 
5177 	if (!found)
5178 		return;
5179 
5180 	threads_native_thread_join_nolock (tid, value);
5181 }
5182 
5183 void
mono_thread_internal_unhandled_exception(MonoObject * exc)5184 mono_thread_internal_unhandled_exception (MonoObject* exc)
5185 {
5186 	MonoClass *klass = exc->vtable->klass;
5187 	if (is_threadabort_exception (klass)) {
5188 		mono_thread_internal_reset_abort (mono_thread_internal_current ());
5189 	} else if (!is_appdomainunloaded_exception (klass)
5190 		&& mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT) {
5191 		mono_unhandled_exception (exc);
5192 		if (mono_environment_exitcode_get () == 1) {
5193 			mono_environment_exitcode_set (255);
5194 			mono_invoke_unhandled_exception_hook (exc);
5195 			g_assert_not_reached ();
5196 		}
5197 	}
5198 }
5199 
5200 void
ves_icall_System_Threading_Thread_GetStackTraces(MonoArray ** out_threads,MonoArray ** out_stack_traces)5201 ves_icall_System_Threading_Thread_GetStackTraces (MonoArray **out_threads, MonoArray **out_stack_traces)
5202 {
5203 	MonoError error;
5204 	mono_threads_get_thread_dump (out_threads, out_stack_traces, &error);
5205 	mono_error_set_pending_exception (&error);
5206 }
5207 
5208 /*
5209  * mono_threads_attach_coop: called by native->managed wrappers
5210  *
5211  *  - @dummy:
5212  *    - blocking mode: contains gc unsafe transition cookie
5213  *    - non-blocking mode: contains random data
5214  *  - @return: the original domain which needs to be restored, or NULL.
5215  */
5216 gpointer
mono_threads_attach_coop(MonoDomain * domain,gpointer * dummy)5217 mono_threads_attach_coop (MonoDomain *domain, gpointer *dummy)
5218 {
5219 	MonoDomain *orig;
5220 	MonoThreadInfo *info;
5221 	gboolean external;
5222 
5223 	orig = mono_domain_get ();
5224 
5225 	if (!domain) {
5226 		/* Happens when called from AOTed code which is only used in the root domain. */
5227 		domain = mono_get_root_domain ();
5228 		g_assert (domain);
5229 	}
5230 
5231 	/* On coop, when we detached, we moved the thread from  RUNNING->BLOCKING.
5232 	 * If we try to reattach we do a BLOCKING->RUNNING transition.  If the thread
5233 	 * is fresh, mono_thread_attach() will do a STARTING->RUNNING transition so
5234 	 * we're only responsible for making the cookie. */
5235 	if (mono_threads_is_blocking_transition_enabled ())
5236 		external = !(info = mono_thread_info_current_unchecked ()) || !mono_thread_info_is_live (info);
5237 
5238 	if (!mono_thread_internal_current ()) {
5239 		mono_thread_attach_full (domain, FALSE);
5240 
5241 		// #678164
5242 		mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
5243 	}
5244 
5245 	if (orig != domain)
5246 		mono_domain_set (domain, TRUE);
5247 
5248 	if (mono_threads_is_blocking_transition_enabled ()) {
5249 		if (external) {
5250 			/* mono_thread_attach put the thread in RUNNING mode from STARTING, but we need to
5251 			 * return the right cookie. */
5252 			*dummy = mono_threads_enter_gc_unsafe_region_cookie ();
5253 		} else {
5254 			/* thread state (BLOCKING|RUNNING) -> RUNNING */
5255 			*dummy = mono_threads_enter_gc_unsafe_region (dummy);
5256 		}
5257 	}
5258 
5259 	return orig;
5260 }
5261 
5262 /*
5263  * mono_threads_detach_coop: called by native->managed wrappers
5264  *
5265  *  - @cookie: the original domain which needs to be restored, or NULL.
5266  *  - @dummy:
5267  *    - blocking mode: contains gc unsafe transition cookie
5268  *    - non-blocking mode: contains random data
5269  */
5270 void
mono_threads_detach_coop(gpointer cookie,gpointer * dummy)5271 mono_threads_detach_coop (gpointer cookie, gpointer *dummy)
5272 {
5273 	MonoDomain *domain, *orig;
5274 
5275 	orig = (MonoDomain*) cookie;
5276 
5277 	domain = mono_domain_get ();
5278 	g_assert (domain);
5279 
5280 	if (mono_threads_is_blocking_transition_enabled ()) {
5281 		/* it won't do anything if cookie is NULL
5282 		 * thread state RUNNING -> (RUNNING|BLOCKING) */
5283 		mono_threads_exit_gc_unsafe_region (*dummy, dummy);
5284 	}
5285 
5286 	if (orig != domain) {
5287 		if (!orig)
5288 			mono_domain_unset ();
5289 		else
5290 			mono_domain_set (orig, TRUE);
5291 	}
5292 }
5293 
5294 #if 0
5295 /* Returns TRUE if the current thread is ready to be interrupted. */
5296 gboolean
5297 mono_threads_is_ready_to_be_interrupted (void)
5298 {
5299 	MonoInternalThread *thread;
5300 
5301 	thread = mono_thread_internal_current ();
5302 	LOCK_THREAD (thread);
5303 	if (thread->state & (ThreadState_SuspendRequested | ThreadState_AbortRequested)) {
5304 		UNLOCK_THREAD (thread);
5305 		return FALSE;
5306 	}
5307 
5308 	if (mono_thread_get_abort_prot_block_count (thread) || mono_get_eh_callbacks ()->mono_current_thread_has_handle_block_guard ()) {
5309 		UNLOCK_THREAD (thread);
5310 		return FALSE;
5311 	}
5312 
5313 	UNLOCK_THREAD (thread);
5314 	return TRUE;
5315 }
5316 #endif
5317 
5318 void
mono_thread_internal_describe(MonoInternalThread * internal,GString * text)5319 mono_thread_internal_describe (MonoInternalThread *internal, GString *text)
5320 {
5321 	g_string_append_printf (text, ", thread handle : %p", internal->handle);
5322 
5323 	if (internal->thread_info) {
5324 		g_string_append (text, ", state : ");
5325 		mono_thread_info_describe_interrupt_token ((MonoThreadInfo*) internal->thread_info, text);
5326 	}
5327 
5328 	if (internal->owned_mutexes) {
5329 		int i;
5330 
5331 		g_string_append (text, ", owns : [");
5332 		for (i = 0; i < internal->owned_mutexes->len; i++)
5333 			g_string_append_printf (text, i == 0 ? "%p" : ", %p", g_ptr_array_index (internal->owned_mutexes, i));
5334 		g_string_append (text, "]");
5335 	}
5336 }
5337 
5338 gboolean
mono_thread_internal_is_current(MonoInternalThread * internal)5339 mono_thread_internal_is_current (MonoInternalThread *internal)
5340 {
5341 	g_assert (internal);
5342 	return mono_native_thread_id_equals (mono_native_thread_id_get (), MONO_UINT_TO_NATIVE_THREAD_ID (internal->tid));
5343 }
5344