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 <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 /** @class LuaAgentPeriodicExecutionThread "periodic_exec_thread.h"
43  * LuaAgent Periodic Execution Thread.
44  * This thread runs and controls the Lua interpreter and passes data into the
45  * execution engine. It hooks into the THINK main loop hook and expects the
46  * agent's execution function to return quickly. If you have a separate agent
47  * main loop use the concurrent execution thread.
48  *
49  * @author Tim Niemueller
50  */
51 
52 /** Constructor. */
54  : Thread("LuaAgentPeriodicExecutionThread", Thread::OPMODE_WAITFORWAKEUP),
55  BlockedTimingAspect(BlockedTimingAspect::WAKEUP_HOOK_THINK)
56 {
57  __lua = NULL;
58 }
59 
60 
61 /** Destructor. */
63 {
64 }
65 
66 
67 /** Clean up when init failed.
68  * You may only call this from init(). Never ever call it from anywhere
69  * else!
70  */
71 void
72 LuaAgentPeriodicExecutionThread::init_failure_cleanup()
73 {
74  try {
75  if ( __skiller_if ) {
77  blackboard->close(__skiller_if);
78  }
79  if ( __agdbg_if ) blackboard->close(__agdbg_if);
80 
81  delete __lua_ifi;
82 
83  } catch (...) {
84  // we really screwed up, can't do anything about it, ignore error, logger is
85  // initialized since this method is only called from init() which is only called if
86  // all aspects had been initialized successfully
87  logger->log_error(name(), "Really screwed up while finalizing, aborting cleanup. "
88  "Fawkes is no longer in a clean state. Restart!");
89  }
90 }
91 
92 
93 void
95 {
96  try {
97  __cfg_agent = config->get_string("/luaagent/agent");
98  __cfg_watch_files = config->get_bool("/luaagent/watch_files");
99  } catch (Exception &e) {
100  e.append("Insufficient configuration for LuaAgent");
101  throw;
102  }
103 
104  logger->log_debug("LuaAgentPeriodicExecutionThread", "Agent: %s", __cfg_agent.c_str());
105 
106  __clog = new ComponentLogger(logger, "LuaAgentLua");
107 
108  __lua = NULL;
109  __lua_ifi = NULL;
110  __skiller_if = NULL;
111  __agdbg_if = NULL;
112 
113  std::string reading_prefix = "/luaagent/interfaces/" + __cfg_agent + "/reading/";
114  std::string writing_prefix = "/luaagent/interfaces/" + __cfg_agent + "/writing/";
115 
116  __skiller_if = blackboard->open_for_reading<SkillerInterface>("Skiller");
117 
118  __skiller_if->read();
119  if (__skiller_if->exclusive_controller() != 0) {
120  throw Exception("Skiller already has an exclusive controller");
121  }
122 
124  __agdbg_if = blackboard->open_for_writing<SkillerDebugInterface>("LuaAgent");
125 
126  try {
127  __lua = new LuaContext();
128  if (__cfg_watch_files) {
129  __lua->setup_fam(/* auto restart */ true, /* conc thread */ false);
130  }
131 
132  __lua_ifi = new LuaInterfaceImporter(__lua, blackboard, config, logger);
133  __lua_ifi->open_reading_interfaces(reading_prefix);
134  __lua_ifi->open_writing_interfaces(writing_prefix);
135 
136  __lua->add_package_dir(LUADIR);
137  __lua->add_cpackage_dir(LUALIBDIR);
138 
139  __lua->add_package("fawkesutils");
140  __lua->add_package("fawkesconfig");
141  __lua->add_package("fawkeslogging");
142  __lua->add_package("fawkesinterface");
143 #ifdef HAVE_TF
144  __lua->add_package("fawkestf");
145 #endif
146 
147  __lua->set_string("AGENT", __cfg_agent.c_str());
148  __lua->set_usertype("config", config, "Configuration", "fawkes");
149  __lua->set_usertype("logger", __clog, "ComponentLogger", "fawkes");
150  __lua->set_usertype("clock", clock, "Clock", "fawkes");
151 #ifdef HAVE_TF
152  __lua->set_usertype("tf", tf_listener, "Transformer", "fawkes::tf");
153 #endif
154 
155  __lua_ifi->add_interface("skiller", __skiller_if);
156  __lua_ifi->add_interface("agdbg", __agdbg_if);
157 
158  __lua_ifi->push_interfaces();
159 
160  __lua->set_start_script(LUADIR"/luaagent/fawkes/start.lua");
161  } catch (Exception &e) {
162  init_failure_cleanup();
163  throw;
164  }
165 
166  __agdbg_if->set_graph("");
167  __agdbg_if->set_graph_fsm(__cfg_agent.c_str());
168 
169 }
170 
171 
172 void
174 {
175  if (__skiller_if->has_writer() ) {
177  }
178 
179  blackboard->close(__skiller_if);
180  blackboard->close(__agdbg_if);
181 
182  delete __lua_ifi;
183  delete __lua;
184  delete __clog;
185 }
186 
187 void
188 LuaAgentPeriodicExecutionThread::process_agdbg_messages()
189 {
190  while ( ! __agdbg_if->msgq_empty() ) {
193  try {
194  std::string graphdir = "TB";
195  switch (m->graph_dir()) {
196  case SkillerDebugInterface::GD_BOTTOM_TOP: graphdir = "BT"; break;
197  case SkillerDebugInterface::GD_LEFT_RIGHT: graphdir = "LR"; break;
198  case SkillerDebugInterface::GD_RIGHT_LEFT: graphdir = "RL"; break;
199  default: break;
200  }
201  __lua->do_string("agentenv.set_graphdir(\"%s\")", graphdir.c_str());
202  } catch (Exception &e) {
203  logger->log_warn("LuaAgentPeriodicExecutionThread", "Failed to set graph direction, exception follows");
204  logger->log_warn("LuaAgentPeriodicExecutionThread", e);
205  }
208  try {
209  __lua->do_string("agentenv.set_graph_colored(%s)", m->is_graph_colored() ? "true" : "false");
210  } catch (Exception &e) {
211  logger->log_warn("LuaAgentPeriodicExecutionThread", "Failed to set graph direction, exception follows");
212  logger->log_warn("LuaAgentPeriodicExecutionThread", e);
213  }
214  }
215 
216  __agdbg_if->msgq_pop();
217  }
218 }
219 
220 
221 void
223 {
224 #ifdef HAVE_INOTIFY
225  __lua->process_fam_events();
226 #endif
227 
228  process_agdbg_messages();
229 
230  __lua_ifi->read();
231  __skiller_if->read();
232 
233  try {
234  // Stack:
235  __lua->do_string("agentenv.execute()");
236  } catch (Exception &e) {
237  logger->log_error("LuaAgentPeriodicExecutionThread", "Execution of %s.execute() failed, exception follows",
238  __cfg_agent.c_str());
239  logger->log_error("LuaAgentPeriodicExecutionThread", e);
240  }
241 
242  __lua_ifi->write();
243 }
void set_graph(const char *new_graph)
Set graph value.
SkillerDebugInterface Fawkes BlackBoard Interface.
void setup_fam(bool auto_restart, bool conc_thread)
Setup file alteration monitor.
Definition: context.cpp:128
bool msgq_empty()
Check if queue is empty.
Definition: interface.cpp:1048
virtual void init()
Initialize the thread.
Fawkes library namespace.
virtual bool get_bool(const char *path)=0
Get value from configuration which is of type bool.
GraphDirectionEnum graph_dir() const
Get graph_dir value.
STL namespace.
ReleaseControlMessage Fawkes BlackBoard Interface Message.
void add_package_dir(const char *path, bool prefix=false)
Add a Lua package directory.
Definition: context.cpp:331
uint32_t exclusive_controller() const
Get exclusive_controller value.
Thread class encapsulation of pthreads.
Definition: thread.h:42
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:383
Clock * clock
By means of this member access to the clock is given.
Definition: clock.h:45
Thread aspect to use blocked timing.
void msgq_pop()
Erase first message from queue.
Definition: interface.cpp:1193
virtual void finalize()
Finalize the thread.
Base class for exceptions in Fawkes.
Definition: exception.h:36
Message * msgq_first()
Get the first message from the message queue.
Definition: interface.cpp:1180
void read()
Read from BlackBoard into local copy.
Definition: interface.cpp:477
void do_string(const char *format,...)
Execute string.
Definition: context.cpp:548
Lua interface importer.
void open_reading_interfaces(std::string &prefix)
Open interfaces for reading.
Lua C++ wrapper.
Definition: context.h:47
bool has_writer() const
Check if there is a writer for the interface.
Definition: interface.cpp:834
void set_graph_fsm(const char *new_graph_fsm)
Set graph_fsm value.
const char * name() const
Get name of thread.
Definition: thread.h:95
bool msgq_first_is()
Check if first message has desired type.
Definition: interface.h:314
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:689
virtual void log_error(const char *component, const char *format,...)=0
Log error message.
Component logger.
Definition: component.h:35
void set_string(const char *name, const char *value)
Assign string to global variable.
Definition: context.cpp:713
void add_interface(std::string varname, Interface *interface)
Add a single interface to be pushed to the context.
SetGraphColoredMessage Fawkes BlackBoard Interface Message.
unsigned int msgq_enqueue(Message *message)
Enqueue message at end of queue.
Definition: interface.cpp:903
void read()
Read from all reading interfaces.
void process_fam_events()
Process FAM events.
Definition: context.cpp:1436
virtual void log_debug(const char *component, const char *format,...)=0
Log debug message.
virtual Interface * open_for_reading(const char *interface_type, const char *identifier, const char *owner=NULL)=0
Open interface for reading.
void add_cpackage_dir(const char *path, bool prefix=false)
Add a Lua C package directory.
Definition: context.cpp:360
void set_start_script(const char *start_script)
Set start script.
Definition: context.cpp:266
void write()
Write all writing interfaces.
SkillerInterface Fawkes BlackBoard Interface.
virtual void loop()
Code to execute in the thread.
Configuration * config
This is the Configuration member used to access the configuration.
Definition: configurable.h:44
SetGraphDirectionMessage Fawkes BlackBoard Interface Message.
virtual Interface * open_for_writing(const char *interface_type, const char *identifier, const char *owner=NULL)=0
Open interface for writing.
virtual ~LuaAgentPeriodicExecutionThread()
Destructor.
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:44
virtual void close(Interface *interface)=0
Close interface.