#ifndef COMPONENT_THREAD_H #define COMPONENT_THREAD_H #include #include #include #include #include #include #include #include #include #include #include namespace smo { class Mind; // Forward declaration class ComponentThread : public std::enable_shared_from_this { public: enum ThreadId { MRNTT = 0, DIRECTOR, SIMULATOR, SUBCONSCIOUS, BODY, WORLD, N_ITEMS }; ComponentThread(ThreadId _id, Mind& parent) : id(_id), name(getThreadName(_id)), parent(parent), work(io_service), pause_work(pause_io_service), pinnedCpuId(-1), thread( ((id == MRNTT) ? marionetteMain : main), std::ref(*this)) {} void cleanup(void); boost::asio::io_service& getIoService(void) { return io_service; } void initializeTls(void); static const std::shared_ptr getSelf(void); static std::shared_ptr getMrntt(); Mind& getParent() const { return parent; } typedef void (mainFn)(ComponentThread &self); static mainFn main, marionetteMain; typedef std::function threadLifetimeMgmtOpCbFn; // Thread management methods void startThreadReq(threadLifetimeMgmtOpCbFn callback); void exitThreadReq(threadLifetimeMgmtOpCbFn callback); void pauseThreadReq(threadLifetimeMgmtOpCbFn callback); void resumeThreadReq(threadLifetimeMgmtOpCbFn callback); /** * JOLTs this thread to begin processing after global initialization. * * JOLTing is the mechanism that allows threads to enter their main * event loops and set up TLS vars after all global constructors have * completed. This prevents race conditions during system startup. */ void joltThreadReq(threadLifetimeMgmtOpCbFn callback); // CPU management methods static int getAvailableCpuCount(); void pinToCpu(int cpuId); enum class ThreadOp { START, PAUSE, RESUME, EXIT, JOLT, N_ITEMS }; typedef std::function mindShutdownIndOpCbFn; // Intentionally doesn't take a callback. void exceptionInd(const std::shared_ptr &faultyThread); // Intentionally doesn't take a callback. void userShutdownInd(); public: ThreadId id; std::string name; Mind &parent; boost::asio::io_service io_service; boost::asio::io_service::work work; boost::asio::io_service pause_io_service; boost::asio::io_service::work pause_work; std::atomic keepLooping; int pinnedCpuId; /* Always ensure that this is last so that the thread is spawned after * everything else is constructed. */ std::thread thread; static const std::string getThreadName(ThreadId id) { if (id < 0 || id >= ComponentThread::N_ITEMS) { throw std::runtime_error(std::string(__func__) + ": Invalid thread ID"); } // Use function-local static to ensure proper initialization order static const std::string threadNames[N_ITEMS] = { "mrntt", "director", "simulator", "subconscious", "body", "world" }; return threadNames[id]; } private: class ThreadLifetimeMgmtOp; class MindShutdownIndOp; }; namespace mrntt { extern std::shared_ptr mrntt; } } // namespace smo #endif // COMPONENT_THREAD_H