Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

Changeset 3313


Ignore:
Timestamp:
Jul 19, 2009, 2:58:24 PM (15 years ago)
Author:
rgrieder
Message:

Reverted TclThreadManager commits to make a tag (there's possibly still an unresolved issue with the TclThreadManager under linux when terminating the game (mutex assert)).

Location:
code/trunk/src/core
Files:
1 deleted
6 edited

Legend:

Unmodified
Added
Removed
  • code/trunk/src/core/CorePrereqs.h

    r3308 r3313  
    150150    class SubclassIdentifier;
    151151    class TclBind;
    152     struct TclInterpreterBundle;
    153     template <class T>
    154     class TclThreadList;
    155152    class TclThreadManager;
    156153    class Template;
     
    204201// Boost
    205202namespace boost
    206 {
     203{ 
    207204    namespace filesystem
    208205    {
     
    213210    class thread;
    214211    class mutex;
    215     class shared_mutex;
    216     class condition_variable;
    217212}
    218213
  • code/trunk/src/core/Game.cc

    r3307 r3313  
    246246
    247247            // UPDATE, Core first
    248             bool threwException = false;
    249248            try
    250249            {
    251250                this->core_->update(*this->gameClock_);
    252251            }
    253             catch (const std::exception& ex)
    254             {
    255                 threwException = true;
    256                 COUT(0) << "Exception while ticking the Core: " << ex.what() << std::endl;
    257             }
    258252            catch (...)
    259             {
    260                 threwException = true;
    261             }
    262             if (threwException)
    263253            {
    264254                COUT(0) << "An exception occured while ticking the Core. This should really never happen!" << std::endl;
  • code/trunk/src/core/IRC.cc

    r3307 r3313  
    5353    {
    5454        unsigned int threadID = IRC_TCL_THREADID;
    55         this->interpreter_ = TclThreadManager::createWithId(threadID);
     55        TclThreadManager::createID(threadID);
     56        this->interpreter_ = TclThreadManager::getInstance().getTclInterpreter(threadID);
    5657
    5758        try
  • code/trunk/src/core/TclBind.cc

    r3307 r3313  
    7979            this->interpreter_->def("orxonox::crossquery", TclThreadManager::tcl_crossquery, Tcl::variadic());
    8080            this->interpreter_->def("execute", TclBind::tcl_execute, Tcl::variadic());
    81             this->interpreter_->def("orxonox::crossexecute", TclThreadManager::tcl_crossexecute, Tcl::variadic());
    8281
    8382            try
    8483            {
    85                 this->interpreter_->eval("proc query args { orxonox::query [join $args] }");
    86                 this->interpreter_->eval("proc crossquery {id args} { orxonox::crossquery 0 $id [join $args] }");
    87                 this->interpreter_->eval("proc crossexecute {id args} { orxonox::crossquery 0 $id [join $args] }");
     84                this->interpreter_->eval("proc query args { orxonox::query $args }");
     85                this->interpreter_->eval("proc crossquery {id args} { orxonox::crossquery 0 $id $args }");
    8886                this->interpreter_->eval("set id 0");
    8987                this->interpreter_->eval("rename exit tcl::exit; proc exit {} { execute exit }");
  • code/trunk/src/core/TclThreadManager.cc

    r3307 r3313  
    3030
    3131#include <boost/bind.hpp>
     32#include <boost/thread/condition.hpp>
     33#include <boost/thread/mutex.hpp>
    3234#include <boost/thread/thread.hpp>
    33 #include <boost/thread/locks.hpp>
    34 #include <boost/thread/shared_mutex.hpp>
    3535#include <OgreTimer.h>
    3636#include <cpptcl/cpptcl.h>
    3737
    3838#include "util/Convert.h"
     39#include "util/Debug.h"
    3940#include "Clock.h"
    4041#include "CommandExecutor.h"
     
    4243#include "CoreIncludes.h"
    4344#include "TclBind.h"
    44 #include "TclThreadList.h"
    4545
    4646namespace orxonox
    4747{
     48    const unsigned int TCLTHREADMANAGER_MAX_QUEUE_LENGTH = 100;
    4849    const float TCLTHREADMANAGER_MAX_CPU_USAGE = 0.50f;
    4950
     
    5455    SetConsoleCommand(TclThreadManager, execute, false).argumentCompleter(0, autocompletion::tclthreads());
    5556    SetConsoleCommand(TclThreadManager, query,   false).argumentCompleter(0, autocompletion::tclthreads());
    56 
    57     /**
    58         @brief A struct containing all informations about a Tcl-interpreter
    59     */
     57    SetConsoleCommand(TclThreadManager, status,  false);
     58    SetConsoleCommand(TclThreadManager, dump,    false).argumentCompleter(0, autocompletion::tclthreads());
     59    SetConsoleCommand(TclThreadManager, flush,   false).argumentCompleter(0, autocompletion::tclthreads());
     60
    6061    struct TclInterpreterBundle
    6162    {
    62         TclInterpreterBundle()
    63         {
    64             this->lock_ = new boost::unique_lock<boost::mutex>(this->mutex_, boost::defer_lock);
    65             this->bRunning_ = true;
    66         }
    67 
    68         ~TclInterpreterBundle()
    69         {
    70             delete this->lock_;
    71         }
    72 
    73         unsigned int                      id_;             ///< The id of the interpreter
    74         Tcl::interpreter*                 interpreter_;    ///< The Tcl-interpreter
    75         boost::mutex                      mutex_;          ///< A mutex to lock the interpreter while it's being used
    76         boost::unique_lock<boost::mutex>* lock_;           ///< The corresponding lock for the mutex
    77         TclThreadList<std::string>        queue_;          ///< The command queue for commands passed by execute(command)
    78         TclThreadList<unsigned int>       queriers_;       ///< A list containing the id's of all other threads sending a query to this interpreter (to avoid circular queries and deadlocks)
    79         bool                              bRunning_;       ///< This variable stays true until destroy() gets called
     63        unsigned int id_;
     64
     65        std::list<std::string> queue_;
     66        boost::mutex queueMutex_;
     67
     68        Tcl::interpreter* interpreter_;
     69        std::string interpreterName_;
     70        boost::try_mutex interpreterMutex_;
     71
     72        std::list<unsigned int> queriers_;
     73        boost::mutex queriersMutex_;
     74
     75        bool running_;
     76        boost::mutex runningMutex_;
     77
     78        bool finished_;
     79        boost::mutex finishedMutex_;
     80        boost::condition finishedCondition_;
    8081    };
    8182
    82     TclThreadManager* TclThreadManager::singletonPtr_s = 0;
    83 
    84     /**
    85         @brief Constructor
    86         @param interpreter A pointer to the standard Tcl-interpreter (see @ref TclBind)
    87     */
     83
     84    static boost::thread::id threadID_g;
     85    static boost::mutex bundlesMutex_g;
     86    static boost::condition fullQueueCondition_g;
     87    static boost::condition orxonoxEvalCondition_g;
     88
     89    TclThreadManager* TclThreadManager::singletonRef_s = 0;
     90
    8891    TclThreadManager::TclThreadManager(Tcl::interpreter* interpreter)
     92        : orxonoxInterpreterBundle_(new TclInterpreterBundle())
    8993    {
    9094        RegisterRootObject(TclThreadManager);
    9195
    92         assert(TclThreadManager::singletonPtr_s == 0);
    93         TclThreadManager::singletonPtr_s = this;
    94 
    95         this->numInterpreterBundles_ = 0;
    96 
    97         this->interpreterBundlesMutex_ = new boost::shared_mutex();
    98         this->mainInterpreterMutex_ = new boost::mutex();
    99         this->messageQueue_ = new TclThreadList<std::string>();
    100 
    101         TclInterpreterBundle* newbundle = new TclInterpreterBundle();
    102         newbundle->id_ = 0;
    103         newbundle->interpreter_ = interpreter;
    104         newbundle->lock_->lock();
    105 
    106         {
    107             boost::unique_lock<boost::shared_mutex> lock(*this->interpreterBundlesMutex_);
    108             this->interpreterBundles_[0] = newbundle;
    109         }
    110     }
    111 
    112     /**
    113         @brief Destructor
    114     */
     96        assert(singletonRef_s == 0);
     97        singletonRef_s = this;
     98
     99        this->threadCounter_ = 0;
     100        this->orxonoxInterpreterBundle_->id_ = 0;
     101        this->orxonoxInterpreterBundle_->interpreter_ = interpreter;
     102        threadID_g = boost::this_thread::get_id();
     103    }
     104
    115105    TclThreadManager::~TclThreadManager()
    116106    {
    117         TclThreadManager::singletonPtr_s = 0;
    118 
    119         delete this->interpreterBundlesMutex_;
    120         delete this->mainInterpreterMutex_;
    121         delete this->messageQueue_;
    122     }
    123 
    124     /**
    125         @brief The "main loop" of the TclThreadManager. Creates new threads if needed and handles queries and queued commands for the main interpreter.
    126     */
    127     void TclThreadManager::update(const Clock& time)
    128     {
    129         // Get the bundle of the main interpreter (0)
    130         TclInterpreterBundle* bundle = this->getInterpreterBundle(0);
     107        unsigned int threadID;
     108        {
     109            boost::mutex::scoped_lock bundles_lock(bundlesMutex_g);
     110            if (this->interpreterBundles_.begin() == this->interpreterBundles_.end())
     111                return;
     112            else
     113                threadID = this->interpreterBundles_.begin()->first;
     114        }
     115        this->destroy(threadID);
     116
     117        delete this->orxonoxInterpreterBundle_;
     118
     119        singletonRef_s = 0;
     120    }
     121
     122    unsigned int TclThreadManager::create()
     123    {
     124        boost::mutex::scoped_lock bundles_lock(bundlesMutex_g);
     125        TclThreadManager::getInstance().threadCounter_++;
     126        std::string name = multi_cast<std::string>(TclThreadManager::getInstance().threadCounter_);
     127
     128        TclInterpreterBundle* bundle = new TclInterpreterBundle;
     129        bundle->id_ = TclThreadManager::getInstance().threadCounter_;
     130        bundle->interpreter_ = TclThreadManager::getInstance().createNewTclInterpreter(name);
     131        bundle->interpreterName_ = name;
     132        bundle->running_ = true;
     133        bundle->finished_ = true;
     134
     135        TclThreadManager::getInstance().interpreterBundles_[TclThreadManager::getInstance().threadCounter_] = bundle;
     136        COUT(0) << "Created new Tcl-interpreter with ID " << TclThreadManager::getInstance().threadCounter_ << std::endl;
     137        return TclThreadManager::getInstance().threadCounter_;
     138    }
     139
     140    unsigned int TclThreadManager::createID(unsigned int threadID)
     141    {
     142        unsigned int temp = TclThreadManager::getInstance().threadCounter_;
     143        TclThreadManager::getInstance().threadCounter_ = threadID - 1;
     144        TclThreadManager::create();
     145        TclThreadManager::getInstance().threadCounter_ = temp;
     146        return threadID;
     147    }
     148
     149    void TclThreadManager::destroy(unsigned int threadID)
     150    {
     151        TclInterpreterBundle* bundle = TclThreadManager::getInstance().getInterpreterBundle(threadID);
    131152        if (bundle)
    132153        {
    133             // Unlock the mutex to allow other threads accessing the main interpreter
    134             bundle->lock_->unlock();
    135 
    136             // Lock the main interpreter mutex once to synchronize with threads that want to query the main interpreter
    137             {
    138                 boost::unique_lock<boost::mutex> lock(*this->mainInterpreterMutex_);
    139             }
    140 
    141             // Lock the mutex again to gain exclusive access to the interpreter for the rest of the mainloop
    142             bundle->lock_->lock();
    143 
    144             // Execute commands in the queues of the threaded interpreters
    145             {
    146                 boost::shared_lock<boost::shared_mutex> lock(*this->interpreterBundlesMutex_);
    147                 for (std::map<unsigned int, TclInterpreterBundle*>::const_iterator it = this->interpreterBundles_.begin(); it != this->interpreterBundles_.end(); ++it)
     154            {
     155                boost::mutex::scoped_lock running_lock(bundle->runningMutex_);
     156                bundle->running_ = false;
     157            }
     158            while (true)
     159            {
    148160                {
    149                     if (it->first == 0)
    150                         continue; // We'll handle the default interpreter later (and without threads of course)
    151 
    152                     TclInterpreterBundle* bundle = it->second;
    153                     if (!bundle->queue_.empty())
     161                    boost::mutex::scoped_lock finished_lock(bundle->finishedMutex_);
     162                    if (bundle->finished_)
    154163                    {
    155                         // There are commands in the queue
     164                        boost::mutex::scoped_lock bundles_lock(bundlesMutex_g);
     165                        boost::mutex::scoped_try_lock interpreter_lock(bundle->interpreterMutex_);
    156166                        try
    157167                        {
    158                             if (!bundle->lock_->owns_lock() && bundle->lock_->try_lock())
     168                            while (!interpreter_lock.try_lock())
    159169                            {
    160                                 // We sucessfully obtained a lock for the interpreter
    161                                 std::string command;
    162                                 if (bundle->queue_.try_pop_front(&command))
    163                                 {
    164                                     // Start a thread to execute the command
    165                                     boost::thread(boost::bind(&tclThread, bundle, command));
    166                                 }
    167                                 else
    168                                 {
    169                                     // Somehow the queue become empty (maybe multiple consumers) - unlock the mutex
    170                                     bundle->lock_->unlock();
    171                                 }
     170                                orxonoxEvalCondition_g.notify_one();
     171                                boost::this_thread::yield();
    172172                            }
    173                         }
    174                         catch (...)
    175                         {
    176                             // A lock error occurred - this is possible if the lock gets locked between !bundle->lock_->owns_lock() and bundle->lock_->try_lock()
    177                             // This isn't too bad, just continue
    178                         }
     173                        } catch (...) {}
     174                        delete bundle->interpreter_;
     175                        delete bundle;
     176                        TclThreadManager::getInstance().interpreterBundles_.erase(threadID);
     177                        break;
    179178                    }
    180179                }
    181             }
    182 
    183             // Execute commands in the message queue
    184             if (!this->messageQueue_->empty())
    185             {
    186                 std::string command;
    187                 while (true)
     180
     181                orxonoxEvalCondition_g.notify_one();
     182                boost::this_thread::yield();
     183            }
     184
     185            COUT(0) << "Destroyed Tcl-interpreter with ID " << threadID << std::endl;
     186        }
     187    }
     188
     189    void TclThreadManager::execute(unsigned int threadID, const std::string& _command)
     190    {
     191        std::string command = stripEnclosingBraces(_command);
     192
     193        if (threadID == 0)
     194            TclThreadManager::getInstance().pushCommandToQueue(command);
     195        else
     196            TclThreadManager::getInstance().pushCommandToQueue(threadID, command);
     197    }
     198
     199    std::string TclThreadManager::query(unsigned int threadID, const std::string& command)
     200    {
     201        return TclThreadManager::getInstance().evalQuery(TclThreadManager::getInstance().orxonoxInterpreterBundle_->id_, threadID, command);
     202    }
     203
     204    void TclThreadManager::status()
     205    {
     206        COUT(0) << "Thread ID" << '\t' << "Queue size" << '\t' << "State" << std::endl;
     207
     208        std::string output = "Orxonox";
     209        output += "\t\t";
     210        {
     211            boost::mutex::scoped_lock queue_lock(TclThreadManager::getInstance().orxonoxInterpreterBundle_->queueMutex_);
     212            output += multi_cast<std::string>(TclThreadManager::getInstance().orxonoxInterpreterBundle_->queue_.size());
     213        }
     214        output += "\t\t";
     215        output += "busy";
     216        COUT(0) << output << std::endl;
     217
     218        boost::mutex::scoped_lock bundles_lock(bundlesMutex_g);
     219        for (std::map<unsigned int, TclInterpreterBundle*>::const_iterator it = TclThreadManager::getInstance().interpreterBundles_.begin(); it != TclThreadManager::getInstance().interpreterBundles_.end(); ++it)
     220        {
     221            std::string output = multi_cast<std::string>((*it).first);
     222            output += "\t\t";
     223            {
     224                boost::mutex::scoped_lock queue_lock((*it).second->queueMutex_);
     225                output += multi_cast<std::string>((*it).second->queue_.size());
     226            }
     227            output += "\t\t";
     228            {
     229                boost::mutex::scoped_try_lock interpreter_lock((*it).second->interpreterMutex_);
     230                if (interpreter_lock.try_lock())
     231                    output += "ready";
     232                else
     233                    output += "busy";
     234            }
     235            COUT(0) << output << std::endl;
     236        }
     237    }
     238
     239    void TclThreadManager::dump(unsigned int threadID)
     240    {
     241        TclInterpreterBundle* bundle = 0;
     242        if (threadID == 0)
     243        {
     244            bundle = TclThreadManager::getInstance().orxonoxInterpreterBundle_;
     245            COUT(0) << "Queue dump of Orxonox:" << std::endl;
     246        }
     247        else
     248        {
     249            if ((bundle = TclThreadManager::getInstance().getInterpreterBundle(threadID)))
     250            {
     251                COUT(0) << "Queue dump of Tcl-thread " << threadID << ":" << std::endl;
     252            }
     253            else
     254                return;
     255        }
     256
     257        boost::mutex::scoped_lock queue_lock(bundle->queueMutex_);
     258        unsigned int index = 0;
     259        for (std::list<std::string>::const_iterator it = bundle->queue_.begin(); it != bundle->queue_.end(); ++it)
     260        {
     261            index++;
     262            COUT(0) << index << ": " << (*it) << std::endl;
     263        }
     264    }
     265
     266    void TclThreadManager::flush(unsigned int threadID)
     267    {
     268        TclInterpreterBundle* bundle = 0;
     269        if (threadID == 0)
     270            bundle = TclThreadManager::getInstance().orxonoxInterpreterBundle_;
     271        else
     272            if (!(bundle = TclThreadManager::getInstance().getInterpreterBundle(threadID)))
     273                return;
     274
     275        boost::mutex::scoped_lock queue_lock(bundle->queueMutex_);
     276        bundle->queue_.clear();
     277        if (threadID == 0)
     278        {
     279            COUT(0) << "Flushed queue of Orxonox Tcl-interpreter." << std::endl;
     280        }
     281        else
     282        {
     283            COUT(0) << "Flushed queue of Tcl-interpreter " << threadID << "." << std::endl;
     284        }
     285    }
     286
     287    void TclThreadManager::tcl_execute(Tcl::object const &args)
     288    {
     289        TclThreadManager::getInstance().pushCommandToQueue(stripEnclosingBraces(args.get()));
     290    }
     291
     292    std::string TclThreadManager::tcl_query(int querierID, Tcl::object const &args)
     293    {
     294        return TclThreadManager::getInstance().evalQuery(static_cast<unsigned int>(querierID), stripEnclosingBraces(args.get()));
     295    }
     296
     297    std::string TclThreadManager::tcl_crossquery(int querierID, int threadID, Tcl::object const &args)
     298    {
     299        return TclThreadManager::getInstance().evalQuery(static_cast<unsigned int>(querierID), static_cast<unsigned int>(threadID), stripEnclosingBraces(args.get()));
     300    }
     301
     302    bool TclThreadManager::tcl_running(int threadID)
     303    {
     304        TclInterpreterBundle* bundle = TclThreadManager::getInstance().getInterpreterBundle(static_cast<unsigned int>(threadID));
     305        if (bundle)
     306        {
     307            boost::mutex::scoped_lock running_lock(bundle->runningMutex_);
     308            return bundle->running_;
     309        }
     310        return false;
     311    }
     312
     313    Tcl::interpreter* TclThreadManager::createNewTclInterpreter(const std::string& threadID)
     314    {
     315        Tcl::interpreter* i = 0;
     316        i = new Tcl::interpreter(TclBind::getInstance().getTclLibPath());
     317
     318        try
     319        {
     320            i->def("orxonox::query", TclThreadManager::tcl_query, Tcl::variadic());
     321            i->def("orxonox::crossquery", TclThreadManager::tcl_crossquery, Tcl::variadic());
     322            i->def("orxonox::execute", TclThreadManager::tcl_execute, Tcl::variadic());
     323            i->def("orxonox::running", TclThreadManager::tcl_running);
     324
     325            i->def("execute", TclThreadManager::tcl_execute, Tcl::variadic());
     326            i->eval("proc query args { orxonox::query " + threadID + " $args }");
     327            i->eval("proc crossquery {id args} { orxonox::crossquery " + threadID + " $id $args }");
     328            i->eval("set id " + threadID);
     329
     330            i->eval("rename exit tcl::exit");
     331            i->eval("proc exit {} { orxonox TclThreadManager destroy " + threadID + " }");
     332
     333            i->eval("redef_puts");
     334
     335//            i->eval("rename while tcl::while");
     336//            i->eval("proc while {test command} { tcl::while {[uplevel 1 expr $test]} {uplevel 1 $command} }"); // (\"$test\" && [orxonox::running " + threadID + "]])
     337//            i->eval("rename for tcl::for");
     338//            i->eval("proc for {start test next command} { uplevel tcl::for \"$start\" \"$test\" \"$next\" \"$command\" }");
     339        }
     340        catch (Tcl::tcl_error const &e)
     341        {   COUT(1) << "Tcl error while creating Tcl-interpreter (" << threadID << "): " << e.what() << std::endl;   }
     342        catch (std::exception const &e)
     343        {   COUT(1) << "Error while creating Tcl-interpreter (" << threadID << "): " << e.what() << std::endl;   }
     344
     345        return i;
     346    }
     347
     348    TclInterpreterBundle* TclThreadManager::getInterpreterBundle(unsigned int threadID)
     349    {
     350        boost::mutex::scoped_lock bundles_lock(bundlesMutex_g);
     351        std::map<unsigned int, TclInterpreterBundle*>::iterator it = this->interpreterBundles_.find(threadID);
     352        if (it != this->interpreterBundles_.end())
     353        {
     354            return (*it).second;
     355        }
     356        else
     357        {
     358            this->error("Error: No Tcl-interpreter with ID " + multi_cast<std::string>(threadID) + " existing.");
     359            return 0;
     360        }
     361    }
     362
     363    Tcl::interpreter* TclThreadManager::getTclInterpreter(unsigned int threadID)
     364    {
     365        return this->getInterpreterBundle(threadID)->interpreter_;
     366    }
     367
     368    std::string TclThreadManager::dumpList(const std::list<unsigned int>& list)
     369    {
     370        std::string output = "";
     371        for (std::list<unsigned int>::const_iterator it = list.begin(); it != list.end(); ++it)
     372        {
     373            if (it != list.begin())
     374                output += " ";
     375
     376            output += multi_cast<std::string>(*it);
     377        }
     378        return output;
     379    }
     380
     381    void TclThreadManager::error(const std::string& error)
     382    {
     383        if (boost::this_thread::get_id() != threadID_g)
     384        {
     385            boost::mutex::scoped_lock queue_lock(this->orxonoxInterpreterBundle_->queueMutex_);
     386            if (this->orxonoxInterpreterBundle_->queue_.size() >= TCLTHREADMANAGER_MAX_QUEUE_LENGTH)
     387            {
     388                boost::this_thread::yield();
     389                return;
     390            }
     391        }
     392
     393        this->forceCommandToFrontOfQueue("error " + error);
     394    }
     395
     396    void TclThreadManager::debug(const std::string& error)
     397    {
     398        if (boost::this_thread::get_id() != threadID_g)
     399        {
     400            boost::mutex::scoped_lock queue_lock(this->orxonoxInterpreterBundle_->queueMutex_);
     401            if (this->orxonoxInterpreterBundle_->queue_.size() >= TCLTHREADMANAGER_MAX_QUEUE_LENGTH)
     402            {
     403                boost::this_thread::yield();
     404                return;
     405            }
     406        }
     407
     408        this->forceCommandToFrontOfQueue("debug " + error);
     409    }
     410
     411    void TclThreadManager::pushCommandToQueue(const std::string& command)
     412    {
     413        boost::mutex::scoped_lock queue_lock(this->orxonoxInterpreterBundle_->queueMutex_);
     414        while (this->orxonoxInterpreterBundle_->queue_.size() >= TCLTHREADMANAGER_MAX_QUEUE_LENGTH)
     415            fullQueueCondition_g.wait(queue_lock);
     416
     417        this->orxonoxInterpreterBundle_->queue_.push_back(command);
     418    }
     419
     420    void TclThreadManager::forceCommandToFrontOfQueue(const std::string& command)
     421    {
     422        boost::mutex::scoped_lock queue_lock(this->orxonoxInterpreterBundle_->queueMutex_);
     423        this->orxonoxInterpreterBundle_->queue_.push_front(command);
     424    }
     425
     426    std::string TclThreadManager::popCommandFromQueue()
     427    {
     428        boost::mutex::scoped_lock queue_lock(this->orxonoxInterpreterBundle_->queueMutex_);
     429        std::string temp = this->orxonoxInterpreterBundle_->queue_.front();
     430        this->orxonoxInterpreterBundle_->queue_.pop_front();
     431        fullQueueCondition_g.notify_one();
     432        return temp;
     433    }
     434
     435    bool TclThreadManager::queueIsEmpty()
     436    {
     437        boost::mutex::scoped_lock queue_lock(this->orxonoxInterpreterBundle_->queueMutex_);
     438        return this->orxonoxInterpreterBundle_->queue_.empty();
     439    }
     440
     441    void TclThreadManager::pushCommandToQueue(unsigned int threadID, const std::string& command)
     442    {
     443        TclInterpreterBundle* bundle = this->getInterpreterBundle(threadID);
     444        if (bundle)
     445        {
     446            boost::mutex::scoped_lock queue_lock(bundle->queueMutex_);
     447            if (bundle->queue_.size() >= TCLTHREADMANAGER_MAX_QUEUE_LENGTH)
     448            {
     449                this->error("Error: Queue of Tcl-interpreter " + multi_cast<std::string>(threadID) + " is full, couldn't add command.");
     450                return;
     451            }
     452
     453            bundle->queue_.push_back(command);
     454        }
     455    }
     456
     457    std::string TclThreadManager::popCommandFromQueue(unsigned int threadID)
     458    {
     459        TclInterpreterBundle* bundle = this->getInterpreterBundle(threadID);
     460        if (bundle)
     461        {
     462            boost::mutex::scoped_lock queue_lock(bundle->queueMutex_);
     463            std::string temp = bundle->queue_.front();
     464            bundle->queue_.pop_front();
     465            return temp;
     466        }
     467        return "";
     468    }
     469
     470    bool TclThreadManager::queueIsEmpty(unsigned int threadID)
     471    {
     472        TclInterpreterBundle* bundle = this->getInterpreterBundle(threadID);
     473        if (bundle)
     474        {
     475            boost::mutex::scoped_lock queue_lock(bundle->queueMutex_);
     476            return bundle->queue_.empty();
     477        }
     478        return true;
     479    }
     480
     481    bool TclThreadManager::updateQueriersList(TclInterpreterBundle* querier, TclInterpreterBundle* target)
     482    {
     483        if (querier == target)
     484            return false;
     485
     486        boost::mutex::scoped_lock queriers_lock(target->queriersMutex_);
     487
     488        {
     489            boost::mutex::scoped_lock queriers_lock(querier->queriersMutex_);
     490            target->queriers_.insert(target->queriers_.end(), querier->queriers_.begin(), querier->queriers_.end());
     491        }
     492
     493        target->queriers_.insert(target->queriers_.end(), querier->id_);
     494
     495        if (std::find(target->queriers_.begin(), target->queriers_.end(), target->id_) != target->queriers_.end())
     496        {
     497            this->error("Error: Circular query (" + this->dumpList(target->queriers_) + " -> " + multi_cast<std::string>(target->id_) + "), couldn't query Tcl-interpreter with ID " + multi_cast<std::string>(target->id_) + " from other interpreter with ID " + multi_cast<std::string>(querier->id_) + ".");
     498            return false;
     499        }
     500
     501        return true;
     502    }
     503
     504    std::string TclThreadManager::evalQuery(unsigned int querierID, const std::string& command)
     505    {
     506        TclInterpreterBundle* querier = this->getInterpreterBundle(querierID);
     507        std::string output = "";
     508        if (querier)
     509        {
     510            if (this->updateQueriersList(querier, this->orxonoxInterpreterBundle_))
     511            {
     512                boost::mutex::scoped_lock interpreter_lock(this->orxonoxInterpreterBundle_->interpreterMutex_);
     513                orxonoxEvalCondition_g.wait(interpreter_lock);
     514
     515                if (!CommandExecutor::execute(command, false))
     516                    this->error("Error: Can't execute command \"" + command + "\"!");
     517
     518                if (CommandExecutor::getLastEvaluation().hasReturnvalue())
     519                    output = CommandExecutor::getLastEvaluation().getReturnvalue().getString();
     520            }
     521
     522            boost::mutex::scoped_lock queriers_lock(this->orxonoxInterpreterBundle_->queriersMutex_);
     523            this->orxonoxInterpreterBundle_->queriers_.clear();
     524        }
     525        return output;
     526    }
     527
     528    std::string TclThreadManager::evalQuery(unsigned int querierID, unsigned int threadID, const std::string& command)
     529    {
     530        TclInterpreterBundle* target = 0;
     531        if (threadID)
     532            target = this->getInterpreterBundle(threadID);
     533        else
     534            target = this->orxonoxInterpreterBundle_;
     535
     536        std::string output = "";
     537        if (target)
     538        {
     539            TclInterpreterBundle* querier = 0;
     540            if (querierID)
     541                querier = this->getInterpreterBundle(querierID);
     542            else
     543                querier = this->orxonoxInterpreterBundle_;
     544
     545            if (querier)
     546            {
     547                if (this->updateQueriersList(querier, target))
    188548                {
    189                     // Pop the front value from the list (break the loop if there are no elements in the list)
    190                     if (!this->messageQueue_->try_pop_front(&command))
    191                         break;
    192 
    193                     // Execute the command
    194                     CommandExecutor::execute(command, false);
    195                 }
    196             }
    197 
    198             // Execute commands in the queue of the main interpreter
    199             if (!bundle->queue_.empty())
    200             {
    201                 // Calculate the time we have until we reach the maximal cpu usage
    202                 unsigned long maxtime = (unsigned long)(time.getDeltaTime() * 1000000 * TCLTHREADMANAGER_MAX_CPU_USAGE);
    203 
    204                 Ogre::Timer timer;
    205                 std::string command;
    206 
    207                 while (timer.getMicroseconds() < maxtime)
    208                 {
    209                     // Pop the front value from the list (break the loop if there are no elements in the list)
    210                     if (!bundle->queue_.try_pop_front(&command))
    211                         break;
    212 
    213                     // Execute the command
    214                     CommandExecutor::execute(command, false);
    215                 }
    216             }
    217         }
    218     }
    219 
    220     /**
    221         @brief Creates a new Tcl-interpreter.
    222     */
    223     unsigned int TclThreadManager::create()
    224     {
    225         TclThreadManager::getInstance().numInterpreterBundles_++;
    226         TclThreadManager::createWithId(TclThreadManager::getInstance().numInterpreterBundles_);
    227         COUT(0) << "Created new Tcl-interpreter with ID " << TclThreadManager::getInstance().numInterpreterBundles_ << std::endl;
    228         return TclThreadManager::getInstance().numInterpreterBundles_;
    229     }
    230 
    231     /**
    232         @brief Creates a new Tcl-interpreter with a given id.
    233 
    234         Use with caution - if the id collides with an already existing interpreter, this call will fail.
    235         This will also be a problem, if the auto-numbered interpreters (by using create()) reach an id
    236         which was previously used in this function. Use high numbers to be safe.
    237     */
    238     Tcl::interpreter* TclThreadManager::createWithId(unsigned int id)
    239     {
    240         TclInterpreterBundle* newbundle = new TclInterpreterBundle();
    241         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;   }
    283 
    284         {
    285             // Add the new bundle to the map
    286             boost::unique_lock<boost::shared_mutex> lock(*TclThreadManager::getInstance().interpreterBundlesMutex_);
    287             TclThreadManager::getInstance().interpreterBundles_[id] = newbundle;
    288         }
    289 
    290         return newbundle->interpreter_;
    291     }
    292 
    293     /**
    294         @brief Stops and destroys a given Tcl-interpreter
    295     */
    296     void TclThreadManager::destroy(unsigned int id)
    297     {
    298         // TODO
    299         // Not yet implemented
    300     }
    301 
    302     /**
    303         @brief Sends a command to the queue of a given Tcl-interpreter
    304         @param id The id of the target interpreter
    305         @param command The command to be sent
    306     */
    307     void TclThreadManager::execute(unsigned int target_id, const std::string& command)
    308     {
    309         TclThreadManager::getInstance()._execute(target_id, command);
    310     }
    311 
    312     /**
    313         @brief This function can be called from Tcl to execute a console command.
    314 
    315         Commands which shall be executed are put into a queue and processed as soon as the
    316         main thread feels ready to do so. The queue may also be full which results in a temporary
    317         suspension of the calling thread until the queue gets ready again.
    318     */
    319     void TclThreadManager::tcl_execute(const Tcl::object& args)
    320     {
    321         TclThreadManager::getInstance()._execute(0, stripEnclosingBraces(args.get()));
    322     }
    323 
    324     /**
    325         @brief This function can be called from Tcl to send a command to the queue of any interpreter.
    326         @param target_id The id of the target thread
    327     */
    328     void TclThreadManager::tcl_crossexecute(int target_id, const Tcl::object& args)
    329     {
    330         TclThreadManager::getInstance()._execute(static_cast<unsigned int>(target_id), stripEnclosingBraces(args.get()));
    331     }
    332 
    333     /**
    334         @brief Sends a command to the queue of a given Tcl-interpreter
    335         @param id The id of the target interpreter
    336         @param command The command to be sent
    337     */
    338     void TclThreadManager::_execute(unsigned int target_id, const std::string& command)
    339     {
    340         TclInterpreterBundle* bundle = this->getInterpreterBundle(target_id);
    341         if (bundle)
    342             bundle->queue_.push_back(command);
    343     }
    344 
    345 
    346     /**
    347         @brief Sends a query to a given Tcl-interpreter and waits for the result
    348         @param id The id of the target interpreter
    349         @param command The command to be sent
    350         @return The result of the command
    351     */
    352     std::string TclThreadManager::query(unsigned int target_id, const std::string& command)
    353     {
    354         return TclThreadManager::getInstance()._query(0, target_id, command);
    355     }
    356 
    357     /**
    358         @brief This function can be called from Tcl to send a query to the main thread.
    359         @param source_id The id of the calling thread
    360 
    361         A query waits for the result of the command. This means, the calling thread will be blocked until
    362         the main thread answers the query. In return, the main thread sends the result of the console
    363         command back to Tcl.
    364     */
    365     std::string TclThreadManager::tcl_query(int source_id, const Tcl::object& args)
    366     {
    367         return TclThreadManager::getInstance()._query(static_cast<unsigned int>(source_id), 0, stripEnclosingBraces(args.get()), true);
    368     }
    369 
    370     /**
    371         @brief This function can be called from Tcl to send a query to another thread.
    372         @param source_id The id of the calling thread
    373         @param target_id The id of the target thread
    374     */
    375     std::string TclThreadManager::tcl_crossquery(int source_id, int target_id, const Tcl::object& args)
    376     {
    377         return TclThreadManager::getInstance()._query(static_cast<unsigned int>(source_id), static_cast<unsigned int>(target_id), stripEnclosingBraces(args.get()));
    378     }
    379 
    380     /**
    381         @brief This function performs a query to any Tcl interpreter
    382         @param source_id The id of the calling thread
    383         @param target_id The id of the target thread
    384         @param command The command to send as a query
    385         @param bUseCommandExecutor Only used if the target_id is 0 (which references the main interpreter). In this case it means if the command should be passed to the CommandExecutor (true) or to the main Tcl interpreter (false). This is true when called by tcl_query and false when called by tcl_crossquery.
    386     */
    387     std::string TclThreadManager::_query(unsigned int source_id, unsigned int target_id, const std::string& command, bool bUseCommandExecutor)
    388     {
    389         TclInterpreterBundle* source_bundle = this->getInterpreterBundle(source_id);
    390         TclInterpreterBundle* target_bundle = this->getInterpreterBundle(target_id);
    391         std::string output;
    392 
    393         if (source_bundle && target_bundle)
    394         {
    395             // At this point we assume the mutex of source_bundle to be locked (because it's executing this query right now an waits for the return value)
    396             // We can safely use it's querier list (because there's no other place in the code using the list except this query - and the interpreter can't start more than one query)
    397 
    398             if ((source_bundle->id_ == target_bundle->id_) || source_bundle->queriers_.is_in(target_bundle->id_))
    399             {
    400                 // 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_) \
    402                             + " -> " + getConvertedValue<unsigned int, std::string>(target_bundle->id_) \
    403                             + "), couldn't query Tcl-interpreter with ID " + getConvertedValue<unsigned int, std::string>(target_bundle->id_) \
    404                             + " from other interpreter with ID " + getConvertedValue<unsigned int, std::string>(source_bundle->id_) + ".");
    405             }
    406             else
    407             {
    408                 boost::unique_lock<boost::mutex> lock(target_bundle->mutex_, boost::try_to_lock);
    409                 boost::unique_lock<boost::mutex> mainlock(*this->mainInterpreterMutex_, boost::defer_lock);
    410 
    411                 if (!lock.owns_lock() && source_bundle->id_ != 0)
    412                 {
    413                     // We couldn't obtain the try_lock immediately and we're not the main interpreter - wait until the lock becomes possible (note: the main interpreter won't wait and instead returns an error - see below)
    414                     if (target_bundle->id_ == 0)
     549                    boost::mutex::scoped_try_lock interpreter_lock(target->interpreterMutex_);
     550                    bool successfullyLocked = false;
     551                    try
    415552                    {
    416                         // We're querying the main interpreter - use the main interpreter mutex to synchronize
    417                         mainlock.lock();
    418                         lock.lock();
     553                        if (querierID == 0 || std::find(querier->queriers_.begin(), querier->queriers_.end(), 0U) != querier->queriers_.end())
     554                            successfullyLocked = interpreter_lock.try_lock();
     555                        else
     556                        {
     557                            while (!interpreter_lock.try_lock())
     558                            {
     559                                boost::this_thread::yield();
     560                            }
     561
     562                            successfullyLocked = true;
     563                        }
     564                    } catch (...) {}
     565
     566                    if (successfullyLocked)
     567                    {
     568                        this->debug("TclThread_query: " + command);
     569                        try
     570                        {   output = static_cast<std::string>(target->interpreter_->eval(command));   }
     571                        catch (Tcl::tcl_error const &e)
     572                        {   this->error("Tcl error: " + static_cast<std::string>(e.what()));   }
     573                        catch (std::exception const &e)
     574                        {   this->error("Error while executing Tcl: " + static_cast<std::string>(e.what()));   }
    419575                    }
    420576                    else
    421577                    {
    422                         // We're querying a threaded interpreter - no synchronization needed
    423                         lock.lock();
     578                        this->error("Error: Couldn't query Tcl-interpreter with ID " + multi_cast<std::string>(threadID) + ", interpreter is busy right now.");
    424579                    }
    425580                }
    426581
    427                 if (lock.owns_lock())
     582                boost::mutex::scoped_lock queriers_lock(target->queriersMutex_);
     583                target->queriers_.clear();
     584            }
     585        }
     586        return output;
     587    }
     588
     589    void TclThreadManager::update(const Clock& time)
     590    {
     591        {
     592            orxonoxEvalCondition_g.notify_one();
     593            boost::this_thread::yield();
     594        }
     595
     596        {
     597            boost::mutex::scoped_lock bundles_lock(bundlesMutex_g);
     598            for (std::map<unsigned int, TclInterpreterBundle*>::iterator it = this->interpreterBundles_.begin(); it != this->interpreterBundles_.end(); ++it)
     599            {
     600                boost::mutex::scoped_lock queue_lock((*it).second->queueMutex_);
     601                if (!(*it).second->queue_.empty())
    428602                {
    429                     // Now the mutex of target_bundle is also locked an we can update the querier list
    430                     target_bundle->queriers_.insert(target_bundle->queriers_.getList().begin(), source_bundle->queriers_.getList().begin(), source_bundle->queriers_.getList().end());
    431                     target_bundle->queriers_.push_back(source_bundle->id_);
    432 
    433                     // Perform the query (note: this happens in the main thread because we need the returnvalue)
    434                     if (target_bundle->id_ == 0 && bUseCommandExecutor)
     603                    std::string command = (*it).second->queue_.front();
     604                    (*it).second->queue_.pop_front();
    435605                    {
    436                         // It's a query to the CommandExecutor
    437                         this->debug("TclThread_query -> CE: " + command);
    438                         if (!CommandExecutor::execute(command, false))
    439                             this->error("Error: Can't execute command \"" + command + "\"!");
    440 
    441                         if (CommandExecutor::getLastEvaluation().hasReturnvalue())
    442                             output = CommandExecutor::getLastEvaluation().getReturnvalue().getString();
     606                        boost::mutex::scoped_lock finished_lock((*it).second->finishedMutex_);
     607                        (*it).second->finished_ = false;
    443608                    }
    444                     else
    445                     {
    446                         // It's a query to a Tcl interpreter
    447                         this->debug("TclThread_query: " + command);
    448 
    449                         output = this->eval(target_bundle, command);
    450                     }
    451 
    452                     // Clear the queriers list of the target
    453                     target_bundle->queriers_.clear();
    454 
    455                     // Unlock the mutex of the target_bundle
    456                     lock.unlock();
    457 
    458                     // Finally unlock the main interpreter lock if necessary
    459                     if (mainlock.owns_lock())
    460                         mainlock.unlock();
     609                    boost::thread(boost::bind(&tclThread, (*it).second, command));
    461610                }
    462                 else
    463                 {
    464                     // This happens if the main thread tries to query a busy interpreter
    465                     // 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.");
    467                 }
    468             }
    469 
    470         }
    471 
    472         return output;
    473     }
    474 
    475     /**
    476         @brief This function can be called from Tcl to ask if the thread is still suposed to be running.
    477         @param id The id of the thread in question
    478     */
    479     bool TclThreadManager::tcl_running(int id)
    480     {
    481         TclInterpreterBundle* bundle = TclThreadManager::getInstance().getInterpreterBundle(static_cast<unsigned int>(id));
    482         if (bundle)
    483             return bundle->bRunning_;
    484         else
    485             return false;
    486     }
    487 
    488     /**
    489         @brief Returns the interpreter bundle with the given id.
    490         @param id The id of the interpreter
    491         @return The interpreter or 0 if the id doesn't exist
    492     */
    493     TclInterpreterBundle* TclThreadManager::getInterpreterBundle(unsigned int id)
    494     {
    495         boost::shared_lock<boost::shared_mutex> lock(*this->interpreterBundlesMutex_);
    496 
    497         std::map<unsigned int, TclInterpreterBundle*>::const_iterator it = this->interpreterBundles_.find(id);
    498         if (it != this->interpreterBundles_.end())
    499         {
    500             return it->second;
    501         }
    502         else
    503         {
    504             this->error("Error: No Tcl-interpreter with ID " + getConvertedValue<unsigned int, std::string>(id) + " existing.");
    505             return 0;
    506         }
    507     }
    508 
    509     /**
    510         @brief Returns a string containing all elements of a unsigned-integer-list separated by spaces.
    511     */
    512     std::string TclThreadManager::dumpList(const std::list<unsigned int>& list)
    513     {
    514         std::string output = "";
    515         for (std::list<unsigned int>::const_iterator it = list.begin(); it != list.end(); ++it)
    516         {
    517             if (it != list.begin())
    518                 output += " ";
    519 
    520             output += getConvertedValue<unsigned int, std::string>(*it);
    521         }
    522         return output;
    523     }
    524 
    525     /**
    526         @brief Returns a list with the numbers of all existing Tcl-interpreters.
    527 
    528         This function is used by the auto completion function.
    529     */
     611            }
     612        }
     613
     614        {
     615            boost::mutex::scoped_lock interpreter_lock(this->orxonoxInterpreterBundle_->interpreterMutex_);
     616            unsigned long maxtime = static_cast<unsigned long>(time.getDeltaTime() * 1000000 * TCLTHREADMANAGER_MAX_CPU_USAGE);
     617            Ogre::Timer timer;
     618            while (!this->queueIsEmpty())
     619            {
     620                CommandExecutor::execute(this->popCommandFromQueue(), false);
     621                if (timer.getMicroseconds() > maxtime)
     622                    break;
     623            }
     624        }
     625    }
     626
    530627    std::list<unsigned int> TclThreadManager::getThreadList() const
    531628    {
    532         boost::shared_lock<boost::shared_mutex> lock(*this->interpreterBundlesMutex_);
    533 
     629        boost::mutex::scoped_lock bundles_lock(bundlesMutex_g);
    534630        std::list<unsigned int> threads;
    535631        for (std::map<unsigned int, TclInterpreterBundle*>::const_iterator it = this->interpreterBundles_.begin(); it != this->interpreterBundles_.end(); ++it)
    536             if (it->first > 0 && it->first <= this->numInterpreterBundles_) // only list autonumbered interpreters (created with create()) - exclude the default interpreter 0 and all manually numbered interpreters)
    537                 threads.push_back(it->first);
     632            threads.push_back((*it).first);
    538633        return threads;
    539634    }
    540635
    541     /**
    542         @brief A helper function to print errors in a thread safe manner.
    543     */
    544     void TclThreadManager::error(const std::string& error)
    545     {
    546         this->messageQueue_->push_back("error " + error);
    547     }
    548 
    549     /**
    550         @brief A helper function to print debug information in a thread safe manner.
    551     */
    552     void TclThreadManager::debug(const std::string& error)
    553     {
    554         this->messageQueue_->push_back("debug " + error);
    555     }
    556 
    557     /**
    558         @brief Evaluates a Tcl command without throwing exceptions (which may rise problems on certain machines).
    559         @return The Tcl return value
    560 
    561         Errors are reported through the @ref error function.
    562     */
    563     std::string TclThreadManager::eval(TclInterpreterBundle* bundle, const std::string& command)
    564     {
    565         Tcl_Interp* interpreter = bundle->interpreter_->get();
    566         int cc = Tcl_Eval(interpreter, command.c_str());
    567 
    568         Tcl::details::result result(interpreter);
    569 
    570         if (cc != TCL_OK)
    571         {
    572             this->error("Tcl error (execute, ID " + getConvertedValue<unsigned int, std::string>(bundle->id_) + "): " + static_cast<std::string>(result));
    573             return "";
    574         }
    575         else
    576         {
    577             return result;
    578         }
    579     }
    580 
    581     ////////////////
    582     // The Thread //
    583     ////////////////
    584 
    585     /**
    586         @brief The main function of the thread. Executes a Tcl command.
    587         @param bundle The interpreter bundle containing all necessary variables
    588         @param command the Command to execute
    589     */
    590     void tclThread(TclInterpreterBundle* bundle, std::string command)
     636    void tclThread(TclInterpreterBundle* interpreterBundle, std::string command)
    591637    {
    592638        TclThreadManager::getInstance().debug("TclThread_execute: " + command);
    593 
    594         TclThreadManager::getInstance().eval(bundle, command);
    595 
    596         bundle->lock_->unlock();
     639        boost::mutex::scoped_lock interpreter_lock(interpreterBundle->interpreterMutex_);
     640        try
     641        {
     642            interpreterBundle->interpreter_->eval(command);
     643        }
     644        catch (Tcl::tcl_error const &e)
     645        {
     646            TclThreadManager::getInstance().error("Tcl (ID " + multi_cast<std::string>(interpreterBundle->id_) + ") error: " + e.what());
     647        }
     648        catch (std::exception const &e)
     649        {
     650            TclThreadManager::getInstance().error("Error while executing Tcl (ID " + multi_cast<std::string>(interpreterBundle->id_) + "): " + e.what());
     651        }
     652
     653        boost::mutex::scoped_lock finished_lock(interpreterBundle->finishedMutex_);
     654        interpreterBundle->finished_ = true;
     655        interpreterBundle->finishedCondition_.notify_all();
    597656    }
    598657}
  • code/trunk/src/core/TclThreadManager.h

    r3308 r3313  
    3333
    3434#include <cassert>
     35#include <list>
    3536#include <map>
    3637#include <string>
    37 
    38 #include "OrxonoxClass.h"
     38#include "core/OrxonoxClass.h"
    3939
    4040namespace orxonox
    4141{
     42    // Internal struct
     43    struct TclInterpreterBundle;
     44
    4245    class _CoreExport TclThreadManager : public OrxonoxClass
    4346    {
     47        friend class IRC;
    4448        friend class TclBind;
    45         friend void tclThread(TclInterpreterBundle* bundle, std::string command);
    4649
    4750        public:
    4851            TclThreadManager(Tcl::interpreter* interpreter);
    49             virtual ~TclThreadManager();
     52            ~TclThreadManager();
    5053
    51             static TclThreadManager& getInstance() { assert(TclThreadManager::singletonPtr_s); return *TclThreadManager::singletonPtr_s; }
     54            static TclThreadManager& getInstance() { assert(singletonRef_s); return *singletonRef_s; }
    5255
    53             static unsigned int      create();
    54             static Tcl::interpreter* createWithId(unsigned int id);
    55             static void              destroy(unsigned int id);
    56             static void              execute(unsigned int target_id, const std::string& command);
    57             static std::string       query(unsigned int target_id, const std::string& command);
     56            static unsigned int create();
     57            static unsigned int createID(unsigned int threadID);
     58            static void destroy(unsigned int threadID);
     59            static void execute(unsigned int threadID, const std::string& command);
     60            static std::string query(unsigned int threadID, const std::string& command);
     61            static void status();
     62            static void dump(unsigned int threadID);
     63            static void flush(unsigned int threadID);
    5864
    5965            void error(const std::string& error);
     
    6571
    6672        private:
    67             static void tcl_execute(const Tcl::object& args);
    68             static void tcl_crossexecute(int target_id, const Tcl::object& args);
    69             static std::string tcl_query(int source_id, const Tcl::object& args);
    70             static std::string tcl_crossquery(int source_id, int target_id, const Tcl::object& args);
    71             static bool tcl_running(int id);
     73            TclThreadManager(const TclThreadManager& other);
    7274
    73             void _execute(unsigned int target_id, const std::string& command);
    74             std::string _query(unsigned int source_id, unsigned int target_id, const std::string& command, bool bUseCommandExecutor = false);
     75            static void tcl_execute(Tcl::object const &args);
     76            static std::string tcl_query(int querierID, Tcl::object const &args);
     77            static std::string tcl_crossquery(int querierID, int threadID, Tcl::object const &args);
     78            static bool tcl_running(int threadID);
    7579
    76             TclInterpreterBundle* getInterpreterBundle(unsigned int id);
     80            Tcl::interpreter* createNewTclInterpreter(const std::string& threadID);
     81            Tcl::interpreter* getTclInterpreter(unsigned int threadID);
     82            TclInterpreterBundle* getInterpreterBundle(unsigned int threadID);
    7783            std::string dumpList(const std::list<unsigned int>& list);
    7884
    79             std::string eval(TclInterpreterBundle* bundle, const std::string& command);
     85            void pushCommandToQueue(const std::string& command);
     86            void forceCommandToFrontOfQueue(const std::string& command);
     87            std::string popCommandFromQueue();
     88            bool queueIsEmpty();
    8089
    81             static TclThreadManager* singletonPtr_s;                            ///< Singleton pointer
     90            void pushCommandToQueue(unsigned int threadID, const std::string& command);
     91            std::string popCommandFromQueue(unsigned int threadID);
     92            bool queueIsEmpty(unsigned int threadID);
    8293
    83             unsigned int numInterpreterBundles_;                                ///< Number of created Tcl-interpreters (only used for auto-numbered interpreters, not affected by @ref createWithId)
    84             std::map<unsigned int, TclInterpreterBundle*> interpreterBundles_;  ///< A map containing all Tcl-interpreters
    85             boost::shared_mutex* interpreterBundlesMutex_;                      ///< A mutex used to synchronize threads when accessing @ref interpreterBundles_
    86             TclThreadList<std::string>* messageQueue_;                          ///< A queue to pass messages from Tcl-threads to the main thread
    87             boost::mutex* mainInterpreterMutex_;                                ///< A mutex to synchronize queries to the main interpreter
     94            bool updateQueriersList(TclInterpreterBundle* querier, TclInterpreterBundle* target);
     95
     96            std::string evalQuery(unsigned int querierID, const std::string& command);
     97            std::string evalQuery(unsigned int querierID, unsigned int threadID, const std::string& command);
     98
     99            unsigned int threadCounter_;
     100            TclInterpreterBundle* orxonoxInterpreterBundle_;
     101            std::map<unsigned int, TclInterpreterBundle*> interpreterBundles_;
     102
     103            static TclThreadManager* singletonRef_s;
    88104    };
    89105
    90     _CoreExport void tclThread(TclInterpreterBundle* bundle, std::string command);
     106    _CoreExport void tclThread(TclInterpreterBundle* interpreterBundle, std::string command);
    91107}
    92108
Note: See TracChangeset for help on using the changeset viewer.