#ifndef COMPONENT_THREAD_H #define COMPONENT_THREAD_H #include #include #include #include #include #include #include #include #include #include #include #include #include namespace smo { class Mind; // Forward declaration class MarionetteThread; class MindThread; class ComponentThread { public: enum ThreadId { MRNTT = 0, DIRECTOR, SIMULATOR, SUBCONSCIOUS, BODY, WORLD, N_ITEMS }; protected: ComponentThread(ThreadId _id) : id(_id), name(getThreadName(_id)), work(io_service) {} public: virtual ~ComponentThread() = default; void cleanup(void); boost::asio::io_service& getIoService(void) { return io_service; } static const std::shared_ptr getSelf(void); static std::shared_ptr getMrntt(); typedef void (mainFn)(ComponentThread &self); // CPU management methods static int getAvailableCpuCount(); 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; boost::asio::io_service io_service; boost::asio::io_service::work work; std::atomic keepLooping; 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]; } }; class MarionetteThread : public std::enable_shared_from_this, public ComponentThread { public: MarionetteThread() : ComponentThread(MRNTT), thread(main, std::ref(*this)) { } static void main(MarionetteThread& self); void initializeTls(void); public: std::thread thread; }; class MindThread : public std::enable_shared_from_this, public ComponentThread { public: enum class ThreadOp { START, PAUSE, RESUME, EXIT, JOLT, N_ITEMS }; MindThread(ThreadId _id, Mind& parent) : ComponentThread(_id), pinnedCpuId(-1), pause_work(pause_io_service), parent(parent), thread(main, std::ref(*this)) { } static void main(MindThread& self); void initializeTls(void); Mind& getParent() const { return parent; } // Thread management methods typedef std::function threadLifetimeMgmtOpCbFn; void startThreadReq(Callback callback); void exitThreadReq(Callback callback); void pauseThreadReq(Callback callback); void resumeThreadReq(Callback 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(Callback callback); // CPU management methods void pinToCpu(int cpuId); public: int pinnedCpuId; boost::asio::io_service pause_io_service; boost::asio::io_service::work pause_work; Mind& parent; std::thread thread; public: class ThreadLifetimeMgmtOp; class MindShutdownIndOp; }; namespace mrntt { extern std::shared_ptr thread; } // namespace mrntt } // namespace smo #endif // COMPONENT_THREAD_H