2015-10-28 15:00:24 +01:00
|
|
|
#include "LoopThreadForkHandler.h"
|
|
|
|
#include <thread>
|
|
|
|
#include "../logging/logging.h"
|
|
|
|
#include "../assert/assert.h"
|
|
|
|
#include "LoopThread.h"
|
|
|
|
|
|
|
|
using namespace cpputils::logging;
|
|
|
|
|
|
|
|
namespace cpputils {
|
|
|
|
LoopThreadForkHandler &LoopThreadForkHandler::singleton() {
|
|
|
|
static LoopThreadForkHandler singleton;
|
|
|
|
return singleton;
|
|
|
|
}
|
|
|
|
|
|
|
|
LoopThreadForkHandler::LoopThreadForkHandler() {
|
2015-10-28 15:18:28 +01:00
|
|
|
//Stopping the thread before fork() (and then also restarting it in the parent thread after fork()) is important,
|
|
|
|
//because as a running thread it might hold locks or condition variables that won't play well when forked.
|
|
|
|
pthread_atfork(&LoopThreadForkHandler::_onBeforeFork, &LoopThreadForkHandler::_onAfterFork, &LoopThreadForkHandler::_onAfterFork);
|
2015-10-28 15:00:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void LoopThreadForkHandler::add(LoopThread *thread) {
|
|
|
|
_runningThreads.push_back(thread);
|
|
|
|
}
|
|
|
|
|
|
|
|
void LoopThreadForkHandler::remove(LoopThread *thread) {
|
|
|
|
auto found = std::find(_runningThreads.begin(), _runningThreads.end(), thread);
|
|
|
|
ASSERT(found != _runningThreads.end(), "Thread not found");
|
|
|
|
_runningThreads.erase(found);
|
|
|
|
}
|
|
|
|
|
|
|
|
void LoopThreadForkHandler::_onBeforeFork() {
|
|
|
|
singleton()._stopThreads();
|
|
|
|
}
|
|
|
|
|
|
|
|
void LoopThreadForkHandler::_stopThreads() {
|
|
|
|
for (LoopThread *thread : _runningThreads) {
|
|
|
|
thread->asyncStop();
|
|
|
|
}
|
|
|
|
for (LoopThread *thread : _runningThreads) {
|
|
|
|
thread->waitUntilStopped();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void LoopThreadForkHandler::_onAfterFork() {
|
|
|
|
singleton()._startThreads();
|
|
|
|
}
|
|
|
|
|
|
|
|
void LoopThreadForkHandler::_startThreads() {
|
|
|
|
for (LoopThread *thread : _runningThreads) {
|
|
|
|
thread->start();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|