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