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