d74cf95227473f46d77dac88cee685e0595ecfa1
[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
35 #include <mono/os/gc_wrapper.h>
36
37 /*#define THREAD_DEBUG(a) do { a; } while (0)*/
38 #define THREAD_DEBUG(a)
39 /*#define THREAD_WAIT_DEBUG(a) do { a; } while (0)*/
40 #define THREAD_WAIT_DEBUG(a)
41 /*#define LIBGC_DEBUG(a) do { a; } while (0)*/
42 #define LIBGC_DEBUG(a)
43
44 struct StartInfo 
45 {
46         guint32 (*func)(void *);
47         MonoThread *obj;
48         MonoObject *delegate;
49         void *start_arg;
50         MonoDomain *domain;
51 };
52
53 typedef union {
54         gint32 ival;
55         gfloat fval;
56 } IntFloatUnion;
57
58 typedef union {
59         gint64 ival;
60         gdouble fval;
61 } LongDoubleUnion;
62  
63 typedef struct {
64         int idx;
65         int offset;
66 } StaticDataInfo;
67
68 /* Number of cached culture objects in the MonoThread->culture_info array */
69 #define NUM_CACHED_CULTURES 4
70
71 /*
72  * The "os_handle" field of the WaitHandle class.
73  */
74 static MonoClassField *wait_handle_os_handle_field = NULL;
75
76 /* Controls access to the 'threads' hash table */
77 static CRITICAL_SECTION threads_mutex;
78
79 /* Controls access to context static data */
80 static CRITICAL_SECTION contexts_mutex;
81
82 /* Holds current status of static data heap */
83 static StaticDataInfo thread_static_info;
84 static StaticDataInfo context_static_info;
85
86 /* The hash of existing threads (key is thread ID) that need joining
87  * before exit
88  */
89 static MonoGHashTable *threads=NULL;
90
91 /* The TLS key that holds the MonoObject assigned to each thread */
92 static guint32 current_object_key = -1;
93
94 #ifdef HAVE_KW_THREAD
95 /* we need to use both the Tls* functions and __thread because
96  * the gc needs to see all the threads 
97  */
98 static __thread MonoThread * tls_current_object;
99 #define SET_CURRENT_OBJECT(x) do { \
100         tls_current_object = x; \
101         TlsSetValue (current_object_key, x); \
102 } while (FALSE)
103 #define GET_CURRENT_OBJECT() tls_current_object
104 #else
105 #define SET_CURRENT_OBJECT(x) TlsSetValue (current_object_key, x);
106 #define GET_CURRENT_OBJECT() (MonoThread*) TlsGetValue (current_object_key);
107 #endif
108
109 /* function called at thread start */
110 static MonoThreadStartCB mono_thread_start_cb = NULL;
111
112 /* function called at thread attach */
113 static MonoThreadAttachCB mono_thread_attach_cb = NULL;
114
115 /* function called at thread cleanup */
116 static MonoThreadCleanupFunc mono_thread_cleanup = NULL;
117
118 /* function called when a new thread has been created */
119 static MonoThreadCallbacks *mono_thread_callbacks = NULL;
120
121 /* The TLS key that holds the LocalDataStoreSlot hash in each thread */
122 static guint32 slothash_key = -1;
123
124 /* The default stack size for each thread */
125 static guint32 default_stacksize = 0;
126 #define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize)
127
128 static void thread_adjust_static_data (MonoThread *thread);
129 static void mono_init_static_data_info (StaticDataInfo *static_data);
130 static guint32 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align);
131
132 /* Spin lock for InterlockedXXX 64 bit functions */
133 static CRITICAL_SECTION interlocked_mutex;
134
135 /* Controls access to interruption flag */
136 static CRITICAL_SECTION interruption_mutex;
137
138 /* global count of thread interruptions requested */
139 static gint32 thread_interruption_requested = 0;
140
141 guint32
142 mono_thread_get_tls_key (void)
143 {
144         return current_object_key;
145 }
146
147 /* handle_store() and handle_remove() manage the array of threads that
148  * still need to be waited for when the main thread exits.
149  */
150 static void handle_store(MonoThread *thread)
151 {
152         EnterCriticalSection(&threads_mutex);
153
154         THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": thread %p ID %d", thread, thread->tid));
155
156         if(threads==NULL) {
157                 MONO_GC_REGISTER_ROOT (threads);
158                 threads=mono_g_hash_table_new(NULL, NULL);
159         }
160
161         /* We don't need to duplicate thread->handle, because it is
162          * only closed when the thread object is finalized by the GC.
163          */
164         mono_g_hash_table_insert(threads, GUINT_TO_POINTER(thread->tid), thread);
165         LeaveCriticalSection(&threads_mutex);
166 }
167
168 static void handle_remove(guint32 tid)
169 {
170         THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": thread ID %d", tid));
171
172         EnterCriticalSection(&threads_mutex);
173
174         if (threads)
175                 mono_g_hash_table_remove (threads, GUINT_TO_POINTER(tid));
176         
177         LeaveCriticalSection(&threads_mutex);
178
179         /* Don't close the handle here, wait for the object finalizer
180          * to do it. Otherwise, the following race condition applies:
181          *
182          * 1) Thread exits (and handle_remove() closes the handle)
183          *
184          * 2) Some other handle is reassigned the same slot
185          *
186          * 3) Another thread tries to join the first thread, and
187          * blocks waiting for the reassigned handle to be signalled
188          * (which might never happen).  This is possible, because the
189          * thread calling Join() still has a reference to the first
190          * thread's object.
191          */
192 }
193
194 static void thread_cleanup (MonoThread *thread)
195 {
196         mono_release_type_locks (thread);
197
198         if (!mono_monitor_enter (thread->synch_lock))
199                 return;
200
201         thread->state |= ThreadState_Stopped;
202         mono_monitor_exit (thread->synch_lock);
203
204         mono_profiler_thread_end (thread->tid);
205         handle_remove (thread->tid);
206
207         mono_thread_pop_appdomain_ref ();
208
209         if (thread->serialized_culture_info)
210                 g_free (thread->serialized_culture_info);
211
212         mono_gc_free_fixed (thread->culture_info);
213         mono_gc_free_fixed (thread->ui_culture_info);
214
215         if (mono_thread_cleanup)
216                 mono_thread_cleanup (thread);
217 }
218
219 static guint32 start_wrapper(void *data)
220 {
221         struct StartInfo *start_info=(struct StartInfo *)data;
222         guint32 (*start_func)(void *);
223         void *start_arg;
224         guint32 tid;
225         MonoThread *thread=start_info->obj;
226         MonoObject *start_delegate = start_info->delegate;
227
228         THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": (%d) Start wrapper", GetCurrentThreadId ()));
229         
230         /* We can be sure start_info->obj->tid and
231          * start_info->obj->handle have been set, because the thread
232          * was created suspended, and these values were set before the
233          * thread resumed
234          */
235
236         tid=thread->tid;
237
238         SET_CURRENT_OBJECT (thread);
239         
240         if (!mono_domain_set (start_info->domain, FALSE)) {
241                 /* No point in raising an appdomain_unloaded exception here */
242                 /* FIXME: Cleanup here */
243                 return 0;
244         }
245
246         start_func = start_info->func;
247         start_arg = start_info->start_arg;
248
249         /* This MUST be called before any managed code can be
250          * executed, as it calls the callback function that (for the
251          * jit) sets the lmf marker.
252          */
253         mono_thread_new_init (tid, &tid, start_func);
254         thread->stack_ptr = &tid;
255
256         LIBGC_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION
257                    ": (%d,%d) Setting thread stack to %p",
258                    GetCurrentThreadId (), getpid (), thread->stack_ptr));
259
260         THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION
261                    ": (%d) Setting current_object_key to %p",
262                    GetCurrentThreadId (), thread));
263
264         mono_profiler_thread_start (tid);
265
266         if(thread->start_notify!=NULL) {
267                 /* Let the thread that called Start() know we're
268                  * ready
269                  */
270                 ReleaseSemaphore (thread->start_notify, 1, NULL);
271         }
272         
273         g_free (start_info);
274
275         /* Every thread references the appdomain which created it */
276         mono_thread_push_appdomain_ref (mono_domain_get ());
277
278         thread_adjust_static_data (thread);
279 #ifdef DEBUG
280         g_message (G_GNUC_PRETTY_FUNCTION "start_wrapper for %d\n", thread->tid);
281 #endif
282
283         /* start_func is set only for unamanged start functions */
284         if (start_func) {
285                 start_func (start_arg);
286         } else {
287                 void *args [1];
288                 g_assert (start_delegate != NULL);
289                 args [0] = start_arg;
290                 /* we may want to handle the exception here. See comment below on unhandled exceptions */
291                 mono_runtime_delegate_invoke (start_delegate, args, NULL);
292         }
293
294         /* If the thread calls ExitThread at all, this remaining code
295          * will not be executed, but the main thread will eventually
296          * call thread_cleanup() on this thread's behalf.
297          */
298
299         THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": (%d) Start wrapper terminating",
300                   GetCurrentThreadId ()));
301
302         /* Remove the reference to the thread object in the TLS data,
303          * so the thread object can be finalized.  This won't be
304          * reached if the thread threw an uncaught exception, so those
305          * thread handles will stay referenced :-( (This is due to
306          * missing support for scanning thread-specific data in the
307          * Boehm GC - the io-layer keeps a GC-visible hash of pointers
308          * to TLS data.)
309          */
310         SET_CURRENT_OBJECT (NULL);
311
312         thread_cleanup (thread);
313
314         return(0);
315 }
316
317 void mono_thread_new_init (guint32 tid, gpointer stack_start, gpointer func)
318 {
319         if (mono_thread_start_cb) {
320                 mono_thread_start_cb (tid, stack_start, func);
321         }
322
323         if (mono_thread_callbacks)
324                 (* mono_thread_callbacks->thread_created) (tid, stack_start, func);
325 }
326
327 void mono_threads_set_default_stacksize (guint32 stacksize)
328 {
329         default_stacksize = stacksize;
330 }
331
332 guint32 mono_threads_get_default_stacksize (void)
333 {
334         return default_stacksize;
335 }
336
337 void mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
338 {
339         MonoThread *thread;
340         HANDLE thread_handle;
341         struct StartInfo *start_info;
342         guint32 tid;
343         
344         thread=(MonoThread *)mono_object_new (domain,
345                                               mono_defaults.thread_class);
346
347         start_info=g_new0 (struct StartInfo, 1);
348         start_info->func = func;
349         start_info->obj = thread;
350         start_info->domain = domain;
351         start_info->start_arg = arg;
352         
353         /* Create suspended, so we can do some housekeeping before the thread
354          * starts
355          */
356         thread_handle = CreateThread(NULL, default_stacksize_for_thread (thread), start_wrapper, start_info,
357                                      CREATE_SUSPENDED, &tid);
358         THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": Started thread ID %d (handle %p)",
359                   tid, thread_handle));
360         g_assert (thread_handle);
361
362         thread->handle=thread_handle;
363         thread->tid=tid;
364
365         thread->synch_lock=mono_object_new (domain, mono_defaults.object_class);
366                                                   
367         handle_store(thread);
368
369         ResumeThread (thread_handle);
370 }
371
372 MonoThread *
373 mono_thread_attach (MonoDomain *domain)
374 {
375         MonoThread *thread;
376         HANDLE thread_handle;
377         guint32 tid;
378
379         if ((thread = mono_thread_current ())) {
380                 /* Already attached */
381                 return thread;
382         }
383
384         thread = (MonoThread *)mono_object_new (domain,
385                                                 mono_defaults.thread_class);
386
387         thread_handle = GetCurrentThread ();
388         g_assert (thread_handle);
389
390         tid=GetCurrentThreadId ();
391
392 #ifdef PLATFORM_WIN32
393         /* 
394          * The handle returned by GetCurrentThread () is a pseudo handle, so it can't be used to
395          * refer to the thread from other threads for things like aborting.
396          */
397         DuplicateHandle (GetCurrentProcess (), thread_handle, GetCurrentProcess (), &thread_handle, 
398                                          THREAD_ALL_ACCESS, TRUE, 0);
399 #endif
400
401         thread->handle=thread_handle;
402         thread->tid=tid;
403         thread->synch_lock=mono_object_new (domain, mono_defaults.object_class);
404
405         THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": Attached thread ID %d (handle %p)",
406                   tid, thread_handle));
407
408         handle_store(thread);
409
410         THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": (%d) Setting current_object_key to %p",
411                    GetCurrentThreadId (), thread));
412
413         SET_CURRENT_OBJECT (thread);
414         mono_domain_set (domain, TRUE);
415
416         thread_adjust_static_data (thread);
417
418         if (mono_thread_attach_cb) {
419                 mono_thread_attach_cb (tid, &tid);
420         }
421
422         return(thread);
423 }
424
425 void
426 mono_thread_detach (MonoThread *thread)
427 {
428         g_return_if_fail (thread != NULL);
429
430         THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION "mono_thread_detach for %d\n", thread->tid));
431         SET_CURRENT_OBJECT (NULL);
432         
433         thread_cleanup (thread);
434 }
435
436 void
437 mono_thread_exit ()
438 {
439         MonoThread *thread = mono_thread_current ();
440
441         SET_CURRENT_OBJECT (NULL);
442         thread_cleanup (thread);
443
444         /* we could add a callback here for embedders to use. */
445         if (thread == mono_thread_get_main ())
446                 exit (mono_environment_exitcode_get ());
447         ExitThread (-1);
448 }
449
450 HANDLE ves_icall_System_Threading_Thread_Thread_internal(MonoThread *this,
451                                                          MonoObject *start)
452 {
453         guint32 (*start_func)(void *);
454         struct StartInfo *start_info;
455         MonoMethod *im;
456         HANDLE thread;
457         guint32 tid;
458         
459         MONO_ARCH_SAVE_REGS;
460
461         THREAD_DEBUG (g_message(G_GNUC_PRETTY_FUNCTION
462                   ": Trying to start a new thread: this (%p) start (%p)", this, start));
463
464 /* FIXME: remove the code inside BROKEN_THREAD_START once martin gets rid of the
465  * thread_start_compile_func stuff.
466  */
467 #define BROKEN_THREAD_START
468 #ifdef BROKEN_THREAD_START
469         im = mono_get_delegate_invoke (start->vtable->klass);
470         im = mono_marshal_get_delegate_invoke (im);
471         if (mono_thread_callbacks)
472                 start_func = (* mono_thread_callbacks->thread_start_compile_func) (im);
473         else
474                 start_func = mono_compile_method (im);
475
476         if(start_func==NULL) {
477                 g_warning(G_GNUC_PRETTY_FUNCTION
478                           ": Can't locate start method!");
479                 return(NULL);
480         } else {
481 #else
482         start_func = NULL;
483         {
484 #endif
485                 /* This is freed in start_wrapper */
486                 start_info = g_new0 (struct StartInfo, 1);
487                 start_info->func = start_func;
488 #ifdef BROKEN_THREAD_START
489                 start_info->start_arg = start;
490 #else
491                 start_info->start_arg = this->start_obj;
492 #endif
493                 start_info->delegate = start;
494                 start_info->obj = this;
495                 start_info->domain = mono_domain_get ();
496
497                 this->start_notify=CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
498                 if(this->start_notify==NULL) {
499                         g_warning (G_GNUC_PRETTY_FUNCTION ": CreateSemaphore error 0x%x", GetLastError ());
500                         return(NULL);
501                 }
502
503                 thread=CreateThread(NULL, default_stacksize_for_thread (this), start_wrapper, start_info,
504                                     CREATE_SUSPENDED, &tid);
505                 if(thread==NULL) {
506                         g_warning(G_GNUC_PRETTY_FUNCTION
507                                   ": CreateThread error 0x%x", GetLastError());
508                         return(NULL);
509                 }
510                 
511                 this->handle=thread;
512                 this->tid=tid;
513
514                 /* Don't call handle_store() here, delay it to Start.
515                  * We can't join a thread (trying to will just block
516                  * forever) until it actually starts running, so don't
517                  * store the handle till then.
518                  */
519
520                 THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION
521                           ": Started thread ID %d (handle %p)", tid, thread));
522
523                 return(thread);
524         }
525 }
526
527 void ves_icall_System_Threading_Thread_Thread_free_internal (MonoThread *this,
528                                                              HANDLE thread)
529 {
530         MONO_ARCH_SAVE_REGS;
531
532         THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": Closing thread %p, handle %p",
533                    this, thread));
534
535         CloseHandle (thread);
536 }
537
538 void ves_icall_System_Threading_Thread_Start_internal(MonoThread *this,
539                                                       HANDLE thread)
540 {
541         MONO_ARCH_SAVE_REGS;
542
543         THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": (%d) Launching thread %p (%d)",
544                   GetCurrentThreadId (), this, this->tid));
545
546         /* Only store the handle when the thread is about to be
547          * launched, to avoid the main thread deadlocking while trying
548          * to clean up a thread that will never be signalled.
549          */
550         handle_store(this);
551
552         if (mono_thread_callbacks)
553                 (* mono_thread_callbacks->start_resume) (this->tid);
554
555         ResumeThread(thread);
556
557         if (mono_thread_callbacks)
558                 (* mono_thread_callbacks->end_resume) (this->tid);
559
560         if(this->start_notify!=NULL) {
561                 /* Wait for the thread to set up its TLS data etc, so
562                  * theres no potential race condition if someone tries
563                  * to look up the data believing the thread has
564                  * started
565                  */
566
567                 THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION
568                           ": (%d) waiting for thread %p (%d) to start",
569                           GetCurrentThreadId (), this, this->tid));
570
571                 WaitForSingleObjectEx (this->start_notify, INFINITE, FALSE);
572                 CloseHandle (this->start_notify);
573                 this->start_notify=NULL;
574         }
575
576         THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION
577                   ": (%d) Done launching thread %p (%d)",
578                   GetCurrentThreadId (), this, this->tid));
579 }
580
581 void ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
582 {
583         MonoThread *thread = mono_thread_current ();
584         
585         MONO_ARCH_SAVE_REGS;
586
587         THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": Sleeping for %d ms", ms));
588
589         mono_monitor_enter (thread->synch_lock);
590         thread->state |= ThreadState_WaitSleepJoin;
591         mono_monitor_exit (thread->synch_lock);
592         
593         SleepEx(ms,TRUE);
594         
595         mono_monitor_enter (thread->synch_lock);
596         thread->state &= ~ThreadState_WaitSleepJoin;
597         mono_monitor_exit (thread->synch_lock);
598 }
599
600 gint32
601 ves_icall_System_Threading_Thread_GetDomainID (void) 
602 {
603         MONO_ARCH_SAVE_REGS;
604
605         return mono_domain_get()->domain_id;
606 }
607
608 MonoString* 
609 ves_icall_System_Threading_Thread_GetName_internal (MonoThread *this_obj)
610 {
611         if (!this_obj->name)
612                 return NULL;
613         else
614                 return mono_string_new_utf16 (mono_domain_get (), this_obj->name, this_obj->name_len);
615 }
616
617 void 
618 ves_icall_System_Threading_Thread_SetName_internal (MonoThread *this_obj, MonoString *name)
619 {
620         if (this_obj->name)
621                 g_free (this_obj->name);
622         if (name) {
623                 this_obj->name = g_new (gunichar2, mono_string_length (name));
624                 memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2);
625                 this_obj->name_len = mono_string_length (name);
626         }
627         else
628                 this_obj->name = NULL;
629 }
630
631 MonoObject*
632 ves_icall_System_Threading_Thread_GetCachedCurrentCulture (MonoThread *this)
633 {
634         MonoObject *res;
635         MonoDomain *domain;
636         int i;
637
638         /* No need to lock here */
639         if (this->culture_info) {
640                 domain = mono_domain_get ();
641                 for (i = 0; i < NUM_CACHED_CULTURES; ++i) {
642                         res = this->culture_info [i];
643                         if (res && res->vtable->domain == domain)
644                                 return res;
645                 }
646         }
647
648         return NULL;
649 }
650
651 MonoArray*
652 ves_icall_System_Threading_Thread_GetSerializedCurrentCulture (MonoThread *this)
653 {
654         MonoArray *res;
655
656         mono_monitor_enter (this->synch_lock);
657         if (this->serialized_culture_info) {
658                 res = mono_array_new (mono_domain_get (), mono_defaults.byte_class, this->serialized_culture_info_len);
659                 memcpy (mono_array_addr (res, guint8, 0), this->serialized_culture_info, this->serialized_culture_info_len);
660         }
661         else
662                 res = NULL;
663         mono_monitor_exit (this->synch_lock);
664
665         return res;
666 }
667
668 void
669 ves_icall_System_Threading_Thread_SetCachedCurrentCulture (MonoThread *this, MonoObject *culture)
670 {
671         int i;
672         MonoDomain *domain = mono_domain_get ();
673
674         mono_monitor_enter (this->synch_lock);
675         if (!this->culture_info) {
676                 this->culture_info = mono_gc_alloc_fixed (sizeof (MonoObject*) * NUM_CACHED_CULTURES, NULL);
677         }
678
679         for (i = 0; i < NUM_CACHED_CULTURES; ++i) {
680                 if (this->culture_info [i]) {
681                         if (this->culture_info [i]->vtable->domain == domain)
682                                 /* Replace */
683                                 break;
684                 }
685                 else
686                         /* Free entry */
687                         break;
688         }
689         if (i < NUM_CACHED_CULTURES)
690                 this->culture_info [i] = culture;
691         mono_monitor_exit (this->synch_lock);
692 }
693
694 void
695 ves_icall_System_Threading_Thread_SetSerializedCurrentCulture (MonoThread *this, MonoArray *arr)
696 {
697         mono_monitor_enter (this->synch_lock);
698         if (this->serialized_culture_info)
699                 g_free (this->serialized_culture_info);
700         this->serialized_culture_info = g_new0 (guint8, mono_array_length (arr));
701         this->serialized_culture_info_len = mono_array_length (arr);
702         memcpy (this->serialized_culture_info, mono_array_addr (arr, guint8, 0), mono_array_length (arr));
703         mono_monitor_exit (this->synch_lock);
704 }
705
706
707 MonoObject*
708 ves_icall_System_Threading_Thread_GetCachedCurrentUICulture (MonoThread *this)
709 {
710         MonoObject *res;
711         MonoDomain *domain;
712         int i;
713
714         /* No need to lock here */
715         if (this->ui_culture_info) {
716                 domain = mono_domain_get ();
717                 for (i = 0; i < NUM_CACHED_CULTURES; ++i) {
718                         res = this->ui_culture_info [i];
719                         if (res && res->vtable->domain == domain)
720                                 return res;
721                 }
722         }
723
724         return NULL;
725 }
726
727 MonoArray*
728 ves_icall_System_Threading_Thread_GetSerializedCurrentUICulture (MonoThread *this)
729 {
730         MonoArray *res;
731
732         mono_monitor_enter (this->synch_lock);
733         if (this->serialized_ui_culture_info) {
734                 res = mono_array_new (mono_domain_get (), mono_defaults.byte_class, this->serialized_ui_culture_info_len);
735                 memcpy (mono_array_addr (res, guint8, 0), this->serialized_ui_culture_info, this->serialized_ui_culture_info_len);
736         }
737         else
738                 res = NULL;
739         mono_monitor_exit (this->synch_lock);
740
741         return res;
742 }
743
744 void
745 ves_icall_System_Threading_Thread_SetCachedCurrentUICulture (MonoThread *this, MonoObject *culture)
746 {
747         int i;
748         MonoDomain *domain = mono_domain_get ();
749
750         mono_monitor_enter (this->synch_lock);
751         if (!this->ui_culture_info) {
752                 this->ui_culture_info = mono_gc_alloc_fixed (sizeof (MonoObject*) * NUM_CACHED_CULTURES, NULL);
753         }
754
755         for (i = 0; i < NUM_CACHED_CULTURES; ++i) {
756                 if (this->ui_culture_info [i]) {
757                         if (this->ui_culture_info [i]->vtable->domain == domain)
758                                 /* Replace */
759                                 break;
760                 }
761                 else
762                         /* Free entry */
763                         break;
764         }
765         if (i < NUM_CACHED_CULTURES)
766                 this->ui_culture_info [i] = culture;
767         mono_monitor_exit (this->synch_lock);
768 }
769
770 void
771 ves_icall_System_Threading_Thread_SetSerializedCurrentUICulture (MonoThread *this, MonoArray *arr)
772 {
773         mono_monitor_enter (this->synch_lock);
774         if (this->serialized_ui_culture_info)
775                 g_free (this->serialized_ui_culture_info);
776         this->serialized_ui_culture_info = g_new0 (guint8, mono_array_length (arr));
777         this->serialized_ui_culture_info_len = mono_array_length (arr);
778         memcpy (this->serialized_ui_culture_info, mono_array_addr (arr, guint8, 0), mono_array_length (arr));
779         mono_monitor_exit (this->synch_lock);
780 }
781
782 /* the jit may read the compiled code of this function */
783 MonoThread *
784 mono_thread_current (void)
785 {
786         THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": returning %p", GET_CURRENT_OBJECT ()));
787         return GET_CURRENT_OBJECT ();
788 }
789
790 gboolean ves_icall_System_Threading_Thread_Join_internal(MonoThread *this,
791                                                          int ms, HANDLE thread)
792 {
793         gboolean ret;
794         
795         MONO_ARCH_SAVE_REGS;
796
797         mono_monitor_enter (this->synch_lock);
798         this->state |= ThreadState_WaitSleepJoin;
799         mono_monitor_exit (this->synch_lock);
800
801         if(ms== -1) {
802                 ms=INFINITE;
803         }
804         THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": joining thread handle %p, %d ms",
805                    thread, ms));
806         
807         ret=WaitForSingleObjectEx (thread, ms, TRUE);
808
809         mono_monitor_enter (this->synch_lock);
810         this->state &= ~ThreadState_WaitSleepJoin;
811         mono_monitor_exit (this->synch_lock);
812         
813         if(ret==WAIT_OBJECT_0) {
814                 THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": join successful"));
815
816                 return(TRUE);
817         }
818         
819         THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": join failed"));
820
821         return(FALSE);
822 }
823
824 void ves_icall_System_Threading_Thread_SlotHash_store(MonoObject *data)
825 {
826         MONO_ARCH_SAVE_REGS;
827
828         THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": Storing key %p", data));
829
830         /* Object location stored here */
831         TlsSetValue(slothash_key, data);
832 }
833
834 MonoObject *ves_icall_System_Threading_Thread_SlotHash_lookup(void)
835 {
836         MonoObject *data;
837
838         MONO_ARCH_SAVE_REGS;
839
840         data=TlsGetValue(slothash_key);
841         
842         THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": Retrieved key %p", data));
843         
844         return(data);
845 }
846
847 /* FIXME: exitContext isnt documented */
848 gboolean ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
849 {
850         HANDLE *handles;
851         guint32 numhandles;
852         guint32 ret;
853         guint32 i;
854         MonoObject *waitHandle;
855         MonoClass *klass;
856         MonoThread *thread = mono_thread_current ();
857                 
858         MONO_ARCH_SAVE_REGS;
859
860         numhandles = mono_array_length(mono_handles);
861         handles = g_new0(HANDLE, numhandles);
862
863         if (wait_handle_os_handle_field == 0) {
864                 /* Get the field os_handle which will contain the actual handle */
865                 klass = mono_class_from_name(mono_defaults.corlib, "System.Threading", "WaitHandle");   
866                 wait_handle_os_handle_field = mono_class_get_field_from_name(klass, "os_handle");
867         }
868                 
869         for(i = 0; i < numhandles; i++) {       
870                 waitHandle = mono_array_get(mono_handles, MonoObject*, i);              
871                 mono_field_get_value(waitHandle, wait_handle_os_handle_field, &handles[i]);
872         }
873         
874         if(ms== -1) {
875                 ms=INFINITE;
876         }
877
878         mono_monitor_enter (thread->synch_lock);
879         thread->state |= ThreadState_WaitSleepJoin;
880         mono_monitor_exit (thread->synch_lock);
881         
882         ret=WaitForMultipleObjectsEx(numhandles, handles, TRUE, ms, TRUE);
883
884         mono_monitor_enter (thread->synch_lock);
885         thread->state &= ~ThreadState_WaitSleepJoin;
886         mono_monitor_exit (thread->synch_lock);
887
888         g_free(handles);
889
890         if(ret==WAIT_FAILED) {
891                 THREAD_WAIT_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": (%d) Wait failed",
892                           GetCurrentThreadId ()));
893                 return(FALSE);
894         } else if(ret==WAIT_TIMEOUT || ret == WAIT_IO_COMPLETION) {
895                 /* Do we want to try again if we get
896                  * WAIT_IO_COMPLETION? The documentation for
897                  * WaitHandle doesn't give any clues.  (We'd have to
898                  * fiddle with the timeout if we retry.)
899                  */
900                 THREAD_WAIT_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": (%d) Wait timed out",
901                           GetCurrentThreadId ()));
902                 return(FALSE);
903         }
904         
905         return(TRUE);
906 }
907
908 /* FIXME: exitContext isnt documented */
909 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
910 {
911         HANDLE *handles;
912         guint32 numhandles;
913         guint32 ret;
914         guint32 i;
915         MonoObject *waitHandle;
916         MonoClass *klass;
917         MonoThread *thread = mono_thread_current ();
918                 
919         MONO_ARCH_SAVE_REGS;
920
921         numhandles = mono_array_length(mono_handles);
922         handles = g_new0(HANDLE, numhandles);
923
924         if (wait_handle_os_handle_field == 0) {
925                 /* Get the field os_handle which will contain the actual handle */
926                 klass = mono_class_from_name(mono_defaults.corlib, "System.Threading", "WaitHandle");   
927                 wait_handle_os_handle_field = mono_class_get_field_from_name(klass, "os_handle");
928         }
929                 
930         for(i = 0; i < numhandles; i++) {       
931                 waitHandle = mono_array_get(mono_handles, MonoObject*, i);              
932                 mono_field_get_value(waitHandle, wait_handle_os_handle_field, &handles[i]);
933         }
934         
935         if(ms== -1) {
936                 ms=INFINITE;
937         }
938
939         mono_monitor_enter (thread->synch_lock);
940         thread->state |= ThreadState_WaitSleepJoin;
941         mono_monitor_exit (thread->synch_lock);
942
943         ret=WaitForMultipleObjectsEx(numhandles, handles, FALSE, ms, TRUE);
944
945         mono_monitor_enter (thread->synch_lock);
946         thread->state &= ~ThreadState_WaitSleepJoin;
947         mono_monitor_exit (thread->synch_lock);
948
949         g_free(handles);
950
951         THREAD_WAIT_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": (%d) returning %d",
952                   GetCurrentThreadId (), ret));
953
954         /*
955          * These need to be here.  See MSDN dos on WaitForMultipleObjects.
956          */
957         if (ret >= WAIT_OBJECT_0 && ret <= WAIT_OBJECT_0 + numhandles - 1) {
958                 return ret - WAIT_OBJECT_0;
959         }
960         else if (ret >= WAIT_ABANDONED_0 && ret <= WAIT_ABANDONED_0 + numhandles - 1) {
961                 return ret - WAIT_ABANDONED_0;
962         }
963         else {
964                 return ret;
965         }
966 }
967
968 /* FIXME: exitContext isnt documented */
969 gboolean ves_icall_System_Threading_WaitHandle_WaitOne_internal(MonoObject *this, HANDLE handle, gint32 ms, gboolean exitContext)
970 {
971         guint32 ret;
972         MonoThread *thread = mono_thread_current ();
973         
974         MONO_ARCH_SAVE_REGS;
975
976         THREAD_WAIT_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": (%d) waiting for %p, %d ms",
977                   GetCurrentThreadId (), handle, ms));
978         
979         if(ms== -1) {
980                 ms=INFINITE;
981         }
982         
983         mono_monitor_enter (thread->synch_lock);
984         thread->state |= ThreadState_WaitSleepJoin;
985         mono_monitor_exit (thread->synch_lock);
986
987         ret=WaitForSingleObjectEx (handle, ms, TRUE);
988         
989         mono_monitor_enter (thread->synch_lock);
990         thread->state &= ~ThreadState_WaitSleepJoin;
991         mono_monitor_exit (thread->synch_lock);
992
993         if(ret==WAIT_FAILED) {
994                 THREAD_WAIT_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": (%d) Wait failed",
995                           GetCurrentThreadId ()));
996                 return(FALSE);
997         } else if(ret==WAIT_TIMEOUT || ret == WAIT_IO_COMPLETION) {
998                 /* Do we want to try again if we get
999                  * WAIT_IO_COMPLETION? The documentation for
1000                  * WaitHandle doesn't give any clues.  (We'd have to
1001                  * fiddle with the timeout if we retry.)
1002                  */
1003                 THREAD_WAIT_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": (%d) Wait timed out",
1004                           GetCurrentThreadId ()));
1005                 return(FALSE);
1006         }
1007         
1008         return(TRUE);
1009 }
1010
1011 HANDLE ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned, MonoString *name, MonoBoolean *created)
1012
1013         HANDLE mutex;
1014         
1015         MONO_ARCH_SAVE_REGS;
1016    
1017         *created = TRUE;
1018         
1019         if (name == NULL) {
1020                 mutex = CreateMutex (NULL, owned, NULL);
1021         } else {
1022                 mutex = CreateMutex (NULL, owned, mono_string_chars (name));
1023                 
1024                 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1025                         *created = FALSE;
1026                 }
1027         }
1028
1029         return(mutex);
1030 }                                                                   
1031
1032 void ves_icall_System_Threading_Mutex_ReleaseMutex_internal (HANDLE handle ) { 
1033         MONO_ARCH_SAVE_REGS;
1034
1035         ReleaseMutex(handle);
1036 }
1037
1038 HANDLE ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manual, MonoBoolean initial, MonoString *name) {
1039         MONO_ARCH_SAVE_REGS;
1040
1041         return(CreateEvent (NULL, manual, initial,
1042                             name==NULL?NULL:mono_string_chars (name)));
1043 }
1044
1045 gboolean ves_icall_System_Threading_Events_SetEvent_internal (HANDLE handle) {
1046         MONO_ARCH_SAVE_REGS;
1047
1048         return (SetEvent(handle));
1049 }
1050
1051 gboolean ves_icall_System_Threading_Events_ResetEvent_internal (HANDLE handle) {
1052         MONO_ARCH_SAVE_REGS;
1053
1054         return (ResetEvent(handle));
1055 }
1056
1057 void
1058 ves_icall_System_Threading_Events_CloseEvent_internal (HANDLE handle) {
1059         MONO_ARCH_SAVE_REGS;
1060
1061         CloseHandle (handle);
1062 }
1063
1064 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
1065 {
1066         MONO_ARCH_SAVE_REGS;
1067
1068         return InterlockedIncrement (location);
1069 }
1070
1071 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
1072 {
1073         gint64 ret;
1074
1075         MONO_ARCH_SAVE_REGS;
1076
1077         EnterCriticalSection(&interlocked_mutex);
1078
1079         ret = ++ *location;
1080         
1081         LeaveCriticalSection(&interlocked_mutex);
1082
1083         
1084         return ret;
1085 }
1086
1087 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
1088 {
1089         MONO_ARCH_SAVE_REGS;
1090
1091         return InterlockedDecrement(location);
1092 }
1093
1094 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
1095 {
1096         gint64 ret;
1097
1098         MONO_ARCH_SAVE_REGS;
1099
1100         EnterCriticalSection(&interlocked_mutex);
1101
1102         ret = -- *location;
1103         
1104         LeaveCriticalSection(&interlocked_mutex);
1105
1106         return ret;
1107 }
1108
1109 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location1, gint32 value)
1110 {
1111         MONO_ARCH_SAVE_REGS;
1112
1113         return InterlockedExchange(location1, value);
1114 }
1115
1116 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location1, MonoObject *value)
1117 {
1118         MONO_ARCH_SAVE_REGS;
1119
1120         return (MonoObject *) InterlockedExchangePointer((gpointer *) location1, value);
1121 }
1122
1123 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location1, gfloat value)
1124 {
1125         IntFloatUnion val, ret;
1126
1127         MONO_ARCH_SAVE_REGS;
1128
1129         val.fval = value;
1130         ret.ival = InterlockedExchange((gint32 *) location1, val.ival);
1131
1132         return ret.fval;
1133 }
1134
1135 gint64 
1136 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64 *location1, gint64 value)
1137 {
1138 #if SIZEOF_VOID_P == 8
1139         return (gint64) InterlockedExchangePointer((gpointer *) location1, (gpointer)value);
1140 #else
1141         gint64 res;
1142
1143         /* 
1144          * According to MSDN, this function is only atomic with regards to the 
1145          * other Interlocked functions on 32 bit platforms.
1146          */
1147         EnterCriticalSection(&interlocked_mutex);
1148         res = *location;
1149         *location = value;
1150         LeaveCriticalSection(&interlocked_mutex);
1151
1152         return res;
1153 #endif
1154 }
1155
1156 gdouble 
1157 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location1, gdouble value)
1158 {
1159 #if SIZEOF_VOID_P == 8
1160         LongDoubleUnion val, ret;
1161
1162         val.fval = value;
1163         ret.ival = (gint64)InterlockedExchangePointer((gpointer *) location1, (gpointer)val.ival);
1164
1165         return ret.fval;
1166 #else
1167         gdouble res;
1168
1169         /* 
1170          * According to MSDN, this function is only atomic with regards to the 
1171          * other Interlocked functions on 32 bit platforms.
1172          */
1173         EnterCriticalSection(&interlocked_mutex);
1174         res = *location;
1175         *location = value;
1176         LeaveCriticalSection(&interlocked_mutex);
1177
1178         return res;
1179 #endif
1180 }
1181
1182 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location1, gint32 value, gint32 comparand)
1183 {
1184         MONO_ARCH_SAVE_REGS;
1185
1186         return InterlockedCompareExchange(location1, value, comparand);
1187 }
1188
1189 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location1, MonoObject *value, MonoObject *comparand)
1190 {
1191         MONO_ARCH_SAVE_REGS;
1192
1193         return (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location1, value, comparand);
1194 }
1195
1196 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location1, gfloat value, gfloat comparand)
1197 {
1198         IntFloatUnion val, ret, cmp;
1199
1200         MONO_ARCH_SAVE_REGS;
1201
1202         val.fval = value;
1203         cmp.fval = comparand;
1204         ret.ival = InterlockedCompareExchange((gint32 *) location1, val.ival, cmp.ival);
1205
1206         return ret.fval;
1207 }
1208
1209 gdouble
1210 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble *location1, gdouble value, gdouble comparand)
1211 {
1212 #if SIZEOF_VOID_P == 8
1213         LongDoubleUnion val, comp, ret;
1214
1215         val.fval = value;
1216         comp.fval = comparand;
1217         ret.ival = (gint64)InterlockedCompareExchangePointer((gpointer *) location1, (gpointer)val.ival, (gpointer)comp.ival);
1218
1219         return ret.fval;
1220 #else
1221         gdouble old;
1222
1223         EnterCriticalSection(&interlocked_mutex);
1224         old = *location1;
1225         if (old == comparand)
1226                 *location1 = value;
1227         LeaveCriticalSection(&interlocked_mutex);
1228
1229         return old;
1230 #endif
1231 }
1232
1233 gint64 
1234 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location1, gint64 value, gint64 comparand)
1235 {
1236 #if SIZEOF_VOID_P == 8
1237         return (gint64)InterlockedCompareExchangePointer((gpointer *) location1, (gpointer)value, (gpointer)comparand);
1238 #else
1239         gint64 old;
1240
1241         EnterCriticalSection(&interlocked_mutex);
1242         old = *location1;
1243         if (old == comparand)
1244                 *location1 = value;
1245         LeaveCriticalSection(&interlocked_mutex);
1246         
1247         return old;
1248 #endif
1249 }
1250
1251 gint32 
1252 ves_icall_System_Threading_Interlocked_Add_Int (gint32 *location1, gint32 value)
1253 {
1254 #if SIZEOF_VOID_P == 8
1255         /* Should be implemented as a JIT intrinsic */
1256         mono_raise_exception (mono_get_exception_not_implemented (NULL));
1257         return 0;
1258 #else
1259         gint32 orig;
1260
1261         EnterCriticalSection(&interlocked_mutex);
1262         orig = *location;
1263         *location = orig + value;
1264         LeaveCriticalSection(&interlocked_mutex);
1265
1266         return orig;
1267 #endif
1268 }
1269
1270 gint64 
1271 ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location1, gint64 value)
1272 {
1273 #if SIZEOF_VOID_P == 8
1274         /* Should be implemented as a JIT intrinsic */
1275         mono_raise_exception (mono_get_exception_not_implemented (NULL));
1276         return 0;
1277 #else
1278         gint64 orig;
1279
1280         EnterCriticalSection(&interlocked_mutex);
1281         orig = *location;
1282         *location = orig + value;
1283         LeaveCriticalSection(&interlocked_mutex);
1284
1285         return orig;
1286 #endif
1287 }
1288
1289 gint64 
1290 ves_icall_System_Threading_Interlocked_Read_Long (gint64 *location1)
1291 {
1292 #if SIZEOF_VOID_P == 8
1293         /* 64 bit reads are already atomic */
1294         return *location1;
1295 #else
1296         gint64 res;
1297
1298         EnterCriticalSection(&interlocked_mutex);
1299         res = *location1;
1300         LeaveCriticalSection(&interlocked_mutex);
1301
1302         return res;
1303 #endif
1304 }
1305
1306 int  
1307 mono_thread_get_abort_signal (void)
1308 {
1309 #ifdef __MINGW32__
1310         return -1;
1311 #else
1312 #ifndef SIGRTMIN
1313         return SIGUSR1;
1314 #else
1315         return SIGRTMIN;
1316 #endif
1317 #endif /* __MINGW32__ */
1318 }
1319
1320 #ifdef __MINGW32__
1321 static CALLBACK void interruption_request_apc (ULONG_PTR param)
1322 {
1323         MonoException* exc = mono_thread_request_interruption (FALSE);
1324         if (exc) mono_raise_exception (exc);
1325         return 0;
1326 }
1327 #endif /* __MINGW32__ */
1328
1329 /*
1330  * signal_thread_state_change
1331  *
1332  * Tells the thread that his state has changed and it has to enter the new
1333  * state as soon as possible.
1334  */
1335 static void signal_thread_state_change (MonoThread *thread)
1336 {
1337         if (thread == mono_thread_current ()) {
1338                 /* Do it synchronously */
1339                 MonoException *exc = mono_thread_request_interruption (FALSE); 
1340                 if (exc)
1341                         mono_raise_exception (exc);
1342         }
1343
1344 #ifdef __MINGW32__
1345         QueueUserAPC (interruption_request_apc, thread->handle, NULL);
1346 #else
1347         /* fixme: store the state somewhere */
1348 #ifdef PTHREAD_POINTER_ID
1349         pthread_kill (GUINT_TO_POINTER(thread->tid), mono_thread_get_abort_signal ());
1350 #else
1351         pthread_kill (thread->tid, mono_thread_get_abort_signal ());
1352 #endif
1353 #endif /* __MINGW32__ */
1354 }
1355
1356 void
1357 ves_icall_System_Threading_Thread_Abort (MonoThread *thread, MonoObject *state)
1358 {
1359         MONO_ARCH_SAVE_REGS;
1360
1361         mono_monitor_enter (thread->synch_lock);
1362
1363         if ((thread->state & ThreadState_AbortRequested) != 0 || 
1364                 (thread->state & ThreadState_StopRequested) != 0) 
1365         {
1366                 mono_monitor_exit (thread->synch_lock);
1367                 return;
1368         }
1369
1370         thread->state |= ThreadState_AbortRequested;
1371         thread->abort_state = state;
1372         thread->abort_exc = NULL;
1373
1374         mono_monitor_exit (thread->synch_lock);
1375
1376         THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION
1377                    ": (%d) Abort requested for %p (%d)", GetCurrentThreadId (),
1378                    thread, thread->tid));
1379         
1380         /* Make sure the thread is awake */
1381         ves_icall_System_Threading_Thread_Resume (thread);
1382         
1383         signal_thread_state_change (thread);
1384 }
1385
1386 void
1387 ves_icall_System_Threading_Thread_ResetAbort (void)
1388 {
1389         MonoThread *thread = mono_thread_current ();
1390
1391         MONO_ARCH_SAVE_REGS;
1392         
1393         mono_monitor_enter (thread->synch_lock);
1394         
1395         thread->state &= ~ThreadState_AbortRequested;
1396         
1397         if (!thread->abort_exc) {
1398                 const char *msg = "Unable to reset abort because no abort was requested";
1399                 mono_monitor_exit (thread->synch_lock);
1400                 mono_raise_exception (mono_get_exception_thread_state (msg));
1401         } else {
1402                 thread->abort_exc = NULL;
1403                 thread->abort_state = NULL;
1404         }
1405         
1406         mono_monitor_exit (thread->synch_lock);
1407 }
1408
1409 void
1410 ves_icall_System_Threading_Thread_Suspend (MonoThread *thread)
1411 {
1412         MONO_ARCH_SAVE_REGS;
1413
1414         mono_monitor_enter (thread->synch_lock);
1415
1416         if ((thread->state & ThreadState_Suspended) != 0 || 
1417                 (thread->state & ThreadState_SuspendRequested) != 0 ||
1418                 (thread->state & ThreadState_StopRequested) != 0) 
1419         {
1420                 mono_monitor_exit (thread->synch_lock);
1421                 return;
1422         }
1423         
1424         thread->state |= ThreadState_SuspendRequested;
1425         mono_monitor_exit (thread->synch_lock);
1426
1427         signal_thread_state_change (thread);
1428 }
1429
1430 void
1431 ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
1432 {
1433         MONO_ARCH_SAVE_REGS;
1434
1435         mono_monitor_enter (thread->synch_lock);
1436
1437         if ((thread->state & ThreadState_SuspendRequested) != 0) {
1438                 thread->state &= ~ThreadState_SuspendRequested;
1439                 mono_monitor_exit (thread->synch_lock);
1440                 return;
1441         }
1442                 
1443         if ((thread->state & ThreadState_Suspended) == 0) 
1444         {
1445                 mono_monitor_exit (thread->synch_lock);
1446                 return;
1447         }
1448         
1449         thread->resume_event = CreateEvent (NULL, TRUE, FALSE, NULL);
1450         
1451         /* Awake the thread */
1452         SetEvent (thread->suspend_event);
1453
1454         mono_monitor_exit (thread->synch_lock);
1455
1456         /* Wait for the thread to awake */
1457         WaitForSingleObject (thread->resume_event, INFINITE);
1458         CloseHandle (thread->resume_event);
1459         thread->resume_event = NULL;
1460 }
1461
1462 static gboolean
1463 find_wrapper (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
1464 {
1465         if (managed)
1466                 return TRUE;
1467
1468         if (m->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE ||
1469                 m->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE ||
1470                 m->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH) 
1471         {
1472                 *((gboolean*)data) = TRUE;
1473                 return TRUE;
1474         }
1475         return FALSE;
1476 }
1477
1478 static gboolean 
1479 is_running_protected_wrapper (void)
1480 {
1481         gboolean found = FALSE;
1482         mono_stack_walk (find_wrapper, &found);
1483         return found;
1484 }
1485
1486 void mono_thread_stop (MonoThread *thread)
1487 {
1488         mono_monitor_enter (thread->synch_lock);
1489
1490         if ((thread->state & ThreadState_StopRequested) != 0 ||
1491                 (thread->state & ThreadState_Stopped) != 0)
1492         {
1493                 mono_monitor_exit (thread->synch_lock);
1494                 return;
1495         }
1496         
1497         /* Make sure the thread is awake */
1498         ves_icall_System_Threading_Thread_Resume (thread);
1499         
1500         thread->state |= ThreadState_StopRequested;
1501         thread->state &= ~ThreadState_AbortRequested;
1502         
1503         mono_monitor_exit (thread->synch_lock);
1504         
1505         signal_thread_state_change (thread);
1506 }
1507
1508 gint8
1509 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
1510 {
1511         return *((volatile gint8 *) (ptr));
1512 }
1513
1514 gint16
1515 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
1516 {
1517         return *((volatile gint16 *) (ptr));
1518 }
1519
1520 gint32
1521 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
1522 {
1523         return *((volatile gint32 *) (ptr));
1524 }
1525
1526 gint64
1527 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
1528 {
1529         return *((volatile gint64 *) (ptr));
1530 }
1531
1532 void *
1533 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
1534 {
1535         return (void *)  *((volatile void **) ptr);
1536 }
1537
1538 void
1539 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
1540 {
1541         *((volatile gint8 *) ptr) = value;
1542 }
1543
1544 void
1545 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
1546 {
1547         *((volatile gint16 *) ptr) = value;
1548 }
1549
1550 void
1551 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
1552 {
1553         *((volatile gint32 *) ptr) = value;
1554 }
1555
1556 void
1557 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
1558 {
1559         *((volatile gint64 *) ptr) = value;
1560 }
1561
1562 void
1563 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
1564 {
1565         *((volatile void **) ptr) = value;
1566 }
1567
1568 void mono_thread_init (MonoThreadStartCB start_cb,
1569                        MonoThreadAttachCB attach_cb)
1570 {
1571         InitializeCriticalSection(&threads_mutex);
1572         InitializeCriticalSection(&interlocked_mutex);
1573         InitializeCriticalSection(&contexts_mutex);
1574         InitializeCriticalSection(&interruption_mutex);
1575         
1576         mono_init_static_data_info (&thread_static_info);
1577         mono_init_static_data_info (&context_static_info);
1578
1579         current_object_key=TlsAlloc();
1580         THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": Allocated current_object_key %d",
1581                    current_object_key));
1582
1583         mono_thread_start_cb = start_cb;
1584         mono_thread_attach_cb = attach_cb;
1585
1586         slothash_key=TlsAlloc();
1587
1588         /* Get a pseudo handle to the current process.  This is just a
1589          * kludge so that wapi can build a process handle if needed.
1590          * As a pseudo handle is returned, we don't need to clean
1591          * anything up.
1592          */
1593         GetCurrentProcess ();
1594 }
1595
1596 void
1597 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
1598 {
1599         mono_thread_cleanup = func;
1600 }
1601
1602 void mono_install_thread_callbacks (MonoThreadCallbacks *callbacks)
1603 {
1604         mono_thread_callbacks = callbacks;
1605 }
1606
1607 #ifdef THREAD_DEBUG
1608 static void print_tids (gpointer key, gpointer value, gpointer user)
1609 {
1610         g_message ("Waiting for: %d", GPOINTER_TO_UINT(key));
1611 }
1612 #endif
1613
1614 struct wait_data 
1615 {
1616         HANDLE handles[MAXIMUM_WAIT_OBJECTS];
1617         MonoThread *threads[MAXIMUM_WAIT_OBJECTS];
1618         guint32 num;
1619 };
1620
1621 static void wait_for_tids (struct wait_data *wait, guint32 timeout)
1622 {
1623         guint32 i, ret;
1624         
1625         THREAD_DEBUG (g_message(G_GNUC_PRETTY_FUNCTION
1626                   ": %d threads to wait for in this batch", wait->num));
1627
1628         ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, FALSE);
1629
1630         if(ret==WAIT_FAILED) {
1631                 /* See the comment in build_wait_tids() */
1632                 THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": Wait failed"));
1633                 return;
1634         }
1635         
1636         for(i=0; i<wait->num; i++)
1637                 CloseHandle (wait->handles[i]);
1638
1639         if (ret == WAIT_TIMEOUT)
1640                 return;
1641
1642         for(i=0; i<wait->num; i++) {
1643                 guint32 tid=wait->threads[i]->tid;
1644                 
1645                 if(mono_g_hash_table_lookup (threads, GUINT_TO_POINTER(tid))!=NULL) {
1646                         /* This thread must have been killed, because
1647                          * it hasn't cleaned itself up. (It's just
1648                          * possible that the thread exited before the
1649                          * parent thread had a chance to store the
1650                          * handle, and now there is another pointer to
1651                          * the already-exited thread stored.  In this
1652                          * case, we'll just get two
1653                          * mono_profiler_thread_end() calls for the
1654                          * same thread.)
1655                          */
1656         
1657                         THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION
1658                                    ": cleaning up after thread %d", tid));
1659                         thread_cleanup (wait->threads[i]);
1660                 }
1661         }
1662 }
1663
1664 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
1665 {
1666         struct wait_data *wait=(struct wait_data *)user;
1667
1668         if(wait->num<MAXIMUM_WAIT_OBJECTS) {
1669                 HANDLE handle;
1670                 MonoThread *thread=(MonoThread *)value;
1671
1672                 /* Ignore background threads, we abort them later */
1673                 if (thread->state & ThreadState_Background)
1674                         return; /* just leave, ignore */
1675                 
1676                 if (mono_gc_is_finalizer_thread (thread))
1677                         return;
1678
1679                 if (thread == mono_thread_current ())
1680                         return;
1681
1682                 if (thread == mono_thread_get_main ())
1683                         return;
1684
1685                 handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
1686                 if (handle == NULL)
1687                         return;
1688                 
1689                 wait->handles[wait->num]=handle;
1690                 wait->threads[wait->num]=thread;
1691                 wait->num++;
1692         } else {
1693                 /* Just ignore the rest, we can't do anything with
1694                  * them yet
1695                  */
1696         }
1697 }
1698
1699 static gboolean
1700 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
1701 {
1702         struct wait_data *wait=(struct wait_data *)user;
1703         guint32 self = GetCurrentThreadId ();
1704         MonoThread *thread = (MonoThread *) value;
1705         HANDLE handle;
1706
1707         /* The finalizer thread is not a background thread */
1708         if (thread->tid != self && thread->state & ThreadState_Background) {
1709         
1710                 handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
1711                 if (handle == NULL)
1712                         return FALSE;
1713                 
1714                 wait->handles[wait->num]=thread->handle;
1715                 wait->threads[wait->num]=thread;
1716                 wait->num++;
1717         
1718                 if(thread->state & ThreadState_AbortRequested ||
1719                    thread->state & ThreadState_Aborted) {
1720                         THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": Thread id %d already aborting", thread->tid));
1721                         return(TRUE);
1722                 }
1723                 
1724                 THREAD_DEBUG (g_print (G_GNUC_PRETTY_FUNCTION ": Aborting id: %d\n", thread->tid));
1725                 mono_thread_stop (thread);
1726                 return TRUE;
1727         }
1728
1729         return (thread->tid != self && !mono_gc_is_finalizer_thread (thread)); 
1730 }
1731
1732 void mono_thread_manage (void)
1733 {
1734         struct wait_data *wait=g_new0 (struct wait_data, 1);
1735         
1736         /* join each thread that's still running */
1737         THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": Joining each running thread..."));
1738         
1739         EnterCriticalSection (&threads_mutex);
1740         if(threads==NULL) {
1741                 THREAD_DEBUG (g_message(G_GNUC_PRETTY_FUNCTION ": No threads"));
1742                 LeaveCriticalSection (&threads_mutex);
1743                 return;
1744         }
1745         LeaveCriticalSection (&threads_mutex);
1746         
1747         do {
1748                 EnterCriticalSection (&threads_mutex);
1749                 THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION
1750                           ":There are %d threads to join", mono_g_hash_table_size (threads));
1751                         mono_g_hash_table_foreach (threads, print_tids, NULL));
1752         
1753                 wait->num=0;
1754                 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
1755                 LeaveCriticalSection (&threads_mutex);
1756                 if(wait->num>0) {
1757                         /* Something to wait for */
1758                         wait_for_tids (wait, INFINITE);
1759                 }
1760         } while(wait->num>0);
1761         
1762         mono_thread_pool_cleanup ();
1763
1764         EnterCriticalSection(&threads_mutex);
1765
1766         /* 
1767          * Remove everything but the finalizer thread and self.
1768          * Also abort all the background threads
1769          * */
1770         wait->num = 0;
1771         mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
1772
1773         LeaveCriticalSection(&threads_mutex);
1774
1775         if(wait->num>0) {
1776                 /* Something to wait for */
1777                 wait_for_tids (wait, INFINITE);
1778         }
1779         /* 
1780          * give the subthreads a chance to really quit (this is mainly needed
1781          * to get correct user and system times from getrusage/wait/time(1)).
1782          * This could be removed if we avoid pthread_detach() and use pthread_join().
1783          */
1784 #ifndef PLATFORM_WIN32
1785         sched_yield ();
1786 #endif
1787
1788         g_free (wait);
1789 }
1790
1791 static void terminate_thread (gpointer key, gpointer value, gpointer user)
1792 {
1793         MonoThread *thread=(MonoThread *)value;
1794         guint32 self=GPOINTER_TO_UINT (user);
1795         
1796         if(thread->tid!=self) {
1797                 /*TerminateThread (thread->handle, -1);*/
1798         }
1799 }
1800
1801 void mono_thread_abort_all_other_threads (void)
1802 {
1803         guint32 self=GetCurrentThreadId ();
1804
1805         EnterCriticalSection (&threads_mutex);
1806         THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ":There are %d threads to abort",
1807                   mono_g_hash_table_size (threads));
1808                 mono_g_hash_table_foreach (threads, print_tids, NULL));
1809
1810         mono_g_hash_table_foreach (threads, terminate_thread,
1811                                    GUINT_TO_POINTER (self));
1812         
1813         LeaveCriticalSection (&threads_mutex);
1814 }
1815
1816 static void suspend_thread (gpointer key, gpointer value, gpointer user)
1817 {
1818         MonoThread *thread=(MonoThread *)value;
1819         guint32 self=GPOINTER_TO_UINT (user);
1820         
1821         if ((thread->tid!=self) && !mono_gc_is_finalizer_thread (thread))
1822                 SuspendThread (thread->handle);
1823 }
1824
1825 /*
1826  * mono_thread_suspend_all_other_threads:
1827  *
1828  *  Suspend all managed threads except the finalizer thread and this thread.
1829  */
1830 void mono_thread_suspend_all_other_threads (void)
1831 {
1832         guint32 self=GetCurrentThreadId ();
1833
1834         EnterCriticalSection (&threads_mutex);
1835         mono_g_hash_table_foreach (threads, suspend_thread,
1836                                    GUINT_TO_POINTER (self));
1837         LeaveCriticalSection (&threads_mutex);
1838 }
1839
1840 /*
1841  * mono_thread_push_appdomain_ref:
1842  *
1843  *   Register that the current thread may have references to objects in domain 
1844  * @domain on its stack. Each call to this function should be paired with a 
1845  * call to pop_appdomain_ref.
1846  */
1847 void 
1848 mono_thread_push_appdomain_ref (MonoDomain *domain)
1849 {
1850         MonoThread *thread = mono_thread_current ();
1851
1852         if (thread) {
1853                 /* printf ("PUSH REF: %x -> %s.\n", thread->tid, domain->friendly_name); */
1854                 EnterCriticalSection (&threads_mutex);
1855                 thread->appdomain_refs = g_slist_prepend (thread->appdomain_refs, domain);
1856                 LeaveCriticalSection (&threads_mutex);
1857         }
1858 }
1859
1860 void
1861 mono_thread_pop_appdomain_ref (void)
1862 {
1863         MonoThread *thread = mono_thread_current ();
1864
1865         if (thread) {
1866                 /* printf ("POP REF: %x -> %s.\n", thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
1867                 EnterCriticalSection (&threads_mutex);
1868                 /* FIXME: How can the list be empty ? */
1869                 if (thread->appdomain_refs)
1870                         thread->appdomain_refs = g_slist_remove (thread->appdomain_refs, thread->appdomain_refs->data);
1871                 LeaveCriticalSection (&threads_mutex);
1872         }
1873 }
1874
1875 gboolean
1876 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
1877 {
1878         gboolean res;
1879         EnterCriticalSection (&threads_mutex);
1880         res = g_slist_find (thread->appdomain_refs, domain) != NULL;
1881         LeaveCriticalSection (&threads_mutex);
1882         return res;
1883 }
1884
1885 typedef struct abort_appdomain_data {
1886         struct wait_data wait;
1887         MonoDomain *domain;
1888 } abort_appdomain_data;
1889
1890 static void
1891 abort_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
1892 {
1893         MonoThread *thread = (MonoThread*)value;
1894         abort_appdomain_data *data = (abort_appdomain_data*)user_data;
1895         MonoDomain *domain = data->domain;
1896
1897         if (mono_thread_has_appdomain_ref (thread, domain)) {
1898                 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
1899                 HANDLE handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
1900                 if (handle == NULL)
1901                         return;
1902
1903                 ves_icall_System_Threading_Thread_Abort (thread, NULL);
1904
1905                 if(data->wait.num<MAXIMUM_WAIT_OBJECTS) {
1906                         data->wait.handles [data->wait.num] = handle;
1907                         data->wait.threads [data->wait.num] = thread;
1908                         data->wait.num++;
1909                 } else {
1910                         /* Just ignore the rest, we can't do anything with
1911                          * them yet
1912                          */
1913                 }
1914         }
1915 }
1916
1917 /*
1918  * mono_threads_abort_appdomain_threads:
1919  *
1920  *   Abort threads which has references to the given appdomain.
1921  */
1922 gboolean
1923 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
1924 {
1925         abort_appdomain_data user_data;
1926         guint32 start_time;
1927
1928         /* printf ("ABORT BEGIN.\n"); */
1929
1930         start_time = GetTickCount ();
1931         do {
1932                 EnterCriticalSection (&threads_mutex);
1933
1934                 user_data.domain = domain;
1935                 user_data.wait.num = 0;
1936                 mono_g_hash_table_foreach (threads, abort_appdomain_thread, &user_data);
1937                 LeaveCriticalSection (&threads_mutex);
1938
1939                 if (user_data.wait.num > 0)
1940                         wait_for_tids (&user_data.wait, timeout);
1941
1942                 /* Update remaining time */
1943                 timeout -= GetTickCount () - start_time;
1944                 start_time = GetTickCount ();
1945
1946                 if (timeout < 0)
1947                         return FALSE;
1948         }
1949         while (user_data.wait.num > 0);
1950
1951         /* printf ("ABORT DONE.\n"); */
1952
1953         return TRUE;
1954 }
1955
1956 static void
1957 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
1958 {
1959         MonoThread *thread = (MonoThread*)value;
1960         MonoDomain *domain = (MonoDomain*)user_data;
1961         int i;
1962
1963         /* No locking needed here */
1964
1965         if (thread->culture_info) {
1966                 for (i = 0; i < NUM_CACHED_CULTURES; ++i) {
1967                         if (thread->culture_info [i] && thread->culture_info [i]->vtable->domain == domain)
1968                                 thread->culture_info [i] = NULL;
1969                 }
1970         }
1971         if (thread->ui_culture_info) {
1972                 for (i = 0; i < NUM_CACHED_CULTURES; ++i) {
1973                         if (thread->ui_culture_info [i] && thread->ui_culture_info [i]->vtable->domain == domain)
1974                                 thread->ui_culture_info [i] = NULL;
1975                 }
1976         }
1977 }
1978         
1979 /*
1980  * mono_threads_clear_cached_culture:
1981  *
1982  *   Clear the cached_current_culture from all threads if it is in the
1983  * given appdomain.
1984  */
1985 void
1986 mono_threads_clear_cached_culture (MonoDomain *domain)
1987 {
1988         EnterCriticalSection (&threads_mutex);
1989         mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
1990         LeaveCriticalSection (&threads_mutex);
1991 }
1992
1993 /*
1994  * mono_thread_get_pending_exception:
1995  *
1996  *   Return an exception which needs to be raised when leaving a catch clause.
1997  * This is used for undeniable exception propagation.
1998  */
1999 MonoException*
2000 mono_thread_get_pending_exception (void)
2001 {
2002         MonoThread *thread = mono_thread_current ();
2003
2004         MONO_ARCH_SAVE_REGS;
2005
2006         if (thread && thread->abort_exc && !is_running_protected_wrapper ()) {
2007                 /*
2008                  * FIXME: Clear the abort exception and return an AppDomainUnloaded 
2009                  * exception if the thread no longer references a dying appdomain.
2010                  */
2011                 thread->abort_exc->trace_ips = NULL;
2012                 thread->abort_exc->stack_trace = NULL;
2013                 return thread->abort_exc;
2014         }
2015
2016         return NULL;
2017 }
2018
2019 #define NUM_STATIC_DATA_IDX 8
2020 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
2021         1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
2022 };
2023
2024
2025 /*
2026  *  mono_alloc_static_data
2027  *
2028  *   Allocate memory blocks for storing threads or context static data
2029  */
2030 static void 
2031 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset)
2032 {
2033         guint idx = (offset >> 24) - 1;
2034         int i;
2035
2036         gpointer* static_data = *static_data_ptr;
2037         if (!static_data) {
2038                 static_data = mono_gc_alloc_fixed (static_data_size [0], NULL);
2039                 *static_data_ptr = static_data;
2040                 static_data [0] = static_data;
2041         }
2042
2043         for (i = 1; i <= idx; ++i) {
2044                 if (static_data [i])
2045                         continue;
2046                 static_data [i] = mono_gc_alloc_fixed (static_data_size [i], NULL);
2047         }
2048 }
2049
2050 /*
2051  *  mono_init_static_data_info
2052  *
2053  *   Initializes static data counters
2054  */
2055 static void mono_init_static_data_info (StaticDataInfo *static_data)
2056 {
2057         static_data->idx = 0;
2058         static_data->offset = 0;
2059 }
2060
2061 /*
2062  *  mono_alloc_static_data_slot
2063  *
2064  *   Generates an offset for static data. static_data contains the counters
2065  *  used to generate it.
2066  */
2067 static guint32
2068 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
2069 {
2070         guint32 offset;
2071
2072         if (!static_data->idx && !static_data->offset) {
2073                 /* 
2074                  * we use the first chunk of the first allocation also as
2075                  * an array for the rest of the data 
2076                  */
2077                 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
2078         }
2079         static_data->offset += align - 1;
2080         static_data->offset &= ~(align - 1);
2081         if (static_data->offset + size >= static_data_size [static_data->idx]) {
2082                 static_data->idx ++;
2083                 g_assert (size <= static_data_size [static_data->idx]);
2084                 /* 
2085                  * massive unloading and reloading of domains with thread-static
2086                  * data may eventually exceed the allocated storage...
2087                  * Need to check what the MS runtime does in that case.
2088                  * Note that for each appdomain, we need to allocate a separate
2089                  * thread data slot for security reasons. We could keep track
2090                  * of the slots per-domain and when the domain is unloaded
2091                  * out the slots on a sort of free list.
2092                  */
2093                 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
2094                 static_data->offset = 0;
2095         }
2096         offset = static_data->offset | ((static_data->idx + 1) << 24);
2097         static_data->offset += size;
2098         return offset;
2099 }
2100
2101 /* 
2102  * ensure thread static fields already allocated are valid for thread
2103  * This function is called when a thread is created or on thread attach.
2104  */
2105 static void
2106 thread_adjust_static_data (MonoThread *thread)
2107 {
2108         guint32 offset;
2109
2110         EnterCriticalSection (&threads_mutex);
2111         if (thread_static_info.offset || thread_static_info.idx > 0) {
2112                 /* get the current allocated size */
2113                 offset = thread_static_info.offset | ((thread_static_info.idx + 1) << 24);
2114                 mono_alloc_static_data (&(thread->static_data), offset);
2115         }
2116         LeaveCriticalSection (&threads_mutex);
2117 }
2118
2119 static void 
2120 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
2121 {
2122         MonoThread *thread = value;
2123         guint32 offset = GPOINTER_TO_UINT (user);
2124         
2125         mono_alloc_static_data (&(thread->static_data), offset);
2126 }
2127
2128 /*
2129  * The offset for a special static variable is composed of three parts:
2130  * a bit that indicates the type of static data (0:thread, 1:context),
2131  * an index in the array of chunks of memory for the thread (thread->static_data)
2132  * and an offset in that chunk of mem. This allows allocating less memory in the 
2133  * common case.
2134  */
2135
2136 guint32
2137 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align)
2138 {
2139         guint32 offset;
2140         if (static_type == SPECIAL_STATIC_THREAD)
2141         {
2142                 EnterCriticalSection (&threads_mutex);
2143                 offset = mono_alloc_static_data_slot (&thread_static_info, size, align);
2144                 /* This can be called during startup */
2145                 if (threads != NULL)
2146                         mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
2147                 LeaveCriticalSection (&threads_mutex);
2148         }
2149         else
2150         {
2151                 g_assert (static_type == SPECIAL_STATIC_CONTEXT);
2152                 EnterCriticalSection (&contexts_mutex);
2153                 offset = mono_alloc_static_data_slot (&context_static_info, size, align);
2154                 LeaveCriticalSection (&contexts_mutex);
2155                 offset |= 0x80000000;   /* Set the high bit to indicate context static data */
2156         }
2157         return offset;
2158 }
2159
2160 gpointer
2161 mono_get_special_static_data (guint32 offset)
2162 {
2163         /* The high bit means either thread (0) or static (1) data. */
2164
2165         guint32 static_type = (offset & 0x80000000);
2166         int idx;
2167
2168         offset &= 0x7fffffff;
2169         idx = (offset >> 24) - 1;
2170
2171         if (static_type == 0)
2172         {
2173                 MonoThread *thread = mono_thread_current ();
2174                 return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
2175         }
2176         else
2177         {
2178                 /* Allocate static data block under demand, since we don't have a list
2179                 // of contexts
2180                 */
2181                 MonoAppContext *context = mono_context_get ();
2182                 if (!context->static_data || !context->static_data [idx]) {
2183                         EnterCriticalSection (&contexts_mutex);
2184                         mono_alloc_static_data (&(context->static_data), offset);
2185                         LeaveCriticalSection (&contexts_mutex);
2186                 }
2187                 return ((char*) context->static_data [idx]) + (offset & 0xffffff);      
2188         }
2189 }
2190
2191 static void gc_stop_world (gpointer key, gpointer value, gpointer user)
2192 {
2193         MonoThread *thread=(MonoThread *)value;
2194         guint32 self=GPOINTER_TO_UINT (user);
2195
2196         LIBGC_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": %d - %d", self, thread->tid));
2197
2198         if(thread->tid==self)
2199                 return;
2200
2201         SuspendThread (thread->handle);
2202 }
2203
2204 void mono_gc_stop_world (void)
2205 {
2206         guint32 self=GetCurrentThreadId ();
2207
2208         LIBGC_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": %d - %p", self, threads));
2209
2210         EnterCriticalSection (&threads_mutex);
2211
2212         if (threads != NULL)
2213                 mono_g_hash_table_foreach (threads, gc_stop_world, GUINT_TO_POINTER (self));
2214         
2215         LeaveCriticalSection (&threads_mutex);
2216 }
2217
2218 static void gc_start_world (gpointer key, gpointer value, gpointer user)
2219 {
2220         MonoThread *thread=(MonoThread *)value;
2221         guint32 self=GPOINTER_TO_UINT (user);
2222         
2223         LIBGC_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": %d - %d", self, thread->tid));
2224
2225         if(thread->tid==self)
2226                 return;
2227
2228         ResumeThread (thread->handle);
2229 }
2230
2231 void mono_gc_start_world (void)
2232 {
2233         guint32 self=GetCurrentThreadId ();
2234
2235         LIBGC_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": %d - %p", self, threads));
2236
2237         EnterCriticalSection (&threads_mutex);
2238
2239         if (threads != NULL)
2240                 mono_g_hash_table_foreach (threads, gc_start_world, GUINT_TO_POINTER (self));
2241         
2242         LeaveCriticalSection (&threads_mutex);
2243 }
2244
2245 #ifdef __MINGW32__
2246 static CALLBACK void dummy_apc (ULONG_PTR param)
2247 {
2248 }
2249 #else
2250 static guint32 dummy_apc (gpointer param)
2251 {
2252         return 0;
2253 }
2254 #endif
2255
2256 /*
2257  * mono_thread_execute_interruption
2258  * 
2259  * Performs the operation that the requested thread state requires (abort,
2260  * suspend or stop)
2261  */
2262 static MonoException* mono_thread_execute_interruption (MonoThread *thread)
2263 {
2264         mono_monitor_enter (thread->synch_lock);
2265
2266         if (thread->interruption_requested) {
2267                 /* this will consume pending APC calls */
2268                 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
2269                 EnterCriticalSection (&interruption_mutex);
2270                 thread_interruption_requested--;
2271                 LeaveCriticalSection (&interruption_mutex);
2272                 thread->interruption_requested = FALSE;
2273         }
2274
2275         if ((thread->state & ThreadState_AbortRequested) != 0) {
2276                 if (thread->abort_exc == NULL)
2277                         thread->abort_exc = mono_get_exception_thread_abort ();
2278                 mono_monitor_exit (thread->synch_lock);
2279                 return thread->abort_exc;
2280         }
2281         else if ((thread->state & ThreadState_SuspendRequested) != 0) {
2282                 thread->state &= ~ThreadState_SuspendRequested;
2283                 thread->state |= ThreadState_Suspended;
2284                 thread->suspend_event = CreateEvent (NULL, TRUE, FALSE, NULL);
2285                 mono_monitor_exit (thread->synch_lock);
2286                 
2287                 WaitForSingleObject (thread->suspend_event, INFINITE);
2288                 
2289                 mono_monitor_enter (thread->synch_lock);
2290                 CloseHandle (thread->suspend_event);
2291                 thread->suspend_event = NULL;
2292                 thread->state &= ~ThreadState_Suspended;
2293         
2294                 /* The thread that requested the resume will have replaced this event
2295              * and will be waiting for it
2296                  */
2297                 SetEvent (thread->resume_event);
2298                 mono_monitor_exit (thread->synch_lock);
2299                 return NULL;
2300         }
2301         else if ((thread->state & ThreadState_StopRequested) != 0) {
2302                 /* FIXME: do this through the JIT? */
2303                 mono_monitor_exit (thread->synch_lock);
2304                 mono_thread_exit ();
2305                 return NULL;
2306         }
2307         
2308         mono_monitor_exit (thread->synch_lock);
2309         return NULL;
2310 }
2311
2312 /*
2313  * mono_thread_request_interruption
2314  *
2315  * A signal handler can call this method to request the interruption of a
2316  * thread. The result of the interruption will depend on the current state of
2317  * the thread. If the result is an exception that needs to be throw, it is 
2318  * provided as return value.
2319  */
2320 MonoException* mono_thread_request_interruption (gboolean running_managed)
2321 {
2322         MonoThread *thread = mono_thread_current ();
2323
2324         /* The thread may already be stopping */
2325         if (thread == NULL) 
2326                 return NULL;
2327         
2328         mono_monitor_enter (thread->synch_lock);
2329         
2330         if (thread->interruption_requested) {
2331                 mono_monitor_exit (thread->synch_lock);
2332                 return NULL;
2333         }
2334
2335         if (!running_managed || is_running_protected_wrapper ()) {
2336                 /* Can't stop while in unmanaged code. Increase the global interruption
2337                    request count. When exiting the unmanaged method the count will be
2338                    checked and the thread will be interrupted. */
2339                 
2340                 EnterCriticalSection (&interruption_mutex);
2341                 thread_interruption_requested++;
2342                 LeaveCriticalSection (&interruption_mutex);
2343                 
2344                 thread->interruption_requested = TRUE;
2345                 mono_monitor_exit (thread->synch_lock);
2346                 
2347                 /* this will awake the thread if it is in WaitForSingleObject 
2348                or similar */
2349                 QueueUserAPC (dummy_apc, thread->handle, NULL);
2350                 
2351                 return NULL;
2352         }
2353         else {
2354                 mono_monitor_exit (thread->synch_lock);
2355                 return mono_thread_execute_interruption (thread);
2356         }
2357 }
2358
2359 gboolean mono_thread_interruption_requested ()
2360 {
2361         if (thread_interruption_requested) {
2362                 MonoThread *thread = mono_thread_current ();
2363                 /* The thread may already be stopping */
2364                 if (thread != NULL) 
2365                         return (thread->interruption_requested);
2366         }
2367         return FALSE;
2368 }
2369
2370 static void mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
2371 {
2372         MonoThread *thread = mono_thread_current ();
2373
2374         /* The thread may already be stopping */
2375         if (thread == NULL) 
2376                 return;
2377         
2378         if (thread->interruption_requested && (bypass_abort_protection || !is_running_protected_wrapper ())) {
2379                 MonoException* exc = mono_thread_execute_interruption (thread);
2380                 if (exc) mono_raise_exception (exc);
2381         }
2382 }
2383
2384 /*
2385  * Performs the interruption of the current thread, if one has been requested,
2386  * and the thread is not running a protected wrapper.
2387  */
2388 void mono_thread_interruption_checkpoint ()
2389 {
2390         mono_thread_interruption_checkpoint_request (FALSE);
2391 }
2392
2393 /*
2394  * Performs the interruption of the current thread, if one has been requested.
2395  */
2396 void mono_thread_force_interruption_checkpoint ()
2397 {
2398         mono_thread_interruption_checkpoint_request (TRUE);
2399 }
2400
2401 /**
2402  * mono_thread_interruption_request_flag:
2403  *
2404  * Returns the address of a flag that will be non-zero if an interruption has
2405  * been requested for a thread. The thread to interrupt may not be the current
2406  * thread, so an additional call to mono_thread_interruption_requested() or
2407  * mono_thread_interruption_checkpoint() is allways needed if the flag is not
2408  * zero.
2409  */
2410 gint32* mono_thread_interruption_request_flag ()
2411 {
2412         return &thread_interruption_requested;
2413 }
2414
2415 #ifdef WITH_INCLUDED_LIBGC
2416
2417 static void gc_push_all_stacks (gpointer key, gpointer value, gpointer user)
2418 {
2419         MonoThread *thread=(MonoThread *)value;
2420         guint32 *selfp=(guint32 *)user, self = *selfp;
2421
2422         LIBGC_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": %d - %d - %p", self, thread->tid, thread->stack_ptr));
2423
2424         if(thread->tid==self) {
2425                 LIBGC_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": %p - %p", selfp, thread->stack_ptr));
2426                 GC_push_all_stack (selfp, thread->stack_ptr);
2427                 return;
2428         }
2429
2430 #ifdef PLATFORM_WIN32
2431         GC_win32_push_thread_stack (thread->handle, thread->stack_ptr);
2432 #else
2433         mono_wapi_push_thread_stack (thread->handle, thread->stack_ptr);
2434 #endif
2435 }
2436
2437 void mono_gc_push_all_stacks (void)
2438 {
2439         guint32 self=GetCurrentThreadId ();
2440
2441         LIBGC_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": %d - %p", self, threads));
2442
2443         EnterCriticalSection (&threads_mutex);
2444
2445         if (threads != NULL)
2446                 mono_g_hash_table_foreach (threads, gc_push_all_stacks, &self);
2447         
2448         LeaveCriticalSection (&threads_mutex);
2449 }
2450
2451 #endif /* WITH_INCLUDED_LIBGC */