Fawkes API  Fawkes Development Version
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
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 <logging/component.h>
29 
30 #include <lua/context.h>
31 #include <lua/interface_importer.h>
32 
33 #include <interfaces/SkillerInterface.h>
34 #include <interfaces/SkillerDebugInterface.h>
35 
36 #include <string>
37 #include <cstring>
38 
39 using namespace std;
40 using namespace fawkes;
41 
42 
43 LuaAgentContinuousExecutionThread *g_agent_thread = NULL;
44 
45 static int l_read_interfaces(lua_State *L)
46 {
47  g_agent_thread->read_interfaces();
48  return 0;
49 }
50 
51 static int l_write_interfaces(lua_State *L)
52 {
53  g_agent_thread->write_interfaces();
54  return 0;
55 }
56 
57 
58 /** @class LuaAgentContinuousExecutionThread "periodic_exec_thread.h"
59  * LuaAgent Periodic Execution Thread.
60  * This thread runs and controls the Lua interpreter and passes data into the
61  * execution engine. It hooks into the THINK main loop hook and expects the
62  * agent's execution function to return quickly. If you have a separate agent
63  * main loop use the concurrent execution thread.
64  *
65  * @author Tim Niemueller
66  */
67 
68 /** Constructor. */
70  : Thread("LuaAgentContinuousExecutionThread", Thread::OPMODE_WAITFORWAKEUP),
71  BlockedTimingAspect(BlockedTimingAspect::WAKEUP_HOOK_THINK)
72 {
73  __lua = NULL;
74  if (g_agent_thread != NULL) {
75  throw Exception("A global thread has already been set");
76  }
77  g_agent_thread = this;
78 }
79 
80 
81 /** Destructor. */
83 {
84  g_agent_thread = NULL;
85 }
86 
87 
88 /** Clean up when init failed.
89  * You may only call this from init(). Never ever call it from anywhere
90  * else!
91  */
92 void
93 LuaAgentContinuousExecutionThread::init_failure_cleanup()
94 {
95  try {
96  if ( __skiller_if ) {
98  blackboard->close(__skiller_if);
99  }
100  delete __lua_ifi;
101  delete __lua_thread;
102  delete __ifi_mutex;
103 
104  } catch (...) {
105  // we really screwed up, can't do anything about it, ignore error, logger is
106  // initialized since this method is only called from init() which is only called if
107  // all aspects had been initialized successfully
108  logger->log_error(name(), "Really screwed up while finalizing, aborting cleanup. "
109  "Fawkes is no longer in a clean state. Restart!");
110  }
111 }
112 
113 
114 void
116 {
117  try {
118  __cfg_agent = config->get_string("/luaagent/agent");
119  __cfg_watch_files = config->get_bool("/luaagent/watch_files");
120  } catch (Exception &e) {
121  e.append("Insufficient configuration for LuaAgent");
122  throw;
123  }
124 
125  logger->log_debug("LuaAgentContinuousExecutionThread", "Agent: %s", __cfg_agent.c_str());
126 
127  __clog = new ComponentLogger(logger, "LuaAgentLua");
128 
129  __lua = NULL;
130  __lua_ifi = NULL;
131  __lua_thread = NULL;
132  __skiller_if = NULL;
133  __ifi_mutex = NULL;
134 
135  std::string reading_prefix = "/luaagent/interfaces/" + __cfg_agent + "/reading/";
136  std::string writing_prefix = "/luaagent/interfaces/" + __cfg_agent + "/writing/";
137 
138  __skiller_if = blackboard->open_for_reading<SkillerInterface>("Skiller");
139 
140  __skiller_if->read();
141  if (__skiller_if->exclusive_controller() != 0) {
142  throw Exception("Skiller already has an exclusive controller");
143  }
144 
146 
147  try {
148  __lua = new LuaContext();
149  if (__cfg_watch_files) {
150  __lua->setup_fam(/* auto restart */ false, /* conc thread */ true);
151  __lua->get_fam()->add_listener(this);
152  }
153 
154  __lua_ifi = new LuaInterfaceImporter(__lua, blackboard, config, logger);
155  __lua_ifi->open_reading_interfaces(reading_prefix);
156  __lua_ifi->open_writing_interfaces(writing_prefix);
157 
158  __lua->add_package_dir(LUADIR);
159  __lua->add_cpackage_dir(LUALIBDIR);
160 
161  __lua->add_package("fawkesutils");
162  __lua->add_package("fawkesconfig");
163  __lua->add_package("fawkesinterface");
164  __lua->add_package("fawkesgeometry");
165 #ifdef HAVE_TF
166  __lua->add_package("fawkestf");
167 #endif
168 
169  __lua->set_string("AGENT", __cfg_agent.c_str());
170  __lua->set_usertype("config", config, "Configuration", "fawkes");
171  __lua->set_usertype("logger", __clog, "ComponentLogger", "fawkes");
172  __lua->set_usertype("clock", clock, "Clock", "fawkes");
173 #ifdef HAVE_TF
174  __lua->set_usertype("tf", tf_listener, "Transformer", "fawkes::tf");
175 #endif
176  __lua->set_cfunction("read_interfaces", l_read_interfaces);
177  __lua->set_cfunction("write_interfaces", l_write_interfaces);
178 
179  __lua_ifi->add_interface("skiller", __skiller_if);
180 
181  __lua_ifi->read_to_buffer();
182  __lua_ifi->push_interfaces();
183 
184  __lua->set_start_script(LUADIR"/luaagent/start.lua");
185 
186  __lua_thread = new LuaThread(__lua);
187  thread_collector->add(__lua_thread);
188 
189  __ifi_mutex = new Mutex();
190  } catch (Exception &e) {
191  init_failure_cleanup();
192  throw;
193  }
194 }
195 
196 
197 void
199 {
200  if (__skiller_if->has_writer() ) {
202  }
203 
204  blackboard->close(__skiller_if);
205 
206  if (__lua_thread) {
207  thread_collector->remove(__lua_thread);
208  delete __lua_thread;
209  }
210 
211  delete __lua_ifi;
212  delete __ifi_mutex;
213  delete __lua;
214  delete __clog;
215 }
216 
217 
218 void
220 {
221  __ifi_mutex->lock();
222 
223  __lua_ifi->read_to_buffer();
224  __skiller_if->read();
225 
226  if (__lua_thread && __lua_thread->failed()) {
227  logger->log_error(name(), "LuaThread failed, agent died, removing thread");
228  thread_collector->remove(__lua_thread);
229  delete __lua_thread;
230  __lua_thread = NULL;
231  }
232  __ifi_mutex->unlock();
233 }
234 
235 
236 /** Update all reading interfaces.
237  * This is meant to be called from inside Lua so that the agent can
238  * update the set of interfaces at suitable points in time.
239  */
240 void
242 {
243  __ifi_mutex->lock();
244  logger->log_debug(name(), "Reading interfaces");
245  __lua_ifi->read_from_buffer();
246  __ifi_mutex->unlock();
247 }
248 
249 
250 /** Update all reading interfaces.
251  * This is meant to be called from inside Lua so that the agent can
252  * update the set of interfaces at suitable points in time.
253  */
254 void
256 {
257  __ifi_mutex->lock();
258  logger->log_debug(name(), "Writing interfaces");
259  __lua_ifi->write();
260  __ifi_mutex->unlock();
261 }
262 
263 void
265  unsigned int mask)
266 {
267  if (__lua_thread) {
268  __lua_thread->cancel();
269  __lua_thread->join();
270  }
271 
272  __ifi_mutex->lock();
273  logger->log_warn(name(), "Restarting Lua context");
274  __lua->restart();
275  __lua_thread->start();
276  __ifi_mutex->unlock();
277 }
278 
279 
280 /** Constructor.
281  * @param lua Lua context to use
282  */
283 LuaAgentContinuousExecutionThread::LuaThread::LuaThread(fawkes::LuaContext *lua)
284  : Thread("LuaAgentContinuousExecutionThread::LuaThread",
285  Thread::OPMODE_CONTINUOUS)
286 {
287  set_prepfin_conc_loop(true);
288  __lua = lua;
289  __failed = false;
290 }
291 
292 
293 /** Loop method continuously calling agentenv.execute() in Lua. */
294 void
295 LuaAgentContinuousExecutionThread::LuaThread::loop()
296 {
297  while (!__failed) {
298  try {
299  // Stack:
300  __lua->do_string("agentenv.execute()");
301  } catch (Exception &e) {
302  __failed = true;
303  logger->log_error(name(), "execute() failed, exception follows");
304  logger->log_error(name(), e);
305  }
306  }
307 }
void restart()
Restart Lua.
Definition: context.cpp:280
virtual void init()
Initialize the thread.
void setup_fam(bool auto_restart, bool conc_thread)
Setup file alteration monitor.
Definition: context.cpp:133
uint32_t exclusive_controller() const
Get exclusive_controller value.
virtual void log_error(const char *component, const char *format,...)
Log error message.
Definition: multi.cpp:247
virtual void remove(ThreadList &tl)=0
Remove multiple threads.
virtual bool get_bool(const char *path)=0
Get value from configuration which is of type bool.
void unlock()
Unlock the mutex.
Definition: mutex.cpp:135
void read_to_buffer()
Read from all reading interfaces into a buffer.
void write_interfaces()
Update all reading interfaces.
void set_cfunction(const char *name, lua_CFunction f)
Assign cfunction to global variable.
Definition: context.cpp:690
void add_cpackage_dir(const char *path)
Add a Lua C package directory.
Definition: context.cpp:320
ReleaseControlMessage Fawkes BlackBoard Interface Message.
void read_interfaces()
Update all reading interfaces.
Thread class encapsulation of pthreads.
Definition: thread.h:42
void set_prepfin_conc_loop(bool concurrent=true)
Set concurrent execution of prepare_finalize() and loop().
Definition: thread.cpp:715
virtual ~LuaAgentContinuousExecutionThread()
Destructor.
void open_writing_interfaces(std::string &prefix)
Open interfaces for writing.
Logger * logger
This is the Logger member used to access the logger.
Definition: logging.h:44
AcquireControlMessage Fawkes BlackBoard Interface Message.
void add_package(const char *package)
Add a default package.
Definition: context.cpp:337
ThreadCollector * thread_collector
Thread collector.
LuaAgent Periodic Execution Thread.
Clock * clock
By means of this member access to the clock is given.
Definition: clock.h:45
bool has_writer() const
Check if there is a writer for the interface.
Definition: interface.cpp:782
Thread aspect to use blocked timing.
Base class for exceptions in Fawkes.
Definition: exception.h:36
void read()
Read from BlackBoard into local copy.
Definition: interface.cpp:472
void do_string(const char *format,...)
Execute string.
Definition: context.cpp:480
Lua interface importer.
void open_reading_interfaces(std::string &prefix)
Open interfaces for reading.
Lua C++ wrapper.
Definition: context.h:47
virtual void fam_event(const char *filename, unsigned int mask)
Event has been raised.
void read_from_buffer()
Update interfaces from internal buffers.
virtual void log_warn(const char *component, const char *format,...)=0
Log warning message.
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:598
virtual void log_error(const char *component, const char *format,...)=0
Log error message.
Component logger.
Definition: component.h:35
virtual void add(ThreadList &tl)=0
Add multiple threads.
virtual void finalize()
Finalize the thread.
const char * name() const
Get name of thread.
Definition: thread.h:95
void set_string(const char *name, const char *value)
Assign string to global variable.
Definition: context.cpp:622
void add_interface(std::string varname, Interface *interface)
Add a single interface to be pushed to the context.
RefPtr< FileAlterationMonitor > get_fam() const
Get file alteration monitor.
Definition: context.cpp:152
unsigned int msgq_enqueue(Message *message)
Enqueue message at end of queue.
Definition: interface.cpp:830
virtual void loop()
Code to execute in the thread.
virtual void log_debug(const char *component, const char *format,...)=0
Log debug message.
void set_start_script(const char *start_script)
Set start script.
Definition: context.cpp:258
virtual Interface * open_for_reading(const char *interface_type, const char *identifier)=0
Open interface for reading.
void write()
Write all writing interfaces.
SkillerInterface Fawkes BlackBoard Interface.
void lock()
Lock this mutex.
Definition: mutex.cpp:89
Mutex mutual exclusion lock.
Definition: mutex.h:32
void add_package_dir(const char *path)
Add a Lua package directory.
Definition: context.cpp:303
Configuration * config
This is the Configuration member used to access the configuration.
Definition: configurable.h:44
void push_interfaces()
Push interfaces to Lua environment.
void append(const char *format,...)
Append messages to the message list.
Definition: exception.cpp:341
virtual std::string get_string(const char *path)=0
Get value from configuration which is of type string.
BlackBoard * blackboard
This is the BlackBoard instance you can use to interact with the BlackBoard.
Definition: blackboard.h:43
virtual void close(Interface *interface)=0
Close interface.