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 * (C) 2001 Ximian, Inc.
14 #define _WIN32_WINNT 0x0500
21 #include <mono/metadata/object.h>
22 #include <mono/metadata/appdomain.h>
23 #include <mono/metadata/profiler-private.h>
24 #include <mono/metadata/threads.h>
25 #include <mono/metadata/threadpool.h>
26 #include <mono/metadata/threads-types.h>
27 #include <mono/metadata/exception.h>
28 #include <mono/metadata/environment.h>
29 #include <mono/metadata/monitor.h>
30 #include <mono/metadata/gc-internal.h>
31 #include <mono/metadata/marshal.h>
32 #include <mono/io-layer/io-layer.h>
34 #include <mono/os/gc_wrapper.h>
37 #undef THREAD_WAIT_DEBUG
41 guint32 (*func)(void *);
58 * The "os_handle" field of the WaitHandle class.
60 static MonoClassField *wait_handle_os_handle_field = NULL;
62 /* Controls access to the 'threads' hash table */
63 static CRITICAL_SECTION threads_mutex;
65 /* Controls access to context static data */
66 static CRITICAL_SECTION contexts_mutex;
68 /* Holds current status of static data heap */
69 static StaticDataInfo thread_static_info;
70 static StaticDataInfo context_static_info;
72 /* The hash of existing threads (key is thread ID) that need joining
75 static MonoGHashTable *threads=NULL;
77 /* The TLS key that holds the MonoObject assigned to each thread */
78 static guint32 current_object_key = -1;
80 /* function called at thread start */
81 static MonoThreadStartCB mono_thread_start_cb = NULL;
83 /* function called at thread attach */
84 static MonoThreadAttachCB mono_thread_attach_cb = NULL;
86 /* function called at thread cleanup */
87 static MonoThreadCleanupFunc mono_thread_cleanup = NULL;
89 /* function called when a new thread has been created */
90 static MonoThreadCallbacks *mono_thread_callbacks = NULL;
92 /* The TLS key that holds the LocalDataStoreSlot hash in each thread */
93 static guint32 slothash_key = -1;
95 /* The default stack size for each thread */
96 static guint32 default_stacksize = 0;
98 static void thread_adjust_static_data (MonoThread *thread);
99 static void mono_init_static_data_info (StaticDataInfo *static_data);
100 static guint32 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align);
102 /* Spin lock for InterlockedXXX 64 bit functions */
103 static CRITICAL_SECTION interlocked_mutex;
105 /* Controls access to interruption flag */
106 static CRITICAL_SECTION interruption_mutex;
108 /* global count of thread interruptions requested */
109 static gint32 thread_interruption_requested = 0;
112 /* handle_store() and handle_remove() manage the array of threads that
113 * still need to be waited for when the main thread exits.
115 static void handle_store(MonoThread *thread)
117 EnterCriticalSection(&threads_mutex);
120 g_message(G_GNUC_PRETTY_FUNCTION ": thread %p ID %d", thread,
125 threads=mono_g_hash_table_new(NULL, NULL);
128 /* We don't need to duplicate thread->handle, because it is
129 * only closed when the thread object is finalized by the GC.
131 mono_g_hash_table_insert(threads, GUINT_TO_POINTER(thread->tid), thread);
132 LeaveCriticalSection(&threads_mutex);
135 static void handle_remove(guint32 tid)
138 g_message(G_GNUC_PRETTY_FUNCTION ": thread ID %d", tid);
141 EnterCriticalSection(&threads_mutex);
144 mono_g_hash_table_remove (threads, GUINT_TO_POINTER(tid));
146 LeaveCriticalSection(&threads_mutex);
148 /* Don't close the handle here, wait for the object finalizer
149 * to do it. Otherwise, the following race condition applies:
151 * 1) Thread exits (and handle_remove() closes the handle)
153 * 2) Some other handle is reassigned the same slot
155 * 3) Another thread tries to join the first thread, and
156 * blocks waiting for the reassigned handle to be signalled
157 * (which might never happen). This is possible, because the
158 * thread calling Join() still has a reference to the first
163 static void thread_cleanup (MonoThread *thread)
165 if (!mono_monitor_try_enter ((MonoObject *)thread, INFINITE))
168 thread->state |= ThreadState_Stopped;
169 mono_monitor_exit ((MonoObject *)thread);
171 mono_profiler_thread_end (thread->tid);
172 handle_remove (thread->tid);
174 mono_thread_pop_appdomain_ref ();
176 if (mono_thread_cleanup)
177 mono_thread_cleanup (thread);
180 static guint32 start_wrapper(void *data)
182 struct StartInfo *start_info=(struct StartInfo *)data;
183 guint32 (*start_func)(void *);
186 MonoThread *thread=start_info->obj;
189 g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Start wrapper",
190 GetCurrentThreadId ());
193 /* We can be sure start_info->obj->tid and
194 * start_info->obj->handle have been set, because the thread
195 * was created suspended, and these values were set before the
201 TlsSetValue (current_object_key, thread);
203 if (!mono_domain_set (start_info->domain, FALSE)) {
204 /* No point in raising an appdomain_unloaded exception here */
205 /* FIXME: Cleanup here */
209 start_func = start_info->func;
210 this = start_info->this;
212 /* This MUST be called before any managed code can be
213 * executed, as it calls the callback function that (for the
214 * jit) sets the lmf marker.
216 mono_thread_new_init (tid, &tid, start_func);
217 thread->stack_ptr = &tid;
220 g_message (G_GNUC_PRETTY_FUNCTION
221 ": (%d,%d) Setting thread stack to %p",
222 GetCurrentThreadId (), getpid (), thread->stack_ptr);
226 g_message (G_GNUC_PRETTY_FUNCTION
227 ": (%d) Setting current_object_key to %p",
228 GetCurrentThreadId (), thread);
231 mono_profiler_thread_start (tid);
233 if(thread->start_notify!=NULL) {
234 /* Let the thread that called Start() know we're
237 ReleaseSemaphore (thread->start_notify, 1, NULL);
242 /* Every thread references the appdomain which created it */
243 mono_thread_push_appdomain_ref (mono_domain_get ());
245 thread_adjust_static_data (thread);
246 #ifndef PLATFORM_WIN32
248 g_message (G_GNUC_PRETTY_FUNCTION "start_wrapper for %d\n", thread->tid);
250 pthread_cleanup_push ((void (*) (void *)) mono_thread_detach, thread);
254 #ifdef PLATFORM_WIN32
255 /* If the thread calls ExitThread at all, this remaining code
256 * will not be executed, but the main thread will eventually
257 * call thread_cleanup() on this thread's behalf.
261 g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Start wrapper terminating",
262 GetCurrentThreadId ());
265 /* Remove the reference to the thread object in the TLS data,
266 * so the thread object can be finalized. This won't be
267 * reached if the thread threw an uncaught exception, so those
268 * thread handles will stay referenced :-( (This is due to
269 * missing support for scanning thread-specific data in the
270 * Boehm GC - the io-layer keeps a GC-visible hash of pointers
273 TlsSetValue (current_object_key, NULL);
275 thread_cleanup (thread);
277 pthread_cleanup_pop (1);
283 void mono_thread_new_init (guint32 tid, gpointer stack_start, gpointer func)
285 if (mono_thread_start_cb) {
286 mono_thread_start_cb (tid, stack_start, func);
289 if (mono_thread_callbacks)
290 (* mono_thread_callbacks->thread_created) (tid, stack_start, func);
293 void mono_threads_set_default_stacksize (guint32 stacksize)
295 default_stacksize = stacksize;
298 guint32 mono_threads_get_default_stacksize (void)
300 return default_stacksize;
303 void mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
306 HANDLE thread_handle;
307 struct StartInfo *start_info;
310 thread=(MonoThread *)mono_object_new (domain,
311 mono_defaults.thread_class);
313 start_info=g_new0 (struct StartInfo, 1);
314 start_info->func = func;
315 start_info->obj = thread;
316 start_info->domain = domain;
317 start_info->this = arg;
319 /* Create suspended, so we can do some housekeeping before the thread
322 thread_handle = CreateThread(NULL, default_stacksize, start_wrapper, start_info,
323 CREATE_SUSPENDED, &tid);
325 g_message(G_GNUC_PRETTY_FUNCTION ": Started thread ID %d (handle %p)",
328 g_assert (thread_handle);
330 thread->handle=thread_handle;
333 handle_store(thread);
335 ResumeThread (thread_handle);
339 mono_thread_attach (MonoDomain *domain)
342 HANDLE thread_handle;
345 if ((thread = mono_thread_current ())) {
346 /* Already attached */
350 thread = (MonoThread *)mono_object_new (domain,
351 mono_defaults.thread_class);
353 thread_handle = GetCurrentThread ();
354 g_assert (thread_handle);
356 tid=GetCurrentThreadId ();
358 thread->handle=thread_handle;
362 g_message(G_GNUC_PRETTY_FUNCTION ": Attached thread ID %d (handle %p)",
366 handle_store(thread);
369 g_message (G_GNUC_PRETTY_FUNCTION
370 ": (%d) Setting current_object_key to %p",
371 GetCurrentThreadId (), thread);
374 TlsSetValue (current_object_key, thread);
375 mono_domain_set (domain, TRUE);
377 thread_adjust_static_data (thread);
379 if (mono_thread_attach_cb) {
380 mono_thread_attach_cb (tid, &tid);
387 mono_thread_detach (MonoThread *thread)
389 g_return_if_fail (thread != NULL);
392 g_message (G_GNUC_PRETTY_FUNCTION "mono_thread_detach for %d\n", thread->tid);
394 TlsSetValue (current_object_key, NULL);
396 thread_cleanup (thread);
399 HANDLE ves_icall_System_Threading_Thread_Thread_internal(MonoThread *this,
402 MonoMulticastDelegate *delegate = (MonoMulticastDelegate*)start;
403 guint32 (*start_func)(void *);
404 struct StartInfo *start_info;
412 g_message(G_GNUC_PRETTY_FUNCTION
413 ": Trying to start a new thread: this (%p) start (%p)",
417 im = mono_get_delegate_invoke (start->vtable->klass);
418 im = mono_marshal_get_delegate_invoke (im);
419 if (mono_thread_callbacks)
420 start_func = (* mono_thread_callbacks->thread_start_compile_func) (im);
422 start_func = mono_compile_method (im);
424 if(start_func==NULL) {
425 g_warning(G_GNUC_PRETTY_FUNCTION
426 ": Can't locate start method!");
429 /* This is freed in start_wrapper */
430 start_info = g_new0 (struct StartInfo, 1);
431 start_info->func = start_func;
432 start_info->this = delegate;
433 start_info->obj = this;
434 start_info->domain = mono_domain_get ();
436 this->start_notify=CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
437 if(this->start_notify==NULL) {
438 g_warning (G_GNUC_PRETTY_FUNCTION ": CreateSemaphore error 0x%x", GetLastError ());
442 thread=CreateThread(NULL, default_stacksize, start_wrapper, start_info,
443 CREATE_SUSPENDED, &tid);
445 g_warning(G_GNUC_PRETTY_FUNCTION
446 ": CreateThread error 0x%x", GetLastError());
453 /* Don't call handle_store() here, delay it to Start.
454 * We can't join a thread (trying to will just block
455 * forever) until it actually starts running, so don't
456 * store the handle till then.
460 g_message(G_GNUC_PRETTY_FUNCTION
461 ": Started thread ID %d (handle %p)", tid, thread);
468 void ves_icall_System_Threading_Thread_Thread_free_internal (MonoThread *this,
474 g_message (G_GNUC_PRETTY_FUNCTION ": Closing thread %p, handle %p",
478 CloseHandle (thread);
481 void ves_icall_System_Threading_Thread_Start_internal(MonoThread *this,
487 g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Launching thread %p (%d)",
488 GetCurrentThreadId (), this, this->tid);
491 /* Only store the handle when the thread is about to be
492 * launched, to avoid the main thread deadlocking while trying
493 * to clean up a thread that will never be signalled.
497 if (mono_thread_callbacks)
498 (* mono_thread_callbacks->start_resume) (this->tid);
500 ResumeThread(thread);
502 if (mono_thread_callbacks)
503 (* mono_thread_callbacks->end_resume) (this->tid);
505 if(this->start_notify!=NULL) {
506 /* Wait for the thread to set up its TLS data etc, so
507 * theres no potential race condition if someone tries
508 * to look up the data believing the thread has
513 g_message(G_GNUC_PRETTY_FUNCTION
514 ": (%d) waiting for thread %p (%d) to start",
515 GetCurrentThreadId (), this, this->tid);
518 WaitForSingleObjectEx (this->start_notify, INFINITE, FALSE);
519 CloseHandle (this->start_notify);
520 this->start_notify=NULL;
524 g_message(G_GNUC_PRETTY_FUNCTION
525 ": (%d) Done launching thread %p (%d)",
526 GetCurrentThreadId (), this, this->tid);
530 void ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
535 g_message(G_GNUC_PRETTY_FUNCTION ": Sleeping for %d ms", ms);
542 ves_icall_System_Threading_Thread_GetDomainID (void)
546 return mono_domain_get()->domain_id;
550 ves_icall_System_Threading_Thread_GetName_internal (MonoThread *this_obj)
555 return mono_string_new_utf16 (mono_domain_get (), this_obj->name, this_obj->name_len);
559 ves_icall_System_Threading_Thread_SetName_internal (MonoThread *this_obj, MonoString *name)
562 g_free (this_obj->name);
564 this_obj->name = g_new (gunichar2, mono_string_length (name));
565 memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2);
566 this_obj->name_len = mono_string_length (name);
569 this_obj->name = NULL;
573 mono_thread_current (void)
579 /* Find the current thread object */
580 thread=TlsGetValue (current_object_key);
583 g_message (G_GNUC_PRETTY_FUNCTION ": returning %p", thread);
589 gboolean ves_icall_System_Threading_Thread_Join_internal(MonoThread *this,
590 int ms, HANDLE thread)
600 g_message (G_GNUC_PRETTY_FUNCTION ": joining thread handle %p, %d ms",
604 ret=WaitForSingleObjectEx (thread, ms, TRUE);
606 if(ret==WAIT_OBJECT_0) {
608 g_message (G_GNUC_PRETTY_FUNCTION ": join successful");
615 g_message (G_GNUC_PRETTY_FUNCTION ": join failed");
621 void ves_icall_System_Threading_Thread_SlotHash_store(MonoObject *data)
626 g_message(G_GNUC_PRETTY_FUNCTION ": Storing key %p", data);
629 /* Object location stored here */
630 TlsSetValue(slothash_key, data);
633 MonoObject *ves_icall_System_Threading_Thread_SlotHash_lookup(void)
639 data=TlsGetValue(slothash_key);
642 g_message(G_GNUC_PRETTY_FUNCTION ": Retrieved key %p", data);
648 /* FIXME: exitContext isnt documented */
649 gboolean ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
655 MonoObject *waitHandle;
660 numhandles = mono_array_length(mono_handles);
661 handles = g_new0(HANDLE, numhandles);
663 if (wait_handle_os_handle_field == 0) {
664 /* Get the field os_handle which will contain the actual handle */
665 klass = mono_class_from_name(mono_defaults.corlib, "System.Threading", "WaitHandle");
666 wait_handle_os_handle_field = mono_class_get_field_from_name(klass, "os_handle");
669 for(i = 0; i < numhandles; i++) {
670 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
671 mono_field_get_value(waitHandle, wait_handle_os_handle_field, &handles[i]);
678 ret=WaitForMultipleObjectsEx(numhandles, handles, TRUE, ms, TRUE);
682 if(ret==WAIT_FAILED) {
683 #ifdef THREAD_WAIT_DEBUG
684 g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Wait failed",
685 GetCurrentThreadId ());
688 } else if(ret==WAIT_TIMEOUT) {
689 #ifdef THREAD_WAIT_DEBUG
690 g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Wait timed out",
691 GetCurrentThreadId ());
699 /* FIXME: exitContext isnt documented */
700 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
706 MonoObject *waitHandle;
711 numhandles = mono_array_length(mono_handles);
712 handles = g_new0(HANDLE, numhandles);
714 if (wait_handle_os_handle_field == 0) {
715 /* Get the field os_handle which will contain the actual handle */
716 klass = mono_class_from_name(mono_defaults.corlib, "System.Threading", "WaitHandle");
717 wait_handle_os_handle_field = mono_class_get_field_from_name(klass, "os_handle");
720 for(i = 0; i < numhandles; i++) {
721 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
722 mono_field_get_value(waitHandle, wait_handle_os_handle_field, &handles[i]);
729 ret=WaitForMultipleObjectsEx(numhandles, handles, FALSE, ms, TRUE);
733 #ifdef THREAD_WAIT_DEBUG
734 g_message(G_GNUC_PRETTY_FUNCTION ": (%d) returning %d",
735 GetCurrentThreadId (), ret);
739 * These need to be here. See MSDN dos on WaitForMultipleObjects.
741 if (ret >= WAIT_OBJECT_0 && ret <= WAIT_OBJECT_0 + numhandles - 1) {
742 return ret - WAIT_OBJECT_0;
744 else if (ret >= WAIT_ABANDONED_0 && ret <= WAIT_ABANDONED_0 + numhandles - 1) {
745 return ret - WAIT_ABANDONED_0;
752 /* FIXME: exitContext isnt documented */
753 gboolean ves_icall_System_Threading_WaitHandle_WaitOne_internal(MonoObject *this, HANDLE handle, gint32 ms, gboolean exitContext)
759 #ifdef THREAD_WAIT_DEBUG
760 g_message(G_GNUC_PRETTY_FUNCTION ": (%d) waiting for %p, %d ms",
761 GetCurrentThreadId (), handle, ms);
768 ret=WaitForSingleObjectEx (handle, ms, TRUE);
770 if(ret==WAIT_FAILED) {
771 #ifdef THREAD_WAIT_DEBUG
772 g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Wait failed",
773 GetCurrentThreadId ());
776 } else if(ret==WAIT_TIMEOUT) {
777 #ifdef THREAD_WAIT_DEBUG
778 g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Wait timed out",
779 GetCurrentThreadId ());
787 HANDLE ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned, MonoString *name)
791 return(CreateMutex (NULL, owned,
792 name==NULL?NULL:mono_string_chars (name)));
795 void ves_icall_System_Threading_Mutex_ReleaseMutex_internal (HANDLE handle ) {
798 ReleaseMutex(handle);
801 HANDLE ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manual, MonoBoolean initial, MonoString *name) {
804 return(CreateEvent (NULL, manual, initial,
805 name==NULL?NULL:mono_string_chars (name)));
808 gboolean ves_icall_System_Threading_Events_SetEvent_internal (HANDLE handle) {
811 return (SetEvent(handle));
814 gboolean ves_icall_System_Threading_Events_ResetEvent_internal (HANDLE handle) {
817 return (ResetEvent(handle));
821 ves_icall_System_Threading_Events_CloseEvent_internal (HANDLE handle) {
824 CloseHandle (handle);
827 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
831 return InterlockedIncrement (location);
834 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
841 EnterCriticalSection(&interlocked_mutex);
843 lowret = InterlockedIncrement((gint32 *) location);
845 highret = InterlockedIncrement((gint32 *) location + 1);
847 highret = *((gint32 *) location + 1);
849 LeaveCriticalSection(&interlocked_mutex);
851 return (gint64) highret << 32 | (gint64) lowret;
854 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
858 return InterlockedDecrement(location);
861 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
868 EnterCriticalSection(&interlocked_mutex);
870 lowret = InterlockedDecrement((gint32 *) location);
872 highret = InterlockedDecrement((gint32 *) location + 1);
874 highret = *((gint32 *) location + 1);
876 LeaveCriticalSection(&interlocked_mutex);
878 return (gint64) highret << 32 | (gint64) lowret;
881 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location1, gint32 value)
885 return InterlockedExchange(location1, value);
888 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location1, MonoObject *value)
892 return (MonoObject *) InterlockedExchangePointer((gpointer *) location1, value);
895 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location1, gfloat value)
897 IntFloatUnion val, ret;
902 ret.ival = InterlockedExchange((gint32 *) location1, val.ival);
907 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location1, gint32 value, gint32 comparand)
911 return InterlockedCompareExchange(location1, value, comparand);
914 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location1, MonoObject *value, MonoObject *comparand)
918 return (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location1, value, comparand);
921 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location1, gfloat value, gfloat comparand)
923 IntFloatUnion val, ret, cmp;
928 cmp.fval = comparand;
929 ret.ival = InterlockedCompareExchange((gint32 *) location1, val.ival, cmp.ival);
935 mono_thread_get_abort_signal (void)
945 #endif /* __MINGW32__ */
949 static guint32 interruption_request_apc (gpointer param)
951 MonoException* exc = mono_thread_request_interruption (FALSE);
952 if (exc) mono_raise_exception (exc);
955 #endif /* __MINGW32__ */
958 * signal_thread_state_change
960 * Tells the thread that his state has changed and it has to enter the new
961 * state as soon as possible.
963 static void signal_thread_state_change (MonoThread *thread)
966 QueueUserAPC (interruption_request_apc, thread->handle, NULL);
968 /* fixme: store the state somewhere */
969 #ifdef PTHREAD_POINTER_ID
970 pthread_kill (GUINT_TO_POINTER(thread->tid), mono_thread_get_abort_signal ());
972 pthread_kill (thread->tid, mono_thread_get_abort_signal ());
974 #endif /* __MINGW32__ */
978 ves_icall_System_Threading_Thread_Abort (MonoThread *thread, MonoObject *state)
982 if (!mono_monitor_try_enter ((MonoObject *)thread, INFINITE))
985 if ((thread->state & ThreadState_AbortRequested) != 0 ||
986 (thread->state & ThreadState_StopRequested) != 0)
988 mono_monitor_exit ((MonoObject *)thread);
992 /* Make sure the thread is awake */
993 ves_icall_System_Threading_Thread_Resume (thread);
995 thread->state |= ThreadState_AbortRequested;
996 thread->abort_state = state;
997 thread->abort_exc = NULL;
999 mono_monitor_exit ((MonoObject *)thread);
1002 g_message (G_GNUC_PRETTY_FUNCTION
1003 ": (%d) Abort requested for %p (%d)", GetCurrentThreadId (),
1004 thread, thread->tid);
1007 signal_thread_state_change (thread);
1011 ves_icall_System_Threading_Thread_ResetAbort (void)
1013 MonoThread *thread = mono_thread_current ();
1015 MONO_ARCH_SAVE_REGS;
1017 if (!mono_monitor_try_enter ((MonoObject *)thread, INFINITE))
1020 thread->state &= ~ThreadState_AbortRequested;
1022 if (!thread->abort_exc) {
1023 const char *msg = "Unable to reset abort because no abort was requested";
1024 mono_monitor_exit ((MonoObject *)thread);
1025 mono_raise_exception (mono_get_exception_thread_state (msg));
1027 thread->abort_exc = NULL;
1028 thread->abort_state = NULL;
1031 mono_monitor_exit ((MonoObject *)thread);
1035 ves_icall_System_Threading_Thread_Suspend (MonoThread *thread)
1037 MONO_ARCH_SAVE_REGS;
1039 if (!mono_monitor_try_enter ((MonoObject *)thread, INFINITE))
1042 if ((thread->state & ThreadState_Suspended) != 0 ||
1043 (thread->state & ThreadState_SuspendRequested) != 0 ||
1044 (thread->state & ThreadState_StopRequested) != 0)
1046 mono_monitor_exit ((MonoObject *)thread);
1050 thread->state |= ThreadState_SuspendRequested;
1051 mono_monitor_exit ((MonoObject *)thread);
1053 signal_thread_state_change (thread);
1057 ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
1059 MONO_ARCH_SAVE_REGS;
1061 if (!mono_monitor_try_enter ((MonoObject *)thread, INFINITE))
1064 if ((thread->state & ThreadState_SuspendRequested) != 0) {
1065 thread->state &= ~ThreadState_SuspendRequested;
1066 mono_monitor_exit ((MonoObject *)thread);
1070 if ((thread->state & ThreadState_Suspended) == 0)
1072 mono_monitor_exit ((MonoObject *)thread);
1076 while (ResumeThread (thread->handle) == 0) {
1077 /* A rare case: we may try to resume the thread when it has not still
1078 called SuspendThread. This my happen since SuspendThread can't be
1079 called from inside the thread lock. In this case, keep trying until
1080 the thread is actually resumed */
1085 mono_monitor_exit ((MonoObject *)thread);
1088 void mono_thread_stop (MonoThread *thread)
1090 if (!mono_monitor_try_enter ((MonoObject *)thread, INFINITE))
1093 if ((thread->state & ThreadState_StopRequested) != 0 ||
1094 (thread->state & ThreadState_Stopped) != 0)
1096 mono_monitor_exit ((MonoObject *)thread);
1100 /* Make sure the thread is awake */
1101 ves_icall_System_Threading_Thread_Resume (thread);
1103 thread->state |= ThreadState_StopRequested;
1104 thread->state &= ~ThreadState_AbortRequested;
1106 mono_monitor_exit ((MonoObject *)thread);
1108 signal_thread_state_change (thread);
1112 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
1114 return *((volatile gint8 *) (ptr));
1118 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
1120 return *((volatile gint16 *) (ptr));
1124 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
1126 return *((volatile gint32 *) (ptr));
1130 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
1132 return *((volatile gint64 *) (ptr));
1136 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
1138 return (void *) *((volatile void **) ptr);
1142 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
1144 *((volatile gint8 *) ptr) = value;
1148 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
1150 *((volatile gint16 *) ptr) = value;
1154 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
1156 *((volatile gint32 *) ptr) = value;
1160 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
1162 *((volatile gint64 *) ptr) = value;
1166 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
1168 *((volatile void **) ptr) = value;
1171 void mono_thread_init (MonoThreadStartCB start_cb,
1172 MonoThreadAttachCB attach_cb)
1174 InitializeCriticalSection(&threads_mutex);
1175 InitializeCriticalSection(&interlocked_mutex);
1176 InitializeCriticalSection(&contexts_mutex);
1177 InitializeCriticalSection(&interruption_mutex);
1179 mono_init_static_data_info (&thread_static_info);
1180 mono_init_static_data_info (&context_static_info);
1182 current_object_key=TlsAlloc();
1184 g_message (G_GNUC_PRETTY_FUNCTION ": Allocated current_object_key %d",
1185 current_object_key);
1188 mono_thread_start_cb = start_cb;
1189 mono_thread_attach_cb = attach_cb;
1191 slothash_key=TlsAlloc();
1193 /* Get a pseudo handle to the current process. This is just a
1194 * kludge so that wapi can build a process handle if needed.
1195 * As a pseudo handle is returned, we don't need to clean
1198 GetCurrentProcess ();
1202 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
1204 mono_thread_cleanup = func;
1207 void mono_install_thread_callbacks (MonoThreadCallbacks *callbacks)
1209 mono_thread_callbacks = callbacks;
1213 static void print_tids (gpointer key, gpointer value, gpointer user)
1215 g_message ("Waiting for: %d", GPOINTER_TO_UINT(key));
1221 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
1222 MonoThread *threads[MAXIMUM_WAIT_OBJECTS];
1226 static void wait_for_tids (struct wait_data *wait, guint32 timeout)
1231 g_message(G_GNUC_PRETTY_FUNCTION
1232 ": %d threads to wait for in this batch", wait->num);
1235 ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, FALSE);
1237 if(ret==WAIT_FAILED) {
1238 /* See the comment in build_wait_tids() */
1240 g_message (G_GNUC_PRETTY_FUNCTION ": Wait failed");
1246 for(i=0; i<wait->num; i++) {
1247 guint32 tid=wait->threads[i]->tid;
1248 CloseHandle (wait->handles[i]);
1250 if(mono_g_hash_table_lookup (threads, GUINT_TO_POINTER(tid))!=NULL) {
1251 /* This thread must have been killed, because
1252 * it hasn't cleaned itself up. (It's just
1253 * possible that the thread exited before the
1254 * parent thread had a chance to store the
1255 * handle, and now there is another pointer to
1256 * the already-exited thread stored. In this
1257 * case, we'll just get two
1258 * mono_profiler_thread_end() calls for the
1263 g_message (G_GNUC_PRETTY_FUNCTION
1264 ": cleaning up after thread %d", tid);
1266 thread_cleanup (wait->threads[i]);
1271 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
1273 struct wait_data *wait=(struct wait_data *)user;
1275 if(wait->num<MAXIMUM_WAIT_OBJECTS) {
1277 MonoThread *thread=(MonoThread *)value;
1279 /* Ignore background threads, we abort them later */
1280 if (thread->state & ThreadState_Background)
1281 return; /* just leave, ignore */
1283 if (mono_gc_is_finalizer_thread (thread))
1286 if (thread == mono_thread_current ())
1289 handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
1293 wait->handles[wait->num]=handle;
1294 wait->threads[wait->num]=thread;
1297 /* Just ignore the rest, we can't do anything with
1304 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
1306 struct wait_data *wait=(struct wait_data *)user;
1307 guint32 self = GetCurrentThreadId ();
1308 MonoThread *thread = (MonoThread *) value;
1311 /* The finalizer thread is not a background thread */
1312 if (thread->tid != self && thread->state & ThreadState_Background) {
1314 handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
1318 wait->handles[wait->num]=thread->handle;
1319 wait->threads[wait->num]=thread;
1322 if(thread->state & ThreadState_AbortRequested ||
1323 thread->state & ThreadState_Aborted) {
1325 g_message (G_GNUC_PRETTY_FUNCTION ": Thread id %d already aborting", thread->tid);
1331 g_print (G_GNUC_PRETTY_FUNCTION ": Aborting id: %d\n", thread->tid);
1333 mono_thread_stop (thread);
1337 return (thread->tid != self && !mono_gc_is_finalizer_thread (thread));
1340 void mono_thread_manage (void)
1342 struct wait_data *wait=g_new0 (struct wait_data, 1);
1344 /* join each thread that's still running */
1346 g_message(G_GNUC_PRETTY_FUNCTION ": Joining each running thread...");
1349 EnterCriticalSection (&threads_mutex);
1352 g_message(G_GNUC_PRETTY_FUNCTION ": No threads");
1354 LeaveCriticalSection (&threads_mutex);
1357 LeaveCriticalSection (&threads_mutex);
1360 EnterCriticalSection (&threads_mutex);
1362 g_message(G_GNUC_PRETTY_FUNCTION
1363 ":There are %d threads to join",
1364 mono_g_hash_table_size (threads));
1365 mono_g_hash_table_foreach (threads, print_tids, NULL);
1369 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
1370 LeaveCriticalSection (&threads_mutex);
1372 /* Something to wait for */
1373 wait_for_tids (wait, INFINITE);
1375 } while(wait->num>0);
1377 mono_thread_pool_cleanup ();
1379 EnterCriticalSection(&threads_mutex);
1382 * Remove everything but the finalizer thread and self.
1383 * Also abort all the background threads
1386 mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
1388 LeaveCriticalSection(&threads_mutex);
1391 /* Something to wait for */
1392 wait_for_tids (wait, INFINITE);
1398 static void terminate_thread (gpointer key, gpointer value, gpointer user)
1400 MonoThread *thread=(MonoThread *)value;
1401 guint32 self=GPOINTER_TO_UINT (user);
1403 if(thread->tid!=self) {
1404 /*TerminateThread (thread->handle, -1);*/
1408 void mono_thread_abort_all_other_threads (void)
1410 guint32 self=GetCurrentThreadId ();
1412 EnterCriticalSection (&threads_mutex);
1414 g_message(G_GNUC_PRETTY_FUNCTION ":There are %d threads to abort",
1415 mono_g_hash_table_size (threads));
1416 mono_g_hash_table_foreach (threads, print_tids, NULL);
1419 mono_g_hash_table_foreach (threads, terminate_thread,
1420 GUINT_TO_POINTER (self));
1422 LeaveCriticalSection (&threads_mutex);
1426 * mono_thread_push_appdomain_ref:
1428 * Register that the current thread may have references to objects in domain
1429 * @domain on its stack. Each call to this function should be paired with a
1430 * call to pop_appdomain_ref.
1433 mono_thread_push_appdomain_ref (MonoDomain *domain)
1435 MonoThread *thread = mono_thread_current ();
1438 //printf ("PUSH REF: %p -> %s.\n", thread, domain->friendly_name);
1439 EnterCriticalSection (&threads_mutex);
1440 thread->appdomain_refs = g_slist_prepend (thread->appdomain_refs, domain);
1441 LeaveCriticalSection (&threads_mutex);
1446 mono_thread_pop_appdomain_ref (void)
1448 MonoThread *thread = mono_thread_current ();
1451 //printf ("POP REF: %p -> %s.\n", thread, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name);
1452 EnterCriticalSection (&threads_mutex);
1453 // FIXME: How can the list be empty ?
1454 if (thread->appdomain_refs)
1455 thread->appdomain_refs = g_slist_remove (thread->appdomain_refs, thread->appdomain_refs->data);
1456 LeaveCriticalSection (&threads_mutex);
1461 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
1464 EnterCriticalSection (&threads_mutex);
1465 res = g_slist_find (thread->appdomain_refs, domain) != NULL;
1466 LeaveCriticalSection (&threads_mutex);
1470 typedef struct abort_appdomain_data {
1471 struct wait_data wait;
1473 } abort_appdomain_data;
1476 abort_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
1478 MonoThread *thread = (MonoThread*)value;
1479 abort_appdomain_data *data = (abort_appdomain_data*)user_data;
1480 MonoDomain *domain = data->domain;
1482 if (mono_thread_has_appdomain_ref (thread, domain)) {
1483 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread, domain->friendly_name); */
1484 ves_icall_System_Threading_Thread_Abort (thread, NULL);
1486 if(data->wait.num<MAXIMUM_WAIT_OBJECTS) {
1487 data->wait.handles [data->wait.num] = thread->handle;
1488 data->wait.threads [data->wait.num] = thread;
1491 /* Just ignore the rest, we can't do anything with
1499 * mono_threads_abort_appdomain_threads:
1501 * Abort threads which has references to the given appdomain.
1504 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
1506 abort_appdomain_data user_data;
1509 /* printf ("ABORT BEGIN.\n"); */
1511 start_time = GetTickCount ();
1513 EnterCriticalSection (&threads_mutex);
1515 user_data.domain = domain;
1516 user_data.wait.num = 0;
1517 mono_g_hash_table_foreach (threads, abort_appdomain_thread, &user_data);
1518 LeaveCriticalSection (&threads_mutex);
1520 if (user_data.wait.num > 0)
1521 wait_for_tids (&user_data.wait, timeout);
1523 /* Update remaining time */
1524 timeout -= GetTickCount () - start_time;
1525 start_time = GetTickCount ();
1530 while (user_data.wait.num > 0);
1532 /* printf ("ABORT DONE.\n"); */
1538 * mono_thread_get_pending_exception:
1540 * Return an exception which needs to be raised when leaving a catch clause.
1541 * This is used for undeniable exception propagation.
1544 mono_thread_get_pending_exception (void)
1546 MonoThread *thread = mono_thread_current ();
1548 MONO_ARCH_SAVE_REGS;
1550 if (thread && thread->abort_exc) {
1552 * FIXME: Clear the abort exception and return an AppDomainUnloaded
1553 * exception if the thread no longer references a dying appdomain.
1555 thread->abort_exc->trace_ips = NULL;
1556 thread->abort_exc->stack_trace = NULL;
1557 return thread->abort_exc;
1563 #define NUM_STATIC_DATA_IDX 8
1564 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
1565 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
1570 * mono_alloc_static_data
1572 * Allocate memory blocks for storing threads or context static data
1575 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset)
1577 guint idx = (offset >> 24) - 1;
1580 gpointer* static_data = *static_data_ptr;
1583 static_data = GC_MALLOC (static_data_size [0]);
1585 static_data = g_malloc0 (static_data_size [0]);
1587 *static_data_ptr = static_data;
1588 static_data [0] = static_data;
1591 for (i = 1; i < idx; ++i) {
1592 if (static_data [i])
1595 static_data [i] = GC_MALLOC (static_data_size [i]);
1597 static_data [i] = g_malloc0 (static_data_size [i]);
1603 * mono_init_static_data_info
1605 * Initializes static data counters
1607 static void mono_init_static_data_info (StaticDataInfo *static_data)
1609 static_data->idx = 0;
1610 static_data->offset = 0;
1614 * mono_alloc_static_data_slot
1616 * Generates an offset for static data. static_data contains the counters
1617 * used to generate it.
1620 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
1624 if (!static_data->idx && !static_data->offset) {
1626 * we use the first chunk of the first allocation also as
1627 * an array for the rest of the data
1629 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
1631 static_data->offset += align - 1;
1632 static_data->offset &= ~(align - 1);
1633 if (static_data->offset + size >= static_data_size [static_data->idx]) {
1634 static_data->idx ++;
1635 g_assert (size <= static_data_size [static_data->idx]);
1637 * massive unloading and reloading of domains with thread-static
1638 * data may eventually exceed the allocated storage...
1639 * Need to check what the MS runtime does in that case.
1640 * Note that for each appdomain, we need to allocate a separate
1641 * thread data slot for security reasons. We could keep track
1642 * of the slots per-domain and when the domain is unloaded
1643 * out the slots on a sort of free list.
1645 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
1646 static_data->offset = 0;
1648 offset = static_data->offset | ((static_data->idx + 1) << 24);
1649 static_data->offset += size;
1654 * ensure thread static fields already allocated are valid for thread
1655 * This function is called when a thread is created or on thread attach.
1658 thread_adjust_static_data (MonoThread *thread)
1662 EnterCriticalSection (&threads_mutex);
1663 if (thread_static_info.offset || thread_static_info.idx > 0) {
1664 /* get the current allocated size */
1665 offset = thread_static_info.offset | ((thread_static_info.idx + 1) << 24);
1666 mono_alloc_static_data (&(thread->static_data), offset);
1668 LeaveCriticalSection (&threads_mutex);
1672 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
1674 MonoThread *thread = value;
1675 guint32 offset = GPOINTER_TO_UINT (user);
1677 mono_alloc_static_data (&(thread->static_data), offset);
1681 * The offset for a special static variable is composed of three parts:
1682 * a bit that indicates the type of static data (0:thread, 1:context),
1683 * an index in the array of chunks of memory for the thread (thread->static_data)
1684 * and an offset in that chunk of mem. This allows allocating less memory in the
1689 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align)
1692 if (static_type == SPECIAL_STATIC_THREAD)
1694 EnterCriticalSection (&threads_mutex);
1695 offset = mono_alloc_static_data_slot (&thread_static_info, size, align);
1696 /* This can be called during startup */
1697 if (threads != NULL)
1698 mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
1699 LeaveCriticalSection (&threads_mutex);
1703 g_assert (static_type == SPECIAL_STATIC_CONTEXT);
1704 EnterCriticalSection (&contexts_mutex);
1705 offset = mono_alloc_static_data_slot (&context_static_info, size, align);
1706 LeaveCriticalSection (&contexts_mutex);
1707 offset |= 0x80000000; // Set the high bit to indicate context static data
1713 mono_get_special_static_data (guint32 offset)
1715 // The high bit means either thread (0) or static (1) data.
1717 guint32 static_type = (offset & 0x80000000);
1720 offset &= 0x7fffffff;
1721 idx = (offset >> 24) - 1;
1723 if (static_type == 0)
1725 MonoThread *thread = mono_thread_current ();
1726 return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
1730 // Allocate static data block under demand, since we don't have a list
1732 MonoAppContext *context = mono_context_get ();
1733 if (!context->static_data || !context->static_data [idx]) {
1734 EnterCriticalSection (&contexts_mutex);
1735 mono_alloc_static_data (&(context->static_data), offset);
1736 LeaveCriticalSection (&contexts_mutex);
1738 return ((char*) context->static_data [idx]) + (offset & 0xffffff);
1742 static void gc_stop_world (gpointer key, gpointer value, gpointer user)
1744 MonoThread *thread=(MonoThread *)value;
1745 guint32 self=GPOINTER_TO_UINT (user);
1748 g_message (G_GNUC_PRETTY_FUNCTION ": %d - %d", self, thread->tid);
1751 if(thread->tid==self)
1754 SuspendThread (thread->handle);
1757 void mono_gc_stop_world (void)
1759 guint32 self=GetCurrentThreadId ();
1762 g_message (G_GNUC_PRETTY_FUNCTION ": %d - %p", self, threads);
1765 EnterCriticalSection (&threads_mutex);
1767 if (threads != NULL)
1768 mono_g_hash_table_foreach (threads, gc_stop_world, GUINT_TO_POINTER (self));
1770 LeaveCriticalSection (&threads_mutex);
1773 static void gc_start_world (gpointer key, gpointer value, gpointer user)
1775 MonoThread *thread=(MonoThread *)value;
1776 guint32 self=GPOINTER_TO_UINT (user);
1779 g_message (G_GNUC_PRETTY_FUNCTION ": %d - %d", self, thread->tid);
1782 if(thread->tid==self)
1785 ResumeThread (thread->handle);
1788 void mono_gc_start_world (void)
1790 guint32 self=GetCurrentThreadId ();
1793 g_message (G_GNUC_PRETTY_FUNCTION ": %d - %p", self, threads);
1796 EnterCriticalSection (&threads_mutex);
1798 if (threads != NULL)
1799 mono_g_hash_table_foreach (threads, gc_start_world, GUINT_TO_POINTER (self));
1801 LeaveCriticalSection (&threads_mutex);
1805 static guint32 dummy_apc (gpointer param)
1811 * mono_thread_execute_interruption
1813 * Performs the operation that the requested thread state requires (abort,
1816 static MonoException* mono_thread_execute_interruption (MonoThread *thread)
1818 while (!mono_monitor_try_enter ((MonoObject *)thread, INFINITE))
1819 ; /* we really need to get in */
1821 if (thread->interruption_requested) {
1822 /* this will consume pending APC calls */
1823 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
1824 EnterCriticalSection (&interruption_mutex);
1825 thread_interruption_requested--;
1826 LeaveCriticalSection (&interruption_mutex);
1827 thread->interruption_requested = FALSE;
1830 if ((thread->state & ThreadState_AbortRequested) != 0) {
1831 thread->abort_exc = mono_get_exception_thread_abort ();
1832 mono_monitor_exit ((MonoObject *)thread);
1833 return thread->abort_exc;
1835 else if ((thread->state & ThreadState_SuspendRequested) != 0) {
1836 thread->state &= ~ThreadState_SuspendRequested;
1837 thread->state |= ThreadState_Suspended;
1838 mono_monitor_exit ((MonoObject *)thread);
1840 SuspendThread (thread->handle);
1842 mono_monitor_try_enter ((MonoObject *)thread, INFINITE);
1843 thread->state &= ~ThreadState_Suspended;
1844 mono_monitor_exit ((MonoObject *)thread);
1847 else if ((thread->state & ThreadState_StopRequested) != 0) {
1848 /* FIXME: do this through the JIT? */
1849 mono_monitor_exit ((MonoObject *)thread);
1854 mono_monitor_exit ((MonoObject *)thread);
1859 * mono_thread_request_interruption
1861 * A signal handler can call this method to request the interruption of a
1862 * thread. The result of the interruption will depend on the current state of
1863 * the thread. If the result is an exception that needs to be throw, it is
1864 * provided as return value.
1866 MonoException* mono_thread_request_interruption (gboolean running_managed)
1868 MonoThread *thread = mono_thread_current ();
1870 /* The thread may already be stopping */
1874 if (!mono_monitor_try_enter ((MonoObject *)thread, INFINITE))
1877 if (thread->interruption_requested) {
1878 mono_monitor_exit ((MonoObject *)thread);
1882 if (!running_managed) {
1883 /* Can't stop while in unmanaged code. Increase the global interruption
1884 request count. When exiting the unmanaged method the count will be
1885 checked and the thread will be interrupted. */
1887 EnterCriticalSection (&interruption_mutex);
1888 thread_interruption_requested++;
1889 LeaveCriticalSection (&interruption_mutex);
1891 thread->interruption_requested = TRUE;
1892 mono_monitor_exit ((MonoObject *)thread);
1894 /* this will awake the thread if it is in WaitForSingleObject
1896 QueueUserAPC (dummy_apc, thread->handle, NULL);
1901 mono_monitor_exit ((MonoObject *)thread);
1902 return mono_thread_execute_interruption (thread);
1906 gboolean mono_thread_interruption_requested ()
1908 if (thread_interruption_requested) {
1909 MonoThread *thread = mono_thread_current ();
1910 /* The thread may already be stopping */
1912 return (thread->interruption_requested);
1918 * Performs the interruption of the current thread, if one has been requested.
1920 void mono_thread_interruption_checkpoint ()
1922 MonoThread *thread = mono_thread_current ();
1924 /* The thread may already be stopping */
1928 if (thread->interruption_requested) {
1929 MonoException* exc = mono_thread_execute_interruption (thread);
1930 if (exc) mono_raise_exception (exc);
1935 * Returns the address of a flag that will be non-zero if an interruption has
1936 * been requested for a thread. The thread to interrupt may not be the current
1937 * thread, so an additional call to mono_thread_interruption_requested() or
1938 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
1941 gint32* mono_thread_interruption_request_flag ()
1943 return &thread_interruption_requested;
1946 #ifdef WITH_INCLUDED_LIBGC
1948 static void gc_push_all_stacks (gpointer key, gpointer value, gpointer user)
1950 MonoThread *thread=(MonoThread *)value;
1951 guint32 *selfp=(guint32 *)user, self = *selfp;
1954 g_message (G_GNUC_PRETTY_FUNCTION ": %d - %d - %p", self, thread->tid, thread->stack_ptr);
1957 if(thread->tid==self) {
1959 g_message (G_GNUC_PRETTY_FUNCTION ": %p - %p", selfp, thread->stack_ptr);
1961 GC_push_all_stack (selfp, thread->stack_ptr);
1965 #ifdef PLATFORM_WIN32
1966 GC_win32_push_thread_stack (thread->handle, thread->stack_ptr);
1968 mono_wapi_push_thread_stack (thread->handle, thread->stack_ptr);
1972 void mono_gc_push_all_stacks (void)
1974 guint32 self=GetCurrentThreadId ();
1977 g_message (G_GNUC_PRETTY_FUNCTION ": %d - %p", self, threads);
1980 EnterCriticalSection (&threads_mutex);
1982 if (threads != NULL)
1983 mono_g_hash_table_foreach (threads, gc_push_all_stacks, &self);
1985 LeaveCriticalSection (&threads_mutex);
1988 #endif /* WITH_INCLUDED_LIBGC */