Introduce a callback API to have notifications when runtime resources exceed preset...
[mono.git] / mono / metadata / threads.c
index cb401d12931272535c73934edd1fb60780a0ec7c..422dff84d531a2ea06ab741bdcfda7e2b8196a24 100644 (file)
@@ -8,6 +8,7 @@
  *
  * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
  * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
+ * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
  */
 
 #include <config.h>
@@ -44,6 +45,7 @@
 #include <mono/utils/mono-time.h>
 #include <mono/utils/mono-threads.h>
 #include <mono/utils/hazard-pointer.h>
+#include <mono/utils/mono-tls.h>
 
 #include <mono/metadata/gc-internal.h>
 
@@ -147,7 +149,7 @@ static MonoGHashTable *threads_starting_up = NULL;
 static MonoGHashTable *thread_start_args = NULL;
 
 /* The TLS key that holds the MonoObject assigned to each thread */
-static guint32 current_object_key = -1;
+static MonoNativeTlsKey current_object_key;
 
 #ifdef MONO_HAVE_FAST_TLS
 /* we need to use both the Tls* functions and __thread because
@@ -156,12 +158,12 @@ static guint32 current_object_key = -1;
 MONO_FAST_TLS_DECLARE(tls_current_object);
 #define SET_CURRENT_OBJECT(x) do { \
        MONO_FAST_TLS_SET (tls_current_object, x); \
-       TlsSetValue (current_object_key, x); \
+       mono_native_tls_set_value (current_object_key, x); \
 } while (FALSE)
 #define GET_CURRENT_OBJECT() ((MonoInternalThread*) MONO_FAST_TLS_GET (tls_current_object))
 #else
-#define SET_CURRENT_OBJECT(x) TlsSetValue (current_object_key, x)
-#define GET_CURRENT_OBJECT() (MonoInternalThread*) TlsGetValue (current_object_key)
+#define SET_CURRENT_OBJECT(x) mono_native_tls_set_value (current_object_key, x)
+#define GET_CURRENT_OBJECT() (MonoInternalThread*) mono_native_tls_get_value (current_object_key)
 #endif
 
 /* function called at thread start */
@@ -216,7 +218,7 @@ get_next_managed_thread_id (void)
        return InterlockedIncrement (&managed_thread_id_counter);
 }
 
-guint32
+MonoNativeTlsKey
 mono_thread_get_tls_key (void)
 {
        return current_object_key;
@@ -366,6 +368,8 @@ static void thread_cleanup (MonoInternalThread *thread)
        }
        mono_release_type_locks (thread);
 
+       ensure_synch_cs_set (thread);
+
        EnterCriticalSection (thread->synch_cs);
 
        thread->state |= ThreadState_Stopped;
@@ -764,6 +768,9 @@ mono_thread_get_stack_bounds (guint8 **staddr, size_t *stsize)
 #if defined(HAVE_PTHREAD_GET_STACKSIZE_NP) && defined(HAVE_PTHREAD_GET_STACKADDR_NP)
        *staddr = (guint8*)pthread_get_stackaddr_np (pthread_self ());
        *stsize = pthread_get_stacksize_np (pthread_self ());
+
+       /* staddr points to the start of the stack, not the end */
+       *staddr -= *stsize;
        *staddr = (guint8*)((gssize)*staddr & ~(mono_pagesize () - 1));
        return;
        /* FIXME: simplify the mess below */
@@ -1241,7 +1248,7 @@ byte_array_to_domain (MonoArray *arr, MonoDomain *domain)
                return arr;
 
        copy = mono_array_new (domain, mono_defaults.byte_class, arr->max_length);
-       memcpy (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length);
+       mono_gc_memmove (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length);
        return copy;
 }
 
