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, ¶m);
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, ¶m);
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