Changeset 3370 for code/trunk/src/core/TclThreadManager.cc
- Timestamp:
- Jul 30, 2009, 2:10:44 PM (16 years ago)
- Location:
- code/trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
code/trunk
- Property svn:mergeinfo changed
/code/branches/resource (added) merged: 3328,3336-3340,3342-3350,3352-3366
- Property svn:mergeinfo changed
-
code/trunk/src/core/TclThreadManager.cc
r3326 r3370 54 54 SetConsoleCommand(TclThreadManager, execute, false).argumentCompleter(0, autocompletion::tclthreads()); 55 55 SetConsoleCommand(TclThreadManager, query, false).argumentCompleter(0, autocompletion::tclthreads()); 56 SetConsoleCommand(TclThreadManager, source, false).argumentCompleter(0, autocompletion::tclthreads()); 56 57 57 58 /** … … 90 91 RegisterRootObject(TclThreadManager); 91 92 92 assert(TclThreadManager::singletonPtr_s == 0);93 TclThreadManager::singletonPtr_s = this;94 95 93 this->numInterpreterBundles_ = 0; 96 94 … … 115 113 TclThreadManager::~TclThreadManager() 116 114 { 117 TclThreadManager::singletonPtr_s = 0;118 119 115 delete this->interpreterBundlesMutex_; 120 116 // delete this->mainInterpreterMutex_; // <-- temporary disabled to avoid crash if a thread is still actively queriyng … … 240 236 TclInterpreterBundle* newbundle = new TclInterpreterBundle(); 241 237 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); 283 241 284 242 { … … 291 249 } 292 250 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 293 293 /** 294 294 @brief Stops and destroys a given Tcl-interpreter … … 298 298 // TODO 299 299 // Not yet implemented 300 TclInterpreterBundle* bundle = TclThreadManager::getInstance().getInterpreterBundle(id); 301 if (bundle) 302 { 303 bundle->bRunning_ = false; 304 } 300 305 } 301 306 … … 399 404 { 400 405 // 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_) \ 402 407 + " -> " + getConvertedValue<unsigned int, std::string>(target_bundle->id_) \ 403 408 + "), couldn't query Tcl-interpreter with ID " + getConvertedValue<unsigned int, std::string>(target_bundle->id_) \ … … 435 440 { 436 441 // It's a query to the CommandExecutor 437 this->debug("TclThread_query -> CE: " + command);442 TclThreadManager::debug("TclThread_query -> CE: " + command); 438 443 if (!CommandExecutor::execute(command, false)) 439 this->error("Error: Can't execute command \"" + command + "\"!");444 TclThreadManager::error("Error: Can't execute command \"" + command + "\"!"); 440 445 441 446 if (CommandExecutor::getLastEvaluation().hasReturnvalue()) … … 445 450 { 446 451 // 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"); 450 455 } 451 456 … … 464 469 // This happens if the main thread tries to query a busy interpreter 465 470 // 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."); 467 472 } 468 473 } … … 471 476 472 477 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)); 473 486 } 474 487 … … 502 515 else 503 516 { 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."); 505 518 return 0; 506 519 } … … 544 557 void TclThreadManager::error(const std::string& error) 545 558 { 546 this->messageQueue_->push_back("error " + error);559 TclThreadManager::getInstance().messageQueue_->push_back("error " + error); 547 560 } 548 561 … … 552 565 void TclThreadManager::debug(const std::string& error) 553 566 { 554 this->messageQueue_->push_back("debug " + error);567 TclThreadManager::getInstance().messageQueue_->push_back("debug " + error); 555 568 } 556 569 … … 561 574 Errors are reported through the @ref error function. 562 575 */ 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) 564 577 { 565 578 Tcl_Interp* interpreter = bundle->interpreter_->get(); … … 570 583 if (cc != TCL_OK) 571 584 { 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)); 573 586 return ""; 574 587 } … … 590 603 void tclThread(TclInterpreterBundle* bundle, std::string command) 591 604 { 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"); 595 608 596 609 bundle->lock_->unlock(); 597 610 } 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 } 598 672 }
Note: See TracChangeset
for help on using the changeset viewer.