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