2006-05-04 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / metadata / threads.c
1 /*
2  * threads.c: Thread support internal calls
3  *
4  * Author:
5  *      Dick Porter (dick@ximian.com)
6  *      Paolo Molaro (lupus@ximian.com)
7  *      Patrik Torstensson (patrik.torstensson@labs2.com)
8  *
9  * (C) 2001 Ximian, Inc.
10  */
11
12 #include <config.h>
13 #ifdef PLATFORM_WIN32
14 #define _WIN32_WINNT 0x0500
15 #endif
16
17 #include <glib.h>
18 #include <signal.h>
19 #include <string.h>
20
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>
36
37 #include <mono/os/gc_wrapper.h>
38
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)
45
46 struct StartInfo 
47 {
48         guint32 (*func)(void *);
49         MonoThread *obj;
50         MonoObject *delegate;
51         void *start_arg;
52         MonoDomain *domain;
53 };
54
55 typedef union {
56         gint32 ival;
57         gfloat fval;
58 } IntFloatUnion;
59
60 typedef union {
61         gint64 ival;
62         gdouble fval;
63 } LongDoubleUnion;
64  
65 typedef struct {
66         int idx;
67         int offset;
68 } StaticDataInfo;
69
70 /* Number of cached culture objects in the MonoThread->cached_culture_info array
71  * (per-type): we use the first NUM entries for CultureInfo and the last for
72  * UICultureInfo. So the size of the array is really NUM_CACHED_CULTURES * 2.
73  */
74 #define NUM_CACHED_CULTURES 4
75 #define CULTURES_START_IDX 0
76 #define UICULTURES_START_IDX NUM_CACHED_CULTURES
77
78 /*
79  * The "os_handle" field of the WaitHandle class.
80  */
81 static MonoClassField *wait_handle_os_handle_field = NULL;
82
83 /* Controls access to the 'threads' hash table */
84 #define mono_threads_lock() EnterCriticalSection (&threads_mutex)
85 #define mono_threads_unlock() LeaveCriticalSection (&threads_mutex)
86 static CRITICAL_SECTION threads_mutex;
87
88 /* Controls access to context static data */
89 #define mono_contexts_lock() EnterCriticalSection (&contexts_mutex)
90 #define mono_contexts_unlock() LeaveCriticalSection (&contexts_mutex)
91 static CRITICAL_SECTION contexts_mutex;
92
93 /* Holds current status of static data heap */
94 static StaticDataInfo thread_static_info;
95 static StaticDataInfo context_static_info;
96
97 /* The hash of existing threads (key is thread ID) that need joining
98  * before exit
99  */
100 static MonoGHashTable *threads=NULL;
101
102 /* The TLS key that holds the MonoObject assigned to each thread */
103 static guint32 current_object_key = -1;
104
105 #ifdef HAVE_KW_THREAD
106 /* we need to use both the Tls* functions and __thread because
107  * the gc needs to see all the threads 
108  */
109 static __thread MonoThread * tls_current_object MONO_TLS_FAST;
110 #define SET_CURRENT_OBJECT(x) do { \
111         tls_current_object = x; \
112         TlsSetValue (current_object_key, x); \
113 } while (FALSE)
114 #define GET_CURRENT_OBJECT() tls_current_object
115 #else
116 #define SET_CURRENT_OBJECT(x) TlsSetValue (current_object_key, x);
117 #define GET_CURRENT_OBJECT() (MonoThread*) TlsGetValue (current_object_key);
118 #endif
119
120 /* function called at thread start */
121 static MonoThreadStartCB mono_thread_start_cb = NULL;
122
123 /* function called at thread attach */
124 static MonoThreadAttachCB mono_thread_attach_cb = NULL;
125
126 /* function called at thread cleanup */
127 static MonoThreadCleanupFunc mono_thread_cleanup = NULL;
128
129 /* The default stack size for each thread */
130 static guint32 default_stacksize = 0;
131 #define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize)
132
133 static void thread_adjust_static_data (MonoThread *thread);
134 static void mono_init_static_data_info (StaticDataInfo *static_data);
135 static guint32 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align);
136 static gboolean mono_thread_resume (MonoThread* thread);
137 static void mono_thread_start (MonoThread *thread);
138
139 /* Spin lock for InterlockedXXX 64 bit functions */
140 #define mono_interlocked_lock() EnterCriticalSection (&interlocked_mutex)
141 #define mono_interlocked_unlock() LeaveCriticalSection (&interlocked_mutex)
142 static CRITICAL_SECTION interlocked_mutex;
143
144 /* global count of thread interruptions requested */
145 static gint32 thread_interruption_requested = 0;
146
147 /* Event signaled when a thread changes its background mode */
148 static HANDLE background_change_event;
149
150 guint32
151 mono_thread_get_tls_key (void)
152 {
153         return current_object_key;
154 }
155
156 gint32
157 mono_thread_get_tls_offset (void)
158 {
159         int offset;
160         MONO_THREAD_VAR_OFFSET (tls_current_object,offset);
161         return offset;
162 }
163
164 /* handle_store() and handle_remove() manage the array of threads that
165  * still need to be waited for when the main thread exits.
166  */
167 static void handle_store(MonoThread *thread)
168 {
169         mono_threads_lock ();
170
171         THREAD_DEBUG (g_message ("%s: thread %p ID %"G_GSIZE_FORMAT, __func__, thread, (gsize)thread->tid));
172
173         if(threads==NULL) {
174                 MONO_GC_REGISTER_ROOT (threads);
175                 threads=mono_g_hash_table_new(NULL, NULL);
176         }
177
178         /* We don't need to duplicate thread->handle, because it is
179          * only closed when the thread object is finalized by the GC.
180          */
181         mono_g_hash_table_insert(threads, (gpointer)(gsize)(thread->tid),
182                                  thread);
183
184         mono_threads_unlock ();
185 }
186
187 static void handle_remove(gsize tid)
188 {
189         THREAD_DEBUG (g_message ("%s: thread ID %"G_GSIZE_FORMAT, __func__, tid));
190
191         mono_threads_lock ();
192         
193
194         if (threads)
195                 mono_g_hash_table_remove (threads, (gpointer)tid);
196         
197         mono_threads_unlock ();
198
199         /* Don't close the handle here, wait for the object finalizer
200          * to do it. Otherwise, the following race condition applies:
201          *
202          * 1) Thread exits (and handle_remove() closes the handle)
203          *
204          * 2) Some other handle is reassigned the same slot
205          *
206          * 3) Another thread tries to join the first thread, and
207          * blocks waiting for the reassigned handle to be signalled
208          * (which might never happen).  This is possible, because the
209          * thread calling Join() still has a reference to the first
210          * thread's object.
211          */
212 }
213
214 /*
215  * Tell the Mono Debugger about a newly created thread.
216  * mono_debugger_event() is a no-op if we're not running inside the debugger.
217  */
218 static void debugger_thread_created (MonoThread *thread)
219 {
220         mono_debugger_event (MONO_DEBUGGER_EVENT_THREAD_CREATED,
221                              (guint64) (gsize) &thread->end_stack, thread->tid);
222 }
223
224 /*
225  * Tell the Mono Debugger that a thrad is about to exit.
226  * mono_debugger_event() is a no-op if we're not running inside the debugger.
227  */
228 static void debugger_thread_exited (MonoThread *thread)
229 {
230         mono_debugger_event (MONO_DEBUGGER_EVENT_THREAD_EXITED,
231                              (guint64) (gsize) &thread->end_stack, thread->tid);
232 }
233
234 static void thread_cleanup (MonoThread *thread)
235 {
236         g_assert (thread != NULL);
237
238         mono_release_type_locks (thread);
239
240         if (!mono_monitor_enter (thread->synch_lock))
241                 return;
242
243         thread->state |= ThreadState_Stopped;
244         mono_monitor_exit (thread->synch_lock);
245
246         mono_profiler_thread_end (thread->tid);
247         handle_remove (thread->tid);
248
249         mono_thread_pop_appdomain_ref ();
250
251         if (thread->serialized_culture_info)
252                 g_free (thread->serialized_culture_info);
253
254         thread->cached_culture_info = NULL;
255
256         debugger_thread_exited (thread);
257
258         if (mono_thread_cleanup)
259                 mono_thread_cleanup (thread);
260 }
261
262 static guint32 WINAPI start_wrapper(void *data)
263 {
264         struct StartInfo *start_info=(struct StartInfo *)data;
265         guint32 (*start_func)(void *);
266         void *start_arg;
267         guint32 tid;
268         MonoThread *thread=start_info->obj;
269         MonoObject *start_delegate = start_info->delegate;
270
271         THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper", __func__, GetCurrentThreadId ()));
272         
273         /* We can be sure start_info->obj->tid and
274          * start_info->obj->handle have been set, because the thread
275          * was created suspended, and these values were set before the
276          * thread resumed
277          */
278
279         tid=thread->tid;
280
281         SET_CURRENT_OBJECT (thread);
282         
283         if (!mono_domain_set (start_info->domain, FALSE)) {
284                 /* No point in raising an appdomain_unloaded exception here */
285                 /* FIXME: Cleanup here */
286                 return 0;
287         }
288
289         start_func = start_info->func;
290         start_arg = start_info->start_arg;
291
292         /* This MUST be called before any managed code can be
293          * executed, as it calls the callback function that (for the
294          * jit) sets the lmf marker.
295          */
296         mono_thread_new_init (tid, &tid, start_func);
297         thread->stack_ptr = &tid;
298
299         debugger_thread_created (thread);
300
301         LIBGC_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT",%d) Setting thread stack to %p", __func__, GetCurrentThreadId (), getpid (), thread->stack_ptr));
302
303         THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, GetCurrentThreadId (), thread));
304
305         mono_profiler_thread_start (tid);
306
307         if(thread->start_notify!=NULL) {
308                 /* Let the thread that called Start() know we're
309                  * ready
310                  */
311                 ReleaseSemaphore (thread->start_notify, 1, NULL);
312         }
313         
314         g_free (start_info);
315
316         /* Every thread references the appdomain which created it */
317         mono_thread_push_appdomain_ref (mono_domain_get ());
318
319         thread_adjust_static_data (thread);
320 #ifdef DEBUG
321         g_message ("%s: start_wrapper for %"G_GSIZE_FORMAT, __func__,
322                    thread->tid);
323 #endif
324
325         /* start_func is set only for unamanged start functions */
326         if (start_func) {
327                 start_func (start_arg);
328         } else {
329                 void *args [1];
330                 g_assert (start_delegate != NULL);
331                 args [0] = start_arg;
332                 /* we may want to handle the exception here. See comment below on unhandled exceptions */
333                 mono_runtime_delegate_invoke (start_delegate, args, NULL);
334         }
335
336         /* If the thread calls ExitThread at all, this remaining code
337          * will not be executed, but the main thread will eventually
338          * call thread_cleanup() on this thread's behalf.
339          */
340
341         THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper terminating", __func__, GetCurrentThreadId ()));
342
343         /* Remove the reference to the thread object in the TLS data,
344          * so the thread object can be finalized.  This won't be
345          * reached if the thread threw an uncaught exception, so those
346          * thread handles will stay referenced :-( (This is due to
347          * missing support for scanning thread-specific data in the
348          * Boehm GC - the io-layer keeps a GC-visible hash of pointers
349          * to TLS data.)
350          */
351         SET_CURRENT_OBJECT (NULL);
352
353         thread_cleanup (thread);
354
355         return(0);
356 }
357
358 void mono_thread_new_init (gsize tid, gpointer stack_start, gpointer func)
359 {
360         if (mono_thread_start_cb) {
361                 mono_thread_start_cb (tid, stack_start, func);
362         }
363 }
364
365 void mono_threads_set_default_stacksize (guint32 stacksize)
366 {
367         default_stacksize = stacksize;
368 }
369
370 guint32 mono_threads_get_default_stacksize (void)
371 {
372         return default_stacksize;
373 }
374
375 void mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
376 {
377         MonoThread *thread;
378         HANDLE thread_handle;
379         struct StartInfo *start_info;
380         gsize tid;
381         
382         thread=(MonoThread *)mono_object_new (domain,
383                                               mono_defaults.thread_class);
384
385         start_info=g_new0 (struct StartInfo, 1);
386         start_info->func = func;
387         start_info->obj = thread;
388         start_info->domain = domain;
389         start_info->start_arg = arg;
390         
391         /* Create suspended, so we can do some housekeeping before the thread
392          * starts
393          */
394         thread_handle = CreateThread(NULL, default_stacksize_for_thread (thread), (LPTHREAD_START_ROUTINE)start_wrapper, start_info,
395                                      CREATE_SUSPENDED, &tid);
396         THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
397         if (thread_handle == NULL) {
398                 /* The thread couldn't be created, so throw an exception */
399                 mono_raise_exception (mono_get_exception_execution_engine ("Couldn't create thread"));
400                 return;
401         }
402
403         thread->handle=thread_handle;
404         thread->tid=tid;
405
406         MONO_OBJECT_SETREF (thread, synch_lock, mono_object_new (domain, mono_defaults.object_class));
407                                                   
408         handle_store(thread);
409
410         ResumeThread (thread_handle);
411 }
412
413 MonoThread *
414 mono_thread_attach (MonoDomain *domain)
415 {
416         MonoThread *thread;
417         HANDLE thread_handle;
418         gsize tid;
419
420         if ((thread = mono_thread_current ())) {
421                 if (domain != mono_domain_get ())
422                         mono_domain_set (domain, TRUE);
423                 /* Already attached */
424                 return thread;
425         }
426
427         if (!mono_gc_register_thread (&domain)) {
428                 g_error ("Thread %p 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.", GetCurrentThread ());
429         }
430
431         thread = (MonoThread *)mono_object_new (domain,
432                                                 mono_defaults.thread_class);
433
434         thread_handle = GetCurrentThread ();
435         g_assert (thread_handle);
436
437         tid=GetCurrentThreadId ();
438
439 #ifdef PLATFORM_WIN32
440         /* 
441          * The handle returned by GetCurrentThread () is a pseudo handle, so it can't be used to
442          * refer to the thread from other threads for things like aborting.
443          */
444         DuplicateHandle (GetCurrentProcess (), thread_handle, GetCurrentProcess (), &thread_handle, 
445                                          THREAD_ALL_ACCESS, TRUE, 0);
446 #endif
447
448         thread->handle=thread_handle;
449         thread->tid=tid;
450         thread->stack_ptr = &tid;
451         MONO_OBJECT_SETREF (thread, synch_lock, mono_object_new (domain, mono_defaults.object_class));
452
453         THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
454
455         handle_store(thread);
456
457         THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, GetCurrentThreadId (), thread));
458
459         SET_CURRENT_OBJECT (thread);
460         mono_domain_set (domain, TRUE);
461
462         debugger_thread_created (thread);
463
464         thread_adjust_static_data (thread);
465
466         if (mono_thread_attach_cb) {
467                 mono_thread_attach_cb (tid, &tid);
468         }
469
470         return(thread);
471 }
472
473 void
474 mono_thread_detach (MonoThread *thread)
475 {
476         g_return_if_fail (thread != NULL);
477
478         THREAD_DEBUG (g_message ("%s: mono_thread_detach for %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
479         SET_CURRENT_OBJECT (NULL);
480         
481         thread_cleanup (thread);
482
483         /* Don't need to CloseHandle this thread, even though we took a
484          * reference in mono_thread_attach (), because the GC will do it
485          * when the Thread object is finalised.
486          */
487 }
488
489 void
490 mono_thread_exit ()
491 {
492         MonoThread *thread = mono_thread_current ();
493
494         SET_CURRENT_OBJECT (NULL);
495         thread_cleanup (thread);
496
497         /* we could add a callback here for embedders to use. */
498         if (thread == mono_thread_get_main ())
499                 exit (mono_environment_exitcode_get ());
500         ExitThread (-1);
501 }
502
503 HANDLE ves_icall_System_Threading_Thread_Thread_internal(MonoThread *this,
504                                                          MonoObject *start)
505 {
506         guint32 (*start_func)(void *);
507         struct StartInfo *start_info;
508         HANDLE thread;
509         gsize tid;
510         
511         MONO_ARCH_SAVE_REGS;
512
513         THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this, start));
514
515         mono_monitor_enter (this->synch_lock);
516
517         if ((this->state & ThreadState_Unstarted) == 0) {
518                 mono_monitor_exit (this->synch_lock);
519                 mono_raise_exception (mono_get_exception_thread_state ("Thread has already been started."));
520                 return NULL;
521         }
522
523         if ((this->state & ThreadState_Aborted) != 0) {
524                 mono_monitor_exit (this->synch_lock);
525                 return this;
526         }
527         start_func = NULL;
528         {
529                 /* This is freed in start_wrapper */
530                 start_info = g_new0 (struct StartInfo, 1);
531                 start_info->func = start_func;
532                 start_info->start_arg = this->start_obj; /* FIXME: GC object stored in unmanaged memory */
533                 start_info->delegate = start;
534                 start_info->obj = this;
535                 start_info->domain = mono_domain_get ();
536
537                 this->start_notify=CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
538                 if(this->start_notify==NULL) {
539                         mono_monitor_exit (this->synch_lock);
540                         g_warning ("%s: CreateSemaphore error 0x%x", __func__, GetLastError ());
541                         return(NULL);
542                 }
543
544                 thread=CreateThread(NULL, default_stacksize_for_thread (this), (LPTHREAD_START_ROUTINE)start_wrapper, start_info,
545                                     CREATE_SUSPENDED, &tid);
546                 if(thread==NULL) {
547                         mono_monitor_exit (this->synch_lock);
548                         g_warning("%s: CreateThread error 0x%x", __func__, GetLastError());
549                         return(NULL);
550                 }
551                 
552                 this->handle=thread;
553                 this->tid=tid;
554
555                 /* Don't call handle_store() here, delay it to Start.
556                  * We can't join a thread (trying to will just block
557                  * forever) until it actually starts running, so don't
558                  * store the handle till then.
559                  */
560
561                 mono_thread_start (this);
562                 
563                 this->state &= ~ThreadState_Unstarted;
564
565                 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread));
566
567                 mono_monitor_exit (this->synch_lock);
568                 return(thread);
569         }
570 }
571
572 void ves_icall_System_Threading_Thread_Thread_free_internal (MonoThread *this,
573                                                              HANDLE thread)
574 {
575         MONO_ARCH_SAVE_REGS;
576
577         THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, thread));
578
579         CloseHandle (thread);
580 }
581
582 static void mono_thread_start (MonoThread *thread)
583 {
584         MONO_ARCH_SAVE_REGS;
585
586         THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), thread, (gsize)thread->tid));
587
588         /* Only store the handle when the thread is about to be
589          * launched, to avoid the main thread deadlocking while trying
590          * to clean up a thread that will never be signalled.
591          */
592         handle_store (thread);
593
594         ResumeThread (thread->handle);
595
596         if(thread->start_notify!=NULL) {
597                 /* Wait for the thread to set up its TLS data etc, so
598                  * theres no potential race condition if someone tries
599                  * to look up the data believing the thread has
600                  * started
601                  */
602
603                 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for thread %p (%"G_GSIZE_FORMAT") to start", __func__, GetCurrentThreadId (), thread, (gsize)thread->tid));
604
605                 WaitForSingleObjectEx (thread->start_notify, INFINITE, FALSE);
606                 CloseHandle (thread->start_notify);
607                 thread->start_notify = NULL;
608         }
609
610         THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Done launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), thread, (gsize)thread->tid));
611 }
612
613 void ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
614 {
615         MonoThread *thread = mono_thread_current ();
616         
617         MONO_ARCH_SAVE_REGS;
618
619         THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
620
621         mono_monitor_enter (thread->synch_lock);
622         thread->state |= ThreadState_WaitSleepJoin;
623         mono_monitor_exit (thread->synch_lock);
624         
625         SleepEx(ms,TRUE);
626         
627         mono_monitor_enter (thread->synch_lock);
628         thread->state &= ~ThreadState_WaitSleepJoin;
629         mono_monitor_exit (thread->synch_lock);
630 }
631
632 gint32
633 ves_icall_System_Threading_Thread_GetDomainID (void) 
634 {
635         MONO_ARCH_SAVE_REGS;
636
637         return mono_domain_get()->domain_id;
638 }
639
640 MonoString* 
641 ves_icall_System_Threading_Thread_GetName_internal (MonoThread *this_obj)
642 {
643         MonoString* str;
644         mono_monitor_enter (this_obj->synch_lock);
645         
646         if (!this_obj->name)
647                 str = NULL;
648         else
649                 str = mono_string_new_utf16 (mono_domain_get (), this_obj->name, this_obj->name_len);
650         
651         mono_monitor_exit (this_obj->synch_lock);
652         return str;
653 }
654
655 void 
656 ves_icall_System_Threading_Thread_SetName_internal (MonoThread *this_obj, MonoString *name)
657 {
658         mono_monitor_enter (this_obj->synch_lock);
659         
660         if (this_obj->name) {
661                 mono_monitor_exit (this_obj->synch_lock);
662                 mono_raise_exception (mono_get_exception_invalid_operation ("Thread.Name can only be set once."));
663                 return;
664         }
665         if (name) {
666                 this_obj->name = g_new (gunichar2, mono_string_length (name));
667                 memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2);
668                 this_obj->name_len = mono_string_length (name);
669         }
670         else
671                 this_obj->name = NULL;
672         
673         mono_monitor_exit (this_obj->synch_lock);
674 }
675
676 static MonoObject*
677 lookup_cached_culture (MonoThread *this, MonoDomain *domain, int start_idx)
678 {
679         MonoObject *res;
680         int i;
681
682         if (this->cached_culture_info) {
683                 domain = mono_domain_get ();
684                 for (i = start_idx; i < start_idx + NUM_CACHED_CULTURES; ++i) {
685                         res = mono_array_get (this->cached_culture_info, MonoObject*, i);
686                         if (res && res->vtable->domain == domain)
687                                 return res;
688                 }
689         }
690
691         return NULL;
692 }
693
694 MonoObject*
695 ves_icall_System_Threading_Thread_GetCachedCurrentCulture (MonoThread *this)
696 {
697         return lookup_cached_culture (this, mono_domain_get (), CULTURES_START_IDX);
698 }
699
700 MonoArray*
701 ves_icall_System_Threading_Thread_GetSerializedCurrentCulture (MonoThread *this)
702 {
703         MonoArray *res;
704
705         mono_monitor_enter (this->synch_lock);
706         if (this->serialized_culture_info) {
707                 res = mono_array_new (mono_domain_get (), mono_defaults.byte_class, this->serialized_culture_info_len);
708                 memcpy (mono_array_addr (res, guint8, 0), this->serialized_culture_info, this->serialized_culture_info_len);
709         } else {
710                 res = NULL;
711         }
712         mono_monitor_exit (this->synch_lock);
713
714         return res;
715 }
716
717 static void
718 cache_culture (MonoThread *this, MonoObject *culture, int start_idx)
719 {
720         int i;
721         MonoDomain *domain = mono_domain_get ();
722         MonoObject *obj;
723         int free_slot = -1;
724         int same_domain_slot = -1;
725
726         mono_monitor_enter (this->synch_lock);
727         if (!this->cached_culture_info)
728                 this->cached_culture_info = mono_array_new (mono_object_domain (this), mono_defaults.object_class, NUM_CACHED_CULTURES * 2);
729
730         for (i = start_idx; i < start_idx + NUM_CACHED_CULTURES; ++i) {
731                 obj = mono_array_get (this->cached_culture_info, MonoObject*, i);
732                 /* Free entry */
733                 if (!obj) {
734                         free_slot = i;
735                         /* we continue, because there may be a slot used with the same domain */
736                         continue;
737                 }
738                 /* Replace */
739                 if (obj->vtable->domain == domain) {
740                         same_domain_slot = i;
741                         break;
742                 }
743         }
744         if (same_domain_slot >= 0)
745                 mono_array_setref (this->cached_culture_info, same_domain_slot, culture);
746         else if (free_slot >= 0)
747                 mono_array_setref (this->cached_culture_info, free_slot, culture);
748         /* we may want to replace an existing entry here, even when no suitable slot is found */
749         mono_monitor_exit (this->synch_lock);
750 }
751
752 void
753 ves_icall_System_Threading_Thread_SetCachedCurrentCulture (MonoThread *this, MonoObject *culture)
754 {
755         cache_culture (this, culture, CULTURES_START_IDX);
756 }
757
758 void
759 ves_icall_System_Threading_Thread_SetSerializedCurrentCulture (MonoThread *this, MonoArray *arr)
760 {
761         mono_monitor_enter (this->synch_lock);
762         if (this->serialized_culture_info)
763                 g_free (this->serialized_culture_info);
764         this->serialized_culture_info = g_new0 (guint8, mono_array_length (arr));
765         this->serialized_culture_info_len = mono_array_length (arr);
766         memcpy (this->serialized_culture_info, mono_array_addr (arr, guint8, 0), mono_array_length (arr));
767         mono_monitor_exit (this->synch_lock);
768 }
769
770
771 MonoObject*
772 ves_icall_System_Threading_Thread_GetCachedCurrentUICulture (MonoThread *this)
773 {
774         return lookup_cached_culture (this, mono_domain_get (), UICULTURES_START_IDX);
775 }
776
777 MonoArray*
778 ves_icall_System_Threading_Thread_GetSerializedCurrentUICulture (MonoThread *this)
779 {
780         MonoArray *res;
781
782         mono_monitor_enter (this->synch_lock);
783         if (this->serialized_ui_culture_info) {
784                 res = mono_array_new (mono_domain_get (), mono_defaults.byte_class, this->serialized_ui_culture_info_len);
785                 memcpy (mono_array_addr (res, guint8, 0), this->serialized_ui_culture_info, this->serialized_ui_culture_info_len);
786         } else {
787                 res = NULL;
788         }
789         mono_monitor_exit (this->synch_lock);
790
791         return res;
792 }
793
794 void
795 ves_icall_System_Threading_Thread_SetCachedCurrentUICulture (MonoThread *this, MonoObject *culture)
796 {
797         cache_culture (this, culture, UICULTURES_START_IDX);
798 }
799
800 void
801 ves_icall_System_Threading_Thread_SetSerializedCurrentUICulture (MonoThread *this, MonoArray *arr)
802 {
803         mono_monitor_enter (this->synch_lock);
804         if (this->serialized_ui_culture_info)
805                 g_free (this->serialized_ui_culture_info);
806         this->serialized_ui_culture_info = g_new0 (guint8, mono_array_length (arr));
807         this->serialized_ui_culture_info_len = mono_array_length (arr);
808         memcpy (this->serialized_ui_culture_info, mono_array_addr (arr, guint8, 0), mono_array_length (arr));
809         mono_monitor_exit (this->synch_lock);
810 }
811
812 /* the jit may read the compiled code of this function */
813 MonoThread *
814 mono_thread_current (void)
815 {
816         THREAD_DEBUG (g_message ("%s: returning %p", __func__, GET_CURRENT_OBJECT ()));
817         return GET_CURRENT_OBJECT ();
818 }
819
820 gboolean ves_icall_System_Threading_Thread_Join_internal(MonoThread *this,
821                                                          int ms, HANDLE thread)
822 {
823         gboolean ret;
824         
825         MONO_ARCH_SAVE_REGS;
826
827         mono_monitor_enter (this->synch_lock);
828         
829         if ((this->state & ThreadState_Unstarted) != 0) {
830                 mono_monitor_exit (this->synch_lock);
831                 mono_raise_exception (mono_get_exception_thread_state ("Thread has not been started."));
832                 return FALSE;
833         }
834         
835         this->state |= ThreadState_WaitSleepJoin;
836         mono_monitor_exit (this->synch_lock);
837
838         if(ms== -1) {
839                 ms=INFINITE;
840         }
841         THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, thread, ms));
842         
843         ret=WaitForSingleObjectEx (thread, ms, TRUE);
844
845         mono_monitor_enter (this->synch_lock);
846         this->state &= ~ThreadState_WaitSleepJoin;
847         mono_monitor_exit (this->synch_lock);
848         
849         if(ret==WAIT_OBJECT_0) {
850                 THREAD_DEBUG (g_message ("%s: join successful", __func__));
851
852                 return(TRUE);
853         }
854         
855         THREAD_DEBUG (g_message ("%s: join failed", __func__));
856
857         return(FALSE);
858 }
859
860 /* FIXME: exitContext isnt documented */
861 gboolean ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
862 {
863         HANDLE *handles;
864         guint32 numhandles;
865         guint32 ret;
866         guint32 i;
867         MonoObject *waitHandle;
868         MonoClass *klass;
869         MonoThread *thread = mono_thread_current ();
870                 
871         MONO_ARCH_SAVE_REGS;
872
873         numhandles = mono_array_length(mono_handles);
874         handles = g_new0(HANDLE, numhandles);
875
876         if (wait_handle_os_handle_field == 0) {
877                 /* Get the field os_handle which will contain the actual handle */
878                 klass = mono_class_from_name(mono_defaults.corlib, "System.Threading", "WaitHandle");   
879                 wait_handle_os_handle_field = mono_class_get_field_from_name(klass, "os_handle");
880         }
881                 
882         for(i = 0; i < numhandles; i++) {       
883                 waitHandle = mono_array_get(mono_handles, MonoObject*, i);              
884                 mono_field_get_value(waitHandle, wait_handle_os_handle_field, &handles[i]);
885         }
886         
887         if(ms== -1) {
888                 ms=INFINITE;
889         }
890
891         mono_monitor_enter (thread->synch_lock);
892         thread->state |= ThreadState_WaitSleepJoin;
893         mono_monitor_exit (thread->synch_lock);
894         
895         ret=WaitForMultipleObjectsEx(numhandles, handles, TRUE, ms, TRUE);
896
897         mono_monitor_enter (thread->synch_lock);
898         thread->state &= ~ThreadState_WaitSleepJoin;
899         mono_monitor_exit (thread->synch_lock);
900
901         g_free(handles);
902
903         if(ret==WAIT_FAILED) {
904                 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
905                 return(FALSE);
906         } else if(ret==WAIT_TIMEOUT || ret == WAIT_IO_COMPLETION) {
907                 /* Do we want to try again if we get
908                  * WAIT_IO_COMPLETION? The documentation for
909                  * WaitHandle doesn't give any clues.  (We'd have to
910                  * fiddle with the timeout if we retry.)
911                  */
912                 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
913                 return(FALSE);
914         }
915         
916         return(TRUE);
917 }
918
919 /* FIXME: exitContext isnt documented */
920 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
921 {
922         HANDLE *handles;
923         guint32 numhandles;
924         guint32 ret;
925         guint32 i;
926         MonoObject *waitHandle;
927         MonoClass *klass;
928         MonoThread *thread = mono_thread_current ();
929                 
930         MONO_ARCH_SAVE_REGS;
931
932         numhandles = mono_array_length(mono_handles);
933         handles = g_new0(HANDLE, numhandles);
934
935         if (wait_handle_os_handle_field == 0) {
936                 /* Get the field os_handle which will contain the actual handle */
937                 klass = mono_class_from_name(mono_defaults.corlib, "System.Threading", "WaitHandle");   
938                 wait_handle_os_handle_field = mono_class_get_field_from_name(klass, "os_handle");
939         }
940                 
941         for(i = 0; i < numhandles; i++) {       
942                 waitHandle = mono_array_get(mono_handles, MonoObject*, i);              
943                 mono_field_get_value(waitHandle, wait_handle_os_handle_field, &handles[i]);
944         }
945         
946         if(ms== -1) {
947                 ms=INFINITE;
948         }
949
950         mono_monitor_enter (thread->synch_lock);
951         thread->state |= ThreadState_WaitSleepJoin;
952         mono_monitor_exit (thread->synch_lock);
953
954         ret=WaitForMultipleObjectsEx(numhandles, handles, FALSE, ms, TRUE);
955
956         mono_monitor_enter (thread->synch_lock);
957         thread->state &= ~ThreadState_WaitSleepJoin;
958         mono_monitor_exit (thread->synch_lock);
959
960         g_free(handles);
961
962         THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, GetCurrentThreadId (), ret));
963
964         /*
965          * These need to be here.  See MSDN dos on WaitForMultipleObjects.
966          */
967         if (ret >= WAIT_OBJECT_0 && ret <= WAIT_OBJECT_0 + numhandles - 1) {
968                 return ret - WAIT_OBJECT_0;
969         }
970         else if (ret >= WAIT_ABANDONED_0 && ret <= WAIT_ABANDONED_0 + numhandles - 1) {
971                 return ret - WAIT_ABANDONED_0;
972         }
973         else {
974                 return ret;
975         }
976 }
977
978 /* FIXME: exitContext isnt documented */
979 gboolean ves_icall_System_Threading_WaitHandle_WaitOne_internal(MonoObject *this, HANDLE handle, gint32 ms, gboolean exitContext)
980 {
981         guint32 ret;
982         MonoThread *thread = mono_thread_current ();
983         
984         MONO_ARCH_SAVE_REGS;
985
986         THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for %p, %d ms", __func__, GetCurrentThreadId (), handle, ms));
987         
988         if(ms== -1) {
989                 ms=INFINITE;
990         }
991         
992         mono_monitor_enter (thread->synch_lock);
993         thread->state |= ThreadState_WaitSleepJoin;
994         mono_monitor_exit (thread->synch_lock);
995
996         ret=WaitForSingleObjectEx (handle, ms, TRUE);
997         
998         mono_monitor_enter (thread->synch_lock);
999         thread->state &= ~ThreadState_WaitSleepJoin;
1000         mono_monitor_exit (thread->synch_lock);
1001
1002         if(ret==WAIT_FAILED) {
1003                 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
1004                 return(FALSE);
1005         } else if(ret==WAIT_TIMEOUT || ret == WAIT_IO_COMPLETION) {
1006                 /* Do we want to try again if we get
1007                  * WAIT_IO_COMPLETION? The documentation for
1008                  * WaitHandle doesn't give any clues.  (We'd have to
1009                  * fiddle with the timeout if we retry.)
1010                  */
1011                 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
1012                 return(FALSE);
1013         }
1014         
1015         return(TRUE);
1016 }
1017
1018 HANDLE ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned, MonoString *name, MonoBoolean *created)
1019
1020         HANDLE mutex;
1021         
1022         MONO_ARCH_SAVE_REGS;
1023    
1024         *created = TRUE;
1025         
1026         if (name == NULL) {
1027                 mutex = CreateMutex (NULL, owned, NULL);
1028         } else {
1029                 mutex = CreateMutex (NULL, owned, mono_string_chars (name));
1030                 
1031                 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1032                         *created = FALSE;
1033                 }
1034         }
1035
1036         return(mutex);
1037 }                                                                   
1038
1039 void ves_icall_System_Threading_Mutex_ReleaseMutex_internal (HANDLE handle ) { 
1040         MONO_ARCH_SAVE_REGS;
1041
1042         ReleaseMutex(handle);
1043 }
1044
1045 HANDLE ves_icall_System_Threading_Mutex_OpenMutex_internal (MonoString *name,
1046                                                             gint32 rights,
1047                                                             gint32 *error)
1048 {
1049         HANDLE ret;
1050         
1051         MONO_ARCH_SAVE_REGS;
1052         
1053         *error = ERROR_SUCCESS;
1054         
1055         ret = OpenMutex (rights, FALSE, mono_string_chars (name));
1056         if (ret == NULL) {
1057                 *error = GetLastError ();
1058         }
1059         
1060         return(ret);
1061 }
1062
1063
1064 HANDLE ves_icall_System_Threading_Semaphore_CreateSemaphore_internal (gint32 initialCount, gint32 maximumCount, MonoString *name, MonoBoolean *created)
1065
1066         HANDLE sem;
1067         
1068         MONO_ARCH_SAVE_REGS;
1069    
1070         *created = TRUE;
1071         
1072         if (name == NULL) {
1073                 sem = CreateSemaphore (NULL, initialCount, maximumCount, NULL);
1074         } else {
1075                 sem = CreateSemaphore (NULL, initialCount, maximumCount,
1076                                        mono_string_chars (name));
1077                 
1078                 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1079                         *created = FALSE;
1080                 }
1081         }
1082
1083         return(sem);
1084 }                                                                   
1085
1086 gint32 ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal (HANDLE handle, gint32 releaseCount, MonoBoolean *fail)
1087
1088         gint32 prevcount;
1089         
1090         MONO_ARCH_SAVE_REGS;
1091
1092         *fail = !ReleaseSemaphore (handle, releaseCount, &prevcount);
1093
1094         return (prevcount);
1095 }
1096
1097 HANDLE ves_icall_System_Threading_Semaphore_OpenSemaphore_internal (MonoString *name, gint32 rights, gint32 *error)
1098 {
1099         HANDLE ret;
1100         
1101         MONO_ARCH_SAVE_REGS;
1102         
1103         *error = ERROR_SUCCESS;
1104         
1105         ret = OpenSemaphore (rights, FALSE, mono_string_chars (name));
1106         if (ret == NULL) {
1107                 *error = GetLastError ();
1108         }
1109         
1110         return(ret);
1111 }
1112
1113 HANDLE ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manual, MonoBoolean initial, MonoString *name, MonoBoolean *created)
1114 {
1115         HANDLE event;
1116         
1117         MONO_ARCH_SAVE_REGS;
1118
1119         *created = TRUE;
1120
1121         if (name == NULL) {
1122                 event = CreateEvent (NULL, manual, initial, NULL);
1123         } else {
1124                 event = CreateEvent (NULL, manual, initial,
1125                                      mono_string_chars (name));
1126                 
1127                 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1128                         *created = FALSE;
1129                 }
1130         }
1131         
1132         return(event);
1133 }
1134
1135 gboolean ves_icall_System_Threading_Events_SetEvent_internal (HANDLE handle) {
1136         MONO_ARCH_SAVE_REGS;
1137
1138         return (SetEvent(handle));
1139 }
1140
1141 gboolean ves_icall_System_Threading_Events_ResetEvent_internal (HANDLE handle) {
1142         MONO_ARCH_SAVE_REGS;
1143
1144         return (ResetEvent(handle));
1145 }
1146
1147 void
1148 ves_icall_System_Threading_Events_CloseEvent_internal (HANDLE handle) {
1149         MONO_ARCH_SAVE_REGS;
1150
1151         CloseHandle (handle);
1152 }
1153
1154 HANDLE ves_icall_System_Threading_Events_OpenEvent_internal (MonoString *name,
1155                                                              gint32 rights,
1156                                                              gint32 *error)
1157 {
1158         HANDLE ret;
1159         
1160         MONO_ARCH_SAVE_REGS;
1161         
1162         *error = ERROR_SUCCESS;
1163         
1164         ret = OpenEvent (rights, FALSE, mono_string_chars (name));
1165         if (ret == NULL) {
1166                 *error = GetLastError ();
1167         }
1168         
1169         return(ret);
1170 }
1171
1172 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
1173 {
1174         MONO_ARCH_SAVE_REGS;
1175
1176         return InterlockedIncrement (location);
1177 }
1178
1179 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
1180 {
1181         gint64 ret;
1182
1183         MONO_ARCH_SAVE_REGS;
1184
1185         mono_interlocked_lock ();
1186
1187         ret = ++ *location;
1188         
1189         mono_interlocked_unlock ();
1190
1191         
1192         return ret;
1193 }
1194
1195 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
1196 {
1197         MONO_ARCH_SAVE_REGS;
1198
1199         return InterlockedDecrement(location);
1200 }
1201
1202 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
1203 {
1204         gint64 ret;
1205
1206         MONO_ARCH_SAVE_REGS;
1207
1208         mono_interlocked_lock ();
1209
1210         ret = -- *location;
1211         
1212         mono_interlocked_unlock ();
1213
1214         return ret;
1215 }
1216
1217 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location, gint32 value)
1218 {
1219         MONO_ARCH_SAVE_REGS;
1220
1221         return InterlockedExchange(location, value);
1222 }
1223
1224 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location, MonoObject *value)
1225 {
1226         MONO_ARCH_SAVE_REGS;
1227
1228         return (MonoObject *) InterlockedExchangePointer((gpointer *) location, value);
1229 }
1230
1231 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, gfloat value)
1232 {
1233         IntFloatUnion val, ret;
1234
1235         MONO_ARCH_SAVE_REGS;
1236
1237         val.fval = value;
1238         ret.ival = InterlockedExchange((gint32 *) location, val.ival);
1239
1240         return ret.fval;
1241 }
1242
1243 gint64 
1244 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64 *location, gint64 value)
1245 {
1246 #if SIZEOF_VOID_P == 8
1247         return (gint64) InterlockedExchangePointer((gpointer *) location, (gpointer)value);
1248 #else
1249         gint64 res;
1250
1251         /* 
1252          * According to MSDN, this function is only atomic with regards to the 
1253          * other Interlocked functions on 32 bit platforms.
1254          */
1255         mono_interlocked_lock ();
1256         res = *location;
1257         *location = value;
1258         mono_interlocked_unlock ();
1259
1260         return res;
1261 #endif
1262 }
1263
1264 gdouble 
1265 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location, gdouble value)
1266 {
1267 #if SIZEOF_VOID_P == 8
1268         LongDoubleUnion val, ret;
1269
1270         val.fval = value;
1271         ret.ival = (gint64)InterlockedExchangePointer((gpointer *) location, (gpointer)val.ival);
1272
1273         return ret.fval;
1274 #else
1275         gdouble res;
1276
1277         /* 
1278          * According to MSDN, this function is only atomic with regards to the 
1279          * other Interlocked functions on 32 bit platforms.
1280          */
1281         mono_interlocked_lock ();
1282         res = *location;
1283         *location = value;
1284         mono_interlocked_unlock ();
1285
1286         return res;
1287 #endif
1288 }
1289
1290 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location, gint32 value, gint32 comparand)
1291 {
1292         MONO_ARCH_SAVE_REGS;
1293
1294         return InterlockedCompareExchange(location, value, comparand);
1295 }
1296
1297 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location, MonoObject *value, MonoObject *comparand)
1298 {
1299         MONO_ARCH_SAVE_REGS;
1300
1301         return (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location, value, comparand);
1302 }
1303
1304 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location, gfloat value, gfloat comparand)
1305 {
1306         IntFloatUnion val, ret, cmp;
1307
1308         MONO_ARCH_SAVE_REGS;
1309
1310         val.fval = value;
1311         cmp.fval = comparand;
1312         ret.ival = InterlockedCompareExchange((gint32 *) location, val.ival, cmp.ival);
1313
1314         return ret.fval;
1315 }
1316
1317 gdouble
1318 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble *location, gdouble value, gdouble comparand)
1319 {
1320 #if SIZEOF_VOID_P == 8
1321         LongDoubleUnion val, comp, ret;
1322
1323         val.fval = value;
1324         comp.fval = comparand;
1325         ret.ival = (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)val.ival, (gpointer)comp.ival);
1326
1327         return ret.fval;
1328 #else
1329         gdouble old;
1330
1331         mono_interlocked_lock ();
1332         old = *location;
1333         if (old == comparand)
1334                 *location = value;
1335         mono_interlocked_unlock ();
1336
1337         return old;
1338 #endif
1339 }
1340
1341 gint64 
1342 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location, gint64 value, gint64 comparand)
1343 {
1344 #if SIZEOF_VOID_P == 8
1345         return (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)value, (gpointer)comparand);
1346 #else
1347         gint64 old;
1348
1349         mono_interlocked_lock ();
1350         old = *location;
1351         if (old == comparand)
1352                 *location = value;
1353         mono_interlocked_unlock ();
1354         
1355         return old;
1356 #endif
1357 }
1358
1359 MonoObject*
1360 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject **location, MonoObject *value, MonoObject *comparand)
1361 {
1362         MONO_ARCH_SAVE_REGS;
1363
1364         return InterlockedCompareExchangePointer ((gpointer *)location, value, comparand);
1365 }
1366
1367 MonoObject*
1368 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject **location, MonoObject *value)
1369 {
1370         MONO_ARCH_SAVE_REGS;
1371
1372         return InterlockedExchangePointer ((gpointer *)location, value);
1373 }
1374
1375 gint32 
1376 ves_icall_System_Threading_Interlocked_Add_Int (gint32 *location, gint32 value)
1377 {
1378 #if SIZEOF_VOID_P == 8
1379         /* Should be implemented as a JIT intrinsic */
1380         mono_raise_exception (mono_get_exception_not_implemented (NULL));
1381         return 0;
1382 #else
1383         gint32 orig;
1384
1385         mono_interlocked_lock ();
1386         orig = *location;
1387         *location = orig + value;
1388         mono_interlocked_unlock ();
1389
1390         return orig;
1391 #endif
1392 }
1393
1394 gint64 
1395 ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location, gint64 value)
1396 {
1397 #if SIZEOF_VOID_P == 8
1398         /* Should be implemented as a JIT intrinsic */
1399         mono_raise_exception (mono_get_exception_not_implemented (NULL));
1400         return 0;
1401 #else
1402         gint64 orig;
1403
1404         mono_interlocked_lock ();
1405         orig = *location;
1406         *location = orig + value;
1407         mono_interlocked_unlock ();
1408
1409         return orig;
1410 #endif
1411 }
1412
1413 gint64 
1414 ves_icall_System_Threading_Interlocked_Read_Long (gint64 *location)
1415 {
1416 #if SIZEOF_VOID_P == 8
1417         /* 64 bit reads are already atomic */
1418         return *location;
1419 #else
1420         gint64 res;
1421
1422         mono_interlocked_lock ();
1423         res = *location;
1424         mono_interlocked_unlock ();
1425
1426         return res;
1427 #endif
1428 }
1429
1430 void
1431 ves_icall_System_Threading_Thread_MemoryBarrier (void)
1432 {
1433         /* Should be implemented as a JIT intrinsic */
1434         mono_raise_exception (mono_get_exception_not_implemented (NULL));
1435 }
1436
1437 void
1438 ves_icall_System_Threading_Thread_ClrState (MonoThread* this, guint32 state)
1439 {
1440         mono_monitor_enter (this->synch_lock);
1441         this->state &= ~state;
1442         if (state & ThreadState_Background) {
1443                 /* If the thread changes the background mode, the main thread has to
1444                  * be notified, since it has to rebuild the list of threads to
1445                  * wait for.
1446                  */
1447                 SetEvent (background_change_event);
1448         }
1449         mono_monitor_exit (this->synch_lock);
1450 }
1451
1452 void
1453 ves_icall_System_Threading_Thread_SetState (MonoThread* this, guint32 state)
1454 {
1455         mono_monitor_enter (this->synch_lock);
1456         this->state |= state;
1457         if (state & ThreadState_Background) {
1458                 /* If the thread changes the background mode, the main thread has to
1459                  * be notified, since it has to rebuild the list of threads to
1460                  * wait for.
1461                  */
1462                 SetEvent (background_change_event);
1463         }
1464         mono_monitor_exit (this->synch_lock);
1465 }
1466
1467 guint32
1468 ves_icall_System_Threading_Thread_GetState (MonoThread* this)
1469 {
1470         guint32 state;
1471         mono_monitor_enter (this->synch_lock);
1472         state = this->state;
1473         mono_monitor_exit (this->synch_lock);
1474         return state;
1475 }
1476
1477 int  
1478 mono_thread_get_abort_signal (void)
1479 {
1480 #if defined (__MINGW32__) || defined (_MSC_VER)
1481         return -1;
1482 #else
1483 #ifndef SIGRTMIN
1484         return SIGUSR1;
1485 #else
1486         static int abort_signum = -1;
1487         int i;
1488         if (abort_signum != -1)
1489                 return abort_signum;
1490         /* we try to avoid SIGRTMIN and any one that might have been set already, see bug #75387 */
1491         for (i = SIGRTMIN + 1; i < SIGRTMAX; ++i) {
1492                 struct sigaction sinfo;
1493                 sigaction (i, NULL, &sinfo);
1494                 if (sinfo.sa_handler == SIG_DFL && (void*)sinfo.sa_sigaction == (void*)SIG_DFL) {
1495                         abort_signum = i;
1496                         return i;
1497                 }
1498         }
1499         /* fallback to the old way */
1500         return SIGRTMIN;
1501 #endif
1502 #endif /*defined (__MINGW32__) || defined (_MSC_VER) */
1503 }
1504
1505 #if defined (__MINGW32__) || defined (_MSC_VER)
1506 static void CALLBACK interruption_request_apc (ULONG_PTR param)
1507 {
1508         MonoException* exc = mono_thread_request_interruption (FALSE);
1509         if (exc) mono_raise_exception (exc);
1510 }
1511 #endif /* defined (__MINGW32__) || defined (_MSC_VER) */
1512
1513 /*
1514  * signal_thread_state_change
1515  *
1516  * Tells the thread that his state has changed and it has to enter the new
1517  * state as soon as possible.
1518  */
1519 static void signal_thread_state_change (MonoThread *thread)
1520 {
1521         if (thread == mono_thread_current ()) {
1522                 /* Do it synchronously */
1523                 MonoException *exc = mono_thread_request_interruption (FALSE); 
1524                 if (exc)
1525                         mono_raise_exception (exc);
1526         }
1527
1528 #if defined (__MINGW32__) || defined (_MSC_VER)
1529         QueueUserAPC ((PAPCFUNC)interruption_request_apc, thread->handle, NULL);
1530 #else
1531         /* fixme: store the state somewhere */
1532 #ifdef PTHREAD_POINTER_ID
1533         pthread_kill ((gpointer)(gsize)(thread->tid), mono_thread_get_abort_signal ());
1534 #else
1535         pthread_kill (thread->tid, mono_thread_get_abort_signal ());
1536 #endif
1537 #endif /* defined (__MINGW32__) || defined (__MSC_VER) */
1538 }
1539
1540 void
1541 ves_icall_System_Threading_Thread_Abort (MonoThread *thread, MonoObject *state)
1542 {
1543         MONO_ARCH_SAVE_REGS;
1544
1545         mono_monitor_enter (thread->synch_lock);
1546
1547         if ((thread->state & ThreadState_AbortRequested) != 0 || 
1548                 (thread->state & ThreadState_StopRequested) != 0 ||
1549                 (thread->state & ThreadState_Stopped) != 0)
1550         {
1551                 mono_monitor_exit (thread->synch_lock);
1552                 return;
1553         }
1554
1555         if ((thread->state & ThreadState_Unstarted) != 0) {
1556                 thread->state |= ThreadState_Aborted;
1557                 mono_monitor_exit (thread->synch_lock);
1558                 return;
1559         }
1560
1561         thread->state |= ThreadState_AbortRequested;
1562         MONO_OBJECT_SETREF (thread, abort_state, state);
1563         thread->abort_exc = NULL;
1564
1565         mono_monitor_exit (thread->synch_lock);
1566
1567         THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Abort requested for %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), thread, (gsize)thread->tid));
1568         
1569         /* Make sure the thread is awake */
1570         mono_thread_resume (thread);
1571         
1572         signal_thread_state_change (thread);
1573 }
1574
1575 void
1576 ves_icall_System_Threading_Thread_ResetAbort (void)
1577 {
1578         MonoThread *thread = mono_thread_current ();
1579
1580         MONO_ARCH_SAVE_REGS;
1581         
1582         mono_monitor_enter (thread->synch_lock);
1583
1584         thread->state &= ~ThreadState_AbortRequested;
1585         
1586         if (!thread->abort_exc) {
1587                 const char *msg = "Unable to reset abort because no abort was requested";
1588                 mono_monitor_exit (thread->synch_lock);
1589                 mono_raise_exception (mono_get_exception_thread_state (msg));
1590         } else {
1591                 thread->abort_exc = NULL;
1592                 thread->abort_state = NULL;
1593         }
1594         
1595         mono_monitor_exit (thread->synch_lock);
1596 }
1597
1598 static gboolean
1599 mono_thread_suspend (MonoThread *thread)
1600 {
1601         MONO_ARCH_SAVE_REGS;
1602
1603         mono_monitor_enter (thread->synch_lock);
1604
1605         if ((thread->state & ThreadState_Unstarted) != 0 || 
1606                 (thread->state & ThreadState_Aborted) != 0 || 
1607                 (thread->state & ThreadState_Stopped) != 0)
1608         {
1609                 mono_monitor_exit (thread->synch_lock);
1610                 return FALSE;
1611         }
1612
1613         if ((thread->state & ThreadState_Suspended) != 0 || 
1614                 (thread->state & ThreadState_SuspendRequested) != 0 ||
1615                 (thread->state & ThreadState_StopRequested) != 0) 
1616         {
1617                 mono_monitor_exit (thread->synch_lock);
1618                 return TRUE;
1619         }
1620         
1621         thread->state |= ThreadState_SuspendRequested;
1622         mono_monitor_exit (thread->synch_lock);
1623
1624         signal_thread_state_change (thread);
1625         return TRUE;
1626 }
1627
1628 void
1629 ves_icall_System_Threading_Thread_Suspend (MonoThread *thread)
1630 {
1631         if (!mono_thread_suspend (thread))
1632                 mono_raise_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
1633 }
1634
1635 static gboolean
1636 mono_thread_resume (MonoThread *thread)
1637 {
1638         MONO_ARCH_SAVE_REGS;
1639
1640         mono_monitor_enter (thread->synch_lock);
1641
1642         if ((thread->state & ThreadState_SuspendRequested) != 0) {
1643                 thread->state &= ~ThreadState_SuspendRequested;
1644                 mono_monitor_exit (thread->synch_lock);
1645                 return TRUE;
1646         }
1647
1648         if ((thread->state & ThreadState_Suspended) == 0 ||
1649                 (thread->state & ThreadState_Unstarted) != 0 || 
1650                 (thread->state & ThreadState_Aborted) != 0 || 
1651                 (thread->state & ThreadState_Stopped) != 0)
1652         {
1653                 mono_monitor_exit (thread->synch_lock);
1654                 return FALSE;
1655         }
1656         
1657         thread->resume_event = CreateEvent (NULL, TRUE, FALSE, NULL);
1658         
1659         /* Awake the thread */
1660         SetEvent (thread->suspend_event);
1661
1662         mono_monitor_exit (thread->synch_lock);
1663
1664         /* Wait for the thread to awake */
1665         WaitForSingleObject (thread->resume_event, INFINITE);
1666         CloseHandle (thread->resume_event);
1667         thread->resume_event = NULL;
1668
1669         return TRUE;
1670 }
1671
1672 void
1673 ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
1674 {
1675         if (!mono_thread_resume (thread))
1676                 mono_raise_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
1677 }
1678
1679 static gboolean
1680 find_wrapper (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
1681 {
1682         if (managed)
1683                 return TRUE;
1684
1685         if (m->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE ||
1686                 m->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE ||
1687                 m->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH) 
1688         {
1689                 *((gboolean*)data) = TRUE;
1690                 return TRUE;
1691         }
1692         return FALSE;
1693 }
1694
1695 static gboolean 
1696 is_running_protected_wrapper (void)
1697 {
1698         gboolean found = FALSE;
1699         mono_stack_walk (find_wrapper, &found);
1700         return found;
1701 }
1702
1703 void mono_thread_stop (MonoThread *thread)
1704 {
1705         mono_monitor_enter (thread->synch_lock);
1706
1707         if ((thread->state & ThreadState_StopRequested) != 0 ||
1708                 (thread->state & ThreadState_Stopped) != 0)
1709         {
1710                 mono_monitor_exit (thread->synch_lock);
1711                 return;
1712         }
1713         
1714         /* Make sure the thread is awake */
1715         mono_thread_resume (thread);
1716
1717         thread->state |= ThreadState_StopRequested;
1718         thread->state &= ~ThreadState_AbortRequested;
1719         
1720         mono_monitor_exit (thread->synch_lock);
1721         
1722         signal_thread_state_change (thread);
1723 }
1724
1725 gint8
1726 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
1727 {
1728         return *((volatile gint8 *) (ptr));
1729 }
1730
1731 gint16
1732 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
1733 {
1734         return *((volatile gint16 *) (ptr));
1735 }
1736
1737 gint32
1738 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
1739 {
1740         return *((volatile gint32 *) (ptr));
1741 }
1742
1743 gint64
1744 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
1745 {
1746         return *((volatile gint64 *) (ptr));
1747 }
1748
1749 void *
1750 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
1751 {
1752         return (void *)  *((volatile void **) ptr);
1753 }
1754
1755 void
1756 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
1757 {
1758         *((volatile gint8 *) ptr) = value;
1759 }
1760
1761 void
1762 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
1763 {
1764         *((volatile gint16 *) ptr) = value;
1765 }
1766
1767 void
1768 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
1769 {
1770         *((volatile gint32 *) ptr) = value;
1771 }
1772
1773 void
1774 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
1775 {
1776         *((volatile gint64 *) ptr) = value;
1777 }
1778
1779 void
1780 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
1781 {
1782         *((volatile void **) ptr) = value;
1783 }
1784
1785 void mono_thread_init (MonoThreadStartCB start_cb,
1786                        MonoThreadAttachCB attach_cb)
1787 {
1788         InitializeCriticalSection(&threads_mutex);
1789         InitializeCriticalSection(&interlocked_mutex);
1790         InitializeCriticalSection(&contexts_mutex);
1791         background_change_event = CreateEvent (NULL, TRUE, FALSE, NULL);
1792         
1793         mono_init_static_data_info (&thread_static_info);
1794         mono_init_static_data_info (&context_static_info);
1795
1796         current_object_key=TlsAlloc();
1797         THREAD_DEBUG (g_message ("%s: Allocated current_object_key %d", __func__, current_object_key));
1798
1799         mono_thread_start_cb = start_cb;
1800         mono_thread_attach_cb = attach_cb;
1801
1802         /* Get a pseudo handle to the current process.  This is just a
1803          * kludge so that wapi can build a process handle if needed.
1804          * As a pseudo handle is returned, we don't need to clean
1805          * anything up.
1806          */
1807         GetCurrentProcess ();
1808 }
1809
1810 void
1811 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
1812 {
1813         mono_thread_cleanup = func;
1814 }
1815
1816 G_GNUC_UNUSED
1817 static void print_tids (gpointer key, gpointer value, gpointer user)
1818 {
1819         /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
1820          * sizeof(uint) and a cast to uint would overflow
1821          */
1822         /* Older versions of glib don't have G_GSIZE_FORMAT, so just
1823          * print this as a pointer.
1824          */
1825         g_message ("Waiting for: %p", key);
1826 }
1827
1828 struct wait_data 
1829 {
1830         HANDLE handles[MAXIMUM_WAIT_OBJECTS];
1831         MonoThread *threads[MAXIMUM_WAIT_OBJECTS];
1832         guint32 num;
1833 };
1834
1835 static void wait_for_tids (struct wait_data *wait, guint32 timeout)
1836 {
1837         guint32 i, ret;
1838         
1839         THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
1840
1841         ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, FALSE);
1842
1843         if(ret==WAIT_FAILED) {
1844                 /* See the comment in build_wait_tids() */
1845                 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
1846                 return;
1847         }
1848         
1849         for(i=0; i<wait->num; i++)
1850                 CloseHandle (wait->handles[i]);
1851
1852         if (ret == WAIT_TIMEOUT)
1853                 return;
1854
1855         for(i=0; i<wait->num; i++) {
1856                 gsize tid = wait->threads[i]->tid;
1857                 
1858                 if(mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
1859                         /* This thread must have been killed, because
1860                          * it hasn't cleaned itself up. (It's just
1861                          * possible that the thread exited before the
1862                          * parent thread had a chance to store the
1863                          * handle, and now there is another pointer to
1864                          * the already-exited thread stored.  In this
1865                          * case, we'll just get two
1866                          * mono_profiler_thread_end() calls for the
1867                          * same thread.)
1868                          */
1869         
1870                         THREAD_DEBUG (g_message ("%s: cleaning up after thread %"G_GSIZE_FORMAT, __func__, tid));
1871                         thread_cleanup (wait->threads[i]);
1872                 }
1873         }
1874 }
1875
1876 static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeout)
1877 {
1878         guint32 i, ret, count;
1879         
1880         THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
1881
1882         /* Add the thread state change event, so it wakes up if a thread changes
1883          * to background mode.
1884          */
1885         count = wait->num;
1886         if (count < MAXIMUM_WAIT_OBJECTS) {
1887                 wait->handles [count] = background_change_event;
1888                 count++;
1889         }
1890
1891         ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, FALSE);
1892
1893         if(ret==WAIT_FAILED) {
1894                 /* See the comment in build_wait_tids() */
1895                 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
1896                 return;
1897         }
1898         
1899         for(i=0; i<wait->num; i++)
1900                 CloseHandle (wait->handles[i]);
1901
1902         if (ret == WAIT_TIMEOUT)
1903                 return;
1904         
1905         if (ret < wait->num) {
1906                 gsize tid = wait->threads[ret]->tid;
1907                 mono_threads_lock ();
1908                 if (mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
1909                         /* See comment in wait_for_tids about thread cleanup */
1910                         mono_threads_unlock ();
1911                         THREAD_DEBUG (g_message ("%s: cleaning up after thread %"G_GSIZE_FORMAT, __func__, tid));
1912                         thread_cleanup (wait->threads [ret]);
1913                 } else
1914                         mono_threads_unlock ();
1915         }
1916 }
1917
1918 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
1919 {
1920         struct wait_data *wait=(struct wait_data *)user;
1921
1922         if(wait->num<MAXIMUM_WAIT_OBJECTS) {
1923                 HANDLE handle;
1924                 MonoThread *thread=(MonoThread *)value;
1925
1926                 /* Ignore background threads, we abort them later */
1927                 mono_monitor_enter (thread->synch_lock);
1928                 if (thread->state & ThreadState_Background) {
1929                         mono_monitor_exit (thread->synch_lock);
1930                         return; /* just leave, ignore */
1931                 }
1932                 mono_monitor_exit (thread->synch_lock);
1933                 
1934                 if (mono_gc_is_finalizer_thread (thread))
1935                         return;
1936
1937                 if (thread == mono_thread_current ())
1938                         return;
1939
1940                 if (thread == mono_thread_get_main ())
1941                         return;
1942
1943                 handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
1944                 if (handle == NULL)
1945                         return;
1946                 
1947                 wait->handles[wait->num]=handle;
1948                 wait->threads[wait->num]=thread;
1949                 wait->num++;
1950         } else {
1951                 /* Just ignore the rest, we can't do anything with
1952                  * them yet
1953                  */
1954         }
1955 }
1956
1957 static gboolean
1958 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
1959 {
1960         struct wait_data *wait=(struct wait_data *)user;
1961         gsize self = GetCurrentThreadId ();
1962         MonoThread *thread = (MonoThread *) value;
1963         HANDLE handle;
1964
1965         if (wait->num >= MAXIMUM_WAIT_OBJECTS)
1966                 return FALSE;
1967
1968         /* The finalizer thread is not a background thread */
1969         if (thread->tid != self && (thread->state & ThreadState_Background) != 0) {
1970         
1971                 handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
1972                 if (handle == NULL)
1973                         return FALSE;
1974                 
1975                 if(thread->state & ThreadState_AbortRequested ||
1976                    thread->state & ThreadState_Aborted) {
1977                         THREAD_DEBUG (g_message ("%s: Thread id %"G_GSIZE_FORMAT" already aborting", __func__, (gsize)thread->tid));
1978                         return(TRUE);
1979                 }
1980
1981                 /* printf ("A: %d\n", wait->num); */
1982                 wait->handles[wait->num]=thread->handle;
1983                 wait->threads[wait->num]=thread;
1984                 wait->num++;
1985
1986                 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
1987                 mono_thread_stop (thread);
1988                 return TRUE;
1989         }
1990
1991         return (thread->tid != self && !mono_gc_is_finalizer_thread (thread)); 
1992 }
1993
1994 void mono_thread_manage (void)
1995 {
1996         struct wait_data *wait=g_new0 (struct wait_data, 1);
1997         
1998         /* join each thread that's still running */
1999         THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
2000         
2001         mono_threads_lock ();
2002         if(threads==NULL) {
2003                 THREAD_DEBUG (g_message("%s: No threads", __func__));
2004                 mono_threads_unlock ();
2005                 return;
2006         }
2007         mono_threads_unlock ();
2008         
2009         do {
2010                 mono_threads_lock ();
2011                 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
2012                         mono_g_hash_table_foreach (threads, print_tids, NULL));
2013         
2014                 ResetEvent (background_change_event);
2015                 wait->num=0;
2016                 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
2017                 mono_threads_unlock ();
2018                 if(wait->num>0) {
2019                         /* Something to wait for */
2020                         wait_for_tids_or_state_change (wait, INFINITE);
2021                 }
2022                 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
2023         } while(wait->num>0);
2024
2025         mono_runtime_set_shutting_down ();
2026
2027         THREAD_DEBUG (g_message ("%s: threadpool cleanup", __func__));
2028         mono_thread_pool_cleanup ();
2029
2030         /* 
2031          * Remove everything but the finalizer thread and self.
2032          * Also abort all the background threads
2033          * */
2034         do {
2035                 mono_threads_lock ();
2036
2037                 wait->num = 0;
2038                 mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
2039
2040                 mono_threads_unlock ();
2041
2042                 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
2043                 if(wait->num>0) {
2044                         /* Something to wait for */
2045                         wait_for_tids (wait, INFINITE);
2046                 }
2047         } while (wait->num > 0);
2048
2049 #if !defined(PLATFORM_WIN32) && !defined(RUN_IN_SUBTHREAD)
2050         /* The main thread must abandon any held mutexes (particularly
2051          * important for named mutexes as they are shared across
2052          * processes, see bug 74680.)  This will happen when the
2053          * thread exits, but if it's not running in a subthread it
2054          * won't exit in time.
2055          */
2056         /* Using non-w32 API is a nasty kludge, but I couldn't find
2057          * anything in the documentation that would let me do this
2058          * here yet still be safe to call on windows.
2059          */
2060         _wapi_thread_abandon_mutexes (GetCurrentThread ());
2061 #endif
2062         
2063         /* 
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().
2067          */
2068 #ifndef PLATFORM_WIN32
2069         sched_yield ();
2070 #endif
2071
2072         g_free (wait);
2073 }
2074
2075 static void terminate_thread (gpointer key, gpointer value, gpointer user)
2076 {
2077         MonoThread *thread=(MonoThread *)value;
2078         
2079         if(thread->tid != (gsize)user) {
2080                 /*TerminateThread (thread->handle, -1);*/
2081         }
2082 }
2083
2084 void mono_thread_abort_all_other_threads (void)
2085 {
2086         gsize self = GetCurrentThreadId ();
2087
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));
2092
2093         mono_g_hash_table_foreach (threads, terminate_thread, (gpointer)self);
2094         
2095         mono_threads_unlock ();
2096 }
2097
2098 static void
2099 collect_threads (gpointer key, gpointer value, gpointer user_data)
2100 {
2101         MonoThread *thread = (MonoThread*)value;
2102         struct wait_data *wait = (struct wait_data*)user_data;
2103         HANDLE handle;
2104
2105         if (wait->num<MAXIMUM_WAIT_OBJECTS) {
2106                 handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
2107                 if (handle == NULL)
2108                         return;
2109
2110                 wait->handles [wait->num] = handle;
2111                 wait->threads [wait->num] = thread;
2112                 wait->num++;
2113         }
2114 }
2115
2116 /*
2117  * mono_thread_suspend_all_other_threads:
2118  *
2119  *  Suspend all managed threads except the finalizer thread and this thread.
2120  */
2121 void mono_thread_suspend_all_other_threads (void)
2122 {
2123         struct wait_data *wait = g_new0 (struct wait_data, 1);
2124         int i, waitnum;
2125         gsize self = GetCurrentThreadId ();
2126         gpointer *events;
2127         guint32 eventidx = 0;
2128
2129         /* 
2130          * Make a copy of the hashtable since we can't do anything with
2131          * threads while threads_mutex is held.
2132          */
2133         mono_threads_lock ();
2134         mono_g_hash_table_foreach (threads, collect_threads, wait);
2135         mono_threads_unlock ();
2136
2137         events = g_new0 (gpointer, wait->num);
2138         waitnum = 0;
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];
2142
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 */
2146                         continue;
2147                 }
2148
2149                 mono_monitor_enter (thread->synch_lock);
2150
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 */
2158                         continue;
2159                 }
2160
2161                 /* Convert abort requests into suspend requests */
2162                 if ((thread->state & ThreadState_AbortRequested) != 0)
2163                         thread->state &= ~ThreadState_AbortRequested;
2164                         
2165                 thread->state |= ThreadState_SuspendRequested;
2166
2167                 if (thread->suspended_event == NULL)
2168                         thread->suspended_event = CreateEvent (NULL, TRUE, FALSE, NULL);
2169
2170                 events [eventidx++] = thread->suspended_event;
2171                 mono_monitor_exit (thread->synch_lock);
2172
2173                 /* Signal the thread to suspend */
2174                 signal_thread_state_change (thread);
2175         }
2176
2177         WaitForMultipleObjectsEx (eventidx, events, TRUE, INFINITE, FALSE);
2178         for (i = 0; i < wait->num; ++i) {
2179                 MonoThread *thread = wait->threads [i];
2180
2181                 if (thread == NULL)
2182                         continue;
2183
2184                 mono_monitor_enter (thread->synch_lock);
2185                 CloseHandle (thread->suspended_event);
2186                 thread->suspended_event = NULL;
2187                 mono_monitor_exit (thread->synch_lock);
2188         }
2189
2190         g_free (events);
2191         g_free (wait);
2192 }
2193
2194 /**
2195  * mono_threads_request_thread_dump:
2196  *
2197  *   Ask all threads except the current to print their stacktrace to stdout.
2198  */
2199 void
2200 mono_threads_request_thread_dump (void)
2201 {
2202         struct wait_data *wait = g_new0 (struct wait_data, 1);
2203         int i;
2204
2205         /* 
2206          * Make a copy of the hashtable since we can't do anything with
2207          * threads while threads_mutex is held.
2208          */
2209         mono_threads_lock ();
2210         mono_g_hash_table_foreach (threads, collect_threads, wait);
2211         mono_threads_unlock ();
2212
2213         for (i = 0; i < wait->num; ++i) {
2214                 MonoThread *thread = wait->threads [i];
2215
2216                 if (!mono_gc_is_finalizer_thread (thread) && (thread != mono_thread_current ()) && !thread->thread_dump_requested) {
2217                         thread->thread_dump_requested = TRUE;
2218
2219                         signal_thread_state_change (thread);
2220                 }
2221
2222                 CloseHandle (wait->handles [i]);
2223         }
2224 }
2225
2226 /*
2227  * mono_thread_push_appdomain_ref:
2228  *
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.
2232  */
2233 void 
2234 mono_thread_push_appdomain_ref (MonoDomain *domain)
2235 {
2236         MonoThread *thread = mono_thread_current ();
2237
2238         if (thread) {
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 ();
2243         }
2244 }
2245
2246 void
2247 mono_thread_pop_appdomain_ref (void)
2248 {
2249         MonoThread *thread = mono_thread_current ();
2250
2251         if (thread) {
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 ();
2258         }
2259 }
2260
2261 gboolean
2262 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
2263 {
2264         gboolean res;
2265         mono_threads_lock ();
2266         res = g_slist_find (thread->appdomain_refs, domain) != NULL;
2267         mono_threads_unlock ();
2268         return res;
2269 }
2270
2271 typedef struct abort_appdomain_data {
2272         struct wait_data wait;
2273         MonoDomain *domain;
2274 } abort_appdomain_data;
2275
2276 static void
2277 abort_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
2278 {
2279         MonoThread *thread = (MonoThread*)value;
2280         abort_appdomain_data *data = (abort_appdomain_data*)user_data;
2281         MonoDomain *domain = data->domain;
2282
2283         if (mono_thread_has_appdomain_ref (thread, domain)) {
2284                 HANDLE handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
2285                 if (handle == NULL)
2286                         return;
2287
2288                 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
2289
2290                 ves_icall_System_Threading_Thread_Abort (thread, NULL);
2291
2292                 if(data->wait.num<MAXIMUM_WAIT_OBJECTS) {
2293                         data->wait.handles [data->wait.num] = handle;
2294                         data->wait.threads [data->wait.num] = thread;
2295                         data->wait.num++;
2296                 } else {
2297                         /* Just ignore the rest, we can't do anything with
2298                          * them yet
2299                          */
2300                 }
2301         }
2302 }
2303
2304 /*
2305  * mono_threads_abort_appdomain_threads:
2306  *
2307  *   Abort threads which has references to the given appdomain.
2308  */
2309 gboolean
2310 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
2311 {
2312         abort_appdomain_data user_data;
2313         guint32 start_time;
2314
2315         /* printf ("ABORT BEGIN.\n"); */
2316
2317         start_time = GetTickCount ();
2318         do {
2319                 mono_threads_lock ();
2320
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 ();
2325
2326                 if (user_data.wait.num > 0)
2327                         /*
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.
2330                          */
2331                         wait_for_tids (&user_data.wait, 100);
2332
2333                 /* Update remaining time */
2334                 timeout -= GetTickCount () - start_time;
2335                 start_time = GetTickCount ();
2336
2337                 if (timeout < 0)
2338                         return FALSE;
2339         }
2340         while (user_data.wait.num > 0);
2341
2342         /* printf ("ABORT DONE.\n"); */
2343
2344         return TRUE;
2345 }
2346
2347 static void
2348 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
2349 {
2350         MonoThread *thread = (MonoThread*)value;
2351         MonoDomain *domain = (MonoDomain*)user_data;
2352         int i;
2353
2354         /* No locking needed here */
2355         /* FIXME: why no locking? writes to the cache are protected with synch_lock above */
2356
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);
2362                 }
2363         }
2364 }
2365         
2366 /*
2367  * mono_threads_clear_cached_culture:
2368  *
2369  *   Clear the cached_current_culture from all threads if it is in the
2370  * given appdomain.
2371  */
2372 void
2373 mono_threads_clear_cached_culture (MonoDomain *domain)
2374 {
2375         mono_threads_lock ();
2376         mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
2377         mono_threads_unlock ();
2378 }
2379
2380 /*
2381  * mono_thread_get_pending_exception:
2382  *
2383  *   Return an exception which needs to be raised when leaving a catch clause.
2384  * This is used for undeniable exception propagation.
2385  */
2386 MonoException*
2387 mono_thread_get_pending_exception (void)
2388 {
2389         MonoThread *thread = mono_thread_current ();
2390
2391         MONO_ARCH_SAVE_REGS;
2392
2393         if (thread && thread->abort_exc && !is_running_protected_wrapper ()) {
2394                 /*
2395                  * FIXME: Clear the abort exception and return an AppDomainUnloaded 
2396                  * exception if the thread no longer references a dying appdomain.
2397                  */
2398                 thread->abort_exc->trace_ips = NULL;
2399                 thread->abort_exc->stack_trace = NULL;
2400                 return thread->abort_exc;
2401         }
2402
2403         return NULL;
2404 }
2405
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
2409 };
2410
2411
2412 /*
2413  *  mono_alloc_static_data
2414  *
2415  *   Allocate memory blocks for storing threads or context static data
2416  */
2417 static void 
2418 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset)
2419 {
2420         guint idx = (offset >> 24) - 1;
2421         int i;
2422
2423         gpointer* static_data = *static_data_ptr;
2424         if (!static_data) {
2425                 static_data = mono_gc_alloc_fixed (static_data_size [0], NULL);
2426                 *static_data_ptr = static_data;
2427                 static_data [0] = static_data;
2428         }
2429
2430         for (i = 1; i <= idx; ++i) {
2431                 if (static_data [i])
2432                         continue;
2433                 static_data [i] = mono_gc_alloc_fixed (static_data_size [i], NULL);
2434         }
2435 }
2436
2437 /*
2438  *  mono_init_static_data_info
2439  *
2440  *   Initializes static data counters
2441  */
2442 static void mono_init_static_data_info (StaticDataInfo *static_data)
2443 {
2444         static_data->idx = 0;
2445         static_data->offset = 0;
2446 }
2447
2448 /*
2449  *  mono_alloc_static_data_slot
2450  *
2451  *   Generates an offset for static data. static_data contains the counters
2452  *  used to generate it.
2453  */
2454 static guint32
2455 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
2456 {
2457         guint32 offset;
2458
2459         if (!static_data->idx && !static_data->offset) {
2460                 /* 
2461                  * we use the first chunk of the first allocation also as
2462                  * an array for the rest of the data 
2463                  */
2464                 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
2465         }
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]);
2471                 /* 
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.
2479                  */
2480                 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
2481                 static_data->offset = 0;
2482         }
2483         offset = static_data->offset | ((static_data->idx + 1) << 24);
2484         static_data->offset += size;
2485         return offset;
2486 }
2487
2488 /* 
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.
2491  */
2492 static void
2493 thread_adjust_static_data (MonoThread *thread)
2494 {
2495         guint32 offset;
2496
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);
2502         }
2503         mono_threads_unlock ();
2504 }
2505
2506 static void 
2507 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
2508 {
2509         MonoThread *thread = value;
2510         guint32 offset = GPOINTER_TO_UINT (user);
2511         
2512         mono_alloc_static_data (&(thread->static_data), offset);
2513 }
2514
2515 /*
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 
2520  * common case.
2521  */
2522
2523 guint32
2524 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align)
2525 {
2526         guint32 offset;
2527         if (static_type == SPECIAL_STATIC_THREAD)
2528         {
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 ();
2535         }
2536         else
2537         {
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 */
2543         }
2544         return offset;
2545 }
2546
2547 gpointer
2548 mono_get_special_static_data (guint32 offset)
2549 {
2550         /* The high bit means either thread (0) or static (1) data. */
2551
2552         guint32 static_type = (offset & 0x80000000);
2553         int idx;
2554
2555         offset &= 0x7fffffff;
2556         idx = (offset >> 24) - 1;
2557
2558         if (static_type == 0)
2559         {
2560                 MonoThread *thread = mono_thread_current ();
2561                 return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
2562         }
2563         else
2564         {
2565                 /* Allocate static data block under demand, since we don't have a list
2566                 // of contexts
2567                 */
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 ();
2573                 }
2574                 return ((char*) context->static_data [idx]) + (offset & 0xffffff);      
2575         }
2576 }
2577
2578 static MonoClassField *local_slots = NULL;
2579
2580 typedef struct {
2581         /* local tls data to get locals_slot from a thread */
2582         guint32 offset;
2583         int idx;
2584         /* index in the locals_slot array */
2585         int slot;
2586 } LocalSlotID;
2587
2588 static void
2589 clear_local_slot (gpointer key, gpointer value, gpointer user_data)
2590 {
2591         LocalSlotID *sid = user_data;
2592         MonoThread *thread = (MonoThread*)value;
2593         MonoArray *slots_array;
2594         /*
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.
2598          */
2599         /*g_print ("handling thread %p\n", thread);*/
2600         if (!thread->static_data || !thread->static_data [sid->idx])
2601                 return;
2602         slots_array = *(MonoArray **)(((char*) thread->static_data [sid->idx]) + (sid->offset & 0xffffff));
2603         if (!slots_array || sid->slot >= mono_array_length (slots_array))
2604                 return;
2605         mono_array_set (slots_array, MonoObject*, sid->slot, NULL);
2606 }
2607
2608 void
2609 mono_thread_free_local_slot_values (int slot, MonoBoolean thread_local)
2610 {
2611         MonoDomain *domain;
2612         LocalSlotID sid;
2613         sid.slot = slot;
2614         if (thread_local) {
2615                 void *addr = NULL;
2616                 if (!local_slots) {
2617                         local_slots = mono_class_get_field_from_name (mono_defaults.thread_class, "local_slots");
2618                         if (!local_slots) {
2619                                 g_warning ("local_slots field not found in Thread class");
2620                                 return;
2621                         }
2622                 }
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);
2628                 if (!addr)
2629                         return;
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 ();
2637         } else {
2638                 /* FIXME: clear the slot for MonoAppContexts, too */
2639         }
2640 }
2641
2642 #ifdef __MINGW32__
2643 static CALLBACK void dummy_apc (ULONG_PTR param)
2644 {
2645 }
2646 #else
2647 static guint32 dummy_apc (gpointer param)
2648 {
2649         return 0;
2650 }
2651 #endif
2652
2653 /*
2654  * mono_thread_execute_interruption
2655  * 
2656  * Performs the operation that the requested thread state requires (abort,
2657  * suspend or stop)
2658  */
2659 static MonoException* mono_thread_execute_interruption (MonoThread *thread)
2660 {
2661         mono_monitor_enter (thread->synch_lock);
2662
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;
2668         }
2669
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;
2675         }
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);
2683                 
2684                 WaitForSingleObject (thread->suspend_event, INFINITE);
2685                 
2686                 mono_monitor_enter (thread->synch_lock);
2687                 CloseHandle (thread->suspend_event);
2688                 thread->suspend_event = NULL;
2689                 thread->state &= ~ThreadState_Suspended;
2690         
2691                 /* The thread that requested the resume will have replaced this event
2692                  * and will be waiting for it
2693                  */
2694                 SetEvent (thread->resume_event);
2695                 mono_monitor_exit (thread->synch_lock);
2696                 return NULL;
2697         }
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 ();
2702                 return NULL;
2703         }
2704         
2705         mono_monitor_exit (thread->synch_lock);
2706         return NULL;
2707 }
2708
2709 /*
2710  * mono_thread_request_interruption
2711  *
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.
2716  */
2717 MonoException* mono_thread_request_interruption (gboolean running_managed)
2718 {
2719         MonoThread *thread = mono_thread_current ();
2720
2721         /* The thread may already be stopping */
2722         if (thread == NULL) 
2723                 return NULL;
2724         
2725         mono_monitor_enter (thread->synch_lock);
2726         
2727         if (thread->interruption_requested) {
2728                 mono_monitor_exit (thread->synch_lock);
2729                 return NULL;
2730         }
2731
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. */
2736
2737                 InterlockedIncrement (&thread_interruption_requested);
2738                 thread->interruption_requested = TRUE;
2739                 mono_monitor_exit (thread->synch_lock);
2740
2741                 /* this will awake the thread if it is in WaitForSingleObject 
2742                    or similar */
2743                 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, NULL);
2744                 return NULL;
2745         }
2746         else {
2747                 mono_monitor_exit (thread->synch_lock);
2748                 return mono_thread_execute_interruption (thread);
2749         }
2750 }
2751
2752 gboolean mono_thread_interruption_requested ()
2753 {
2754         if (thread_interruption_requested) {
2755                 MonoThread *thread = mono_thread_current ();
2756                 /* The thread may already be stopping */
2757                 if (thread != NULL) 
2758                         return (thread->interruption_requested);
2759         }
2760         return FALSE;
2761 }
2762
2763 static void mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
2764 {
2765         MonoThread *thread = mono_thread_current ();
2766
2767         /* The thread may already be stopping */
2768         if (thread == NULL)
2769                 return;
2770
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);
2774         }
2775 }
2776
2777 /*
2778  * Performs the interruption of the current thread, if one has been requested,
2779  * and the thread is not running a protected wrapper.
2780  */
2781 void mono_thread_interruption_checkpoint ()
2782 {
2783         mono_thread_interruption_checkpoint_request (FALSE);
2784 }
2785
2786 /*
2787  * Performs the interruption of the current thread, if one has been requested.
2788  */
2789 void mono_thread_force_interruption_checkpoint ()
2790 {
2791         mono_thread_interruption_checkpoint_request (TRUE);
2792 }
2793
2794 /**
2795  * mono_thread_interruption_request_flag:
2796  *
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
2801  * zero.
2802  */
2803 gint32* mono_thread_interruption_request_flag ()
2804 {
2805         return &thread_interruption_requested;
2806 }
2807
2808 #if MONO_DEBUGGER_SUPPORTED
2809
2810 extern void GC_push_all_stack (gpointer b, gpointer t);
2811
2812 static void
2813 debugger_gc_push_stack (gpointer key, gpointer value, gpointer user)
2814 {
2815         MonoThread *thread = (MonoThread*)value;
2816         gpointer end_stack;
2817
2818         /*
2819          * The debugger stops all other threads for us in debugger_gc_stop_world() and
2820          * then sets `thread->end_stack' for each of them.
2821          */
2822
2823         end_stack = (thread->tid == GetCurrentThreadId ()) ? &key : thread->end_stack;
2824
2825         if (!end_stack || !thread->stack_ptr) {
2826                 g_warning (G_STRLOC ": Cannot push stack of thread %Lx", thread->tid);
2827                 return;
2828         }
2829
2830         GC_push_all_stack (end_stack, thread->stack_ptr);
2831 }
2832
2833 /*
2834  * We're called with the thread lock.
2835  */
2836 static void
2837 debugger_gc_push_all_stacks (void)
2838 {
2839         if (threads != NULL)
2840                 mono_g_hash_table_foreach (threads, debugger_gc_push_stack, NULL);
2841 }
2842
2843 static void
2844 debugger_gc_stop_world (void)
2845 {
2846         /*
2847          * Acquire the thread lock and tell the debugger to stop all other threads.
2848          */
2849         mono_threads_lock ();
2850         mono_debugger_event (
2851                 MONO_DEBUGGER_EVENT_ACQUIRE_GLOBAL_THREAD_LOCK, 0, 0);
2852 }
2853
2854 static void
2855 debugger_gc_start_world (void)
2856 {
2857         /*
2858          * Tell the debugger to resume all other threads and release the lock.
2859          */
2860         mono_debugger_event (
2861                 MONO_DEBUGGER_EVENT_RELEASE_GLOBAL_THREAD_LOCK, 0, 0);
2862         mono_threads_unlock ();
2863 }
2864
2865 static void
2866 debugger_gc_init (void)
2867 { }
2868
2869 static GCThreadFunctions debugger_thread_vtable = {
2870         debugger_gc_init,
2871
2872         debugger_gc_stop_world,
2873         debugger_gc_push_all_stacks,
2874         debugger_gc_start_world
2875 };
2876
2877 static GCThreadFunctions *old_gc_thread_vtable = NULL;
2878
2879 /**
2880  * mono_debugger_init_threads:
2881  *
2882  * This is used when running inside the Mono Debugger.
2883  */
2884 void
2885 mono_debugger_init_threads (void)
2886 {
2887         old_gc_thread_vtable = gc_thread_vtable;
2888         gc_thread_vtable = &debugger_thread_vtable;
2889         debugger_thread_created (mono_thread_current ());
2890 }
2891
2892 /**
2893  * mono_debugger_finalize_threads:
2894  *
2895  * This is used when running inside the Mono Debugger.
2896  * Undo the effects of mono_debugger_init_threads(); this is called
2897  * prior to detaching from a process.
2898  */
2899 void
2900 mono_debugger_finalize_threads (void)
2901 {
2902         gc_thread_vtable = old_gc_thread_vtable;
2903 }
2904
2905 #else /* WITH_INCLUDED_LIBGC */
2906
2907 void
2908 mono_debugger_init_threads (void)
2909 {
2910         g_assert_not_reached ();
2911 }
2912
2913 void
2914 mono_debugger_finalize_threads (void)
2915 {
2916         g_assert_not_reached ();
2917 }
2918
2919 #endif