2 * threads.c: Thread support internal calls
5 * Dick Porter (dick@ximian.com)
6 * Paolo Molaro (lupus@ximian.com)
7 * Patrik Torstensson (patrik.torstensson@labs2.com)
9 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
19 #include <mono/metadata/object.h>
20 #include <mono/metadata/domain-internals.h>
21 #include <mono/metadata/profiler-private.h>
22 #include <mono/metadata/threads.h>
23 #include <mono/metadata/threadpool.h>
24 #include <mono/metadata/threads-types.h>
25 #include <mono/metadata/exception.h>
26 #include <mono/metadata/environment.h>
27 #include <mono/metadata/monitor.h>
28 #include <mono/metadata/gc-internal.h>
29 #include <mono/metadata/marshal.h>
30 #include <mono/io-layer/io-layer.h>
32 #include <mono/io-layer/threads.h>
34 #include <mono/metadata/object-internals.h>
35 #include <mono/metadata/mono-debug-debugger.h>
36 #include <mono/utils/mono-compiler.h>
37 #include <mono/utils/mono-mmap.h>
38 #include <mono/utils/mono-membar.h>
39 #include <mono/utils/mono-time.h>
41 #include <mono/metadata/gc-internal.h>
43 /*#define THREAD_DEBUG(a) do { a; } while (0)*/
44 #define THREAD_DEBUG(a)
45 /*#define THREAD_WAIT_DEBUG(a) do { a; } while (0)*/
46 #define THREAD_WAIT_DEBUG(a)
47 /*#define LIBGC_DEBUG(a) do { a; } while (0)*/
48 #define LIBGC_DEBUG(a)
50 /* Provide this for systems with glib < 2.6 */
51 #ifndef G_GSIZE_FORMAT
52 # if GLIB_SIZEOF_LONG == 8
53 # define G_GSIZE_FORMAT "lu"
55 # define G_GSIZE_FORMAT "u"
61 guint32 (*func
)(void *);
77 typedef struct _MonoThreadDomainTls MonoThreadDomainTls
;
78 struct _MonoThreadDomainTls
{
79 MonoThreadDomainTls
*next
;
87 MonoThreadDomainTls
*freelist
;
92 MonoHazardousFreeFunc free_func
;
95 /* Number of cached culture objects in the MonoThread->cached_culture_info array
96 * (per-type): we use the first NUM entries for CultureInfo and the last for
97 * UICultureInfo. So the size of the array is really NUM_CACHED_CULTURES * 2.
99 #define NUM_CACHED_CULTURES 4
100 #define CULTURES_START_IDX 0
101 #define UICULTURES_START_IDX NUM_CACHED_CULTURES
103 /* Controls access to the 'threads' hash table */
104 #define mono_threads_lock() EnterCriticalSection (&threads_mutex)
105 #define mono_threads_unlock() LeaveCriticalSection (&threads_mutex)
106 static CRITICAL_SECTION threads_mutex
;
108 /* Controls access to context static data */
109 #define mono_contexts_lock() EnterCriticalSection (&contexts_mutex)
110 #define mono_contexts_unlock() LeaveCriticalSection (&contexts_mutex)
111 static CRITICAL_SECTION contexts_mutex
;
113 /* Holds current status of static data heap */
114 static StaticDataInfo thread_static_info
;
115 static StaticDataInfo context_static_info
;
117 /* The hash of existing threads (key is thread ID, value is
118 * MonoInternalThread*) that need joining before exit
120 static MonoGHashTable
*threads
=NULL
;
123 * Threads which are starting up and they are not in the 'threads' hash yet.
124 * When handle_store is called for a thread, it will be removed from this hash table.
125 * Protected by mono_threads_lock ().
127 static MonoGHashTable
*threads_starting_up
= NULL
;
129 /* Maps a MonoThread to its start argument */
130 /* Protected by mono_threads_lock () */
131 static MonoGHashTable
*thread_start_args
= NULL
;
133 /* The TLS key that holds the MonoObject assigned to each thread */
134 static guint32 current_object_key
= -1;
136 #ifdef HAVE_KW_THREAD
137 /* we need to use both the Tls* functions and __thread because
138 * the gc needs to see all the threads
140 static __thread MonoInternalThread
* tls_current_object MONO_TLS_FAST
;
141 #define SET_CURRENT_OBJECT(x) do { \
142 tls_current_object = x; \
143 TlsSetValue (current_object_key, x); \
145 #define GET_CURRENT_OBJECT() tls_current_object
147 #define SET_CURRENT_OBJECT(x) TlsSetValue (current_object_key, x)
148 #define GET_CURRENT_OBJECT() (MonoThread*) TlsGetValue (current_object_key)
151 /* function called at thread start */
152 static MonoThreadStartCB mono_thread_start_cb
= NULL
;
154 /* function called at thread attach */
155 static MonoThreadAttachCB mono_thread_attach_cb
= NULL
;
157 /* function called at thread cleanup */
158 static MonoThreadCleanupFunc mono_thread_cleanup_fn
= NULL
;
160 /* function called to notify the runtime about a pending exception on the current thread */
161 static MonoThreadNotifyPendingExcFunc mono_thread_notify_pending_exc_fn
= NULL
;
163 /* The default stack size for each thread */
164 static guint32 default_stacksize
= 0;
165 #define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize)
167 static void thread_adjust_static_data (MonoInternalThread
*thread
);
168 static void mono_init_static_data_info (StaticDataInfo
*static_data
);
169 static guint32
mono_alloc_static_data_slot (StaticDataInfo
*static_data
, guint32 size
, guint32 align
);
170 static gboolean
mono_thread_resume (MonoInternalThread
* thread
);
171 static void mono_thread_start (MonoThread
*thread
);
172 static void signal_thread_state_change (MonoInternalThread
*thread
);
174 static MonoException
* mono_thread_execute_interruption (MonoInternalThread
*thread
);
176 /* Spin lock for InterlockedXXX 64 bit functions */
177 #define mono_interlocked_lock() EnterCriticalSection (&interlocked_mutex)
178 #define mono_interlocked_unlock() LeaveCriticalSection (&interlocked_mutex)
179 static CRITICAL_SECTION interlocked_mutex
;
181 /* global count of thread interruptions requested */
182 static gint32 thread_interruption_requested
= 0;
184 /* Event signaled when a thread changes its background mode */
185 static HANDLE background_change_event
;
187 /* The table for small ID assignment */
188 static CRITICAL_SECTION small_id_mutex
;
189 static int small_id_table_size
= 0;
190 static int small_id_next
= 0;
191 static int highest_small_id
= -1;
192 static MonoInternalThread
**small_id_table
= NULL
;
194 /* The hazard table */
195 #if MONO_SMALL_CONFIG
196 #define HAZARD_TABLE_MAX_SIZE 256
198 #define HAZARD_TABLE_MAX_SIZE 16384 /* There cannot be more threads than this number. */
200 static volatile int hazard_table_size
= 0;
201 static MonoThreadHazardPointers
* volatile hazard_table
= NULL
;
203 /* The table where we keep pointers to blocks to be freed but that
204 have to wait because they're guarded by a hazard pointer. */
205 static CRITICAL_SECTION delayed_free_table_mutex
;
206 static GArray
*delayed_free_table
= NULL
;
208 static gboolean shutting_down
= FALSE
;
211 mono_thread_get_tls_key (void)
213 return current_object_key
;
217 mono_thread_get_tls_offset (void)
220 MONO_THREAD_VAR_OFFSET (tls_current_object
,offset
);
224 /* handle_store() and handle_remove() manage the array of threads that
225 * still need to be waited for when the main thread exits.
227 * If handle_store() returns FALSE the thread must not be started
228 * because Mono is shutting down.
230 static gboolean
handle_store(MonoThread
*thread
)
232 mono_threads_lock ();
234 THREAD_DEBUG (g_message ("%s: thread %p ID %"G_GSIZE_FORMAT
, __func__
, thread
, (gsize
)thread
->tid
));
236 if (threads_starting_up
)
237 mono_g_hash_table_remove (threads_starting_up
, thread
);
240 mono_threads_unlock ();
245 MONO_GC_REGISTER_ROOT (threads
);
246 threads
=mono_g_hash_table_new_type (NULL
, NULL
, MONO_HASH_VALUE_GC
);
249 /* We don't need to duplicate thread->handle, because it is
250 * only closed when the thread object is finalized by the GC.
252 g_assert (thread
->internal_thread
);
253 mono_g_hash_table_insert(threads
, (gpointer
)(gsize
)(thread
->internal_thread
->tid
),
254 thread
->internal_thread
);
256 mono_threads_unlock ();
261 static gboolean
handle_remove(MonoInternalThread
*thread
)
264 gsize tid
= thread
->tid
;
266 THREAD_DEBUG (g_message ("%s: thread ID %"G_GSIZE_FORMAT
, __func__
, tid
));
268 mono_threads_lock ();
271 /* We have to check whether the thread object for the
272 * tid is still the same in the table because the
273 * thread might have been destroyed and the tid reused
274 * in the meantime, in which case the tid would be in
275 * the table, but with another thread object.
277 if (mono_g_hash_table_lookup (threads
, (gpointer
)tid
) == thread
) {
278 mono_g_hash_table_remove (threads
, (gpointer
)tid
);
287 mono_threads_unlock ();
289 /* Don't close the handle here, wait for the object finalizer
290 * to do it. Otherwise, the following race condition applies:
292 * 1) Thread exits (and handle_remove() closes the handle)
294 * 2) Some other handle is reassigned the same slot
296 * 3) Another thread tries to join the first thread, and
297 * blocks waiting for the reassigned handle to be signalled
298 * (which might never happen). This is possible, because the
299 * thread calling Join() still has a reference to the first
306 * Allocate a small thread id.
308 * FIXME: The biggest part of this function is very similar to
309 * domain_id_alloc() in domain.c and should be merged.
312 small_id_alloc (MonoInternalThread
*thread
)
316 EnterCriticalSection (&small_id_mutex
);
318 if (!small_id_table
) {
319 small_id_table_size
= 2;
320 small_id_table
= mono_gc_alloc_fixed (small_id_table_size
* sizeof (MonoInternalThread
*), NULL
);
322 for (i
= small_id_next
; i
< small_id_table_size
; ++i
) {
323 if (!small_id_table
[i
]) {
329 for (i
= 0; i
< small_id_next
; ++i
) {
330 if (!small_id_table
[i
]) {
337 MonoInternalThread
**new_table
;
338 int new_size
= small_id_table_size
* 2;
339 if (new_size
>= (1 << 16))
340 g_assert_not_reached ();
341 id
= small_id_table_size
;
342 new_table
= mono_gc_alloc_fixed (new_size
* sizeof (MonoInternalThread
*), NULL
);
343 memcpy (new_table
, small_id_table
, small_id_table_size
* sizeof (void*));
344 mono_gc_free_fixed (small_id_table
);
345 small_id_table
= new_table
;
346 small_id_table_size
= new_size
;
348 thread
->small_id
= id
;
349 g_assert (small_id_table
[id
] == NULL
);
350 small_id_table
[id
] = thread
;
352 if (small_id_next
> small_id_table_size
)
355 g_assert (id
< HAZARD_TABLE_MAX_SIZE
);
356 if (id
>= hazard_table_size
) {
357 #if MONO_SMALL_CONFIG
358 hazard_table
= g_malloc0 (sizeof (MonoThreadHazardPointers
) * HAZARD_TABLE_MAX_SIZE
);
359 hazard_table_size
= HAZARD_TABLE_MAX_SIZE
;
362 int pagesize
= mono_pagesize ();
363 int num_pages
= (hazard_table_size
* sizeof (MonoThreadHazardPointers
) + pagesize
- 1) / pagesize
;
365 if (hazard_table
== NULL
) {
366 hazard_table
= mono_valloc (NULL
,
367 sizeof (MonoThreadHazardPointers
) * HAZARD_TABLE_MAX_SIZE
,
371 g_assert (hazard_table
!= NULL
);
372 page_addr
= (guint8
*)hazard_table
+ num_pages
* pagesize
;
374 mono_mprotect (page_addr
, pagesize
, MONO_MMAP_READ
| MONO_MMAP_WRITE
);
377 hazard_table_size
= num_pages
* pagesize
/ sizeof (MonoThreadHazardPointers
);
380 g_assert (id
< hazard_table_size
);
381 hazard_table
[id
].hazard_pointers
[0] = NULL
;
382 hazard_table
[id
].hazard_pointers
[1] = NULL
;
385 if (id
> highest_small_id
) {
386 highest_small_id
= id
;
387 mono_memory_write_barrier ();
390 LeaveCriticalSection (&small_id_mutex
);
396 small_id_free (int id
)
398 g_assert (id
>= 0 && id
< small_id_table_size
);
399 g_assert (small_id_table
[id
] != NULL
);
401 small_id_table
[id
] = NULL
;
405 is_pointer_hazardous (gpointer p
)
408 int highest
= highest_small_id
;
410 g_assert (highest
< hazard_table_size
);
412 for (i
= 0; i
<= highest
; ++i
) {
413 if (hazard_table
[i
].hazard_pointers
[0] == p
414 || hazard_table
[i
].hazard_pointers
[1] == p
)
421 MonoThreadHazardPointers
*
422 mono_hazard_pointer_get (void)
424 MonoInternalThread
*current_thread
= mono_thread_internal_current ();
426 if (!(current_thread
&& current_thread
->small_id
>= 0)) {
427 static MonoThreadHazardPointers emerg_hazard_table
;
428 g_warning ("Thread %p may have been prematurely finalized", current_thread
);
429 return &emerg_hazard_table
;
432 return &hazard_table
[current_thread
->small_id
];
436 try_free_delayed_free_item (int index
)
438 if (delayed_free_table
->len
> index
) {
439 DelayedFreeItem item
= { NULL
, NULL
};
441 EnterCriticalSection (&delayed_free_table_mutex
);
442 /* We have to check the length again because another
443 thread might have freed an item before we acquired
445 if (delayed_free_table
->len
> index
) {
446 item
= g_array_index (delayed_free_table
, DelayedFreeItem
, index
);
448 if (!is_pointer_hazardous (item
.p
))
449 g_array_remove_index_fast (delayed_free_table
, index
);
453 LeaveCriticalSection (&delayed_free_table_mutex
);
456 item
.free_func (item
.p
);
461 mono_thread_hazardous_free_or_queue (gpointer p
, MonoHazardousFreeFunc free_func
)
465 /* First try to free a few entries in the delayed free
467 for (i
= 2; i
>= 0; --i
)
468 try_free_delayed_free_item (i
);
470 /* Now see if the pointer we're freeing is hazardous. If it
471 isn't, free it. Otherwise put it in the delay list. */
472 if (is_pointer_hazardous (p
)) {
473 DelayedFreeItem item
= { p
, free_func
};
475 ++mono_stats
.hazardous_pointer_count
;
477 EnterCriticalSection (&delayed_free_table_mutex
);
478 g_array_append_val (delayed_free_table
, item
);
479 LeaveCriticalSection (&delayed_free_table_mutex
);
485 mono_thread_hazardous_try_free_all (void)
490 if (!delayed_free_table
)
493 len
= delayed_free_table
->len
;
495 for (i
= len
- 1; i
>= 0; --i
)
496 try_free_delayed_free_item (i
);
499 static void ensure_synch_cs_set (MonoInternalThread
*thread
)
501 CRITICAL_SECTION
*synch_cs
;
503 if (thread
->synch_cs
!= NULL
) {
507 synch_cs
= g_new0 (CRITICAL_SECTION
, 1);
508 InitializeCriticalSection (synch_cs
);
510 if (InterlockedCompareExchangePointer ((gpointer
*)&thread
->synch_cs
,
511 synch_cs
, NULL
) != NULL
) {
512 /* Another thread must have installed this CS */
513 DeleteCriticalSection (synch_cs
);
519 * NOTE: this function can be called also for threads different from the current one:
520 * make sure no code called from it will ever assume it is run on the thread that is
521 * getting cleaned up.
523 static void thread_cleanup (MonoInternalThread
*thread
)
525 g_assert (thread
!= NULL
);
527 if (thread
->abort_state_handle
) {
528 mono_gchandle_free (thread
->abort_state_handle
);
529 thread
->abort_state_handle
= 0;
531 thread
->abort_exc
= NULL
;
532 thread
->current_appcontext
= NULL
;
535 * This is necessary because otherwise we might have
536 * cross-domain references which will not get cleaned up when
537 * the target domain is unloaded.
539 if (thread
->cached_culture_info
) {
541 for (i
= 0; i
< NUM_CACHED_CULTURES
* 2; ++i
)
542 mono_array_set (thread
->cached_culture_info
, MonoObject
*, i
, NULL
);
545 /* if the thread is not in the hash it has been removed already */
546 if (!handle_remove (thread
))
548 mono_release_type_locks (thread
);
550 EnterCriticalSection (thread
->synch_cs
);
552 thread
->state
|= ThreadState_Stopped
;
553 thread
->state
&= ~ThreadState_Background
;
555 LeaveCriticalSection (thread
->synch_cs
);
557 mono_profiler_thread_end (thread
->tid
);
559 if (thread
== mono_thread_internal_current ())
560 mono_thread_pop_appdomain_ref ();
562 thread
->cached_culture_info
= NULL
;
564 mono_gc_free_fixed (thread
->static_data
);
565 thread
->static_data
= NULL
;
568 * FIXME: The check for shutting_down here is a kludge and
569 * should be removed. The reason we need it here is because
570 * mono_thread_manage() does not wait for finalizer threads,
571 * so we might still be at this point in a finalizer thread
572 * after the main thread has cleared the root domain, so
573 * thread could have been zeroed out.
575 if (mono_thread_cleanup_fn
&& !shutting_down
)
576 mono_thread_cleanup_fn (thread
->root_domain_thread
);
578 small_id_free (thread
->small_id
);
579 thread
->small_id
= -2;
583 get_thread_static_data (MonoInternalThread
*thread
, guint32 offset
)
586 g_assert ((offset
& 0x80000000) == 0);
587 offset
&= 0x7fffffff;
588 idx
= (offset
>> 24) - 1;
589 return ((char*) thread
->static_data
[idx
]) + (offset
& 0xffffff);
593 get_current_thread_ptr_for_domain (MonoDomain
*domain
, MonoInternalThread
*thread
)
595 static MonoClassField
*current_thread_field
= NULL
;
599 if (!current_thread_field
) {
600 current_thread_field
= mono_class_get_field_from_name (mono_defaults
.thread_class
, "current_thread");
601 g_assert (current_thread_field
);
604 mono_class_vtable (domain
, mono_defaults
.thread_class
);
605 mono_domain_lock (domain
);
606 offset
= GPOINTER_TO_UINT (g_hash_table_lookup (domain
->special_static_fields
, current_thread_field
));
607 mono_domain_unlock (domain
);
610 return get_thread_static_data (thread
, offset
);
614 set_current_thread_for_domain (MonoDomain
*domain
, MonoInternalThread
*thread
, MonoThread
*current
)
616 MonoThread
**current_thread_ptr
= get_current_thread_ptr_for_domain (domain
, thread
);
618 g_assert (current
->obj
.vtable
->domain
== domain
);
620 g_assert (!*current_thread_ptr
);
621 *current_thread_ptr
= current
;
625 new_thread_with_internal (MonoDomain
*domain
, MonoInternalThread
*internal
)
627 MonoThread
*thread
= (MonoThread
*) mono_object_new (domain
, mono_defaults
.thread_class
);
628 MONO_OBJECT_SETREF (thread
, internal_thread
, internal
);
633 init_root_domain_thread (MonoInternalThread
*thread
, MonoThread
*candidate
)
635 MonoDomain
*domain
= mono_get_root_domain ();
637 if (!candidate
|| candidate
->obj
.vtable
->domain
!= domain
)
638 candidate
= new_thread_with_internal (domain
, thread
);
639 set_current_thread_for_domain (domain
, thread
, candidate
);
640 g_assert (!thread
->root_domain_thread
);
641 MONO_OBJECT_SETREF (thread
, root_domain_thread
, candidate
);
644 static guint32 WINAPI
start_wrapper(void *data
)
646 struct StartInfo
*start_info
=(struct StartInfo
*)data
;
647 guint32 (*start_func
)(void *);
650 MonoThread
*thread
=start_info
->obj
;
651 MonoInternalThread
*internal
= thread
->internal_thread
;
652 MonoObject
*start_delegate
= start_info
->delegate
;
654 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT
") Start wrapper", __func__
, GetCurrentThreadId ()));
656 /* We can be sure start_info->obj->tid and
657 * start_info->obj->handle have been set, because the thread
658 * was created suspended, and these values were set before the
664 SET_CURRENT_OBJECT (internal
);
666 mono_monitor_init_tls ();
668 /* Every thread references the appdomain which created it */
669 mono_thread_push_appdomain_ref (thread
->obj
.vtable
->domain
);
671 if (!mono_domain_set (thread
->obj
.vtable
->domain
, FALSE
)) {
672 /* No point in raising an appdomain_unloaded exception here */
673 /* FIXME: Cleanup here */
674 mono_thread_pop_appdomain_ref ();
678 start_func
= start_info
->func
;
679 start_arg
= start_info
->start_arg
;
681 /* We have to do this here because mono_thread_new_init()
682 requires that root_domain_thread is set up. */
683 thread_adjust_static_data (internal
);
684 init_root_domain_thread (internal
, thread
);
686 /* This MUST be called before any managed code can be
687 * executed, as it calls the callback function that (for the
688 * jit) sets the lmf marker.
690 mono_thread_new_init (tid
, &tid
, start_func
);
691 internal
->stack_ptr
= &tid
;
693 LIBGC_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT
",%d) Setting thread stack to %p", __func__
, GetCurrentThreadId (), getpid (), thread
->stack_ptr
));
695 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT
") Setting current_object_key to %p", __func__
, GetCurrentThreadId (), thread
));
697 /* On 2.0 profile (and higher), set explicitly since state might have been
699 if (internal
->apartment_state
== ThreadApartmentState_Unknown
)
700 internal
->apartment_state
= ThreadApartmentState_MTA
;
702 mono_thread_init_apartment_state ();
704 if(internal
->start_notify
!=NULL
) {
705 /* Let the thread that called Start() know we're
708 ReleaseSemaphore (internal
->start_notify
, 1, NULL
);
711 mono_threads_lock ();
712 mono_g_hash_table_remove (thread_start_args
, thread
);
713 mono_threads_unlock ();
717 g_message ("%s: start_wrapper for %"G_GSIZE_FORMAT
, __func__
,
721 mono_thread_set_execution_context (thread
->ec_to_set
);
722 thread
->ec_to_set
= NULL
;
725 * Call this after calling start_notify, since the profiler callback might want
726 * to lock the thread, and the lock is held by thread_start () which waits for
729 mono_profiler_thread_start (tid
);
731 /* start_func is set only for unmanaged start functions */
733 start_func (start_arg
);
736 g_assert (start_delegate
!= NULL
);
737 args
[0] = start_arg
;
738 /* we may want to handle the exception here. See comment below on unhandled exceptions */
739 mono_runtime_delegate_invoke (start_delegate
, args
, NULL
);
742 /* If the thread calls ExitThread at all, this remaining code
743 * will not be executed, but the main thread will eventually
744 * call thread_cleanup() on this thread's behalf.
747 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT
") Start wrapper terminating", __func__
, GetCurrentThreadId ()));
749 thread_cleanup (internal
);
751 /* Do any cleanup needed for apartment state. This
752 * cannot be done in thread_cleanup since thread_cleanup could be
753 * called for a thread other than the current thread.
754 * mono_thread_cleanup_apartment_state cleans up apartment
755 * for the current thead */
756 mono_thread_cleanup_apartment_state ();
758 /* Remove the reference to the thread object in the TLS data,
759 * so the thread object can be finalized. This won't be
760 * reached if the thread threw an uncaught exception, so those
761 * thread handles will stay referenced :-( (This is due to
762 * missing support for scanning thread-specific data in the
763 * Boehm GC - the io-layer keeps a GC-visible hash of pointers
766 SET_CURRENT_OBJECT (NULL
);
767 mono_domain_unset ();
772 void mono_thread_new_init (intptr_t tid
, gpointer stack_start
, gpointer func
)
774 if (mono_thread_start_cb
) {
775 mono_thread_start_cb (tid
, stack_start
, func
);
779 void mono_threads_set_default_stacksize (guint32 stacksize
)
781 default_stacksize
= stacksize
;
784 guint32
mono_threads_get_default_stacksize (void)
786 return default_stacksize
;
790 * mono_create_thread:
792 * This is a wrapper around CreateThread which handles differences in the type of
793 * the the 'tid' argument.
795 gpointer
mono_create_thread (WapiSecurityAttributes
*security
,
796 guint32 stacksize
, WapiThreadStart start
,
797 gpointer param
, guint32 create
, gsize
*tid
)
804 res
= CreateThread (security
, stacksize
, start
, param
, create
, &real_tid
);
808 res
= CreateThread (security
, stacksize
, start
, param
, create
, tid
);
815 * The thread start argument may be an object reference, and there is
816 * no ref to keep it alive when the new thread is started but not yet
817 * registered with the collector. So we store it in a GC tracked hash
820 * LOCKING: Assumes the threads lock is held.
823 register_thread_start_argument (MonoThread
*thread
, struct StartInfo
*start_info
)
825 if (thread_start_args
== NULL
) {
826 MONO_GC_REGISTER_ROOT (thread_start_args
);
827 thread_start_args
= mono_g_hash_table_new (NULL
, NULL
);
829 mono_g_hash_table_insert (thread_start_args
, thread
, start_info
->start_arg
);
832 MonoInternalThread
* mono_thread_create_internal (MonoDomain
*domain
, gpointer func
, gpointer arg
, gboolean threadpool_thread
)
835 MonoInternalThread
*internal
;
836 HANDLE thread_handle
;
837 struct StartInfo
*start_info
;
840 thread
=(MonoThread
*)mono_object_new (domain
,
841 mono_defaults
.thread_class
);
842 internal
= (MonoInternalThread
*)mono_object_new (mono_get_root_domain (),
843 mono_defaults
.internal_thread_class
);
844 MONO_OBJECT_SETREF (thread
, internal_thread
, internal
);
846 start_info
=g_new0 (struct StartInfo
, 1);
847 start_info
->func
= func
;
848 start_info
->obj
= thread
;
849 start_info
->start_arg
= arg
;
851 mono_threads_lock ();
853 mono_threads_unlock ();
857 if (threads_starting_up
== NULL
) {
858 MONO_GC_REGISTER_ROOT (threads_starting_up
);
859 threads_starting_up
= mono_g_hash_table_new (NULL
, NULL
);
862 register_thread_start_argument (thread
, start_info
);
863 mono_g_hash_table_insert (threads_starting_up
, thread
, thread
);
864 mono_threads_unlock ();
866 /* Create suspended, so we can do some housekeeping before the thread
869 thread_handle
= mono_create_thread (NULL
, default_stacksize_for_thread (internal
), (LPTHREAD_START_ROUTINE
)start_wrapper
, start_info
,
870 CREATE_SUSPENDED
, &tid
);
871 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT
" (handle %p)", __func__
, tid
, thread_handle
));
872 if (thread_handle
== NULL
) {
873 /* The thread couldn't be created, so throw an exception */
874 mono_threads_lock ();
875 mono_g_hash_table_remove (threads_starting_up
, thread
);
876 mono_threads_unlock ();
878 mono_raise_exception (mono_get_exception_execution_engine ("Couldn't create thread"));
882 internal
->handle
=thread_handle
;
884 internal
->apartment_state
=ThreadApartmentState_Unknown
;
885 small_id_alloc (internal
);
887 internal
->synch_cs
= g_new0 (CRITICAL_SECTION
, 1);
888 InitializeCriticalSection (internal
->synch_cs
);
890 internal
->threadpool_thread
= threadpool_thread
;
891 if (threadpool_thread
)
892 mono_thread_set_state (internal
, ThreadState_Background
);
894 if (handle_store (thread
))
895 ResumeThread (thread_handle
);
901 mono_thread_create (MonoDomain
*domain
, gpointer func
, gpointer arg
)
903 mono_thread_create_internal (domain
, func
, arg
, FALSE
);
907 * mono_thread_get_stack_bounds:
909 * Return the address and size of the current threads stack. Return NULL as the
910 * stack address if the stack address cannot be determined.
913 mono_thread_get_stack_bounds (guint8
**staddr
, size_t *stsize
)
915 #if defined(HAVE_PTHREAD_GET_STACKSIZE_NP) && defined(HAVE_PTHREAD_GET_STACKADDR_NP)
916 *staddr
= (guint8
*)pthread_get_stackaddr_np (pthread_self ());
917 *stsize
= pthread_get_stacksize_np (pthread_self ());
918 *staddr
= (guint8
*)((gssize
)*staddr
& ~(mono_pagesize () - 1));
920 /* FIXME: simplify the mess below */
921 #elif !defined(HOST_WIN32)
923 guint8
*current
= (guint8
*)&attr
;
925 pthread_attr_init (&attr
);
926 # ifdef HAVE_PTHREAD_GETATTR_NP
927 pthread_getattr_np (pthread_self(), &attr
);
929 # ifdef HAVE_PTHREAD_ATTR_GET_NP
930 pthread_attr_get_np (pthread_self(), &attr
);
933 pthread_attr_getstacksize (&attr
, &stsize
);
942 pthread_attr_getstack (&attr
, (void**)staddr
, stsize
);
944 g_assert ((current
> *staddr
) && (current
< *staddr
+ *stsize
));
947 pthread_attr_destroy (&attr
);
950 /* When running under emacs, sometimes staddr is not aligned to a page size */
951 *staddr
= (guint8
*)((gssize
)*staddr
& ~(mono_pagesize () - 1));
955 mono_thread_attach (MonoDomain
*domain
)
957 MonoInternalThread
*thread
;
958 MonoThread
*current_thread
;
959 HANDLE thread_handle
;
962 if ((thread
= mono_thread_internal_current ())) {
963 if (domain
!= mono_domain_get ())
964 mono_domain_set (domain
, TRUE
);
965 /* Already attached */
966 return mono_thread_current ();
969 if (!mono_gc_register_thread (&domain
)) {
970 g_error ("Thread %"G_GSIZE_FORMAT
" calling into managed code is not registered with the GC. On UNIX, this can be fixed by #include-ing <gc.h> before <pthread.h> in the file containing the thread creation code.", GetCurrentThreadId ());
973 thread
= (MonoInternalThread
*)mono_object_new (domain
, mono_defaults
.internal_thread_class
);
975 thread_handle
= GetCurrentThread ();
976 g_assert (thread_handle
);
978 tid
=GetCurrentThreadId ();
981 * The handle returned by GetCurrentThread () is a pseudo handle, so it can't be used to
982 * refer to the thread from other threads for things like aborting.
984 DuplicateHandle (GetCurrentProcess (), thread_handle
, GetCurrentProcess (), &thread_handle
,
985 THREAD_ALL_ACCESS
, TRUE
, 0);
987 thread
->handle
=thread_handle
;
989 thread
->apartment_state
=ThreadApartmentState_Unknown
;
990 small_id_alloc (thread
);
991 thread
->stack_ptr
= &tid
;
993 thread
->synch_cs
= g_new0 (CRITICAL_SECTION
, 1);
994 InitializeCriticalSection (thread
->synch_cs
);
996 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT
" (handle %p)", __func__
, tid
, thread_handle
));
998 current_thread
= new_thread_with_internal (domain
, thread
);
1000 if (!handle_store (current_thread
)) {
1001 /* Mono is shutting down, so just wait for the end */
1006 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT
") Setting current_object_key to %p", __func__
, GetCurrentThreadId (), thread
));
1008 SET_CURRENT_OBJECT (thread
);
1009 mono_domain_set (domain
, TRUE
);
1011 mono_monitor_init_tls ();
1013 thread_adjust_static_data (thread
);
1015 init_root_domain_thread (thread
, current_thread
);
1016 if (domain
!= mono_get_root_domain ())
1017 set_current_thread_for_domain (domain
, thread
, current_thread
);
1020 if (mono_thread_attach_cb
) {
1024 mono_thread_get_stack_bounds (&staddr
, &stsize
);
1027 mono_thread_attach_cb (tid
, &tid
);
1029 mono_thread_attach_cb (tid
, staddr
+ stsize
);
1032 // FIXME: Need a separate callback
1033 mono_profiler_thread_start (tid
);
1035 return current_thread
;
1039 mono_thread_detach (MonoThread
*thread
)
1041 g_return_if_fail (thread
!= NULL
);
1043 THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT
")", __func__
, thread
, (gsize
)thread
->tid
));
1045 thread_cleanup (thread
->internal_thread
);
1047 SET_CURRENT_OBJECT (NULL
);
1048 mono_domain_unset ();
1050 /* Don't need to CloseHandle this thread, even though we took a
1051 * reference in mono_thread_attach (), because the GC will do it
1052 * when the Thread object is finalised.
1059 MonoInternalThread
*thread
= mono_thread_internal_current ();
1061 THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT
")", __func__
, thread
, (gsize
)thread
->tid
));
1063 thread_cleanup (thread
);
1064 SET_CURRENT_OBJECT (NULL
);
1065 mono_domain_unset ();
1067 /* we could add a callback here for embedders to use. */
1068 if (mono_thread_get_main () && (thread
== mono_thread_get_main ()->internal_thread
))
1069 exit (mono_environment_exitcode_get ());
1074 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread
*this)
1076 MonoInternalThread
*internal
= (MonoInternalThread
*)mono_object_new (mono_get_root_domain (), mono_defaults
.internal_thread_class
);
1077 internal
->state
= ThreadState_Unstarted
;
1078 internal
->apartment_state
= ThreadApartmentState_Unknown
;
1080 InterlockedCompareExchangePointer ((gpointer
)&this->internal_thread
, internal
, NULL
);
1083 HANDLE
ves_icall_System_Threading_Thread_Thread_internal(MonoThread
*this,
1086 guint32 (*start_func
)(void *);
1087 struct StartInfo
*start_info
;
1090 MonoInternalThread
*internal
;
1092 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__
, this, start
));
1094 if (!this->internal_thread
)
1095 ves_icall_System_Threading_Thread_ConstructInternalThread (this);
1096 internal
= this->internal_thread
;
1098 ensure_synch_cs_set (internal
);
1100 EnterCriticalSection (internal
->synch_cs
);
1102 if ((internal
->state
& ThreadState_Unstarted
) == 0) {
1103 LeaveCriticalSection (internal
->synch_cs
);
1104 mono_raise_exception (mono_get_exception_thread_state ("Thread has already been started."));
1108 internal
->small_id
= -1;
1110 if ((internal
->state
& ThreadState_Aborted
) != 0) {
1111 LeaveCriticalSection (internal
->synch_cs
);
1116 /* This is freed in start_wrapper */
1117 start_info
= g_new0 (struct StartInfo
, 1);
1118 start_info
->func
= start_func
;
1119 start_info
->start_arg
= this->start_obj
; /* FIXME: GC object stored in unmanaged memory */
1120 start_info
->delegate
= start
;
1121 start_info
->obj
= this;
1122 g_assert (this->obj
.vtable
->domain
== mono_domain_get ());
1124 internal
->start_notify
=CreateSemaphore (NULL
, 0, 0x7fffffff, NULL
);
1125 if (internal
->start_notify
==NULL
) {
1126 LeaveCriticalSection (internal
->synch_cs
);
1127 g_warning ("%s: CreateSemaphore error 0x%x", __func__
, GetLastError ());
1128 g_free (start_info
);
1132 mono_threads_lock ();
1133 register_thread_start_argument (this, start_info
);
1134 if (threads_starting_up
== NULL
) {
1135 MONO_GC_REGISTER_ROOT (threads_starting_up
);
1136 threads_starting_up
= mono_g_hash_table_new (NULL
, NULL
);
1138 mono_g_hash_table_insert (threads_starting_up
, this, this);
1139 mono_threads_unlock ();
1141 thread
=mono_create_thread(NULL
, default_stacksize_for_thread (internal
), (LPTHREAD_START_ROUTINE
)start_wrapper
, start_info
,
1142 CREATE_SUSPENDED
, &tid
);
1144 LeaveCriticalSection (internal
->synch_cs
);
1145 mono_threads_lock ();
1146 mono_g_hash_table_remove (threads_starting_up
, this);
1147 mono_threads_unlock ();
1148 g_warning("%s: CreateThread error 0x%x", __func__
, GetLastError());
1152 internal
->handle
=thread
;
1154 small_id_alloc (internal
);
1156 /* Don't call handle_store() here, delay it to Start.
1157 * We can't join a thread (trying to will just block
1158 * forever) until it actually starts running, so don't
1159 * store the handle till then.
1162 mono_thread_start (this);
1164 internal
->state
&= ~ThreadState_Unstarted
;
1166 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT
" (handle %p)", __func__
, tid
, thread
));
1168 LeaveCriticalSection (internal
->synch_cs
);
1173 void ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread
*this, HANDLE thread
)
1175 MONO_ARCH_SAVE_REGS
;
1177 THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__
, this, thread
));
1180 CloseHandle (thread
);
1182 if (this->synch_cs
) {
1183 DeleteCriticalSection (this->synch_cs
);
1184 g_free (this->synch_cs
);
1185 this->synch_cs
= NULL
;
1188 g_free (this->name
);
1191 static void mono_thread_start (MonoThread
*thread
)
1193 MonoInternalThread
*internal
= thread
->internal_thread
;
1195 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT
") Launching thread %p (%"G_GSIZE_FORMAT
")", __func__
, GetCurrentThreadId (), thread
, (gsize
)thread
->tid
));
1197 /* Only store the handle when the thread is about to be
1198 * launched, to avoid the main thread deadlocking while trying
1199 * to clean up a thread that will never be signalled.
1201 if (!handle_store (thread
))
1204 ResumeThread (internal
->handle
);
1206 if(internal
->start_notify
!=NULL
) {
1207 /* Wait for the thread to set up its TLS data etc, so
1208 * theres no potential race condition if someone tries
1209 * to look up the data believing the thread has
1213 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT
") waiting for thread %p (%"G_GSIZE_FORMAT
") to start", __func__
, GetCurrentThreadId (), thread
, (gsize
)thread
->tid
));
1215 WaitForSingleObjectEx (internal
->start_notify
, INFINITE
, FALSE
);
1216 CloseHandle (internal
->start_notify
);
1217 internal
->start_notify
= NULL
;
1220 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT
") Done launching thread %p (%"G_GSIZE_FORMAT
")", __func__
, GetCurrentThreadId (), thread
, (gsize
)thread
->tid
));
1223 void ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms
)
1226 MonoInternalThread
*thread
= mono_thread_internal_current ();
1228 THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__
, ms
));
1230 mono_thread_current_check_pending_interrupt ();
1232 mono_thread_set_state (thread
, ThreadState_WaitSleepJoin
);
1234 res
= SleepEx(ms
,TRUE
);
1236 mono_thread_clr_state (thread
, ThreadState_WaitSleepJoin
);
1238 if (res
== WAIT_IO_COMPLETION
) { /* we might have been interrupted */
1239 MonoException
* exc
= mono_thread_execute_interruption (thread
);
1240 if (exc
) mono_raise_exception (exc
);
1244 void ves_icall_System_Threading_Thread_SpinWait_nop (void)
1249 ves_icall_System_Threading_Thread_GetDomainID (void)
1251 MONO_ARCH_SAVE_REGS
;
1253 return mono_domain_get()->domain_id
;
1257 * mono_thread_get_name:
1259 * Return the name of the thread. NAME_LEN is set to the length of the name.
1260 * Return NULL if the thread has no name. The returned memory is owned by the
1264 mono_thread_get_name (MonoInternalThread
*this_obj
, guint32
*name_len
)
1268 ensure_synch_cs_set (this_obj
);
1270 EnterCriticalSection (this_obj
->synch_cs
);
1272 if (!this_obj
->name
) {
1276 *name_len
= this_obj
->name_len
;
1277 res
= g_new (gunichar2
, this_obj
->name_len
);
1278 memcpy (res
, this_obj
->name
, sizeof (gunichar2
) * this_obj
->name_len
);
1281 LeaveCriticalSection (this_obj
->synch_cs
);
1287 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread
*this_obj
)
1291 ensure_synch_cs_set (this_obj
);
1293 EnterCriticalSection (this_obj
->synch_cs
);
1295 if (!this_obj
->name
)
1298 str
= mono_string_new_utf16 (mono_domain_get (), this_obj
->name
, this_obj
->name_len
);
1300 LeaveCriticalSection (this_obj
->synch_cs
);
1306 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread
*this_obj
, MonoString
*name
)
1308 ensure_synch_cs_set (this_obj
);
1310 EnterCriticalSection (this_obj
->synch_cs
);
1312 if (this_obj
->name
) {
1313 LeaveCriticalSection (this_obj
->synch_cs
);
1315 mono_raise_exception (mono_get_exception_invalid_operation ("Thread.Name can only be set once."));
1319 this_obj
->name
= g_new (gunichar2
, mono_string_length (name
));
1320 memcpy (this_obj
->name
, mono_string_chars (name
), mono_string_length (name
) * 2);
1321 this_obj
->name_len
= mono_string_length (name
);
1324 this_obj
->name
= NULL
;
1326 LeaveCriticalSection (this_obj
->synch_cs
);
1330 lookup_cached_culture (MonoInternalThread
*this, MonoDomain
*domain
, int start_idx
)
1335 if (this->cached_culture_info
) {
1336 domain
= mono_domain_get ();
1337 for (i
= start_idx
; i
< start_idx
+ NUM_CACHED_CULTURES
; ++i
) {
1338 res
= mono_array_get (this->cached_culture_info
, MonoObject
*, i
);
1339 if (res
&& res
->vtable
->domain
== domain
)
1347 /* If the array is already in the requested domain, we just return it,
1348 otherwise we return a copy in that domain. */
1350 byte_array_to_domain (MonoArray
*arr
, MonoDomain
*domain
)
1357 if (mono_object_domain (arr
) == domain
)
1360 copy
= mono_array_new (domain
, mono_defaults
.byte_class
, arr
->max_length
);
1361 memcpy (mono_array_addr (copy
, guint8
, 0), mono_array_addr (arr
, guint8
, 0), arr
->max_length
);
1366 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray
*arr
)
1368 return byte_array_to_domain (arr
, mono_get_root_domain ());
1372 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray
*arr
)
1374 return byte_array_to_domain (arr
, mono_domain_get ());
1378 ves_icall_System_Threading_Thread_GetCachedCurrentCulture (MonoInternalThread
*this)
1380 return lookup_cached_culture (this, mono_domain_get (), CULTURES_START_IDX
);
1384 cache_culture (MonoInternalThread
*this, MonoObject
*culture
, int start_idx
)
1387 MonoDomain
*domain
= mono_domain_get ();
1390 int same_domain_slot
= -1;
1392 ensure_synch_cs_set (this);
1394 EnterCriticalSection (this->synch_cs
);
1396 if (!this->cached_culture_info
)
1397 MONO_OBJECT_SETREF (this, cached_culture_info
, mono_array_new_cached (mono_get_root_domain (), mono_defaults
.object_class
, NUM_CACHED_CULTURES
* 2));
1399 for (i
= start_idx
; i
< start_idx
+ NUM_CACHED_CULTURES
; ++i
) {
1400 obj
= mono_array_get (this->cached_culture_info
, MonoObject
*, i
);
1404 /* we continue, because there may be a slot used with the same domain */
1408 if (obj
->vtable
->domain
== domain
) {
1409 same_domain_slot
= i
;
1413 if (same_domain_slot
>= 0)
1414 mono_array_setref (this->cached_culture_info
, same_domain_slot
, culture
);
1415 else if (free_slot
>= 0)
1416 mono_array_setref (this->cached_culture_info
, free_slot
, culture
);
1417 /* we may want to replace an existing entry here, even when no suitable slot is found */
1419 LeaveCriticalSection (this->synch_cs
);
1423 ves_icall_System_Threading_Thread_SetCachedCurrentCulture (MonoThread
*this, MonoObject
*culture
)
1425 MonoDomain
*domain
= mono_object_get_domain (&this->obj
);
1426 g_assert (domain
== mono_domain_get ());
1427 cache_culture (this->internal_thread
, culture
, CULTURES_START_IDX
);
1431 ves_icall_System_Threading_Thread_GetCachedCurrentUICulture (MonoInternalThread
*this)
1433 return lookup_cached_culture (this, mono_domain_get (), UICULTURES_START_IDX
);
1437 ves_icall_System_Threading_Thread_SetCachedCurrentUICulture (MonoThread
*this, MonoObject
*culture
)
1439 MonoDomain
*domain
= mono_object_get_domain (&this->obj
);
1440 g_assert (domain
== mono_domain_get ());
1441 cache_culture (this->internal_thread
, culture
, UICULTURES_START_IDX
);
1445 mono_thread_current (void)
1447 MonoDomain
*domain
= mono_domain_get ();
1448 MonoInternalThread
*internal
= mono_thread_internal_current ();
1449 MonoThread
**current_thread_ptr
;
1451 g_assert (internal
);
1452 current_thread_ptr
= get_current_thread_ptr_for_domain (domain
, internal
);
1454 if (!*current_thread_ptr
) {
1455 g_assert (domain
!= mono_get_root_domain ());
1456 *current_thread_ptr
= new_thread_with_internal (domain
, internal
);
1458 return *current_thread_ptr
;
1462 mono_thread_internal_current (void)
1464 MonoInternalThread
*res
= GET_CURRENT_OBJECT ();
1465 THREAD_DEBUG (g_message ("%s: returning %p", __func__
, res
));
1469 gboolean
ves_icall_System_Threading_Thread_Join_internal(MonoInternalThread
*this,
1470 int ms
, HANDLE thread
)
1472 MonoInternalThread
*cur_thread
= mono_thread_internal_current ();
1475 mono_thread_current_check_pending_interrupt ();
1477 ensure_synch_cs_set (this);
1479 EnterCriticalSection (this->synch_cs
);
1481 if ((this->state
& ThreadState_Unstarted
) != 0) {
1482 LeaveCriticalSection (this->synch_cs
);
1484 mono_raise_exception (mono_get_exception_thread_state ("Thread has not been started."));
1488 LeaveCriticalSection (this->synch_cs
);
1493 THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__
, thread
, ms
));
1495 mono_thread_set_state (cur_thread
, ThreadState_WaitSleepJoin
);
1497 ret
=WaitForSingleObjectEx (thread
, ms
, TRUE
);
1499 mono_thread_clr_state (cur_thread
, ThreadState_WaitSleepJoin
);
1501 if(ret
==WAIT_OBJECT_0
) {
1502 THREAD_DEBUG (g_message ("%s: join successful", __func__
));
1507 THREAD_DEBUG (g_message ("%s: join failed", __func__
));
1512 /* FIXME: exitContext isnt documented */
1513 gboolean
ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray
*mono_handles
, gint32 ms
, gboolean exitContext
)
1519 MonoObject
*waitHandle
;
1520 MonoInternalThread
*thread
= mono_thread_internal_current ();
1522 /* Do this WaitSleepJoin check before creating objects */
1523 mono_thread_current_check_pending_interrupt ();
1525 numhandles
= mono_array_length(mono_handles
);
1526 handles
= g_new0(HANDLE
, numhandles
);
1528 for(i
= 0; i
< numhandles
; i
++) {
1529 waitHandle
= mono_array_get(mono_handles
, MonoObject
*, i
);
1530 handles
[i
] = mono_wait_handle_get_handle ((MonoWaitHandle
*) waitHandle
);
1537 mono_thread_set_state (thread
, ThreadState_WaitSleepJoin
);
1539 ret
=WaitForMultipleObjectsEx(numhandles
, handles
, TRUE
, ms
, TRUE
);
1541 mono_thread_clr_state (thread
, ThreadState_WaitSleepJoin
);
1545 if(ret
==WAIT_FAILED
) {
1546 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT
") Wait failed", __func__
, GetCurrentThreadId ()));
1548 } else if(ret
==WAIT_TIMEOUT
|| ret
== WAIT_IO_COMPLETION
) {
1549 /* Do we want to try again if we get
1550 * WAIT_IO_COMPLETION? The documentation for
1551 * WaitHandle doesn't give any clues. (We'd have to
1552 * fiddle with the timeout if we retry.)
1554 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT
") Wait timed out", __func__
, GetCurrentThreadId ()));
1561 /* FIXME: exitContext isnt documented */
1562 gint32
ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray
*mono_handles
, gint32 ms
, gboolean exitContext
)
1568 MonoObject
*waitHandle
;
1569 MonoInternalThread
*thread
= mono_thread_internal_current ();
1571 /* Do this WaitSleepJoin check before creating objects */
1572 mono_thread_current_check_pending_interrupt ();
1574 numhandles
= mono_array_length(mono_handles
);
1575 handles
= g_new0(HANDLE
, numhandles
);
1577 for(i
= 0; i
< numhandles
; i
++) {
1578 waitHandle
= mono_array_get(mono_handles
, MonoObject
*, i
);
1579 handles
[i
] = mono_wait_handle_get_handle ((MonoWaitHandle
*) waitHandle
);
1586 mono_thread_set_state (thread
, ThreadState_WaitSleepJoin
);
1588 ret
=WaitForMultipleObjectsEx(numhandles
, handles
, FALSE
, ms
, TRUE
);
1590 mono_thread_clr_state (thread
, ThreadState_WaitSleepJoin
);
1594 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT
") returning %d", __func__
, GetCurrentThreadId (), ret
));
1597 * These need to be here. See MSDN dos on WaitForMultipleObjects.
1599 if (ret
>= WAIT_OBJECT_0
&& ret
<= WAIT_OBJECT_0
+ numhandles
- 1) {
1600 return ret
- WAIT_OBJECT_0
;
1602 else if (ret
>= WAIT_ABANDONED_0
&& ret
<= WAIT_ABANDONED_0
+ numhandles
- 1) {
1603 return ret
- WAIT_ABANDONED_0
;
1610 /* FIXME: exitContext isnt documented */
1611 gboolean
ves_icall_System_Threading_WaitHandle_WaitOne_internal(MonoObject
*this, HANDLE handle
, gint32 ms
, gboolean exitContext
)
1614 MonoInternalThread
*thread
= mono_thread_internal_current ();
1616 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT
") waiting for %p, %d ms", __func__
, GetCurrentThreadId (), handle
, ms
));
1622 mono_thread_current_check_pending_interrupt ();
1624 mono_thread_set_state (thread
, ThreadState_WaitSleepJoin
);
1626 ret
=WaitForSingleObjectEx (handle
, ms
, TRUE
);
1628 mono_thread_clr_state (thread
, ThreadState_WaitSleepJoin
);
1630 if(ret
==WAIT_FAILED
) {
1631 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT
") Wait failed", __func__
, GetCurrentThreadId ()));
1633 } else if(ret
==WAIT_TIMEOUT
|| ret
== WAIT_IO_COMPLETION
) {
1634 /* Do we want to try again if we get
1635 * WAIT_IO_COMPLETION? The documentation for
1636 * WaitHandle doesn't give any clues. (We'd have to
1637 * fiddle with the timeout if we retry.)
1639 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT
") Wait timed out", __func__
, GetCurrentThreadId ()));
1647 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal
, HANDLE toWait
, gint32 ms
, gboolean exitContext
)
1650 MonoInternalThread
*thread
= mono_thread_internal_current ();
1652 MONO_ARCH_SAVE_REGS
;
1657 mono_thread_current_check_pending_interrupt ();
1659 mono_thread_set_state (thread
, ThreadState_WaitSleepJoin
);
1661 ret
= SignalObjectAndWait (toSignal
, toWait
, ms
, TRUE
);
1663 mono_thread_clr_state (thread
, ThreadState_WaitSleepJoin
);
1665 return (!(ret
== WAIT_TIMEOUT
|| ret
== WAIT_IO_COMPLETION
|| ret
== WAIT_FAILED
));
1668 HANDLE
ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned
, MonoString
*name
, MonoBoolean
*created
)
1672 MONO_ARCH_SAVE_REGS
;
1677 mutex
= CreateMutex (NULL
, owned
, NULL
);
1679 mutex
= CreateMutex (NULL
, owned
, mono_string_chars (name
));
1681 if (GetLastError () == ERROR_ALREADY_EXISTS
) {
1689 MonoBoolean
ves_icall_System_Threading_Mutex_ReleaseMutex_internal (HANDLE handle
) {
1690 MONO_ARCH_SAVE_REGS
;
1692 return(ReleaseMutex (handle
));
1695 HANDLE
ves_icall_System_Threading_Mutex_OpenMutex_internal (MonoString
*name
,
1701 MONO_ARCH_SAVE_REGS
;
1703 *error
= ERROR_SUCCESS
;
1705 ret
= OpenMutex (rights
, FALSE
, mono_string_chars (name
));
1707 *error
= GetLastError ();
1714 HANDLE
ves_icall_System_Threading_Semaphore_CreateSemaphore_internal (gint32 initialCount
, gint32 maximumCount
, MonoString
*name
, MonoBoolean
*created
)
1718 MONO_ARCH_SAVE_REGS
;
1723 sem
= CreateSemaphore (NULL
, initialCount
, maximumCount
, NULL
);
1725 sem
= CreateSemaphore (NULL
, initialCount
, maximumCount
,
1726 mono_string_chars (name
));
1728 if (GetLastError () == ERROR_ALREADY_EXISTS
) {
1736 gint32
ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal (HANDLE handle
, gint32 releaseCount
, MonoBoolean
*fail
)
1740 MONO_ARCH_SAVE_REGS
;
1742 *fail
= !ReleaseSemaphore (handle
, releaseCount
, &prevcount
);
1747 HANDLE
ves_icall_System_Threading_Semaphore_OpenSemaphore_internal (MonoString
*name
, gint32 rights
, gint32
*error
)
1751 MONO_ARCH_SAVE_REGS
;
1753 *error
= ERROR_SUCCESS
;
1755 ret
= OpenSemaphore (rights
, FALSE
, mono_string_chars (name
));
1757 *error
= GetLastError ();
1763 HANDLE
ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manual
, MonoBoolean initial
, MonoString
*name
, MonoBoolean
*created
)
1767 MONO_ARCH_SAVE_REGS
;
1772 event
= CreateEvent (NULL
, manual
, initial
, NULL
);
1774 event
= CreateEvent (NULL
, manual
, initial
,
1775 mono_string_chars (name
));
1777 if (GetLastError () == ERROR_ALREADY_EXISTS
) {
1785 gboolean
ves_icall_System_Threading_Events_SetEvent_internal (HANDLE handle
) {
1786 MONO_ARCH_SAVE_REGS
;
1788 return (SetEvent(handle
));
1791 gboolean
ves_icall_System_Threading_Events_ResetEvent_internal (HANDLE handle
) {
1792 MONO_ARCH_SAVE_REGS
;
1794 return (ResetEvent(handle
));
1798 ves_icall_System_Threading_Events_CloseEvent_internal (HANDLE handle
) {
1799 MONO_ARCH_SAVE_REGS
;
1801 CloseHandle (handle
);
1804 HANDLE
ves_icall_System_Threading_Events_OpenEvent_internal (MonoString
*name
,
1810 MONO_ARCH_SAVE_REGS
;
1812 *error
= ERROR_SUCCESS
;
1814 ret
= OpenEvent (rights
, FALSE
, mono_string_chars (name
));
1816 *error
= GetLastError ();
1822 gint32
ves_icall_System_Threading_Interlocked_Increment_Int (gint32
*location
)
1824 MONO_ARCH_SAVE_REGS
;
1826 return InterlockedIncrement (location
);
1829 gint64
ves_icall_System_Threading_Interlocked_Increment_Long (gint64
*location
)
1833 MONO_ARCH_SAVE_REGS
;
1835 mono_interlocked_lock ();
1839 mono_interlocked_unlock ();
1845 gint32
ves_icall_System_Threading_Interlocked_Decrement_Int (gint32
*location
)
1847 MONO_ARCH_SAVE_REGS
;
1849 return InterlockedDecrement(location
);
1852 gint64
ves_icall_System_Threading_Interlocked_Decrement_Long (gint64
* location
)
1856 MONO_ARCH_SAVE_REGS
;
1858 mono_interlocked_lock ();
1862 mono_interlocked_unlock ();
1867 gint32
ves_icall_System_Threading_Interlocked_Exchange_Int (gint32
*location
, gint32 value
)
1869 MONO_ARCH_SAVE_REGS
;
1871 return InterlockedExchange(location
, value
);
1874 MonoObject
* ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject
**location
, MonoObject
*value
)
1877 res
= (MonoObject
*) InterlockedExchangePointer((gpointer
*) location
, value
);
1878 mono_gc_wbarrier_generic_nostore (location
);
1882 gpointer
ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer
*location
, gpointer value
)
1884 return InterlockedExchangePointer(location
, value
);
1887 gfloat
ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat
*location
, gfloat value
)
1889 IntFloatUnion val
, ret
;
1891 MONO_ARCH_SAVE_REGS
;
1894 ret
.ival
= InterlockedExchange((gint32
*) location
, val
.ival
);
1900 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64
*location
, gint64 value
)
1902 #if SIZEOF_VOID_P == 8
1903 return (gint64
) InterlockedExchangePointer((gpointer
*) location
, (gpointer
)value
);
1908 * According to MSDN, this function is only atomic with regards to the
1909 * other Interlocked functions on 32 bit platforms.
1911 mono_interlocked_lock ();
1914 mono_interlocked_unlock ();
1921 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble
*location
, gdouble value
)
1923 #if SIZEOF_VOID_P == 8
1924 LongDoubleUnion val
, ret
;
1927 ret
.ival
= (gint64
)InterlockedExchangePointer((gpointer
*) location
, (gpointer
)val
.ival
);
1934 * According to MSDN, this function is only atomic with regards to the
1935 * other Interlocked functions on 32 bit platforms.
1937 mono_interlocked_lock ();
1940 mono_interlocked_unlock ();
1946 gint32
ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32
*location
, gint32 value
, gint32 comparand
)
1948 MONO_ARCH_SAVE_REGS
;
1950 return InterlockedCompareExchange(location
, value
, comparand
);
1953 MonoObject
* ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject
**location
, MonoObject
*value
, MonoObject
*comparand
)
1956 res
= (MonoObject
*) InterlockedCompareExchangePointer((gpointer
*) location
, value
, comparand
);
1957 mono_gc_wbarrier_generic_nostore (location
);
1961 gpointer
ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer
*location
, gpointer value
, gpointer comparand
)
1963 return InterlockedCompareExchangePointer(location
, value
, comparand
);
1966 gfloat
ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat
*location
, gfloat value
, gfloat comparand
)
1968 IntFloatUnion val
, ret
, cmp
;
1970 MONO_ARCH_SAVE_REGS
;
1973 cmp
.fval
= comparand
;
1974 ret
.ival
= InterlockedCompareExchange((gint32
*) location
, val
.ival
, cmp
.ival
);
1980 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble
*location
, gdouble value
, gdouble comparand
)
1982 #if SIZEOF_VOID_P == 8
1983 LongDoubleUnion val
, comp
, ret
;
1986 comp
.fval
= comparand
;
1987 ret
.ival
= (gint64
)InterlockedCompareExchangePointer((gpointer
*) location
, (gpointer
)val
.ival
, (gpointer
)comp
.ival
);
1993 mono_interlocked_lock ();
1995 if (old
== comparand
)
1997 mono_interlocked_unlock ();
2004 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64
*location
, gint64 value
, gint64 comparand
)
2006 #if SIZEOF_VOID_P == 8
2007 return (gint64
)InterlockedCompareExchangePointer((gpointer
*) location
, (gpointer
)value
, (gpointer
)comparand
);
2011 mono_interlocked_lock ();
2013 if (old
== comparand
)
2015 mono_interlocked_unlock ();
2022 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject
**location
, MonoObject
*value
, MonoObject
*comparand
)
2025 res
= InterlockedCompareExchangePointer ((gpointer
*)location
, value
, comparand
);
2026 mono_gc_wbarrier_generic_nostore (location
);
2031 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject
**location
, MonoObject
*value
)
2034 res
= InterlockedExchangePointer ((gpointer
*)location
, value
);
2035 mono_gc_wbarrier_generic_nostore (location
);
2040 ves_icall_System_Threading_Interlocked_Add_Int (gint32
*location
, gint32 value
)
2042 #if SIZEOF_VOID_P == 8
2043 /* Should be implemented as a JIT intrinsic */
2044 mono_raise_exception (mono_get_exception_not_implemented (NULL
));
2049 mono_interlocked_lock ();
2051 *location
= orig
+ value
;
2052 mono_interlocked_unlock ();
2054 return orig
+ value
;
2059 ves_icall_System_Threading_Interlocked_Add_Long (gint64
*location
, gint64 value
)
2061 #if SIZEOF_VOID_P == 8
2062 /* Should be implemented as a JIT intrinsic */
2063 mono_raise_exception (mono_get_exception_not_implemented (NULL
));
2068 mono_interlocked_lock ();
2070 *location
= orig
+ value
;
2071 mono_interlocked_unlock ();
2073 return orig
+ value
;
2078 ves_icall_System_Threading_Interlocked_Read_Long (gint64
*location
)
2080 #if SIZEOF_VOID_P == 8
2081 /* 64 bit reads are already atomic */
2086 mono_interlocked_lock ();
2088 mono_interlocked_unlock ();
2095 ves_icall_System_Threading_Thread_MemoryBarrier (void)
2097 mono_threads_lock ();
2098 mono_threads_unlock ();
2102 ves_icall_System_Threading_Thread_ClrState (MonoInternalThread
* this, guint32 state
)
2104 mono_thread_clr_state (this, state
);
2106 if (state
& ThreadState_Background
) {
2107 /* If the thread changes the background mode, the main thread has to
2108 * be notified, since it has to rebuild the list of threads to
2111 SetEvent (background_change_event
);
2116 ves_icall_System_Threading_Thread_SetState (MonoInternalThread
* this, guint32 state
)
2118 mono_thread_set_state (this, state
);
2120 if (state
& ThreadState_Background
) {
2121 /* If the thread changes the background mode, the main thread has to
2122 * be notified, since it has to rebuild the list of threads to
2125 SetEvent (background_change_event
);
2130 ves_icall_System_Threading_Thread_GetState (MonoInternalThread
* this)
2134 ensure_synch_cs_set (this);
2136 EnterCriticalSection (this->synch_cs
);
2138 state
= this->state
;
2140 LeaveCriticalSection (this->synch_cs
);
2145 void ves_icall_System_Threading_Thread_Interrupt_internal (MonoInternalThread
*this)
2147 gboolean
throw = FALSE
;
2149 ensure_synch_cs_set (this);
2151 if (this == mono_thread_internal_current ())
2154 EnterCriticalSection (this->synch_cs
);
2156 this->thread_interrupt_requested
= TRUE
;
2158 if (this->state
& ThreadState_WaitSleepJoin
) {
2162 LeaveCriticalSection (this->synch_cs
);
2165 signal_thread_state_change (this);
2169 void mono_thread_current_check_pending_interrupt ()
2171 MonoInternalThread
*thread
= mono_thread_internal_current ();
2172 gboolean
throw = FALSE
;
2174 mono_debugger_check_interruption ();
2176 ensure_synch_cs_set (thread
);
2178 EnterCriticalSection (thread
->synch_cs
);
2180 if (thread
->thread_interrupt_requested
) {
2182 thread
->thread_interrupt_requested
= FALSE
;
2185 LeaveCriticalSection (thread
->synch_cs
);
2188 mono_raise_exception (mono_get_exception_thread_interrupted ());
2193 mono_thread_get_abort_signal (void)
2205 static int abort_signum
= -1;
2207 if (abort_signum
!= -1)
2208 return abort_signum
;
2209 /* we try to avoid SIGRTMIN and any one that might have been set already, see bug #75387 */
2210 for (i
= SIGRTMIN
+ 1; i
< SIGRTMAX
; ++i
) {
2211 struct sigaction sinfo
;
2212 sigaction (i
, NULL
, &sinfo
);
2213 if (sinfo
.sa_handler
== SIG_DFL
&& (void*)sinfo
.sa_sigaction
== (void*)SIG_DFL
) {
2218 /* fallback to the old way */
2221 #endif /* HOST_WIN32 */
2225 static void CALLBACK
interruption_request_apc (ULONG_PTR param
)
2227 MonoException
* exc
= mono_thread_request_interruption (FALSE
);
2228 if (exc
) mono_raise_exception (exc
);
2230 #endif /* HOST_WIN32 */
2233 * signal_thread_state_change
2235 * Tells the thread that his state has changed and it has to enter the new
2236 * state as soon as possible.
2238 static void signal_thread_state_change (MonoInternalThread
*thread
)
2240 if (thread
== mono_thread_internal_current ()) {
2241 /* Do it synchronously */
2242 MonoException
*exc
= mono_thread_request_interruption (FALSE
);
2244 mono_raise_exception (exc
);
2248 QueueUserAPC ((PAPCFUNC
)interruption_request_apc
, thread
->handle
, NULL
);
2250 /* fixme: store the state somewhere */
2251 #ifdef PTHREAD_POINTER_ID
2252 pthread_kill ((gpointer
)(gsize
)(thread
->tid
), mono_thread_get_abort_signal ());
2254 pthread_kill (thread
->tid
, mono_thread_get_abort_signal ());
2258 * This will cause waits to be broken.
2259 * It will also prevent the thread from entering a wait, so if the thread returns
2260 * from the wait before it receives the abort signal, it will just spin in the wait
2261 * functions in the io-layer until the signal handler calls QueueUserAPC which will
2264 wapi_interrupt_thread (thread
->handle
);
2265 #endif /* HOST_WIN32 */
2269 ves_icall_System_Threading_Thread_Abort (MonoInternalThread
*thread
, MonoObject
*state
)
2271 ensure_synch_cs_set (thread
);
2273 EnterCriticalSection (thread
->synch_cs
);
2275 if ((thread
->state
& ThreadState_AbortRequested
) != 0 ||
2276 (thread
->state
& ThreadState_StopRequested
) != 0 ||
2277 (thread
->state
& ThreadState_Stopped
) != 0)
2279 LeaveCriticalSection (thread
->synch_cs
);
2283 if ((thread
->state
& ThreadState_Unstarted
) != 0) {
2284 thread
->state
|= ThreadState_Aborted
;
2285 LeaveCriticalSection (thread
->synch_cs
);
2289 thread
->state
|= ThreadState_AbortRequested
;
2290 if (thread
->abort_state_handle
)
2291 mono_gchandle_free (thread
->abort_state_handle
);
2293 thread
->abort_state_handle
= mono_gchandle_new (state
, FALSE
);
2294 g_assert (thread
->abort_state_handle
);
2296 thread
->abort_state_handle
= 0;
2298 thread
->abort_exc
= NULL
;
2301 * abort_exc is set in mono_thread_execute_interruption(),
2302 * triggered by the call to signal_thread_state_change(),
2303 * below. There's a point between where we have
2304 * abort_state_handle set, but abort_exc NULL, but that's not
2308 LeaveCriticalSection (thread
->synch_cs
);
2310 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT
") Abort requested for %p (%"G_GSIZE_FORMAT
")", __func__
, GetCurrentThreadId (), thread
, (gsize
)thread
->tid
));
2312 /* During shutdown, we can't wait for other threads */
2314 /* Make sure the thread is awake */
2315 mono_thread_resume (thread
);
2317 signal_thread_state_change (thread
);
2321 ves_icall_System_Threading_Thread_ResetAbort (void)
2323 MonoInternalThread
*thread
= mono_thread_internal_current ();
2325 ensure_synch_cs_set (thread
);
2327 EnterCriticalSection (thread
->synch_cs
);
2329 thread
->state
&= ~ThreadState_AbortRequested
;
2331 if (!thread
->abort_exc
) {
2332 const char *msg
= "Unable to reset abort because no abort was requested";
2333 LeaveCriticalSection (thread
->synch_cs
);
2334 mono_raise_exception (mono_get_exception_thread_state (msg
));
2336 thread
->abort_exc
= NULL
;
2337 if (thread
->abort_state_handle
) {
2338 mono_gchandle_free (thread
->abort_state_handle
);
2339 /* This is actually not necessary - the handle
2340 only counts if the exception is set */
2341 thread
->abort_state_handle
= 0;
2345 LeaveCriticalSection (thread
->synch_cs
);
2349 mono_thread_internal_reset_abort (MonoInternalThread
*thread
)
2351 ensure_synch_cs_set (thread
);
2353 EnterCriticalSection (thread
->synch_cs
);
2355 thread
->state
&= ~ThreadState_AbortRequested
;
2357 if (thread
->abort_exc
) {
2358 thread
->abort_exc
= NULL
;
2359 if (thread
->abort_state_handle
) {
2360 mono_gchandle_free (thread
->abort_state_handle
);
2361 /* This is actually not necessary - the handle
2362 only counts if the exception is set */
2363 thread
->abort_state_handle
= 0;
2367 LeaveCriticalSection (thread
->synch_cs
);
2371 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread
*this)
2373 MonoInternalThread
*thread
= this->internal_thread
;
2374 MonoObject
*state
, *deserialized
= NULL
, *exc
;
2377 if (!thread
->abort_state_handle
)
2380 state
= mono_gchandle_get_target (thread
->abort_state_handle
);
2383 domain
= mono_domain_get ();
2384 if (mono_object_domain (state
) == domain
)
2387 deserialized
= mono_object_xdomain_representation (state
, domain
, &exc
);
2389 if (!deserialized
) {
2390 MonoException
*invalid_op_exc
= mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
2392 MONO_OBJECT_SETREF (invalid_op_exc
, inner_ex
, exc
);
2393 mono_raise_exception (invalid_op_exc
);
2396 return deserialized
;
2400 mono_thread_suspend (MonoInternalThread
*thread
)
2402 ensure_synch_cs_set (thread
);
2404 EnterCriticalSection (thread
->synch_cs
);
2406 if ((thread
->state
& ThreadState_Unstarted
) != 0 ||
2407 (thread
->state
& ThreadState_Aborted
) != 0 ||
2408 (thread
->state
& ThreadState_Stopped
) != 0)
2410 LeaveCriticalSection (thread
->synch_cs
);
2414 if ((thread
->state
& ThreadState_Suspended
) != 0 ||
2415 (thread
->state
& ThreadState_SuspendRequested
) != 0 ||
2416 (thread
->state
& ThreadState_StopRequested
) != 0)
2418 LeaveCriticalSection (thread
->synch_cs
);
2422 thread
->state
|= ThreadState_SuspendRequested
;
2424 LeaveCriticalSection (thread
->synch_cs
);
2426 signal_thread_state_change (thread
);
2431 ves_icall_System_Threading_Thread_Suspend (MonoInternalThread
*thread
)
2433 if (!mono_thread_suspend (thread
))
2434 mono_raise_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2438 mono_thread_resume (MonoInternalThread
*thread
)
2440 ensure_synch_cs_set (thread
);
2442 EnterCriticalSection (thread
->synch_cs
);
2444 if ((thread
->state
& ThreadState_SuspendRequested
) != 0) {
2445 thread
->state
&= ~ThreadState_SuspendRequested
;
2446 LeaveCriticalSection (thread
->synch_cs
);
2450 if ((thread
->state
& ThreadState_Suspended
) == 0 ||
2451 (thread
->state
& ThreadState_Unstarted
) != 0 ||
2452 (thread
->state
& ThreadState_Aborted
) != 0 ||
2453 (thread
->state
& ThreadState_Stopped
) != 0)
2455 LeaveCriticalSection (thread
->synch_cs
);
2459 thread
->resume_event
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
2460 if (thread
->resume_event
== NULL
) {
2461 LeaveCriticalSection (thread
->synch_cs
);
2465 /* Awake the thread */
2466 SetEvent (thread
->suspend_event
);
2468 LeaveCriticalSection (thread
->synch_cs
);
2470 /* Wait for the thread to awake */
2471 WaitForSingleObject (thread
->resume_event
, INFINITE
);
2472 CloseHandle (thread
->resume_event
);
2473 thread
->resume_event
= NULL
;
2479 ves_icall_System_Threading_Thread_Resume (MonoThread
*thread
)
2481 if (!thread
->internal_thread
|| !mono_thread_resume (thread
->internal_thread
))
2482 mono_raise_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2486 find_wrapper (MonoMethod
*m
, gint no
, gint ilo
, gboolean managed
, gpointer data
)
2491 if (m
->wrapper_type
== MONO_WRAPPER_RUNTIME_INVOKE
||
2492 m
->wrapper_type
== MONO_WRAPPER_XDOMAIN_INVOKE
||
2493 m
->wrapper_type
== MONO_WRAPPER_XDOMAIN_DISPATCH
)
2495 *((gboolean
*)data
) = TRUE
;
2502 is_running_protected_wrapper (void)
2504 gboolean found
= FALSE
;
2505 mono_stack_walk (find_wrapper
, &found
);
2509 void mono_thread_internal_stop (MonoInternalThread
*thread
)
2511 ensure_synch_cs_set (thread
);
2513 EnterCriticalSection (thread
->synch_cs
);
2515 if ((thread
->state
& ThreadState_StopRequested
) != 0 ||
2516 (thread
->state
& ThreadState_Stopped
) != 0)
2518 LeaveCriticalSection (thread
->synch_cs
);
2522 /* Make sure the thread is awake */
2523 mono_thread_resume (thread
);
2525 thread
->state
|= ThreadState_StopRequested
;
2526 thread
->state
&= ~ThreadState_AbortRequested
;
2528 LeaveCriticalSection (thread
->synch_cs
);
2530 signal_thread_state_change (thread
);
2533 void mono_thread_stop (MonoThread
*thread
)
2535 mono_thread_internal_stop (thread
->internal_thread
);
2539 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr
)
2541 return *((volatile gint8
*) (ptr
));
2545 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr
)
2547 return *((volatile gint16
*) (ptr
));
2551 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr
)
2553 return *((volatile gint32
*) (ptr
));
2557 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr
)
2559 return *((volatile gint64
*) (ptr
));
2563 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr
)
2565 return (void *) *((volatile void **) ptr
);
2569 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr
, gint8 value
)
2571 *((volatile gint8
*) ptr
) = value
;
2575 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr
, gint16 value
)
2577 *((volatile gint16
*) ptr
) = value
;
2581 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr
, gint32 value
)
2583 *((volatile gint32
*) ptr
) = value
;
2587 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr
, gint64 value
)
2589 *((volatile gint64
*) ptr
) = value
;
2593 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr
, void *value
)
2595 *((volatile void **) ptr
) = value
;
2599 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr
, void *value
)
2601 mono_gc_wbarrier_generic_store (ptr
, value
);
2604 void mono_thread_init (MonoThreadStartCB start_cb
,
2605 MonoThreadAttachCB attach_cb
)
2607 MONO_GC_REGISTER_ROOT (small_id_table
);
2608 InitializeCriticalSection(&threads_mutex
);
2609 InitializeCriticalSection(&interlocked_mutex
);
2610 InitializeCriticalSection(&contexts_mutex
);
2611 InitializeCriticalSection(&delayed_free_table_mutex
);
2612 InitializeCriticalSection(&small_id_mutex
);
2614 background_change_event
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
2615 g_assert(background_change_event
!= NULL
);
2617 mono_init_static_data_info (&thread_static_info
);
2618 mono_init_static_data_info (&context_static_info
);
2620 current_object_key
=TlsAlloc();
2621 THREAD_DEBUG (g_message ("%s: Allocated current_object_key %d", __func__
, current_object_key
));
2623 mono_thread_start_cb
= start_cb
;
2624 mono_thread_attach_cb
= attach_cb
;
2626 delayed_free_table
= g_array_new (FALSE
, FALSE
, sizeof (DelayedFreeItem
));
2628 /* Get a pseudo handle to the current process. This is just a
2629 * kludge so that wapi can build a process handle if needed.
2630 * As a pseudo handle is returned, we don't need to clean
2633 GetCurrentProcess ();
2636 void mono_thread_cleanup (void)
2638 mono_thread_hazardous_try_free_all ();
2640 #if !defined(HOST_WIN32) && !defined(RUN_IN_SUBTHREAD)
2641 /* The main thread must abandon any held mutexes (particularly
2642 * important for named mutexes as they are shared across
2643 * processes, see bug 74680.) This will happen when the
2644 * thread exits, but if it's not running in a subthread it
2645 * won't exit in time.
2647 /* Using non-w32 API is a nasty kludge, but I couldn't find
2648 * anything in the documentation that would let me do this
2649 * here yet still be safe to call on windows.
2651 _wapi_thread_signal_self (mono_environment_exitcode_get ());
2655 /* This stuff needs more testing, it seems one of these
2656 * critical sections can be locked when mono_thread_cleanup is
2659 DeleteCriticalSection (&threads_mutex
);
2660 DeleteCriticalSection (&interlocked_mutex
);
2661 DeleteCriticalSection (&contexts_mutex
);
2662 DeleteCriticalSection (&delayed_free_table_mutex
);
2663 DeleteCriticalSection (&small_id_mutex
);
2664 CloseHandle (background_change_event
);
2667 g_array_free (delayed_free_table
, TRUE
);
2668 delayed_free_table
= NULL
;
2670 TlsFree (current_object_key
);
2674 mono_threads_install_cleanup (MonoThreadCleanupFunc func
)
2676 mono_thread_cleanup_fn
= func
;
2680 mono_thread_set_manage_callback (MonoThread
*thread
, MonoThreadManageCallback func
)
2682 thread
->internal_thread
->manage_callback
= func
;
2685 void mono_threads_install_notify_pending_exc (MonoThreadNotifyPendingExcFunc func
)
2687 mono_thread_notify_pending_exc_fn
= func
;
2691 static void print_tids (gpointer key
, gpointer value
, gpointer user
)
2693 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
2694 * sizeof(uint) and a cast to uint would overflow
2696 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
2697 * print this as a pointer.
2699 g_message ("Waiting for: %p", key
);
2704 HANDLE handles
[MAXIMUM_WAIT_OBJECTS
];
2705 MonoInternalThread
*threads
[MAXIMUM_WAIT_OBJECTS
];
2709 static void wait_for_tids (struct wait_data
*wait
, guint32 timeout
)
2713 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__
, wait
->num
));
2715 ret
=WaitForMultipleObjectsEx(wait
->num
, wait
->handles
, TRUE
, timeout
, FALSE
);
2717 if(ret
==WAIT_FAILED
) {
2718 /* See the comment in build_wait_tids() */
2719 THREAD_DEBUG (g_message ("%s: Wait failed", __func__
));
2723 for(i
=0; i
<wait
->num
; i
++)
2724 CloseHandle (wait
->handles
[i
]);
2726 if (ret
== WAIT_TIMEOUT
)
2729 for(i
=0; i
<wait
->num
; i
++) {
2730 gsize tid
= wait
->threads
[i
]->tid
;
2732 mono_threads_lock ();
2733 if(mono_g_hash_table_lookup (threads
, (gpointer
)tid
)!=NULL
) {
2734 /* This thread must have been killed, because
2735 * it hasn't cleaned itself up. (It's just
2736 * possible that the thread exited before the
2737 * parent thread had a chance to store the
2738 * handle, and now there is another pointer to
2739 * the already-exited thread stored. In this
2740 * case, we'll just get two
2741 * mono_profiler_thread_end() calls for the
2745 mono_threads_unlock ();
2746 THREAD_DEBUG (g_message ("%s: cleaning up after thread %p (%"G_GSIZE_FORMAT
")", __func__
, wait
->threads
[i
], tid
));
2747 thread_cleanup (wait
->threads
[i
]);
2749 mono_threads_unlock ();
2754 static void wait_for_tids_or_state_change (struct wait_data
*wait
, guint32 timeout
)
2756 guint32 i
, ret
, count
;
2758 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__
, wait
->num
));
2760 /* Add the thread state change event, so it wakes up if a thread changes
2761 * to background mode.
2764 if (count
< MAXIMUM_WAIT_OBJECTS
) {
2765 wait
->handles
[count
] = background_change_event
;
2769 ret
=WaitForMultipleObjectsEx (count
, wait
->handles
, FALSE
, timeout
, FALSE
);
2771 if(ret
==WAIT_FAILED
) {
2772 /* See the comment in build_wait_tids() */
2773 THREAD_DEBUG (g_message ("%s: Wait failed", __func__
));
2777 for(i
=0; i
<wait
->num
; i
++)
2778 CloseHandle (wait
->handles
[i
]);
2780 if (ret
== WAIT_TIMEOUT
)
2783 if (ret
< wait
->num
) {
2784 gsize tid
= wait
->threads
[ret
]->tid
;
2785 mono_threads_lock ();
2786 if (mono_g_hash_table_lookup (threads
, (gpointer
)tid
)!=NULL
) {
2787 /* See comment in wait_for_tids about thread cleanup */
2788 mono_threads_unlock ();
2789 THREAD_DEBUG (g_message ("%s: cleaning up after thread %"G_GSIZE_FORMAT
, __func__
, tid
));
2790 thread_cleanup (wait
->threads
[ret
]);
2792 mono_threads_unlock ();
2796 static void build_wait_tids (gpointer key
, gpointer value
, gpointer user
)
2798 struct wait_data
*wait
=(struct wait_data
*)user
;
2800 if(wait
->num
<MAXIMUM_WAIT_OBJECTS
) {
2802 MonoInternalThread
*thread
=(MonoInternalThread
*)value
;
2804 /* Ignore background threads, we abort them later */
2805 /* Do not lock here since it is not needed and the caller holds threads_lock */
2806 if (thread
->state
& ThreadState_Background
) {
2807 THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT
, __func__
, (gsize
)thread
->tid
));
2808 return; /* just leave, ignore */
2811 if (mono_gc_is_finalizer_internal_thread (thread
)) {
2812 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT
, __func__
, (gsize
)thread
->tid
));
2816 if (thread
== mono_thread_internal_current ()) {
2817 THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT
, __func__
, (gsize
)thread
->tid
));
2821 if (mono_thread_get_main () && (thread
== mono_thread_get_main ()->internal_thread
)) {
2822 THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT
, __func__
, (gsize
)thread
->tid
));
2826 if (thread
->flags
& MONO_THREAD_FLAG_DONT_MANAGE
) {
2827 THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT
"with DONT_MANAGE flag set.", __func__
, (gsize
)thread
->tid
));
2831 handle
= OpenThread (THREAD_ALL_ACCESS
, TRUE
, thread
->tid
);
2832 if (handle
== NULL
) {
2833 THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT
, __func__
, (gsize
)thread
->tid
));
2837 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__
, thread
));
2838 if ((thread
->manage_callback
== NULL
) || (thread
->manage_callback (thread
->root_domain_thread
) == TRUE
)) {
2839 wait
->handles
[wait
->num
]=handle
;
2840 wait
->threads
[wait
->num
]=thread
;
2843 THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT
, __func__
, (gsize
)thread
->tid
));
2845 THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT
, __func__
, (gsize
)thread
->tid
));
2850 /* Just ignore the rest, we can't do anything with
2857 remove_and_abort_threads (gpointer key
, gpointer value
, gpointer user
)
2859 struct wait_data
*wait
=(struct wait_data
*)user
;
2860 gsize self
= GetCurrentThreadId ();
2861 MonoInternalThread
*thread
= value
;
2864 if (wait
->num
>= MAXIMUM_WAIT_OBJECTS
)
2867 /* The finalizer thread is not a background thread */
2868 if (thread
->tid
!= self
&& (thread
->state
& ThreadState_Background
) != 0 &&
2869 !(thread
->flags
& MONO_THREAD_FLAG_DONT_MANAGE
)) {
2871 handle
= OpenThread (THREAD_ALL_ACCESS
, TRUE
, thread
->tid
);
2875 /* printf ("A: %d\n", wait->num); */
2876 wait
->handles
[wait
->num
]=thread
->handle
;
2877 wait
->threads
[wait
->num
]=thread
;
2880 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT
"\n", __func__
, (gsize
)thread
->tid
));
2881 mono_thread_internal_stop (thread
);
2885 return (thread
->tid
!= self
&& !mono_gc_is_finalizer_internal_thread (thread
));
2889 * mono_threads_set_shutting_down:
2891 * Is called by a thread that wants to shut down Mono. If the runtime is already
2892 * shutting down, the calling thread is suspended/stopped, and this function never
2896 mono_threads_set_shutting_down (void)
2898 MonoInternalThread
*current_thread
= mono_thread_internal_current ();
2900 mono_threads_lock ();
2902 if (shutting_down
) {
2903 mono_threads_unlock ();
2905 /* Make sure we're properly suspended/stopped */
2907 EnterCriticalSection (current_thread
->synch_cs
);
2909 if ((current_thread
->state
& ThreadState_SuspendRequested
) ||
2910 (current_thread
->state
& ThreadState_AbortRequested
) ||
2911 (current_thread
->state
& ThreadState_StopRequested
)) {
2912 LeaveCriticalSection (current_thread
->synch_cs
);
2913 mono_thread_execute_interruption (current_thread
);
2915 current_thread
->state
|= ThreadState_Stopped
;
2916 LeaveCriticalSection (current_thread
->synch_cs
);
2919 /* Wake up other threads potentially waiting for us */
2922 shutting_down
= TRUE
;
2924 /* Not really a background state change, but this will
2925 * interrupt the main thread if it is waiting for all
2926 * the other threads.
2928 SetEvent (background_change_event
);
2930 mono_threads_unlock ();
2935 * mono_threads_is_shutting_down:
2937 * Returns whether a thread has commenced shutdown of Mono. Note that
2938 * if the function returns FALSE the caller must not assume that
2939 * shutdown is not in progress, because the situation might have
2940 * changed since the function returned. For that reason this function
2941 * is of very limited utility.
2944 mono_threads_is_shutting_down (void)
2946 return shutting_down
;
2949 void mono_thread_manage (void)
2951 struct wait_data
*wait
=g_new0 (struct wait_data
, 1);
2953 /* join each thread that's still running */
2954 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__
));
2956 mono_threads_lock ();
2958 THREAD_DEBUG (g_message("%s: No threads", __func__
));
2959 mono_threads_unlock ();
2963 mono_threads_unlock ();
2966 mono_threads_lock ();
2967 if (shutting_down
) {
2968 /* somebody else is shutting down */
2969 mono_threads_unlock ();
2972 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__
, mono_g_hash_table_size (threads
));
2973 mono_g_hash_table_foreach (threads
, print_tids
, NULL
));
2975 ResetEvent (background_change_event
);
2977 mono_g_hash_table_foreach (threads
, build_wait_tids
, wait
);
2978 mono_threads_unlock ();
2980 /* Something to wait for */
2981 wait_for_tids_or_state_change (wait
, INFINITE
);
2983 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__
, wait
->num
));
2984 } while(wait
->num
>0);
2986 mono_threads_set_shutting_down ();
2988 /* No new threads will be created after this point */
2990 mono_runtime_set_shutting_down ();
2992 THREAD_DEBUG (g_message ("%s: threadpool cleanup", __func__
));
2993 mono_thread_pool_cleanup ();
2996 * Remove everything but the finalizer thread and self.
2997 * Also abort all the background threads
3000 mono_threads_lock ();
3003 mono_g_hash_table_foreach_remove (threads
, remove_and_abort_threads
, wait
);
3005 mono_threads_unlock ();
3007 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__
, wait
->num
));
3009 /* Something to wait for */
3010 wait_for_tids (wait
, INFINITE
);
3012 } while (wait
->num
> 0);
3015 * give the subthreads a chance to really quit (this is mainly needed
3016 * to get correct user and system times from getrusage/wait/time(1)).
3017 * This could be removed if we avoid pthread_detach() and use pthread_join().
3026 static void terminate_thread (gpointer key
, gpointer value
, gpointer user
)
3028 MonoInternalThread
*thread
=(MonoInternalThread
*)value
;
3030 if(thread
->tid
!= (gsize
)user
) {
3031 /*TerminateThread (thread->handle, -1);*/
3035 void mono_thread_abort_all_other_threads (void)
3037 gsize self
= GetCurrentThreadId ();
3039 mono_threads_lock ();
3040 THREAD_DEBUG (g_message ("%s: There are %d threads to abort", __func__
,
3041 mono_g_hash_table_size (threads
));
3042 mono_g_hash_table_foreach (threads
, print_tids
, NULL
));
3044 mono_g_hash_table_foreach (threads
, terminate_thread
, (gpointer
)self
);
3046 mono_threads_unlock ();
3050 collect_threads_for_suspend (gpointer key
, gpointer value
, gpointer user_data
)
3052 MonoInternalThread
*thread
= (MonoInternalThread
*)value
;
3053 struct wait_data
*wait
= (struct wait_data
*)user_data
;
3057 * We try to exclude threads early, to avoid running into the MAXIMUM_WAIT_OBJECTS
3059 * This needs no locking.
3061 if ((thread
->state
& ThreadState_Suspended
) != 0 ||
3062 (thread
->state
& ThreadState_Stopped
) != 0)
3065 if (wait
->num
<MAXIMUM_WAIT_OBJECTS
) {
3066 handle
= OpenThread (THREAD_ALL_ACCESS
, TRUE
, thread
->tid
);
3070 wait
->handles
[wait
->num
] = handle
;
3071 wait
->threads
[wait
->num
] = thread
;
3077 * mono_thread_suspend_all_other_threads:
3079 * Suspend all managed threads except the finalizer thread and this thread. It is
3080 * not possible to resume them later.
3082 void mono_thread_suspend_all_other_threads (void)
3084 struct wait_data
*wait
= g_new0 (struct wait_data
, 1);
3086 gsize self
= GetCurrentThreadId ();
3088 guint32 eventidx
= 0;
3089 gboolean starting
, finished
;
3092 * The other threads could be in an arbitrary state at this point, i.e.
3093 * they could be starting up, shutting down etc. This means that there could be
3094 * threads which are not even in the threads hash table yet.
3098 * First we set a barrier which will be checked by all threads before they
3099 * are added to the threads hash table, and they will exit if the flag is set.
3100 * This ensures that no threads could be added to the hash later.
3101 * We will use shutting_down as the barrier for now.
3103 g_assert (shutting_down
);
3106 * We make multiple calls to WaitForMultipleObjects since:
3107 * - we can only wait for MAXIMUM_WAIT_OBJECTS threads
3108 * - some threads could exit without becoming suspended
3113 * Make a copy of the hashtable since we can't do anything with
3114 * threads while threads_mutex is held.
3117 mono_threads_lock ();
3118 mono_g_hash_table_foreach (threads
, collect_threads_for_suspend
, wait
);
3119 mono_threads_unlock ();
3121 events
= g_new0 (gpointer
, wait
->num
);
3123 /* Get the suspended events that we'll be waiting for */
3124 for (i
= 0; i
< wait
->num
; ++i
) {
3125 MonoInternalThread
*thread
= wait
->threads
[i
];
3126 gboolean signal_suspend
= FALSE
;
3128 if ((thread
->tid
== self
) || mono_gc_is_finalizer_internal_thread (thread
) || (thread
->flags
& MONO_THREAD_FLAG_DONT_MANAGE
)) {
3129 //CloseHandle (wait->handles [i]);
3130 wait
->threads
[i
] = NULL
; /* ignore this thread in next loop */
3134 ensure_synch_cs_set (thread
);
3136 EnterCriticalSection (thread
->synch_cs
);
3138 if (thread
->suspended_event
== NULL
) {
3139 thread
->suspended_event
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
3140 if (thread
->suspended_event
== NULL
) {
3141 /* Forget this one and go on to the next */
3142 LeaveCriticalSection (thread
->synch_cs
);
3147 if ((thread
->state
& ThreadState_Suspended
) != 0 ||
3148 (thread
->state
& ThreadState_StopRequested
) != 0 ||
3149 (thread
->state
& ThreadState_Stopped
) != 0) {
3150 LeaveCriticalSection (thread
->synch_cs
);
3151 CloseHandle (wait
->handles
[i
]);
3152 wait
->threads
[i
] = NULL
; /* ignore this thread in next loop */
3156 if ((thread
->state
& ThreadState_SuspendRequested
) == 0)
3157 signal_suspend
= TRUE
;
3159 events
[eventidx
++] = thread
->suspended_event
;
3161 /* Convert abort requests into suspend requests */
3162 if ((thread
->state
& ThreadState_AbortRequested
) != 0)
3163 thread
->state
&= ~ThreadState_AbortRequested
;
3165 thread
->state
|= ThreadState_SuspendRequested
;
3167 LeaveCriticalSection (thread
->synch_cs
);
3169 /* Signal the thread to suspend */
3171 signal_thread_state_change (thread
);
3175 WaitForMultipleObjectsEx (eventidx
, events
, TRUE
, 100, FALSE
);
3176 for (i
= 0; i
< wait
->num
; ++i
) {
3177 MonoInternalThread
*thread
= wait
->threads
[i
];
3182 EnterCriticalSection (thread
->synch_cs
);
3183 if ((thread
->state
& ThreadState_Suspended
) != 0) {
3184 CloseHandle (thread
->suspended_event
);
3185 thread
->suspended_event
= NULL
;
3187 LeaveCriticalSection (thread
->synch_cs
);
3191 * If there are threads which are starting up, we wait until they
3192 * are suspended when they try to register in the threads hash.
3193 * This is guaranteed to finish, since the threads which can create new
3194 * threads get suspended after a while.
3195 * FIXME: The finalizer thread can still create new threads.
3197 mono_threads_lock ();
3198 if (threads_starting_up
)
3199 starting
= mono_g_hash_table_size (threads_starting_up
) > 0;
3202 mono_threads_unlock ();
3216 collect_threads (gpointer key
, gpointer value
, gpointer user_data
)
3218 MonoInternalThread
*thread
= (MonoInternalThread
*)value
;
3219 struct wait_data
*wait
= (struct wait_data
*)user_data
;
3222 if (wait
->num
<MAXIMUM_WAIT_OBJECTS
) {
3223 handle
= OpenThread (THREAD_ALL_ACCESS
, TRUE
, thread
->tid
);
3227 wait
->handles
[wait
->num
] = handle
;
3228 wait
->threads
[wait
->num
] = thread
;
3234 * mono_threads_request_thread_dump:
3236 * Ask all threads except the current to print their stacktrace to stdout.
3239 mono_threads_request_thread_dump (void)
3241 struct wait_data
*wait
= g_new0 (struct wait_data
, 1);
3245 * Make a copy of the hashtable since we can't do anything with
3246 * threads while threads_mutex is held.
3248 mono_threads_lock ();
3249 mono_g_hash_table_foreach (threads
, collect_threads
, wait
);
3250 mono_threads_unlock ();
3252 for (i
= 0; i
< wait
->num
; ++i
) {
3253 MonoInternalThread
*thread
= wait
->threads
[i
];
3255 if (!mono_gc_is_finalizer_internal_thread (thread
) &&
3256 (thread
!= mono_thread_internal_current ()) &&
3257 !thread
->thread_dump_requested
) {
3258 thread
->thread_dump_requested
= TRUE
;
3260 signal_thread_state_change (thread
);
3263 CloseHandle (wait
->handles
[i
]);
3268 * mono_thread_push_appdomain_ref:
3270 * Register that the current thread may have references to objects in domain
3271 * @domain on its stack. Each call to this function should be paired with a
3272 * call to pop_appdomain_ref.
3275 mono_thread_push_appdomain_ref (MonoDomain
*domain
)
3277 MonoInternalThread
*thread
= mono_thread_internal_current ();
3280 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3281 mono_threads_lock ();
3282 thread
->appdomain_refs
= g_slist_prepend (thread
->appdomain_refs
, domain
);
3283 mono_threads_unlock ();
3288 mono_thread_pop_appdomain_ref (void)
3290 MonoInternalThread
*thread
= mono_thread_internal_current ();
3293 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3294 mono_threads_lock ();
3295 /* FIXME: How can the list be empty ? */
3296 if (thread
->appdomain_refs
)
3297 thread
->appdomain_refs
= g_slist_remove (thread
->appdomain_refs
, thread
->appdomain_refs
->data
);
3298 mono_threads_unlock ();
3303 mono_thread_internal_has_appdomain_ref (MonoInternalThread
*thread
, MonoDomain
*domain
)
3306 mono_threads_lock ();
3307 res
= g_slist_find (thread
->appdomain_refs
, domain
) != NULL
;
3308 mono_threads_unlock ();
3313 mono_thread_has_appdomain_ref (MonoThread
*thread
, MonoDomain
*domain
)
3315 return mono_thread_internal_has_appdomain_ref (thread
->internal_thread
, domain
);
3318 typedef struct abort_appdomain_data
{
3319 struct wait_data wait
;
3321 } abort_appdomain_data
;
3324 collect_appdomain_thread (gpointer key
, gpointer value
, gpointer user_data
)
3326 MonoInternalThread
*thread
= (MonoInternalThread
*)value
;
3327 abort_appdomain_data
*data
= (abort_appdomain_data
*)user_data
;
3328 MonoDomain
*domain
= data
->domain
;
3330 if (mono_thread_internal_has_appdomain_ref (thread
, domain
)) {
3331 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3333 if(data
->wait
.num
<MAXIMUM_WAIT_OBJECTS
) {
3334 HANDLE handle
= OpenThread (THREAD_ALL_ACCESS
, TRUE
, thread
->tid
);
3337 data
->wait
.handles
[data
->wait
.num
] = handle
;
3338 data
->wait
.threads
[data
->wait
.num
] = thread
;
3341 /* Just ignore the rest, we can't do anything with
3349 * mono_threads_abort_appdomain_threads:
3351 * Abort threads which has references to the given appdomain.
3354 mono_threads_abort_appdomain_threads (MonoDomain
*domain
, int timeout
)
3356 abort_appdomain_data user_data
;
3358 int orig_timeout
= timeout
;
3361 THREAD_DEBUG (g_message ("%s: starting abort", __func__
));
3363 start_time
= mono_msec_ticks ();
3365 mono_threads_lock ();
3367 user_data
.domain
= domain
;
3368 user_data
.wait
.num
= 0;
3369 /* This shouldn't take any locks */
3370 mono_g_hash_table_foreach (threads
, collect_appdomain_thread
, &user_data
);
3371 mono_threads_unlock ();
3373 if (user_data
.wait
.num
> 0) {
3374 /* Abort the threads outside the threads lock */
3375 for (i
= 0; i
< user_data
.wait
.num
; ++i
)
3376 ves_icall_System_Threading_Thread_Abort (user_data
.wait
.threads
[i
], NULL
);
3379 * We should wait for the threads either to abort, or to leave the
3380 * domain. We can't do the latter, so we wait with a timeout.
3382 wait_for_tids (&user_data
.wait
, 100);
3385 /* Update remaining time */
3386 timeout
-= mono_msec_ticks () - start_time
;
3387 start_time
= mono_msec_ticks ();
3389 if (orig_timeout
!= -1 && timeout
< 0)
3392 while (user_data
.wait
.num
> 0);
3394 THREAD_DEBUG (g_message ("%s: abort done", __func__
));
3400 clear_cached_culture (gpointer key
, gpointer value
, gpointer user_data
)
3402 MonoInternalThread
*thread
= (MonoInternalThread
*)value
;
3403 MonoDomain
*domain
= (MonoDomain
*)user_data
;
3406 /* No locking needed here */
3407 /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
3409 if (thread
->cached_culture_info
) {
3410 for (i
= 0; i
< NUM_CACHED_CULTURES
* 2; ++i
) {
3411 MonoObject
*obj
= mono_array_get (thread
->cached_culture_info
, MonoObject
*, i
);
3412 if (obj
&& obj
->vtable
->domain
== domain
)
3413 mono_array_set (thread
->cached_culture_info
, MonoObject
*, i
, NULL
);
3419 * mono_threads_clear_cached_culture:
3421 * Clear the cached_current_culture from all threads if it is in the
3425 mono_threads_clear_cached_culture (MonoDomain
*domain
)
3427 mono_threads_lock ();
3428 mono_g_hash_table_foreach (threads
, clear_cached_culture
, domain
);
3429 mono_threads_unlock ();
3433 * mono_thread_get_undeniable_exception:
3435 * Return an exception which needs to be raised when leaving a catch clause.
3436 * This is used for undeniable exception propagation.
3439 mono_thread_get_undeniable_exception (void)
3441 MonoInternalThread
*thread
= mono_thread_internal_current ();
3443 if (thread
&& thread
->abort_exc
&& !is_running_protected_wrapper ()) {
3445 * FIXME: Clear the abort exception and return an AppDomainUnloaded
3446 * exception if the thread no longer references a dying appdomain.
3448 thread
->abort_exc
->trace_ips
= NULL
;
3449 thread
->abort_exc
->stack_trace
= NULL
;
3450 return thread
->abort_exc
;
3456 #if MONO_SMALL_CONFIG
3457 #define NUM_STATIC_DATA_IDX 4
3458 static const int static_data_size
[NUM_STATIC_DATA_IDX
] = {
3462 #define NUM_STATIC_DATA_IDX 8
3463 static const int static_data_size
[NUM_STATIC_DATA_IDX
] = {
3464 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
3469 * mono_alloc_static_data
3471 * Allocate memory blocks for storing threads or context static data
3474 mono_alloc_static_data (gpointer
**static_data_ptr
, guint32 offset
)
3476 guint idx
= (offset
>> 24) - 1;
3479 gpointer
* static_data
= *static_data_ptr
;
3481 static_data
= mono_gc_alloc_fixed (static_data_size
[0], NULL
);
3482 *static_data_ptr
= static_data
;
3483 static_data
[0] = static_data
;
3486 for (i
= 1; i
<= idx
; ++i
) {
3487 if (static_data
[i
])
3489 static_data
[i
] = mono_gc_alloc_fixed (static_data_size
[i
], NULL
);
3494 * mono_init_static_data_info
3496 * Initializes static data counters
3498 static void mono_init_static_data_info (StaticDataInfo
*static_data
)
3500 static_data
->idx
= 0;
3501 static_data
->offset
= 0;
3502 static_data
->freelist
= NULL
;
3506 * mono_alloc_static_data_slot
3508 * Generates an offset for static data. static_data contains the counters
3509 * used to generate it.
3512 mono_alloc_static_data_slot (StaticDataInfo
*static_data
, guint32 size
, guint32 align
)
3516 if (!static_data
->idx
&& !static_data
->offset
) {
3518 * we use the first chunk of the first allocation also as
3519 * an array for the rest of the data
3521 static_data
->offset
= sizeof (gpointer
) * NUM_STATIC_DATA_IDX
;
3523 static_data
->offset
+= align
- 1;
3524 static_data
->offset
&= ~(align
- 1);
3525 if (static_data
->offset
+ size
>= static_data_size
[static_data
->idx
]) {
3526 static_data
->idx
++;
3527 g_assert (size
<= static_data_size
[static_data
->idx
]);
3528 g_assert (static_data
->idx
< NUM_STATIC_DATA_IDX
);
3529 static_data
->offset
= 0;
3531 offset
= static_data
->offset
| ((static_data
->idx
+ 1) << 24);
3532 static_data
->offset
+= size
;
3537 * ensure thread static fields already allocated are valid for thread
3538 * This function is called when a thread is created or on thread attach.
3541 thread_adjust_static_data (MonoInternalThread
*thread
)
3545 mono_threads_lock ();
3546 if (thread_static_info
.offset
|| thread_static_info
.idx
> 0) {
3547 /* get the current allocated size */
3548 offset
= thread_static_info
.offset
| ((thread_static_info
.idx
+ 1) << 24);
3549 mono_alloc_static_data (&(thread
->static_data
), offset
);
3551 mono_threads_unlock ();
3555 alloc_thread_static_data_helper (gpointer key
, gpointer value
, gpointer user
)
3557 MonoInternalThread
*thread
= value
;
3558 guint32 offset
= GPOINTER_TO_UINT (user
);
3560 mono_alloc_static_data (&(thread
->static_data
), offset
);
3563 static MonoThreadDomainTls
*
3564 search_tls_slot_in_freelist (StaticDataInfo
*static_data
, guint32 size
, guint32 align
)
3566 MonoThreadDomainTls
* prev
= NULL
;
3567 MonoThreadDomainTls
* tmp
= static_data
->freelist
;
3569 if (tmp
->size
== size
) {
3571 prev
->next
= tmp
->next
;
3573 static_data
->freelist
= tmp
->next
;
3582 * The offset for a special static variable is composed of three parts:
3583 * a bit that indicates the type of static data (0:thread, 1:context),
3584 * an index in the array of chunks of memory for the thread (thread->static_data)
3585 * and an offset in that chunk of mem. This allows allocating less memory in the
3590 mono_alloc_special_static_data (guint32 static_type
, guint32 size
, guint32 align
)
3593 if (static_type
== SPECIAL_STATIC_THREAD
)
3595 MonoThreadDomainTls
*item
;
3596 mono_threads_lock ();
3597 item
= search_tls_slot_in_freelist (&thread_static_info
, size
, align
);
3598 /*g_print ("TLS alloc: %d in domain %p (total: %d), cached: %p\n", size, mono_domain_get (), thread_static_info.offset, item);*/
3600 offset
= item
->offset
;
3603 offset
= mono_alloc_static_data_slot (&thread_static_info
, size
, align
);
3605 /* This can be called during startup */
3606 if (threads
!= NULL
)
3607 mono_g_hash_table_foreach (threads
, alloc_thread_static_data_helper
, GUINT_TO_POINTER (offset
));
3608 mono_threads_unlock ();
3612 g_assert (static_type
== SPECIAL_STATIC_CONTEXT
);
3613 mono_contexts_lock ();
3614 offset
= mono_alloc_static_data_slot (&context_static_info
, size
, align
);
3615 mono_contexts_unlock ();
3616 offset
|= 0x80000000; /* Set the high bit to indicate context static data */
3622 mono_get_special_static_data (guint32 offset
)
3624 /* The high bit means either thread (0) or static (1) data. */
3626 guint32 static_type
= (offset
& 0x80000000);
3629 offset
&= 0x7fffffff;
3630 idx
= (offset
>> 24) - 1;
3632 if (static_type
== 0) {
3633 return get_thread_static_data (mono_thread_internal_current (), offset
);
3635 /* Allocate static data block under demand, since we don't have a list
3638 MonoAppContext
*context
= mono_context_get ();
3639 if (!context
->static_data
|| !context
->static_data
[idx
]) {
3640 mono_contexts_lock ();
3641 mono_alloc_static_data (&(context
->static_data
), offset
);
3642 mono_contexts_unlock ();
3644 return ((char*) context
->static_data
[idx
]) + (offset
& 0xffffff);
3654 free_thread_static_data_helper (gpointer key
, gpointer value
, gpointer user
)
3656 MonoInternalThread
*thread
= value
;
3657 TlsOffsetSize
*data
= user
;
3658 int idx
= (data
->offset
>> 24) - 1;
3661 if (!thread
->static_data
|| !thread
->static_data
[idx
])
3663 ptr
= ((char*) thread
->static_data
[idx
]) + (data
->offset
& 0xffffff);
3664 memset (ptr
, 0, data
->size
);
3668 do_free_special (gpointer key
, gpointer value
, gpointer data
)
3670 MonoClassField
*field
= key
;
3671 guint32 offset
= GPOINTER_TO_UINT (value
);
3672 guint32 static_type
= (offset
& 0x80000000);
3675 size
= mono_type_size (field
->type
, &align
);
3676 /*g_print ("free %s , size: %d, offset: %x\n", field->name, size, offset);*/
3677 if (static_type
== 0) {
3679 MonoThreadDomainTls
*item
= g_new0 (MonoThreadDomainTls
, 1);
3680 data
.offset
= offset
& 0x7fffffff;
3682 if (threads
!= NULL
)
3683 mono_g_hash_table_foreach (threads
, free_thread_static_data_helper
, &data
);
3684 item
->offset
= offset
;
3686 item
->next
= thread_static_info
.freelist
;
3687 thread_static_info
.freelist
= item
;
3689 /* FIXME: free context static data as well */
3694 mono_alloc_special_static_data_free (GHashTable
*special_static_fields
)
3696 mono_threads_lock ();
3697 g_hash_table_foreach (special_static_fields
, do_free_special
, NULL
);
3698 mono_threads_unlock ();
3701 static MonoClassField
*local_slots
= NULL
;
3704 /* local tls data to get locals_slot from a thread */
3707 /* index in the locals_slot array */
3712 clear_local_slot (gpointer key
, gpointer value
, gpointer user_data
)
3714 LocalSlotID
*sid
= user_data
;
3715 MonoInternalThread
*thread
= (MonoInternalThread
*)value
;
3716 MonoArray
*slots_array
;
3718 * the static field is stored at: ((char*) thread->static_data [idx]) + (offset & 0xffffff);
3719 * it is for the right domain, so we need to check if it is allocated an initialized
3720 * for the current thread.
3722 /*g_print ("handling thread %p\n", thread);*/
3723 if (!thread
->static_data
|| !thread
->static_data
[sid
->idx
])
3725 slots_array
= *(MonoArray
**)(((char*) thread
->static_data
[sid
->idx
]) + (sid
->offset
& 0xffffff));
3726 if (!slots_array
|| sid
->slot
>= mono_array_length (slots_array
))
3728 mono_array_set (slots_array
, MonoObject
*, sid
->slot
, NULL
);
3732 mono_thread_free_local_slot_values (int slot
, MonoBoolean thread_local
)
3740 local_slots
= mono_class_get_field_from_name (mono_defaults
.thread_class
, "local_slots");
3742 g_warning ("local_slots field not found in Thread class");
3746 domain
= mono_domain_get ();
3747 mono_domain_lock (domain
);
3748 if (domain
->special_static_fields
)
3749 addr
= g_hash_table_lookup (domain
->special_static_fields
, local_slots
);
3750 mono_domain_unlock (domain
);
3753 /*g_print ("freeing slot %d at %p\n", slot, addr);*/
3754 sid
.offset
= GPOINTER_TO_UINT (addr
);
3755 sid
.offset
&= 0x7fffffff;
3756 sid
.idx
= (sid
.offset
>> 24) - 1;
3757 mono_threads_lock ();
3758 mono_g_hash_table_foreach (threads
, clear_local_slot
, &sid
);
3759 mono_threads_unlock ();
3761 /* FIXME: clear the slot for MonoAppContexts, too */
3766 static void CALLBACK
dummy_apc (ULONG_PTR param
)
3770 static guint32
dummy_apc (gpointer param
)
3777 * mono_thread_execute_interruption
3779 * Performs the operation that the requested thread state requires (abort,
3782 static MonoException
* mono_thread_execute_interruption (MonoInternalThread
*thread
)
3784 ensure_synch_cs_set (thread
);
3786 EnterCriticalSection (thread
->synch_cs
);
3788 /* MonoThread::interruption_requested can only be changed with atomics */
3789 if (InterlockedCompareExchange (&thread
->interruption_requested
, FALSE
, TRUE
)) {
3790 /* this will consume pending APC calls */
3791 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE
);
3792 InterlockedDecrement (&thread_interruption_requested
);
3794 /* Clear the interrupted flag of the thread so it can wait again */
3795 wapi_clear_interruption ();
3799 if ((thread
->state
& ThreadState_AbortRequested
) != 0) {
3800 LeaveCriticalSection (thread
->synch_cs
);
3801 if (thread
->abort_exc
== NULL
) {
3803 * This might be racy, but it has to be called outside the lock
3804 * since it calls managed code.
3806 MONO_OBJECT_SETREF (thread
, abort_exc
, mono_get_exception_thread_abort ());
3808 return thread
->abort_exc
;
3810 else if ((thread
->state
& ThreadState_SuspendRequested
) != 0) {
3811 thread
->state
&= ~ThreadState_SuspendRequested
;
3812 thread
->state
|= ThreadState_Suspended
;
3813 thread
->suspend_event
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
3814 if (thread
->suspend_event
== NULL
) {
3815 LeaveCriticalSection (thread
->synch_cs
);
3818 if (thread
->suspended_event
)
3819 SetEvent (thread
->suspended_event
);
3821 LeaveCriticalSection (thread
->synch_cs
);
3823 if (shutting_down
) {
3824 /* After we left the lock, the runtime might shut down so everything becomes invalid */
3829 WaitForSingleObject (thread
->suspend_event
, INFINITE
);
3831 EnterCriticalSection (thread
->synch_cs
);
3833 CloseHandle (thread
->suspend_event
);
3834 thread
->suspend_event
= NULL
;
3835 thread
->state
&= ~ThreadState_Suspended
;
3837 /* The thread that requested the resume will have replaced this event
3838 * and will be waiting for it
3840 SetEvent (thread
->resume_event
);
3842 LeaveCriticalSection (thread
->synch_cs
);
3846 else if ((thread
->state
& ThreadState_StopRequested
) != 0) {
3847 /* FIXME: do this through the JIT? */
3849 LeaveCriticalSection (thread
->synch_cs
);
3851 mono_thread_exit ();
3853 } else if (thread
->thread_interrupt_requested
) {
3855 thread
->thread_interrupt_requested
= FALSE
;
3856 LeaveCriticalSection (thread
->synch_cs
);
3858 return(mono_get_exception_thread_interrupted ());
3861 LeaveCriticalSection (thread
->synch_cs
);
3867 * mono_thread_request_interruption
3869 * A signal handler can call this method to request the interruption of a
3870 * thread. The result of the interruption will depend on the current state of
3871 * the thread. If the result is an exception that needs to be throw, it is
3872 * provided as return value.
3875 mono_thread_request_interruption (gboolean running_managed
)
3877 MonoInternalThread
*thread
= mono_thread_internal_current ();
3879 /* The thread may already be stopping */
3884 if (thread
->interrupt_on_stop
&&
3885 thread
->state
& ThreadState_StopRequested
&&
3886 thread
->state
& ThreadState_Background
)
3890 if (InterlockedCompareExchange (&thread
->interruption_requested
, 1, 0) == 1)
3893 if (!running_managed
|| is_running_protected_wrapper ()) {
3894 /* Can't stop while in unmanaged code. Increase the global interruption
3895 request count. When exiting the unmanaged method the count will be
3896 checked and the thread will be interrupted. */
3898 InterlockedIncrement (&thread_interruption_requested
);
3900 if (mono_thread_notify_pending_exc_fn
&& !running_managed
)
3901 /* The JIT will notify the thread about the interruption */
3902 /* This shouldn't take any locks */
3903 mono_thread_notify_pending_exc_fn ();
3905 /* this will awake the thread if it is in WaitForSingleObject
3907 /* Our implementation of this function ignores the func argument */
3908 QueueUserAPC ((PAPCFUNC
)dummy_apc
, thread
->handle
, NULL
);
3912 return mono_thread_execute_interruption (thread
);
3916 gboolean
mono_thread_interruption_requested ()
3918 if (thread_interruption_requested
) {
3919 MonoInternalThread
*thread
= mono_thread_internal_current ();
3920 /* The thread may already be stopping */
3922 return (thread
->interruption_requested
);
3927 static void mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection
)
3929 MonoInternalThread
*thread
= mono_thread_internal_current ();
3931 /* The thread may already be stopping */
3935 mono_debugger_check_interruption ();
3937 if (thread
->interruption_requested
&& (bypass_abort_protection
|| !is_running_protected_wrapper ())) {
3938 MonoException
* exc
= mono_thread_execute_interruption (thread
);
3939 if (exc
) mono_raise_exception (exc
);
3944 * Performs the interruption of the current thread, if one has been requested,
3945 * and the thread is not running a protected wrapper.
3947 void mono_thread_interruption_checkpoint ()
3949 mono_thread_interruption_checkpoint_request (FALSE
);
3953 * Performs the interruption of the current thread, if one has been requested.
3955 void mono_thread_force_interruption_checkpoint ()
3957 mono_thread_interruption_checkpoint_request (TRUE
);
3961 * mono_thread_get_and_clear_pending_exception:
3963 * Return any pending exceptions for the current thread and clear it as a side effect.
3966 mono_thread_get_and_clear_pending_exception (void)
3968 MonoInternalThread
*thread
= mono_thread_internal_current ();
3970 /* The thread may already be stopping */
3974 if (thread
->interruption_requested
&& !is_running_protected_wrapper ()) {
3975 return mono_thread_execute_interruption (thread
);
3978 if (thread
->pending_exception
) {
3979 MonoException
*exc
= thread
->pending_exception
;
3981 thread
->pending_exception
= NULL
;
3989 * mono_set_pending_exception:
3991 * Set the pending exception of the current thread to EXC. On platforms which
3992 * support it, the exception will be thrown when execution returns to managed code.
3993 * On other platforms, this function is equivalent to mono_raise_exception ().
3994 * Internal calls which report exceptions using this function instead of
3995 * raise_exception () might be called by JITted code using a more efficient calling
3999 mono_set_pending_exception (MonoException
*exc
)
4001 MonoInternalThread
*thread
= mono_thread_internal_current ();
4003 /* The thread may already be stopping */
4007 if (mono_thread_notify_pending_exc_fn
) {
4008 MONO_OBJECT_SETREF (thread
, pending_exception
, exc
);
4010 mono_thread_notify_pending_exc_fn ();
4012 /* No way to notify the JIT about the exception, have to throw it now */
4013 mono_raise_exception (exc
);
4018 * mono_thread_interruption_request_flag:
4020 * Returns the address of a flag that will be non-zero if an interruption has
4021 * been requested for a thread. The thread to interrupt may not be the current
4022 * thread, so an additional call to mono_thread_interruption_requested() or
4023 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4026 gint32
* mono_thread_interruption_request_flag ()
4028 return &thread_interruption_requested
;
4032 mono_thread_init_apartment_state (void)
4035 MonoInternalThread
* thread
= mono_thread_internal_current ();
4037 /* Positive return value indicates success, either
4038 * S_OK if this is first CoInitialize call, or
4039 * S_FALSE if CoInitialize already called, but with same
4040 * threading model. A negative value indicates failure,
4041 * probably due to trying to change the threading model.
4043 if (CoInitializeEx(NULL
, (thread
->apartment_state
== ThreadApartmentState_STA
)
4044 ? COINIT_APARTMENTTHREADED
4045 : COINIT_MULTITHREADED
) < 0) {
4046 thread
->apartment_state
= ThreadApartmentState_Unknown
;
4052 mono_thread_cleanup_apartment_state (void)
4055 MonoInternalThread
* thread
= mono_thread_internal_current ();
4057 if (thread
&& thread
->apartment_state
!= ThreadApartmentState_Unknown
) {
4064 mono_thread_set_state (MonoInternalThread
*thread
, MonoThreadState state
)
4066 ensure_synch_cs_set (thread
);
4068 EnterCriticalSection (thread
->synch_cs
);
4069 thread
->state
|= state
;
4070 LeaveCriticalSection (thread
->synch_cs
);
4074 mono_thread_clr_state (MonoInternalThread
*thread
, MonoThreadState state
)
4076 ensure_synch_cs_set (thread
);
4078 EnterCriticalSection (thread
->synch_cs
);
4079 thread
->state
&= ~state
;
4080 LeaveCriticalSection (thread
->synch_cs
);
4084 mono_thread_test_state (MonoInternalThread
*thread
, MonoThreadState test
)
4086 gboolean ret
= FALSE
;
4088 ensure_synch_cs_set (thread
);
4090 EnterCriticalSection (thread
->synch_cs
);
4092 if ((thread
->state
& test
) != 0) {
4096 LeaveCriticalSection (thread
->synch_cs
);
4101 static MonoClassField
*execution_context_field
;
4104 get_execution_context_addr (void)
4106 MonoDomain
*domain
= mono_domain_get ();
4109 if (!execution_context_field
) {
4110 execution_context_field
= mono_class_get_field_from_name (mono_defaults
.thread_class
,
4112 g_assert (execution_context_field
);
4115 g_assert (mono_class_try_get_vtable (domain
, mono_defaults
.appdomain_class
));
4117 mono_domain_lock (domain
);
4118 offset
= GPOINTER_TO_UINT (g_hash_table_lookup (domain
->special_static_fields
, execution_context_field
));
4119 mono_domain_unlock (domain
);
4122 return (MonoObject
**) mono_get_special_static_data (offset
);
4126 mono_thread_get_execution_context (void)
4128 return *get_execution_context_addr ();
4132 mono_thread_set_execution_context (MonoObject
*ec
)
4134 *get_execution_context_addr () = ec
;
4137 static gboolean has_tls_get
= FALSE
;
4140 mono_runtime_set_has_tls_get (gboolean val
)
4146 mono_runtime_has_tls_get (void)