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
37using namespace std;
38using namespace fawkes;
39
40LuaAgentContinuousExecutionThread *g_agent_thread = NULL;
41
42static int
43l_read_interfaces(lua_State *L)
44{
45 g_agent_thread->read_interfaces();
46 return 0;
47}
48
49static int
50l_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),
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 */
88void
89LuaAgentContinuousExecutionThread::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
105 "Really screwed up while finalizing, aborting cleanup. "
106 "Fawkes is no longer in a clean state. Restart!");
107 }
108}
109
110void
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
191void
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
211void
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 */
232void
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 */
245void
247{
248 ifi_mutex_->lock();
249 logger->log_debug(name(), "Writing interfaces");
250 lua_ifi_->write();
251 ifi_mutex_->unlock();
252}
253
254void
255LuaAgentContinuousExecutionThread::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 */
272LuaAgentContinuousExecutionThread::LuaThread::LuaThread(fawkes::LuaContext *lua)
273: Thread("LuaAgentContinuousExecutionThread::LuaThread", Thread::OPMODE_CONTINUOUS)
274{
276 lua_ = lua;
277 failed_ = false;
278}
279
280/** Loop method continuously calling agentenv.execute() in Lua. */
281void
282LuaAgentContinuousExecutionThread::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}
LuaAgent Periodic Execution Thread.
void write_interfaces()
Update all reading interfaces.
virtual void fam_event(const char *filename, unsigned int mask)
Event has been raised.
virtual void init()
Initialize the thread.
virtual void finalize()
Finalize the thread.
virtual ~LuaAgentContinuousExecutionThread()
Destructor.
virtual void loop()
Code to execute in the thread.
void read_interfaces()
Update all reading interfaces.
BlackBoard * blackboard
This is the BlackBoard instance you can use to interact with the BlackBoard.
Definition: blackboard.h:44
virtual Interface * open_for_reading(const char *interface_type, const char *identifier, const char *owner=NULL)=0
Open interface for reading.
virtual void close(Interface *interface)=0
Close interface.
Thread aspect to use blocked timing.
Clock * clock
By means of this member access to the clock is given.
Definition: clock.h:42
Component logger.
Definition: component.h:36
Configuration * config
This is the Configuration member used to access the configuration.
Definition: configurable.h:41
virtual bool get_bool(const char *path)=0
Get value from configuration which is of type bool.
virtual std::string get_string(const char *path)=0
Get value from configuration which is of type string.
Base class for exceptions in Fawkes.
Definition: exception.h:36
void append(const char *format,...) noexcept
Append messages to the message list.
Definition: exception.cpp:333
unsigned int msgq_enqueue(Message *message, bool proxy=false)
Enqueue message at end of queue.
Definition: interface.cpp:915
void read()
Read from BlackBoard into local copy.
Definition: interface.cpp:479
bool has_writer() const
Check if there is a writer for the interface.
Definition: interface.cpp:848
virtual void log_debug(const char *component, const char *format,...)=0
Log debug message.
virtual void log_warn(const char *component, const char *format,...)=0
Log warning message.
virtual void log_error(const char *component, const char *format,...)=0
Log error message.
Logger * logger
This is the Logger member used to access the logger.
Definition: logging.h:41
Lua C++ wrapper.
Definition: context.h:44
void setup_fam(bool auto_restart, bool conc_thread)
Setup file alteration monitor.
Definition: context.cpp:125
void restart()
Restart Lua.
Definition: context.cpp:285
void add_cpackage_dir(const char *path, bool prefix=false)
Add a Lua C package directory.
Definition: context.cpp:363
void set_start_script(const char *start_script)
Set start script.
Definition: context.cpp:263
RefPtr< FileAlterationMonitor > get_fam() const
Get file alteration monitor.
Definition: context.cpp:143
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:661
void add_package_dir(const char *path, bool prefix=false)
Add a Lua package directory.
Definition: context.cpp:330
void set_cfunction(const char *name, lua_CFunction f)
Assign cfunction to global variable.
Definition: context.cpp:750
void do_string(const char *format,...)
Execute string.
Definition: context.cpp:532
void set_string(const char *name, const char *value)
Assign string to global variable.
Definition: context.cpp:686
void add_package(const char *package)
Add a default package.
Definition: context.cpp:386
Lua interface importer.
void add_interface(std::string varname, Interface *interface)
Add a single interface to be pushed to the context.
void push_interfaces()
Push interfaces to Lua environment.
void read_from_buffer()
Update interfaces from internal buffers.
void read_to_buffer()
Read from all reading interfaces into a buffer.
void open_writing_interfaces(std::string &prefix)
Open interfaces for writing.
void write()
Write all writing interfaces.
void open_reading_interfaces(std::string &prefix)
Open interfaces for reading.
virtual void log_error(const char *component, const char *format,...)
Log error message.
Definition: multi.cpp:237
Mutex mutual exclusion lock.
Definition: mutex.h:33
void lock()
Lock this mutex.
Definition: mutex.cpp:87
void unlock()
Unlock the mutex.
Definition: mutex.cpp:131
AcquireControlMessage Fawkes BlackBoard Interface Message.
ReleaseControlMessage Fawkes BlackBoard Interface Message.
SkillerInterface Fawkes BlackBoard Interface.
char * exclusive_controller() const
Get exclusive_controller value.
virtual void add(ThreadList &tl)=0
Add multiple threads.
virtual void remove(ThreadList &tl)=0
Remove multiple threads.
ThreadCollector * thread_collector
Thread collector.
Thread class encapsulation of pthreads.
Definition: thread.h:46
void set_prepfin_conc_loop(bool concurrent=true)
Set concurrent execution of prepare_finalize() and loop().
Definition: thread.cpp:716
const char * name() const
Get name of thread.
Definition: thread.h:100
Fawkes library namespace.