Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Forgot coroutines files
authorSamuel Lepetit <samuel.lepetit@inria.fr>
Tue, 12 Jun 2012 13:18:14 +0000 (15:18 +0200)
committerSamuel Lepetit <samuel.lepetit@inria.fr>
Tue, 12 Jun 2012 13:18:14 +0000 (15:18 +0200)
src/smx_context_cojava.c [new file with mode: 0644]
src/smx_context_cojava.h [new file with mode: 0644]

diff --git a/src/smx_context_cojava.c b/src/smx_context_cojava.c
new file mode 100644 (file)
index 0000000..66e1899
--- /dev/null
@@ -0,0 +1,268 @@
+/* context_cojava - implementation of context switching for java coroutines */
+
+/* Copyright 2012. The SimGrid Team.
+ * All rights reserved.                                                     */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+
+#include <xbt/function_types.h>
+#include <simgrid/simix.h>
+#include <xbt/ex.h>
+#include "smx_context_cojava.h"
+#include "jxbt_utilities.h"
+#include "xbt/dynar.h"
+
+
+//Coroutine methodID/class cache.
+jclass coclass;
+jmethodID coroutine_init;
+jmethodID coroutine_yield;
+jmethodID coroutine_yieldTo;
+jmethodID coroutine_stop;
+//Maestro java coroutine
+jobject cojava_maestro_coroutine;
+
+JNIEnv *global_env;
+
+static smx_context_t my_current_context = NULL;
+static smx_context_t maestro_context = NULL;
+
+
+xbt_dynar_t cojava_processes;
+static unsigned long int cojava_process_index = 0;
+
+static JavaVM *get_current_vm(void);
+static JavaVM *get_current_vm(void)
+{
+       JavaVM *jvm;
+       JNI_GetCreatedJavaVMs(&jvm,1,NULL);
+  return jvm;
+}
+
+XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(jmsg);
+
+
+static smx_context_t
+smx_ctx_cojava_factory_create_context(xbt_main_func_t code, int argc,
+                                    char **argv,
+                                    void_pfn_smxprocess_t cleanup_func,
+                                    void *data);
+
+static void smx_ctx_cojava_free(smx_context_t context);
+static void smx_ctx_cojava_start(smx_context_t context);
+static void smx_ctx_cojava_suspend(smx_context_t context);
+static void smx_ctx_cojava_resume(smx_context_t new_context);
+static void smx_ctx_cojava_runall(void);
+static void* smx_ctx_cojava_run(void *data);
+static void smx_ctx_cojava_create_coroutine(smx_ctx_cojava_t context);
+void SIMIX_ctx_cojava_factory_init(smx_context_factory_t * factory)
+{
+  /* instantiate the context factory */
+  smx_ctx_base_factory_init(factory);
+
+  (*factory)->create_context = smx_ctx_cojava_factory_create_context;
+  /* Leave default behavior of (*factory)->finalize */
+  (*factory)->free = smx_ctx_cojava_free;
+  (*factory)->stop = smx_ctx_cojava_stop;
+  (*factory)->suspend = smx_ctx_cojava_suspend;
+  (*factory)->runall = smx_ctx_cojava_runall;
+  (*factory)->name = "ctx_cojava_factory";
+  //(*factory)->finalize = smx_ctx_base_factory_finalize;
+  (*factory)->self = smx_ctx_cojava_self;
+  (*factory)->get_data = smx_ctx_base_get_data;
+
+  global_env = get_current_thread_env();
+
+  coclass = (*global_env)->FindClass(global_env, "java/dyn/Coroutine");
+  xbt_assert((coclass != NULL), "Can't find java.dyn.Coroutine class.");
+  //Cache the method id we are going to use
+  coroutine_init = (*global_env)->GetMethodID(global_env, coclass, "<init>", "(Ljava/lang/Runnable;)V");
+  xbt_assert((coroutine_init != NULL), "Can't find <init>");
+  coroutine_stop = (*global_env)->GetMethodID(global_env, coclass, "stop", "()V");
+  xbt_assert((coroutine_stop != NULL), "Method not found...");
+  coroutine_yield = (*global_env)->GetStaticMethodID(global_env, coclass, "yield", "()V");
+       xbt_assert((coroutine_yield != NULL), "Method yield not found.");
+       coroutine_yieldTo = (*global_env)->GetStaticMethodID(global_env, coclass, "yieldTo", "(Ljava/dyn/Coroutine;)V");
+       xbt_assert((coroutine_yieldTo != NULL), "Method yieldTo not found.");
+
+       jclass class_thread = (*global_env)->FindClass(global_env, "java/lang/Thread");
+       xbt_assert((class_thread != NULL), "Can't find java.lang.Thread class");
+       jclass class_coroutine_support = (*global_env)->FindClass(global_env, "java/dyn/CoroutineSupport");
+       xbt_assert((class_coroutine_support != NULL), "Can't find java.dyn.CoroutineSupport class");
+       jmethodID thread_get_current = (*global_env)->GetStaticMethodID(global_env, class_thread, "currentThread", "()Ljava/lang/Thread;");
+       xbt_assert((thread_get_current != NULL), "Can't find Thread.currentThread() method.");
+
+       /**
+        * Retrieve maetro coroutine object
+        */
+       jobject jthread;
+       jthread = (*global_env)->CallStaticObjectMethod(global_env, class_thread, thread_get_current);
+       xbt_assert((jthread != NULL), "Can't find current thread.");
+
+       jmethodID thread_get_coroutine_support = (*global_env)->GetMethodID(global_env, class_thread, "getCoroutineSupport", "()Ljava/dyn/CoroutineSupport;");
+       xbt_assert((thread_get_coroutine_support != NULL), "Can't find Thread.getCoroutineSupport method");
+
+       jobject jcoroutine_support;
+       jcoroutine_support = (*global_env)->CallObjectMethod(global_env, jthread, thread_get_coroutine_support);
+       xbt_assert((jcoroutine_support != NULL), "Can't find coroutine support object");
+       //FIXME ? Be careful, might change in the implementation (we are relying on private fields, so...).
+       jfieldID coroutine_support_thread_coroutine = (*global_env)->GetFieldID(global_env, class_coroutine_support, "threadCoroutine", "Ljava/dyn/Coroutine;");
+       xbt_assert((coroutine_support_thread_coroutine != NULL), "Can't find threadCoroutine field");
+       cojava_maestro_coroutine = (jobject)(*global_env)->GetObjectField(global_env, jcoroutine_support, coroutine_support_thread_coroutine);
+       xbt_assert((cojava_maestro_coroutine != NULL), "Can't find the thread coroutine.");
+       cojava_maestro_coroutine = (*global_env)->NewGlobalRef(global_env, cojava_maestro_coroutine);
+       xbt_assert((cojava_maestro_coroutine != NULL), "Can't get a global reference to the thread coroutine.");
+}
+smx_context_t smx_ctx_cojava_self(void)
+{
+       return my_current_context;
+}
+
+static smx_context_t
+smx_ctx_cojava_factory_create_context(xbt_main_func_t code, int argc,
+                                    char **argv,
+                                    void_pfn_smxprocess_t cleanup_func,
+                                    void* data)
+{
+       smx_ctx_cojava_t context = xbt_new0(s_smx_ctx_cojava_t, 1);
+  /* If the user provided a function for the process then use it
+     otherwise is the context for maestro */
+  if (code) {
+               if (argc == 0) {
+                       context->jprocess = (jobject) code;
+               }
+               else {
+                       context->jprocess = NULL;
+               }
+               context->super.cleanup_func = cleanup_func;
+
+               context->super.argc = argc;
+               context->super.argv = argv;
+               context->super.code = code;
+
+               smx_ctx_cojava_run(context);
+  }
+  else {
+       context->jcoroutine = NULL;
+       my_current_context = (smx_context_t)context;
+       maestro_context = (smx_context_t)context;
+  }
+  context->bound = 0;
+  context->super.data = data;
+  return (smx_context_t) context;
+}
+
+static void* smx_ctx_cojava_run(void *data) {
+       smx_ctx_cojava_t context = (smx_ctx_cojava_t)data;
+       my_current_context = (smx_context_t)context;
+       //Create the "Process" object if needed.
+       if (context->super.argc <= 0) {
+               smx_ctx_cojava_create_coroutine(context);
+       }
+       my_current_context = maestro_context;
+  return NULL;
+}
+static void smx_ctx_cojava_free(smx_context_t context)
+{
+       if (context) {
+               smx_ctx_cojava_t ctx_java = (smx_ctx_cojava_t) context;
+               if (ctx_java->jcoroutine) { /* We are not in maestro context */
+                       JNIEnv *env = get_current_thread_env();
+                       (*env)->DeleteGlobalRef(env, ctx_java->jcoroutine);
+                       (*env)->DeleteGlobalRef(env, ctx_java->jprocess);
+               }
+  }
+  smx_ctx_base_free(context);
+}
+
+
+void smx_ctx_cojava_stop(smx_context_t context)
+{
+       /*
+        * The java stack needs to be empty, otherwise weird stuff
+        * will happen
+        */
+       if (context->iwannadie == -1) {
+       context->iwannadie = 0;
+       JNIEnv *env = get_current_thread_env();
+       jxbt_throw_by_name(env, "org/simgrid/msg/ProcessKilledError", bprintf("Process killed :)"));
+       THROWF(cancel_error, 0, "process cancelled");
+  }
+       else {
+               smx_ctx_base_stop(context);
+               smx_ctx_cojava_suspend(context);
+       }
+}
+
+static void smx_ctx_cojava_suspend(smx_context_t context)
+{
+       smx_context_t previous_context = context;
+       unsigned long int i = cojava_process_index++;
+       jobject next_coroutine;
+
+       if (i < xbt_dynar_length(cojava_processes)) {
+               smx_context_t next_context = SIMIX_process_get_context(xbt_dynar_get_as(
+                               cojava_processes,i, smx_process_t));
+               my_current_context = next_context;
+               XBT_DEBUG("Switching to %p",my_current_context);
+               smx_ctx_cojava_t java_context = (smx_ctx_cojava_t)(next_context);
+
+               if (!java_context->jprocess) {
+                       (*(java_context->super.code))(java_context->super.argc, java_context->super.argv);
+                       smx_ctx_cojava_create_coroutine(java_context);
+               }
+               else if (!java_context->bound) {
+                       java_context->bound = 1;
+                       smx_process_t process = SIMIX_process_self();
+                       (*global_env)->SetLongField(global_env, java_context->jprocess, jprocess_field_Process_bind, (jlong)process);
+               }
+
+               next_coroutine = java_context->jcoroutine;
+       }
+       else {
+               //Give maestro the control back.
+               next_coroutine = cojava_maestro_coroutine;
+               my_current_context = maestro_context;
+       }
+  (*global_env)->CallStaticVoidMethod(global_env, coclass, coroutine_yieldTo, next_coroutine);
+  my_current_context = previous_context;
+}
+
+static void smx_ctx_cojava_resume(smx_context_t new_context) {
+       my_current_context = new_context;
+       smx_ctx_cojava_t java_context = (smx_ctx_cojava_t)(new_context);
+
+       if (!java_context->jprocess) {
+               (*(java_context->super.code))(java_context->super.argc, java_context->super.argv);
+               smx_ctx_cojava_create_coroutine(java_context);
+               java_context->bound = 1;
+       }
+       else if (!java_context->bound) {
+               java_context->bound = 1;
+               smx_process_t process = SIMIX_process_self();
+               (*global_env)->SetLongField(global_env, java_context->jprocess, jprocess_field_Process_bind, (jlong)process);
+       }
+  (*global_env)->CallStaticVoidMethod(global_env, coclass, coroutine_yieldTo, java_context->jcoroutine);
+}
+
+static void smx_ctx_cojava_runall(void)
+{
+  cojava_processes = SIMIX_process_get_runnable();
+       smx_process_t process;
+       process = xbt_dynar_get_as(cojava_processes, 0, smx_process_t);
+       cojava_process_index = 1;
+       /* Execute the first process */
+       smx_ctx_cojava_resume(SIMIX_process_get_context(process));
+}
+
+static void smx_ctx_cojava_create_coroutine(smx_ctx_cojava_t context) {
+       JNIEnv *env = get_current_thread_env();
+       jclass coclass = (*env)->FindClass(env, "java/dyn/Coroutine");
+  xbt_assert((coclass != NULL), "Can't find coroutine class ! :(");
+  jobject jcoroutine = (*env)->NewObject(env, coclass, coroutine_init, context->jprocess);
+  xbt_assert((jcoroutine != NULL), "Can't create coroutine object.");
+  jcoroutine = (*env)->NewGlobalRef(env, jcoroutine);
+  context->jcoroutine = jcoroutine;
+}
diff --git a/src/smx_context_cojava.h b/src/smx_context_cojava.h
new file mode 100644 (file)
index 0000000..1f7a8de
--- /dev/null
@@ -0,0 +1,32 @@
+/* Copyright (c) 2012. The SimGrid Team.
+ * All rights reserved.                                                     */
+
+/* This program is free software; you can redistribute it and/or modify it
+  * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#ifndef _XBT_CONTEXT_COJAVA_H
+#define _XBT_CONTEXT_COJAVA_H
+
+#include <xbt/misc.h>
+#include <simgrid/simix.h>
+#include <xbt/xbt_os_thread.h>
+
+#include "jmsg.h"
+#include "jmsg_process.h"
+
+SG_BEGIN_DECL()
+
+typedef struct s_smx_ctx_cojava {
+  s_smx_ctx_base_t super;       /* Fields of super implementation */
+  jobject jprocess;             /* the java process instance binded with the msg process structure */
+  JNIEnv *jenv;                 /* jni interface pointer associated to this thread */
+  jobject jcoroutine;                                          /* java coroutine object */
+  int bound:1;
+} s_smx_ctx_cojava_t, *smx_ctx_cojava_t;
+
+void SIMIX_ctx_cojava_factory_init(smx_context_factory_t *factory);
+void smx_ctx_cojava_stop(smx_context_t context);
+smx_context_t smx_ctx_cojava_self(void);
+SG_END_DECL()
+
+#endif                          /* !_XBT_CONTEXT_JAVA_H */