Mon Apr 6 14:09:53 CEST 2009 Paolo Molaro <lupus@ximian.com>
authorPaolo Molaro <lupus@oddwiz.org>
Mon, 6 Apr 2009 12:12:28 +0000 (12:12 -0000)
committerPaolo Molaro <lupus@oddwiz.org>
Mon, 6 Apr 2009 12:12:28 +0000 (12:12 -0000)
* tasklets.h, tasklets.c, mini.h, mini.c, Makefile.am: arch-indep
part of tasklet/continuation support.

svn path=/trunk/mono/; revision=131109

mono/mini/ChangeLog
mono/mini/Makefile.am
mono/mini/mini.c
mono/mini/mini.h
mono/mini/tasklets.c [new file with mode: 0644]
mono/mini/tasklets.h [new file with mode: 0644]

index 0ec22e3004e629224765cae9dbe6f67ef1682b83..c5ec2b40a5fc794a53593afca8e58a47c68d7a92 100644 (file)
@@ -1,3 +1,9 @@
+
+Mon Apr 6 14:09:53 CEST 2009 Paolo Molaro <lupus@ximian.com>
+
+       * tasklets.h, tasklets.c, mini.h, mini.c, Makefile.am: arch-indep
+       part of tasklet/continuation support.
+
 2009-04-05  Zoltan Varga  <vargaz@gmail.com>
 
        * mini-llvm.c (mono_llvm_emit_method): Move the handling of
index 129c9d62ef6a96e694c6b375f12faead2e3ff0e5..afd201a2e09446f40bf88d78770f8ae43c0dc2b5 100644 (file)
@@ -273,6 +273,8 @@ common_sources = \
        mini-generic-sharing.c  \
        regalloc2.c             \
        simd-methods.h          \
+       tasklets.c              \
+       tasklets.h              \
        simd-intrinsics.c       \
        unwind.h                \
        unwind.c                \
index 23ce7cba11c64f76462eece4f422f116e6fa3fa4..b60ae8bb235d8be27cb26275708fc7a5c50cb60b 100644 (file)
@@ -55,6 +55,7 @@
 #include <mono/utils/dtrace.h>
 
 #include "mini.h"
+#include "tasklets.h"
 #include <string.h>
 #include <ctype.h>
 #include "trace.h"
@@ -4931,6 +4932,10 @@ mini_init (const char *filename, const char *runtime_version)
        mono_simd_intrinsics_init ();
 #endif
 
