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 *);
42 /* Controls access to the 'threads' array */
43 static CRITICAL_SECTION threads_mutex;
45 /* Controls access to the sync field in MonoObjects, to avoid race
46 * conditions when adding sync data to an object for the first time.
48 static CRITICAL_SECTION monitor_mutex;
50 /* The hash of existing threads (key is thread ID) that need joining
53 static MonoGHashTable *threads=NULL;
55 /* The MonoObject associated with the main thread */
56 static MonoThread *main_thread;
58 /* The TLS key that holds the MonoObject assigned to each thread */
59 static guint32 current_object_key;
61 /* function called at thread start */
62 static MonoThreadStartCB mono_thread_start_cb = NULL;
64 /* function called at thread attach */
65 static MonoThreadStartCB mono_thread_attach_cb = NULL;
67 /* The TLS key that holds the LocalDataStoreSlot hash in each thread */
68 static guint32 slothash_key;
70 /* Spin lock for InterlockedXXX 64 bit functions */
71 static CRITICAL_SECTION interlocked_mutex;
73 /* handle_store() and handle_remove() manage the array of threads that
74 * still need to be waited for when the main thread exits.
76 static void handle_store(MonoThread *thread)
78 EnterCriticalSection(&threads_mutex);
81 g_message(G_GNUC_PRETTY_FUNCTION ": thread %p ID %d", thread,
86 threads=mono_g_hash_table_new(g_int_hash, g_int_equal);
89 /* GHashTable will remove a previous entry if a duplicate key
90 * is stored, which is exactly what we want: we store the
91 * thread both in the start_wrapper (in the subthread), and as
92 * soon as possible in the parent thread. This is to minimise
93 * the window in which the thread exists but we haven't
97 /* We don't need to duplicate thread->handle, because it is
98 * only closed when the thread object is finalized by the GC.
100 mono_g_hash_table_insert(threads, &thread->tid, thread);
101 LeaveCriticalSection(&threads_mutex);
104 static void handle_remove(guint32 tid)
107 g_message(G_GNUC_PRETTY_FUNCTION ": thread ID %d", tid);
110 EnterCriticalSection(&threads_mutex);
112 mono_g_hash_table_remove (threads, &tid);
114 LeaveCriticalSection(&threads_mutex);
116 /* Don't close the handle here, wait for the object finalizer
117 * to do it. Otherwise, the following race condition applies:
119 * 1) Thread exits (and handle_remove() closes the handle)
121 * 2) Some other handle is reassigned the same slot
123 * 3) Another thread tries to join the first thread, and
124 * blocks waiting for the reassigned handle to be signalled
125 * (which might never happen). This is possible, because the
126 * thread calling Join() still has a reference to the first
131 static void thread_cleanup (guint32 tid)
133 mono_profiler_thread_end (tid);
137 static guint32 start_wrapper(void *data)
139 struct StartInfo *start_info=(struct StartInfo *)data;
140 guint32 (*start_func)(void *);
145 g_message(G_GNUC_PRETTY_FUNCTION ": Start wrapper");
148 start_func = start_info->func;
149 mono_domain_set (start_info->domain);
150 this = start_info->this;
152 tid=GetCurrentThreadId ();
153 /* Set the thread ID here as well as in the parent thread,
154 * because we don't know whether the thread object will
155 * already have its ID set before we get to it. This isn't a
156 * race condition, because if we're not guaranteed to get the
157 * same number in both the parent and child threads, then
158 * something else is seriously broken.
160 start_info->obj->tid=tid;
162 handle_store(start_info->obj);
164 mono_profiler_thread_start (tid);
166 mono_new_thread_init (start_info->obj, &tid);
172 /* If the thread calls ExitThread at all, this remaining code
173 * will not be executed, but the main thread will eventually
174 * call thread_cleanup() on this thread's behalf.
178 g_message(G_GNUC_PRETTY_FUNCTION ": Start wrapper terminating");
181 thread_cleanup (tid);
186 void mono_new_thread_init (MonoThread *thread_object, gpointer stack_start)
188 /* FIXME: GC problem here with recorded object
191 * This is recorded so CurrentThread can return the
194 TlsSetValue (current_object_key, thread_object);
196 if (mono_thread_start_cb) {
197 mono_thread_start_cb (stack_start);
201 MonoThread *mono_thread_create (MonoDomain *domain, gpointer func,
205 HANDLE thread_handle;
206 struct StartInfo *start_info;
209 thread = (MonoThread *)mono_object_new (domain,
210 mono_defaults.thread_class);
212 start_info=g_new0 (struct StartInfo, 1);
213 start_info->func = func;
214 start_info->obj = thread;
215 start_info->domain = domain;
216 start_info->this = arg;
218 thread_handle = CreateThread(NULL, 0, start_wrapper, start_info, 0, &tid);
220 g_message(G_GNUC_PRETTY_FUNCTION ": Started thread ID %d (handle %p)",
223 g_assert (thread_handle);
225 thread->handle=thread_handle;
228 handle_store(thread);
234 mono_thread_attach (MonoDomain *domain)
237 HANDLE thread_handle;
240 thread = (MonoThread *)mono_object_new (domain,
241 mono_defaults.thread_class);
243 thread_handle = GetCurrentThread ();
244 g_assert (thread_handle);
246 tid=GetCurrentThreadId ();
248 thread->handle=thread_handle;
252 g_message(G_GNUC_PRETTY_FUNCTION ": Attached thread ID %d (handle %p)",
256 handle_store(thread);
258 TlsSetValue (current_object_key, thread);
259 mono_domain_set (domain);
261 if (mono_thread_attach_cb) {
262 mono_thread_attach_cb (&tid);
268 HANDLE ves_icall_System_Threading_Thread_Thread_internal(MonoThread *this,
271 MonoMulticastDelegate *delegate = (MonoMulticastDelegate*)start;
272 guint32 (*start_func)(void *);
273 struct StartInfo *start_info;
279 g_message(G_GNUC_PRETTY_FUNCTION
280 ": Trying to start a new thread: this (%p) start (%p)",
284 im = mono_get_delegate_invoke (start->vtable->klass);
285 start_func = mono_compile_method (im);
287 if(start_func==NULL) {
288 g_warning(G_GNUC_PRETTY_FUNCTION
289 ": Can't locate start method!");
292 /* This is freed in start_wrapper */
293 start_info = g_new0 (struct StartInfo, 1);
294 start_info->func = start_func;
295 start_info->this = delegate;
296 start_info->obj = this;
297 start_info->domain = mono_domain_get ();
299 thread=CreateThread(NULL, 0, start_wrapper, start_info,
300 CREATE_SUSPENDED, &tid);
302 g_warning(G_GNUC_PRETTY_FUNCTION
303 ": CreateThread error 0x%x", GetLastError());
310 /* Don't call handle_store() here, delay it to Start.
311 * We can't join a thread (trying to will just block
312 * forever) until it actually starts running, so don't
313 * store the handle till then.
317 g_message(G_GNUC_PRETTY_FUNCTION
318 ": Started thread ID %d (handle %p)", tid, thread);
325 void ves_icall_System_Threading_Thread_Thread_free_internal (MonoThread *this,
329 g_message (G_GNUC_PRETTY_FUNCTION ": Closing thread %p, handle %p",
333 CloseHandle (thread);
336 void ves_icall_System_Threading_Thread_Start_internal(MonoThread *this,
340 g_message(G_GNUC_PRETTY_FUNCTION ": Launching thread %p", this);
343 /* Only store the handle when the thread is about to be
344 * launched, to avoid the main thread deadlocking while trying
345 * to clean up a thread that will never be signalled.
349 ResumeThread(thread);
352 void ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
355 g_message(G_GNUC_PRETTY_FUNCTION ": Sleeping for %d ms", ms);
362 ves_icall_System_Threading_Thread_GetDomainID (void)
364 return mono_domain_get()->domain_id;
368 mono_thread_current (void)
372 /* Find the current thread object */
373 thread=TlsGetValue (current_object_key);
376 g_message (G_GNUC_PRETTY_FUNCTION ": returning %p", thread);
382 gboolean ves_icall_System_Threading_Thread_Join_internal(MonoThread *this,
383 int ms, HANDLE thread)
391 g_message (G_GNUC_PRETTY_FUNCTION ": joining thread handle %p, %d ms",
395 ret=WaitForSingleObject(thread, ms);
396 if(ret==WAIT_OBJECT_0) {
398 g_message (G_GNUC_PRETTY_FUNCTION ": join successful");
405 g_message (G_GNUC_PRETTY_FUNCTION ": join failed");
411 void ves_icall_System_Threading_Thread_SlotHash_store(MonoObject *data)
414 g_message(G_GNUC_PRETTY_FUNCTION ": Storing key %p", data);
417 /* Object location stored here */
418 TlsSetValue(slothash_key, data);
421 MonoObject *ves_icall_System_Threading_Thread_SlotHash_lookup(void)
425 data=TlsGetValue(slothash_key);
428 g_message(G_GNUC_PRETTY_FUNCTION ": Retrieved key %p", data);
434 static void mon_finalize (void *o, void *unused)
436 MonoThreadsSync *mon=(MonoThreadsSync *)o;
438 #ifdef THREAD_LOCK_DEBUG
439 g_message (G_GNUC_PRETTY_FUNCTION ": Finalizing sync");
442 CloseHandle (mon->monitor);
443 CloseHandle (mon->sema);
444 CloseHandle (mon->waiters_done);
447 static MonoThreadsSync *mon_new(void)
449 MonoThreadsSync *new;
452 new=(MonoThreadsSync *)GC_MALLOC (sizeof(MonoThreadsSync));
453 GC_REGISTER_FINALIZER (new, mon_finalize, NULL, NULL, NULL);
455 /* This should be freed when the object that owns it is
458 new=(MonoThreadsSync *)g_new0 (MonoThreadsSync, 1);
461 new->monitor=CreateMutex(NULL, FALSE, NULL);
462 if(new->monitor==NULL) {
463 /* Throw some sort of system exception? (ditto for the
464 * sem and event handles below)
468 new->waiters_count=0;
469 new->was_broadcast=FALSE;
470 InitializeCriticalSection(&new->waiters_count_lock);
471 new->sema=CreateSemaphore(NULL, 0, 0x7fffffff, NULL);
472 new->waiters_done=CreateEvent(NULL, FALSE, FALSE, NULL);
474 #ifdef THREAD_LOCK_DEBUG
475 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);
481 gboolean ves_icall_System_Threading_Monitor_Monitor_try_enter(MonoObject *obj,
484 MonoThreadsSync *mon;
487 #ifdef THREAD_LOCK_DEBUG
488 g_message(G_GNUC_PRETTY_FUNCTION
489 ": (%d) Trying to lock object %p", GetCurrentThreadId(),
493 EnterCriticalSection(&monitor_mutex);
495 mon=obj->synchronisation;
498 obj->synchronisation=mon;
501 /* Don't hold the monitor lock while waiting to acquire the
504 LeaveCriticalSection(&monitor_mutex);
506 /* Acquire the mutex */
507 #ifdef THREAD_LOCK_DEBUG
508 g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Acquiring monitor mutex %p",
509 GetCurrentThreadId (), mon->monitor);
511 ret=WaitForSingleObject(mon->monitor, ms);
512 if(ret==WAIT_OBJECT_0) {
514 mon->tid=GetCurrentThreadId();
516 #ifdef THREAD_LOCK_DEBUG
517 g_message(G_GNUC_PRETTY_FUNCTION
518 ": (%d) object %p now locked %d times",
519 GetCurrentThreadId (), obj, mon->count);
528 void ves_icall_System_Threading_Monitor_Monitor_exit(MonoObject *obj)
530 MonoThreadsSync *mon;
532 #ifdef THREAD_LOCK_DEBUG
533 g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Unlocking %p",
534 GetCurrentThreadId (), obj);
537 /* No need to lock monitor_mutex here because we only adjust
538 * the monitor state if this thread already owns the lock
540 mon=obj->synchronisation;
546 if(mon->tid!=GetCurrentThreadId()) {
552 #ifdef THREAD_LOCK_DEBUG
553 g_message(G_GNUC_PRETTY_FUNCTION ": (%d) %p now locked %d times",
554 GetCurrentThreadId (), obj, mon->count);
558 mon->tid=0; /* FIXME: check that 0 isnt a valid id */
561 #ifdef THREAD_LOCK_DEBUG
562 g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Releasing mutex %p",
563 GetCurrentThreadId (), mon->monitor);
566 ReleaseMutex(mon->monitor);
569 gboolean ves_icall_System_Threading_Monitor_Monitor_test_owner(MonoObject *obj)
571 MonoThreadsSync *mon;
574 #ifdef THREAD_LOCK_DEBUG
575 g_message(G_GNUC_PRETTY_FUNCTION
576 ": Testing if %p is owned by thread %d", obj,
577 GetCurrentThreadId());
580 EnterCriticalSection(&monitor_mutex);
582 mon=obj->synchronisation;
587 if(mon->tid!=GetCurrentThreadId()) {
588 #ifdef THREAD_LOCK_DEBUG
589 g_message (G_GNUC_PRETTY_FUNCTION
590 ": (%d) object %p is owned by thread %d",
591 GetCurrentThreadId (), obj, mon->tid);
600 LeaveCriticalSection(&monitor_mutex);
605 gboolean ves_icall_System_Threading_Monitor_Monitor_test_synchronised(MonoObject *obj)
607 MonoThreadsSync *mon;
610 #ifdef THREAD_LOCK_DEBUG
611 g_message(G_GNUC_PRETTY_FUNCTION
612 ": (%d) Testing if %p is owned by any thread",
613 GetCurrentThreadId (), obj);
616 EnterCriticalSection(&monitor_mutex);
618 mon=obj->synchronisation;
627 g_assert(mon->count);
632 LeaveCriticalSection(&monitor_mutex);
638 void ves_icall_System_Threading_Monitor_Monitor_pulse(MonoObject *obj)
640 gboolean have_waiters;
641 MonoThreadsSync *mon;
643 #ifdef THREAD_LOCK_DEBUG
644 g_message("(%d) Pulsing %p", GetCurrentThreadId (), obj);
647 EnterCriticalSection(&monitor_mutex);
649 mon=obj->synchronisation;
651 LeaveCriticalSection(&monitor_mutex);
655 if(mon->tid!=GetCurrentThreadId()) {
656 LeaveCriticalSection(&monitor_mutex);
659 LeaveCriticalSection(&monitor_mutex);
661 EnterCriticalSection(&mon->waiters_count_lock);
662 have_waiters=(mon->waiters_count>0);
663 LeaveCriticalSection(&mon->waiters_count_lock);
665 if(have_waiters==TRUE) {
666 ReleaseSemaphore(mon->sema, 1, 0);
670 void ves_icall_System_Threading_Monitor_Monitor_pulse_all(MonoObject *obj)
672 gboolean have_waiters=FALSE;
673 MonoThreadsSync *mon;
675 #ifdef THREAD_LOCK_DEBUG
676 g_message("(%d) Pulsing all %p", GetCurrentThreadId (), obj);
679 EnterCriticalSection(&monitor_mutex);
681 mon=obj->synchronisation;
683 LeaveCriticalSection(&monitor_mutex);
687 if(mon->tid!=GetCurrentThreadId()) {
688 LeaveCriticalSection(&monitor_mutex);
691 LeaveCriticalSection(&monitor_mutex);
693 EnterCriticalSection(&mon->waiters_count_lock);
694 if(mon->waiters_count>0) {
695 mon->was_broadcast=TRUE;
699 if(have_waiters==TRUE) {
700 ReleaseSemaphore(mon->sema, mon->waiters_count, 0);
702 LeaveCriticalSection(&mon->waiters_count_lock);
704 WaitForSingleObject(mon->waiters_done, INFINITE);
705 mon->was_broadcast=FALSE;
707 LeaveCriticalSection(&mon->waiters_count_lock);
711 gboolean ves_icall_System_Threading_Monitor_Monitor_wait(MonoObject *obj,
714 gboolean last_waiter;
715 MonoThreadsSync *mon;
718 #ifdef THREAD_LOCK_DEBUG
719 g_message("(%d) Trying to wait for %p with timeout %dms",
720 GetCurrentThreadId (), obj, ms);
723 EnterCriticalSection(&monitor_mutex);
725 mon=obj->synchronisation;
727 LeaveCriticalSection(&monitor_mutex);
731 if(mon->tid!=GetCurrentThreadId()) {
732 LeaveCriticalSection(&monitor_mutex);
735 LeaveCriticalSection(&monitor_mutex);
737 EnterCriticalSection(&mon->waiters_count_lock);
738 mon->waiters_count++;
739 LeaveCriticalSection(&mon->waiters_count_lock);
741 #ifdef THREAD_LOCK_DEBUG
742 g_message(G_GNUC_PRETTY_FUNCTION ": (%d) %p locked %d times",
743 GetCurrentThreadId (), obj, mon->count);
746 /* We need to put the lock count back afterwards */
747 save_count=mon->count;
749 while(mon->count>1) {
750 #ifdef THREAD_LOCK_DEBUG
751 g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Releasing mutex %p",
752 GetCurrentThreadId (), mon->monitor);
755 ReleaseMutex(mon->monitor);
759 /* We're releasing this mutex */
762 #ifdef THREAD_LOCK_DEBUG
763 g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Signalling monitor mutex %p",
764 GetCurrentThreadId (), mon->monitor);
767 SignalObjectAndWait(mon->monitor, mon->sema, INFINITE, FALSE);
769 EnterCriticalSection(&mon->waiters_count_lock);
770 mon->waiters_count++;
771 last_waiter=mon->was_broadcast && mon->waiters_count==0;
772 LeaveCriticalSection(&mon->waiters_count_lock);
775 #ifdef THREAD_LOCK_DEBUG
776 g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Waiting for monitor mutex %p",
777 GetCurrentThreadId (), mon->monitor);
779 SignalObjectAndWait(mon->waiters_done, mon->monitor, INFINITE, FALSE);
781 #ifdef THREAD_LOCK_DEBUG
782 g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Waiting for monitor mutex %p",
783 GetCurrentThreadId (), mon->monitor);
785 WaitForSingleObject(mon->monitor, INFINITE);
788 /* We've reclaimed this mutex */
789 mon->count=save_count;
790 mon->tid=GetCurrentThreadId();
792 /* Lock the mutex the required number of times */
793 while(save_count>1) {
794 #ifdef THREAD_LOCK_DEBUG
795 g_message(G_GNUC_PRETTY_FUNCTION
796 ": (%d) Waiting for monitor mutex %p",
797 GetCurrentThreadId (), mon->monitor);
799 WaitForSingleObject(mon->monitor, INFINITE);
803 #ifdef THREAD_LOCK_DEBUG
804 g_message(G_GNUC_PRETTY_FUNCTION ": (%d) %p still locked %d times",
805 GetCurrentThreadId (), obj, mon->count);
811 /* FIXME: exitContext isnt documented */
812 gboolean ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
819 numhandles=mono_array_length(mono_handles);
820 handles=g_new0(HANDLE, numhandles);
821 for(i=0; i<numhandles; i++) {
822 handles[i]=mono_array_get(mono_handles, HANDLE, i);
829 ret=WaitForMultipleObjects(numhandles, handles, TRUE, ms);
833 if(ret==WAIT_FAILED) {
834 #ifdef THREAD_WAIT_DEBUG
835 g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Wait failed",
836 GetCurrentThreadId ());
839 } else if(ret==WAIT_TIMEOUT) {
840 #ifdef THREAD_WAIT_DEBUG
841 g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Wait timed out",
842 GetCurrentThreadId ());
850 /* FIXME: exitContext isnt documented */
851 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
858 numhandles=mono_array_length(mono_handles);
859 handles=g_new0(HANDLE, numhandles);
860 for(i=0; i<numhandles; i++) {
861 handles[i]=mono_array_get(mono_handles, HANDLE, i);
868 ret=WaitForMultipleObjects(numhandles, handles, FALSE, ms);
872 #ifdef THREAD_WAIT_DEBUG
873 g_message(G_GNUC_PRETTY_FUNCTION ": (%d) returning %d",
874 GetCurrentThreadId (), ret);
880 /* FIXME: exitContext isnt documented */
881 gboolean ves_icall_System_Threading_WaitHandle_WaitOne_internal(MonoObject *this, HANDLE handle, gint32 ms, gboolean exitContext)
885 #ifdef THREAD_WAIT_DEBUG
886 g_message(G_GNUC_PRETTY_FUNCTION ": (%d) waiting for %p",
887 GetCurrentThreadId (), handle);
894 ret=WaitForSingleObject(handle, ms);
895 if(ret==WAIT_FAILED) {
896 #ifdef THREAD_WAIT_DEBUG
897 g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Wait failed",
898 GetCurrentThreadId ());
901 } else if(ret==WAIT_TIMEOUT) {
902 #ifdef THREAD_WAIT_DEBUG
903 g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Wait timed out",
904 GetCurrentThreadId ());
912 HANDLE ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned,char *name) {
913 return(CreateMutex(NULL,owned,name));
916 void ves_icall_System_Threading_Mutex_ReleaseMutex_internal (HANDLE handle ) {
917 ReleaseMutex(handle);
920 HANDLE ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manual,
923 return (CreateEvent(NULL,manual,initial,name));
926 gboolean ves_icall_System_Threading_Events_SetEvent_internal (HANDLE handle) {
927 return (SetEvent(handle));
930 gboolean ves_icall_System_Threading_Events_ResetEvent_internal (HANDLE handle) {
931 return (ResetEvent(handle));
934 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
936 return InterlockedIncrement (location);
939 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
944 EnterCriticalSection(&interlocked_mutex);
946 lowret = InterlockedIncrement((gint32 *) location);
948 highret = InterlockedIncrement((gint32 *) location + 1);
950 highret = *((gint32 *) location + 1);
952 LeaveCriticalSection(&interlocked_mutex);
954 return (gint64) highret << 32 | (gint64) lowret;
957 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
959 return InterlockedDecrement(location);
962 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
967 EnterCriticalSection(&interlocked_mutex);
969 lowret = InterlockedDecrement((gint32 *) location);
971 highret = InterlockedDecrement((gint32 *) location + 1);
973 highret = *((gint32 *) location + 1);
975 LeaveCriticalSection(&interlocked_mutex);
977 return (gint64) highret << 32 | (gint64) lowret;
980 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location1, gint32 value)
982 return InterlockedExchange(location1, value);
985 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location1, MonoObject *value)
987 return (MonoObject *) InterlockedExchangePointer((gpointer *) location1, value);
990 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location1, gfloat value)
992 IntFloatUnion val, ret;
995 ret.ival = InterlockedExchange((gint32 *) location1, val.ival);
1000 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location1, gint32 value, gint32 comparand)
1002 return InterlockedCompareExchange(location1, value, comparand);
1005 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location1, MonoObject *value, MonoObject *comparand)
1007 return (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location1, value, comparand);
1010 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location1, gfloat value, gfloat comparand)
1012 IntFloatUnion val, ret, cmp;
1015 cmp.fval = comparand;
1016 ret.ival = InterlockedCompareExchange((gint32 *) location1, val.ival, cmp.ival);
1022 ves_icall_System_Threading_Thread_Abort (MonoThread *thread, MonoObject *state)
1024 thread->abort_state = state;
1025 thread->abort_exc = mono_get_exception_thread_abort ();
1028 /* fixme: store the state somewhere */
1030 #ifdef PTHREAD_POINTER_ID
1031 pthread_kill (GUINT_TO_POINTER(thread->tid), SIGUSR1);
1033 pthread_kill (thread->tid, SIGUSR1);
1036 g_assert_not_reached ();
1041 ves_icall_System_Threading_Thread_ResetAbort (void)
1043 MonoThread *thread = mono_thread_current ();
1045 if (!thread->abort_exc) {
1046 const char *msg = "Unable to reset abort because no abort was requested";
1047 mono_raise_exception (mono_get_exception_thread_state (msg));
1049 thread->abort_exc = NULL;
1050 thread->abort_state = NULL;
1054 void mono_thread_init (MonoDomain *domain, MonoThreadStartCB start_cb,
1055 MonoThreadStartCB attach_cb)
1057 /* Build a System.Threading.Thread object instance to return
1058 * for the main line's Thread.CurrentThread property.
1061 /* I wonder what happens if someone tries to destroy this
1062 * object? In theory, I guess the whole program should act as
1063 * though exit() were called :-)
1066 g_message(G_GNUC_PRETTY_FUNCTION
1067 ": Starting to build main Thread object");
1069 main_thread = (MonoThread *)mono_object_new (domain, mono_defaults.thread_class);
1071 main_thread->handle = GetCurrentThread ();
1074 g_message(G_GNUC_PRETTY_FUNCTION
1075 ": Finished building main Thread object: %p", main_thread);
1078 InitializeCriticalSection(&threads_mutex);
1079 InitializeCriticalSection(&monitor_mutex);
1080 InitializeCriticalSection(&interlocked_mutex);
1082 current_object_key=TlsAlloc();
1084 g_message (G_GNUC_PRETTY_FUNCTION ": Allocated current_object_key %d",
1085 current_object_key);
1088 TlsSetValue(current_object_key, main_thread);
1090 mono_thread_start_cb = start_cb;
1091 mono_thread_attach_cb = attach_cb;
1093 slothash_key=TlsAlloc();
1095 /* Get a pseudo handle to the current process. This is just a
1096 * kludge so that wapi can build a process handle if needed.
1097 * As a pseudo handle is returned, we don't need to clean
1100 GetCurrentProcess ();
1104 static void print_tids (gpointer key, gpointer value, gpointer user)
1106 g_message ("Waiting for: %d", *(guint32 *)key);
1112 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
1113 MonoThread *threads[MAXIMUM_WAIT_OBJECTS];
1117 static void wait_for_tids (struct wait_data *wait)
1122 g_message(G_GNUC_PRETTY_FUNCTION
1123 ": %d threads to wait for in this batch", wait->num);
1126 ret=WaitForMultipleObjects(wait->num, wait->handles, TRUE, INFINITE);
1127 if(ret==WAIT_FAILED) {
1128 /* See the comment in build_wait_tids() */
1130 g_message (G_GNUC_PRETTY_FUNCTION ": Wait failed");
1136 for(i=0; i<wait->num; i++) {
1137 guint32 tid=wait->threads[i]->tid;
1139 if(mono_g_hash_table_lookup (threads, &tid)!=NULL) {
1140 /* This thread must have been killed, because
1141 * it hasn't cleaned itself up. (It's just
1142 * possible that the thread exited before the
1143 * parent thread had a chance to store the
1144 * handle, and now there is another pointer to
1145 * the already-exited thread stored. In this
1146 * case, we'll just get two
1147 * mono_profiler_thread_end() calls for the
1152 g_message (G_GNUC_PRETTY_FUNCTION
1153 ": cleaning up after thread %d", tid);
1155 thread_cleanup (tid);
1160 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
1162 struct wait_data *wait=(struct wait_data *)user;
1164 if(wait->num<MAXIMUM_WAIT_OBJECTS) {
1165 MonoThread *thread=(MonoThread *)value;
1167 /* Theres a theoretical chance that thread->handle
1168 * might be NULL if the child thread has called
1169 * handle_store() but the parent thread hasn't set the
1170 * handle pointer yet. WaitForMultipleObjects will
1171 * fail, and we'll just go round the loop again. By
1172 * that time the handle should be stored properly.
1174 wait->handles[wait->num]=thread->handle;
1175 wait->threads[wait->num]=thread;
1178 /* Just ignore the rest, we can't do anything with
1184 void mono_thread_cleanup(void)
1186 struct wait_data *wait=g_new0 (struct wait_data, 1);
1188 /* join each thread that's still running */
1190 g_message(G_GNUC_PRETTY_FUNCTION ": Joining each running thread...");
1195 g_message(G_GNUC_PRETTY_FUNCTION ": No threads");
1201 EnterCriticalSection (&threads_mutex);
1203 g_message(G_GNUC_PRETTY_FUNCTION
1204 ":There are %d threads to join",
1205 mono_g_hash_table_size (threads));
1206 mono_g_hash_table_foreach (threads, print_tids, NULL);
1210 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
1212 LeaveCriticalSection (&threads_mutex);
1214 /* Something to wait for */
1215 wait_for_tids (wait);
1217 } while(wait->num>0);
1221 mono_g_hash_table_destroy(threads);