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