2 * threads.c: Thread support internal calls
5 * Dick Porter (dick@ximian.com)
6 * Patrik Torstensson (patrik.torstensson@labs2.com)
8 * (C) 2001 Ximian, Inc.
15 #include <mono/metadata/object.h>
16 #include <mono/metadata/appdomain.h>
17 #include <mono/metadata/profiler-private.h>
18 #include <mono/metadata/threads.h>
19 #include <mono/metadata/threads-types.h>
20 #include <mono/metadata/exception.h>
21 #include <mono/io-layer/io-layer.h>
23 #include <mono/os/gc_wrapper.h>
26 #undef THREAD_LOCK_DEBUG
27 #undef THREAD_WAIT_DEBUG
31 guint32 (*func)(void *);
43 * The "os_handle" field of the WaitHandle class.
45 static MonoClassField *wait_handle_os_handle_field = NULL;
47 /* Controls access to the 'threads' array */
48 static CRITICAL_SECTION threads_mutex;
50 /* Controls access to the sync field in MonoObjects, to avoid race
51 * conditions when adding sync data to an object for the first time.
53 static CRITICAL_SECTION monitor_mutex;
55 /* The hash of existing threads (key is thread ID) that need joining
58 static MonoGHashTable *threads=NULL;
60 /* The MonoObject associated with the main thread */
61 static MonoThread *main_thread;
63 /* The TLS key that holds the MonoObject assigned to each thread */
64 static guint32 current_object_key;
66 /* function called at thread start */
67 static MonoThreadStartCB mono_thread_start_cb = NULL;
69 /* function called at thread attach */
70 static MonoThreadStartCB mono_thread_attach_cb = NULL;
72 /* The TLS key that holds the LocalDataStoreSlot hash in each thread */
73 static guint32 slothash_key;
75 /* Spin lock for InterlockedXXX 64 bit functions */
76 static CRITICAL_SECTION interlocked_mutex;
78 /* handle_store() and handle_remove() manage the array of threads that
79 * still need to be waited for when the main thread exits.
81 static void handle_store(MonoThread *thread)
83 EnterCriticalSection(&threads_mutex);
86 g_message(G_GNUC_PRETTY_FUNCTION ": thread %p ID %d", thread,
91 threads=mono_g_hash_table_new(g_int_hash, g_int_equal);
94 /* GHashTable will remove a previous entry if a duplicate key
95 * is stored, which is exactly what we want: we store the
96 * thread both in the start_wrapper (in the subthread), and as
97 * soon as possible in the parent thread. This is to minimise
98 * the window in which the thread exists but we haven't
102 /* We don't need to duplicate thread->handle, because it is
103 * only closed when the thread object is finalized by the GC.
105 mono_g_hash_table_insert(threads, &thread->tid, thread);
106 LeaveCriticalSection(&threads_mutex);
109 static void handle_remove(guint32 tid)
112 g_message(G_GNUC_PRETTY_FUNCTION ": thread ID %d", tid);
115 EnterCriticalSection(&threads_mutex);
117 mono_g_hash_table_remove (threads, &tid);
119 LeaveCriticalSection(&threads_mutex);
121 /* Don't close the handle here, wait for the object finalizer
122 * to do it. Otherwise, the following race condition applies:
124 * 1) Thread exits (and handle_remove() closes the handle)
126 * 2) Some other handle is reassigned the same slot
128 * 3) Another thread tries to join the first thread, and
129 * blocks waiting for the reassigned handle to be signalled
130 * (which might never happen). This is possible, because the
131 * thread calling Join() still has a reference to the first
136 static void thread_cleanup (guint32 tid)
138 mono_profiler_thread_end (tid);
142 static guint32 start_wrapper(void *data)
144 struct StartInfo *start_info=(struct StartInfo *)data;
145 guint32 (*start_func)(void *);
150 g_message(G_GNUC_PRETTY_FUNCTION ": Start wrapper");
153 start_func = start_info->func;
154 mono_domain_set (start_info->domain);
155 this = start_info->this;
157 tid=GetCurrentThreadId ();
158 /* Set the thread ID here as well as in the parent thread,
159 * because we don't know whether the thread object will
160 * already have its ID set before we get to it. This isn't a
161 * race condition, because if we're not guaranteed to get the
162 * same number in both the parent and child threads, then
163 * something else is seriously broken.
165 start_info->obj->tid=tid;
167 handle_store(start_info->obj);
169 mono_profiler_thread_start (tid);
171 mono_new_thread_init (start_info->obj, &tid);
177 /* If the thread calls ExitThread at all, this remaining code
178 * will not be executed, but the main thread will eventually
179 * call thread_cleanup() on this thread's behalf.
183 g_message(G_GNUC_PRETTY_FUNCTION ": Start wrapper terminating");
186 thread_cleanup (tid);
191 void mono_new_thread_init (MonoThread *thread_object, gpointer stack_start)
193 /* FIXME: GC problem here with recorded object
196 * This is recorded so CurrentThread can return the
199 TlsSetValue (current_object_key, thread_object);
201 if (mono_thread_start_cb) {
202 mono_thread_start_cb (stack_start);
206 MonoThread *mono_thread_create (MonoDomain *domain, gpointer func,
210 HANDLE thread_handle;
211 struct StartInfo *start_info;
214 thread = (MonoThread *)mono_object_new (domain,
215 mono_defaults.thread_class);
217 start_info=g_new0 (struct StartInfo, 1);
218 start_info->func = func;
219 start_info->obj = thread;
220 start_info->domain = domain;
221 start_info->this = arg;
223 thread_handle = CreateThread(NULL, 0, start_wrapper, start_info, 0, &tid);
225 g_message(G_GNUC_PRETTY_FUNCTION ": Started thread ID %d (handle %p)",
228 g_assert (thread_handle);
230 thread->handle=thread_handle;
233 handle_store(thread);
239 mono_thread_attach (MonoDomain *domain)
242 HANDLE thread_handle;
245 thread = (MonoThread *)mono_object_new (domain,
246 mono_defaults.thread_class);
248 thread_handle = GetCurrentThread ();
249 g_assert (thread_handle);
251 tid=GetCurrentThreadId ();
253 thread->handle=thread_handle;
257 g_message(G_GNUC_PRETTY_FUNCTION ": Attached thread ID %d (handle %p)",
261 handle_store(thread);
263 TlsSetValue (current_object_key, thread);
264 mono_domain_set (domain);
266 if (mono_thread_attach_cb) {
267 mono_thread_attach_cb (&tid);
273 HANDLE ves_icall_System_Threading_Thread_Thread_internal(MonoThread *this,
276 MonoMulticastDelegate *delegate = (MonoMulticastDelegate*)start;
277 guint32 (*start_func)(void *);
278 struct StartInfo *start_info;
286 g_message(G_GNUC_PRETTY_FUNCTION
287 ": Trying to start a new thread: this (%p) start (%p)",
291 im = mono_get_delegate_invoke (start->vtable->klass);
292 start_func = mono_compile_method (im);
294 if(start_func==NULL) {
295 g_warning(G_GNUC_PRETTY_FUNCTION
296 ": Can't locate start method!");
299 /* This is freed in start_wrapper */
300 start_info = g_new0 (struct StartInfo, 1);
301 start_info->func = start_func;
302 start_info->this = delegate;
303 start_info->obj = this;
304 start_info->domain = mono_domain_get ();
306 thread=CreateThread(NULL, 0, start_wrapper, start_info,
307 CREATE_SUSPENDED, &tid);
309 g_warning(G_GNUC_PRETTY_FUNCTION
310 ": CreateThread error 0x%x", GetLastError());
317 /* Don't call handle_store() here, delay it to Start.
318 * We can't join a thread (trying to will just block
319 * forever) until it actually starts running, so don't
320 * store the handle till then.
324 g_message(G_GNUC_PRETTY_FUNCTION
325 ": Started thread ID %d (handle %p)", tid, thread);
332 void ves_icall_System_Threading_Thread_Thread_free_internal (MonoThread *this,
338 g_message (G_GNUC_PRETTY_FUNCTION ": Closing thread %p, handle %p",
342 CloseHandle (thread);
345 void ves_icall_System_Threading_Thread_Start_internal(MonoThread *this,
351 g_message(G_GNUC_PRETTY_FUNCTION ": Launching thread %p", this);
354 /* Only store the handle when the thread is about to be
355 * launched, to avoid the main thread deadlocking while trying
356 * to clean up a thread that will never be signalled.
360 ResumeThread(thread);
363 void ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
368 g_message(G_GNUC_PRETTY_FUNCTION ": Sleeping for %d ms", ms);
375 ves_icall_System_Threading_Thread_GetDomainID (void)
379 return mono_domain_get()->domain_id;
383 mono_thread_current (void)
389 /* Find the current thread object */
390 thread=TlsGetValue (current_object_key);
393 g_message (G_GNUC_PRETTY_FUNCTION ": returning %p", thread);
399 gboolean ves_icall_System_Threading_Thread_Join_internal(MonoThread *this,
400 int ms, HANDLE thread)
410 g_message (G_GNUC_PRETTY_FUNCTION ": joining thread handle %p, %d ms",
414 ret=WaitForSingleObject(thread, ms);
415 if(ret==WAIT_OBJECT_0) {
417 g_message (G_GNUC_PRETTY_FUNCTION ": join successful");
424 g_message (G_GNUC_PRETTY_FUNCTION ": join failed");
430 void ves_icall_System_Threading_Thread_SlotHash_store(MonoObject *data)
435 g_message(G_GNUC_PRETTY_FUNCTION ": Storing key %p", data);
438 /* Object location stored here */
439 TlsSetValue(slothash_key, data);
442 MonoObject *ves_icall_System_Threading_Thread_SlotHash_lookup(void)
448 data=TlsGetValue(slothash_key);
451 g_message(G_GNUC_PRETTY_FUNCTION ": Retrieved key %p", data);
457 static void mon_finalize (void *o, void *unused)
459 MonoThreadsSync *mon=(MonoThreadsSync *)o;
461 #ifdef THREAD_LOCK_DEBUG
462 g_message (G_GNUC_PRETTY_FUNCTION ": Finalizing sync");
465 CloseHandle (mon->monitor);
466 CloseHandle (mon->sema);
467 CloseHandle (mon->waiters_done);
468 DeleteCriticalSection (&mon->waiters_count_lock);
471 static MonoThreadsSync *mon_new(void)
473 MonoThreadsSync *new;
476 new=(MonoThreadsSync *)GC_MALLOC (sizeof(MonoThreadsSync));
477 GC_REGISTER_FINALIZER (new, mon_finalize, NULL, NULL, NULL);
479 /* This should be freed when the object that owns it is
482 new=(MonoThreadsSync *)g_new0 (MonoThreadsSync, 1);
485 new->monitor=CreateMutex(NULL, FALSE, NULL);
486 if(new->monitor==NULL) {
487 /* Throw some sort of system exception? (ditto for the
488 * sem and event handles below)
492 new->waiters_count=0;
493 new->was_broadcast=FALSE;
494 InitializeCriticalSection(&new->waiters_count_lock);
495 new->sema=CreateSemaphore(NULL, 0, 0x7fffffff, NULL);
496 new->waiters_done=CreateEvent(NULL, FALSE, FALSE, NULL);
498 #ifdef THREAD_LOCK_DEBUG
499 g_message(G_GNUC_PRETTY_FUNCTION ": (%d) ThreadsSync %p mutex created: %p, sem: %p, event: %p", GetCurrentThreadId (), new, new->monitor, new->sema, new->waiters_done);
505 gboolean ves_icall_System_Threading_Monitor_Monitor_try_enter(MonoObject *obj,
508 MonoThreadsSync *mon;
513 #ifdef THREAD_LOCK_DEBUG
514 g_message(G_GNUC_PRETTY_FUNCTION
515 ": (%d) Trying to lock object %p", GetCurrentThreadId(),
519 EnterCriticalSection(&monitor_mutex);
521 mon=obj->synchronisation;
524 obj->synchronisation=mon;
527 /* Don't hold the monitor lock while waiting to acquire the
530 LeaveCriticalSection(&monitor_mutex);
532 /* Acquire the mutex */
533 #ifdef THREAD_LOCK_DEBUG
534 g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Acquiring monitor mutex %p",
535 GetCurrentThreadId (), mon->monitor);
537 ret=WaitForSingleObject(mon->monitor, ms);
538 if(ret==WAIT_OBJECT_0) {
540 mon->tid=GetCurrentThreadId();
542 #ifdef THREAD_LOCK_DEBUG
543 g_message(G_GNUC_PRETTY_FUNCTION
544 ": (%d) object %p now locked %d times",
545 GetCurrentThreadId (), obj, mon->count);
554 void ves_icall_System_Threading_Monitor_Monitor_exit(MonoObject *obj)
556 MonoThreadsSync *mon;
560 #ifdef THREAD_LOCK_DEBUG
561 g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Unlocking %p",
562 GetCurrentThreadId (), obj);
565 /* No need to lock monitor_mutex here because we only adjust
566 * the monitor state if this thread already owns the lock
568 mon=obj->synchronisation;
574 if(mon->tid!=GetCurrentThreadId()) {
580 #ifdef THREAD_LOCK_DEBUG
581 g_message(G_GNUC_PRETTY_FUNCTION ": (%d) %p now locked %d times",
582 GetCurrentThreadId (), obj, mon->count);
586 mon->tid=0; /* FIXME: check that 0 isnt a valid id */
589 #ifdef THREAD_LOCK_DEBUG
590 g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Releasing mutex %p",
591 GetCurrentThreadId (), mon->monitor);
594 ReleaseMutex(mon->monitor);
597 gboolean ves_icall_System_Threading_Monitor_Monitor_test_owner(MonoObject *obj)
599 MonoThreadsSync *mon;
604 #ifdef THREAD_LOCK_DEBUG
605 g_message(G_GNUC_PRETTY_FUNCTION
606 ": Testing if %p is owned by thread %d", obj,
607 GetCurrentThreadId());
610 EnterCriticalSection(&monitor_mutex);
612 mon=obj->synchronisation;
617 if(mon->tid!=GetCurrentThreadId()) {
618 #ifdef THREAD_LOCK_DEBUG
619 g_message (G_GNUC_PRETTY_FUNCTION
620 ": (%d) object %p is owned by thread %d",
621 GetCurrentThreadId (), obj, mon->tid);
630 LeaveCriticalSection(&monitor_mutex);
635 gboolean ves_icall_System_Threading_Monitor_Monitor_test_synchronised(MonoObject *obj)
637 MonoThreadsSync *mon;
642 #ifdef THREAD_LOCK_DEBUG
643 g_message(G_GNUC_PRETTY_FUNCTION
644 ": (%d) Testing if %p is owned by any thread",
645 GetCurrentThreadId (), obj);
648 EnterCriticalSection(&monitor_mutex);
650 mon=obj->synchronisation;
659 g_assert(mon->count);
664 LeaveCriticalSection(&monitor_mutex);
670 void ves_icall_System_Threading_Monitor_Monitor_pulse(MonoObject *obj)
672 gboolean have_waiters;
673 MonoThreadsSync *mon;
677 #ifdef THREAD_LOCK_DEBUG
678 g_message("(%d) Pulsing %p", GetCurrentThreadId (), obj);
681 EnterCriticalSection(&monitor_mutex);
683 mon=obj->synchronisation;
685 LeaveCriticalSection(&monitor_mutex);
689 if(mon->tid!=GetCurrentThreadId()) {
690 LeaveCriticalSection(&monitor_mutex);
693 LeaveCriticalSection(&monitor_mutex);
695 EnterCriticalSection(&mon->waiters_count_lock);
696 have_waiters=(mon->waiters_count>0);
697 LeaveCriticalSection(&mon->waiters_count_lock);
699 if(have_waiters==TRUE) {
700 ReleaseSemaphore(mon->sema, 1, 0);
704 void ves_icall_System_Threading_Monitor_Monitor_pulse_all(MonoObject *obj)
706 gboolean have_waiters=FALSE;
707 MonoThreadsSync *mon;
711 #ifdef THREAD_LOCK_DEBUG
712 g_message("(%d) Pulsing all %p", GetCurrentThreadId (), obj);
715 EnterCriticalSection(&monitor_mutex);
717 mon=obj->synchronisation;
719 LeaveCriticalSection(&monitor_mutex);
723 if(mon->tid!=GetCurrentThreadId()) {
724 LeaveCriticalSection(&monitor_mutex);
727 LeaveCriticalSection(&monitor_mutex);
729 EnterCriticalSection(&mon->waiters_count_lock);
730 if(mon->waiters_count>0) {
731 mon->was_broadcast=TRUE;
735 if(have_waiters==TRUE) {
736 ReleaseSemaphore(mon->sema, mon->waiters_count, 0);
738 LeaveCriticalSection(&mon->waiters_count_lock);
740 WaitForSingleObject(mon->waiters_done, INFINITE);
741 mon->was_broadcast=FALSE;
743 LeaveCriticalSection(&mon->waiters_count_lock);
747 gboolean ves_icall_System_Threading_Monitor_Monitor_wait(MonoObject *obj,
750 gboolean last_waiter;
751 MonoThreadsSync *mon;
756 #ifdef THREAD_LOCK_DEBUG
757 g_message("(%d) Trying to wait for %p with timeout %dms",
758 GetCurrentThreadId (), obj, ms);
761 EnterCriticalSection(&monitor_mutex);
763 mon=obj->synchronisation;
765 LeaveCriticalSection(&monitor_mutex);
769 if(mon->tid!=GetCurrentThreadId()) {
770 LeaveCriticalSection(&monitor_mutex);
773 LeaveCriticalSection(&monitor_mutex);
775 EnterCriticalSection(&mon->waiters_count_lock);
776 mon->waiters_count++;
777 LeaveCriticalSection(&mon->waiters_count_lock);
779 #ifdef THREAD_LOCK_DEBUG
780 g_message(G_GNUC_PRETTY_FUNCTION ": (%d) %p locked %d times",
781 GetCurrentThreadId (), obj, mon->count);
784 /* We need to put the lock count back afterwards */
785 save_count=mon->count;
787 while(mon->count>1) {
788 #ifdef THREAD_LOCK_DEBUG
789 g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Releasing mutex %p",
790 GetCurrentThreadId (), mon->monitor);
793 ReleaseMutex(mon->monitor);
797 /* We're releasing this mutex */
800 #ifdef THREAD_LOCK_DEBUG
801 g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Signalling monitor mutex %p",
802 GetCurrentThreadId (), mon->monitor);
805 SignalObjectAndWait(mon->monitor, mon->sema, INFINITE, FALSE);
807 EnterCriticalSection(&mon->waiters_count_lock);
808 mon->waiters_count++;
809 last_waiter=mon->was_broadcast && mon->waiters_count==0;
810 LeaveCriticalSection(&mon->waiters_count_lock);
813 #ifdef THREAD_LOCK_DEBUG
814 g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Waiting for monitor mutex %p",
815 GetCurrentThreadId (), mon->monitor);
817 SignalObjectAndWait(mon->waiters_done, mon->monitor, INFINITE, FALSE);
819 #ifdef THREAD_LOCK_DEBUG
820 g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Waiting for monitor mutex %p",
821 GetCurrentThreadId (), mon->monitor);
823 WaitForSingleObject(mon->monitor, INFINITE);
826 /* We've reclaimed this mutex */
827 mon->count=save_count;
828 mon->tid=GetCurrentThreadId();
830 /* Lock the mutex the required number of times */
831 while(save_count>1) {
832 #ifdef THREAD_LOCK_DEBUG
833 g_message(G_GNUC_PRETTY_FUNCTION
834 ": (%d) Waiting for monitor mutex %p",
835 GetCurrentThreadId (), mon->monitor);
837 WaitForSingleObject(mon->monitor, INFINITE);
841 #ifdef THREAD_LOCK_DEBUG
842 g_message(G_GNUC_PRETTY_FUNCTION ": (%d) %p still locked %d times",
843 GetCurrentThreadId (), obj, mon->count);
849 /* FIXME: exitContext isnt documented */
850 gboolean ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
856 MonoObject *waitHandle;
861 numhandles = mono_array_length(mono_handles);
862 handles = g_new0(HANDLE, numhandles);
864 if (wait_handle_os_handle_field == 0) {
865 /* Get the field os_handle which will contain the actual handle */
866 klass = mono_class_from_name(mono_defaults.corlib, "System.Threading", "WaitHandle");
867 wait_handle_os_handle_field = mono_class_get_field_from_name(klass, "os_handle");
870 for(i = 0; i < numhandles; i++) {
871 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
872 mono_field_get_value(waitHandle, wait_handle_os_handle_field, &handles[i]);
879 ret=WaitForMultipleObjects(numhandles, handles, TRUE, ms);
883 if(ret==WAIT_FAILED) {
884 #ifdef THREAD_WAIT_DEBUG
885 g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Wait failed",
886 GetCurrentThreadId ());
889 } else if(ret==WAIT_TIMEOUT) {
890 #ifdef THREAD_WAIT_DEBUG
891 g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Wait timed out",
892 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;
912 numhandles = mono_array_length(mono_handles);
913 handles = g_new0(HANDLE, numhandles);
915 if (wait_handle_os_handle_field == 0) {
916 /* Get the field os_handle which will contain the actual handle */
917 klass = mono_class_from_name(mono_defaults.corlib, "System.Threading", "WaitHandle");
918 wait_handle_os_handle_field = mono_class_get_field_from_name(klass, "os_handle");
921 for(i = 0; i < numhandles; i++) {
922 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
923 mono_field_get_value(waitHandle, wait_handle_os_handle_field, &handles[i]);
930 ret=WaitForMultipleObjects(numhandles, handles, FALSE, ms);
934 #ifdef THREAD_WAIT_DEBUG
935 g_message(G_GNUC_PRETTY_FUNCTION ": (%d) returning %d",
936 GetCurrentThreadId (), ret);
940 * These need to be here. See MSDN dos on WaitForMultipleObjects.
942 if (ret >= WAIT_OBJECT_0 && ret <= WAIT_OBJECT_0 + numhandles - 1) {
943 return ret - WAIT_OBJECT_0;
945 else if (ret >= WAIT_ABANDONED_0 && ret <= WAIT_ABANDONED_0 + numhandles - 1) {
946 return ret - WAIT_ABANDONED_0;
953 /* FIXME: exitContext isnt documented */
954 gboolean ves_icall_System_Threading_WaitHandle_WaitOne_internal(MonoObject *this, HANDLE handle, gint32 ms, gboolean exitContext)
960 #ifdef THREAD_WAIT_DEBUG
961 g_message(G_GNUC_PRETTY_FUNCTION ": (%d) waiting for %p, %d ms",
962 GetCurrentThreadId (), handle, ms);
969 ret=WaitForSingleObject(handle, ms);
970 if(ret==WAIT_FAILED) {
971 #ifdef THREAD_WAIT_DEBUG
972 g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Wait failed",
973 GetCurrentThreadId ());
976 } else if(ret==WAIT_TIMEOUT) {
977 #ifdef THREAD_WAIT_DEBUG
978 g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Wait timed out",
979 GetCurrentThreadId ());
987 HANDLE ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned,char *name) {
990 return(CreateMutex(NULL,owned,name));
993 void ves_icall_System_Threading_Mutex_ReleaseMutex_internal (HANDLE handle ) {
996 ReleaseMutex(handle);
999 HANDLE ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manual,
1000 MonoBoolean initial,
1002 MONO_ARCH_SAVE_REGS;
1004 return (CreateEvent(NULL,manual,initial,name));
1007 gboolean ves_icall_System_Threading_Events_SetEvent_internal (HANDLE handle) {
1008 MONO_ARCH_SAVE_REGS;
1010 return (SetEvent(handle));
1013 gboolean ves_icall_System_Threading_Events_ResetEvent_internal (HANDLE handle) {
1014 MONO_ARCH_SAVE_REGS;
1016 return (ResetEvent(handle));
1019 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
1021 MONO_ARCH_SAVE_REGS;
1023 return InterlockedIncrement (location);
1026 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
1031 MONO_ARCH_SAVE_REGS;
1033 EnterCriticalSection(&interlocked_mutex);
1035 lowret = InterlockedIncrement((gint32 *) location);
1037 highret = InterlockedIncrement((gint32 *) location + 1);
1039 highret = *((gint32 *) location + 1);
1041 LeaveCriticalSection(&interlocked_mutex);
1043 return (gint64) highret << 32 | (gint64) lowret;
1046 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
1048 MONO_ARCH_SAVE_REGS;
1050 return InterlockedDecrement(location);
1053 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
1058 MONO_ARCH_SAVE_REGS;
1060 EnterCriticalSection(&interlocked_mutex);
1062 lowret = InterlockedDecrement((gint32 *) location);
1064 highret = InterlockedDecrement((gint32 *) location + 1);
1066 highret = *((gint32 *) location + 1);
1068 LeaveCriticalSection(&interlocked_mutex);
1070 return (gint64) highret << 32 | (gint64) lowret;
1073 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location1, gint32 value)
1075 MONO_ARCH_SAVE_REGS;
1077 return InterlockedExchange(location1, value);
1080 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location1, MonoObject *value)
1082 MONO_ARCH_SAVE_REGS;
1084 return (MonoObject *) InterlockedExchangePointer((gpointer *) location1, value);
1087 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location1, gfloat value)
1089 IntFloatUnion val, ret;
1091 MONO_ARCH_SAVE_REGS;
1094 ret.ival = InterlockedExchange((gint32 *) location1, val.ival);
1099 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location1, gint32 value, gint32 comparand)
1101 MONO_ARCH_SAVE_REGS;
1103 return InterlockedCompareExchange(location1, value, comparand);
1106 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location1, MonoObject *value, MonoObject *comparand)
1108 MONO_ARCH_SAVE_REGS;
1110 return (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location1, value, comparand);
1113 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location1, gfloat value, gfloat comparand)
1115 IntFloatUnion val, ret, cmp;
1117 MONO_ARCH_SAVE_REGS;
1120 cmp.fval = comparand;
1121 ret.ival = InterlockedCompareExchange((gint32 *) location1, val.ival, cmp.ival);
1127 ves_icall_System_Threading_Thread_Abort (MonoThread *thread, MonoObject *state)
1129 MONO_ARCH_SAVE_REGS;
1131 thread->abort_state = state;
1132 thread->abort_exc = mono_get_exception_thread_abort ();
1135 /* fixme: store the state somewhere */
1137 #ifdef PTHREAD_POINTER_ID
1138 pthread_kill (GUINT_TO_POINTER(thread->tid), SIGRTMIN);
1140 pthread_kill (thread->tid, SIGRTMIN);
1143 g_assert_not_reached ();
1148 ves_icall_System_Threading_Thread_ResetAbort (void)
1150 MonoThread *thread = mono_thread_current ();
1152 MONO_ARCH_SAVE_REGS;
1154 if (!thread->abort_exc) {
1155 const char *msg = "Unable to reset abort because no abort was requested";
1156 mono_raise_exception (mono_get_exception_thread_state (msg));
1158 thread->abort_exc = NULL;
1159 thread->abort_state = NULL;
1163 void mono_thread_init (MonoDomain *domain, MonoThreadStartCB start_cb,
1164 MonoThreadStartCB attach_cb)
1166 /* Build a System.Threading.Thread object instance to return
1167 * for the main line's Thread.CurrentThread property.
1170 /* I wonder what happens if someone tries to destroy this
1171 * object? In theory, I guess the whole program should act as
1172 * though exit() were called :-)
1175 g_message(G_GNUC_PRETTY_FUNCTION
1176 ": Starting to build main Thread object");
1178 main_thread = (MonoThread *)mono_object_new (domain, mono_defaults.thread_class);
1180 main_thread->handle = GetCurrentThread ();
1183 g_message(G_GNUC_PRETTY_FUNCTION
1184 ": Finished building main Thread object: %p", main_thread);
1187 InitializeCriticalSection(&threads_mutex);
1188 InitializeCriticalSection(&monitor_mutex);
1189 InitializeCriticalSection(&interlocked_mutex);
1191 current_object_key=TlsAlloc();
1193 g_message (G_GNUC_PRETTY_FUNCTION ": Allocated current_object_key %d",
1194 current_object_key);
1197 TlsSetValue(current_object_key, main_thread);
1199 mono_thread_start_cb = start_cb;
1200 mono_thread_attach_cb = attach_cb;
1202 slothash_key=TlsAlloc();
1204 /* Get a pseudo handle to the current process. This is just a
1205 * kludge so that wapi can build a process handle if needed.
1206 * As a pseudo handle is returned, we don't need to clean
1209 GetCurrentProcess ();
1213 static void print_tids (gpointer key, gpointer value, gpointer user)
1215 g_message ("Waiting for: %d", *(guint32 *)key);
1221 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
1222 MonoThread *threads[MAXIMUM_WAIT_OBJECTS];
1226 static void wait_for_tids (struct wait_data *wait)
1231 g_message(G_GNUC_PRETTY_FUNCTION
1232 ": %d threads to wait for in this batch", wait->num);
1235 ret=WaitForMultipleObjects(wait->num, wait->handles, TRUE, INFINITE);
1236 if(ret==WAIT_FAILED) {
1237 /* See the comment in build_wait_tids() */
1239 g_message (G_GNUC_PRETTY_FUNCTION ": Wait failed");
1245 for(i=0; i<wait->num; i++) {
1246 guint32 tid=wait->threads[i]->tid;
1248 if(mono_g_hash_table_lookup (threads, &tid)!=NULL) {
1249 /* This thread must have been killed, because
1250 * it hasn't cleaned itself up. (It's just
1251 * possible that the thread exited before the
1252 * parent thread had a chance to store the
1253 * handle, and now there is another pointer to
1254 * the already-exited thread stored. In this
1255 * case, we'll just get two
1256 * mono_profiler_thread_end() calls for the
1261 g_message (G_GNUC_PRETTY_FUNCTION
1262 ": cleaning up after thread %d", tid);
1264 thread_cleanup (tid);
1269 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
1271 struct wait_data *wait=(struct wait_data *)user;
1273 if(wait->num<MAXIMUM_WAIT_OBJECTS) {
1274 MonoThread *thread=(MonoThread *)value;
1276 /* Theres a theoretical chance that thread->handle
1277 * might be NULL if the child thread has called
1278 * handle_store() but the parent thread hasn't set the
1279 * handle pointer yet. WaitForMultipleObjects will
1280 * fail, and we'll just go round the loop again. By
1281 * that time the handle should be stored properly.
1283 wait->handles[wait->num]=thread->handle;
1284 wait->threads[wait->num]=thread;
1287 /* Just ignore the rest, we can't do anything with
1293 void mono_thread_cleanup(void)
1295 struct wait_data *wait=g_new0 (struct wait_data, 1);
1297 /* join each thread that's still running */
1299 g_message(G_GNUC_PRETTY_FUNCTION ": Joining each running thread...");
1304 g_message(G_GNUC_PRETTY_FUNCTION ": No threads");
1310 EnterCriticalSection (&threads_mutex);
1312 g_message(G_GNUC_PRETTY_FUNCTION
1313 ":There are %d threads to join",
1314 mono_g_hash_table_size (threads));
1315 mono_g_hash_table_foreach (threads, print_tids, NULL);
1319 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
1321 LeaveCriticalSection (&threads_mutex);
1323 /* Something to wait for */
1324 wait_for_tids (wait);
1326 } while(wait->num>0);
1330 mono_g_hash_table_destroy(threads);