[Orxonox-commit 848] r3360 - in branches/resource/src: core cpptcl

landauf at orxonox.net landauf at orxonox.net
Tue Jul 28 17:04:38 CEST 2009


Author: landauf
Date: 2009-07-28 17:04:38 +0200 (Tue, 28 Jul 2009)
New Revision: 3360

Modified:
   branches/resource/src/core/TclBind.cc
   branches/resource/src/core/TclBind.h
   branches/resource/src/core/TclThreadManager.cc
   branches/resource/src/core/TclThreadManager.h
   branches/resource/src/cpptcl/changes_orxonox.diff
   branches/resource/src/cpptcl/cpptcl.cc
   branches/resource/src/cpptcl/cpptcl.h
Log:
- bugfix in TclBind: Tcl_Init was only called if the constructor of Tcl::interpreter was called with a library path. The initialization is now moved from cpptcl to TclBind.

- added a new command: TclThreadManager source <file>. This creates a non-interactive tcl-interpreter which executes a file. This allows for example to run the telnet_server.tcl script without a thread compatible tcl library. Warning: experimental state. A script-exit terminates Orxonox.

- Several small changes in TclThreadManager

Modified: branches/resource/src/core/TclBind.cc
===================================================================
--- branches/resource/src/core/TclBind.cc	2009-07-27 21:18:17 UTC (rev 3359)
+++ branches/resource/src/core/TclBind.cc	2009-07-28 15:04:38 UTC (rev 3360)
@@ -103,29 +103,40 @@
 
     Tcl::interpreter* TclBind::createTclInterpreter()
     {
-        Tcl::interpreter* interpreter;
-#ifdef DEPENDENCY_PACKAGE_ENABLE
-        if (Core::isDevelopmentRun())
-            interpreter = new Tcl::interpreter(std::string(ORXONOX_DEP_LIB_PATH) + "/tcl");
-        else
-            interpreter = new Tcl::interpreter(Core::getRootPathString() + "lib/tcl");
-#else
-        interpreter = new Tcl::interpreter();
-#endif
+        Tcl::interpreter* interpreter = new Tcl::interpreter();
+        std::string libpath = TclBind::getTclLibraryPath();
+
         try
         {
+            if (libpath != "")
+                interpreter->eval("set tcl_library \"" + libpath + "\"");
+
+            Tcl_Init(interpreter->get());
+
             interpreter->eval("source \"" + TclBind::getInstance().tclDataPath_ + "/init.tcl\"");
         }
         catch (Tcl::tcl_error const &e)
-        {   COUT(1) << "Tcl error while creating Tcl-interpreter: " << e.what() << std::endl;   }
+        {   COUT(1) << "Tcl error while creating Tcl-interpreter: " << e.what() << std::endl; COUT(1) << "Error: Tcl isn't properly initialized. Orxonox might possibly not work like that." << std::endl;   }
         catch (std::exception const &e)
-        {   COUT(1) << "Error while creating Tcl-interpreter: " << e.what() << std::endl;   }
+        {   COUT(1) << "Error while creating Tcl-interpreter: " << e.what() << std::endl; COUT(1) << "Error: Tcl isn't properly initialized. Orxonox might possibly not work like that." << std::endl;   }
         catch (...)
-        {   COUT(1) << "Error while creating Tcl-interpreter." << std::endl;   }
+        {   COUT(1) << "Error while creating Tcl-interpreter." << std::endl; COUT(1) << "Error: Tcl isn't properly initialized. Orxonox might possibly not work like that." << std::endl;   }
 
         return interpreter;
     }
 
