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