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