+    std::string TclBind::getTclLibraryPath()
+    {
+#ifdef DEPENDENCY_PACKAGE_ENABLE
+        if (Core::isDevelopmentRun())
+            return (std::string(ORXONOX_DEP_LIB_PATH) + "/tcl");
+        else
+            return (Core::getRootPathString() + "lib/tcl");
+#else
+        return "";
+#endif
+    }
+
     std::string TclBind::tcl_query(Tcl::object const &args)
     {
         COUT(4) << "Tcl_query: " << args.get() << std::endl;

Modified: branches/resource/src/core/TclBind.h
===================================================================
--- branches/resource/src/core/TclBind.h	2009-07-27 21:18:17 UTC (rev 3359)
+++ branches/resource/src/core/TclBind.h	2009-07-28 15:04:38 UTC (rev 3360)
@@ -49,6 +49,8 @@
 
             void setDataPath(const std::string& datapath);
             const std::string& getTclDataPath() const { return this->tclDataPath_; }
+            static std::string getTclLibraryPath();
+
             void initializeTclInterpreter();
             static Tcl::interpreter* createTclInterpreter();
             Tcl::interpreter* getTclInterpreter() const { return this->interpreter_; }

Modified: branches/resource/src/core/TclThreadManager.cc
===================================================================
--- branches/resource/src/core/TclThreadManager.cc	2009-07-27 21:18:17 UTC (rev 3359)
+++ branches/resource/src/core/TclThreadManager.cc	2009-07-28 15:04:38 UTC (rev 3360)
@@ -53,6 +53,7 @@
     SetConsoleCommand(TclThreadManager, destroy, false).argumentCompleter(0, autocompletion::tclthreads());
     SetConsoleCommand(TclThreadManager, execute, false).argumentCompleter(0, autocompletion::tclthreads());
     SetConsoleCommand(TclThreadManager, query,   false).argumentCompleter(0, autocompletion::tclthreads());
+    SetConsoleCommand(TclThreadManager, source,  false).argumentCompleter(0, autocompletion::tclthreads());
 
     /**
         @brief A struct containing all informations about a Tcl-interpreter
@@ -241,52 +242,57 @@
         newbundle->id_ = id;
         newbundle->interpreter_ = TclBind::createTclInterpreter();
 
+        TclThreadManager::initialize(newbundle);
+
+        {
+            // Add the new bundle to the map
+            boost::unique_lock<boost::shared_mutex> lock(*TclThreadManager::getInstance().interpreterBundlesMutex_);
+            TclThreadManager::getInstance().interpreterBundles_[id] = newbundle;
+        }
+
+        return newbundle->interpreter_;
+    }
+
+    void TclThreadManager::initialize(TclInterpreterBundle* bundle)
+    {
+        std::string id_string = getConvertedValue<unsigned int, std::string>(bundle->id_);
+
         // Initialize the new interpreter
         try
         {
-            std::string id_string = getConvertedValue<unsigned int, std::string>(id);
-
             // Define the functions which are implemented in C++
-            newbundle->interpreter_->def("::orxonox::execute",      TclThreadManager::tcl_execute,      Tcl::variadic());
-            newbundle->interpreter_->def("::orxonox::crossexecute", TclThreadManager::tcl_crossexecute, Tcl::variadic());
-            newbundle->interpreter_->def("::orxonox::query",        TclThreadManager::tcl_query,        Tcl::variadic());
-            newbundle->interpreter_->def("::orxonox::crossquery",   TclThreadManager::tcl_crossquery,   Tcl::variadic());
-            newbundle->interpreter_->def("::orxonox::running",      TclThreadManager::tcl_running);
+            bundle->interpreter_->def("::orxonox::execute",      TclThreadManager::tcl_execute,      Tcl::variadic());
+            bundle->interpreter_->def("::orxonox::crossexecute", TclThreadManager::tcl_crossexecute, Tcl::variadic());
+            bundle->interpreter_->def("::orxonox::query",        TclThreadManager::tcl_query,        Tcl::variadic());
+            bundle->interpreter_->def("::orxonox::crossquery",   TclThreadManager::tcl_crossquery,   Tcl::variadic());
+            bundle->interpreter_->def("::orxonox::running",      TclThreadManager::tcl_running);
 
             // Create threadspecific shortcuts for the functions above
-            newbundle->interpreter_->def("execute",      TclThreadManager::tcl_execute,      Tcl::variadic());
-            newbundle->interpreter_->def("crossexecute", TclThreadManager::tcl_crossexecute, Tcl::variadic());
-            newbundle->interpreter_->eval("proc query      {args}    { ::orxonox::query " + id_string + " $args }");
-            newbundle->interpreter_->eval("proc crossquery {id args} { ::orxonox::crossquery " + id_string + " $id $args }");
-            newbundle->interpreter_->eval("proc running    {}        { return [::orxonox::running " + id_string + "] }");
+            bundle->interpreter_->def("execute",      TclThreadManager::tcl_execute,      Tcl::variadic());
+            bundle->interpreter_->def("crossexecute", TclThreadManager::tcl_crossexecute, Tcl::variadic());
+            bundle->interpreter_->eval("proc query      {args}    { ::orxonox::query " + id_string + " $args }");
+            bundle->interpreter_->eval("proc crossquery {id args} { ::orxonox::crossquery " + id_string + " $id $args }");
+            bundle->interpreter_->eval("proc running    {}        { return [::orxonox::running " + id_string + "] }");
 
             // Define a variable containing the thread id
-            newbundle->interpreter_->eval("set id " + id_string);
+            bundle->interpreter_->eval("set id " + id_string);
 
             // Use our own exit function to avoid shutting down the whole program instead of just the interpreter
-            newbundle->interpreter_->eval("rename exit ::tcl::exit");
-            newbundle->interpreter_->eval("proc exit {} { execute TclThreadManager destroy " + id_string + " }");
+            bundle->interpreter_->eval("rename exit ::tcl::exit");
+            bundle->interpreter_->eval("proc exit {} { execute TclThreadManager destroy " + id_string + " }");
 
             // Redefine some native functions
-            newbundle->interpreter_->eval("rename while ::tcl::while");
-            newbundle->interpreter_->eval("rename ::orxonox::while while");
-            newbundle->interpreter_->eval("rename for ::tcl::for");
-            newbundle->interpreter_->eval("rename ::orxonox::for for");
+            bundle->interpreter_->eval("rename while ::tcl::while");
+            bundle->interpreter_->eval("rename ::orxonox::while while");
+            bundle->interpreter_->eval("rename for ::tcl::for");
+            bundle->interpreter_->eval("rename ::orxonox::for for");
         }
         catch (const Tcl::tcl_error& e)
-        {   newbundle->interpreter_ = 0; COUT(1) << "Tcl error while creating Tcl-interpreter (" << id << "): " << e.what() << std::endl;   }
+        {   bundle->interpreter_ = 0; COUT(1) << "Tcl error while creating Tcl-interpreter (" << id_string << "): " << e.what() << std::endl;   }
         catch (const std::exception& e)
-        {   newbundle->interpreter_ = 0; COUT(1) << "Error while creating Tcl-interpreter (" << id << "): " << e.what() << std::endl;   }
+        {   bundle->interpreter_ = 0; COUT(1) << "Error while creating Tcl-interpreter (" << id_string << "): " << e.what() << std::endl;   }
         catch (...)
-        {   newbundle->interpreter_ = 0; COUT(1) << "An error occurred while creating a new Tcl-interpreter (" << id << ")" << std::endl;   }
-
-        {
-            // Add the new bundle to the map
-            boost::unique_lock<boost::shared_mutex> lock(*TclThreadManager::getInstance().interpreterBundlesMutex_);
-            TclThreadManager::getInstance().interpreterBundles_[id] = newbundle;
-        }
-
-        return newbundle->interpreter_;
+        {   bundle->interpreter_ = 0; COUT(1) << "An error occurred while creating a new Tcl-interpreter (" << id_string << ")" << std::endl;   }
     }
 
     /**
@@ -402,7 +408,7 @@
             if ((source_bundle->id_ == target_bundle->id_) || source_bundle->queriers_.is_in(target_bundle->id_))
             {
                 // This query would lead to a deadlock - return with an error
-                this->error("Error: Circular query (" + this->dumpList(source_bundle->queriers_.getList()) + " " + getConvertedValue<unsigned int, std::string>(source_bundle->id_) \
+                TclThreadManager::error("Error: Circular query (" + this->dumpList(source_bundle->queriers_.getList()) + " " + getConvertedValue<unsigned int, std::string>(source_bundle->id_) \
                             + " -> " + getConvertedValue<unsigned int, std::string>(target_bundle->id_) \
                             + "), couldn't query Tcl-interpreter with ID " + getConvertedValue<unsigned int, std::string>(target_bundle->id_) \
                             + " from other interpreter with ID " + getConvertedValue<unsigned int, std::string>(source_bundle->id_) + ".");
@@ -438,9 +444,9 @@
                     if (target_bundle->id_ == 0 && bUseCommandExecutor)
                     {
                         // It's a query to the CommandExecutor
-                        this->debug("TclThread_query -> CE: " + command);
+                        TclThreadManager::debug("TclThread_query -> CE: " + command);
                         if (!CommandExecutor::execute(command, false))
-                            this->error("Error: Can't execute command \"" + command + "\"!");
+                            TclThreadManager::error("Error: Can't execute command \"" + command + "\"!");
 
                         if (CommandExecutor::getLastEvaluation().hasReturnvalue())
                             output = CommandExecutor::getLastEvaluation().getReturnvalue().getString();
@@ -448,9 +454,9 @@
                     else
                     {
                         // It's a query to a Tcl interpreter
-                        this->debug("TclThread_query: " + command);
+                        TclThreadManager::debug("TclThread_query: " + command);
 
-                        output = this->eval(target_bundle, command);
+                        output = TclThreadManager::eval(target_bundle, command, "query");
                     }
 
                     // Clear the queriers list of the target
@@ -467,7 +473,7 @@
                 {
                     // This happens if the main thread tries to query a busy interpreter
                     // To avoid a lock of the main thread, we simply don't proceed with the query in this case
-                    this->error("Error: Couldn't query Tcl-interpreter with ID " + getConvertedValue<unsigned int, std::string>(target_bundle->id_) + ", interpreter is busy right now.");
+                    TclThreadManager::error("Error: Couldn't query Tcl-interpreter with ID " + getConvertedValue<unsigned int, std::string>(target_bundle->id_) + ", interpreter is busy right now.");
                 }
             }
 
@@ -477,6 +483,14 @@
     }
 
     /**
+        @brief Creates a non-interactive Tcl-interpreter which executes a file.
+    */
+    void TclThreadManager::source(const std::string& file)
+    {
+        boost::thread(boost::bind(&sourceThread, file));
+    }
+
+    /**
         @brief This function can be called from Tcl to ask if the thread is still suposed to be running.
         @param id The id of the thread in question
     */
@@ -505,7 +519,7 @@
         }
         else
         {
-            this->error("Error: No Tcl-interpreter with ID " + getConvertedValue<unsigned int, std::string>(id) + " existing.");
+            TclThreadManager::error("Error: No Tcl-interpreter with ID " + getConvertedValue<unsigned int, std::string>(id) + " existing.");
             return 0;
         }
     }
