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