@@ -1973,21 +1980,18 @@ ves_icall_System_Threading_Thread_GetState (MonoInternalThread* this)
 
 void ves_icall_System_Threading_Thread_Interrupt_internal (MonoInternalThread *this)
 {
-       gboolean throw = FALSE;
-       
+       MonoInternalThread *current;
+       gboolean throw;
+
        ensure_synch_cs_set (this);
 
-       if (this == mono_thread_internal_current ())
-               return;
-       
-       EnterCriticalSection (this->synch_cs);
-       
-       this->thread_interrupt_requested = TRUE;
-       
-       if (this->state & ThreadState_WaitSleepJoin) {
-               throw = TRUE;
-       }
-       
+       current = mono_thread_internal_current ();
+
+       EnterCriticalSection (this->synch_cs);  
+
+       this->thread_interrupt_requested = TRUE;        
+       throw = current != this && (this->state & ThreadState_WaitSleepJoin);   
+
        LeaveCriticalSection (this->synch_cs);
        
        if (throw) {
@@ -2431,7 +2435,7 @@ void mono_thread_init (MonoThreadStartCB start_cb,
        mono_init_static_data_info (&context_static_info);
 
        MONO_FAST_TLS_INIT (tls_current_object);
-       current_object_key=TlsAlloc();
+       mono_native_tls_alloc (&current_object_key, NULL);
        THREAD_DEBUG (g_message ("%s: Allocated current_object_key %d", __func__, current_object_key));
 
        mono_thread_start_cb = start_cb;
@@ -2474,7 +2478,7 @@ void mono_thread_cleanup (void)
        CloseHandle (background_change_event);
 #endif
 
-       TlsFree (current_object_key);
+       mono_native_tls_free (current_object_key);
 }
 
 void
@@ -3076,7 +3080,7 @@ static void
 print_thread_dump (MonoInternalThread *thread, MonoThreadInfo *info)
 {
        GString* text = g_string_new (0);
-       char *name, *wapi_desc;
+       char *name;
        GError *error = NULL;
 
        if (thread->name) {
@@ -3128,7 +3132,7 @@ dump_thread (gpointer key, gpointer value, gpointer user)
        We probably should loop a bit around trying to get it to either managed code
        or WSJ state.
        */
-       info = mono_thread_info_safe_suspend_sync ((pthread_t)(gpointer)(gsize)thread->tid, FALSE);
+       info = mono_thread_info_safe_suspend_sync ((MonoNativeThreadId)(gpointer)(gsize)thread->tid, FALSE);
 
        if (!info)
                return;
@@ -3761,7 +3765,7 @@ free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
        if (!thread->static_data || !thread->static_data [idx])
                return;
        ptr = ((char*) thread->static_data [idx]) + (data->offset & 0xffffff);
-       memset (ptr, 0, data->size);
+       mono_gc_bzero (ptr, data->size);
 }
 
 static void
@@ -4410,6 +4414,8 @@ abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception,
 {
        MonoJitInfo *ji;
        MonoThreadInfo *info = NULL;
+       gboolean protected_wrapper;
+       gboolean running_managed;
 
        if (!mono_thread_info_new_interrupt_enabled ()) {
                signal_thread_state_change (thread);
@@ -4425,7 +4431,9 @@ abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception,
                MonoException *exc = mono_thread_request_interruption (can_raise_exception); 
                if (exc)
                        mono_raise_exception (exc);
+#ifndef HOST_WIN32
                wapi_interrupt_thread (thread->handle);
+#endif
                return;
        }
 
@@ -4446,8 +4454,8 @@ abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception,
        }
 
        ji = mono_thread_info_get_last_managed (info);
-       gboolean protected_wrapper = ji && mono_threads_is_critical_method (ji->method);
-       gboolean running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&info->suspend_state.ctx));
+       protected_wrapper = ji && mono_threads_is_critical_method (ji->method);
+       running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&info->suspend_state.ctx));
 
        if (!protected_wrapper && running_managed) {
                /*We are in managed code*/
@@ -4465,7 +4473,9 @@ abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception,
                 */
                InterlockedIncrement (&thread_interruption_requested);
                mono_thread_info_resume (mono_thread_info_get_tid (info));
+#ifndef HOST_WIN32
                wapi_interrupt_thread (thread->handle);
+#endif
        }
        /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
 }
@@ -4476,7 +4486,7 @@ transition_to_suspended (MonoInternalThread *thread)
        if ((thread->state & ThreadState_SuspendRequested) == 0) {
                g_assert (0); /*FIXME we should not reach this */
                /*Make sure we balance the suspend count.*/
-               mono_thread_info_resume ((pthread_t)(gpointer)(gsize)thread->tid);
+               mono_thread_info_resume ((MonoNativeThreadId)(gpointer)(gsize)thread->tid);
        } else {
                thread->state &= ~ThreadState_SuspendRequested;
                thread->state |= ThreadState_Suspended;
@@ -4507,8 +4517,10 @@ suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt)
                } else {
                        if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
                                InterlockedIncrement (&thread_interruption_requested);
+#ifndef HOST_WIN32
                        if (interrupt)
                                wapi_interrupt_thread (thread->handle);
+#endif
                        mono_thread_info_resume (mono_thread_info_get_tid (info));
                        LeaveCriticalSection (thread->synch_cs);
                }
@@ -4584,7 +4596,7 @@ resume_thread_internal (MonoInternalThread *thread)
 
        LeaveCriticalSection (thread->synch_cs);        
        /* Awake the thread */
-       if (!mono_thread_info_resume ((pthread_t)(gpointer)(gsize)thread->tid))
+       if (!mono_thread_info_resume ((MonoNativeThreadId)(gpointer)(gsize)thread->tid))
                return FALSE;
        EnterCriticalSection (thread->synch_cs);
        thread->state &= ~ThreadState_Suspended;