@@ -547,7 +561,7 @@
     */
     void TclThreadManager::error(const std::string& error)
     {
-        this->messageQueue_->push_back("error " + error);
+        TclThreadManager::getInstance().messageQueue_->push_back("error " + error);
     }
 
     /**
@@ -555,7 +569,7 @@
     */
     void TclThreadManager::debug(const std::string& error)
     {
-        this->messageQueue_->push_back("debug " + error);
+        TclThreadManager::getInstance().messageQueue_->push_back("debug " + error);
     }
 
     /**
@@ -564,7 +578,7 @@
 
         Errors are reported through the @ref error function.
     */
-    std::string TclThreadManager::eval(TclInterpreterBundle* bundle, const std::string& command)
+    std::string TclThreadManager::eval(TclInterpreterBundle* bundle, const std::string& command, const std::string& action)
     {
         Tcl_Interp* interpreter = bundle->interpreter_->get();
         int cc = Tcl_Eval(interpreter, command.c_str());
@@ -573,7 +587,7 @@
 
         if (cc != TCL_OK)
         {
-            this->error("Tcl error (execute, ID " + getConvertedValue<unsigned int, std::string>(bundle->id_) + "): " + static_cast<std::string>(result));
+            TclThreadManager::error("Tcl error (" + action + ", ID " + getConvertedValue<unsigned int, std::string>(bundle->id_) + "): " + static_cast<std::string>(result));
             return "";
         }
         else
@@ -593,10 +607,71 @@
     */
     void tclThread(TclInterpreterBundle* bundle, std::string command)
     {
-        TclThreadManager::getInstance().debug("TclThread_execute: " + command);
+        TclThreadManager::debug("TclThread_execute: " + command);
 
-        TclThreadManager::getInstance().eval(bundle, command);
+        TclThreadManager::eval(bundle, command, "execute");
 
         bundle->lock_->unlock();
     }
+
+    /**
+        @brief The main function of a non-interactive source thread. Executes the file.
+        @param file The name of the file that should be executed by the non-interactive interpreter.
+    */
+    void sourceThread(std::string file)
+    {
+        TclThreadManager::debug("TclThread_source: " + file);
+
+        // Prepare the command-line arguments
+        int argc = 2;
+        char* argv[argc];
+        argv[0] = "tclthread";
+        argv[1] = const_cast<char*>(file.c_str());
+
+        // Start the Tcl-command Tcl_Main with the Tcl_OrxonoxAppInit hook
+        Tcl_Main(argc, argv, Tcl_OrxonoxAppInit);
+
+//        Tcl::object object(file);
+//        int cc = Tcl_FSEvalFile(bundle->interpreter_->get(), object.get_object());
+//        Tcl::details::result result(bundle->interpreter_->get());
+//        if (cc != TCL_OK)
+//            TclThreadManager::error("Tcl error (source, ID " + getConvertedValue<unsigned int, std::string>(bundle->id_) + "): " + static_cast<std::string>(result));
+//
+//        // Unlock the mutex
+//        bundle->lock_->unlock();
+    }
+
+    /**
+        @brief A tcl-init hook to inject the non-interactive Tcl-interpreter into the TclThreadManager.
+    */
+    int Tcl_OrxonoxAppInit(Tcl_Interp* interp)
+    {
+        // Create a new interpreter bundle
+        unsigned int id = TclThreadManager::create();
+        TclInterpreterBundle* bundle = TclThreadManager::getInstance().getInterpreterBundle(id);
+
+        // Replace the default interpreter in the bundle with the non-interactive one (passed as an argument to this function)
+        if (bundle->interpreter_)
+            delete bundle->interpreter_;
+        bundle->interpreter_ = new Tcl::interpreter(interp, true);
+
+        // Initialize the non-interactive interpreter (like in @ref TclBind::createTclInterpreter but exception safe)
+        std::string libpath = TclBind::getTclLibraryPath();
+        if (libpath != "")
+            TclThreadManager::eval(bundle, "set tcl_library \"" + libpath + "\"", "source");
+        int cc = Tcl_Init(interp);
+        TclThreadManager::eval(bundle, "source \"" + TclBind::getInstance().getTclDataPath() + "/init.tcl\"", "source");
+
+        // Initialize the non-interactive interpreter also with the thread-specific stuff
+        TclThreadManager::initialize(bundle);
+
+        // Lock the mutex (this will be locked until the thread finishes - no chance to interact with the interpreter)
+        bundle->lock_->lock();
+
+        // Return to Tcl_Main
+        if (!bundle->interpreter_)
+            return TCL_ERROR;
+        else
+            return cc;
+    }
 }

