[Orxonox-commit 848] r3360 - in branches/resource/src: core cpptcl
landauf at orxonox.net
landauf at orxonox.net
Tue Jul 28 17:04:38 CEST 2009
Author: landauf
Date: 2009-07-28 17:04:38 +0200 (Tue, 28 Jul 2009)
New Revision: 3360
Modified:
branches/resource/src/core/TclBind.cc
branches/resource/src/core/TclBind.h
branches/resource/src/core/TclThreadManager.cc
branches/resource/src/core/TclThreadManager.h
branches/resource/src/cpptcl/changes_orxonox.diff
branches/resource/src/cpptcl/cpptcl.cc
branches/resource/src/cpptcl/cpptcl.h
Log:
- bugfix in TclBind: Tcl_Init was only called if the constructor of Tcl::interpreter was called with a library path. The initialization is now moved from cpptcl to TclBind.
- added a new command: TclThreadManager source <file>. This creates a non-interactive tcl-interpreter which executes a file. This allows for example to run the telnet_server.tcl script without a thread compatible tcl library. Warning: experimental state. A script-exit terminates Orxonox.
- Several small changes in TclThreadManager
Modified: branches/resource/src/core/TclBind.cc
===================================================================
--- branches/resource/src/core/TclBind.cc 2009-07-27 21:18:17 UTC (rev 3359)
+++ branches/resource/src/core/TclBind.cc 2009-07-28 15:04:38 UTC (rev 3360)
@@ -103,29 +103,40 @@
Tcl::interpreter* TclBind::createTclInterpreter()
{
- Tcl::interpreter* interpreter;
-#ifdef DEPENDENCY_PACKAGE_ENABLE
- if (Core::isDevelopmentRun())
- interpreter = new Tcl::interpreter(std::string(ORXONOX_DEP_LIB_PATH) + "/tcl");
- else
- interpreter = new Tcl::interpreter(Core::getRootPathString() + "lib/tcl");
-#else
- interpreter = new Tcl::interpreter();
-#endif
+ Tcl::interpreter* interpreter = new Tcl::interpreter();
+ std::string libpath = TclBind::getTclLibraryPath();
+
try
{
+ if (libpath != "")
+ interpreter->eval("set tcl_library \"" + libpath + "\"");
+
+ Tcl_Init(interpreter->get());
+
interpreter->eval("source \"" + TclBind::getInstance().tclDataPath_ + "/init.tcl\"");
}
catch (Tcl::tcl_error const &e)
- { COUT(1) << "Tcl error while creating Tcl-interpreter: " << e.what() << std::endl; }
+ { COUT(1) << "Tcl error while creating Tcl-interpreter: " << e.what() << std::endl; COUT(1) << "Error: Tcl isn't properly initialized. Orxonox might possibly not work like that." << std::endl; }
catch (std::exception const &e)
- { COUT(1) << "Error while creating Tcl-interpreter: " << e.what() << std::endl; }
+ { COUT(1) << "Error while creating Tcl-interpreter: " << e.what() << std::endl; COUT(1) << "Error: Tcl isn't properly initialized. Orxonox might possibly not work like that." << std::endl; }
catch (...)
- { COUT(1) << "Error while creating Tcl-interpreter." << std::endl; }
+ { COUT(1) << "Error while creating Tcl-interpreter." << std::endl; COUT(1) << "Error: Tcl isn't properly initialized. Orxonox might possibly not work like that." << std::endl; }
return interpreter;
}
+ std::string TclBind::getTclLibraryPath()
+ {
+#ifdef DEPENDENCY_PACKAGE_ENABLE
+ if (Core::isDevelopmentRun())
+ return (std::string(ORXONOX_DEP_LIB_PATH) + "/tcl");
+ else
+ return (Core::getRootPathString() + "lib/tcl");
+#else
+ return "";
+#endif
+ }
+
std::string TclBind::tcl_query(Tcl::object const &args)
{
COUT(4) << "Tcl_query: " << args.get() << std::endl;
Modified: branches/resource/src/core/TclBind.h
===================================================================
--- branches/resource/src/core/TclBind.h 2009-07-27 21:18:17 UTC (rev 3359)
+++ branches/resource/src/core/TclBind.h 2009-07-28 15:04:38 UTC (rev 3360)
@@ -49,6 +49,8 @@
void setDataPath(const std::string& datapath);
const std::string& getTclDataPath() const { return this->tclDataPath_; }
+ static std::string getTclLibraryPath();
+
void initializeTclInterpreter();
static Tcl::interpreter* createTclInterpreter();
Tcl::interpreter* getTclInterpreter() const { return this->interpreter_; }
Modified: branches/resource/src/core/TclThreadManager.cc
===================================================================
--- branches/resource/src/core/TclThreadManager.cc 2009-07-27 21:18:17 UTC (rev 3359)
+++ branches/resource/src/core/TclThreadManager.cc 2009-07-28 15:04:38 UTC (rev 3360)
@@ -53,6 +53,7 @@
SetConsoleCommand(TclThreadManager, destroy, false).argumentCompleter(0, autocompletion::tclthreads());
SetConsoleCommand(TclThreadManager, execute, false).argumentCompleter(0, autocompletion::tclthreads());
SetConsoleCommand(TclThreadManager, query, false).argumentCompleter(0, autocompletion::tclthreads());
+ SetConsoleCommand(TclThreadManager, source, false).argumentCompleter(0, autocompletion::tclthreads());
/**
@brief A struct containing all informations about a Tcl-interpreter
@@ -241,52 +242,57 @@
newbundle->id_ = id;
newbundle->interpreter_ = TclBind::createTclInterpreter();
+ TclThreadManager::initialize(newbundle);
+
+ {
+ // Add the new bundle to the map
+ boost::unique_lock<boost::shared_mutex> lock(*TclThreadManager::getInstance().interpreterBundlesMutex_);
+ TclThreadManager::getInstance().interpreterBundles_[id] = newbundle;
+ }
+
+ return newbundle->interpreter_;
+ }
+
+ void TclThreadManager::initialize(TclInterpreterBundle* bundle)
+ {
+ std::string id_string = getConvertedValue<unsigned int, std::string>(bundle->id_);
+
// Initialize the new interpreter
try
{
- std::string id_string = getConvertedValue<unsigned int, std::string>(id);
-
// Define the functions which are implemented in C++
- newbundle->interpreter_->def("::orxonox::execute", TclThreadManager::tcl_execute, Tcl::variadic());
- newbundle->interpreter_->def("::orxonox::crossexecute", TclThreadManager::tcl_crossexecute, Tcl::variadic());
- newbundle->interpreter_->def("::orxonox::query", TclThreadManager::tcl_query, Tcl::variadic());
- newbundle->interpreter_->def("::orxonox::crossquery", TclThreadManager::tcl_crossquery, Tcl::variadic());
- newbundle->interpreter_->def("::orxonox::running", TclThreadManager::tcl_running);
+ bundle->interpreter_->def("::orxonox::execute", TclThreadManager::tcl_execute, Tcl::variadic());
+ bundle->interpreter_->def("::orxonox::crossexecute", TclThreadManager::tcl_crossexecute, Tcl::variadic());
+ bundle->interpreter_->def("::orxonox::query", TclThreadManager::tcl_query, Tcl::variadic());
+ bundle->interpreter_->def("::orxonox::crossquery", TclThreadManager::tcl_crossquery, Tcl::variadic());
+ bundle->interpreter_->def("::orxonox::running", TclThreadManager::tcl_running);
// Create threadspecific shortcuts for the functions above
- newbundle->interpreter_->def("execute", TclThreadManager::tcl_execute, Tcl::variadic());
- newbundle->interpreter_->def("crossexecute", TclThreadManager::tcl_crossexecute, Tcl::variadic());
- newbundle->interpreter_->eval("proc query {args} { ::orxonox::query " + id_string + " $args }");
- newbundle->interpreter_->eval("proc crossquery {id args} { ::orxonox::crossquery " + id_string + " $id $args }");
- newbundle->interpreter_->eval("proc running {} { return [::orxonox::running " + id_string + "] }");
+ bundle->interpreter_->def("execute", TclThreadManager::tcl_execute, Tcl::variadic());
+ bundle->interpreter_->def("crossexecute", TclThreadManager::tcl_crossexecute, Tcl::variadic());
+ bundle->interpreter_->eval("proc query {args} { ::orxonox::query " + id_string + " $args }");
+ bundle->interpreter_->eval("proc crossquery {id args} { ::orxonox::crossquery " + id_string + " $id $args }");
+ bundle->interpreter_->eval("proc running {} { return [::orxonox::running " + id_string + "] }");
// Define a variable containing the thread id
- newbundle->interpreter_->eval("set id " + id_string);
+ bundle->interpreter_->eval("set id " + id_string);
// Use our own exit function to avoid shutting down the whole program instead of just the interpreter
- newbundle->interpreter_->eval("rename exit ::tcl::exit");
- newbundle->interpreter_->eval("proc exit {} { execute TclThreadManager destroy " + id_string + " }");
+ bundle->interpreter_->eval("rename exit ::tcl::exit");
+ bundle->interpreter_->eval("proc exit {} { execute TclThreadManager destroy " + id_string + " }");
// Redefine some native functions
- newbundle->interpreter_->eval("rename while ::tcl::while");
- newbundle->interpreter_->eval("rename ::orxonox::while while");
- newbundle->interpreter_->eval("rename for ::tcl::for");
- newbundle->interpreter_->eval("rename ::orxonox::for for");
+ bundle->interpreter_->eval("rename while ::tcl::while");
+ bundle->interpreter_->eval("rename ::orxonox::while while");
+ bundle->interpreter_->eval("rename for ::tcl::for");
+ bundle->interpreter_->eval("rename ::orxonox::for for");
}
catch (const Tcl::tcl_error& e)
- { newbundle->interpreter_ = 0; COUT(1) << "Tcl error while creating Tcl-interpreter (" << id << "): " << e.what() << std::endl; }
+ { bundle->interpreter_ = 0; COUT(1) << "Tcl error while creating Tcl-interpreter (" << id_string << "): " << e.what() << std::endl; }
catch (const std::exception& e)
- { newbundle->interpreter_ = 0; COUT(1) << "Error while creating Tcl-interpreter (" << id << "): " << e.what() << std::endl; }
+ { bundle->interpreter_ = 0; COUT(1) << "Error while creating Tcl-interpreter (" << id_string << "): " << e.what() << std::endl; }
catch (...)
- { newbundle->interpreter_ = 0; COUT(1) << "An error occurred while creating a new Tcl-interpreter (" << id << ")" << std::endl; }
-
- {
- // Add the new bundle to the map
- boost::unique_lock<boost::shared_mutex> lock(*TclThreadManager::getInstance().interpreterBundlesMutex_);
- TclThreadManager::getInstance().interpreterBundles_[id] = newbundle;
- }
-
- return newbundle->interpreter_;
+ { bundle->interpreter_ = 0; COUT(1) << "An error occurred while creating a new Tcl-interpreter (" << id_string << ")" << std::endl; }
}
/**
@@ -402,7 +408,7 @@
if ((source_bundle->id_ == target_bundle->id_) || source_bundle->queriers_.is_in(target_bundle->id_))
{
// This query would lead to a deadlock - return with an error
- this->error("Error: Circular query (" + this->dumpList(source_bundle->queriers_.getList()) + " " + getConvertedValue<unsigned int, std::string>(source_bundle->id_) \
+ TclThreadManager::error("Error: Circular query (" + this->dumpList(source_bundle->queriers_.getList()) + " " + getConvertedValue<unsigned int, std::string>(source_bundle->id_) \
+ " -> " + getConvertedValue<unsigned int, std::string>(target_bundle->id_) \
+ "), couldn't query Tcl-interpreter with ID " + getConvertedValue<unsigned int, std::string>(target_bundle->id_) \
+ " from other interpreter with ID " + getConvertedValue<unsigned int, std::string>(source_bundle->id_) + ".");
@@ -438,9 +444,9 @@
if (target_bundle->id_ == 0 && bUseCommandExecutor)
{
// It's a query to the CommandExecutor
- this->debug("TclThread_query -> CE: " + command);
+ TclThreadManager::debug("TclThread_query -> CE: " + command);
if (!CommandExecutor::execute(command, false))
- this->error("Error: Can't execute command \"" + command + "\"!");
+ TclThreadManager::error("Error: Can't execute command \"" + command + "\"!");
if (CommandExecutor::getLastEvaluation().hasReturnvalue())
output = CommandExecutor::getLastEvaluation().getReturnvalue().getString();
@@ -448,9 +454,9 @@
else
{
// It's a query to a Tcl interpreter
- this->debug("TclThread_query: " + command);
+ TclThreadManager::debug("TclThread_query: " + command);
- output = this->eval(target_bundle, command);
+ output = TclThreadManager::eval(target_bundle, command, "query");
}
// Clear the queriers list of the target
@@ -467,7 +473,7 @@
{
// This happens if the main thread tries to query a busy interpreter
// To avoid a lock of the main thread, we simply don't proceed with the query in this case
- this->error("Error: Couldn't query Tcl-interpreter with ID " + getConvertedValue<unsigned int, std::string>(target_bundle->id_) + ", interpreter is busy right now.");
+ TclThreadManager::error("Error: Couldn't query Tcl-interpreter with ID " + getConvertedValue<unsigned int, std::string>(target_bundle->id_) + ", interpreter is busy right now.");
}
}
@@ -477,6 +483,14 @@
}
/**
+ @brief Creates a non-interactive Tcl-interpreter which executes a file.
+ */
+ void TclThreadManager::source(const std::string& file)
+ {
+ boost::thread(boost::bind(&sourceThread, file));
+ }
+
+ /**
@brief This function can be called from Tcl to ask if the thread is still suposed to be running.
@param id The id of the thread in question
*/
@@ -505,7 +519,7 @@
}
else
{
- this->error("Error: No Tcl-interpreter with ID " + getConvertedValue<unsigned int, std::string>(id) + " existing.");
+ TclThreadManager::error("Error: No Tcl-interpreter with ID " + getConvertedValue<unsigned int, std::string>(id) + " existing.");
return 0;
}
}
@@ -547,7 +561,7 @@
*/
void TclThreadManager::error(const std::string& error)
{
- this->messageQueue_->push_back("error " + error);
+ TclThreadManager::getInstance().messageQueue_->push_back("error " + error);
}
/**
@@ -555,7 +569,7 @@
*/
void TclThreadManager::debug(const std::string& error)
{
- this->messageQueue_->push_back("debug " + error);
+ TclThreadManager::getInstance().messageQueue_->push_back("debug " + error);
}
/**
@@ -564,7 +578,7 @@
Errors are reported through the @ref error function.
*/
- std::string TclThreadManager::eval(TclInterpreterBundle* bundle, const std::string& command)
+ std::string TclThreadManager::eval(TclInterpreterBundle* bundle, const std::string& command, const std::string& action)
{
Tcl_Interp* interpreter = bundle->interpreter_->get();
int cc = Tcl_Eval(interpreter, command.c_str());
@@ -573,7 +587,7 @@
if (cc != TCL_OK)
{
- this->error("Tcl error (execute, ID " + getConvertedValue<unsigned int, std::string>(bundle->id_) + "): " + static_cast<std::string>(result));
+ TclThreadManager::error("Tcl error (" + action + ", ID " + getConvertedValue<unsigned int, std::string>(bundle->id_) + "): " + static_cast<std::string>(result));
return "";
}
else
@@ -593,10 +607,71 @@
*/
void tclThread(TclInterpreterBundle* bundle, std::string command)
{
- TclThreadManager::getInstance().debug("TclThread_execute: " + command);
+ TclThreadManager::debug("TclThread_execute: " + command);
- TclThreadManager::getInstance().eval(bundle, command);
+ TclThreadManager::eval(bundle, command, "execute");
bundle->lock_->unlock();
}
+
+ /**
+ @brief The main function of a non-interactive source thread. Executes the file.
+ @param file The name of the file that should be executed by the non-interactive interpreter.
+ */
+ void sourceThread(std::string file)
+ {
+ TclThreadManager::debug("TclThread_source: " + file);
+
+ // Prepare the command-line arguments
+ int argc = 2;
+ char* argv[argc];
+ argv[0] = "tclthread";
+ argv[1] = const_cast<char*>(file.c_str());
+
+ // Start the Tcl-command Tcl_Main with the Tcl_OrxonoxAppInit hook
+ Tcl_Main(argc, argv, Tcl_OrxonoxAppInit);
+
+// Tcl::object object(file);
+// int cc = Tcl_FSEvalFile(bundle->interpreter_->get(), object.get_object());
+// Tcl::details::result result(bundle->interpreter_->get());
+// if (cc != TCL_OK)
+// TclThreadManager::error("Tcl error (source, ID " + getConvertedValue<unsigned int, std::string>(bundle->id_) + "): " + static_cast<std::string>(result));
+//
+// // Unlock the mutex
+// bundle->lock_->unlock();
+ }
+
+ /**
+ @brief A tcl-init hook to inject the non-interactive Tcl-interpreter into the TclThreadManager.
+ */
+ int Tcl_OrxonoxAppInit(Tcl_Interp* interp)
+ {
+ // Create a new interpreter bundle
+ unsigned int id = TclThreadManager::create();
+ TclInterpreterBundle* bundle = TclThreadManager::getInstance().getInterpreterBundle(id);
+
+ // Replace the default interpreter in the bundle with the non-interactive one (passed as an argument to this function)
+ if (bundle->interpreter_)
+ delete bundle->interpreter_;
+ bundle->interpreter_ = new Tcl::interpreter(interp, true);
+
+ // Initialize the non-interactive interpreter (like in @ref TclBind::createTclInterpreter but exception safe)
+ std::string libpath = TclBind::getTclLibraryPath();
+ if (libpath != "")
+ TclThreadManager::eval(bundle, "set tcl_library \"" + libpath + "\"", "source");
+ int cc = Tcl_Init(interp);
+ TclThreadManager::eval(bundle, "source \"" + TclBind::getInstance().getTclDataPath() + "/init.tcl\"", "source");
+
+ // Initialize the non-interactive interpreter also with the thread-specific stuff
+ TclThreadManager::initialize(bundle);
+
+ // Lock the mutex (this will be locked until the thread finishes - no chance to interact with the interpreter)
+ bundle->lock_->lock();
+
+ // Return to Tcl_Main
+ if (!bundle->interpreter_)
+ return TCL_ERROR;
+ else
+ return cc;
+ }
}
Modified: branches/resource/src/core/TclThreadManager.h
===================================================================
--- branches/resource/src/core/TclThreadManager.h 2009-07-27 21:18:17 UTC (rev 3359)
+++ branches/resource/src/core/TclThreadManager.h 2009-07-28 15:04:38 UTC (rev 3360)
@@ -38,12 +38,16 @@
#include "OrxonoxClass.h"
+class Tcl_Interp;
+
namespace orxonox
{
class _CoreExport TclThreadManager : public OrxonoxClass
{
friend class TclBind;
friend _CoreExport void tclThread(TclInterpreterBundle* bundle, std::string command);
+ friend _CoreExport void sourceThread(std::string file);
+ friend _CoreExport int Tcl_OrxonoxAppInit(Tcl_Interp* interp);
public:
TclThreadManager(Tcl::interpreter* interpreter);
@@ -56,9 +60,10 @@
static void destroy(unsigned int id);
static void execute(unsigned int target_id, const std::string& command);
static std::string query(unsigned int target_id, const std::string& command);
+ static void source(const std::string& file);
- void error(const std::string& error);
- void debug(const std::string& error);
+ static void error(const std::string& error);
+ static void debug(const std::string& error);
void update(const Clock& time);
@@ -77,7 +82,8 @@
TclInterpreterBundle* getInterpreterBundle(unsigned int id);
std::string dumpList(const std::list<unsigned int>& list);
- std::string eval(TclInterpreterBundle* bundle, const std::string& command);
+ static void initialize(TclInterpreterBundle* bundle);
+ static std::string eval(TclInterpreterBundle* bundle, const std::string& command, const std::string& action);
static TclThreadManager* singletonPtr_s; ///< Singleton pointer
@@ -89,6 +95,8 @@
};
_CoreExport void tclThread(TclInterpreterBundle* bundle, std::string command);
+ _CoreExport void sourceThread(std::string file);
+ _CoreExport int Tcl_OrxonoxAppInit(Tcl_Interp* interp);
}
#endif /* _TclThreadManager_H__ */
Modified: branches/resource/src/cpptcl/changes_orxonox.diff
===================================================================
--- branches/resource/src/cpptcl/changes_orxonox.diff 2009-07-27 21:18:17 UTC (rev 3359)
+++ branches/resource/src/cpptcl/changes_orxonox.diff 2009-07-28 15:04:38 UTC (rev 3360)
@@ -27,32 +27,3 @@
{
Tcl_SetResult(interp, const_cast<char*>(e.what()), TCL_VOLATILE);
return TCL_ERROR;
-@@ -858,6 +858,18 @@
- owner_ = true;
- }
-
-+interpreter::interpreter(string const &libpath)
-+{
-+ interp_ = Tcl_CreateInterp();
-+ owner_ = true;
-+
-+ try
-+ {
-+ this->eval("set tcl_library \"" + libpath + "\"");
-+ Tcl_Init(this->interp_);
-+ } catch (...) {}
-+}
-+
- interpreter::interpreter(Tcl_Interp *interp, bool owner)
- {
- interp_ = interp;
---- cpptcl.h Wed Jan 28 20:56:11 2009
-+++ cpptcl.h Sat Jan 24 12:52:54 2009
-@@ -467,6 +467,7 @@
- {
- public:
- interpreter();
-+ interpreter(std::string const &libpath);
- interpreter(Tcl_Interp *, bool owner = true);
- ~interpreter();
-
Modified: branches/resource/src/cpptcl/cpptcl.cc
===================================================================
--- branches/resource/src/cpptcl/cpptcl.cc 2009-07-27 21:18:17 UTC (rev 3359)
+++ branches/resource/src/cpptcl/cpptcl.cc 2009-07-28 15:04:38 UTC (rev 3360)
@@ -858,18 +858,6 @@
owner_ = true;
}
-interpreter::interpreter(string const &libpath)
-{
- interp_ = Tcl_CreateInterp();
- owner_ = true;
-
- try
- {
- this->eval("set tcl_library \"" + libpath + "\"");
- Tcl_Init(this->interp_);
- } catch (...) {}
-}
-
interpreter::interpreter(Tcl_Interp *interp, bool owner)
{
interp_ = interp;
Modified: branches/resource/src/cpptcl/cpptcl.h
===================================================================
--- branches/resource/src/cpptcl/cpptcl.h 2009-07-27 21:18:17 UTC (rev 3359)
+++ branches/resource/src/cpptcl/cpptcl.h 2009-07-28 15:04:38 UTC (rev 3360)
@@ -467,7 +467,6 @@
{
public:
interpreter();
- interpreter(std::string const &libpath);
interpreter(Tcl_Interp *, bool owner = true);
~interpreter();
More information about the Orxonox-commit
mailing list