Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Move xbt_modinter.h to src/include/xbt/.
[simgrid.git] / src / kernel / context / ContextThread.cpp
1 /* Copyright (c) 2009-2021. The SimGrid Team. All rights reserved.          */
2
3 /* This program is free software; you can redistribute it and/or modify it
4  * under the terms of the license (GNU LGPL) which comes with this package. */
5
6 #include "src/kernel/context/ContextThread.hpp"
7
8 #include "simgrid/Exception.hpp"
9 #include "src/internal_config.h" /* loads context system definitions */
10 #include "src/simix/smx_private.hpp"
11 #include "xbt/function_types.h"
12 #include "xbt/xbt_modinter.h" /* prototype of os thread module's init/exit in XBT */
13
14 #include <boost/core/demangle.hpp>
15 #include <functional>
16 #include <utility>
17
18 XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(simix_context);
19
20 namespace simgrid {
21 namespace kernel {
22 namespace context {
23
24 // ThreadContextFactory
25
26 ThreadContextFactory::ThreadContextFactory() : ContextFactory()
27 {
28   if (smx_context_stack_size != 8 * 1024 * 1024)
29     XBT_INFO("Stack size modifications are ignored by thread factory.");
30   if (SIMIX_context_is_parallel())
31     ParallelThreadContext::initialize();
32 }
33
34 ThreadContextFactory::~ThreadContextFactory()
35 {
36   if (SIMIX_context_is_parallel())
37     ParallelThreadContext::finalize();
38 }
39
40 ThreadContext* ThreadContextFactory::create_context(std::function<void()>&& code, actor::ActorImpl* actor, bool maestro)
41 {
42   if (SIMIX_context_is_parallel())
43     return this->new_context<ParallelThreadContext>(std::move(code), actor, maestro);
44   else
45     return this->new_context<SerialThreadContext>(std::move(code), actor, maestro);
46 }
47
48 void ThreadContextFactory::run_all()
49 {
50   if (SIMIX_context_is_parallel()) {
51     // Parallel execution
52     ParallelThreadContext::run_all();
53   } else {
54     // Serial execution
55     SerialThreadContext::run_all();
56   }
57 }
58
59 // ThreadContext
60
61 ThreadContext::ThreadContext(std::function<void()>&& code, actor::ActorImpl* actor, bool maestro)
62     : AttachContext(std::move(code), actor), is_maestro_(maestro)
63 {
64   /* If the user provided a function for the actor then use it */
65   if (has_code()) {
66     /* create and start the actor */
67     this->thread_ = new std::thread(ThreadContext::wrapper, this);
68     /* wait the starting of the newly created actor */
69     this->end_.acquire();
70   }
71
72   /* Otherwise, we attach to the current thread */
73   else {
74     Context::set_current(this);
75   }
76 }
77
78 ThreadContext::~ThreadContext()
79 {
80   if (this->thread_) { /* Maestro don't have any thread */
81     thread_->join();
82     delete thread_;
83   }
84 }
85
86 void ThreadContext::wrapper(ThreadContext* context)
87 {
88   Context::set_current(context);
89
90 #ifndef WIN32
91   install_sigsegv_stack(nullptr, true);
92 #endif
93   // Tell the caller (normally the maestro) we are starting, and wait for its green light
94   context->end_.release();
95   context->start();
96
97   try {
98     (*context)();
99     if (not context->is_maestro()) { // Just in case somebody detached maestro
100       context->Context::stop();
101       context->stop_hook();
102     }
103   } catch (ForcefulKillException const&) {
104     XBT_DEBUG("Caught a ForcefulKillException in Thread::wrapper");
105     xbt_assert(not context->is_maestro(), "Maestro shall not receive ForcefulKillExceptions, even when detached.");
106   } catch (simgrid::Exception const& e) {
107     XBT_INFO("Actor killed by an uncaught exception %s", boost::core::demangle(typeid(e).name()).c_str());
108     throw;
109   }
110   // Signal to the caller (normally the maestro) that we have finished:
111   context->yield();
112
113 #ifndef WIN32
114   install_sigsegv_stack(nullptr, false);
115 #endif
116   XBT_DEBUG("Terminating");
117   Context::set_current(nullptr);
118 }
119
120 void ThreadContext::release()
121 {
122   this->begin_.release();
123 }
124
125 void ThreadContext::wait()
126 {
127   this->end_.acquire();
128 }
129
130 void ThreadContext::start()
131 {
132   this->begin_.acquire();
133   this->start_hook();
134 }
135
136 void ThreadContext::yield()
137 {
138   this->yield_hook();
139   this->end_.release();
140 }
141
142 void ThreadContext::stop()
143 {
144   Context::stop();
145   stop_hook();
146   throw ForcefulKillException();
147 }
148
149 void ThreadContext::suspend()
150 {
151   this->yield();
152   this->start();
153 }
154
155 void ThreadContext::attach_start()
156 {
157   // We're breaking the layers here by depending on the upper layer:
158   auto* maestro = static_cast<ThreadContext*>(simix_global->maestro_->context_.get());
159   maestro->begin_.release();
160   xbt_assert(not this->is_maestro());
161   this->start();
162 }
163
164 void ThreadContext::attach_stop()
165 {
166   xbt_assert(not this->is_maestro());
167   this->yield();
168
169   auto* maestro = static_cast<ThreadContext*>(simix_global->maestro_->context_.get());
170   maestro->end_.acquire();
171
172   Context::set_current(nullptr);
173 }
174
175 // SerialThreadContext
176
177 void SerialThreadContext::run_all()
178 {
179   for (smx_actor_t const& actor : simix_global->actors_to_run) {
180     XBT_DEBUG("Handling %p", actor);
181     auto* context = static_cast<ThreadContext*>(actor->context_.get());
182     context->release();
183     context->wait();
184   }
185 }
186
187 // ParallelThreadContext
188
189 xbt::OsSemaphore* ParallelThreadContext::thread_sem_ = nullptr;
190
191 void ParallelThreadContext::initialize()
192 {
193   thread_sem_ = new xbt::OsSemaphore(SIMIX_context_get_nthreads());
194 }
195
196 void ParallelThreadContext::finalize()
197 {
198   delete thread_sem_;
199   thread_sem_ = nullptr;
200 }
201
202 void ParallelThreadContext::run_all()
203 {
204   for (smx_actor_t const& actor : simix_global->actors_to_run)
205     static_cast<ThreadContext*>(actor->context_.get())->release();
206   for (smx_actor_t const& actor : simix_global->actors_to_run)
207     static_cast<ThreadContext*>(actor->context_.get())->wait();
208 }
209
210 void ParallelThreadContext::start_hook()
211 {
212   if (not is_maestro()) /* parallel run */
213     thread_sem_->acquire();
214 }
215
216 void ParallelThreadContext::yield_hook()
217 {
218   if (not is_maestro()) /* parallel run */
219     thread_sem_->release();
220 }
221
222 XBT_PRIVATE ContextFactory* thread_factory()
223 {
224   XBT_VERB("Activating thread context factory");
225   return new ThreadContextFactory();
226 }
227 } // namespace context
228 } // namespace kernel
229 } // namespace simgrid