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