Fawkes API  Fawkes Development Version
periodic_exec_thread.cpp
1 
2 /***************************************************************************
3  * periodic_exec_thread.cpp - Fawkes LuaAgent: Periodic Execution Thread
4  *
5  * Created: Thu Jan 01 11:12:13 2009
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 "periodic_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 /** @class LuaAgentPeriodicExecutionThread "periodic_exec_thread.h"
41  * LuaAgent Periodic Execution Thread.
42  * This thread runs and controls the Lua interpreter and passes data into the
43  * execution engine. It hooks into the THINK main loop hook and expects the
44  * agent's execution function to return quickly. If you have a separate agent
45  * main loop use the concurrent execution thread.
46  *
47  * @author Tim Niemueller
48  */
49 
50 /** Constructor. */
52 : Thread("LuaAgentPeriodicExecutionThread", Thread::OPMODE_WAITFORWAKEUP),
53  BlockedTimingAspect(BlockedTimingAspect::WAKEUP_HOOK_THINK)
54 {
55  lua_ = NULL;
56 }
57 
58 /** Destructor. */
60 {
61 }
62 
63 /** Clean up when init failed.
64  * You may only call this from init(). Never ever call it from anywhere
65  * else!
66  */
67 void
68 LuaAgentPeriodicExecutionThread::init_failure_cleanup()
69 {
70  try {
71  if (skiller_if_) {
73  blackboard->close(skiller_if_);
74  }
75  if (agdbg_if_)
76  blackboard->close(agdbg_if_);
77 
78  delete lua_ifi_;
79 
80  } catch (...) {
81  // we really screwed up, can't do anything about it, ignore error, logger is
82  // initialized since this method is only called from init() which is only called if
83  // all aspects had been initialized successfully
85  "Really screwed up while finalizing, aborting cleanup. "
86  "Fawkes is no longer in a clean state. Restart!");
87  }
88 }
89 
90 void
92 {
93  try {
94  cfg_agent_ = config->get_string("/luaagent/agent");
95  cfg_watch_files_ = config->get_bool("/luaagent/watch_files");
96  } catch (Exception &e) {
97  e.append("Insufficient configuration for LuaAgent");
98  throw;
99  }
100 
101  logger->log_debug("LuaAgentPeriodicExecutionThread", "Agent: %s", cfg_agent_.c_str());
102 
103  clog_ = new ComponentLogger(logger, "LuaAgentLua");
104 
105  lua_ = NULL;
106  lua_ifi_ = NULL;
107  skiller_if_ = NULL;
108  agdbg_if_ = NULL;
109 
110  std::string reading_prefix = "/luaagent/interfaces/" + cfg_agent_ + "/reading/";
111  std::string writing_prefix = "/luaagent/interfaces/" + cfg_agent_ + "/writing/";
112 
113  skiller_if_ = blackboard->open_for_reading<SkillerInterface>("Skiller");
114 
115  skiller_if_->read();
116  if (skiller_if_->exclusive_controller() != 0) {
117  throw Exception("Skiller already has an exclusive controller");
118  }
119 
121  agdbg_if_ = blackboard->open_for_writing<SkillerDebugInterface>("LuaAgent");
122 
123  try {
124  lua_ = new LuaContext();
125  if (cfg_watch_files_) {
126  lua_->setup_fam(/* auto restart */ true, /* conc thread */ false);
127  }
128 
129  lua_ifi_ = new LuaInterfaceImporter(lua_, blackboard, config, logger);
130  lua_ifi_->open_reading_interfaces(reading_prefix);
131  lua_ifi_->open_writing_interfaces(writing_prefix);
132 
133  lua_->add_package_dir(LUADIR);
134  lua_->add_cpackage_dir(LUALIBDIR);
135 
136  lua_->add_package("fawkesutils");
137  lua_->add_package("fawkesconfig");
138  lua_->add_package("fawkeslogging");
139  lua_->add_package("fawkesinterface");
140 #ifdef HAVE_TF
141  lua_->add_package("fawkestf");
142 #endif
143 
144  lua_->set_string("AGENT", cfg_agent_.c_str());
145  lua_->set_usertype("config", config, "Configuration", "fawkes");
146  lua_->set_usertype("logger", clog_, "ComponentLogger", "fawkes");
147  lua_->set_usertype("clock", clock, "Clock", "fawkes");
148 #ifdef HAVE_TF
149  lua_->set_usertype("tf", tf_listener, "Transformer", "fawkes::tf");
150 #endif
151 
152  lua_ifi_->add_interface("skiller", skiller_if_);
153  lua_ifi_->add_interface("agdbg", agdbg_if_);
154 
155  lua_ifi_->push_interfaces();
156 
157  lua_->set_start_script(LUADIR "/luaagent/fawkes/start.lua");
158  } catch (Exception &e) {
159  init_failure_cleanup();
160  throw;
161  }
162 
163  agdbg_if_->set_graph("");
164  agdbg_if_->set_graph_fsm(cfg_agent_.c_str());
165 }
166 
167 void
169 {
170  if (skiller_if_->has_writer()) {
172  }
173 
174  blackboard->close(skiller_if_);
175  blackboard->close(agdbg_if_);
176 
177  delete lua_ifi_;
178  delete lua_;
179  delete clog_;
180 }
181 
182 void
183 LuaAgentPeriodicExecutionThread::process_agdbg_messages()
184 {
185  while (!agdbg_if_->msgq_empty()) {
189  try {
190  std::string graphdir = "TB";
191  switch (m->graph_dir()) {
192  case SkillerDebugInterface::GD_BOTTOM_TOP: graphdir = "BT"; break;
193  case SkillerDebugInterface::GD_LEFT_RIGHT: graphdir = "LR"; break;
194  case SkillerDebugInterface::GD_RIGHT_LEFT: graphdir = "RL"; break;
195  default: break;
196  }
197  lua_->do_string("agentenv.set_graphdir(\"%s\")", graphdir.c_str());
198  } catch (Exception &e) {
199  logger->log_warn("LuaAgentPeriodicExecutionThread",
200  "Failed to set graph direction, exception follows");
201  logger->log_warn("LuaAgentPeriodicExecutionThread", e);
202  }
206  try {
207  lua_->do_string("agentenv.set_graph_colored(%s)", m->is_graph_colored() ? "true" : "false");
208  } catch (Exception &e) {
209  logger->log_warn("LuaAgentPeriodicExecutionThread",
210  "Failed to set graph direction, exception follows");
211  logger->log_warn("LuaAgentPeriodicExecutionThread", e);
212  }
213  }
214 
215  agdbg_if_->msgq_pop();
216  }
217 }
218 
219 void
221 {
222 #ifdef HAVE_INOTIFY
223  lua_->process_fam_events();
224 #endif
225 
226  process_agdbg_messages();
227 
228  lua_ifi_->read();
229  skiller_if_->read();
230 
231  try {
232  // Stack:
233  lua_->do_string("agentenv.execute()");
234  } catch (Exception &e) {
235  logger->log_error("LuaAgentPeriodicExecutionThread",
236  "Execution of %s.execute() failed, exception follows",
237  cfg_agent_.c_str());
238  logger->log_error("LuaAgentPeriodicExecutionThread", e);
239  }
240 
241  lua_ifi_->write();
242 }
virtual ~LuaAgentPeriodicExecutionThread()
Destructor.
virtual void loop()
Code to execute in the thread.
virtual void init()
Initialize the thread.
virtual void finalize()
Finalize the thread.
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 Interface * open_for_writing(const char *interface_type, const char *identifier, const char *owner=NULL)=0
Open interface for writing.
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,...)
Append messages to the message list.
Definition: exception.cpp:333
bool msgq_first_is()
Check if first message has desired type.
Definition: interface.h:314
void msgq_pop()
Erase first message from queue.
Definition: interface.cpp:1182
Message * msgq_first()
Get the first message from the message queue.
Definition: interface.cpp:1167
bool msgq_empty()
Check if queue is empty.
Definition: interface.cpp:1029
void read()
Read from BlackBoard into local copy.
Definition: interface.cpp:472
bool has_writer() const
Check if there is a writer for the interface.
Definition: interface.cpp:817
unsigned int msgq_enqueue(Message *message)
Enqueue message at end of queue.
Definition: interface.cpp:882
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 process_fam_events()
Process FAM events.
Definition: context.cpp:1355
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
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 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 read()
Read from all reading interfaces.
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 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.
SetGraphColoredMessage Fawkes BlackBoard Interface Message.
SetGraphDirectionMessage Fawkes BlackBoard Interface Message.
GraphDirectionEnum graph_dir() const
Get graph_dir value.
SkillerDebugInterface Fawkes BlackBoard Interface.
void set_graph(const char *new_graph)
Set graph value.
void set_graph_fsm(const char *new_graph_fsm)
Set graph_fsm value.
AcquireControlMessage Fawkes BlackBoard Interface Message.
ReleaseControlMessage Fawkes BlackBoard Interface Message.
SkillerInterface Fawkes BlackBoard Interface.
uint32_t exclusive_controller() const
Get exclusive_controller value.
Thread class encapsulation of pthreads.
Definition: thread.h:46
const char * name() const
Get name of thread.
Definition: thread.h:100
Fawkes library namespace.