Fawkes API
Fawkes Development Version
|
00001 00002 /*************************************************************************** 00003 * continuous_exec_thread.cpp - Fawkes LuaAgent: Continuous Execution Thread 00004 * 00005 * Created: Thu May 26 11:50:15 2011 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 "continuous_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 00043 LuaAgentContinuousExecutionThread *g_agent_thread = NULL; 00044 00045 static int l_read_interfaces(lua_State *L) 00046 { 00047 g_agent_thread->read_interfaces(); 00048 return 0; 00049 } 00050 00051 static int l_write_interfaces(lua_State *L) 00052 { 00053 g_agent_thread->write_interfaces(); 00054 return 0; 00055 } 00056 00057 00058 /** @class LuaAgentContinuousExecutionThread "periodic_exec_thread.h" 00059 * LuaAgent Periodic Execution Thread. 00060 * This thread runs and controls the Lua interpreter and passes data into the 00061 * execution engine. It hooks into the THINK main loop hook and expects the 00062 * agent's execution function to return quickly. If you have a separate agent 00063 * main loop use the concurrent execution thread. 00064 * 00065 * @author Tim Niemueller 00066 */ 00067 00068 /** Constructor. */ 00069 LuaAgentContinuousExecutionThread::LuaAgentContinuousExecutionThread() 00070 : Thread("LuaAgentContinuousExecutionThread", Thread::OPMODE_WAITFORWAKEUP), 00071 BlockedTimingAspect(BlockedTimingAspect::WAKEUP_HOOK_THINK) 00072 { 00073 __lua = NULL; 00074 if (g_agent_thread != NULL) { 00075 throw Exception("A global thread has already been set"); 00076 } 00077 g_agent_thread = this; 00078 } 00079 00080 00081 /** Destructor. */ 00082 LuaAgentContinuousExecutionThread::~LuaAgentContinuousExecutionThread() 00083 { 00084 g_agent_thread = NULL; 00085 } 00086 00087 00088 /** Clean up when init failed. 00089 * You may only call this from init(). Never ever call it from anywhere 00090 * else! 00091 */ 00092 void 00093 LuaAgentContinuousExecutionThread::init_failure_cleanup() 00094 { 00095 try { 00096 if ( __skiller_if ) { 00097 __skiller_if->msgq_enqueue(new SkillerInterface::ReleaseControlMessage()); 00098 blackboard->close(__skiller_if); 00099 } 00100 delete __lua_ifi; 00101 delete __lua_thread; 00102 delete __ifi_mutex; 00103 00104 } catch (...) { 00105 // we really screwed up, can't do anything about it, ignore error, logger is 00106 // initialized since this method is only called from init() which is only called if 00107 // all aspects had been initialized successfully 00108 logger->log_error(name(), "Really screwed up while finalizing, aborting cleanup. " 00109 "Fawkes is no longer in a clean state. Restart!"); 00110 } 00111 } 00112 00113 00114 void 00115 LuaAgentContinuousExecutionThread::init() 00116 { 00117 try { 00118 __cfg_agent = config->get_string("/luaagent/agent"); 00119 __cfg_watch_files = config->get_bool("/luaagent/watch_files"); 00120 } catch (Exception &e) { 00121 e.append("Insufficient configuration for LuaAgent"); 00122 throw; 00123 } 00124 00125 logger->log_debug("LuaAgentContinuousExecutionThread", "Agent: %s", __cfg_agent.c_str()); 00126 00127 __clog = new ComponentLogger(logger, "LuaAgentLua"); 00128 00129 __lua = NULL; 00130 __lua_ifi = NULL; 00131 __lua_thread = NULL; 00132 __skiller_if = NULL; 00133 __ifi_mutex = NULL; 00134 00135 std::string reading_prefix = "/luaagent/interfaces/" + __cfg_agent + "/reading/"; 00136 std::string writing_prefix = "/luaagent/interfaces/" + __cfg_agent + "/writing/"; 00137 00138 __skiller_if = blackboard->open_for_reading<SkillerInterface>("Skiller"); 00139 00140 __skiller_if->read(); 00141 if (__skiller_if->exclusive_controller() != 0) { 00142 throw Exception("Skiller already has an exclusive controller"); 00143 } 00144 00145 __skiller_if->msgq_enqueue(new SkillerInterface::AcquireControlMessage()); 00146 00147 try { 00148 __lua = new LuaContext(); 00149 if (__cfg_watch_files) { 00150 __lua->setup_fam(/* auto restart */ false, /* conc thread */ true); 00151 __lua->get_fam()->add_listener(this); 00152 } 00153 00154 __lua_ifi = new LuaInterfaceImporter(__lua, blackboard, config, logger); 00155 __lua_ifi->open_reading_interfaces(reading_prefix); 00156 __lua_ifi->open_writing_interfaces(writing_prefix); 00157 00158 __lua->add_package_dir(LUADIR); 00159 __lua->add_cpackage_dir(LUALIBDIR); 00160 00161 __lua->add_package("fawkesutils"); 00162 __lua->add_package("fawkesconfig"); 00163 __lua->add_package("fawkesinterface"); 00164 __lua->add_package("fawkesgeometry"); 00165 #ifdef HAVE_TF 00166 __lua->add_package("fawkestf"); 00167 #endif 00168 00169 __lua->set_string("AGENT", __cfg_agent.c_str()); 00170 __lua->set_usertype("config", config, "Configuration", "fawkes"); 00171 __lua->set_usertype("logger", __clog, "ComponentLogger", "fawkes"); 00172 __lua->set_usertype("clock", clock, "Clock", "fawkes"); 00173 #ifdef HAVE_TF 00174 __lua->set_usertype("tf", tf_listener, "Transformer", "fawkes::tf"); 00175 #endif 00176 __lua->set_cfunction("read_interfaces", l_read_interfaces); 00177 __lua->set_cfunction("write_interfaces", l_write_interfaces); 00178 00179 __lua_ifi->add_interface("skiller", __skiller_if); 00180 00181 __lua_ifi->read_to_buffer(); 00182 __lua_ifi->push_interfaces(); 00183 00184 __lua->set_start_script(LUADIR"/luaagent/start.lua"); 00185 00186 __lua_thread = new LuaThread(__lua); 00187 thread_collector->add(__lua_thread); 00188 00189 __ifi_mutex = new Mutex(); 00190 } catch (Exception &e) { 00191 init_failure_cleanup(); 00192 throw; 00193 } 00194 } 00195 00196 00197 void 00198 LuaAgentContinuousExecutionThread::finalize() 00199 { 00200 if (__skiller_if->has_writer() ) { 00201 __skiller_if->msgq_enqueue(new SkillerInterface::ReleaseControlMessage()); 00202 } 00203 00204 blackboard->close(__skiller_if); 00205 00206 if (__lua_thread) { 00207 thread_collector->remove(__lua_thread); 00208 delete __lua_thread; 00209 } 00210 00211 delete __lua_ifi; 00212 delete __ifi_mutex; 00213 delete __lua; 00214 delete __clog; 00215 } 00216 00217 00218 void 00219 LuaAgentContinuousExecutionThread::loop() 00220 { 00221 __ifi_mutex->lock(); 00222 00223 __lua_ifi->read_to_buffer(); 00224 __skiller_if->read(); 00225 00226 if (__lua_thread && __lua_thread->failed()) { 00227 logger->log_error(name(), "LuaThread failed, agent died, removing thread"); 00228 thread_collector->remove(__lua_thread); 00229 delete __lua_thread; 00230 __lua_thread = NULL; 00231 } 00232 __ifi_mutex->unlock(); 00233 } 00234 00235 00236 /** Update all reading interfaces. 00237 * This is meant to be called from inside Lua so that the agent can 00238 * update the set of interfaces at suitable points in time. 00239 */ 00240 void 00241 LuaAgentContinuousExecutionThread::read_interfaces() 00242 { 00243 __ifi_mutex->lock(); 00244 logger->log_debug(name(), "Reading interfaces"); 00245 __lua_ifi->read_from_buffer(); 00246 __ifi_mutex->unlock(); 00247 } 00248 00249 00250 /** Update all reading interfaces. 00251 * This is meant to be called from inside Lua so that the agent can 00252 * update the set of interfaces at suitable points in time. 00253 */ 00254 void 00255 LuaAgentContinuousExecutionThread::write_interfaces() 00256 { 00257 __ifi_mutex->lock(); 00258 logger->log_debug(name(), "Writing interfaces"); 00259 __lua_ifi->write(); 00260 __ifi_mutex->unlock(); 00261 } 00262 00263 void 00264 LuaAgentContinuousExecutionThread::fam_event(const char *filename, 00265 unsigned int mask) 00266 { 00267 if (__lua_thread) { 00268 __lua_thread->cancel(); 00269 __lua_thread->join(); 00270 } 00271 00272 __ifi_mutex->lock(); 00273 logger->log_warn(name(), "Restarting Lua context"); 00274 __lua->restart(); 00275 __lua_thread->start(); 00276 __ifi_mutex->unlock(); 00277 } 00278 00279 00280 /** Constructor. 00281 * @param lua Lua context to use 00282 */ 00283 LuaAgentContinuousExecutionThread::LuaThread::LuaThread(fawkes::LuaContext *lua) 00284 : Thread("LuaAgentContinuousExecutionThread::LuaThread", 00285 Thread::OPMODE_CONTINUOUS) 00286 { 00287 set_prepfin_conc_loop(true); 00288 __lua = lua; 00289 __failed = false; 00290 } 00291 00292 00293 /** Loop method continuously calling agentenv.execute() in Lua. */ 00294 void 00295 LuaAgentContinuousExecutionThread::LuaThread::loop() 00296 { 00297 while (!__failed) { 00298 try { 00299 // Stack: 00300 __lua->do_string("agentenv.execute()"); 00301 } catch (Exception &e) { 00302 __failed = true; 00303 logger->log_error(name(), "execute() failed, exception follows"); 00304 logger->log_error(name(), e); 00305 } 00306 } 00307 }