+#if MONO_SUPPORT_TASKLETS
+       mono_tasklets_init ();
+#endif
+
        if (mono_compile_aot)
                /* 
                 * Avoid running managed code when AOT compiling, since the platform
index a2d044cfdb89295f38f3b23647575045cb29d352..5062f1d5441d4998fa5ed7ba1cbe9562f094bf57 100644 (file)
@@ -54,6 +54,10 @@ typedef gint64 mgreg_t;
 #define MINI_DEBUG(level,limit,code) do {if (G_UNLIKELY ((level) >= (limit))) code} while (0)
 #endif
 
+#if !defined(DISABLE_TASKLETS) && defined(MONO_ARCH_SUPPORT_TASKLETS) && defined(__GNUC__)
+#define MONO_SUPPORT_TASKLETS 1
+#endif
+
 #if ENABLE_LLVM
 #define COMPILE_LLVM(cfg) ((cfg)->compile_llvm)
 #else
diff --git a/mono/mini/tasklets.c b/mono/mini/tasklets.c
new file mode 100644 (file)
index 0000000..fb48687
--- /dev/null
@@ -0,0 +1,158 @@
+
+#include "config.h"
+#include "tasklets.h"
+#include "mono/metadata/exception.h"
+#include "mono/metadata/gc-internal.h"
+#include "mini.h"
+
+#if defined(MONO_SUPPORT_TASKLETS)
+
+/* keepalive_stacks could be a per-stack var to avoid locking overhead */
+static MonoGHashTable *keepalive_stacks = NULL;
+static CRITICAL_SECTION tasklets_mutex;
+#define tasklets_lock() EnterCriticalSection(&tasklets_mutex)
+#define tasklets_unlock() LeaveCriticalSection(&tasklets_mutex)
+
+/* LOCKING: tasklets_mutex is assumed to e taken */
+static void
+internal_init (void)
+{
+       if (keepalive_stacks)
+               return;
+       MONO_GC_REGISTER_ROOT (keepalive_stacks);
+       keepalive_stacks = mono_g_hash_table_new (NULL, NULL);
+}
+
+static void*
+continuation_alloc (void)
+{
+       MonoContinuation *cont = g_new0 (MonoContinuation, 1);
+       return cont;
+}
+
+static void
+continuation_free (MonoContinuation *cont)
+{
+       if (cont->saved_stack) {
+               tasklets_lock ();
+               mono_g_hash_table_remove (keepalive_stacks, cont->saved_stack);
+               tasklets_unlock ();
+               mono_gc_free_fixed (cont->saved_stack);
+       }
+       g_free (cont);
+}
+
+static MonoException*
+continuation_mark_frame (MonoContinuation *cont)
+{
+       MonoJitTlsData *jit_tls;
+       MonoLMF *lmf;
+       MonoContext ctx, new_ctx;
+       MonoJitInfo *ji, rji;
+       int endloop = FALSE;
+
+       if (cont->domain)
+               return mono_get_exception_argument ("cont", "Already marked");
+
+       jit_tls = TlsGetValue (mono_jit_tls_id);
+       lmf = mono_get_lmf();
+       cont->domain = mono_domain_get ();
+       cont->thread_id = GetCurrentThreadId ();
+
+       /* get to the frame that called Mark () */
+       memset (&rji, 0, sizeof (rji));
+       do {
+               ji = mono_find_jit_info (cont->domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, NULL, NULL);
+               if (!ji || ji == (gpointer)-1) {
+                       return mono_get_exception_not_supported ("Invalid stack frame");
+               }
+               ctx = new_ctx;
+               if (endloop)
+                       break;
+               if (strcmp (ji->method->name, "Mark") == 0)
+                       endloop = TRUE;
+       } while (1);
+
+       cont->top_sp = MONO_CONTEXT_GET_SP (&ctx);
+       /*g_print ("method: %s, sp: %p\n", ji->method->name, cont->top_sp);*/
+
+       return NULL;
+}
+
+static MonoException*
+continuation_store (MonoContinuation *cont, int state, int *rstate)
+{
+       MonoLMF *lmf = mono_get_lmf ();
+       gsize num_bytes;
+
+       if (!cont->domain)
+               return mono_get_exception_argument ("cont", "Continuation not initialized");
+       if (cont->domain != mono_domain_get () || cont->thread_id != GetCurrentThreadId ())
+               return mono_get_exception_argument ("cont", "Continuation from another thread or domain");
+
+       cont->lmf = lmf;
+       cont->return_ip = __builtin_return_address (0);
+       cont->return_sp = __builtin_frame_address (0);
+
+       num_bytes = (char*)cont->top_sp - (char*)cont->return_sp;
+
+       /*g_print ("store: %d bytes, sp: %p, ip: %p, lmf: %p\n", num_bytes, cont->return_sp, cont->return_ip, lmf);*/
+
+       if (cont->saved_stack && num_bytes <= cont->stack_alloc_size) {
+               /* clear to avoid GC retention */
+               if (num_bytes < cont->stack_used_size)
+                       memset ((char*)cont->saved_stack + num_bytes, 0, cont->stack_used_size - num_bytes);
+       } else {
+               tasklets_lock ();
+               internal_init ();
+               if (cont->saved_stack) {
+                       mono_g_hash_table_remove (keepalive_stacks, cont->saved_stack);
+                       mono_gc_free_fixed (cont->saved_stack);
+               }
+               cont->stack_used_size = num_bytes;
+               cont->stack_alloc_size = num_bytes * 1.1;
+               cont->saved_stack = mono_gc_alloc_fixed (cont->stack_alloc_size, NULL);
+               mono_g_hash_table_insert (keepalive_stacks, cont->saved_stack, cont->saved_stack);
+               tasklets_unlock ();
+       }
+       memcpy (cont->saved_stack, cont->return_sp, num_bytes);
+       *rstate = state;
+       return NULL;
+}
+
+static MonoException*
+continuation_restore (MonoContinuation *cont, int state)
+{
+       MonoLMF **lmf_addr = mono_get_lmf_addr ();
+       MonoContinuationRestore restore_state = mono_tasklets_arch_restore ();
+
+       if (!cont->domain || !cont->return_sp)
+               return mono_get_exception_argument ("cont", "Continuation not initialized");
+       if (cont->domain != mono_domain_get () || cont->thread_id != GetCurrentThreadId ())
+               return mono_get_exception_argument ("cont", "Continuation from another thread or domain");
+
+       /*g_print ("restore: %p, state: %d\n", cont, state);*/
+       *lmf_addr = cont->lmf;
+       restore_state (cont, state, lmf_addr);
+       g_assert_not_reached ();
+}
+
+void
+mono_tasklets_init (void)
+{
+       InitializeCriticalSection (&tasklets_mutex);
+
+       mono_add_internal_call ("Mono.Tasklets.Continuation::alloc", continuation_alloc);
+       mono_add_internal_call ("Mono.Tasklets.Continuation::free", continuation_free);
+       mono_add_internal_call ("Mono.Tasklets.Continuation::mark", continuation_mark_frame);
+       mono_add_internal_call ("Mono.Tasklets.Continuation::store", continuation_store);
+       mono_add_internal_call ("Mono.Tasklets.Continuation::restore", continuation_restore);
+}
+
+void
+mono_tasklets_cleanup (void)
+{
+}
+
+#endif
+
diff --git a/mono/mini/tasklets.h b/mono/mini/tasklets.h
new file mode 100644 (file)
index 0000000..8275628
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef __MONO_TASKLETS_H__
+#define __MONO_TASKLETS_H__
+
+#include "mini.h"
+
+typedef struct {
+       MonoLMF *lmf;
+       gpointer top_sp;
+       gsize thread_id;
+       MonoDomain *domain;
+
+       /* the instruction pointer and stack to return to on Restore */
+       gpointer return_ip;
+       gpointer return_sp;
+
+       /* the saved stack information */
+       int stack_alloc_size;
+       int stack_used_size;
+       /* pointer to GC memory */
+       gpointer saved_stack;
+} MonoContinuation;
+
+typedef void (*MonoContinuationRestore) (MonoContinuation *cont, int state, MonoLMF **lmf_addr);
+
+void  mono_tasklets_init    (void) MONO_INTERNAL;
+void  mono_tasklets_cleanup (void) MONO_INTERNAL;
+
+MonoContinuationRestore mono_tasklets_arch_restore (void) MONO_INTERNAL;
+
+#endif /* __MONO_TASKLETS_H__ */
+