Logo AND Algorithmique Numérique Distribuée

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