Fawkes API  Fawkes Development Version
continuous_exec_thread.cpp
1 
2 /***************************************************************************
3  * continuous_exec_thread.cpp - Fawkes LuaAgent: Continuous Execution Thread
4  *
5  * Created: Thu May 26 11:50:15 2011
6  * Copyright 2006-2011 Tim Niemueller [www.niemueller.de]
7  *
8  ****************************************************************************/
9 
10 /* This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU Library General Public License for more details.
19  *
20  * Read the full text in the LICENSE.GPL file in the doc directory.
21  */
22 
23 #include "continuous_exec_thread.h"
24 
25 #include <core/exceptions/software.h>
26 #include <core/exceptions/system.h>
27 #include <core/threading/mutex.h>
28 #include <interfaces/SkillerDebugInterface.h>
29 #include <interfaces/SkillerInterface.h>
30 #include <logging/component.h>
31 #include <lua/context.h>
32 #include <lua/interface_importer.h>
33 
34 #include <cstring>
35 #include <string>
36 
37 using namespace std;
38 using namespace fawkes;
39 
40 LuaAgentContinuousExecutionThread *g_agent_thread = NULL;
41 
42 static int
43 l_read_interfaces(lua_State *L)
44 {
45  g_agent_thread->read_interfaces();
46  return 0;
47 }
48 
49 static int
50 l_write_interfaces(lua_State *L)
51 {
52  g_agent_thread->write_interfaces();
53  return 0;
54 }
55 
56 /** @class LuaAgentContinuousExecutionThread "periodic_exec_thread.h"
57  * LuaAgent Periodic Execution Thread.
58  * This thread runs and controls the Lua interpreter and passes data into the
59  * execution engine. It hooks into the THINK main loop hook and expects the
60  * agent's execution function to return quickly. If you have a separate agent
61  * main loop use the concurrent execution thread.
62  *
63  * @author Tim Niemueller
64  */
65 
66 /** Constructor. */
68 : Thread("LuaAgentContinuousExecutionThread", Thread::OPMODE_WAITFORWAKEUP),
69  BlockedTimingAspect(BlockedTimingAspect::WAKEUP_HOOK_THINK)
70 {
71  lua_ = NULL;
72  if (g_agent_thread != NULL) {
73  throw Exception("A global thread has already been set");
74  }
75  g_agent_thread = this;
76 }
77 
78 /** Destructor. */
80 {
81  g_agent_thread = NULL;
82 }
83 
84 /** Clean up when init failed.
85  * You may only call this from init(). Never ever call it from anywhere
86  * else!
87  */
88 void
89 LuaAgentContinuousExecutionThread::init_failure_cleanup()
90 {
91  try {
92  if (skiller_if_) {
94  blackboard->close(skiller_if_);
95  }
96  delete lua_ifi_;
97  delete lua_thread_;
98  delete ifi_mutex_;
99 
100  } catch (...) {
101  // we really screwed up, can't do anything about it, ignore error, logger is
102  // initialized since this method is only called from init() which is only called if
103  // all aspects had been initialized successfully
104  logger->log_error(name(),
105  "Really screwed up while finalizing, aborting cleanup. "
106  "Fawkes is no longer in a clean state. Restart!");
107  }
108 }
109 
110 void
112 {
113  try {
114  cfg_agent_ = config->get_string("/luaagent/agent");
115  cfg_watch_files_ = config->get_bool("/luaagent/watch_files");
116  } catch (Exception &e) {
117  e.append("Insufficient configuration for LuaAgent");
118  throw;
119  }
120 
121  logger->log_debug("LuaAgentContinuousExecutionThread", "Agent: %s", cfg_agent_.c_str());
122 
123  clog_ = new ComponentLogger(logger, "LuaAgentLua");
124 
125  lua_ = NULL;
126  lua_ifi_ = NULL;
127  lua_thread_ = NULL;
128  skiller_if_ = NULL;
129  ifi_mutex_ = NULL;
130 
131  std::string reading_prefix = "/luaagent/interfaces/" + cfg_agent_ + "/reading/";
132  std::string writing_prefix = "/luaagent/interfaces/" + cfg_agent_ + "/writing/";
133 
134  skiller_if_ = blackboard->open_for_reading<SkillerInterface>("Skiller");
135 
136  skiller_if_->read();
137  if (skiller_if_->exclusive_controller() != 0) {
138  throw Exception("Skiller already has an exclusive controller");
139  }
140 
142 
143  try {
144  lua_ = new LuaContext();
145  if (cfg_watch_files_) {
146  lua_->setup_fam(/* auto restart */ false, /* conc thread */ true);
147  lua_->get_fam()->add_listener(this);
148  }
149 
150  lua_ifi_ = new LuaInterfaceImporter(lua_, blackboard, config, logger);
151  lua_ifi_->open_reading_interfaces(reading_prefix);
152  lua_ifi_->open_writing_interfaces(writing_prefix);
153 
154  lua_->add_package_dir(LUADIR);
155  lua_->add_cpackage_dir(LUALIBDIR);
156 
157  lua_->add_package("fawkesutils");
158  lua_->add_package("fawkesconfig");
159  lua_->add_package("fawkesinterface");
160 #ifdef HAVE_TF
161  lua_->add_package("fawkestf");
162 #endif
163 
164  lua_->set_string("AGENT", cfg_agent_.c_str());
165  lua_->set_usertype("config", config, "Configuration", "fawkes");
166  lua_->set_usertype("logger", clog_, "ComponentLogger", "fawkes");
167  lua_->set_usertype("clock", clock, "Clock", "fawkes");
168 #ifdef HAVE_TF
169  lua_->set_usertype("tf", tf_listener, "Transformer", "fawkes::tf");
170 #endif
171  lua_->set_cfunction("read_interfaces", l_read_interfaces);
172  lua_->set_cfunction("write_interfaces", l_write_interfaces);
173 
174  lua_ifi_->add_interface("skiller", skiller_if_);
175 
176  lua_ifi_->read_to_buffer();
177  lua_ifi_->push_interfaces();
178 
179  lua_->set_start_script(LUADIR "/luaagent/fawkes/start.lua");
180 
181  lua_thread_ = new LuaThread(lua_);
182  thread_collector->add(lua_thread_);
183 
184  ifi_mutex_ = new Mutex();
185  } catch (Exception &e) {
186  init_failure_cleanup();
187  throw;
188  }
189 }
190 
191 void
193 {
194  if (skiller_if_->has_writer()) {
196  }
197 
198  blackboard->close(skiller_if_);
199 
200  if (lua_thread_) {
201  thread_collector->remove(lua_thread_);
202  delete lua_thread_;
203  }
204 
205  delete lua_ifi_;
206  delete ifi_mutex_;
207  delete lua_;
208  delete clog_;
209 }
210 
211 void
213 {
214  ifi_mutex_->lock();
215 
216  lua_ifi_->read_to_buffer();
217  skiller_if_->read();
218 
219  if (lua_thread_ && lua_thread_->failed()) {
220  logger->log_error(name(), "LuaThread failed, agent died, removing thread");
221  thread_collector->remove(lua_thread_);
222  delete lua_thread_;
223  lua_thread_ = NULL;
224  }
225  ifi_mutex_->unlock();
226 }
227 
228 /** Update all reading interfaces.
229  * This is meant to be called from inside Lua so that the agent can
230  * update the set of interfaces at suitable points in time.
231  */
232 void
234 {
235  ifi_mutex_->lock();
236  logger->log_debug(name(), "Reading interfaces");
237  lua_ifi_->read_from_buffer();
238  ifi_mutex_->unlock();
239 }
240 
241 /** Update all reading interfaces.
242  * This is meant to be called from inside Lua so that the agent can
243  * update the set of interfaces at suitable points in time.
244  */
245 void
247 {
248  ifi_mutex_->lock();
249  logger->log_debug(name(), "Writing interfaces");
250  lua_ifi_->write();
251  ifi_mutex_->unlock();
252 }
253 
254 void
255 LuaAgentContinuousExecutionThread::fam_event(const char *filename, unsigned int mask)
256 {
257  if (lua_thread_) {
258  lua_thread_->cancel();
259  lua_thread_->join();
260  }
261 
262  ifi_mutex_->lock();
263  logger->log_warn(name(), "Restarting Lua context");
264  lua_->restart();
265  lua_thread_->start();
266  ifi_mutex_->unlock();
267 }
268 
269 /** Constructor.
270  * @param lua Lua context to use
271  */
272 LuaAgentContinuousExecutionThread::LuaThread::LuaThread(fawkes::LuaContext *lua)
273 : Thread("LuaAgentContinuousExecutionThread::LuaThread", Thread::OPMODE_CONTINUOUS)
274 {
275  set_prepfin_conc_loop(true);
276  lua_ = lua;
277  failed_ = false;
278 }
279 
280 /** Loop method continuously calling agentenv.execute() in Lua. */
281 void
282 LuaAgentContinuousExecutionThread::LuaThread::loop()
283 {
284  while (!failed_) {
285  try {
286  // Stack:
287  lua_->do_string("agentenv.execute()");
288  } catch (Exception &e) {
289  failed_ = true;
290  logger->log_error(name(), "execute() failed, exception follows");
291  logger->log_error(name(), e);
292  }
293  }
294 }
fawkes::Mutex::lock
void lock()
Lock this mutex.
Definition: mutex.cpp:91
fawkes::MultiLogger::log_error
virtual void log_error(const char *component, const char *format,...)
Definition: multi.cpp:241
fawkes::Thread::set_prepfin_conc_loop
void set_prepfin_conc_loop(bool concurrent=true)
Set concurrent execution of prepare_finalize() and loop().
Definition: thread.cpp:720
fawkes::ThreadCollector::remove
virtual void remove(ThreadList &tl)=0
fawkes::LuaInterfaceImporter::write
void write()
Write all writing interfaces.
Definition: interface_importer.cpp:338
fawkes::LuaInterfaceImporter::add_interface
void add_interface(std::string varname, Interface *interface)
Add a single interface to be pushed to the context.
Definition: interface_importer.cpp:204
fawkes::LuaContext
Definition: context.h:47
fawkes::LuaInterfaceImporter::open_reading_interfaces
void open_reading_interfaces(std::string &prefix)
Open interfaces for reading.
Definition: interface_importer.cpp:180
fawkes::Mutex
Definition: mutex.h:36
fawkes::ComponentLogger
Definition: component.h:39
fawkes::LuaContext::do_string
void do_string(const char *format,...)
Execute string.
Definition: context.cpp:536
fawkes::Interface::read
void read()
Read from BlackBoard into local copy.
Definition: interface.cpp:475
fawkes::LuaContext::set_cfunction
void set_cfunction(const char *name, lua_CFunction f)
Assign cfunction to global variable.
Definition: context.cpp:754
fawkes::SkillerInterface::ReleaseControlMessage
Definition: SkillerInterface.h:194
fawkes::LuaInterfaceImporter
Definition: interface_importer.h:45
fawkes::Configuration::get_bool
virtual bool get_bool(const char *path)=0
LuaAgentContinuousExecutionThread::write_interfaces
void write_interfaces()
Update all reading interfaces.
Definition: continuous_exec_thread.cpp:246
fawkes::BlockedTimingAspect
Definition: blocked_timing.h:54
LuaAgentContinuousExecutionThread::LuaAgentContinuousExecutionThread
LuaAgentContinuousExecutionThread()
Constructor.
Definition: continuous_exec_thread.cpp:67
LuaAgentContinuousExecutionThread::read_interfaces
void read_interfaces()
Update all reading interfaces.
Definition: continuous_exec_thread.cpp:233
fawkes::LuaInterfaceImporter::read_to_buffer
void read_to_buffer()
Read from all reading interfaces into a buffer.
Definition: interface_importer.cpp:305
fawkes::Thread::name
const char * name() const
Definition: thread.h:99
fawkes::ClockAspect::clock
Clock * clock
Definition: clock.h:53
fawkes::Mutex::unlock
void unlock()
Unlock the mutex.
Definition: mutex.cpp:135
fawkes::ThreadCollector::add
virtual void add(ThreadList &tl)=0
fawkes::Exception::append
void append(const char *format,...)
Append messages to the message list.
Definition: exception.cpp:332
fawkes::LuaContext::get_fam
RefPtr< FileAlterationMonitor > get_fam() const
Get file alteration monitor.
Definition: context.cpp:147
fawkes::LuaContext::restart
void restart()
Restart Lua.
Definition: context.cpp:289
fawkes::SkillerInterface::AcquireControlMessage
Definition: SkillerInterface.h:163
fawkes::LoggingAspect::logger
Logger * logger
Definition: logging.h:50
fawkes::BlackBoard::close
virtual void close(Interface *interface)=0
fawkes::Logger::log_error
virtual void log_error(const char *component, const char *format,...)=0
LuaAgentContinuousExecutionThread::fam_event
virtual void fam_event(const char *filename, unsigned int mask)
Definition: continuous_exec_thread.cpp:255
fawkes::ThreadProducerAspect::thread_collector
ThreadCollector * thread_collector
Definition: thread_producer.h:50
LuaAgentContinuousExecutionThread::init
virtual void init()
Initialize the thread.
Definition: continuous_exec_thread.cpp:111
fawkes
fawkes::Logger::log_warn
virtual void log_warn(const char *component, const char *format,...)=0
fawkes::Interface::has_writer
bool has_writer() const
Check if there is a writer for the interface.
Definition: interface.cpp:817
LuaAgentContinuousExecutionThread::loop
virtual void loop()
Code to execute in the thread.
Definition: continuous_exec_thread.cpp:212
fawkes::ConfigurableAspect::config
Configuration * config
Definition: configurable.h:50
fawkes::SkillerInterface
Definition: SkillerInterface.h:37
fawkes::LuaInterfaceImporter::open_writing_interfaces
void open_writing_interfaces(std::string &prefix)
Open interfaces for writing.
Definition: interface_importer.cpp:189
fawkes::LuaContext::setup_fam
void setup_fam(bool auto_restart, bool conc_thread)
Setup file alteration monitor.
Definition: context.cpp:129
LuaAgentContinuousExecutionThread::~LuaAgentContinuousExecutionThread
virtual ~LuaAgentContinuousExecutionThread()
Destructor.
Definition: continuous_exec_thread.cpp:79
fawkes::LuaContext::set_usertype
void set_usertype(const char *name, void *data, const char *type_name, const char *name_space=0)
Assign usertype to global variable.
Definition: context.cpp:665
fawkes::LuaContext::set_start_script
void set_start_script(const char *start_script)
Set start script.
Definition: context.cpp:267
LuaAgentContinuousExecutionThread
Definition: continuous_exec_thread.h:50
fawkes::Thread
Definition: thread.h:44
fawkes::BlackBoardAspect::blackboard
BlackBoard * blackboard
Definition: blackboard.h:47
fawkes::LuaContext::add_package
void add_package(const char *package)
Add a default package.
Definition: context.cpp:390
fawkes::Configuration::get_string
virtual std::string get_string(const char *path)=0
fawkes::BlackBoard::open_for_reading
virtual Interface * open_for_reading(const char *interface_type, const char *identifier, const char *owner=NULL)=0
fawkes::LuaContext::add_cpackage_dir
void add_cpackage_dir(const char *path, bool prefix=false)
Add a Lua C package directory.
Definition: context.cpp:367
fawkes::LuaInterfaceImporter::read_from_buffer
void read_from_buffer()
Update interfaces from internal buffers.
Definition: interface_importer.cpp:324
fawkes::LuaInterfaceImporter::push_interfaces
void push_interfaces()
Push interfaces to Lua environment.
Definition: interface_importer.cpp:426
fawkes::Interface::msgq_enqueue
unsigned int msgq_enqueue(Message *message)
Enqueue message at end of queue.
Definition: interface.cpp:882
LuaAgentContinuousExecutionThread::finalize
virtual void finalize()
Finalize the thread.
Definition: continuous_exec_thread.cpp:192
fawkes::SkillerInterface::exclusive_controller
uint32_t exclusive_controller() const
Get exclusive_controller value.
Definition: SkillerInterface.cpp:182
fawkes::LuaContext::add_package_dir
void add_package_dir(const char *path, bool prefix=false)
Add a Lua package directory.
Definition: context.cpp:334
fawkes::LuaContext::set_string
void set_string(const char *name, const char *value)
Assign string to global variable.
Definition: context.cpp:690
fawkes::Logger::log_debug
virtual void log_debug(const char *component, const char *format,...)=0
fawkes::Exception
Definition: exception.h:39