Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

Changeset 3360


Ignore:
Timestamp:
Jul 28, 2009, 5:04:38 PM (15 years ago)
Author:
landauf
Message:
  • 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
Location:
code/branches/resource/src
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • code/branches/resource/src/core/TclBind.cc

    r3354 r3360  
    104104    Tcl::interpreter* TclBind::createTclInterpreter()
    105105    {
    106         Tcl::interpreter* interpreter;
     106        Tcl::interpreter* interpreter = new Tcl::interpreter();
     107        std::string libpath = TclBind::getTclLibraryPath();
     108
     109        try
     110        {
     111            if (libpath != "")
     112                interpreter->eval("set tcl_library \"" + libpath + "\"");
     113
     114            Tcl_Init(interpreter->get());
     115
     116            interpreter->eval("source \"" + TclBind::getInstance().tclDataPath_ + "/init.tcl\"");
     117        }
     118        catch (Tcl::tcl_error const &e)
     119        {   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;   }
     120        catch (std::exception const &e)
     121        {   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;   }
     122        catch (...)
     123        {   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;   }
     124
     125        return interpreter;
     126    }
     127
     128    std::string TclBind::getTclLibraryPath()
     129    {
    107130#ifdef DEPENDENCY_PACKAGE_ENABLE
    108131        if (Core::isDevelopmentRun())
    109             interpreter = new Tcl::interpreter(std::string(ORXONOX_DEP_LIB_PATH) + "/tcl");
     132            return (std::string(ORXONOX_DEP_LIB_PATH) + "/tcl");
    110133        else
    111             interpreter = new Tcl::interpreter(Core::getRootPathString() + "lib/tcl");
     134            return (Core::getRootPathString() + "lib/tcl");
    112135#else
    113         interpreter = new Tcl::interpreter();
     136        return "";
    114137#endif
    115         try
    116         {
    117             interpreter->eval("source \"" + TclBind::getInstance().tclDataPath_ + "/init.tcl\"");
    118         }
    119         catch (Tcl::tcl_error const &e)
    120         {   COUT(1) << "Tcl error while creating Tcl-interpreter: " << e.what() << std::endl;   }
    121         catch (std::exception const &e)
    122         {   COUT(1) << "Error while creating Tcl-interpreter: " << e.what() << std::endl;   }
    123         catch (...)
    124         {   COUT(1) << "Error while creating Tcl-interpreter." << std::endl;   }
    125 
    126         return interpreter;
    127138    }
    128139
  • code/branches/resource/src/core/TclBind.h

    r3344 r3360  
    5050            void setDataPath(const std::string& datapath);
    5151            const std::string& getTclDataPath() const { return this->tclDataPath_; }
     52            static std::string getTclLibraryPath();
     53
    5254            void initializeTclInterpreter();
    5355            static Tcl::interpreter* createTclInterpreter();
  • code/branches/resource/src/core/TclThreadManager.cc

    r3353 r3360  
    5454    SetConsoleCommand(TclThreadManager, execute, false).argumentCompleter(0, autocompletion::tclthreads());
    5555    SetConsoleCommand(TclThreadManager, query,   false).argumentCompleter(0, autocompletion::tclthreads());
     56    SetConsoleCommand(TclThreadManager, source,  false).argumentCompleter(0, autocompletion::tclthreads());
    5657
    5758    /**
     
    242243        newbundle->interpreter_ = TclBind::createTclInterpreter();
    243244
    244         // Initialize the new interpreter
    245         try
    246         {
    247             std::string id_string = getConvertedValue<unsigned int, std::string>(id);
    248 
    249             // Define the functions which are implemented in C++
    250             newbundle->interpreter_->def("::orxonox::execute",      TclThreadManager::tcl_execute,      Tcl::variadic());
    251             newbundle->interpreter_->def("::orxonox::crossexecute", TclThreadManager::tcl_crossexecute, Tcl::variadic());
    252             newbundle->interpreter_->def("::orxonox::query",        TclThreadManager::tcl_query,        Tcl::variadic());
    253             newbundle->interpreter_->def("::orxonox::crossquery",   TclThreadManager::tcl_crossquery,   Tcl::variadic());
    254             newbundle->interpreter_->def("::orxonox::running",      TclThreadManager::tcl_running);
    255 
    256             // Create threadspecific shortcuts for the functions above
    257             newbundle->interpreter_->def("execute",      TclThreadManager::tcl_execute,      Tcl::variadic());
    258             newbundle->interpreter_->def("crossexecute", TclThreadManager::tcl_crossexecute, Tcl::variadic());
    259             newbundle->interpreter_->eval("proc query      {args}    { ::orxonox::query " + id_string + " $args }");
    260             newbundle->interpreter_->eval("proc crossquery {id args} { ::orxonox::crossquery " + id_string + " $id $args }");
    261             newbundle->interpreter_->eval("proc running    {}        { return [::orxonox::running " + id_string + "] }");
    262 
    263             // Define a variable containing the thread id
    264             newbundle->interpreter_->eval("set id " + id_string);
    265 
    266             // Use our own exit function to avoid shutting down the whole program instead of just the interpreter
    267             newbundle->interpreter_->eval("rename exit ::tcl::exit");
    268             newbundle->interpreter_->eval("proc exit {} { execute TclThreadManager destroy " + id_string + " }");
    269 
    270             // Redefine some native functions
    271             newbundle->interpreter_->eval("rename while ::tcl::while");
    272             newbundle->interpreter_->eval("rename ::orxonox::while while");
    273             newbundle->interpreter_->eval("rename for ::tcl::for");
    274             newbundle->interpreter_->eval("rename ::orxonox::for for");
    275         }
    276         catch (const Tcl::tcl_error& e)
    277         {   newbundle->interpreter_ = 0; COUT(1) << "Tcl error while creating Tcl-interpreter (" << id << "): " << e.what() << std::endl;   }
    278         catch (const std::exception& e)
    279         {   newbundle->interpreter_ = 0; COUT(1) << "Error while creating Tcl-interpreter (" << id << "): " << e.what() << std::endl;   }
    280         catch (...)
    281         {   newbundle->interpreter_ = 0; COUT(1) << "An error occurred while creating a new Tcl-interpreter (" << id << ")" << std::endl;   }
     245        TclThreadManager::initialize(newbundle);
    282246
    283247        {
     
    288252
    289253        return newbundle->interpreter_;
     254    }
     255
     256    void TclThreadManager::initialize(TclInterpreterBundle* bundle)
     257    {
     258        std::string id_string = getConvertedValue<unsigned int, std::string>(bundle->id_);
     259
     260        // Initialize the new interpreter
     261        try
     262        {
     263            // Define the functions which are implemented in C++
     264            bundle->interpreter_->def("::orxonox::execute",      TclThreadManager::tcl_execute,      Tcl::variadic());
     265            bundle->interpreter_->def("::orxonox::crossexecute", TclThreadManager::tcl_crossexecute, Tcl::variadic());
     266            bundle->interpreter_->def("::orxonox::query",        TclThreadManager::tcl_query,        Tcl::variadic());
     267            bundle->interpreter_->def("::orxonox::crossquery",   TclThreadManager::tcl_crossquery,   Tcl::variadic());
     268            bundle->interpreter_->def("::orxonox::running",      TclThreadManager::tcl_running);
     269
     270            // Create threadspecific shortcuts for the functions above
     271            bundle->interpreter_->def("execute",      TclThreadManager::tcl_execute,      Tcl::variadic());
     272            bundle->interpreter_->def("crossexecute", TclThreadManager::tcl_crossexecute, Tcl::variadic());
     273            bundle->interpreter_->eval("proc query      {args}    { ::orxonox::query " + id_string + " $args }");
     274            bundle->interpreter_->eval("proc crossquery {id args} { ::orxonox::crossquery " + id_string + " $id $args }");
     275            bundle->interpreter_->eval("proc running    {}        { return [::orxonox::running " + id_string + "] }");
     276
     277            // Define a variable containing the thread id
     278            bundle->interpreter_->eval("set id " + id_string);
     279
     280            // Use our own exit function to avoid shutting down the whole program instead of just the interpreter
     281            bundle->interpreter_->eval("rename exit ::tcl::exit");
     282            bundle->interpreter_->eval("proc exit {} { execute TclThreadManager destroy " + id_string + " }");
     283
     284            // Redefine some native functions
     285            bundle->interpreter_->eval("rename while ::tcl::while");
     286            bundle->interpreter_->eval("rename ::orxonox::while while");
     287            bundle->interpreter_->eval("rename for ::tcl::for");
     288            bundle->interpreter_->eval("rename ::orxonox::for for");
     289        }
     290        catch (const Tcl::tcl_error& e)
     291        {   bundle->interpreter_ = 0; COUT(1) << "Tcl error while creating Tcl-interpreter (" << id_string << "): " << e.what() << std::endl;   }
     292        catch (const std::exception& e)
     293        {   bundle->interpreter_ = 0; COUT(1) << "Error while creating Tcl-interpreter (" << id_string << "): " << e.what() << std::endl;   }
     294        catch (...)
     295        {   bundle->interpreter_ = 0; COUT(1) << "An error occurred while creating a new Tcl-interpreter (" << id_string << ")" << std::endl;   }
    290296    }
    291297
     
    403409            {
    404410                // This query would lead to a deadlock - return with an error
    405                 this->error("Error: Circular query (" + this->dumpList(source_bundle->queriers_.getList()) + " " + getConvertedValue<unsigned int, std::string>(source_bundle->id_) \
     411                TclThreadManager::error("Error: Circular query (" + this->dumpList(source_bundle->queriers_.getList()) + " " + getConvertedValue<unsigned int, std::string>(source_bundle->id_) \
    406412                            + " -> " + getConvertedValue<unsigned int, std::string>(target_bundle->id_) \
    407413                            + "), couldn't query Tcl-interpreter with ID " + getConvertedValue<unsigned int, std::string>(target_bundle->id_) \
     
    439445                    {
    440446                        // It's a query to the CommandExecutor
    441                         this->debug("TclThread_query -> CE: " + command);
     447                        TclThreadManager::debug("TclThread_query -> CE: " + command);
    442448                        if (!CommandExecutor::execute(command, false))
    443                             this->error("Error: Can't execute command \"" + command + "\"!");
     449                            TclThreadManager::error("Error: Can't execute command \"" + command + "\"!");
    444450
    445451                        if (CommandExecutor::getLastEvaluation().hasReturnvalue())
     
    449455                    {
    450456                        // It's a query to a Tcl interpreter
    451                         this->debug("TclThread_query: " + command);
    452 
    453                         output = this->eval(target_bundle, command);
     457                        TclThreadManager::debug("TclThread_query: " + command);
     458
     459                        output = TclThreadManager::eval(target_bundle, command, "query");
    454460                    }
    455461
     
    468474                    // This happens if the main thread tries to query a busy interpreter
    469475                    // To avoid a lock of the main thread, we simply don't proceed with the query in this case
    470                     this->error("Error: Couldn't query Tcl-interpreter with ID " + getConvertedValue<unsigned int, std::string>(target_bundle->id_) + ", interpreter is busy right now.");
     476                    TclThreadManager::error("Error: Couldn't query Tcl-interpreter with ID " + getConvertedValue<unsigned int, std::string>(target_bundle->id_) + ", interpreter is busy right now.");
    471477                }
    472478            }
     
    475481
    476482        return output;
     483    }
     484
     485    /**
     486        @brief Creates a non-interactive Tcl-interpreter which executes a file.
     487    */
     488    void TclThreadManager::source(const std::string& file)
     489    {
     490        boost::thread(boost::bind(&sourceThread, file));
    477491    }
    478492
     
    506520        else
    507521        {
    508             this->error("Error: No Tcl-interpreter with ID " + getConvertedValue<unsigned int, std::string>(id) + " existing.");
     522            TclThreadManager::error("Error: No Tcl-interpreter with ID " + getConvertedValue<unsigned int, std::string>(id) + " existing.");
    509523            return 0;
    510524        }
     
    548562    void TclThreadManager::error(const std::string& error)
    549563    {
    550         this->messageQueue_->push_back("error " + error);
     564        TclThreadManager::getInstance().messageQueue_->push_back("error " + error);
    551565    }
    552566
     
    556570    void TclThreadManager::debug(const std::string& error)
    557571    {
    558         this->messageQueue_->push_back("debug " + error);
     572        TclThreadManager::getInstance().messageQueue_->push_back("debug " + error);
    559573    }
    560574
     
    565579        Errors are reported through the @ref error function.
    566580    */
    567     std::string TclThreadManager::eval(TclInterpreterBundle* bundle, const std::string& command)
     581    std::string TclThreadManager::eval(TclInterpreterBundle* bundle, const std::string& command, const std::string& action)
    568582    {
    569583        Tcl_Interp* interpreter = bundle->interpreter_->get();
     
    574588        if (cc != TCL_OK)
    575589        {
    576             this->error("Tcl error (execute, ID " + getConvertedValue<unsigned int, std::string>(bundle->id_) + "): " + static_cast<std::string>(result));
     590            TclThreadManager::error("Tcl error (" + action + ", ID " + getConvertedValue<unsigned int, std::string>(bundle->id_) + "): " + static_cast<std::string>(result));
    577591            return "";
    578592        }
     
    594608    void tclThread(TclInterpreterBundle* bundle, std::string command)
    595609    {
    596         TclThreadManager::getInstance().debug("TclThread_execute: " + command);
    597 
    598         TclThreadManager::getInstance().eval(bundle, command);
     610        TclThreadManager::debug("TclThread_execute: " + command);
     611
     612        TclThreadManager::eval(bundle, command, "execute");
    599613
    600614        bundle->lock_->unlock();
    601615    }
     616
     617    /**
     618        @brief The main function of a non-interactive source thread. Executes the file.
     619        @param file The name of the file that should be executed by the non-interactive interpreter.
     620    */
     621    void sourceThread(std::string file)
     622    {
     623        TclThreadManager::debug("TclThread_source: " + file);
     624
     625        // Prepare the command-line arguments
     626        int argc = 2;
     627        char* argv[argc];
     628        argv[0] = "tclthread";
     629        argv[1] = const_cast<char*>(file.c_str());
     630
     631        // Start the Tcl-command Tcl_Main with the Tcl_OrxonoxAppInit hook
     632        Tcl_Main(argc, argv, Tcl_OrxonoxAppInit);
     633
     634//        Tcl::object object(file);
     635//        int cc = Tcl_FSEvalFile(bundle->interpreter_->get(), object.get_object());
     636//        Tcl::details::result result(bundle->interpreter_->get());
     637//        if (cc != TCL_OK)
     638//            TclThreadManager::error("Tcl error (source, ID " + getConvertedValue<unsigned int, std::string>(bundle->id_) + "): " + static_cast<std::string>(result));
     639//
     640//        // Unlock the mutex
     641//        bundle->lock_->unlock();
     642    }
     643
     644    /**
     645        @brief A tcl-init hook to inject the non-interactive Tcl-interpreter into the TclThreadManager.
     646    */
     647    int Tcl_OrxonoxAppInit(Tcl_Interp* interp)
     648    {
     649        // Create a new interpreter bundle
     650        unsigned int id = TclThreadManager::create();
     651        TclInterpreterBundle* bundle = TclThreadManager::getInstance().getInterpreterBundle(id);
     652
     653        // Replace the default interpreter in the bundle with the non-interactive one (passed as an argument to this function)
     654        if (bundle->interpreter_)
     655            delete bundle->interpreter_;
     656        bundle->interpreter_ = new Tcl::interpreter(interp, true);
     657
     658        // Initialize the non-interactive interpreter (like in @ref TclBind::createTclInterpreter but exception safe)
     659        std::string libpath = TclBind::getTclLibraryPath();
     660        if (libpath != "")
     661            TclThreadManager::eval(bundle, "set tcl_library \"" + libpath + "\"", "source");
     662        int cc = Tcl_Init(interp);
     663        TclThreadManager::eval(bundle, "source \"" + TclBind::getInstance().getTclDataPath() + "/init.tcl\"", "source");
     664
     665        // Initialize the non-interactive interpreter also with the thread-specific stuff
     666        TclThreadManager::initialize(bundle);
     667
     668        // Lock the mutex (this will be locked until the thread finishes - no chance to interact with the interpreter)
     669        bundle->lock_->lock();
     670
     671        // Return to Tcl_Main
     672        if (!bundle->interpreter_)
     673            return TCL_ERROR;
     674        else
     675            return cc;
     676    }
    602677}
  • code/branches/resource/src/core/TclThreadManager.h

    r3359 r3360  
    3939#include "OrxonoxClass.h"
    4040
     41class Tcl_Interp;
     42
    4143namespace orxonox
    4244{
     
    4547        friend class TclBind;
    4648        friend _CoreExport void tclThread(TclInterpreterBundle* bundle, std::string command);
     49        friend _CoreExport void sourceThread(std::string file);
     50        friend _CoreExport int Tcl_OrxonoxAppInit(Tcl_Interp* interp);
    4751
    4852        public:
     
    5761            static void              execute(unsigned int target_id, const std::string& command);
    5862            static std::string       query(unsigned int target_id, const std::string& command);
     63            static void              source(const std::string& file);
    5964
    60             void error(const std::string& error);
    61             void debug(const std::string& error);
     65            static void error(const std::string& error);
     66            static void debug(const std::string& error);
    6267
    6368            void update(const Clock& time);
     
    7883            std::string dumpList(const std::list<unsigned int>& list);
    7984
    80             std::string eval(TclInterpreterBundle* bundle, const std::string& command);
     85            static void initialize(TclInterpreterBundle* bundle);
     86            static std::string eval(TclInterpreterBundle* bundle, const std::string& command, const std::string& action);
    8187
    8288            static TclThreadManager* singletonPtr_s;                            ///< Singleton pointer
     
    9096
    9197    _CoreExport void tclThread(TclInterpreterBundle* bundle, std::string command);
     98    _CoreExport void sourceThread(std::string file);
     99    _CoreExport int Tcl_OrxonoxAppInit(Tcl_Interp* interp);
    92100}
    93101
  • code/branches/resource/src/cpptcl/changes_orxonox.diff

    r2710 r3360  
    2828           Tcl_SetResult(interp, const_cast<char*>(e.what()), TCL_VOLATILE);
    2929           return TCL_ERROR;
    30 @@ -858,6 +858,18 @@
    31       owner_ = true;
    32  }
    33  
    34 +interpreter::interpreter(string const &libpath)
    35 +{
    36 +     interp_ =  Tcl_CreateInterp();
    37 +     owner_ = true;
    38 +
    39 +     try
    40 +     {
    41 +        this->eval("set tcl_library \"" + libpath + "\"");
    42 +        Tcl_Init(this->interp_);
    43 +     } catch (...) {}
    44 +}
    45 +
    46  interpreter::interpreter(Tcl_Interp *interp, bool owner)
    47  {
    48       interp_ =  interp;
    49 --- cpptcl.h    Wed Jan 28 20:56:11 2009
    50 +++ cpptcl.h    Sat Jan 24 12:52:54 2009
    51 @@ -467,6 +467,7 @@
    52  {
    53  public:
    54       interpreter();
    55 +     interpreter(std::string const &libpath);
    56       interpreter(Tcl_Interp *, bool owner = true);
    57       ~interpreter();
    58      
  • code/branches/resource/src/cpptcl/cpptcl.cc

    r3068 r3360  
    859859}
    860860
    861 interpreter::interpreter(string const &libpath)
    862 {
    863      interp_ =  Tcl_CreateInterp();
    864      owner_ = true;
    865 
    866      try
    867      {
    868         this->eval("set tcl_library \"" + libpath + "\"");
    869         Tcl_Init(this->interp_);
    870      } catch (...) {}
    871 }
    872 
    873861interpreter::interpreter(Tcl_Interp *interp, bool owner)
    874862{
  • code/branches/resource/src/cpptcl/cpptcl.h

    r3068 r3360  
    468468public:
    469469     interpreter();
    470      interpreter(std::string const &libpath);
    471470     interpreter(Tcl_Interp *, bool owner = true);
    472471     ~interpreter();
Note: See TracChangeset for help on using the changeset viewer.