exec_thread.cpp

00001
00002 /***************************************************************************
00003  *  exec_thread.cpp - Fawkes LuaAgent: Execution Thread
00004  *
00005  *  Created: Thu Jan 01 11:12:13 2009
00006  *  Copyright  2006-2009  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 "exec_thread.h"
00024
00025 #include <core/exceptions/software.h>
00026 #include <core/exceptions/system.h>
00027 #include <core/threading/mutex.h>
00028 #include <utils/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 LuaAgentExecutionThread "exec_thread.h"
00043  * LuaAgent Execution Thread.
00044  * This thread runs and controls the Lua interpreter and passes data into the
00045  * execution engine.
00046  *
00047  * @author Tim Niemueller
00048  */
00049 
00050 /** Constructor. */
00051 LuaAgentExecutionThread::LuaAgentExecutionThread()
00052   : Thread("LuaAgentExecutionThread", Thread::OPMODE_WAITFORWAKEUP),
00053     BlockedTimingAspect(BlockedTimingAspect::WAKEUP_HOOK_THINK)
00054 {
00055   __lua = NULL;
00056 }
00057
00058 
00059 /** Destructor. */
00060 LuaAgentExecutionThread::~LuaAgentExecutionThread()
00061 {
00062 }
00063
00064 
00065 /** Clean up when init failed.
00066  * You may only call this from init(). Never ever call it from anywhere
00067  * else!
00068  */
00069 void
00070 LuaAgentExecutionThread::init_failure_cleanup()
00071 {
00072   try {
00073     if ( __skiller_if ) blackboard->close(__skiller_if);
00074     if ( __agdbg_if )   blackboard->close(__agdbg_if);
00075
00076     delete __lua_ifi;
00077
00078   } catch (...) {
00079     // we really screwed up, can't do anything about it, ignore error, logger is
00080     // initialized since this method is only called from init() which is only called if
00081     // all aspects had been initialized successfully
00082     logger->log_error(name(), "Really screwed up while finalizing, aborting cleanup. "
00083                               "Fawkes is no longer in a clean state. Restart!");
00084   }
00085 }
00086
00087
00088 void
00089 LuaAgentExecutionThread::init()
00090 {
00091   try {
00092     __cfg_agent       = config->get_string("/luaagent/agent");
00093     __cfg_watch_files = config->get_bool("/luaagent/watch_files");
00094   } catch (Exception &e) {
00095     e.append("Insufficient configuration for LuaAgent");
00096     throw;
00097   }
00098
00099   logger->log_debug("LuaAgentExecutionThread", "Agent: %s", __cfg_agent.c_str());
00100
00101   __clog = new ComponentLogger(logger, "LuaAgentLua");
00102
00103   __lua = NULL;
00104   __lua_ifi = NULL;
00105   __skiller_if = NULL;
00106   __agdbg_if = NULL;
00107
00108   std::string reading_prefix = "/luaagent/interfaces/" + __cfg_agent + "/reading/";
00109   std::string writing_prefix = "/luaagent/interfaces/" + __cfg_agent + "/writing/";
00110
00111   __skiller_if = blackboard->open_for_reading<SkillerInterface>("Skiller");
00112
00113   __skiller_if->read();
00114   if (__skiller_if->exclusive_controller() != 0) {
00115     throw Exception("Skiller already has an exclusive controller");
00116   }
00117
00118   __skiller_if->msgq_enqueue(new SkillerInterface::AcquireControlMessage());
00119   __agdbg_if   = blackboard->open_for_writing<SkillerDebugInterface>("LuaAgent");
00120
00121   try {
00122     __lua  = new LuaContext(__cfg_watch_files);
00123
00124     __lua_ifi = new LuaInterfaceImporter(__lua, blackboard, config, logger);
00125     __lua_ifi->open_reading_interfaces(reading_prefix);
00126     __lua_ifi->open_writing_interfaces(writing_prefix);
00127
00128     __lua->add_package_dir(LUADIR);
00129     __lua->add_cpackage_dir(LUALIBDIR);
00130
00131     __lua->add_package("fawkesutils");
00132     __lua->add_package("fawkesconfig");
00133     __lua->add_package("fawkesinterface");
00134
00135     __lua->set_string("AGENT", __cfg_agent.c_str());
00136     __lua->set_usertype("config", config, "Configuration", "fawkes");
00137     __lua->set_usertype("logger", __clog, "ComponentLogger", "fawkes");
00138     __lua->set_usertype("clock", clock, "Clock", "fawkes");
00139
00140     __lua_ifi->add_interface("skiller", __skiller_if);
00141     __lua_ifi->add_interface("agdbg", __agdbg_if);
00142
00143     __lua_ifi->push_interfaces();
00144
00145     __lua->set_start_script(LUADIR"/luaagent/start.lua");
00146   } catch (Exception &e) {
00147     init_failure_cleanup();
00148     throw;
00149   }
00150
00151   __agdbg_if->set_graph("");
00152   __agdbg_if->set_graph_fsm(__cfg_agent.c_str());
00153
00154 }
00155
00156
00157 void
00158 LuaAgentExecutionThread::finalize()
00159 {
00160   if (__skiller_if->has_writer() ) {
00161     __skiller_if->msgq_enqueue(new SkillerInterface::ReleaseControlMessage());
00162   }
00163
00164   blackboard->close(__skiller_if);
00165   blackboard->close(__agdbg_if);
00166
00167   delete __lua_ifi;
00168   delete __lua;
00169   delete __clog;
00170 }
00171
00172 void
00173 LuaAgentExecutionThread::process_agdbg_messages()
00174 {
00175   while ( ! __agdbg_if->msgq_empty() ) {
00176     if (__agdbg_if->msgq_first_is<SkillerDebugInterface::SetGraphDirectionMessage>() ) {
00177       SkillerDebugInterface::SetGraphDirectionMessage *m = __agdbg_if->msgq_first<SkillerDebugInterface::SetGraphDirectionMessage>();
00178       try {
00179         std::string graphdir = "TB";
00180         switch (m->graph_dir()) {
00181         case SkillerDebugInterface::GD_BOTTOM_TOP: graphdir = "BT"; break;
00182         case SkillerDebugInterface::GD_LEFT_RIGHT: graphdir = "LR"; break;
00183         case SkillerDebugInterface::GD_RIGHT_LEFT: graphdir = "RL"; break;
00184         default: break;
00185         }
00186         __lua->do_string("agentenv.set_graphdir(\"%s\")", graphdir.c_str());
00187       } catch (Exception &e) {
00188         logger->log_warn("LuaAgentExecutionThread", "Failed to set graph direction, exception follows");
00189         logger->log_warn("LuaAgentExecutionThread", e);
00190       }
00191     } else if (__agdbg_if->msgq_first_is<SkillerDebugInterface::SetGraphColoredMessage>() ) {
00192       SkillerDebugInterface::SetGraphColoredMessage *m = __agdbg_if->msgq_first<SkillerDebugInterface::SetGraphColoredMessage>();
00193       try {
00194         __lua->do_string("agentenv.set_graph_colored(%s)", m->is_graph_colored() ? "true" : "false");
00195       } catch (Exception &e) {
00196         logger->log_warn("LuaAgentExecutionThread", "Failed to set graph direction, exception follows");
00197         logger->log_warn("LuaAgentExecutionThread", e);
00198       }
00199     }
00200
00201     __agdbg_if->msgq_pop();
00202   }
00203 }
00204
00205
00206 void
00207 LuaAgentExecutionThread::loop()
00208 {
00209 #ifdef HAVE_INOTIFY
00210   __lua->process_fam_events();
00211 #endif
00212 
00213   process_agdbg_messages();
00214
00215   __lua_ifi->read();
00216   __skiller_if->read();
00217
00218   try {
00219     // Stack:
00220     __lua->do_string("agentenv.execute()");
00221   } catch (Exception &e) {
00222     logger->log_error("LuaAgentExecutionThread", "Execution of %s.execute() failed, exception follows",
00223                       __cfg_agent.c_str());
00224     logger->log_error("LuaAgentExecutionThread", e);
00225   }
00226
00227   __lua_ifi->write();
00228 }