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