Changeset 3360 for code/branches/resource/src/core/TclThreadManager.cc
- Timestamp:
- Jul 28, 2009, 5:04:38 PM (15 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
code/branches/resource/src/core/TclThreadManager.cc
r3353 r3360 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 /** … … 242 243 newbundle->interpreter_ = TclBind::createTclInterpreter(); 243 244 244 // Initialize the new interpreter 245 try 246 { 247 std::string id_string = getConvertedValue<unsigned int, std::string>(id); 248 249 // Define the functions which are implemented in C++ 250 newbundle->interpreter_->def("::orxonox::execute", TclThreadManager::tcl_execute, Tcl::variadic()); 251 newbundle->interpreter_->def("::orxonox::crossexecute", TclThreadManager::tcl_crossexecute, Tcl::variadic()); 252 newbundle->interpreter_->def("::orxonox::query", TclThreadManager::tcl_query, Tcl::variadic()); 253 newbundle->interpreter_->def("::orxonox::crossquery", TclThreadManager::tcl_crossquery, Tcl::variadic()); 254 newbundle->interpreter_->def("::orxonox::running", TclThreadManager::tcl_running); 255 256 // Create threadspecific shortcuts for the functions above 257 newbundle->interpreter_->def("execute", TclThreadManager::tcl_execute, Tcl::variadic()); 258 newbundle->interpreter_->def("crossexecute", TclThreadManager::tcl_crossexecute, Tcl::variadic()); 259 newbundle->interpreter_->eval("proc query {args} { ::orxonox::query " + id_string + " $args }"); 260 newbundle->interpreter_->eval("proc crossquery {id args} { ::orxonox::crossquery " + id_string + " $id $args }"); 261 newbundle->interpreter_->eval("proc running {} { return [::orxonox::running " + id_string + "] }"); 262 263 // Define a variable containing the thread id 264 newbundle->interpreter_->eval("set id " + id_string); 265 266 // Use our own exit function to avoid shutting down the whole program instead of just the interpreter 267 newbundle->interpreter_->eval("rename exit ::tcl::exit"); 268 newbundle->interpreter_->eval("proc exit {} { execute TclThreadManager destroy " + id_string + " }"); 269 270 // Redefine some native functions 271 newbundle->interpreter_->eval("rename while ::tcl::while"); 272 newbundle->interpreter_->eval("rename ::orxonox::while while"); 273 newbundle->interpreter_->eval("rename for ::tcl::for"); 274 newbundle->interpreter_->eval("rename ::orxonox::for for"); 275 } 276 catch (const Tcl::tcl_error& e) 277 { newbundle->interpreter_ = 0; COUT(1) << "Tcl error while creating Tcl-interpreter (" << id << "): " << e.what() << std::endl; } 278 catch (const std::exception& e) 279 { newbundle->interpreter_ = 0; COUT(1) << "Error while creating Tcl-interpreter (" << id << "): " << e.what() << std::endl; } 280 catch (...) 281 { newbundle->interpreter_ = 0; COUT(1) << "An error occurred while creating a new Tcl-interpreter (" << id << ")" << std::endl; } 245 TclThreadManager::initialize(newbundle); 282 246 283 247 { … … 288 252 289 253 return newbundle->interpreter_; 254 } 255 256 void TclThreadManager::initialize(TclInterpreterBundle* bundle) 257 { 258 std::string id_string = getConvertedValue<unsigned int, std::string>(bundle->id_); 259 260 // Initialize the new interpreter 261 try 262 { 263 // Define the functions which are implemented in C++ 264 bundle->interpreter_->def("::orxonox::execute", TclThreadManager::tcl_execute, Tcl::variadic()); 265 bundle->interpreter_->def("::orxonox::crossexecute", TclThreadManager::tcl_crossexecute, Tcl::variadic()); 266 bundle->interpreter_->def("::orxonox::query", TclThreadManager::tcl_query, Tcl::variadic()); 267 bundle->interpreter_->def("::orxonox::crossquery", TclThreadManager::tcl_crossquery, Tcl::variadic()); 268 bundle->interpreter_->def("::orxonox::running", TclThreadManager::tcl_running); 269 270 // Create threadspecific shortcuts for the functions above 271 bundle->interpreter_->def("execute", TclThreadManager::tcl_execute, Tcl::variadic()); 272 bundle->interpreter_->def("crossexecute", TclThreadManager::tcl_crossexecute, Tcl::variadic()); 273 bundle->interpreter_->eval("proc query {args} { ::orxonox::query " + id_string + " $args }"); 274 bundle->interpreter_->eval("proc crossquery {id args} { ::orxonox::crossquery " + id_string + " $id $args }"); 275 bundle->interpreter_->eval("proc running {} { return [::orxonox::running " + id_string + "] }"); 276 277 // Define a variable containing the thread id 278 bundle->interpreter_->eval("set id " + id_string); 279 280 // Use our own exit function to avoid shutting down the whole program instead of just the interpreter 281 bundle->interpreter_->eval("rename exit ::tcl::exit"); 282 bundle->interpreter_->eval("proc exit {} { execute TclThreadManager destroy " + id_string + " }"); 283 284 // Redefine some native functions 285 bundle->interpreter_->eval("rename while ::tcl::while"); 286 bundle->interpreter_->eval("rename ::orxonox::while while"); 287 bundle->interpreter_->eval("rename for ::tcl::for"); 288 bundle->interpreter_->eval("rename ::orxonox::for for"); 289 } 290 catch (const Tcl::tcl_error& e) 291 { bundle->interpreter_ = 0; COUT(1) << "Tcl error while creating Tcl-interpreter (" << id_string << "): " << e.what() << std::endl; } 292 catch (const std::exception& e) 293 { bundle->interpreter_ = 0; COUT(1) << "Error while creating Tcl-interpreter (" << id_string << "): " << e.what() << std::endl; } 294 catch (...) 295 { bundle->interpreter_ = 0; COUT(1) << "An error occurred while creating a new Tcl-interpreter (" << id_string << ")" << std::endl; } 290 296 } 291 297 … … 403 409 { 404 410 // This query would lead to a deadlock - return with an error 405 this->error("Error: Circular query (" + this->dumpList(source_bundle->queriers_.getList()) + " " + getConvertedValue<unsigned int, std::string>(source_bundle->id_) \411 TclThreadManager::error("Error: Circular query (" + this->dumpList(source_bundle->queriers_.getList()) + " " + getConvertedValue<unsigned int, std::string>(source_bundle->id_) \ 406 412 + " -> " + getConvertedValue<unsigned int, std::string>(target_bundle->id_) \ 407 413 + "), couldn't query Tcl-interpreter with ID " + getConvertedValue<unsigned int, std::string>(target_bundle->id_) \ … … 439 445 { 440 446 // It's a query to the CommandExecutor 441 this->debug("TclThread_query -> CE: " + command);447 TclThreadManager::debug("TclThread_query -> CE: " + command); 442 448 if (!CommandExecutor::execute(command, false)) 443 this->error("Error: Can't execute command \"" + command + "\"!");449 TclThreadManager::error("Error: Can't execute command \"" + command + "\"!"); 444 450 445 451 if (CommandExecutor::getLastEvaluation().hasReturnvalue()) … … 449 455 { 450 456 // It's a query to a Tcl interpreter 451 this->debug("TclThread_query: " + command);452 453 output = this->eval(target_bundle, command);457 TclThreadManager::debug("TclThread_query: " + command); 458 459 output = TclThreadManager::eval(target_bundle, command, "query"); 454 460 } 455 461 … … 468 474 // This happens if the main thread tries to query a busy interpreter 469 475 // To avoid a lock of the main thread, we simply don't proceed with the query in this case 470 this->error("Error: Couldn't query Tcl-interpreter with ID " + getConvertedValue<unsigned int, std::string>(target_bundle->id_) + ", interpreter is busy right now.");476 TclThreadManager::error("Error: Couldn't query Tcl-interpreter with ID " + getConvertedValue<unsigned int, std::string>(target_bundle->id_) + ", interpreter is busy right now."); 471 477 } 472 478 } … … 475 481 476 482 return output; 483 } 484 485 /** 486 @brief Creates a non-interactive Tcl-interpreter which executes a file. 487 */ 488 void TclThreadManager::source(const std::string& file) 489 { 490 boost::thread(boost::bind(&sourceThread, file)); 477 491 } 478 492 … … 506 520 else 507 521 { 508 this->error("Error: No Tcl-interpreter with ID " + getConvertedValue<unsigned int, std::string>(id) + " existing.");522 TclThreadManager::error("Error: No Tcl-interpreter with ID " + getConvertedValue<unsigned int, std::string>(id) + " existing."); 509 523 return 0; 510 524 } … … 548 562 void TclThreadManager::error(const std::string& error) 549 563 { 550 this->messageQueue_->push_back("error " + error);564 TclThreadManager::getInstance().messageQueue_->push_back("error " + error); 551 565 } 552 566 … … 556 570 void TclThreadManager::debug(const std::string& error) 557 571 { 558 this->messageQueue_->push_back("debug " + error);572 TclThreadManager::getInstance().messageQueue_->push_back("debug " + error); 559 573 } 560 574 … … 565 579 Errors are reported through the @ref error function. 566 580 */ 567 std::string TclThreadManager::eval(TclInterpreterBundle* bundle, const std::string& command )581 std::string TclThreadManager::eval(TclInterpreterBundle* bundle, const std::string& command, const std::string& action) 568 582 { 569 583 Tcl_Interp* interpreter = bundle->interpreter_->get(); … … 574 588 if (cc != TCL_OK) 575 589 { 576 this->error("Tcl error (execute, ID " + getConvertedValue<unsigned int, std::string>(bundle->id_) + "): " + static_cast<std::string>(result));590 TclThreadManager::error("Tcl error (" + action + ", ID " + getConvertedValue<unsigned int, std::string>(bundle->id_) + "): " + static_cast<std::string>(result)); 577 591 return ""; 578 592 } … … 594 608 void tclThread(TclInterpreterBundle* bundle, std::string command) 595 609 { 596 TclThreadManager:: getInstance().debug("TclThread_execute: " + command);597 598 TclThreadManager:: getInstance().eval(bundle, command);610 TclThreadManager::debug("TclThread_execute: " + command); 611 612 TclThreadManager::eval(bundle, command, "execute"); 599 613 600 614 bundle->lock_->unlock(); 601 615 } 616 617 /** 618 @brief The main function of a non-interactive source thread. Executes the file. 619 @param file The name of the file that should be executed by the non-interactive interpreter. 620 */ 621 void sourceThread(std::string file) 622 { 623 TclThreadManager::debug("TclThread_source: " + file); 624 625 // Prepare the command-line arguments 626 int argc = 2; 627 char* argv[argc]; 628 argv[0] = "tclthread"; 629 argv[1] = const_cast<char*>(file.c_str()); 630 631 // Start the Tcl-command Tcl_Main with the Tcl_OrxonoxAppInit hook 632 Tcl_Main(argc, argv, Tcl_OrxonoxAppInit); 633 634 // Tcl::object object(file); 635 // int cc = Tcl_FSEvalFile(bundle->interpreter_->get(), object.get_object()); 636 // Tcl::details::result result(bundle->interpreter_->get()); 637 // if (cc != TCL_OK) 638 // TclThreadManager::error("Tcl error (source, ID " + getConvertedValue<unsigned int, std::string>(bundle->id_) + "): " + static_cast<std::string>(result)); 639 // 640 // // Unlock the mutex 641 // bundle->lock_->unlock(); 642 } 643 644 /** 645 @brief A tcl-init hook to inject the non-interactive Tcl-interpreter into the TclThreadManager. 646 */ 647 int Tcl_OrxonoxAppInit(Tcl_Interp* interp) 648 { 649 // Create a new interpreter bundle 650 unsigned int id = TclThreadManager::create(); 651 TclInterpreterBundle* bundle = TclThreadManager::getInstance().getInterpreterBundle(id); 652 653 // Replace the default interpreter in the bundle with the non-interactive one (passed as an argument to this function) 654 if (bundle->interpreter_) 655 delete bundle->interpreter_; 656 bundle->interpreter_ = new Tcl::interpreter(interp, true); 657 658 // Initialize the non-interactive interpreter (like in @ref TclBind::createTclInterpreter but exception safe) 659 std::string libpath = TclBind::getTclLibraryPath(); 660 if (libpath != "") 661 TclThreadManager::eval(bundle, "set tcl_library \"" + libpath + "\"", "source"); 662 int cc = Tcl_Init(interp); 663 TclThreadManager::eval(bundle, "source \"" + TclBind::getInstance().getTclDataPath() + "/init.tcl\"", "source"); 664 665 // Initialize the non-interactive interpreter also with the thread-specific stuff 666 TclThreadManager::initialize(bundle); 667 668 // Lock the mutex (this will be locked until the thread finishes - no chance to interact with the interpreter) 669 bundle->lock_->lock(); 670 671 // Return to Tcl_Main 672 if (!bundle->interpreter_) 673 return TCL_ERROR; 674 else 675 return cc; 676 } 602 677 }
Note: See TracChangeset
for help on using the changeset viewer.