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