Files
salmanoff/smocore/include/componentThread.h
T
hayodea 0dc8abaa28 Rework: Modularize Mind
Now we have modularized the Mind class to contain all of its
ComponentThreads. This enables us to run multiple mind instances
within the same SMO process, at least in theory.

We probably won't actually do this, but we want to ensure that the
design is clean enough to enable it.
2025-09-03 14:56:00 -04:00

136 lines
3.0 KiB
C++

#ifndef COMPONENT_THREAD_H
#define COMPONENT_THREAD_H
#include <atomic>
#include <thread>
#include <unordered_map>
#include <boost/asio.hpp>
#include <stdexcept>
#include <queue>
#include <functional>
#include <pthread.h>
#include <sched.h>
#include <unistd.h>
#include <memory>
namespace smo {
class Mind; // Forward declaration
class ComponentThread
: public std::enable_shared_from_this<ComponentThread>
{
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<ComponentThread> getSelf(void);
static std::shared_ptr<ComponentThread> getMrntt();
Mind& getParent() const { return parent; }
typedef void (mainFn)(ComponentThread &self);
static mainFn main, marionetteMain;
// Thread management methods
void startThreadReq(std::function<void()> callback = nullptr);
void exitThreadReq(std::function<void()> callback = nullptr);
void pauseThreadReq(std::function<void()> callback = nullptr);
void resumeThreadReq(std::function<void()> callback = nullptr);
/**
* 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(std::function<void()> callback = nullptr);
// CPU management methods
static int getAvailableCpuCount();
void pinToCpu(int cpuId);
enum class ThreadOp
{
START,
PAUSE,
RESUME,
EXIT,
JOLT,
N_ITEMS
};
// Intentionally doesn't take a callback.
void exceptionInd(ComponentThread& thread);
// 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<bool> 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];
}
};
namespace mrntt {
extern std::shared_ptr<ComponentThread> mrntt;
}
} // namespace smo
#endif // COMPONENT_THREAD_H