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