1111#include < algorithm>
1212#include < fstream>
1313#include < map>
14+ #include < thread>
15+ #include < vector>
1416
1517#include " reactor-cpp/action.hh"
1618#include " reactor-cpp/assert.hh"
2123
2224namespace reactor {
2325
26+ Environment::Environment (unsigned int num_workers, bool run_forever, bool fast_fwd_execution, const Duration& timeout)
27+ : log_(" Environment" )
28+ , num_workers_(num_workers)
29+ , run_forever_(run_forever)
30+ , fast_fwd_execution_(fast_fwd_execution)
31+ , top_environment_(this )
32+ , scheduler_(this )
33+ , timeout_(timeout) {}
34+
35+ Environment::Environment (const std::string& name, Environment* containing_environment)
36+ : name_(name)
37+ , log_(" Environment " + name)
38+ , num_workers_(containing_environment->num_workers_)
39+ , run_forever_(containing_environment->run_forever_)
40+ , fast_fwd_execution_(containing_environment->fast_fwd_execution_)
41+ , containing_environment_(containing_environment)
42+ , top_environment_(containing_environment_->top_environment_)
43+ , scheduler_(this )
44+ , timeout_(containing_environment->timeout ()) {
45+ reactor_assert (containing_environment->contained_environments_ .insert (this ).second );
46+ }
47+
2448void Environment::register_reactor (Reactor* reactor) {
2549 reactor_assert (reactor != nullptr );
2650 validate (this ->phase () == Phase::Construction, " Reactors may only be registered during construction phase!" );
@@ -36,6 +60,7 @@ void recursive_assemble(Reactor* container) { // NOLINT
3660}
3761
3862void Environment::assemble () {
63+ log_.debug () << " Assemble" ;
3964 validate (this ->phase () == Phase::Construction, " assemble() may only be called during construction phase!" );
4065 phase_ = Phase::Assembly;
4166 for (auto * reactor : top_level_reactors_) {
@@ -47,6 +72,11 @@ void Environment::assemble() {
4772 build_dependency_graph (reactor);
4873 }
4974 calculate_indexes ();
75+
76+ // assemble all contained environments
77+ for (auto * env : contained_environments_) {
78+ env->assemble ();
79+ }
5080}
5181
5282void Environment::build_dependency_graph (Reactor* reactor) { // NOLINT
@@ -89,7 +119,7 @@ void Environment::build_dependency_graph(Reactor* reactor) { // NOLINT
89119
90120void Environment::sync_shutdown () {
91121 {
92- std::lock_guard<std::mutex> lock ( shutdown_mutex_) ;
122+ std::lock_guard<std::mutex> lock{ shutdown_mutex_} ;
93123
94124 if (phase_ >= Phase::Shutdown) {
95125 // sync_shutdown() was already called -> abort
@@ -101,7 +131,7 @@ void Environment::sync_shutdown() {
101131 }
102132
103133 // the following will only be executed once
104- log::Debug () << " Terminating the execution" ;
134+ log_. debug () << " Terminating the execution" ;
105135
106136 for (auto * reactor : top_level_reactors_) {
107137 reactor->shutdown ();
@@ -164,7 +194,7 @@ void Environment::export_dependency_graph(const std::string& path) {
164194
165195 dot.close ();
166196
167- log::Info () << " Reaction graph was written to " << path;
197+ log_. info () << " Reaction graph was written to " << path;
168198}
169199
170200void Environment::calculate_indexes () {
@@ -177,7 +207,7 @@ void Environment::calculate_indexes() {
177207 graph[dependencies.first ].insert (dependencies.second );
178208 }
179209
180- log::Debug () << " Reactions sorted by index:" ;
210+ log_. debug () << " Reactions sorted by index:" ;
181211 unsigned int index = 0 ;
182212 while (!graph.empty ()) {
183213 // find nodes with degree zero and assign index
@@ -195,7 +225,7 @@ void Environment::calculate_indexes() {
195225 " /tmp/reactor_dependency_graph.dot" );
196226 }
197227
198- log::Debug dbg;
228+ auto dbg = log_. debug () ;
199229 dbg << index << " : " ;
200230 for (auto * reaction : degree_zero) {
201231 dbg << reaction->fqn () << " , " ;
@@ -218,26 +248,39 @@ void Environment::calculate_indexes() {
218248}
219249
220250auto Environment::startup () -> std::thread {
221- validate (this ->phase () == Phase::Assembly, " startup() may only be called during assembly phase!" );
251+ validate (this == top_environment_, " startup() may only be called on the top environment" );
252+ auto start_time = get_physical_time ();
253+ return startup (start_time);
254+ }
222255
223- // build the dependency graph
224- for (auto * reactor : top_level_reactors_) {
225- build_dependency_graph (reactor);
226- }
227- calculate_indexes ();
256+ auto Environment::startup (const TimePoint& start_time) -> std::thread {
257+ validate (this ->phase () == Phase::Assembly, " startup() may only be called during assembly phase!" );
228258
229- log::Info () << " Starting the execution" ;
259+ log_. debug () << " Starting the execution" ;
230260 phase_ = Phase::Startup;
231261
232- start_time_ = get_physical_time () ;
262+ start_time_ = start_time ;
233263 // start up initialize all reactors
234264 for (auto * reactor : top_level_reactors_) {
235265 reactor->startup ();
236266 }
237267
238268 // start processing events
239269 phase_ = Phase::Execution;
240- return std::thread ([this ]() { this ->scheduler_ .start (); });
270+
271+ return std::thread ([this ]() {
272+ std::vector<std::thread> threads;
273+ // startup all contained environments recursively
274+ for (auto * env : contained_environments_) {
275+ threads.emplace_back (env->startup (start_time_));
276+ }
277+ // start the local scheduler and wait until it returns
278+ this ->scheduler_ .start ();
279+ // then join all the created threads
280+ for (auto & thread : threads) {
281+ thread.join ();
282+ }
283+ });
241284}
242285
243286void Environment::dump_trigger_to_yaml (std::ofstream& yaml, const BaseAction& trigger) {
@@ -367,7 +410,7 @@ void Environment::dump_to_yaml(const std::string& path) {
367410 yaml << " - to: " << iterator.second ->fqn () << std::endl;
368411 }
369412
370- log::Info () << " Program structure was dumped to " << path;
413+ log_. info () << " Program structure was dumped to " << path;
371414}
372415
373416} // namespace reactor
0 commit comments