Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

Ignore:
Timestamp:
Jul 30, 2009, 2:10:44 PM (15 years ago)
Author:
rgrieder
Message:

Merged resource branch back to the trunk. Changes:

  • Automated graphics loading by evaluating whether a GameState requires it
  • Using native Tcl library (x3n)

Windows users: Update your dependency package!

Location:
code/trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • code/trunk

  • code/trunk/src/core/TclThreadManager.cc

    r3326 r3370  
    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    /**
     
    9091        RegisterRootObject(TclThreadManager);
    9192
    92         assert(TclThreadManager::singletonPtr_s == 0);
    93         TclThreadManager::singletonPtr_s = this;
    94 
    9593        this->numInterpreterBundles_ = 0;
    9694
     
    115113    TclThreadManager::~TclThreadManager()
    116114    {
    117         TclThreadManager::singletonPtr_s = 0;
    118 
    119115        delete this->interpreterBundlesMutex_;
    120116//        delete this->mainInterpreterMutex_; // <-- temporary disabled to avoid crash if a thread is still actively queriyng
     
    240236        TclInterpreterBundle* newbundle = new TclInterpreterBundle();
    241237        newbundle->id_ = id;
    242         newbundle->interpreter_ = new Tcl::interpreter(TclBind::getInstance().getTclLibPath());
    243 
    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 
    262             // Define a variable containing the thread id
    263             newbundle->interpreter_->eval("set id " + id_string);
    264 
    265             // Use our own exit function to avoid shutting down the whole program instead of just the interpreter
    266             newbundle->interpreter_->eval("rename exit tcl::exit");
    267             newbundle->interpreter_->eval("proc exit {} { execute TclThreadManager destroy " + id_string + " }");
    268 
    269             // Redefine some native functions
    270             newbundle->interpreter_->eval("redef_puts");
    271 
    272 //            newbundle->interpreter_->eval("rename while tcl::while");
    273 //            newbundle->interpreter_->eval("proc while {test command} { tcl::while {[uplevel 1 expr $test]} {uplevel 1 $command} }"); // (\"$test\" && [orxonox::running " + id + "]])
    274 //            newbundle->interpreter_->eval("rename for tcl::for");
    275 //            newbundle->interpreter_->eval("proc for {start test next command} { uplevel tcl::for \"$start\" \"$test\" \"$next\" \"$command\" }");
    276         }
    277         catch (const Tcl::tcl_error& e)
    278         {   newbundle->interpreter_ = 0; COUT(1) << "Tcl error while creating Tcl-interpreter (" << id << "): " << e.what() << std::endl;   }
    279         catch (const std::exception& e)
    280         {   newbundle->interpreter_ = 0; COUT(1) << "Error while creating Tcl-interpreter (" << id << "): " << e.what() << std::endl;   }
    281         catch (...)
    282         {   newbundle->interpreter_ = 0; COUT(1) << "An error occurred while creating a new Tcl-interpreter (" << id << ")" << std::endl;   }
     238        newbundle->interpreter_ = TclBind::createTclInterpreter();
     239
     240        TclThreadManager::initialize(newbundle);
    283241
    284242        {
     
    291249    }
    292250
     251    void TclThreadManager::initialize(TclInterpreterBundle* bundle)
     252    {
     253        std::string id_string = getConvertedValue<unsigned int, std::string>(bundle->id_);
     254
     255        // Initialize the new interpreter
     256        try
     257        {
     258            // Define the functions which are implemented in C++
     259            bundle->interpreter_->def("::orxonox::execute",      TclThreadManager::tcl_execute,      Tcl::variadic());
     260            bundle->interpreter_->def("::orxonox::crossexecute", TclThreadManager::tcl_crossexecute, Tcl::variadic());
     261            bundle->interpreter_->def("::orxonox::query",        TclThreadManager::tcl_query,        Tcl::variadic());
     262            bundle->interpreter_->def("::orxonox::crossquery",   TclThreadManager::tcl_crossquery,   Tcl::variadic());
     263            bundle->interpreter_->def("::orxonox::running",      TclThreadManager::tcl_running);
     264
     265            // Create threadspecific shortcuts for the functions above
     266            bundle->interpreter_->def("execute",      TclThreadManager::tcl_execute,      Tcl::variadic());
     267            bundle->interpreter_->def("crossexecute", TclThreadManager::tcl_crossexecute, Tcl::variadic());
     268            bundle->interpreter_->eval("proc query      {args}    { ::orxonox::query " + id_string + " $args }");
     269            bundle->interpreter_->eval("proc crossquery {id args} { ::orxonox::crossquery " + id_string + " $id $args }");
     270            bundle->interpreter_->eval("proc running    {}        { return [::orxonox::running " + id_string + "] }");
     271
     272            // Define a variable containing the thread id
     273            bundle->interpreter_->eval("set id " + id_string);
     274
     275            // Use our own exit function to avoid shutting down the whole program instead of just the interpreter
     276            bundle->interpreter_->eval("rename exit ::tcl::exit");
     277            bundle->interpreter_->eval("proc exit {} { execute TclThreadManager destroy " + id_string + " }");
     278
     279            // Redefine some native functions
     280            bundle->interpreter_->eval("rename while ::tcl::while");
     281            bundle->interpreter_->eval("rename ::orxonox::while while");
     282            bundle->interpreter_->eval("rename for ::tcl::for");
     283            bundle->interpreter_->eval("rename ::orxonox::for for");
     284        }
     285        catch (const Tcl::tcl_error& e)
     286        {   bundle->interpreter_ = 0; COUT(1) << "Tcl error while creating Tcl-interpreter (" << id_string << "): " << e.what() << std::endl;   }
     287        catch (const std::exception& e)
     288        {   bundle->interpreter_ = 0; COUT(1) << "Error while creating Tcl-interpreter (" << id_string << "): " << e.what() << std::endl;   }
     289        catch (...)
     290        {   bundle->interpreter_ = 0; COUT(1) << "An error occurred while creating a new Tcl-interpreter (" << id_string << ")" << std::endl;   }
     291    }
     292
    293293    /**
    294294        @brief Stops and destroys a given Tcl-interpreter
     
    298298        // TODO
    299299        // Not yet implemented
     300        TclInterpreterBundle* bundle = TclThreadManager::getInstance().getInterpreterBundle(id);
     301        if (bundle)
     302        {
     303            bundle->bRunning_ = false;
     304        }
    300305    }
    301306
     
    399404            {
    400405                // This query would lead to a deadlock - return with an error
    401                 this->error("Error: Circular query (" + this->dumpList(source_bundle->queriers_.getList()) + " " + getConvertedValue<unsigned int, std::string>(source_bundle->id_) \
     406                TclThreadManager::error("Error: Circular query (" + this->dumpList(source_bundle->queriers_.getList()) + " " + getConvertedValue<unsigned int, std::string>(source_bundle->id_) \
    402407                            + " -> " + getConvertedValue<unsigned int, std::string>(target_bundle->id_) \
    403408                            + "), couldn't query Tcl-interpreter with ID " + getConvertedValue<unsigned int, std::string>(target_bundle->id_) \
     
    435440                    {
    436441                        // It's a query to the CommandExecutor
    437                         this->debug("TclThread_query -> CE: " + command);
     442                        TclThreadManager::debug("TclThread_query -> CE: " + command);
    438443                        if (!CommandExecutor::execute(command, false))
    439                             this->error("Error: Can't execute command \"" + command + "\"!");
     444                            TclThreadManager::error("Error: Can't execute command \"" + command + "\"!");
    440445
    441446                        if (CommandExecutor::getLastEvaluation().hasReturnvalue())
     
    445450                    {
    446451                        // It's a query to a Tcl interpreter
    447                         this->debug("TclThread_query: " + command);
    448 
    449                         output = this->eval(target_bundle, command);
     452                        TclThreadManager::debug("TclThread_query: " + command);
     453
     454                        output = TclThreadManager::eval(target_bundle, command, "query");
    450455                    }
    451456
     
    464469                    // This happens if the main thread tries to query a busy interpreter
    465470                    // To avoid a lock of the main thread, we simply don't proceed with the query in this case
    466                     this->error("Error: Couldn't query Tcl-interpreter with ID " + getConvertedValue<unsigned int, std::string>(target_bundle->id_) + ", interpreter is busy right now.");
     471                    TclThreadManager::error("Error: Couldn't query Tcl-interpreter with ID " + getConvertedValue<unsigned int, std::string>(target_bundle->id_) + ", interpreter is busy right now.");
    467472                }
    468473            }
     
    471476
    472477        return output;
     478    }
     479
     480    /**
     481        @brief Creates a non-interactive Tcl-interpreter which executes a file.
     482    */
     483    void TclThreadManager::source(const std::string& file)
     484    {
     485        boost::thread(boost::bind(&sourceThread, file));
    473486    }
    474487
     
    502515        else
    503516        {
    504             this->error("Error: No Tcl-interpreter with ID " + getConvertedValue<unsigned int, std::string>(id) + " existing.");
     517            TclThreadManager::error("Error: No Tcl-interpreter with ID " + getConvertedValue<unsigned int, std::string>(id) + " existing.");
    505518            return 0;
    506519        }
     
    544557    void TclThreadManager::error(const std::string& error)
    545558    {
    546         this->messageQueue_->push_back("error " + error);
     559        TclThreadManager::getInstance().messageQueue_->push_back("error " + error);
    547560    }
    548561
     
    552565    void TclThreadManager::debug(const std::string& error)
    553566    {
    554         this->messageQueue_->push_back("debug " + error);
     567        TclThreadManager::getInstance().messageQueue_->push_back("debug " + error);
    555568    }
    556569
     
    561574        Errors are reported through the @ref error function.
    562575    */
    563     std::string TclThreadManager::eval(TclInterpreterBundle* bundle, const std::string& command)
     576    std::string TclThreadManager::eval(TclInterpreterBundle* bundle, const std::string& command, const std::string& action)
    564577    {
    565578        Tcl_Interp* interpreter = bundle->interpreter_->get();
     
    570583        if (cc != TCL_OK)
    571584        {
    572             this->error("Tcl error (execute, ID " + getConvertedValue<unsigned int, std::string>(bundle->id_) + "): " + static_cast<std::string>(result));
     585            TclThreadManager::error("Tcl error (" + action + ", ID " + getConvertedValue<unsigned int, std::string>(bundle->id_) + "): " + static_cast<std::string>(result));
    573586            return "";
    574587        }
     
    590603    void tclThread(TclInterpreterBundle* bundle, std::string command)
    591604    {
    592         TclThreadManager::getInstance().debug("TclThread_execute: " + command);
    593 
    594         TclThreadManager::getInstance().eval(bundle, command);
     605        TclThreadManager::debug("TclThread_execute: " + command);
     606
     607        TclThreadManager::eval(bundle, command, "execute");
    595608
    596609        bundle->lock_->unlock();
    597610    }
     611
     612    /**
     613        @brief The main function of a non-interactive source thread. Executes the file.
     614        @param file The name of the file that should be executed by the non-interactive interpreter.
     615    */
     616    void sourceThread(std::string file)
     617    {
     618        TclThreadManager::debug("TclThread_source: " + file);
     619
     620        // Prepare the command-line arguments
     621        const int argc = 2;
     622        char* argv[argc];
     623        argv[0] = "tclthread";
     624        argv[1] = const_cast<char*>(file.c_str());
     625
     626        // Start the Tcl-command Tcl_Main with the Tcl_OrxonoxAppInit hook
     627        Tcl_Main(argc, argv, Tcl_OrxonoxAppInit);
     628
     629//        Tcl::object object(file);
     630//        int cc = Tcl_FSEvalFile(bundle->interpreter_->get(), object.get_object());
     631//        Tcl::details::result result(bundle->interpreter_->get());
     632//        if (cc != TCL_OK)
     633//            TclThreadManager::error("Tcl error (source, ID " + getConvertedValue<unsigned int, std::string>(bundle->id_) + "): " + static_cast<std::string>(result));
     634//
     635//        // Unlock the mutex
     636//        bundle->lock_->unlock();
     637    }
     638
     639    /**
     640        @brief A tcl-init hook to inject the non-interactive Tcl-interpreter into the TclThreadManager.
     641    */
     642    int Tcl_OrxonoxAppInit(Tcl_Interp* interp)
     643    {
     644        // Create a new interpreter bundle
     645        unsigned int id = TclThreadManager::create();
     646        TclInterpreterBundle* bundle = TclThreadManager::getInstance().getInterpreterBundle(id);
     647
     648        // Replace the default interpreter in the bundle with the non-interactive one (passed as an argument to this function)
     649        if (bundle->interpreter_)
     650            delete bundle->interpreter_;
     651        bundle->interpreter_ = new Tcl::interpreter(interp, true);
     652
     653        // Initialize the non-interactive interpreter (like in @ref TclBind::createTclInterpreter but exception safe)
     654        std::string libpath = TclBind::getTclLibraryPath();
     655        if (libpath != "")
     656            TclThreadManager::eval(bundle, "set tcl_library \"" + libpath + "\"", "source");
     657        int cc = Tcl_Init(interp);
     658        TclThreadManager::eval(bundle, "source \"" + TclBind::getInstance().getTclDataPath() + "/init.tcl\"", "source");
     659
     660        // Initialize the non-interactive interpreter also with the thread-specific stuff
     661        TclThreadManager::initialize(bundle);
     662
     663        // Lock the mutex (this will be locked until the thread finishes - no chance to interact with the interpreter)
     664        bundle->lock_->lock();
     665
     666        // Return to Tcl_Main
     667        if (!bundle->interpreter_)
     668            return TCL_ERROR;
     669        else
     670            return cc;
     671    }
    598672}
Note: See TracChangeset for help on using the changeset viewer.