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/domain-internals.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>
33 #include <mono/metadata/object-internals.h>
34 #include <mono/metadata/mono-debug-debugger.h>
35 #include <mono/utils/mono-compiler.h>
37 #include <mono/os/gc_wrapper.h>
39 /*#define THREAD_DEBUG(a) do { a; } while (0)*/
40 #define THREAD_DEBUG(a)
41 /*#define THREAD_WAIT_DEBUG(a) do { a; } while (0)*/
42 #define THREAD_WAIT_DEBUG(a)
43 /*#define LIBGC_DEBUG(a) do { a; } while (0)*/
44 #define LIBGC_DEBUG(a)
46 /* Provide this for systems with glib < 2.6 */
47 #ifndef G_GSIZE_FORMAT
48 # if GLIB_SIZEOF_LONG == 8
49 # define G_GSIZE_FORMAT "lu"
51 # define G_GSIZE_FORMAT "u"
57 guint32 (*func)(void *);
79 /* Number of cached culture objects in the MonoThread->cached_culture_info array
80 * (per-type): we use the first NUM entries for CultureInfo and the last for
81 * UICultureInfo. So the size of the array is really NUM_CACHED_CULTURES * 2.
83 #define NUM_CACHED_CULTURES 4
84 #define CULTURES_START_IDX 0
85 #define UICULTURES_START_IDX NUM_CACHED_CULTURES
88 * The "os_handle" field of the WaitHandle class.
90 static MonoClassField *wait_handle_os_handle_field = NULL;
92 /* Controls access to the 'threads' hash table */
93 #define mono_threads_lock() EnterCriticalSection (&threads_mutex)
94 #define mono_threads_unlock() LeaveCriticalSection (&threads_mutex)
95 static CRITICAL_SECTION threads_mutex;
97 /* Controls access to context static data */
98 #define mono_contexts_lock() EnterCriticalSection (&contexts_mutex)
99 #define mono_contexts_unlock() LeaveCriticalSection (&contexts_mutex)
100 static CRITICAL_SECTION contexts_mutex;
102 /* Holds current status of static data heap */
103 static StaticDataInfo thread_static_info;
104 static StaticDataInfo context_static_info;
106 /* The hash of existing threads (key is thread ID) that need joining
109 static MonoGHashTable *threads=NULL;
111 /* The TLS key that holds the MonoObject assigned to each thread */
112 static guint32 current_object_key = -1;
114 #ifdef HAVE_KW_THREAD
115 /* we need to use both the Tls* functions and __thread because
116 * the gc needs to see all the threads
118 static __thread MonoThread * tls_current_object MONO_TLS_FAST;
119 #define SET_CURRENT_OBJECT(x) do { \
120 tls_current_object = x; \
121 TlsSetValue (current_object_key, x); \
123 #define GET_CURRENT_OBJECT() tls_current_object
125 #define SET_CURRENT_OBJECT(x) TlsSetValue (current_object_key, x);
126 #define GET_CURRENT_OBJECT() (MonoThread*) TlsGetValue (current_object_key);
129 /* function called at thread start */
130 static MonoThreadStartCB mono_thread_start_cb = NULL;
132 /* function called at thread attach */
133 static MonoThreadAttachCB mono_thread_attach_cb = NULL;
135 /* function called at thread cleanup */
136 static MonoThreadCleanupFunc mono_thread_cleanup_fn = NULL;
138 /* The default stack size for each thread */
139 static guint32 default_stacksize = 0;
140 #define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize)
142 static void thread_adjust_static_data (MonoThread *thread);
143 static void mono_init_static_data_info (StaticDataInfo *static_data);
144 static guint32 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align);
145 static gboolean mono_thread_resume (MonoThread* thread);
146 static void mono_thread_start (MonoThread *thread);
148 /* Spin lock for InterlockedXXX 64 bit functions */
149 #define mono_interlocked_lock() EnterCriticalSection (&interlocked_mutex)
150 #define mono_interlocked_unlock() LeaveCriticalSection (&interlocked_mutex)
151 static CRITICAL_SECTION interlocked_mutex;
153 /* global count of thread interruptions requested */
154 static gint32 thread_interruption_requested = 0;
156 /* Event signaled when a thread changes its background mode */
157 static HANDLE background_change_event;
160 mono_thread_get_tls_key (void)
162 return current_object_key;
166 mono_thread_get_tls_offset (void)
169 MONO_THREAD_VAR_OFFSET (tls_current_object,offset);
173 /* handle_store() and handle_remove() manage the array of threads that
174 * still need to be waited for when the main thread exits.
176 static void handle_store(MonoThread *thread)
178 mono_threads_lock ();
180 THREAD_DEBUG (g_message ("%s: thread %p ID %"G_GSIZE_FORMAT, __func__, thread, (gsize)thread->tid));
183 MONO_GC_REGISTER_ROOT (threads);
184 threads=mono_g_hash_table_new(NULL, NULL);
187 /* We don't need to duplicate thread->handle, because it is
188 * only closed when the thread object is finalized by the GC.
190 mono_g_hash_table_insert(threads, (gpointer)(gsize)(thread->tid),
193 mono_threads_unlock ();
196 static void handle_remove(gsize tid)
198 THREAD_DEBUG (g_message ("%s: thread ID %"G_GSIZE_FORMAT, __func__, tid));
200 mono_threads_lock ();
204 mono_g_hash_table_remove (threads, (gpointer)tid);
206 mono_threads_unlock ();
208 /* Don't close the handle here, wait for the object finalizer
209 * to do it. Otherwise, the following race condition applies:
211 * 1) Thread exits (and handle_remove() closes the handle)
213 * 2) Some other handle is reassigned the same slot
215 * 3) Another thread tries to join the first thread, and
216 * blocks waiting for the reassigned handle to be signalled
217 * (which might never happen). This is possible, because the
218 * thread calling Join() still has a reference to the first
223 static void thread_cleanup (MonoThread *thread)
225 g_assert (thread != NULL);
227 mono_release_type_locks (thread);
229 if (!mono_monitor_enter (thread->synch_lock))
232 thread->state |= ThreadState_Stopped;
233 mono_monitor_exit (thread->synch_lock);
235 mono_profiler_thread_end (thread->tid);
236 handle_remove (thread->tid);
238 mono_thread_pop_appdomain_ref ();
240 if (thread->serialized_culture_info)
241 g_free (thread->serialized_culture_info);
243 thread->cached_culture_info = NULL;
245 if (mono_thread_cleanup_fn)
246 mono_thread_cleanup_fn (thread);
249 static guint32 WINAPI start_wrapper(void *data)
251 struct StartInfo *start_info=(struct StartInfo *)data;
252 guint32 (*start_func)(void *);
255 MonoThread *thread=start_info->obj;
256 MonoObject *start_delegate = start_info->delegate;
258 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper", __func__, GetCurrentThreadId ()));
260 /* We can be sure start_info->obj->tid and
261 * start_info->obj->handle have been set, because the thread
262 * was created suspended, and these values were set before the
268 SET_CURRENT_OBJECT (thread);
270 if (!mono_domain_set (start_info->domain, FALSE)) {
271 /* No point in raising an appdomain_unloaded exception here */
272 /* FIXME: Cleanup here */
276 start_func = start_info->func;
277 start_arg = start_info->start_arg;
279 /* This MUST be called before any managed code can be
280 * executed, as it calls the callback function that (for the
281 * jit) sets the lmf marker.
283 mono_thread_new_init (tid, &tid, start_func);
284 thread->stack_ptr = &tid;
286 LIBGC_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT",%d) Setting thread stack to %p", __func__, GetCurrentThreadId (), getpid (), thread->stack_ptr));
288 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, GetCurrentThreadId (), thread));
290 mono_profiler_thread_start (tid);
292 if(thread->start_notify!=NULL) {
293 /* Let the thread that called Start() know we're
296 ReleaseSemaphore (thread->start_notify, 1, NULL);
301 /* Every thread references the appdomain which created it */
302 mono_thread_push_appdomain_ref (mono_domain_get ());
304 thread_adjust_static_data (thread);
306 g_message ("%s: start_wrapper for %"G_GSIZE_FORMAT, __func__,
310 /* start_func is set only for unamanged start functions */
312 start_func (start_arg);
315 g_assert (start_delegate != NULL);
316 args [0] = start_arg;
317 /* we may want to handle the exception here. See comment below on unhandled exceptions */
318 mono_runtime_delegate_invoke (start_delegate, args, NULL);
321 /* If the thread calls ExitThread at all, this remaining code
322 * will not be executed, but the main thread will eventually
323 * call thread_cleanup() on this thread's behalf.
326 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper terminating", __func__, GetCurrentThreadId ()));
328 /* Remove the reference to the thread object in the TLS data,
329 * so the thread object can be finalized. This won't be
330 * reached if the thread threw an uncaught exception, so those
331 * thread handles will stay referenced :-( (This is due to
332 * missing support for scanning thread-specific data in the
333 * Boehm GC - the io-layer keeps a GC-visible hash of pointers
336 SET_CURRENT_OBJECT (NULL);
338 thread_cleanup (thread);
343 void mono_thread_new_init (gsize tid, gpointer stack_start, gpointer func)
345 if (mono_thread_start_cb) {
346 mono_thread_start_cb (tid, stack_start, func);
350 void mono_threads_set_default_stacksize (guint32 stacksize)
352 default_stacksize = stacksize;
355 guint32 mono_threads_get_default_stacksize (void)
357 return default_stacksize;
360 void mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
363 HANDLE thread_handle;
364 struct StartInfo *start_info;
367 thread=(MonoThread *)mono_object_new (domain,
368 mono_defaults.thread_class);
370 start_info=g_new0 (struct StartInfo, 1);
371 start_info->func = func;
372 start_info->obj = thread;
373 start_info->domain = domain;
374 start_info->start_arg = arg;
376 /* Create suspended, so we can do some housekeeping before the thread
379 thread_handle = CreateThread(NULL, default_stacksize_for_thread (thread), (LPTHREAD_START_ROUTINE)start_wrapper, start_info,
380 CREATE_SUSPENDED, &tid);
381 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
382 if (thread_handle == NULL) {
383 /* The thread couldn't be created, so throw an exception */
384 mono_raise_exception (mono_get_exception_execution_engine ("Couldn't create thread"));
388 thread->handle=thread_handle;
391 MONO_OBJECT_SETREF (thread, synch_lock, mono_object_new (domain, mono_defaults.object_class));
393 handle_store(thread);
395 ResumeThread (thread_handle);
399 mono_thread_attach (MonoDomain *domain)
402 HANDLE thread_handle;
405 if ((thread = mono_thread_current ())) {
406 if (domain != mono_domain_get ())
407 mono_domain_set (domain, TRUE);
408 /* Already attached */
412 if (!mono_gc_register_thread (&domain)) {
413 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 ());
416 thread = (MonoThread *)mono_object_new (domain,
417 mono_defaults.thread_class);
419 thread_handle = GetCurrentThread ();
420 g_assert (thread_handle);
422 tid=GetCurrentThreadId ();
425 * The handle returned by GetCurrentThread () is a pseudo handle, so it can't be used to
426 * refer to the thread from other threads for things like aborting.
428 DuplicateHandle (GetCurrentProcess (), thread_handle, GetCurrentProcess (), &thread_handle,
429 THREAD_ALL_ACCESS, TRUE, 0);
431 thread->handle=thread_handle;
433 thread->stack_ptr = &tid;
434 MONO_OBJECT_SETREF (thread, synch_lock, mono_object_new (domain, mono_defaults.object_class));
436 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
438 handle_store(thread);
440 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, GetCurrentThreadId (), thread));
442 SET_CURRENT_OBJECT (thread);
443 mono_domain_set (domain, TRUE);
445 thread_adjust_static_data (thread);
447 if (mono_thread_attach_cb) {
448 mono_thread_attach_cb (tid, &tid);
455 mono_thread_detach (MonoThread *thread)
457 g_return_if_fail (thread != NULL);
459 THREAD_DEBUG (g_message ("%s: mono_thread_detach for %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
460 SET_CURRENT_OBJECT (NULL);
462 thread_cleanup (thread);
464 /* Don't need to CloseHandle this thread, even though we took a
465 * reference in mono_thread_attach (), because the GC will do it
466 * when the Thread object is finalised.
473 MonoThread *thread = mono_thread_current ();
475 SET_CURRENT_OBJECT (NULL);
476 thread_cleanup (thread);
478 /* we could add a callback here for embedders to use. */
479 if (thread == mono_thread_get_main ())
480 exit (mono_environment_exitcode_get ());
484 HANDLE ves_icall_System_Threading_Thread_Thread_internal(MonoThread *this,
487 guint32 (*start_func)(void *);
488 struct StartInfo *start_info;
494 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this, start));
496 mono_monitor_enter (this->synch_lock);
498 if ((this->state & ThreadState_Unstarted) == 0) {
499 mono_monitor_exit (this->synch_lock);
500 mono_raise_exception (mono_get_exception_thread_state ("Thread has already been started."));
504 if ((this->state & ThreadState_Aborted) != 0) {
505 mono_monitor_exit (this->synch_lock);
510 /* This is freed in start_wrapper */
511 start_info = g_new0 (struct StartInfo, 1);
512 start_info->func = start_func;
513 start_info->start_arg = this->start_obj; /* FIXME: GC object stored in unmanaged memory */
514 start_info->delegate = start;
515 start_info->obj = this;
516 start_info->domain = mono_domain_get ();
518 this->start_notify=CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
519 if(this->start_notify==NULL) {
520 mono_monitor_exit (this->synch_lock);
521 g_warning ("%s: CreateSemaphore error 0x%x", __func__, GetLastError ());
525 thread=CreateThread(NULL, default_stacksize_for_thread (this), (LPTHREAD_START_ROUTINE)start_wrapper, start_info,
526 CREATE_SUSPENDED, &tid);
528 mono_monitor_exit (this->synch_lock);
529 g_warning("%s: CreateThread error 0x%x", __func__, GetLastError());
536 /* Don't call handle_store() here, delay it to Start.
537 * We can't join a thread (trying to will just block
538 * forever) until it actually starts running, so don't
539 * store the handle till then.
542 mono_thread_start (this);
544 this->state &= ~ThreadState_Unstarted;
546 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread));
548 mono_monitor_exit (this->synch_lock);
553 void ves_icall_System_Threading_Thread_Thread_free_internal (MonoThread *this,
558 THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, thread));
560 CloseHandle (thread);
563 static void mono_thread_start (MonoThread *thread)
567 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), thread, (gsize)thread->tid));
569 /* Only store the handle when the thread is about to be
570 * launched, to avoid the main thread deadlocking while trying
571 * to clean up a thread that will never be signalled.
573 handle_store (thread);
575 ResumeThread (thread->handle);
577 if(thread->start_notify!=NULL) {
578 /* Wait for the thread to set up its TLS data etc, so
579 * theres no potential race condition if someone tries
580 * to look up the data believing the thread has
584 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for thread %p (%"G_GSIZE_FORMAT") to start", __func__, GetCurrentThreadId (), thread, (gsize)thread->tid));
586 WaitForSingleObjectEx (thread->start_notify, INFINITE, FALSE);
587 CloseHandle (thread->start_notify);
588 thread->start_notify = NULL;
591 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Done launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), thread, (gsize)thread->tid));
594 void ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
596 MonoThread *thread = mono_thread_current ();
600 THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
602 mono_monitor_enter (thread->synch_lock);
603 thread->state |= ThreadState_WaitSleepJoin;
604 mono_monitor_exit (thread->synch_lock);
608 mono_monitor_enter (thread->synch_lock);
609 thread->state &= ~ThreadState_WaitSleepJoin;
610 mono_monitor_exit (thread->synch_lock);
614 ves_icall_System_Threading_Thread_GetDomainID (void)
618 return mono_domain_get()->domain_id;
622 ves_icall_System_Threading_Thread_GetName_internal (MonoThread *this_obj)
625 mono_monitor_enter (this_obj->synch_lock);
630 str = mono_string_new_utf16 (mono_domain_get (), this_obj->name, this_obj->name_len);
632 mono_monitor_exit (this_obj->synch_lock);
637 ves_icall_System_Threading_Thread_SetName_internal (MonoThread *this_obj, MonoString *name)
639 mono_monitor_enter (this_obj->synch_lock);
641 if (this_obj->name) {
642 mono_monitor_exit (this_obj->synch_lock);
643 mono_raise_exception (mono_get_exception_invalid_operation ("Thread.Name can only be set once."));
647 this_obj->name = g_new (gunichar2, mono_string_length (name));
648 memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2);
649 this_obj->name_len = mono_string_length (name);
652 this_obj->name = NULL;
654 mono_monitor_exit (this_obj->synch_lock);
658 lookup_cached_culture (MonoThread *this, MonoDomain *domain, int start_idx)
663 if (this->cached_culture_info) {
664 domain = mono_domain_get ();
665 for (i = start_idx; i < start_idx + NUM_CACHED_CULTURES; ++i) {
666 res = mono_array_get (this->cached_culture_info, MonoObject*, i);
667 if (res && res->vtable->domain == domain)
676 ves_icall_System_Threading_Thread_GetCachedCurrentCulture (MonoThread *this)
678 return lookup_cached_culture (this, mono_domain_get (), CULTURES_START_IDX);
682 ves_icall_System_Threading_Thread_GetSerializedCurrentCulture (MonoThread *this)
686 mono_monitor_enter (this->synch_lock);
687 if (this->serialized_culture_info) {
688 res = mono_array_new (mono_domain_get (), mono_defaults.byte_class, this->serialized_culture_info_len);
689 memcpy (mono_array_addr (res, guint8, 0), this->serialized_culture_info, this->serialized_culture_info_len);
693 mono_monitor_exit (this->synch_lock);
699 cache_culture (MonoThread *this, MonoObject *culture, int start_idx)
702 MonoDomain *domain = mono_domain_get ();
705 int same_domain_slot = -1;
707 mono_monitor_enter (this->synch_lock);
708 if (!this->cached_culture_info)
709 this->cached_culture_info = mono_array_new (mono_object_domain (this), mono_defaults.object_class, NUM_CACHED_CULTURES * 2);
711 for (i = start_idx; i < start_idx + NUM_CACHED_CULTURES; ++i) {
712 obj = mono_array_get (this->cached_culture_info, MonoObject*, i);
716 /* we continue, because there may be a slot used with the same domain */
720 if (obj->vtable->domain == domain) {
721 same_domain_slot = i;
725 if (same_domain_slot >= 0)
726 mono_array_setref (this->cached_culture_info, same_domain_slot, culture);
727 else if (free_slot >= 0)
728 mono_array_setref (this->cached_culture_info, free_slot, culture);
729 /* we may want to replace an existing entry here, even when no suitable slot is found */
730 mono_monitor_exit (this->synch_lock);
734 ves_icall_System_Threading_Thread_SetCachedCurrentCulture (MonoThread *this, MonoObject *culture)
736 cache_culture (this, culture, CULTURES_START_IDX);
740 ves_icall_System_Threading_Thread_SetSerializedCurrentCulture (MonoThread *this, MonoArray *arr)
742 mono_monitor_enter (this->synch_lock);
743 if (this->serialized_culture_info)
744 g_free (this->serialized_culture_info);
745 this->serialized_culture_info = g_new0 (guint8, mono_array_length (arr));
746 this->serialized_culture_info_len = mono_array_length (arr);
747 memcpy (this->serialized_culture_info, mono_array_addr (arr, guint8, 0), mono_array_length (arr));
748 mono_monitor_exit (this->synch_lock);
753 ves_icall_System_Threading_Thread_GetCachedCurrentUICulture (MonoThread *this)
755 return lookup_cached_culture (this, mono_domain_get (), UICULTURES_START_IDX);
759 ves_icall_System_Threading_Thread_GetSerializedCurrentUICulture (MonoThread *this)
763 mono_monitor_enter (this->synch_lock);
764 if (this->serialized_ui_culture_info) {
765 res = mono_array_new (mono_domain_get (), mono_defaults.byte_class, this->serialized_ui_culture_info_len);
766 memcpy (mono_array_addr (res, guint8, 0), this->serialized_ui_culture_info, this->serialized_ui_culture_info_len);
770 mono_monitor_exit (this->synch_lock);
776 ves_icall_System_Threading_Thread_SetCachedCurrentUICulture (MonoThread *this, MonoObject *culture)
778 cache_culture (this, culture, UICULTURES_START_IDX);
782 ves_icall_System_Threading_Thread_SetSerializedCurrentUICulture (MonoThread *this, MonoArray *arr)
784 mono_monitor_enter (this->synch_lock);
785 if (this->serialized_ui_culture_info)
786 g_free (this->serialized_ui_culture_info);
787 this->serialized_ui_culture_info = g_new0 (guint8, mono_array_length (arr));
788 this->serialized_ui_culture_info_len = mono_array_length (arr);
789 memcpy (this->serialized_ui_culture_info, mono_array_addr (arr, guint8, 0), mono_array_length (arr));
790 mono_monitor_exit (this->synch_lock);
793 /* the jit may read the compiled code of this function */
795 mono_thread_current (void)
797 THREAD_DEBUG (g_message ("%s: returning %p", __func__, GET_CURRENT_OBJECT ()));
798 return GET_CURRENT_OBJECT ();
801 gboolean ves_icall_System_Threading_Thread_Join_internal(MonoThread *this,
802 int ms, HANDLE thread)
808 mono_monitor_enter (this->synch_lock);
810 if ((this->state & ThreadState_Unstarted) != 0) {
811 mono_monitor_exit (this->synch_lock);
812 mono_raise_exception (mono_get_exception_thread_state ("Thread has not been started."));
816 this->state |= ThreadState_WaitSleepJoin;
817 mono_monitor_exit (this->synch_lock);
822 THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, thread, ms));
824 ret=WaitForSingleObjectEx (thread, ms, TRUE);
826 mono_monitor_enter (this->synch_lock);
827 this->state &= ~ThreadState_WaitSleepJoin;
828 mono_monitor_exit (this->synch_lock);
830 if(ret==WAIT_OBJECT_0) {
831 THREAD_DEBUG (g_message ("%s: join successful", __func__));
836 THREAD_DEBUG (g_message ("%s: join failed", __func__));
841 /* FIXME: exitContext isnt documented */
842 gboolean ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
848 MonoObject *waitHandle;
850 MonoThread *thread = mono_thread_current ();
854 numhandles = mono_array_length(mono_handles);
855 handles = g_new0(HANDLE, numhandles);
857 if (wait_handle_os_handle_field == 0) {
858 /* Get the field os_handle which will contain the actual handle */
859 klass = mono_class_from_name(mono_defaults.corlib, "System.Threading", "WaitHandle");
860 wait_handle_os_handle_field = mono_class_get_field_from_name(klass, "os_handle");
863 for(i = 0; i < numhandles; i++) {
864 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
865 mono_field_get_value(waitHandle, wait_handle_os_handle_field, &handles[i]);
872 mono_monitor_enter (thread->synch_lock);
873 thread->state |= ThreadState_WaitSleepJoin;
874 mono_monitor_exit (thread->synch_lock);
876 ret=WaitForMultipleObjectsEx(numhandles, handles, TRUE, ms, TRUE);
878 mono_monitor_enter (thread->synch_lock);
879 thread->state &= ~ThreadState_WaitSleepJoin;
880 mono_monitor_exit (thread->synch_lock);
884 if(ret==WAIT_FAILED) {
885 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
887 } else if(ret==WAIT_TIMEOUT || ret == WAIT_IO_COMPLETION) {
888 /* Do we want to try again if we get
889 * WAIT_IO_COMPLETION? The documentation for
890 * WaitHandle doesn't give any clues. (We'd have to
891 * fiddle with the timeout if we retry.)
893 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
900 /* FIXME: exitContext isnt documented */
901 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
907 MonoObject *waitHandle;
909 MonoThread *thread = mono_thread_current ();
913 numhandles = mono_array_length(mono_handles);
914 handles = g_new0(HANDLE, numhandles);
916 if (wait_handle_os_handle_field == 0) {
917 /* Get the field os_handle which will contain the actual handle */
918 klass = mono_class_from_name(mono_defaults.corlib, "System.Threading", "WaitHandle");
919 wait_handle_os_handle_field = mono_class_get_field_from_name(klass, "os_handle");
922 for(i = 0; i < numhandles; i++) {
923 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
924 mono_field_get_value(waitHandle, wait_handle_os_handle_field, &handles[i]);
931 mono_monitor_enter (thread->synch_lock);
932 thread->state |= ThreadState_WaitSleepJoin;
933 mono_monitor_exit (thread->synch_lock);
935 ret=WaitForMultipleObjectsEx(numhandles, handles, FALSE, ms, TRUE);
937 mono_monitor_enter (thread->synch_lock);
938 thread->state &= ~ThreadState_WaitSleepJoin;
939 mono_monitor_exit (thread->synch_lock);
943 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, GetCurrentThreadId (), ret));
946 * These need to be here. See MSDN dos on WaitForMultipleObjects.
948 if (ret >= WAIT_OBJECT_0 && ret <= WAIT_OBJECT_0 + numhandles - 1) {
949 return ret - WAIT_OBJECT_0;
951 else if (ret >= WAIT_ABANDONED_0 && ret <= WAIT_ABANDONED_0 + numhandles - 1) {
952 return ret - WAIT_ABANDONED_0;
959 /* FIXME: exitContext isnt documented */
960 gboolean ves_icall_System_Threading_WaitHandle_WaitOne_internal(MonoObject *this, HANDLE handle, gint32 ms, gboolean exitContext)
963 MonoThread *thread = mono_thread_current ();
967 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for %p, %d ms", __func__, GetCurrentThreadId (), handle, ms));
973 mono_monitor_enter (thread->synch_lock);
974 thread->state |= ThreadState_WaitSleepJoin;
975 mono_monitor_exit (thread->synch_lock);
977 ret=WaitForSingleObjectEx (handle, ms, TRUE);
979 mono_monitor_enter (thread->synch_lock);
980 thread->state &= ~ThreadState_WaitSleepJoin;
981 mono_monitor_exit (thread->synch_lock);
983 if(ret==WAIT_FAILED) {
984 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
986 } else if(ret==WAIT_TIMEOUT || ret == WAIT_IO_COMPLETION) {
987 /* Do we want to try again if we get
988 * WAIT_IO_COMPLETION? The documentation for
989 * WaitHandle doesn't give any clues. (We'd have to
990 * fiddle with the timeout if we retry.)
992 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
999 HANDLE ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned, MonoString *name, MonoBoolean *created)
1003 MONO_ARCH_SAVE_REGS;
1008 mutex = CreateMutex (NULL, owned, NULL);
1010 mutex = CreateMutex (NULL, owned, mono_string_chars (name));
1012 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1020 void ves_icall_System_Threading_Mutex_ReleaseMutex_internal (HANDLE handle ) {
1021 MONO_ARCH_SAVE_REGS;
1023 ReleaseMutex(handle);
1026 HANDLE ves_icall_System_Threading_Mutex_OpenMutex_internal (MonoString *name,
1032 MONO_ARCH_SAVE_REGS;
1034 *error = ERROR_SUCCESS;
1036 ret = OpenMutex (rights, FALSE, mono_string_chars (name));
1038 *error = GetLastError ();
1045 HANDLE ves_icall_System_Threading_Semaphore_CreateSemaphore_internal (gint32 initialCount, gint32 maximumCount, MonoString *name, MonoBoolean *created)
1049 MONO_ARCH_SAVE_REGS;
1054 sem = CreateSemaphore (NULL, initialCount, maximumCount, NULL);
1056 sem = CreateSemaphore (NULL, initialCount, maximumCount,
1057 mono_string_chars (name));
1059 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1067 gint32 ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal (HANDLE handle, gint32 releaseCount, MonoBoolean *fail)
1071 MONO_ARCH_SAVE_REGS;
1073 *fail = !ReleaseSemaphore (handle, releaseCount, &prevcount);
1078 HANDLE ves_icall_System_Threading_Semaphore_OpenSemaphore_internal (MonoString *name, gint32 rights, gint32 *error)
1082 MONO_ARCH_SAVE_REGS;
1084 *error = ERROR_SUCCESS;
1086 ret = OpenSemaphore (rights, FALSE, mono_string_chars (name));
1088 *error = GetLastError ();
1094 HANDLE ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manual, MonoBoolean initial, MonoString *name, MonoBoolean *created)
1098 MONO_ARCH_SAVE_REGS;
1103 event = CreateEvent (NULL, manual, initial, NULL);
1105 event = CreateEvent (NULL, manual, initial,
1106 mono_string_chars (name));
1108 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1116 gboolean ves_icall_System_Threading_Events_SetEvent_internal (HANDLE handle) {
1117 MONO_ARCH_SAVE_REGS;
1119 return (SetEvent(handle));
1122 gboolean ves_icall_System_Threading_Events_ResetEvent_internal (HANDLE handle) {
1123 MONO_ARCH_SAVE_REGS;
1125 return (ResetEvent(handle));
1129 ves_icall_System_Threading_Events_CloseEvent_internal (HANDLE handle) {
1130 MONO_ARCH_SAVE_REGS;
1132 CloseHandle (handle);
1135 HANDLE ves_icall_System_Threading_Events_OpenEvent_internal (MonoString *name,
1141 MONO_ARCH_SAVE_REGS;
1143 *error = ERROR_SUCCESS;
1145 ret = OpenEvent (rights, FALSE, mono_string_chars (name));
1147 *error = GetLastError ();
1153 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
1155 MONO_ARCH_SAVE_REGS;
1157 return InterlockedIncrement (location);
1160 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
1164 MONO_ARCH_SAVE_REGS;
1166 mono_interlocked_lock ();
1170 mono_interlocked_unlock ();
1176 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
1178 MONO_ARCH_SAVE_REGS;
1180 return InterlockedDecrement(location);
1183 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
1187 MONO_ARCH_SAVE_REGS;
1189 mono_interlocked_lock ();
1193 mono_interlocked_unlock ();
1198 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location, gint32 value)
1200 MONO_ARCH_SAVE_REGS;
1202 return InterlockedExchange(location, value);
1205 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location, MonoObject *value)
1207 MONO_ARCH_SAVE_REGS;
1209 return (MonoObject *) InterlockedExchangePointer((gpointer *) location, value);
1212 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, gfloat value)
1214 IntFloatUnion val, ret;
1216 MONO_ARCH_SAVE_REGS;
1219 ret.ival = InterlockedExchange((gint32 *) location, val.ival);
1225 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64 *location, gint64 value)
1227 #if SIZEOF_VOID_P == 8
1228 return (gint64) InterlockedExchangePointer((gpointer *) location, (gpointer)value);
1233 * According to MSDN, this function is only atomic with regards to the
1234 * other Interlocked functions on 32 bit platforms.
1236 mono_interlocked_lock ();
1239 mono_interlocked_unlock ();
1246 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location, gdouble value)
1248 #if SIZEOF_VOID_P == 8
1249 LongDoubleUnion val, ret;
1252 ret.ival = (gint64)InterlockedExchangePointer((gpointer *) location, (gpointer)val.ival);
1259 * According to MSDN, this function is only atomic with regards to the
1260 * other Interlocked functions on 32 bit platforms.
1262 mono_interlocked_lock ();
1265 mono_interlocked_unlock ();
1271 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location, gint32 value, gint32 comparand)
1273 MONO_ARCH_SAVE_REGS;
1275 return InterlockedCompareExchange(location, value, comparand);
1278 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location, MonoObject *value, MonoObject *comparand)
1280 MONO_ARCH_SAVE_REGS;
1282 return (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location, value, comparand);
1285 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location, gfloat value, gfloat comparand)
1287 IntFloatUnion val, ret, cmp;
1289 MONO_ARCH_SAVE_REGS;
1292 cmp.fval = comparand;
1293 ret.ival = InterlockedCompareExchange((gint32 *) location, val.ival, cmp.ival);
1299 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble *location, gdouble value, gdouble comparand)
1301 #if SIZEOF_VOID_P == 8
1302 LongDoubleUnion val, comp, ret;
1305 comp.fval = comparand;
1306 ret.ival = (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)val.ival, (gpointer)comp.ival);
1312 mono_interlocked_lock ();
1314 if (old == comparand)
1316 mono_interlocked_unlock ();
1323 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location, gint64 value, gint64 comparand)
1325 #if SIZEOF_VOID_P == 8
1326 return (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)value, (gpointer)comparand);
1330 mono_interlocked_lock ();
1332 if (old == comparand)
1334 mono_interlocked_unlock ();
1341 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject **location, MonoObject *value, MonoObject *comparand)
1343 MONO_ARCH_SAVE_REGS;
1345 return InterlockedCompareExchangePointer ((gpointer *)location, value, comparand);
1349 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject **location, MonoObject *value)
1351 MONO_ARCH_SAVE_REGS;
1353 return InterlockedExchangePointer ((gpointer *)location, value);
1357 ves_icall_System_Threading_Interlocked_Add_Int (gint32 *location, gint32 value)
1359 #if SIZEOF_VOID_P == 8
1360 /* Should be implemented as a JIT intrinsic */
1361 mono_raise_exception (mono_get_exception_not_implemented (NULL));
1366 mono_interlocked_lock ();
1368 *location = orig + value;
1369 mono_interlocked_unlock ();
1371 return orig + value;
1376 ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location, gint64 value)
1378 #if SIZEOF_VOID_P == 8
1379 /* Should be implemented as a JIT intrinsic */
1380 mono_raise_exception (mono_get_exception_not_implemented (NULL));
1385 mono_interlocked_lock ();
1387 *location = orig + value;
1388 mono_interlocked_unlock ();
1390 return orig + value;
1395 ves_icall_System_Threading_Interlocked_Read_Long (gint64 *location)
1397 #if SIZEOF_VOID_P == 8
1398 /* 64 bit reads are already atomic */
1403 mono_interlocked_lock ();
1405 mono_interlocked_unlock ();
1412 ves_icall_System_Threading_Thread_MemoryBarrier (void)
1414 /* Should be implemented as a JIT intrinsic */
1415 mono_raise_exception (mono_get_exception_not_implemented (NULL));
1419 ves_icall_System_Threading_Thread_ClrState (MonoThread* this, guint32 state)
1421 mono_monitor_enter (this->synch_lock);
1422 this->state &= ~state;
1423 if (state & ThreadState_Background) {
1424 /* If the thread changes the background mode, the main thread has to
1425 * be notified, since it has to rebuild the list of threads to
1428 SetEvent (background_change_event);
1430 mono_monitor_exit (this->synch_lock);
1434 ves_icall_System_Threading_Thread_SetState (MonoThread* this, guint32 state)
1436 mono_monitor_enter (this->synch_lock);
1437 this->state |= state;
1438 if (state & ThreadState_Background) {
1439 /* If the thread changes the background mode, the main thread has to
1440 * be notified, since it has to rebuild the list of threads to
1443 SetEvent (background_change_event);
1445 mono_monitor_exit (this->synch_lock);
1449 ves_icall_System_Threading_Thread_GetState (MonoThread* this)
1452 mono_monitor_enter (this->synch_lock);
1453 state = this->state;
1454 mono_monitor_exit (this->synch_lock);
1459 mono_thread_get_abort_signal (void)
1461 #if defined (__MINGW32__) || defined (_MSC_VER)
1467 static int abort_signum = -1;
1469 if (abort_signum != -1)
1470 return abort_signum;
1471 /* we try to avoid SIGRTMIN and any one that might have been set already, see bug #75387 */
1472 for (i = SIGRTMIN + 1; i < SIGRTMAX; ++i) {
1473 struct sigaction sinfo;
1474 sigaction (i, NULL, &sinfo);
1475 if (sinfo.sa_handler == SIG_DFL && (void*)sinfo.sa_sigaction == (void*)SIG_DFL) {
1480 /* fallback to the old way */
1483 #endif /*defined (__MINGW32__) || defined (_MSC_VER) */
1486 #if defined (__MINGW32__) || defined (_MSC_VER)
1487 static void CALLBACK interruption_request_apc (ULONG_PTR param)
1489 MonoException* exc = mono_thread_request_interruption (FALSE);
1490 if (exc) mono_raise_exception (exc);
1492 #endif /* defined (__MINGW32__) || defined (_MSC_VER) */
1495 * signal_thread_state_change
1497 * Tells the thread that his state has changed and it has to enter the new
1498 * state as soon as possible.
1500 static void signal_thread_state_change (MonoThread *thread)
1502 if (thread == mono_thread_current ()) {
1503 /* Do it synchronously */
1504 MonoException *exc = mono_thread_request_interruption (FALSE);
1506 mono_raise_exception (exc);
1509 #if defined (__MINGW32__) || defined (_MSC_VER)
1510 QueueUserAPC ((PAPCFUNC)interruption_request_apc, thread->handle, NULL);
1512 /* fixme: store the state somewhere */
1513 #ifdef PTHREAD_POINTER_ID
1514 pthread_kill ((gpointer)(gsize)(thread->tid), mono_thread_get_abort_signal ());
1516 pthread_kill (thread->tid, mono_thread_get_abort_signal ());
1518 #endif /* defined (__MINGW32__) || defined (__MSC_VER) */
1522 ves_icall_System_Threading_Thread_Abort (MonoThread *thread, MonoObject *state)
1524 MONO_ARCH_SAVE_REGS;
1526 mono_monitor_enter (thread->synch_lock);
1528 if ((thread->state & ThreadState_AbortRequested) != 0 ||
1529 (thread->state & ThreadState_StopRequested) != 0 ||
1530 (thread->state & ThreadState_Stopped) != 0)
1532 mono_monitor_exit (thread->synch_lock);
1536 if ((thread->state & ThreadState_Unstarted) != 0) {
1537 thread->state |= ThreadState_Aborted;
1538 mono_monitor_exit (thread->synch_lock);
1542 thread->state |= ThreadState_AbortRequested;
1543 MONO_OBJECT_SETREF (thread, abort_state, state);
1544 thread->abort_exc = NULL;
1546 mono_monitor_exit (thread->synch_lock);
1548 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Abort requested for %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), thread, (gsize)thread->tid));
1550 /* Make sure the thread is awake */
1551 mono_thread_resume (thread);
1553 signal_thread_state_change (thread);
1557 ves_icall_System_Threading_Thread_ResetAbort (void)
1559 MonoThread *thread = mono_thread_current ();
1561 MONO_ARCH_SAVE_REGS;
1563 mono_monitor_enter (thread->synch_lock);
1565 thread->state &= ~ThreadState_AbortRequested;
1567 if (!thread->abort_exc) {
1568 const char *msg = "Unable to reset abort because no abort was requested";
1569 mono_monitor_exit (thread->synch_lock);
1570 mono_raise_exception (mono_get_exception_thread_state (msg));
1572 thread->abort_exc = NULL;
1573 thread->abort_state = NULL;
1576 mono_monitor_exit (thread->synch_lock);
1580 mono_thread_suspend (MonoThread *thread)
1582 MONO_ARCH_SAVE_REGS;
1584 mono_monitor_enter (thread->synch_lock);
1586 if ((thread->state & ThreadState_Unstarted) != 0 ||
1587 (thread->state & ThreadState_Aborted) != 0 ||
1588 (thread->state & ThreadState_Stopped) != 0)
1590 mono_monitor_exit (thread->synch_lock);
1594 if ((thread->state & ThreadState_Suspended) != 0 ||
1595 (thread->state & ThreadState_SuspendRequested) != 0 ||
1596 (thread->state & ThreadState_StopRequested) != 0)
1598 mono_monitor_exit (thread->synch_lock);
1602 thread->state |= ThreadState_SuspendRequested;
1603 mono_monitor_exit (thread->synch_lock);
1605 signal_thread_state_change (thread);
1610 ves_icall_System_Threading_Thread_Suspend (MonoThread *thread)
1612 if (!mono_thread_suspend (thread))
1613 mono_raise_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
1617 mono_thread_resume (MonoThread *thread)
1619 MONO_ARCH_SAVE_REGS;
1621 mono_monitor_enter (thread->synch_lock);
1623 if ((thread->state & ThreadState_SuspendRequested) != 0) {
1624 thread->state &= ~ThreadState_SuspendRequested;
1625 mono_monitor_exit (thread->synch_lock);
1629 if ((thread->state & ThreadState_Suspended) == 0 ||
1630 (thread->state & ThreadState_Unstarted) != 0 ||
1631 (thread->state & ThreadState_Aborted) != 0 ||
1632 (thread->state & ThreadState_Stopped) != 0)
1634 mono_monitor_exit (thread->synch_lock);
1638 thread->resume_event = CreateEvent (NULL, TRUE, FALSE, NULL);
1640 /* Awake the thread */
1641 SetEvent (thread->suspend_event);
1643 mono_monitor_exit (thread->synch_lock);
1645 /* Wait for the thread to awake */
1646 WaitForSingleObject (thread->resume_event, INFINITE);
1647 CloseHandle (thread->resume_event);
1648 thread->resume_event = NULL;
1654 ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
1656 if (!mono_thread_resume (thread))
1657 mono_raise_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
1661 find_wrapper (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
1666 if (m->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE ||
1667 m->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE ||
1668 m->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH)
1670 *((gboolean*)data) = TRUE;
1677 is_running_protected_wrapper (void)
1679 gboolean found = FALSE;
1680 mono_stack_walk (find_wrapper, &found);
1684 void mono_thread_stop (MonoThread *thread)
1686 mono_monitor_enter (thread->synch_lock);
1688 if ((thread->state & ThreadState_StopRequested) != 0 ||
1689 (thread->state & ThreadState_Stopped) != 0)
1691 mono_monitor_exit (thread->synch_lock);
1695 /* Make sure the thread is awake */
1696 mono_thread_resume (thread);
1698 thread->state |= ThreadState_StopRequested;
1699 thread->state &= ~ThreadState_AbortRequested;
1701 mono_monitor_exit (thread->synch_lock);
1703 signal_thread_state_change (thread);
1707 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
1709 return *((volatile gint8 *) (ptr));
1713 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
1715 return *((volatile gint16 *) (ptr));
1719 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
1721 return *((volatile gint32 *) (ptr));
1725 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
1727 return *((volatile gint64 *) (ptr));
1731 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
1733 return (void *) *((volatile void **) ptr);
1737 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
1739 *((volatile gint8 *) ptr) = value;
1743 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
1745 *((volatile gint16 *) ptr) = value;
1749 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
1751 *((volatile gint32 *) ptr) = value;
1755 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
1757 *((volatile gint64 *) ptr) = value;
1761 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
1763 *((volatile void **) ptr) = value;
1766 void mono_thread_init (MonoThreadStartCB start_cb,
1767 MonoThreadAttachCB attach_cb)
1769 InitializeCriticalSection(&threads_mutex);
1770 InitializeCriticalSection(&interlocked_mutex);
1771 InitializeCriticalSection(&contexts_mutex);
1772 background_change_event = CreateEvent (NULL, TRUE, FALSE, NULL);
1774 mono_init_static_data_info (&thread_static_info);
1775 mono_init_static_data_info (&context_static_info);
1777 current_object_key=TlsAlloc();
1778 THREAD_DEBUG (g_message ("%s: Allocated current_object_key %d", __func__, current_object_key));
1780 mono_thread_start_cb = start_cb;
1781 mono_thread_attach_cb = attach_cb;
1783 /* Get a pseudo handle to the current process. This is just a
1784 * kludge so that wapi can build a process handle if needed.
1785 * As a pseudo handle is returned, we don't need to clean
1788 GetCurrentProcess ();
1791 void mono_thread_cleanup (void)
1793 #if !defined(PLATFORM_WIN32) && !defined(RUN_IN_SUBTHREAD)
1794 /* The main thread must abandon any held mutexes (particularly
1795 * important for named mutexes as they are shared across
1796 * processes, see bug 74680.) This will happen when the
1797 * thread exits, but if it's not running in a subthread it
1798 * won't exit in time.
1800 /* Using non-w32 API is a nasty kludge, but I couldn't find
1801 * anything in the documentation that would let me do this
1802 * here yet still be safe to call on windows.
1804 _wapi_thread_signal_self (mono_environment_exitcode_get ());
1807 DeleteCriticalSection (&threads_mutex);
1808 DeleteCriticalSection (&interlocked_mutex);
1809 DeleteCriticalSection (&contexts_mutex);
1810 CloseHandle (background_change_event);
1814 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
1816 mono_thread_cleanup_fn = func;
1820 static void print_tids (gpointer key, gpointer value, gpointer user)
1822 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
1823 * sizeof(uint) and a cast to uint would overflow
1825 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
1826 * print this as a pointer.
1828 g_message ("Waiting for: %p", key);
1833 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
1834 MonoThread *threads[MAXIMUM_WAIT_OBJECTS];
1838 static void wait_for_tids (struct wait_data *wait, guint32 timeout)
1842 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
1844 ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, FALSE);
1846 if(ret==WAIT_FAILED) {
1847 /* See the comment in build_wait_tids() */
1848 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
1852 for(i=0; i<wait->num; i++)
1853 CloseHandle (wait->handles[i]);
1855 if (ret == WAIT_TIMEOUT)
1858 for(i=0; i<wait->num; i++) {
1859 gsize tid = wait->threads[i]->tid;
1861 if(mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
1862 /* This thread must have been killed, because
1863 * it hasn't cleaned itself up. (It's just
1864 * possible that the thread exited before the
1865 * parent thread had a chance to store the
1866 * handle, and now there is another pointer to
1867 * the already-exited thread stored. In this
1868 * case, we'll just get two
1869 * mono_profiler_thread_end() calls for the
1873 THREAD_DEBUG (g_message ("%s: cleaning up after thread %"G_GSIZE_FORMAT, __func__, tid));
1874 thread_cleanup (wait->threads[i]);
1879 static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeout)
1881 guint32 i, ret, count;
1883 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
1885 /* Add the thread state change event, so it wakes up if a thread changes
1886 * to background mode.
1889 if (count < MAXIMUM_WAIT_OBJECTS) {
1890 wait->handles [count] = background_change_event;
1894 ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, FALSE);
1896 if(ret==WAIT_FAILED) {
1897 /* See the comment in build_wait_tids() */
1898 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
1902 for(i=0; i<wait->num; i++)
1903 CloseHandle (wait->handles[i]);
1905 if (ret == WAIT_TIMEOUT)
1908 if (ret < wait->num) {
1909 gsize tid = wait->threads[ret]->tid;
1910 mono_threads_lock ();
1911 if (mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
1912 /* See comment in wait_for_tids about thread cleanup */
1913 mono_threads_unlock ();
1914 THREAD_DEBUG (g_message ("%s: cleaning up after thread %"G_GSIZE_FORMAT, __func__, tid));
1915 thread_cleanup (wait->threads [ret]);
1917 mono_threads_unlock ();
1921 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
1923 struct wait_data *wait=(struct wait_data *)user;
1925 if(wait->num<MAXIMUM_WAIT_OBJECTS) {
1927 MonoThread *thread=(MonoThread *)value;
1929 /* Ignore background threads, we abort them later */
1930 mono_monitor_enter (thread->synch_lock);
1931 if (thread->state & ThreadState_Background) {
1932 THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
1933 mono_monitor_exit (thread->synch_lock);
1934 return; /* just leave, ignore */
1936 mono_monitor_exit (thread->synch_lock);
1938 if (mono_gc_is_finalizer_thread (thread)) {
1939 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
1943 if (thread == mono_thread_current ()) {
1944 THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
1948 if (thread == mono_thread_get_main ()) {
1949 THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
1953 handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
1954 if (handle == NULL) {
1955 THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
1959 wait->handles[wait->num]=handle;
1960 wait->threads[wait->num]=thread;
1963 THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
1965 /* Just ignore the rest, we can't do anything with
1972 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
1974 struct wait_data *wait=(struct wait_data *)user;
1975 gsize self = GetCurrentThreadId ();
1976 MonoThread *thread = (MonoThread *) value;
1979 if (wait->num >= MAXIMUM_WAIT_OBJECTS)
1982 /* The finalizer thread is not a background thread */
1983 if (thread->tid != self && (thread->state & ThreadState_Background) != 0) {
1985 handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
1989 if(thread->state & ThreadState_AbortRequested ||
1990 thread->state & ThreadState_Aborted) {
1991 THREAD_DEBUG (g_message ("%s: Thread id %"G_GSIZE_FORMAT" already aborting", __func__, (gsize)thread->tid));
1995 /* printf ("A: %d\n", wait->num); */
1996 wait->handles[wait->num]=thread->handle;
1997 wait->threads[wait->num]=thread;
2000 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
2001 mono_thread_stop (thread);
2005 return (thread->tid != self && !mono_gc_is_finalizer_thread (thread));
2008 void mono_thread_manage (void)
2010 struct wait_data *wait=g_new0 (struct wait_data, 1);
2012 /* join each thread that's still running */
2013 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
2015 mono_threads_lock ();
2017 THREAD_DEBUG (g_message("%s: No threads", __func__));
2018 mono_threads_unlock ();
2021 mono_threads_unlock ();
2024 mono_threads_lock ();
2025 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
2026 mono_g_hash_table_foreach (threads, print_tids, NULL));
2028 ResetEvent (background_change_event);
2030 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
2031 mono_threads_unlock ();
2033 /* Something to wait for */
2034 wait_for_tids_or_state_change (wait, INFINITE);
2036 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
2037 } while(wait->num>0);
2039 mono_runtime_set_shutting_down ();
2041 THREAD_DEBUG (g_message ("%s: threadpool cleanup", __func__));
2042 mono_thread_pool_cleanup ();
2045 * Remove everything but the finalizer thread and self.
2046 * Also abort all the background threads
2049 mono_threads_lock ();
2052 mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
2054 mono_threads_unlock ();
2056 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
2058 /* Something to wait for */
2059 wait_for_tids (wait, INFINITE);
2061 } while (wait->num > 0);
2064 * give the subthreads a chance to really quit (this is mainly needed
2065 * to get correct user and system times from getrusage/wait/time(1)).
2066 * This could be removed if we avoid pthread_detach() and use pthread_join().
2068 #ifndef PLATFORM_WIN32
2075 static void terminate_thread (gpointer key, gpointer value, gpointer user)
2077 MonoThread *thread=(MonoThread *)value;
2079 if(thread->tid != (gsize)user) {
2080 /*TerminateThread (thread->handle, -1);*/
2084 void mono_thread_abort_all_other_threads (void)
2086 gsize self = GetCurrentThreadId ();
2088 mono_threads_lock ();
2089 THREAD_DEBUG (g_message ("%s: There are %d threads to abort", __func__,
2090 mono_g_hash_table_size (threads));
2091 mono_g_hash_table_foreach (threads, print_tids, NULL));
2093 mono_g_hash_table_foreach (threads, terminate_thread, (gpointer)self);
2095 mono_threads_unlock ();
2099 collect_threads (gpointer key, gpointer value, gpointer user_data)
2101 MonoThread *thread = (MonoThread*)value;
2102 struct wait_data *wait = (struct wait_data*)user_data;
2105 if (wait->num<MAXIMUM_WAIT_OBJECTS) {
2106 handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
2110 wait->handles [wait->num] = handle;
2111 wait->threads [wait->num] = thread;
2117 * mono_thread_suspend_all_other_threads:
2119 * Suspend all managed threads except the finalizer thread and this thread.
2121 void mono_thread_suspend_all_other_threads (void)
2123 struct wait_data *wait = g_new0 (struct wait_data, 1);
2125 gsize self = GetCurrentThreadId ();
2127 guint32 eventidx = 0;
2130 * Make a copy of the hashtable since we can't do anything with
2131 * threads while threads_mutex is held.
2133 mono_threads_lock ();
2134 mono_g_hash_table_foreach (threads, collect_threads, wait);
2135 mono_threads_unlock ();
2137 events = g_new0 (gpointer, wait->num);
2139 /* Get the suspended events that we'll be waiting for */
2140 for (i = 0; i < wait->num; ++i) {
2141 MonoThread *thread = wait->threads [i];
2143 if ((thread->tid == self) || mono_gc_is_finalizer_thread (thread)) {
2144 //CloseHandle (wait->handles [i]);
2145 wait->threads [i] = NULL; /* ignore this thread in next loop */
2149 mono_monitor_enter (thread->synch_lock);
2151 if ((thread->state & ThreadState_Suspended) != 0 ||
2152 (thread->state & ThreadState_SuspendRequested) != 0 ||
2153 (thread->state & ThreadState_StopRequested) != 0 ||
2154 (thread->state & ThreadState_Stopped) != 0) {
2155 mono_monitor_exit (thread->synch_lock);
2156 CloseHandle (wait->handles [i]);
2157 wait->threads [i] = NULL; /* ignore this thread in next loop */
2161 /* Convert abort requests into suspend requests */
2162 if ((thread->state & ThreadState_AbortRequested) != 0)
2163 thread->state &= ~ThreadState_AbortRequested;
2165 thread->state |= ThreadState_SuspendRequested;
2167 if (thread->suspended_event == NULL)
2168 thread->suspended_event = CreateEvent (NULL, TRUE, FALSE, NULL);
2170 events [eventidx++] = thread->suspended_event;
2171 mono_monitor_exit (thread->synch_lock);
2173 /* Signal the thread to suspend */
2174 signal_thread_state_change (thread);
2177 WaitForMultipleObjectsEx (eventidx, events, TRUE, INFINITE, FALSE);
2178 for (i = 0; i < wait->num; ++i) {
2179 MonoThread *thread = wait->threads [i];
2184 mono_monitor_enter (thread->synch_lock);
2185 CloseHandle (thread->suspended_event);
2186 thread->suspended_event = NULL;
2187 mono_monitor_exit (thread->synch_lock);
2195 * mono_threads_request_thread_dump:
2197 * Ask all threads except the current to print their stacktrace to stdout.
2200 mono_threads_request_thread_dump (void)
2202 struct wait_data *wait = g_new0 (struct wait_data, 1);
2206 * Make a copy of the hashtable since we can't do anything with
2207 * threads while threads_mutex is held.
2209 mono_threads_lock ();
2210 mono_g_hash_table_foreach (threads, collect_threads, wait);
2211 mono_threads_unlock ();
2213 for (i = 0; i < wait->num; ++i) {
2214 MonoThread *thread = wait->threads [i];
2216 if (!mono_gc_is_finalizer_thread (thread) && (thread != mono_thread_current ()) && !thread->thread_dump_requested) {
2217 thread->thread_dump_requested = TRUE;
2219 signal_thread_state_change (thread);
2222 CloseHandle (wait->handles [i]);
2227 * mono_thread_push_appdomain_ref:
2229 * Register that the current thread may have references to objects in domain
2230 * @domain on its stack. Each call to this function should be paired with a
2231 * call to pop_appdomain_ref.
2234 mono_thread_push_appdomain_ref (MonoDomain *domain)
2236 MonoThread *thread = mono_thread_current ();
2239 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
2240 mono_threads_lock ();
2241 thread->appdomain_refs = g_slist_prepend (thread->appdomain_refs, domain);
2242 mono_threads_unlock ();
2247 mono_thread_pop_appdomain_ref (void)
2249 MonoThread *thread = mono_thread_current ();
2252 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
2253 mono_threads_lock ();
2254 /* FIXME: How can the list be empty ? */
2255 if (thread->appdomain_refs)
2256 thread->appdomain_refs = g_slist_remove (thread->appdomain_refs, thread->appdomain_refs->data);
2257 mono_threads_unlock ();
2262 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
2265 mono_threads_lock ();
2266 res = g_slist_find (thread->appdomain_refs, domain) != NULL;
2267 mono_threads_unlock ();
2271 typedef struct abort_appdomain_data {
2272 struct wait_data wait;
2274 } abort_appdomain_data;
2277 abort_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
2279 MonoThread *thread = (MonoThread*)value;
2280 abort_appdomain_data *data = (abort_appdomain_data*)user_data;
2281 MonoDomain *domain = data->domain;
2283 if (mono_thread_has_appdomain_ref (thread, domain)) {
2284 HANDLE handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
2288 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
2290 ves_icall_System_Threading_Thread_Abort (thread, NULL);
2292 if(data->wait.num<MAXIMUM_WAIT_OBJECTS) {
2293 data->wait.handles [data->wait.num] = handle;
2294 data->wait.threads [data->wait.num] = thread;
2297 /* Just ignore the rest, we can't do anything with
2305 * mono_threads_abort_appdomain_threads:
2307 * Abort threads which has references to the given appdomain.
2310 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
2312 abort_appdomain_data user_data;
2315 /* printf ("ABORT BEGIN.\n"); */
2317 start_time = GetTickCount ();
2319 mono_threads_lock ();
2321 user_data.domain = domain;
2322 user_data.wait.num = 0;
2323 mono_g_hash_table_foreach (threads, abort_appdomain_thread, &user_data);
2324 mono_threads_unlock ();
2326 if (user_data.wait.num > 0)
2328 * We should wait for the threads either to abort, or to leave the
2329 * domain. We can't do the latter, so we wait with a timeout.
2331 wait_for_tids (&user_data.wait, 100);
2333 /* Update remaining time */
2334 timeout -= GetTickCount () - start_time;
2335 start_time = GetTickCount ();
2340 while (user_data.wait.num > 0);
2342 /* printf ("ABORT DONE.\n"); */
2348 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
2350 MonoThread *thread = (MonoThread*)value;
2351 MonoDomain *domain = (MonoDomain*)user_data;
2354 /* No locking needed here */
2355 /* FIXME: why no locking? writes to the cache are protected with synch_lock above */
2357 if (thread->cached_culture_info) {
2358 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
2359 MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
2360 if (obj && obj->vtable->domain == domain)
2361 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
2367 * mono_threads_clear_cached_culture:
2369 * Clear the cached_current_culture from all threads if it is in the
2373 mono_threads_clear_cached_culture (MonoDomain *domain)
2375 mono_threads_lock ();
2376 mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
2377 mono_threads_unlock ();
2381 * mono_thread_get_pending_exception:
2383 * Return an exception which needs to be raised when leaving a catch clause.
2384 * This is used for undeniable exception propagation.
2387 mono_thread_get_pending_exception (void)
2389 MonoThread *thread = mono_thread_current ();
2391 MONO_ARCH_SAVE_REGS;
2393 if (thread && thread->abort_exc && !is_running_protected_wrapper ()) {
2395 * FIXME: Clear the abort exception and return an AppDomainUnloaded
2396 * exception if the thread no longer references a dying appdomain.
2398 thread->abort_exc->trace_ips = NULL;
2399 thread->abort_exc->stack_trace = NULL;
2400 return thread->abort_exc;
2406 #define NUM_STATIC_DATA_IDX 8
2407 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
2408 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
2413 * mono_alloc_static_data
2415 * Allocate memory blocks for storing threads or context static data
2418 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset)
2420 guint idx = (offset >> 24) - 1;
2423 gpointer* static_data = *static_data_ptr;
2425 static_data = mono_gc_alloc_fixed (static_data_size [0], NULL);
2426 *static_data_ptr = static_data;
2427 static_data [0] = static_data;
2430 for (i = 1; i <= idx; ++i) {
2431 if (static_data [i])
2433 static_data [i] = mono_gc_alloc_fixed (static_data_size [i], NULL);
2438 * mono_init_static_data_info
2440 * Initializes static data counters
2442 static void mono_init_static_data_info (StaticDataInfo *static_data)
2444 static_data->idx = 0;
2445 static_data->offset = 0;
2449 * mono_alloc_static_data_slot
2451 * Generates an offset for static data. static_data contains the counters
2452 * used to generate it.
2455 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
2459 if (!static_data->idx && !static_data->offset) {
2461 * we use the first chunk of the first allocation also as
2462 * an array for the rest of the data
2464 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
2466 static_data->offset += align - 1;
2467 static_data->offset &= ~(align - 1);
2468 if (static_data->offset + size >= static_data_size [static_data->idx]) {
2469 static_data->idx ++;
2470 g_assert (size <= static_data_size [static_data->idx]);
2472 * massive unloading and reloading of domains with thread-static
2473 * data may eventually exceed the allocated storage...
2474 * Need to check what the MS runtime does in that case.
2475 * Note that for each appdomain, we need to allocate a separate
2476 * thread data slot for security reasons. We could keep track
2477 * of the slots per-domain and when the domain is unloaded
2478 * out the slots on a sort of free list.
2480 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
2481 static_data->offset = 0;
2483 offset = static_data->offset | ((static_data->idx + 1) << 24);
2484 static_data->offset += size;
2489 * ensure thread static fields already allocated are valid for thread
2490 * This function is called when a thread is created or on thread attach.
2493 thread_adjust_static_data (MonoThread *thread)
2497 mono_threads_lock ();
2498 if (thread_static_info.offset || thread_static_info.idx > 0) {
2499 /* get the current allocated size */
2500 offset = thread_static_info.offset | ((thread_static_info.idx + 1) << 24);
2501 mono_alloc_static_data (&(thread->static_data), offset);
2503 mono_threads_unlock ();
2507 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
2509 MonoThread *thread = value;
2510 guint32 offset = GPOINTER_TO_UINT (user);
2512 mono_alloc_static_data (&(thread->static_data), offset);
2516 * The offset for a special static variable is composed of three parts:
2517 * a bit that indicates the type of static data (0:thread, 1:context),
2518 * an index in the array of chunks of memory for the thread (thread->static_data)
2519 * and an offset in that chunk of mem. This allows allocating less memory in the
2524 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align)
2527 if (static_type == SPECIAL_STATIC_THREAD)
2529 mono_threads_lock ();
2530 offset = mono_alloc_static_data_slot (&thread_static_info, size, align);
2531 /* This can be called during startup */
2532 if (threads != NULL)
2533 mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
2534 mono_threads_unlock ();
2538 g_assert (static_type == SPECIAL_STATIC_CONTEXT);
2539 mono_contexts_lock ();
2540 offset = mono_alloc_static_data_slot (&context_static_info, size, align);
2541 mono_contexts_unlock ();
2542 offset |= 0x80000000; /* Set the high bit to indicate context static data */
2548 mono_get_special_static_data (guint32 offset)
2550 /* The high bit means either thread (0) or static (1) data. */
2552 guint32 static_type = (offset & 0x80000000);
2555 offset &= 0x7fffffff;
2556 idx = (offset >> 24) - 1;
2558 if (static_type == 0)
2560 MonoThread *thread = mono_thread_current ();
2561 return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
2565 /* Allocate static data block under demand, since we don't have a list
2568 MonoAppContext *context = mono_context_get ();
2569 if (!context->static_data || !context->static_data [idx]) {
2570 mono_contexts_lock ();
2571 mono_alloc_static_data (&(context->static_data), offset);
2572 mono_contexts_unlock ();
2574 return ((char*) context->static_data [idx]) + (offset & 0xffffff);
2578 static MonoClassField *local_slots = NULL;
2581 /* local tls data to get locals_slot from a thread */
2584 /* index in the locals_slot array */
2589 clear_local_slot (gpointer key, gpointer value, gpointer user_data)
2591 LocalSlotID *sid = user_data;
2592 MonoThread *thread = (MonoThread*)value;
2593 MonoArray *slots_array;
2595 * the static field is stored at: ((char*) thread->static_data [idx]) + (offset & 0xffffff);
2596 * it is for the right domain, so we need to check if it is allocated an initialized
2597 * for the current thread.
2599 /*g_print ("handling thread %p\n", thread);*/
2600 if (!thread->static_data || !thread->static_data [sid->idx])
2602 slots_array = *(MonoArray **)(((char*) thread->static_data [sid->idx]) + (sid->offset & 0xffffff));
2603 if (!slots_array || sid->slot >= mono_array_length (slots_array))
2605 mono_array_set (slots_array, MonoObject*, sid->slot, NULL);
2609 mono_thread_free_local_slot_values (int slot, MonoBoolean thread_local)
2617 local_slots = mono_class_get_field_from_name (mono_defaults.thread_class, "local_slots");
2619 g_warning ("local_slots field not found in Thread class");
2623 domain = mono_domain_get ();
2624 mono_domain_lock (domain);
2625 if (domain->special_static_fields)
2626 addr = g_hash_table_lookup (domain->special_static_fields, local_slots);
2627 mono_domain_unlock (domain);
2630 /*g_print ("freeing slot %d at %p\n", slot, addr);*/
2631 sid.offset = GPOINTER_TO_UINT (addr);
2632 sid.offset &= 0x7fffffff;
2633 sid.idx = (sid.offset >> 24) - 1;
2634 mono_threads_lock ();
2635 mono_g_hash_table_foreach (threads, clear_local_slot, &sid);
2636 mono_threads_unlock ();
2638 /* FIXME: clear the slot for MonoAppContexts, too */
2643 static CALLBACK void dummy_apc (ULONG_PTR param)
2647 static guint32 dummy_apc (gpointer param)
2654 * mono_thread_execute_interruption
2656 * Performs the operation that the requested thread state requires (abort,
2659 static MonoException* mono_thread_execute_interruption (MonoThread *thread)
2661 mono_monitor_enter (thread->synch_lock);
2663 if (thread->interruption_requested) {
2664 /* this will consume pending APC calls */
2665 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
2666 InterlockedDecrement (&thread_interruption_requested);
2667 thread->interruption_requested = FALSE;
2670 if ((thread->state & ThreadState_AbortRequested) != 0) {
2671 if (thread->abort_exc == NULL)
2672 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
2673 mono_monitor_exit (thread->synch_lock);
2674 return thread->abort_exc;
2676 else if ((thread->state & ThreadState_SuspendRequested) != 0) {
2677 thread->state &= ~ThreadState_SuspendRequested;
2678 thread->state |= ThreadState_Suspended;
2679 thread->suspend_event = CreateEvent (NULL, TRUE, FALSE, NULL);
2680 if (thread->suspended_event)
2681 SetEvent (thread->suspended_event);
2682 mono_monitor_exit (thread->synch_lock);
2684 WaitForSingleObject (thread->suspend_event, INFINITE);
2686 mono_monitor_enter (thread->synch_lock);
2687 CloseHandle (thread->suspend_event);
2688 thread->suspend_event = NULL;
2689 thread->state &= ~ThreadState_Suspended;
2691 /* The thread that requested the resume will have replaced this event
2692 * and will be waiting for it
2694 SetEvent (thread->resume_event);
2695 mono_monitor_exit (thread->synch_lock);
2698 else if ((thread->state & ThreadState_StopRequested) != 0) {
2699 /* FIXME: do this through the JIT? */
2700 mono_monitor_exit (thread->synch_lock);
2701 mono_thread_exit ();
2705 mono_monitor_exit (thread->synch_lock);
2710 * mono_thread_request_interruption
2712 * A signal handler can call this method to request the interruption of a
2713 * thread. The result of the interruption will depend on the current state of
2714 * the thread. If the result is an exception that needs to be throw, it is
2715 * provided as return value.
2717 MonoException* mono_thread_request_interruption (gboolean running_managed)
2719 MonoThread *thread = mono_thread_current ();
2721 /* The thread may already be stopping */
2725 mono_monitor_enter (thread->synch_lock);
2727 if (thread->interruption_requested) {
2728 mono_monitor_exit (thread->synch_lock);
2732 if (!running_managed || is_running_protected_wrapper ()) {
2733 /* Can't stop while in unmanaged code. Increase the global interruption
2734 request count. When exiting the unmanaged method the count will be
2735 checked and the thread will be interrupted. */
2737 InterlockedIncrement (&thread_interruption_requested);
2738 thread->interruption_requested = TRUE;
2739 mono_monitor_exit (thread->synch_lock);
2741 /* this will awake the thread if it is in WaitForSingleObject
2743 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, NULL);
2747 mono_monitor_exit (thread->synch_lock);
2748 return mono_thread_execute_interruption (thread);
2752 gboolean mono_thread_interruption_requested ()
2754 if (thread_interruption_requested) {
2755 MonoThread *thread = mono_thread_current ();
2756 /* The thread may already be stopping */
2758 return (thread->interruption_requested);
2763 static void mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
2765 MonoThread *thread = mono_thread_current ();
2767 /* The thread may already be stopping */
2771 if (thread->interruption_requested && (bypass_abort_protection || !is_running_protected_wrapper ())) {
2772 MonoException* exc = mono_thread_execute_interruption (thread);
2773 if (exc) mono_raise_exception (exc);
2778 * Performs the interruption of the current thread, if one has been requested,
2779 * and the thread is not running a protected wrapper.
2781 void mono_thread_interruption_checkpoint ()
2783 mono_thread_interruption_checkpoint_request (FALSE);
2787 * Performs the interruption of the current thread, if one has been requested.
2789 void mono_thread_force_interruption_checkpoint ()
2791 mono_thread_interruption_checkpoint_request (TRUE);
2795 * mono_thread_interruption_request_flag:
2797 * Returns the address of a flag that will be non-zero if an interruption has
2798 * been requested for a thread. The thread to interrupt may not be the current
2799 * thread, so an additional call to mono_thread_interruption_requested() or
2800 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
2803 gint32* mono_thread_interruption_request_flag ()
2805 return &thread_interruption_requested;