1 /* context_java - implementation of context switching for java threads */
3 /* Copyright (c) 2009-2010, 2012-2014. The SimGrid Team.
4 * All rights reserved. */
6 /* This program is free software; you can redistribute it and/or modify it
7 * under the terms of the license (GNU LGPL) which comes with this package. */
9 #include <xbt/function_types.h>
10 #include <simgrid/simix.h>
12 #include "smx_context_java.h"
13 #include "jxbt_utilities.h"
14 #include "xbt/dynar.h"
15 extern JavaVM *__java_vm;
17 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(jmsg, bindings, "MSG for Java(TM)");
20 smx_ctx_java_factory_create_context(xbt_main_func_t code,
21 int argc, char **argv,
22 void_pfn_smxprocess_t cleanup_func,
23 smx_process_t process);
25 static void smx_ctx_java_free(smx_context_t context);
26 static void smx_ctx_java_suspend(smx_context_t context);
27 static void smx_ctx_java_resume(smx_context_t new_context);
28 static void smx_ctx_java_runall(void);
29 static void* smx_ctx_java_thread_run(void *data);
30 void SIMIX_ctx_java_factory_init(smx_context_factory_t * factory)
32 /* instantiate the context factory */
33 smx_ctx_base_factory_init(factory);
35 (*factory)->create_context = smx_ctx_java_factory_create_context;
36 /* Leave default behavior of (*factory)->finalize */
37 (*factory)->free = smx_ctx_java_free;
38 (*factory)->stop = smx_ctx_java_stop;
39 (*factory)->suspend = smx_ctx_java_suspend;
40 (*factory)->runall = smx_ctx_java_runall;
41 (*factory)->name = "ctx_java_factory";
42 //(*factory)->finalize = smx_ctx_base_factory_finalize;
43 (*factory)->self = smx_ctx_java_self;
44 (*factory)->get_process = smx_ctx_base_get_process;
46 smx_context_t smx_ctx_java_self(void)
48 return (smx_context_t)xbt_os_thread_get_extra_data();
52 smx_ctx_java_factory_create_context(xbt_main_func_t code,
53 int argc, char **argv,
54 void_pfn_smxprocess_t cleanup_func,
55 smx_process_t process)
57 static int thread_amount=0;
58 smx_ctx_java_t context = xbt_new0(s_smx_ctx_java_t, 1);
60 /* If the user provided a function for the process then use it
61 otherwise is the context for maestro */
64 context->jprocess = (jobject) code;
67 context->jprocess = NULL;
69 context->super.cleanup_func = cleanup_func;
70 context->begin = xbt_os_sem_init(0);
71 context->end = xbt_os_sem_init(0);
73 context->super.argc = argc;
74 context->super.argv = argv;
75 context->super.code = code;
78 context->thread = xbt_os_thread_create(NULL,smx_ctx_java_thread_run,context,NULL);
81 RETHROWF("Failed to create context #%d. You may want to switch to Java coroutines to increase your limits (error: %s)."
82 "See the Install section of simgrid-java documentation (in doc/install.html) for more on coroutines.",
86 context->thread = NULL;
87 xbt_os_thread_set_extra_data(context);
89 context->super.process = process;
91 return (smx_context_t) context;
94 static void* smx_ctx_java_thread_run(void *data) {
95 smx_ctx_java_t context = (smx_ctx_java_t)data;
96 xbt_os_thread_set_extra_data(context);
97 //Attach the thread to the JVM
99 _XBT_GNUC_UNUSED jint error = (*__java_vm)->AttachCurrentThread(__java_vm, (void **) &env, NULL);
100 xbt_assert((error == JNI_OK), "The thread could not be attached to the JVM");
101 context->jenv = get_current_thread_env();
102 //Wait for the first scheduling round to happen.
103 xbt_os_sem_acquire(context->begin);
104 //Create the "Process" object if needed.
105 if (context->super.argc > 0) {
106 context->super.code(context->super.argc, context->super.argv);
109 smx_process_t process = SIMIX_process_self();
110 (*env)->SetLongField(env, context->jprocess, jprocess_field_Process_bind,
114 // Adrien, ugly path, just to bypass creation of context at low levels
115 // (i.e such as for the VM migration for instance)
116 if(context->jprocess != NULL){
117 xbt_assert((context->jprocess != NULL), "Process not created...");
118 //wait for the process to be able to begin
120 jfieldID jprocess_field_Process_startTime = jxbt_get_sfield(env, "org/simgrid/msg/Process", "startTime", "D");
121 jdouble startTime = (*env)->GetDoubleField(env, context->jprocess, jprocess_field_Process_startTime);
122 if (startTime > MSG_get_clock()) {
123 MSG_process_sleep(startTime - MSG_get_clock());
125 //Execution of the "run" method.
126 jmethodID id = jxbt_get_smethod(env, "org/simgrid/msg/Process", "run", "()V");
127 xbt_assert( (id != NULL), "Method not found...");
128 (*env)->CallVoidMethod(env, context->jprocess, id);
130 smx_ctx_java_stop((smx_context_t)context);
135 static void smx_ctx_java_free(smx_context_t context)
138 smx_ctx_java_t ctx_java = (smx_ctx_java_t) context;
139 if (ctx_java->thread) { /* We are not in maestro context */
140 xbt_os_thread_join(ctx_java->thread, NULL);
141 xbt_os_sem_destroy(ctx_java->begin);
142 xbt_os_sem_destroy(ctx_java->end);
145 smx_ctx_base_free(context);
149 void smx_ctx_java_stop(smx_context_t context)
151 smx_ctx_java_t ctx_java = (smx_ctx_java_t)context;
152 /* I am the current process and I am dying */
153 if (context->iwannadie) {
154 context->iwannadie = 0;
155 JNIEnv *env = get_current_thread_env();
156 XBT_DEBUG("Gonnal launch Killed Error");
157 // TODO Adrien, if the process has not been created at the java layer, why should we raise the exception/error at the java level (this happens
158 // for instance during the migration process that creates at the C level two processes: one on the SRC node and one on the DST node, if the DST process is killed.
159 // it is not required to raise an exception at the JAVA level, the low level should be able to manage such an issue correctly but this is not the case right now unfortunately ...
160 // TODO it will be nice to have the name of the process to help the end-user to know which Process has been killed
161 jxbt_throw_by_name(env, "org/simgrid/msg/ProcessKilledError", bprintf("Process %s killed :) (file smx_context_java.c)", MSG_process_get_name( (msg_process_t)context) ));
162 XBT_DEBUG("Trigger a cancel error at the C level");
163 THROWF(cancel_error, 0, "process cancelled");
165 smx_ctx_base_stop(context);
166 /* detach the thread and kills it */
167 JNIEnv *env = ctx_java->jenv;
168 (*env)->DeleteGlobalRef(env,ctx_java->jprocess);
169 _XBT_GNUC_UNUSED jint error = (*__java_vm)->DetachCurrentThread(__java_vm);
170 xbt_assert((error == JNI_OK), "The thread couldn't be detached.");
171 xbt_os_sem_release(((smx_ctx_java_t)context)->end);
172 xbt_os_thread_exit(NULL);
176 static void smx_ctx_java_suspend(smx_context_t context)
178 smx_ctx_java_t ctx_java = (smx_ctx_java_t) context;
179 xbt_os_sem_release(ctx_java->end);
180 xbt_os_sem_acquire(ctx_java->begin);
183 // FIXME: inline those functions
184 static void smx_ctx_java_resume(smx_context_t new_context)
186 smx_ctx_java_t ctx_java = (smx_ctx_java_t) new_context;
187 xbt_os_sem_release(ctx_java->begin);
188 xbt_os_sem_acquire(ctx_java->end);
191 static void smx_ctx_java_runall(void)
193 xbt_dynar_t processes = SIMIX_process_get_runnable();
194 smx_process_t process;
196 xbt_dynar_foreach(processes, cursor, process) {
197 smx_ctx_java_resume(SIMIX_process_get_context(process));