Logo AND Algorithmique Numérique Distribuée

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