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