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