Fawkes API
Fawkes Development Version
|
00001 00002 /*************************************************************************** 00003 * periodic_exec_thread.cpp - Fawkes LuaAgent: Periodic Execution Thread 00004 * 00005 * Created: Thu Jan 01 11:12:13 2009 00006 * Copyright 2006-2011 Tim Niemueller [www.niemueller.de] 00007 * 00008 ****************************************************************************/ 00009 00010 /* This program is free software; you can redistribute it and/or modify 00011 * it under the terms of the GNU General Public License as published by 00012 * the Free Software Foundation; either version 2 of the License, or 00013 * (at your option) any later version. 00014 * 00015 * This program is distributed in the hope that it will be useful, 00016 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00018 * GNU Library General Public License for more details. 00019 * 00020 * Read the full text in the LICENSE.GPL file in the doc directory. 00021 */ 00022 00023 #include "periodic_exec_thread.h" 00024 00025 #include <core/exceptions/software.h> 00026 #include <core/exceptions/system.h> 00027 #include <core/threading/mutex.h> 00028 #include <logging/component.h> 00029 00030 #include <lua/context.h> 00031 #include <lua/interface_importer.h> 00032 00033 #include <interfaces/SkillerInterface.h> 00034 #include <interfaces/SkillerDebugInterface.h> 00035 00036 #include <string> 00037 #include <cstring> 00038 00039 using namespace std; 00040 using namespace fawkes; 00041 00042 /** @class LuaAgentPeriodicExecutionThread "periodic_exec_thread.h" 00043 * LuaAgent Periodic Execution Thread. 00044 * This thread runs and controls the Lua interpreter and passes data into the 00045 * execution engine. It hooks into the THINK main loop hook and expects the 00046 * agent's execution function to return quickly. If you have a separate agent 00047 * main loop use the concurrent execution thread. 00048 * 00049 * @author Tim Niemueller 00050 */ 00051 00052 /** Constructor. */ 00053 LuaAgentPeriodicExecutionThread::LuaAgentPeriodicExecutionThread() 00054 : Thread("LuaAgentPeriodicExecutionThread", Thread::OPMODE_WAITFORWAKEUP), 00055 BlockedTimingAspect(BlockedTimingAspect::WAKEUP_HOOK_THINK) 00056 { 00057 __lua = NULL; 00058 } 00059 00060 00061 /** Destructor. */ 00062 LuaAgentPeriodicExecutionThread::~LuaAgentPeriodicExecutionThread() 00063 { 00064 } 00065 00066 00067 /** Clean up when init failed. 00068 * You may only call this from init(). Never ever call it from anywhere 00069 * else! 00070 */ 00071 void 00072 LuaAgentPeriodicExecutionThread::init_failure_cleanup() 00073 { 00074 try { 00075 if ( __skiller_if ) { 00076 __skiller_if->msgq_enqueue(new SkillerInterface::ReleaseControlMessage()); 00077 blackboard->close(__skiller_if); 00078 } 00079 if ( __agdbg_if ) blackboard->close(__agdbg_if); 00080 00081 delete __lua_ifi; 00082 00083 } catch (...) { 00084 // we really screwed up, can't do anything about it, ignore error, logger is 00085 // initialized since this method is only called from init() which is only called if 00086 // all aspects had been initialized successfully 00087 logger->log_error(name(), "Really screwed up while finalizing, aborting cleanup. " 00088 "Fawkes is no longer in a clean state. Restart!"); 00089 } 00090 } 00091 00092 00093 void 00094 LuaAgentPeriodicExecutionThread::init() 00095 { 00096 try { 00097 __cfg_agent = config->get_string("/luaagent/agent"); 00098 __cfg_watch_files = config->get_bool("/luaagent/watch_files"); 00099 } catch (Exception &e) { 00100 e.append("Insufficient configuration for LuaAgent"); 00101 throw; 00102 } 00103 00104 logger->log_debug("LuaAgentPeriodicExecutionThread", "Agent: %s", __cfg_agent.c_str()); 00105 00106 __clog = new ComponentLogger(logger, "LuaAgentLua"); 00107 00108 __lua = NULL; 00109 __lua_ifi = NULL; 00110 __skiller_if = NULL; 00111 __agdbg_if = NULL; 00112 00113 std::string reading_prefix = "/luaagent/interfaces/" + __cfg_agent + "/reading/"; 00114 std::string writing_prefix = "/luaagent/interfaces/" + __cfg_agent + "/writing/"; 00115 00116 __skiller_if = blackboard->open_for_reading<SkillerInterface>("Skiller"); 00117 00118 __skiller_if->read(); 00119 if (__skiller_if->exclusive_controller() != 0) { 00120 throw Exception("Skiller already has an exclusive controller"); 00121 } 00122 00123 __skiller_if->msgq_enqueue(new SkillerInterface::AcquireControlMessage()); 00124 __agdbg_if = blackboard->open_for_writing<SkillerDebugInterface>("LuaAgent"); 00125 00126 try { 00127 __lua = new LuaContext(); 00128 if (__cfg_watch_files) { 00129 __lua->setup_fam(/* auto restart */ true, /* conc thread */ false); 00130 } 00131 00132 __lua_ifi = new LuaInterfaceImporter(__lua, blackboard, config, logger); 00133 __lua_ifi->open_reading_interfaces(reading_prefix); 00134 __lua_ifi->open_writing_interfaces(writing_prefix); 00135 00136 __lua->add_package_dir(LUADIR); 00137 __lua->add_cpackage_dir(LUALIBDIR); 00138 00139 __lua->add_package("fawkesutils"); 00140 __lua->add_package("fawkesconfig"); 00141 __lua->add_package("fawkeslogging"); 00142 __lua->add_package("fawkesinterface"); 00143 __lua->add_package("fawkesgeometry"); 00144 #ifdef HAVE_TF 00145 __lua->add_package("fawkestf"); 00146 #endif 00147 00148 __lua->set_string("AGENT", __cfg_agent.c_str()); 00149 __lua->set_usertype("config", config, "Configuration", "fawkes"); 00150 __lua->set_usertype("logger", __clog, "ComponentLogger", "fawkes"); 00151 __lua->set_usertype("clock", clock, "Clock", "fawkes"); 00152 #ifdef HAVE_TF 00153 __lua->set_usertype("tf", tf_listener, "Transformer", "fawkes::tf"); 00154 #endif 00155 00156 __lua_ifi->add_interface("skiller", __skiller_if); 00157 __lua_ifi->add_interface("agdbg", __agdbg_if); 00158 00159 __lua_ifi->push_interfaces(); 00160 00161 __lua->set_start_script(LUADIR"/luaagent/start.lua"); 00162 } catch (Exception &e) { 00163 init_failure_cleanup(); 00164 throw; 00165 } 00166 00167 __agdbg_if->set_graph(""); 00168 __agdbg_if->set_graph_fsm(__cfg_agent.c_str()); 00169 00170 } 00171 00172 00173 void 00174 LuaAgentPeriodicExecutionThread::finalize() 00175 { 00176 if (__skiller_if->has_writer() ) { 00177 __skiller_if->msgq_enqueue(new SkillerInterface::ReleaseControlMessage()); 00178 } 00179 00180 blackboard->close(__skiller_if); 00181 blackboard->close(__agdbg_if); 00182 00183 delete __lua_ifi; 00184 delete __lua; 00185 delete __clog; 00186 } 00187 00188 void 00189 LuaAgentPeriodicExecutionThread::process_agdbg_messages() 00190 { 00191 while ( ! __agdbg_if->msgq_empty() ) { 00192 if (__agdbg_if->msgq_first_is<SkillerDebugInterface::SetGraphDirectionMessage>() ) { 00193 SkillerDebugInterface::SetGraphDirectionMessage *m = __agdbg_if->msgq_first<SkillerDebugInterface::SetGraphDirectionMessage>(); 00194 try { 00195 std::string graphdir = "TB"; 00196 switch (m->graph_dir()) { 00197 case SkillerDebugInterface::GD_BOTTOM_TOP: graphdir = "BT"; break; 00198 case SkillerDebugInterface::GD_LEFT_RIGHT: graphdir = "LR"; break; 00199 case SkillerDebugInterface::GD_RIGHT_LEFT: graphdir = "RL"; break; 00200 default: break; 00201 } 00202 __lua->do_string("agentenv.set_graphdir(\"%s\")", graphdir.c_str()); 00203 } catch (Exception &e) { 00204 logger->log_warn("LuaAgentPeriodicExecutionThread", "Failed to set graph direction, exception follows"); 00205 logger->log_warn("LuaAgentPeriodicExecutionThread", e); 00206 } 00207 } else if (__agdbg_if->msgq_first_is<SkillerDebugInterface::SetGraphColoredMessage>() ) { 00208 SkillerDebugInterface::SetGraphColoredMessage *m = __agdbg_if->msgq_first<SkillerDebugInterface::SetGraphColoredMessage>(); 00209 try { 00210 __lua->do_string("agentenv.set_graph_colored(%s)", m->is_graph_colored() ? "true" : "false"); 00211 } catch (Exception &e) { 00212 logger->log_warn("LuaAgentPeriodicExecutionThread", "Failed to set graph direction, exception follows"); 00213 logger->log_warn("LuaAgentPeriodicExecutionThread", e); 00214 } 00215 } 00216 00217 __agdbg_if->msgq_pop(); 00218 } 00219 } 00220 00221 00222 void 00223 LuaAgentPeriodicExecutionThread::loop() 00224 { 00225 #ifdef HAVE_INOTIFY 00226 __lua->process_fam_events(); 00227 #endif 00228 00229 process_agdbg_messages(); 00230 00231 __lua_ifi->read(); 00232 __skiller_if->read(); 00233 00234 try { 00235 // Stack: 00236 __lua->do_string("agentenv.execute()"); 00237 } catch (Exception &e) { 00238 logger->log_error("LuaAgentPeriodicExecutionThread", "Execution of %s.execute() failed, exception follows", 00239 __cfg_agent.c_str()); 00240 logger->log_error("LuaAgentPeriodicExecutionThread", e); 00241 } 00242 00243 __lua_ifi->write(); 00244 }