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 #include "../../simix/smx_private.h"
16 extern JavaVM *__java_vm;
18 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(jmsg, bindings, "MSG for Java(TM)");
21 smx_ctx_java_factory_create_context(xbt_main_func_t code,
22 int argc, char **argv,
23 void_pfn_smxprocess_t cleanup_func,
24 smx_process_t process);
26 static void smx_ctx_java_free(smx_context_t context);
27 static void smx_ctx_java_suspend(smx_context_t context);
28 static void smx_ctx_java_resume(smx_context_t new_context);
29 static void smx_ctx_java_runall(void);
30 static void* smx_ctx_java_thread_run(void *data);
31 void SIMIX_ctx_java_factory_init(smx_context_factory_t * factory)
33 /* instantiate the context factory */
34 smx_ctx_base_factory_init(factory);
36 (*factory)->create_context = smx_ctx_java_factory_create_context;
37 /* Leave default behavior of (*factory)->finalize */
38 (*factory)->free = smx_ctx_java_free;
39 (*factory)->stop = smx_ctx_java_stop;
40 (*factory)->suspend = smx_ctx_java_suspend;
41 (*factory)->runall = smx_ctx_java_runall;
42 (*factory)->name = "ctx_java_factory";
43 //(*factory)->finalize = smx_ctx_base_factory_finalize;
44 (*factory)->self = smx_ctx_java_self;
45 (*factory)->get_process = smx_ctx_base_get_process;
47 smx_context_t smx_ctx_java_self(void)
49 return (smx_context_t)xbt_os_thread_get_extra_data();
53 smx_ctx_java_factory_create_context(xbt_main_func_t code,
54 int argc, char **argv,
55 void_pfn_smxprocess_t cleanup_func,
56 smx_process_t process)
58 static int thread_amount=0;
59 smx_ctx_java_t context = xbt_new0(s_smx_ctx_java_t, 1);
61 /* If the user provided a function for the process then use it
62 otherwise is the context for maestro */
65 context->jprocess = (jobject) code;
68 context->jprocess = NULL;
70 context->super.cleanup_func = cleanup_func;
71 context->begin = xbt_os_sem_init(0);
72 context->end = xbt_os_sem_init(0);
74 context->super.argc = argc;
75 context->super.argv = argv;
76 context->super.code = code;
79 context->thread = xbt_os_thread_create(NULL,smx_ctx_java_thread_run,context,NULL);
82 RETHROWF("Failed to create context #%d. You may want to switch to Java coroutines to increase your limits (error: %s)."
83 "See the Install section of simgrid-java documentation (in doc/install.html) for more on coroutines.",
87 context->thread = NULL;
88 xbt_os_thread_set_extra_data(context);
90 context->super.process = process;
92 return (smx_context_t) context;
95 static void* smx_ctx_java_thread_run(void *data) {
96 smx_ctx_java_t context = (smx_ctx_java_t)data;
97 xbt_os_thread_set_extra_data(context);
98 //Attach the thread to the JVM
100 XBT_ATTRIB_UNUSED jint error = (*__java_vm)->AttachCurrentThread(__java_vm, (void **) &env, NULL);
101 xbt_assert((error == JNI_OK), "The thread could not be attached to the JVM");
102 context->jenv = get_current_thread_env();
103 //Wait for the first scheduling round to happen.
104 xbt_os_sem_acquire(context->begin);
105 //Create the "Process" object if needed.
106 if (context->super.argc > 0) {
107 context->super.code(context->super.argc, context->super.argv);
110 smx_process_t process = SIMIX_process_self();
111 (*env)->SetLongField(env, context->jprocess, jprocess_field_Process_bind,
115 // Adrien, ugly path, just to bypass creation of context at low levels
116 // (i.e such as for the VM migration for instance)
117 if(context->jprocess != NULL){
118 xbt_assert((context->jprocess != NULL), "Process not created...");
119 //wait for the process to be able to begin
121 jfieldID jprocess_field_Process_startTime = jxbt_get_sfield(env, "org/simgrid/msg/Process", "startTime", "D");
122 jdouble startTime = (*env)->GetDoubleField(env, context->jprocess, jprocess_field_Process_startTime);
123 if (startTime > MSG_get_clock()) {
124 MSG_process_sleep(startTime - MSG_get_clock());
126 //Execution of the "run" method.
127 jmethodID id = jxbt_get_smethod(env, "org/simgrid/msg/Process", "run", "()V");
128 xbt_assert( (id != NULL), "Method not found...");
129 (*env)->CallVoidMethod(env, context->jprocess, id);
131 smx_ctx_java_stop((smx_context_t)context);
136 static void smx_ctx_java_free(smx_context_t context)
139 smx_ctx_java_t ctx_java = (smx_ctx_java_t) context;
140 if (ctx_java->thread) { /* We are not in maestro context */
141 xbt_os_thread_join(ctx_java->thread, NULL);
142 xbt_os_sem_destroy(ctx_java->begin);
143 xbt_os_sem_destroy(ctx_java->end);
146 smx_ctx_base_free(context);
150 void smx_ctx_java_stop(smx_context_t context)
152 smx_ctx_java_t ctx_java = (smx_ctx_java_t)context;
153 /* I am the current process and I am dying */
154 if (context->iwannadie) {
155 context->iwannadie = 0;
156 JNIEnv *env = get_current_thread_env();
157 XBT_DEBUG("Gonna launch Killed Error");
158 // 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
159 // 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.
160 // 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 ...
161 // TODO it will be nice to have the name of the process to help the end-user to know which Process has been killed
162 // 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) ));
163 jxbt_throw_by_name(env, "org/simgrid/msg/ProcessKilledError", bprintf("Process %s killed :) (file smx_context_java.c)", simcall_process_get_name((smx_process_t) SIMIX_context_get_process(context))) );
164 XBT_DEBUG("Trigger a cancel error at the C level");
165 THROWF(cancel_error, 0, "process cancelled");
167 smx_ctx_base_stop(context);
168 /* detach the thread and kills it */
169 JNIEnv *env = ctx_java->jenv;
170 (*env)->DeleteGlobalRef(env,ctx_java->jprocess);
171 XBT_ATTRIB_UNUSED jint error = (*__java_vm)->DetachCurrentThread(__java_vm);
172 xbt_assert((error == JNI_OK), "The thread couldn't be detached.");
173 xbt_os_sem_release(((smx_ctx_java_t)context)->end);
174 xbt_os_thread_exit(NULL);
178 static void smx_ctx_java_suspend(smx_context_t context)
180 smx_ctx_java_t ctx_java = (smx_ctx_java_t) context;
181 xbt_os_sem_release(ctx_java->end);
182 xbt_os_sem_acquire(ctx_java->begin);
185 // FIXME: inline those functions
186 static void smx_ctx_java_resume(smx_context_t new_context)
188 smx_ctx_java_t ctx_java = (smx_ctx_java_t) new_context;
189 xbt_os_sem_release(ctx_java->begin);
190 xbt_os_sem_acquire(ctx_java->end);
193 static void smx_ctx_java_runall(void)
195 xbt_dynar_t processes = SIMIX_process_get_runnable();
196 smx_process_t process;
198 xbt_dynar_foreach(processes, cursor, process) {
199 smx_ctx_java_resume(SIMIX_process_get_context(process));