Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
make msg_vm_migrate robust (i.e. now SRC or DST can be turned off during the migratio...
[simgrid.git] / src / bindings / java / smx_context_java.c
1 /* context_java - implementation of context switching for java threads */
2
3 /* Copyright (c) 2009-2010, 2012-2014. The SimGrid Team.
4  * All rights reserved.                                                     */
5
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. */
8
9 #include <xbt/function_types.h>
10 #include <simgrid/simix.h>
11 #include <xbt/ex.h>
12 #include "smx_context_java.h"
13 #include "jxbt_utilities.h"
14 #include "xbt/dynar.h"
15 extern JavaVM *__java_vm;
16
17 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(jmsg, bindings, "MSG for Java(TM)");
18
19 static smx_context_t
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);
24
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)
31 {
32   /* instantiate the context factory */
33   smx_ctx_base_factory_init(factory);
34
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;
45 }
46 smx_context_t smx_ctx_java_self(void)
47 {
48         return (smx_context_t)xbt_os_thread_get_extra_data();
49 }
50
51 static smx_context_t
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)
56 {
57   static int thread_amount=0;
58   smx_ctx_java_t context = xbt_new0(s_smx_ctx_java_t, 1);
59   thread_amount++;
60   /* If the user provided a function for the process then use it
61      otherwise is the context for maestro */
62   if (code) {
63     if (argc == 0) {
64       context->jprocess = (jobject) code;
65     }
66     else {
67       context->jprocess = NULL;
68     }
69     context->super.cleanup_func = cleanup_func;
70     context->begin = xbt_os_sem_init(0);
71     context->end = xbt_os_sem_init(0);
72
73     context->super.argc = argc;
74     context->super.argv = argv;
75     context->super.code = code;
76
77     TRY {         
78        context->thread = xbt_os_thread_create(NULL,smx_ctx_java_thread_run,context,NULL);
79     }
80     CATCH_ANONYMOUS {
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.",
83                thread_amount);
84     }
85   } else {
86         context->thread = NULL;
87     xbt_os_thread_set_extra_data(context);
88   }
89   context->super.process = process;
90   
91   return (smx_context_t) context;
92 }
93
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
98   JNIEnv *env;
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);
107   }
108   else {
109     smx_process_t process = SIMIX_process_self();
110     (*env)->SetLongField(env, context->jprocess, jprocess_field_Process_bind,
111                          (intptr_t)process);
112   }
113
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
119         //TODO: Cache it
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());
124         }
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);
129   }
130   smx_ctx_java_stop((smx_context_t)context);
131
132   return NULL;
133 }
134
135 static void smx_ctx_java_free(smx_context_t context)
136 {
137   if (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);
143     }
144   }
145   smx_ctx_base_free(context);
146 }
147
148
149 void smx_ctx_java_stop(smx_context_t context)
150 {
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", xbt_strdup("Process killed :) (file smx_context_java.c)"));
162     XBT_DEBUG("Trigger a cancel error at the C level");
163     THROWF(cancel_error, 0, "process cancelled");
164   } else {
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);
173   }
174 }
175
176 static void smx_ctx_java_suspend(smx_context_t context)
177 {
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);
181 }
182
183 // FIXME: inline those functions
184 static void smx_ctx_java_resume(smx_context_t new_context)
185 {
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);
189 }
190
191 static void smx_ctx_java_runall(void)
192 {
193   xbt_dynar_t processes = SIMIX_process_get_runnable();
194   smx_process_t process;
195   unsigned int cursor;
196   xbt_dynar_foreach(processes, cursor, process) {
197     smx_ctx_java_resume(SIMIX_process_get_context(process));
198   }
199 }