Modified: branches/resource/src/core/TclThreadManager.h
===================================================================
--- branches/resource/src/core/TclThreadManager.h	2009-07-27 21:18:17 UTC (rev 3359)
+++ branches/resource/src/core/TclThreadManager.h	2009-07-28 15:04:38 UTC (rev 3360)
@@ -38,12 +38,16 @@
 
 #include "OrxonoxClass.h"
 
+class Tcl_Interp;
+
 namespace orxonox
 {
     class _CoreExport TclThreadManager : public OrxonoxClass
     {
         friend class TclBind;
         friend _CoreExport void tclThread(TclInterpreterBundle* bundle, std::string command);
+        friend _CoreExport void sourceThread(std::string file);
+        friend _CoreExport int Tcl_OrxonoxAppInit(Tcl_Interp* interp);
 
         public:
             TclThreadManager(Tcl::interpreter* interpreter);
@@ -56,9 +60,10 @@
             static void              destroy(unsigned int id);
             static void              execute(unsigned int target_id, const std::string& command);
             static std::string       query(unsigned int target_id, const std::string& command);
+            static void              source(const std::string& file);
 
-            void error(const std::string& error);
-            void debug(const std::string& error);
+            static void error(const std::string& error);
+            static void debug(const std::string& error);
 
             void update(const Clock& time);
 
@@ -77,7 +82,8 @@
             TclInterpreterBundle* getInterpreterBundle(unsigned int id);
             std::string dumpList(const std::list<unsigned int>& list);
 
-            std::string eval(TclInterpreterBundle* bundle, const std::string& command);
+            static void initialize(TclInterpreterBundle* bundle);
+            static std::string eval(TclInterpreterBundle* bundle, const std::string& command, const std::string& action);
 
             static TclThreadManager* singletonPtr_s;                            ///< Singleton pointer
 
@@ -89,6 +95,8 @@
     };
 
     _CoreExport void tclThread(TclInterpreterBundle* bundle, std::string command);
+    _CoreExport void sourceThread(std::string file);
+    _CoreExport int Tcl_OrxonoxAppInit(Tcl_Interp* interp);
 }
 
 #endif /* _TclThreadManager_H__ */

