Fawkes API  Fawkes Development Version
continuous_exec_thread.cpp
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 }