OrocosComponentLibrary  2.7.0
LuaComponent.cpp
00001 /*
00002  * Lua-RTT bindings. LuaComponent.
00003  *
00004  * (C) Copyright 2010 Markus Klotzbuecher
00005  * markus.klotzbuecher@mech.kuleuven.be
00006  * Department of Mechanical Engineering,
00007  * Katholieke Universiteit Leuven, Belgium.
00008  *
00009  * This library is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU General Public
00011  * License as published by the Free Software Foundation;
00012  * version 2 of the License.
00013  *
00014  * As a special exception, you may use this file as part of a free
00015  * software library without restriction.  Specifically, if other files
00016  * instantiate templates or use macros or inline functions from this
00017  * file, or you compile this file and link it with other files to
00018  * produce an executable, this file does not by itself cause the
00019  * resulting executable to be covered by the GNU General Public
00020  * License.  This exception does not however invalidate any other
00021  * reasons why the executable file might be covered by the GNU General
00022  * Public License.
00023  *
00024  * This library is distributed in the hope that it will be useful,
00025  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00026  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00027  * Lesser General Public License for more details.
00028  *
00029  * You should have received a copy of the GNU General Public
00030  * License along with this library; if not, write to the Free Software
00031  * Foundation, Inc., 59 Temple Place,
00032  * Suite 330, Boston, MA  02111-1307  USA
00033  */
00034 
00035 #ifndef OCL_COMPONENT_ONLY
00036 
00037 #include <rtt/rtt-config.h>
00038 #ifdef OS_RT_MALLOC
00039 // need access to all TLSF functions embedded in RTT
00040 #define ORO_MEMORY_POOL
00041 #include <rtt/os/tlsf/tlsf.h>
00042 #endif
00043 #include <rtt/os/main.h>
00044 #include <rtt/RTT.hpp>
00045 #include <rtt/Logger.hpp>
00046 #ifdef  ORO_BUILD_LOGGING
00047 #   ifndef OS_RT_MALLOC
00048 #   warning "Logging needs rtalloc!"
00049 #   endif
00050 #include <log4cpp/HierarchyMaintainer.hh>
00051 #include "logging/Category.hpp"
00052 #endif
00053 
00054 extern "C" {
00055 #include "lua-repl.h"
00056 void dotty (lua_State *L);
00057 void l_message (const char *pname, const char *msg);
00058 int dofile (lua_State *L, const char *name);
00059 int dostring (lua_State *L, const char *s, const char *name);
00060 int main_args(lua_State *L, int argc, char **argv);
00061 
00062 #include <sys/types.h>
00063 #include <sys/stat.h>
00064 #include <unistd.h>
00065 #include <wordexp.h>
00066 }
00067 #endif
00068 
00069 #include "rtt.hpp"
00070 
00071 #include <string>
00072 #include <rtt/os/main.h>
00073 #include <rtt/os/Mutex.hpp>
00074 #include <rtt/os/MutexLock.hpp>
00075 #include <rtt/TaskContext.hpp>
00076 #include <ocl/OCL.hpp>
00077 #if defined(LUA_RTT_CORBA)
00078 #include <rtt/transports/corba/TaskContextServer.hpp>
00079 #include <deployment/CorbaDeploymentComponent.hpp>
00080 #else
00081 #include <deployment/DeploymentComponent.hpp>
00082 #endif
00083 
00084 #ifdef LUA_RTT_TLSF
00085 extern "C" {
00086 #include "tlsf_rtt.h"
00087 }
00088 #endif
00089 
00090 #ifdef LUA_RTT_TLSF
00091 #define LuaComponent LuaTLSFComponent
00092 #else
00093 #define LuaComponent LuaComponent
00094 #endif
00095 
00096 #define INIT_FILE   "~/.rttlua"
00097 
00098 using namespace std;
00099 using namespace RTT;
00100 using namespace Orocos;
00101 #if defined(LUA_RTT_CORBA)
00102 using namespace RTT::corba;
00103 #endif
00104 
00105 namespace OCL
00106 {
00107     class LuaComponent : public TaskContext
00108     {
00109     protected:
00110         std::string lua_string;
00111         std::string lua_file;
00112         lua_State *L;
00113         os::MutexRecursive m;
00114 #if LUA_RTT_TLSF
00115         struct lua_tlsf_info tlsf_inf;
00116 #endif
00117 
00118     public:
00119         LuaComponent(std::string name)
00120             : TaskContext(name, PreOperational)
00121         {
00122             os::MutexLock lock(m);
00123 #if LUA_RTT_TLSF
00124             if(tlsf_rtt_init_mp(&tlsf_inf, TLSF_INITIAL_POOLSIZE)) {
00125                 Logger::log(Logger::Error) << "LuaComponent '" << name << ": failed to create tlsf pool ("
00126                                << std::hex << TLSF_INITIAL_POOLSIZE << "bytes)" << endlog();
00127                 throw;
00128             }
00129 
00130             L = lua_newstate(tlsf_alloc, &tlsf_inf);
00131             tlsf_inf.L = L;
00132             set_context_tlsf_info(&tlsf_inf);
00133             register_tlsf_api(L);
00134 #else
00135             L = luaL_newstate();
00136 #endif
00137             if (L == NULL) {
00138                 Logger::log(Logger::Error) << "LuaComponent '" << name
00139                                << "': failed to allocate memory for Lua state" << endlog();
00140                 throw;
00141             }
00142 
00143             lua_gc(L, LUA_GCSTOP, 0);
00144             luaL_openlibs(L);
00145             lua_gc(L, LUA_GCRESTART, 0);
00146 
00147             /* setup rtt bindings */
00148             lua_pushcfunction(L, luaopen_rtt);
00149             lua_call(L, 0, 0);
00150 
00151             set_context_tc(this, L);
00152 
00153             this->addProperty("lua_string", lua_string).doc("string of lua code to be executed during configureHook");
00154             this->addProperty("lua_file", lua_file).doc("file with lua program to be executed during configuration");
00155 
00156             this->addOperation("exec_file", &LuaComponent::exec_file, this, OwnThread)
00157                 .doc("load (and run) the given lua script")
00158                 .arg("filename", "filename of the lua script");
00159 
00160             this->addOperation("exec_str", &LuaComponent::exec_str, this, OwnThread)
00161                 .doc("evaluate the given string in the lua environment")
00162                 .arg("lua-string", "string of lua code to evaluate");
00163 
00164 #ifdef LUA_RTT_TLSF
00165             this->addOperation("tlsf_incmem", &LuaComponent::tlsf_incmem, this, OwnThread)
00166                 .doc("increase the TLSF memory pool")
00167                 .arg("size", "size in bytes to add to pool");
00168 #endif
00169         }
00170 
00171         ~LuaComponent()
00172         {
00173             os::MutexLock lock(m);
00174             lua_close(L);
00175 #ifdef LUA_RTT_TLSF
00176             tlsf_rtt_free_mp(&tlsf_inf);
00177 #endif
00178         }
00179 
00180 #ifdef LUA_RTT_TLSF
00181         bool tlsf_incmem(unsigned int size)
00182         {
00183             return tlsf_rtt_incmem(&tlsf_inf, size);
00184         }
00185 #endif
00186 
00187 
00188         bool exec_file(const std::string &file)
00189         {
00190             os::MutexLock lock(m);
00191             if (luaL_dofile(L, file.c_str())) {
00192                 Logger::log(Logger::Error) << "LuaComponent '" << this->getName() << "': " << lua_tostring(L, -1) << endlog();
00193                 return false;
00194             }
00195             return true;
00196         }
00197 
00198         bool exec_str(const std::string &str)
00199         {
00200             os::MutexLock lock(m);
00201             if (luaL_dostring(L, str.c_str())) {
00202                 Logger::log(Logger::Error) << "LuaComponent '" << this->getName() << "': " << lua_tostring(L, -1) << endlog();
00203                 return false;
00204             }
00205             return true;
00206         }
00207 
00208 #ifndef OCL_COMPONENT_ONLY
00209         void lua_repl()
00210         {
00211             os::MutexLock lock(m);
00212             dotty(L);
00213         }
00214 
00215         int lua_repl(int argc, char **argv)
00216         {
00217             os::MutexLock lock(m);
00218             return main_args(L, argc, argv);
00219         }
00220 #endif
00221         bool configureHook()
00222         {
00223             if(!lua_string.empty())
00224                 exec_str(lua_string);
00225 
00226             if(!lua_file.empty())
00227                 exec_file(lua_file);
00228             return call_func(L, "configureHook", this, 0, 1);
00229         }
00230 
00231         bool activateHook()
00232         {
00233             os::MutexLock lock(m);
00234             return call_func(L, "activateHook", this, 0, 1);
00235         }
00236 
00237         bool startHook()
00238         {
00239             os::MutexLock lock(m);
00240             return call_func(L, "startHook", this, 0, 1);
00241         }
00242 
00243         void updateHook()
00244         {
00245             os::MutexLock lock(m);
00246             call_func(L, "updateHook", this, 0, 0);
00247         }
00248 
00249         void stopHook()
00250         {
00251             os::MutexLock lock(m);
00252             call_func(L, "stopHook", this, 0, 0);
00253         }
00254 
00255         void cleanupHook()
00256         {
00257             os::MutexLock lock(m);
00258             call_func(L, "cleanupHook", this, 0, 0);
00259         }
00260 
00261         void errorHook()
00262         {
00263             os::MutexLock lock(m);
00264             call_func(L, "errorHook", this, 0, 0);
00265         }
00266     };
00267 }
00268 
00269 
00270 #ifndef OCL_COMPONENT_ONLY
00271 
00272 int ORO_main(int argc, char** argv)
00273 {
00274     struct stat stb;
00275     wordexp_t init_exp;
00276 
00277 #ifdef  ORO_BUILD_RTALLOC
00278     size_t                  memSize     = ORO_DEFAULT_RTALLOC_SIZE;
00279     void*                   rtMem       = 0;
00280     size_t                  freeMem     = 0;
00281     if (0 < memSize)
00282     {
00283         // don't calloc() as is first thing TLSF does.
00284         rtMem = malloc(memSize);
00285         assert(0 != rtMem);
00286         freeMem = init_memory_pool(memSize, rtMem);
00287         if ((size_t)-1 == freeMem)
00288         {
00289             cerr << "Invalid memory pool size of " << memSize 
00290                           << " bytes (TLSF has a several kilobyte overhead)." << endl;
00291             free(rtMem);
00292             return -1;
00293         }
00294         cout << "Real-time memory: " << freeMem << " bytes free of "
00295                   << memSize << " allocated." << endl;
00296     }
00297 #endif  // ORO_BUILD_RTALLOC
00298 
00299 #ifdef  ORO_BUILD_LOGGING
00300     log4cpp::HierarchyMaintainer::set_category_factory(
00301         OCL::logging::Category::createOCLCategory);
00302 #endif
00303 
00304     LuaComponent lua("lua");
00305     DeploymentComponent * dc = 0;
00306 
00307 #if defined(LUA_RTT_CORBA)
00308     int  orb_argc = argc;
00309     char** orb_argv = 0;
00310     char* orb_sep = 0;
00311         
00312     /* find the "--" separator */
00313     while(orb_argc) {
00314       if(0 == strcmp("--", argv[argc - orb_argc])) {
00315         orb_sep = argv[argc - orb_argc];
00316         argv[argc - orb_argc] = argv[0];
00317         orb_argv = &argv[argc - orb_argc];
00318         argc -= orb_argc;
00319         break;
00320       }
00321       orb_argc--;
00322     }
00323         
00324     /* if the "--" separator is found perhaps we have orb arguments */
00325     if(orb_argc) {
00326       try {
00327         TaskContextServer::InitOrb(orb_argc, orb_argv);
00328    
00329         dc = new CorbaDeploymentComponent("Deployer");
00330    
00331         TaskContextServer::Create( dc, true, true );
00332    
00333         // The orb thread accepts incomming CORBA calls.
00334         TaskContextServer::ThreadOrb();
00335       } 
00336       catch( CORBA::Exception &e ) {
00337         log(Error) << argv[0] <<" ORO_main : CORBA exception raised!" << Logger::nl;
00338         log() << CORBA_EXCEPTION_INFO(e) << endlog();
00339         if(dc)
00340         {
00341           delete dc;
00342           dc = 0;
00343         }
00344       } catch (...) {
00345         log(Error) << "Uncaught exception." << endlog();
00346         if(dc)
00347         {
00348           delete dc;
00349           dc = 0;
00350         }
00351       }
00352  
00353       argv[argc] = dc?NULL:orb_sep;
00354     }
00355 
00356     /* fallback to the default deployer if corba have failed to provide one */
00357     if(!dc)
00358 #endif
00359     dc = new DeploymentComponent("Deployer");
00360 
00361     lua.connectPeers(dc);
00362 
00363     /* run init file */
00364     wordexp(INIT_FILE, &init_exp, 0);
00365     if(stat(init_exp.we_wordv[0], &stb) != -1) {
00366         if((stb.st_mode & S_IFMT) != S_IFREG)
00367             cout << "rttlua: warning: init file " << init_exp.we_wordv[0] << " is not a regular file" << endl;
00368         else
00369             lua.exec_file(init_exp.we_wordv[0]);
00370     }
00371     wordfree(&init_exp);
00372 
00373     lua.lua_repl(argc, argv);
00374 
00375 #if defined(LUA_RTT_CORBA)
00376     if(orb_argc) {
00377       TaskContextServer::ShutdownOrb();
00378       TaskContextServer::DestroyOrb();
00379     }
00380 #endif
00381 
00382     delete dc;
00383 
00384 #ifdef  ORO_BUILD_LOGGING
00385     log4cpp::HierarchyMaintainer::getDefaultMaintainer().shutdown();
00386     log4cpp::HierarchyMaintainer::getDefaultMaintainer().deleteAllCategories();
00387 #endif
00388 
00389 #ifdef  ORO_BUILD_RTALLOC
00390     if (0 != rtMem)
00391     {
00392         std::cout << "TLSF bytes allocated=" << memSize
00393                   << " overhead=" << (memSize - freeMem)
00394                   << " max-used=" << get_max_size(rtMem)
00395                   << " currently-used=" << get_used_size(rtMem)
00396                   << " still-allocated=" << (get_used_size(rtMem) - (memSize - freeMem))
00397                   << "\n";
00398 
00399         destroy_memory_pool(rtMem);
00400         free(rtMem);
00401     }
00402 #endif
00403     return 0;
00404 }
00405 
00406 #else
00407 
00408 #include "ocl/Component.hpp"
00409 
00410 ORO_CREATE_COMPONENT( OCL::LuaComponent )
00411 #endif