#ifndef __ExecutionContext_h_ #define __ExecutionContext_h_ #include #include "GridFiller.h" /* ExecutionContext contains the data needed to execute our standard commands, * like create a prototype or request data. * * Originally each command took different inputs. But the commands reference * each other, so I put all the common inputs into one place, this class. * * Originally a lot of commands referenced (directly or indirectly) the * ScriptDispatcher. I got rid of that reference in part so you could easily * reuse a command in different types of threads. Also, by removing that * reference, I send a lot less data to each command. Now it's much more * clear which data is actually required. * * I eventually moved a lot of code for the tcl commands from the script * dispatcher into here. That made sense because this had the relevant data. * * The idea is to have one of these per thread / TCL interpreter. These will * reference other data, like the symbol list. The symbol list might change * as different users are accessing the data. But the interpreter should not * change. A pointer to this object might be embedded in a command in a TCL * interpreter, and you don't want that interpreter to be able to reference * another interpreter in a different thread. * * We generally assume an ExecutionContext will be a long lived object. We * store pointers to it in the TCL interpreter. Presumably we we ever destroy * the ExecutionContext, we'll destroy the interpreter first. More likely, * though, neither will go away until the program is terminated. Like a lot * of threads, we don't have any planned shutdown in place. * * This class used to directly include a lot of code for various things, like * the old routines for creating and manipulating prototypes and grids. Newer * TCL functions, including the new way of manipulating prototypes and grids, * are typically written in their own C++ files and classes. ExecutionContext * just makes one call to initialize each of these. */ class ExecutionContext { private: Tcl_Interp *const _interp; GridFiller *const _gridFiller; // Some commands create new commands, and the user can specify the name // of the new command. Tcl_CreateObjCommand() will use exactly the name // you provide. I want to create a command in the current namespace, // consistent with proc. If the suggested name starts with "::" there is // no change. Otherwise, we add the current namespace. std::string getAbsoluteName(std::string const &name); static __thread ExecutionContext *_instance; public: virtual ~ExecutionContext(); ExecutionContext(Tcl_Interp *interp, GridFiller *gridFiller); // There is at most one ExecutionContext per thread. That rule was written // so it would be easier for people to find the ExecutionContext. This will // return NULL if there is no execution context in this thread. That // shouldn't happen. Typically when you create a thread you immediately // create the execution context. Of course, some threads weren't made to be // used this way, and don't have an execution context. // // Not all execution contexts are the same. In particular, see initInterp(). // That's why we don't try to create one the first time someone asks. static ExecutionContext *getInstance() { return _instance; } Tcl_Interp *getInterp() const { return _interp; } GridFiller *getGridFiller() const { return _gridFiller; } Tcl_Command installMainCommand(std::string name = "grids"); void initInterp(std::string const &interpType = ""); // Some commands create new commands, and the user can specify the name // of the new command. Tcl_CreateObjCommand() will use exactly the name // you provide. I want to create a command in the current namespace, // consistent with proc. If the suggested name starts with "::" there is // no change. Otherwise, we add the current namespace. static std::string getAbsoluteName(Tcl_Interp *interp, std::string const &name); }; #endif