0dc8abaa28
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.
136 lines
3.0 KiB
C++
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
|