91ccd16b33
This makes the initialization sequence much cleaner and conceptually well encapsulated. We also now dynamically allocate the Mind objects. They're allocated dynamically by Mrntt inside of initializeReq. This means that we no longer have to worry about jolting and cleaning up the running threads of global mind object even when we never explicitly called Mind.initializeReq. Along with other conceptual improvements to our abstractions, this patch also gets us to a real "end of program initialization" point for the first time.
176 lines
3.6 KiB
C++
176 lines
3.6 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 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<ComponentThread> getSelf(void);
|
|
static std::shared_ptr<MarionetteThread> getMrntt();
|
|
|
|
typedef void (mainFn)(ComponentThread &self);
|
|
|
|
// CPU management methods
|
|
static int getAvailableCpuCount();
|
|
|
|
typedef std::function<void()> mindShutdownIndOpCbFn;
|
|
// Intentionally doesn't take a callback.
|
|
void exceptionInd(const std::shared_ptr<ComponentThread> &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<bool> 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<MarionetteThread>,
|
|
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<MindThread>, 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<void()> threadLifetimeMgmtOpCbFn;
|
|
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
|
|
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<MarionetteThread> thread;
|
|
} // namespace mrntt
|
|
|
|
} // namespace smo
|
|
|
|
#endif // COMPONENT_THREAD_H
|