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