Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
c6a3d481ac7396f0da8f30be68368f66c3c9ee19
[simgrid.git] / src / bindings / java / JavaContext.cpp
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 <functional>
10 #include <utility>
11
12 #include <xbt/function_types.h>
13 #include <simgrid/simix.h>
14 #include <xbt/ex.h>
15 #include "JavaContext.hpp"
16 #include "jxbt_utilities.h"
17 #include "xbt/dynar.h"
18 #include "../../simix/smx_private.h"
19 extern JavaVM *__java_vm;
20
21 XBT_LOG_NEW_DEFAULT_CATEGORY(jmsg, "MSG for Java(TM)");
22
23 namespace simgrid {
24 namespace java {
25
26 simgrid::simix::ContextFactory* java_factory()
27 {
28   XBT_INFO("Using regular java threads.");
29   return new JavaContextFactory();
30 }
31
32 JavaContextFactory::JavaContextFactory()
33   : ContextFactory("JavaContextFactory")
34 {
35 }
36
37 JavaContextFactory::~JavaContextFactory()
38 {
39 }
40
41 JavaContext* JavaContextFactory::self()
42 {
43   return (JavaContext*) xbt_os_thread_get_extra_data();
44 }
45
46 JavaContext* JavaContextFactory::create_context(
47   std::function<void()> code,
48   void_pfn_smxprocess_t cleanup, smx_process_t process)
49 {
50   return this->new_context<JavaContext>(std::move(code), cleanup, process);
51 }
52
53 void JavaContextFactory::run_all()
54 {
55   xbt_dynar_t processes = SIMIX_process_get_runnable();
56   smx_process_t process;
57   unsigned int cursor;
58   xbt_dynar_foreach(processes, cursor, process) {
59     static_cast<JavaContext*>(SIMIX_process_get_context(process))->resume();
60   }
61 }
62
63 JavaContext::JavaContext(std::function<void()> code,
64         void_pfn_smxprocess_t cleanup_func,
65         smx_process_t process)
66   : Context(std::move(code), cleanup_func, process)
67 {
68   static int thread_amount=0;
69   thread_amount++;
70
71   /* If the user provided a function for the process then use it otherwise is the context for maestro */
72   if (has_code()) {
73     this->jprocess = nullptr;
74     this->begin = xbt_os_sem_init(0);
75     this->end = xbt_os_sem_init(0);
76
77     try {
78        this->thread = xbt_os_thread_create(
79          nullptr, JavaContext::wrapper, this, nullptr);
80     }
81     catch (xbt_ex& ex) {
82       char* str = bprintf(
83         "Failed to create context #%d. You may want to switch to Java coroutines to increase your limits (error: %s)."
84         "See the Install section of simgrid-java documentation (in doc/install.html) for more on coroutines.",
85         thread_amount, ex.what());
86       xbt_ex new_exception(str);
87       free(str);
88       new_exception.category = ex.category;
89       new_exception.value = ex.value;
90       new_exception.procname = ex.procname;
91       new_exception.file = ex.file;
92       new_exception.line = ex.line;
93       new_exception.func = ex.func;
94       new_exception.pid = ex.pid;
95       new_exception.bt = ex.bt;
96       throw new_exception;
97     }
98   } else {
99     this->thread = nullptr;
100     xbt_os_thread_set_extra_data(this);
101   }
102 }
103
104 JavaContext::~JavaContext()
105 {
106   if (this->thread) {
107     // We are not in maestro context
108     xbt_os_thread_join(this->thread, nullptr);
109     xbt_os_sem_destroy(this->begin);
110     xbt_os_sem_destroy(this->end);
111   }
112 }
113
114 void* JavaContext::wrapper(void *data)
115 {
116   JavaContext* context = (JavaContext*)data;
117   xbt_os_thread_set_extra_data(context);
118   //Attach the thread to the JVM
119
120   JNIEnv *env;
121   XBT_ATTRIB_UNUSED jint error =
122     __java_vm->AttachCurrentThread((void **) &env, nullptr);
123   xbt_assert((error == JNI_OK), "The thread could not be attached to the JVM");
124   context->jenv = get_current_thread_env();
125   //Wait for the first scheduling round to happen.
126   xbt_os_sem_acquire(context->begin);
127   //Create the "Process" object if needed.
128   (*context)();
129   context->stop();
130   return nullptr;
131 }
132
133 void JavaContext::stop()
134 {
135   /* I am the current process and I am dying */
136   if (this->iwannadie) {
137     this->iwannadie = 0;
138     JNIEnv *env = get_current_thread_env();
139     XBT_DEBUG("Gonna launch Killed Error");
140     // 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
141     // 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.
142     // 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 ...
143     // TODO it will be nice to have the name of the process to help the end-user to know which Process has been killed
144    // 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) ));
145     jxbt_throw_by_name(env, "org/simgrid/msg/ProcessKilledError",
146       bprintf("Process %s killed :) (file JavaContext.cpp)",
147       simcall_process_get_name(this->process()) ));
148     XBT_DEBUG("Trigger a cancel error at the C level");
149     THROWF(cancel_error, 0, "process cancelled");
150   } else {
151     Context::stop();
152     /* detach the thread and kills it */
153     JNIEnv *env = this->jenv;
154     env->DeleteGlobalRef(this->jprocess);
155     XBT_ATTRIB_UNUSED jint error = __java_vm->DetachCurrentThread();
156     xbt_assert((error == JNI_OK), "The thread couldn't be detached.");
157     xbt_os_sem_release(this->end);
158     xbt_os_thread_exit(nullptr);
159   }
160 }
161
162 void JavaContext::suspend()
163 {
164   xbt_os_sem_release(this->end);
165   xbt_os_sem_acquire(this->begin);
166 }
167
168 // FIXME: inline those functions
169 void JavaContext::resume()
170 {
171   xbt_os_sem_release(this->begin);
172   xbt_os_sem_acquire(this->end);
173 }
174
175 }
176 }