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