Merge pull request #496 from nicolas-raoul/unit-test-for-issue2907
[mono.git] / mono / mini / mini-darwin.c
index 87b44f876c5f88d80d80da0f174f952e662183a5..5ec06d20a748c8036e64b9900bbc623f3a47b723 100644 (file)
@@ -5,7 +5,8 @@
  *   Mono Team (mono-list@lists.ximian.com)
  *
  * Copyright 2001-2003 Ximian, Inc.
- * Copyright 2003-2008 Ximian, Inc.
+ * Copyright 2003-2011 Novell, Inc (http://www.novell.com)
+ * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
  *
  * See LICENSE for licensing information.
  */
@@ -68,7 +69,7 @@
 #include <dlfcn.h>
 #include <AvailabilityMacros.h>
 
-#if (MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_5) && !defined (TARGET_ARM)
+#if defined (TARGET_OSX) && (MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_5)
 #define NEEDS_EXCEPTION_THREAD
 #endif
 
@@ -95,6 +96,15 @@ typedef struct {
 /* The exception port */
 static mach_port_t mach_exception_port = VM_MAP_NULL;
 
+kern_return_t
+catch_exception_raise (
+       mach_port_t exception_port,
+       mach_port_t thread,
+       mach_port_t task,
+       exception_type_t exception,
+       exception_data_t code,
+       mach_msg_type_number_t code_count);
+
 /*
  * Implicitly called by exc_server. Must be public.
  *
@@ -148,13 +158,17 @@ mach_exception_thread (void *arg)
                                   MACH_MSG_TIMEOUT_NONE,
                                   MACH_PORT_NULL);
 
-               g_assert (result == MACH_MSG_SUCCESS);
+               /*
+               If we try to abort the thread while delivering an exception. The port will be gone since the kernel
+               setup a send once port to deliver the resume message and thread_abort will consume it.
+               */
+               g_assert (result == MACH_MSG_SUCCESS || result == MACH_SEND_INVALID_DEST);
        }
        return NULL;
 }
 
 static void
-macosx_register_exception_handler ()
+macosx_register_exception_handler (void)
 {
        mach_port_t task;
        pthread_attr_t attr;
@@ -196,6 +210,8 @@ macosx_register_exception_handler ()
 /* This is #define'd by Boehm GC to _GC_dlopen. */
 #undef dlopen
 
+void* dlopen(const char* path, int mode);
+
 void
 mono_runtime_install_handlers (void)
 {
@@ -226,21 +242,21 @@ mono_runtime_syscall_fork ()
        return (pid_t) fork ();
 }
 
-gboolean
-mono_gdb_render_native_backtraces ()
+void
+mono_gdb_render_native_backtraces (pid_t crashed_pid)
 {
        const char *argv [5];
        char gdb_template [] = "/tmp/mono-gdb-commands.XXXXXX";
 
        argv [0] = g_find_program_in_path ("gdb");
        if (argv [0] == NULL) {
-               return FALSE;
+               return;
        }
 
        if (mkstemp (gdb_template) != -1) {
                FILE *gdb_commands = fopen (gdb_template, "w");
 
-               fprintf (gdb_commands, "attach %ld\n", (long) getpid ());
+               fprintf (gdb_commands, "attach %ld\n", (long) crashed_pid);
                fprintf (gdb_commands, "info threads\n");
                fprintf (gdb_commands, "thread apply all bt\n");
 
@@ -256,8 +272,6 @@ mono_gdb_render_native_backtraces ()
 
                unlink (gdb_template);
        }
-
-       return TRUE;
 }
 
 gboolean
@@ -271,6 +285,15 @@ mono_thread_state_init_from_handle (MonoThreadUnwindState *tctx, MonoNativeThrea
        guint32 domain_key, jit_key;
        MonoJitTlsData *jit_tls;
        void *domain;
+#if defined (MONO_ARCH_ENABLE_MONO_LMF_VAR)
+       guint32 lmf_key;
+#endif
+
+       /*Zero enough state to make sure the caller doesn't confuse itself*/
+       tctx->valid = FALSE;
+       tctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = NULL;
+       tctx->unwind_data [MONO_UNWIND_DATA_LMF] = NULL;
+       tctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = NULL;
 
        state = (thread_state_t) alloca (mono_mach_arch_get_thread_state_size ());
        mctx = (mcontext_t) alloca (mono_mach_arch_get_mcontext_size ());
@@ -284,18 +307,24 @@ mono_thread_state_init_from_handle (MonoThreadUnwindState *tctx, MonoNativeThrea
 
        mono_sigctx_to_monoctx (&ctx, &tctx->ctx);
 
-       domain_key = mono_domain_get_tls_offset ();
+       domain_key = mono_domain_get_tls_key ();
        jit_key = mono_get_jit_tls_key ();
+
        jit_tls = mono_mach_arch_get_tls_value_from_thread (thread_id, jit_key);
        domain = mono_mach_arch_get_tls_value_from_thread (thread_id, domain_key);
 
        /*Thread already started to cleanup, can no longer capture unwind state*/
-       if (!jit_tls)
+       if (!jit_tls || !domain)
                return FALSE;
-       g_assert (domain);
 
-       tctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = domain;
+#if defined (MONO_ARCH_ENABLE_MONO_LMF_VAR)
+       lmf_key =  mono_get_lmf_tls_offset ();
+       tctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_mach_arch_get_tls_value_from_thread (thread_id, lmf_key);;
+#else
        tctx->unwind_data [MONO_UNWIND_DATA_LMF] = jit_tls ? jit_tls->lmf : NULL;
+#endif
+
+       tctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = domain;
        tctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = jit_tls;
        tctx->valid = TRUE;