Fawkes API  Fawkes Development Version
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
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  __lua->add_package("fawkesgeometry");
144 #ifdef HAVE_TF
145  __lua->add_package("fawkestf");
146 #endif
147 
148  __lua->set_string("AGENT", __cfg_agent.c_str());
149  __lua->set_usertype("config", config, "Configuration", "fawkes");
150  __lua->set_usertype("logger", __clog, "ComponentLogger", "fawkes");
151  __lua->set_usertype("clock", clock, "Clock", "fawkes");
152 #ifdef HAVE_TF
153  __lua->set_usertype("tf", tf_listener, "Transformer", "fawkes::tf");
154 #endif
155 
156  __lua_ifi->add_interface("skiller", __skiller_if);
157  __lua_ifi->add_interface("agdbg", __agdbg_if);
158 
159  __lua_ifi->push_interfaces();
160 
161  __lua->set_start_script(LUADIR"/luaagent/start.lua");
162  } catch (Exception &e) {
163  init_failure_cleanup();
164  throw;
165  }
166 
167  __agdbg_if->set_graph("");
168  __agdbg_if->set_graph_fsm(__cfg_agent.c_str());
169 
170 }
171 
172 
173 void
175 {
176  if (__skiller_if->has_writer() ) {
178  }
179 
180  blackboard->close(__skiller_if);
181  blackboard->close(__agdbg_if);
182 
183  delete __lua_ifi;
184  delete __lua;
185  delete __clog;
186 }
187 
188 void
189 LuaAgentPeriodicExecutionThread::process_agdbg_messages()
190 {
191  while ( ! __agdbg_if->msgq_empty() ) {
194  try {
195  std::string graphdir = "TB";
196  switch (m->graph_dir()) {
197  case SkillerDebugInterface::GD_BOTTOM_TOP: graphdir = "BT"; break;
198  case SkillerDebugInterface::GD_LEFT_RIGHT: graphdir = "LR"; break;
199  case SkillerDebugInterface::GD_RIGHT_LEFT: graphdir = "RL"; break;
200  default: break;
201  }
202  __lua->do_string("agentenv.set_graphdir(\"%s\")", graphdir.c_str());
203  } catch (Exception &e) {
204  logger->log_warn("LuaAgentPeriodicExecutionThread", "Failed to set graph direction, exception follows");
205  logger->log_warn("LuaAgentPeriodicExecutionThread", e);
206  }
209  try {
210  __lua->do_string("agentenv.set_graph_colored(%s)", m->is_graph_colored() ? "true" : "false");
211  } catch (Exception &e) {
212  logger->log_warn("LuaAgentPeriodicExecutionThread", "Failed to set graph direction, exception follows");
213  logger->log_warn("LuaAgentPeriodicExecutionThread", e);
214  }
215  }
216 
217  __agdbg_if->msgq_pop();
218  }
219 }
220 
221 
222 void
224 {
225 #ifdef HAVE_INOTIFY
226  __lua->process_fam_events();
227 #endif
228 
229  process_agdbg_messages();
230 
231  __lua_ifi->read();
232  __skiller_if->read();
233 
234  try {
235  // Stack:
236  __lua->do_string("agentenv.execute()");
237  } catch (Exception &e) {
238  logger->log_error("LuaAgentPeriodicExecutionThread", "Execution of %s.execute() failed, exception follows",
239  __cfg_agent.c_str());
240  logger->log_error("LuaAgentPeriodicExecutionThread", e);
241  }
242 
243  __lua_ifi->write();
244 }