From: Samuel Lepetit Date: Tue, 12 Jun 2012 15:57:06 +0000 (+0200) Subject: Merge scm.gforge.inria.fr:/gitroot/simgrid/simgrid-java X-Git-Tag: v3_9_90~569^2~19^2~56^2~1 X-Git-Url: http://info.iut-bm.univ-fcomte.fr/pub/gitweb/simgrid.git/commitdiff_plain/1f6232c64d77147f9a47e29f85dbeee71e925b0b?hp=412056feb3620f52a63ca3cdcc84c943218ccd29 Merge scm.gforge.inria.fr:/gitroot/simgrid/simgrid-java --- diff --git a/CMakeLists.txt b/CMakeLists.txt index e58b928ebc..327131ae71 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -72,6 +72,8 @@ include(FindJavaSG.cmake) # Declare our package content # ############################### set(JMSG_C_SRC + src/smx_context_cojava.h + src/smx_context_cojava.c src/smx_context_java.h src/smx_context_java.c src/jxbt_utilities.c diff --git a/org/simgrid/msg/Process.java b/org/simgrid/msg/Process.java index b726b8df69..714a7a3a75 100644 --- a/org/simgrid/msg/Process.java +++ b/org/simgrid/msg/Process.java @@ -392,6 +392,7 @@ public abstract class Process implements Runnable { catch(ProcessKilledError pk) { } + exit(); } /** @@ -402,7 +403,7 @@ public abstract class Process implements Runnable { */ public abstract void main(String[]args) throws MsgException; - + public native void exit(); /** * Class initializer, to initialize various JNI stuff */ diff --git a/org/simgrid/msg/RngStream.java b/org/simgrid/msg/RngStream.java index b1b0c9d2e4..5f4a8bf3b0 100644 --- a/org/simgrid/msg/RngStream.java +++ b/org/simgrid/msg/RngStream.java @@ -76,7 +76,7 @@ public class RngStream { */ public native void resetNextSubstream(); /** - * If a = true the stream g will start generating antithetic variates, i.e., 1 − U instead of U , until + * If a = true the stream g will start generating antithetic variates, i.e., 1 - U instead of U , until * this method is called again with a = false. */ public native void setAntithetic(boolean a); diff --git a/src/jmsg.c b/src/jmsg.c index aaf5b10819..92d5d979ca 100644 --- a/src/jmsg.c +++ b/src/jmsg.c @@ -12,6 +12,7 @@ #include #include "smx_context_java.h" +#include "smx_context_cojava.h" #include "jmsg_process.h" @@ -87,7 +88,18 @@ Java_org_simgrid_msg_Msg_init(JNIEnv * env, jclass cls, jobjectArray jargs) (*env)->GetJavaVM(env, &__java_vm); - smx_factory_initializer_to_use = SIMIX_ctx_java_factory_init; + if ((*env)->FindClass(env, "java/dyn/Coroutine")) { + XBT_VERB("Using Coroutines"); + smx_factory_initializer_to_use = SIMIX_ctx_cojava_factory_init; + } + else { + XBT_VERB("Using java threads"); + smx_factory_initializer_to_use = SIMIX_ctx_java_factory_init; + } + jthrowable exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->ExceptionClear(env); + } setlocale(LC_NUMERIC,"C"); @@ -231,7 +243,6 @@ static int create_jprocess(int argc, char *argv[]) { /* sets the PID and the PPID of the process */ (*env)->SetIntField(env, jprocess, jprocess_field_Process_pid,(jint) MSG_process_get_PID(process)); (*env)->SetIntField(env, jprocess, jprocess_field_Process_ppid, (jint) MSG_process_get_PPID(process)); - jprocess_bind(jprocess, process, env); return 0; diff --git a/src/jmsg_process.c b/src/jmsg_process.c index 47de57ad8c..dc3d26271b 100644 --- a/src/jmsg_process.c +++ b/src/jmsg_process.c @@ -11,9 +11,19 @@ #include "jmsg_host.h" #include "jxbt_utilities.h" #include "smx_context_java.h" +#include "smx_context_cojava.h" XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(jmsg); +JNIEXPORT void JNICALL +Java_org_simgrid_msg_Process_exit(JNIEnv *env, jobject jprocess) { + if (smx_factory_initializer_to_use == SIMIX_ctx_cojava_factory_init) { + m_process_t process = jprocess_to_native_process(jprocess, env); + smx_context_t context = MSG_process_get_smx_ctx(process); + smx_ctx_cojava_stop(context); + } +} + jobject native_to_java_process(m_process_t process) { return ((smx_ctx_java_t)MSG_process_get_smx_ctx(process))->jprocess; diff --git a/src/jmsg_process.h b/src/jmsg_process.h index 266f646487..7d5beadcd3 100644 --- a/src/jmsg_process.h +++ b/src/jmsg_process.h @@ -22,6 +22,9 @@ jfieldID jprocess_field_Process_name; jfieldID jprocess_field_Process_pid; jfieldID jprocess_field_Process_ppid; +JNIEXPORT void JNICALL +Java_org_simgrid_msg_Process_exit(JNIEnv *env, jobject); + jobject native_to_java_process(m_process_t process); diff --git a/src/jmsg_task.c b/src/jmsg_task.c index 9eb973c9f6..b7584644b4 100644 --- a/src/jmsg_task.c +++ b/src/jmsg_task.c @@ -56,7 +56,7 @@ Java_org_simgrid_msg_Task_nativeInit(JNIEnv *env, jclass cls) { if (!jtask_field_Task_bind || !jtask_class_Task || !jtask_field_Comm_bind || !jtask_field_Comm_taskBind || !jtask_field_Comm_receiving || !jtask_method_Comm_constructor) { jxbt_throw_native(env,bprintf("Can't find some fields in Java class.")); - } + } } JNIEXPORT void JNICALL @@ -410,7 +410,9 @@ Java_org_simgrid_msg_Task_receive(JNIEnv * env, jclass cls, jobject jhost) { MSG_error_t rv; - m_task_t task = NULL; + m_task_t *task = xbt_new(m_task_t,1); + *task = NULL; + m_host_t host = NULL; jobject jtask_global, jtask_local; const char *alias; @@ -426,7 +428,7 @@ Java_org_simgrid_msg_Task_receive(JNIEnv * env, jclass cls, alias = (*env)->GetStringUTFChars(env, jalias, 0); TRY { - rv = MSG_task_receive_ext(&task, alias, (double) jtimeout, host); + rv = MSG_task_receive_ext(task, alias, (double) jtimeout, host); } CATCH_ANONYMOUS { return NULL; @@ -435,15 +437,17 @@ Java_org_simgrid_msg_Task_receive(JNIEnv * env, jclass cls, jmsg_throw_status(env,rv); return NULL; } - jtask_global = MSG_task_get_data(task); + jtask_global = MSG_task_get_data(*task); /* Convert the global ref into a local ref so that the JVM can free the stuff */ jtask_local = (*env)->NewLocalRef(env, jtask_global); (*env)->DeleteGlobalRef(env, jtask_global); - MSG_task_set_data(task, NULL); + MSG_task_set_data(*task, NULL); (*env)->ReleaseStringUTFChars(env, jalias, alias); + xbt_free(task); + jxbt_check_res("MSG_task_receive_ext()", rv, MSG_HOST_FAILURE | MSG_TRANSFER_FAILURE | MSG_TIMEOUT, bprintf("while receiving from mailbox %s", alias)); diff --git a/src/smx_context_cojava.c b/src/smx_context_cojava.c new file mode 100644 index 0000000000..2905ece3ef --- /dev/null +++ b/src/smx_context_cojava.c @@ -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 +#include +#include +#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, "", "(Ljava/lang/Runnable;)V"); + xbt_assert((coroutine_init != NULL), "Can't find "); + 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) { + 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 index 0000000000..1f7a8dea49 --- /dev/null +++ b/src/smx_context_cojava.h @@ -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 +#include +#include + +#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 */ diff --git a/src/smx_context_java.h b/src/smx_context_java.h index 4142bf120c..084c5d4ade 100644 --- a/src/smx_context_java.h +++ b/src/smx_context_java.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, 2010. The SimGrid Team. +/* Copyright (c) 2009, 2010, 2012. The SimGrid Team. * All rights reserved. */ /* This program is free software; you can redistribute it and/or modify it