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