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_cojava.c
1 /* context_cojava - implementation of context switching for java coroutines */
2
3 /* Copyright (c) 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_cojava.h"
13 #include "jxbt_utilities.h"
14 #include "xbt/dynar.h"
15
16
17 //Coroutine methodID/class cache.
18 jclass coclass;
19 jmethodID coroutine_init;
20 jmethodID coroutine_yield;
21 jmethodID coroutine_yieldTo;
22 jmethodID coroutine_stop;
23 //Maestro java coroutine
24 jobject cojava_maestro_coroutine;
25
26 JNIEnv *global_env;
27
28 static smx_context_t my_current_context = NULL;
29 static smx_context_t maestro_context = NULL;
30
31
32 xbt_dynar_t cojava_processes;
33 static unsigned long int cojava_process_index = 0;
34
35 extern JavaVM *__java_vm;
36
37 XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(jmsg);
38
39
40 static smx_context_t
41 smx_ctx_cojava_factory_create_context(xbt_main_func_t code,
42                                       int argc, char **argv,
43                                       void_pfn_smxprocess_t cleanup_func,
44                                       smx_process_t process);
45
46 static void smx_ctx_cojava_free(smx_context_t context);
47 static void smx_ctx_cojava_suspend(smx_context_t context);
48 static void smx_ctx_cojava_resume(smx_context_t new_context);
49 static void smx_ctx_cojava_runall(void);
50 static void* smx_ctx_cojava_run(void *data);
51 static void smx_ctx_cojava_create_coroutine(smx_ctx_cojava_t context);
52 void SIMIX_ctx_cojava_factory_init(smx_context_factory_t * factory)
53 {
54   /* instantiate the context factory */
55   smx_ctx_base_factory_init(factory);
56
57   (*factory)->create_context = smx_ctx_cojava_factory_create_context;
58   /* Leave default behavior of (*factory)->finalize */
59   (*factory)->free = smx_ctx_cojava_free;
60   (*factory)->stop = smx_ctx_cojava_stop;
61   (*factory)->suspend = smx_ctx_cojava_suspend;
62   (*factory)->runall = smx_ctx_cojava_runall;
63   (*factory)->name = "ctx_cojava_factory";
64   //(*factory)->finalize = smx_ctx_base_factory_finalize;
65   (*factory)->self = smx_ctx_cojava_self;
66   (*factory)->get_process = smx_ctx_base_get_process;
67
68   global_env = get_current_thread_env();
69
70   coclass = (*global_env)->FindClass(global_env, "java/dyn/Coroutine");
71   xbt_assert((coclass != NULL), "Can't find java.dyn.Coroutine class.");
72   //Cache the method id we are going to use
73   coroutine_init = (*global_env)->GetMethodID(global_env, coclass, "<init>", "(Ljava/lang/Runnable;)V");
74   xbt_assert((coroutine_init != NULL), "Can't find <init>");
75   coroutine_stop = (*global_env)->GetMethodID(global_env, coclass, "stop", "()V");
76   xbt_assert((coroutine_stop != NULL), "Method not found...");
77   coroutine_yield = (*global_env)->GetStaticMethodID(global_env, coclass, "yield", "()V");
78   xbt_assert((coroutine_yield != NULL), "Method yield not found.");
79   coroutine_yieldTo = (*global_env)->GetStaticMethodID(global_env, coclass, "yieldTo", "(Ljava/dyn/Coroutine;)V");
80   xbt_assert((coroutine_yieldTo != NULL), "Method yieldTo not found.");
81
82   jclass class_thread = (*global_env)->FindClass(global_env, "java/lang/Thread");
83   xbt_assert((class_thread != NULL), "Can't find java.lang.Thread class");
84   
85   jclass class_coroutine_support = (*global_env)->FindClass(global_env, "java/dyn/CoroutineSupport");
86   xbt_assert((class_coroutine_support != NULL), "Can't find java.dyn.CoroutineSupport class");
87   jmethodID thread_get_current = (*global_env)->GetStaticMethodID(global_env, class_thread, "currentThread", "()Ljava/lang/Thread;");
88   xbt_assert((thread_get_current != NULL), "Can't find Thread.currentThread() method.");
89
90   /**
91    * Retrieve maetro coroutine object
92    */
93   jobject jthread;
94   jthread = (*global_env)->CallStaticObjectMethod(global_env, class_thread, thread_get_current);
95   xbt_assert((jthread != NULL), "Can't find current thread.");
96
97   jmethodID thread_get_coroutine_support = (*global_env)->GetMethodID(global_env, class_thread, "getCoroutineSupport", "()Ljava/dyn/CoroutineSupport;");
98   xbt_assert((thread_get_coroutine_support != NULL), "Can't find Thread.getCoroutineSupport method");
99
100   jobject jcoroutine_support;
101   jcoroutine_support = (*global_env)->CallObjectMethod(global_env, jthread, thread_get_coroutine_support);
102   xbt_assert((jcoroutine_support != NULL), "Can't find coroutine support object");
103   //FIXME ? Be careful, might change in the implementation (we are relying on private fields, so...).
104   jfieldID coroutine_support_thread_coroutine = (*global_env)->GetFieldID(global_env, class_coroutine_support, "threadCoroutine", "Ljava/dyn/Coroutine;");
105   xbt_assert((coroutine_support_thread_coroutine != NULL), "Can't find threadCoroutine field");
106   cojava_maestro_coroutine = (jobject)(*global_env)->GetObjectField(global_env, jcoroutine_support, coroutine_support_thread_coroutine);
107   xbt_assert((cojava_maestro_coroutine != NULL), "Can't find the thread coroutine.");
108   cojava_maestro_coroutine = (*global_env)->NewGlobalRef(global_env, cojava_maestro_coroutine);
109   xbt_assert((cojava_maestro_coroutine != NULL), "Can't get a global reference to the thread coroutine.");
110 }
111 smx_context_t smx_ctx_cojava_self(void)
112 {
113         return my_current_context;
114 }
115
116 static smx_context_t
117 smx_ctx_cojava_factory_create_context(xbt_main_func_t code,
118                                       int argc, char **argv,
119                                       void_pfn_smxprocess_t cleanup_func,
120                                       smx_process_t process)
121 {
122         smx_ctx_cojava_t context = xbt_new0(s_smx_ctx_cojava_t, 1);
123   /* If the user provided a function for the process then use it
124      otherwise is the context for maestro */
125   if (code) {
126     if (argc == 0) {
127       context->jprocess = (jobject) code;
128     }
129     else {
130       context->jprocess = NULL;
131     }
132     context->super.cleanup_func = cleanup_func;
133
134     context->super.argc = argc;
135     context->super.argv = argv;
136     context->super.code = code;
137
138     smx_ctx_cojava_run(context);
139   }
140   else {
141         context->jcoroutine = NULL;
142         my_current_context = (smx_context_t)context;
143         maestro_context = (smx_context_t)context;
144   }
145   context->bound = 0;
146   context->super.process = process;
147   return (smx_context_t) context;
148 }
149
150 static void* smx_ctx_cojava_run(void *data) {
151   smx_ctx_cojava_t context = (smx_ctx_cojava_t)data;
152   my_current_context = (smx_context_t)context;
153   //Create the "Process" object if needed.
154   if (context->super.argc <= 0) {
155     smx_ctx_cojava_create_coroutine(context);
156   }
157   my_current_context = maestro_context;
158   return NULL;
159 }
160 static void smx_ctx_cojava_free(smx_context_t context)
161 {
162   if (context) {
163     smx_ctx_cojava_t ctx_java = (smx_ctx_cojava_t) context;
164     if (ctx_java->jcoroutine) { /* We are not in maestro context */
165       JNIEnv *env = get_current_thread_env();
166       (*env)->DeleteGlobalRef(env, ctx_java->jcoroutine);
167       (*env)->DeleteGlobalRef(env, ctx_java->jprocess);
168     }
169   }
170   smx_ctx_base_free(context);
171 }
172
173
174 void smx_ctx_cojava_stop(smx_context_t context)
175 {
176   /*
177    * The java stack needs to be empty, otherwise weird stuff
178    * will happen
179    */
180   if (context->iwannadie) {
181     context->iwannadie = 0;
182     JNIEnv *env = get_current_thread_env();
183     // TODO it will be nice to have the name of the process to help the end-user to know which Process has been killed
184     jxbt_throw_by_name(env, "org/simgrid/msg/ProcessKilledError", xbt_strdup("Process killed :) (file smx_context_cojava.c)"));
185     THROWF(cancel_error, 0, "process cancelled");
186   }
187   else {
188     smx_ctx_base_stop(context);
189     smx_ctx_cojava_suspend(context);
190   }
191 }
192
193 static void smx_ctx_cojava_suspend(smx_context_t context)
194 {
195   smx_context_t previous_context = context;
196   unsigned long int i = cojava_process_index++;
197   jobject next_coroutine;
198
199   if (i < xbt_dynar_length(cojava_processes)) {
200     smx_context_t next_context = SIMIX_process_get_context(xbt_dynar_get_as(
201     cojava_processes,i, smx_process_t));
202     my_current_context = next_context;
203     XBT_DEBUG("Switching to %p",my_current_context);
204     smx_ctx_cojava_t java_context = (smx_ctx_cojava_t)(next_context);
205     if (!java_context->jprocess) {
206       java_context->super.code(java_context->super.argc, java_context->super.argv);
207       smx_ctx_cojava_create_coroutine(java_context);
208     }
209     else if (!java_context->bound) {
210       java_context->bound = 1;
211       smx_process_t process = SIMIX_process_self();
212       (*global_env)->SetLongField(global_env, java_context->jprocess,
213                                   jprocess_field_Process_bind,
214                                   (intptr_t)process);
215     }
216
217     next_coroutine = java_context->jcoroutine;
218   }
219   else {
220     //Give maestro the control back.
221     next_coroutine = cojava_maestro_coroutine;
222     my_current_context = maestro_context;
223   }
224   (*global_env)->CallStaticVoidMethod(global_env, coclass, coroutine_yieldTo, next_coroutine);
225   my_current_context = previous_context;
226 }
227
228 static void smx_ctx_cojava_resume(smx_context_t new_context) {
229   my_current_context = new_context;
230   smx_ctx_cojava_t java_context = (smx_ctx_cojava_t)(new_context);
231
232   if (!java_context->jprocess) {
233     java_context->super.code(java_context->super.argc, java_context->super.argv);
234     smx_ctx_cojava_create_coroutine(java_context);
235     java_context->bound = 1;
236   }
237   else if (!java_context->bound) {
238     java_context->bound = 1;
239     smx_process_t process = SIMIX_process_self();
240     (*global_env)->SetLongField(global_env, java_context->jprocess,
241                                 jprocess_field_Process_bind, (intptr_t)process);
242   }
243   (*global_env)->CallStaticVoidMethod(global_env, coclass, coroutine_yieldTo, java_context->jcoroutine);
244 }
245
246 static void smx_ctx_cojava_runall(void)
247 {
248   cojava_processes = SIMIX_process_get_runnable();
249   smx_process_t process;
250   if (!xbt_dynar_is_empty(cojava_processes)) {
251     process = xbt_dynar_get_as(cojava_processes, 0, smx_process_t);
252     cojava_process_index = 1;
253     /* Execute the first process */
254     smx_ctx_cojava_resume(SIMIX_process_get_context(process));
255   }
256 }
257
258 static void smx_ctx_cojava_create_coroutine(smx_ctx_cojava_t context) {
259   JNIEnv *env = get_current_thread_env();
260   jclass coclass = (*env)->FindClass(env, "java/dyn/Coroutine");
261   xbt_assert((coclass != NULL), "Can't find coroutine class ! :(");
262   jobject jcoroutine = (*env)->NewObject(env, coclass, coroutine_init, context->jprocess);
263   if (jcoroutine == NULL) {
264      FILE *conf= fopen("/proc/sys/vm/max_map_count","r");
265      if (conf) {
266         int limit=-1;
267         if(fscanf(conf,"%d",&limit) != 1)
268            xbt_die("Error while creating a new coroutine. Parse error.");
269         fclose(conf);
270         if (limit!=-1 && SIMIX_process_count() > (limit - 100) /2)
271            xbt_die("Error while creating a new coroutine. "
272                    "This seem due to the the vm.max_map_count system limit that is only equal to %d while we already have %d coroutines. "
273                    "Please check the install documentation to see how to increase this limit", limit, SIMIX_process_count());
274         if (limit == -1)
275           xbt_die("Error while creating a new coroutine. "
276                   "This seems to be a non-linux system, disabling the automatic verification that the system limit on the amount of memory maps is high enough.");
277         xbt_die("Error while creating a new coroutine. ");
278      }
279      
280   }
281    
282   jcoroutine = (*env)->NewGlobalRef(env, jcoroutine);
283   context->jcoroutine = jcoroutine;
284 }