Modified: branches/resource/src/cpptcl/changes_orxonox.diff
===================================================================
--- branches/resource/src/cpptcl/changes_orxonox.diff	2009-07-27 21:18:17 UTC (rev 3359)
+++ branches/resource/src/cpptcl/changes_orxonox.diff	2009-07-28 15:04:38 UTC (rev 3360)
@@ -27,32 +27,3 @@
       {
            Tcl_SetResult(interp, const_cast<char*>(e.what()), TCL_VOLATILE);
            return TCL_ERROR;
-@@ -858,6 +858,18 @@
-      owner_ = true;
- }
- 
-+interpreter::interpreter(string const &libpath)
-+{
-+     interp_ =  Tcl_CreateInterp();
-+     owner_ = true;
-+
-+     try
-+     {
-+        this->eval("set tcl_library \"" + libpath + "\"");
-+        Tcl_Init(this->interp_);
-+     } catch (...) {}
-+}
-+
- interpreter::interpreter(Tcl_Interp *interp, bool owner)
- {
-      interp_ =  interp;
---- cpptcl.h	Wed Jan 28 20:56:11 2009
-+++ cpptcl.h	Sat Jan 24 12:52:54 2009
-@@ -467,6 +467,7 @@
- {
- public:
-      interpreter();
-+     interpreter(std::string const &libpath);
-      interpreter(Tcl_Interp *, bool owner = true);
-      ~interpreter();
-      

Modified: branches/resource/src/cpptcl/cpptcl.cc
===================================================================
--- branches/resource/src/cpptcl/cpptcl.cc	2009-07-27 21:18:17 UTC (rev 3359)
+++ branches/resource/src/cpptcl/cpptcl.cc	2009-07-28 15:04:38 UTC (rev 3360)
@@ -858,18 +858,6 @@
      owner_ = true;
 }
 
-interpreter::interpreter(string const &libpath)
-{
-     interp_ =  Tcl_CreateInterp();
-     owner_ = true;
-
-     try
-     {
-        this->eval("set tcl_library \"" + libpath + "\"");
-        Tcl_Init(this->interp_);
-     } catch (...) {}
-}
-
 interpreter::interpreter(Tcl_Interp *interp, bool owner)
 {
      interp_ =  interp;

Modified: branches/resource/src/cpptcl/cpptcl.h
===================================================================
--- branches/resource/src/cpptcl/cpptcl.h	2009-07-27 21:18:17 UTC (rev 3359)
+++ branches/resource/src/cpptcl/cpptcl.h	2009-07-28 15:04:38 UTC (rev 3360)
@@ -467,7 +467,6 @@
 {
 public:
      interpreter();
-     interpreter(std::string const &libpath);
      interpreter(Tcl_Interp *, bool owner = true);
      ~interpreter();
      




More information about the Orxonox-commit mailing list