mirror of
https://github.com/overte-org/overte.git
synced 2025-08-10 11:13:09 +02:00
Merge pull request #4823 from birarda/master
repairs to AC stop and clean shutdown
This commit is contained in:
commit
866a6fba9b
30 changed files with 369 additions and 281 deletions
|
@ -224,5 +224,7 @@ void Agent::run() {
|
||||||
|
|
||||||
void Agent::aboutToFinish() {
|
void Agent::aboutToFinish() {
|
||||||
_scriptEngine.stop();
|
_scriptEngine.stop();
|
||||||
NetworkAccessManager::getInstance().clearAccessCache();
|
|
||||||
|
// our entity tree is going to go away so tell that to the EntityScriptingInterface
|
||||||
|
DependencyManager::get<EntityScriptingInterface>()->setEntityTree(NULL);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include <QSharedMemory>
|
#include <QSharedMemory>
|
||||||
|
@ -30,22 +32,19 @@
|
||||||
#include <SoundCache.h>
|
#include <SoundCache.h>
|
||||||
|
|
||||||
#include "AssignmentFactory.h"
|
#include "AssignmentFactory.h"
|
||||||
#include "AssignmentThread.h"
|
|
||||||
|
|
||||||
#include "AssignmentClient.h"
|
#include "AssignmentClient.h"
|
||||||
|
|
||||||
const QString ASSIGNMENT_CLIENT_TARGET_NAME = "assignment-client";
|
const QString ASSIGNMENT_CLIENT_TARGET_NAME = "assignment-client";
|
||||||
const long long ASSIGNMENT_REQUEST_INTERVAL_MSECS = 1 * 1000;
|
const long long ASSIGNMENT_REQUEST_INTERVAL_MSECS = 1 * 1000;
|
||||||
|
|
||||||
SharedAssignmentPointer AssignmentClient::_currentAssignment;
|
|
||||||
|
|
||||||
int hifiSockAddrMeta = qRegisterMetaType<HifiSockAddr>("HifiSockAddr");
|
int hifiSockAddrMeta = qRegisterMetaType<HifiSockAddr>("HifiSockAddr");
|
||||||
|
|
||||||
AssignmentClient::AssignmentClient(int ppid, Assignment::Type requestAssignmentType, QString assignmentPool,
|
AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QString assignmentPool,
|
||||||
QUuid walletUUID, QString assignmentServerHostname, quint16 assignmentServerPort) :
|
QUuid walletUUID, QString assignmentServerHostname, quint16 assignmentServerPort,
|
||||||
|
quint16 assignmentMonitorPort) :
|
||||||
_assignmentServerHostname(DEFAULT_ASSIGNMENT_SERVER_HOSTNAME),
|
_assignmentServerHostname(DEFAULT_ASSIGNMENT_SERVER_HOSTNAME),
|
||||||
_localASPortSharedMem(NULL),
|
_localASPortSharedMem(NULL)
|
||||||
_localACMPortSharedMem(NULL)
|
|
||||||
{
|
{
|
||||||
LogUtils::init();
|
LogUtils::init();
|
||||||
|
|
||||||
|
@ -108,19 +107,39 @@ AssignmentClient::AssignmentClient(int ppid, Assignment::Type requestAssignmentT
|
||||||
|
|
||||||
// Create Singleton objects on main thread
|
// Create Singleton objects on main thread
|
||||||
NetworkAccessManager::getInstance();
|
NetworkAccessManager::getInstance();
|
||||||
|
|
||||||
// Hook up a timer to send this child's status to the Monitor once per second
|
// did we get an assignment-client monitor port?
|
||||||
setUpStatsToMonitor(ppid);
|
if (assignmentMonitorPort > 0) {
|
||||||
|
_assignmentClientMonitorSocket = HifiSockAddr(DEFAULT_ASSIGNMENT_CLIENT_MONITOR_HOSTNAME, assignmentMonitorPort);
|
||||||
|
|
||||||
|
qDebug() << "Assignment-client monitor socket is" << _assignmentClientMonitorSocket;
|
||||||
|
|
||||||
|
// Hook up a timer to send this child's status to the Monitor once per second
|
||||||
|
setUpStatsToMonitor();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void AssignmentClient::stopAssignmentClient() {
|
void AssignmentClient::stopAssignmentClient() {
|
||||||
qDebug() << "Exiting.";
|
qDebug() << "Forced stop of assignment-client.";
|
||||||
|
|
||||||
_requestTimer.stop();
|
_requestTimer.stop();
|
||||||
_statsTimerACM.stop();
|
_statsTimerACM.stop();
|
||||||
|
|
||||||
if (_currentAssignment) {
|
if (_currentAssignment) {
|
||||||
_currentAssignment->aboutToQuit();
|
// grab the thread for the current assignment
|
||||||
QThread* currentAssignmentThread = _currentAssignment->thread();
|
QThread* currentAssignmentThread = _currentAssignment->thread();
|
||||||
|
|
||||||
|
// ask the current assignment to stop
|
||||||
|
QMetaObject::invokeMethod(_currentAssignment, "stop", Qt::BlockingQueuedConnection);
|
||||||
|
|
||||||
|
// ask the current assignment to delete itself on its thread
|
||||||
|
_currentAssignment->deleteLater();
|
||||||
|
|
||||||
|
// when this thread is destroyed we don't need to run our assignment complete method
|
||||||
|
disconnect(currentAssignmentThread, &QThread::destroyed, this, &AssignmentClient::assignmentCompleted);
|
||||||
|
|
||||||
|
// wait on the thread from that assignment - it will be gone once the current assignment deletes
|
||||||
currentAssignmentThread->quit();
|
currentAssignmentThread->quit();
|
||||||
currentAssignmentThread->wait();
|
currentAssignmentThread->wait();
|
||||||
}
|
}
|
||||||
|
@ -129,24 +148,13 @@ void AssignmentClient::stopAssignmentClient() {
|
||||||
|
|
||||||
void AssignmentClient::aboutToQuit() {
|
void AssignmentClient::aboutToQuit() {
|
||||||
stopAssignmentClient();
|
stopAssignmentClient();
|
||||||
|
|
||||||
// clear the log handler so that Qt doesn't call the destructor on LogHandler
|
// clear the log handler so that Qt doesn't call the destructor on LogHandler
|
||||||
qInstallMessageHandler(0);
|
qInstallMessageHandler(0);
|
||||||
// clear out pointer to the assignment so the destructor gets called. if we don't do this here,
|
|
||||||
// it will get destroyed along with all the other "static" stuff. various static member variables
|
|
||||||
// will be destroyed first and things go wrong.
|
|
||||||
_currentAssignment.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void AssignmentClient::setUpStatsToMonitor(int ppid) {
|
void AssignmentClient::setUpStatsToMonitor() {
|
||||||
// Figure out the address to send out stats to
|
|
||||||
quint16 localMonitorServerPort = DEFAULT_ASSIGNMENT_CLIENT_MONITOR_PORT;
|
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
|
||||||
|
|
||||||
nodeList->getLocalServerPortFromSharedMemory(QString(ASSIGNMENT_CLIENT_MONITOR_LOCAL_PORT_SMEM_KEY) + "-" +
|
|
||||||
QString::number(ppid), _localACMPortSharedMem, localMonitorServerPort);
|
|
||||||
_assignmentClientMonitorSocket = HifiSockAddr(DEFAULT_ASSIGNMENT_CLIENT_MONITOR_HOSTNAME, localMonitorServerPort, true);
|
|
||||||
|
|
||||||
// send a stats packet every 1 seconds
|
// send a stats packet every 1 seconds
|
||||||
connect(&_statsTimerACM, &QTimer::timeout, this, &AssignmentClient::sendStatsPacketToACM);
|
connect(&_statsTimerACM, &QTimer::timeout, this, &AssignmentClient::sendStatsPacketToACM);
|
||||||
_statsTimerACM.start(1000);
|
_statsTimerACM.start(1000);
|
||||||
|
@ -202,8 +210,11 @@ void AssignmentClient::readPendingDatagrams() {
|
||||||
|
|
||||||
if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
|
if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
|
||||||
if (packetTypeForPacket(receivedPacket) == PacketTypeCreateAssignment) {
|
if (packetTypeForPacket(receivedPacket) == PacketTypeCreateAssignment) {
|
||||||
|
|
||||||
|
qDebug() << "Received a PacketTypeCreateAssignment - attempting to unpack.";
|
||||||
|
|
||||||
// construct the deployed assignment from the packet data
|
// construct the deployed assignment from the packet data
|
||||||
_currentAssignment = SharedAssignmentPointer(AssignmentFactory::unpackAssignment(receivedPacket));
|
_currentAssignment = AssignmentFactory::unpackAssignment(receivedPacket);
|
||||||
|
|
||||||
if (_currentAssignment) {
|
if (_currentAssignment) {
|
||||||
qDebug() << "Received an assignment -" << *_currentAssignment;
|
qDebug() << "Received an assignment -" << *_currentAssignment;
|
||||||
|
@ -216,15 +227,24 @@ void AssignmentClient::readPendingDatagrams() {
|
||||||
qDebug() << "Destination IP for assignment is" << nodeList->getDomainHandler().getIP().toString();
|
qDebug() << "Destination IP for assignment is" << nodeList->getDomainHandler().getIP().toString();
|
||||||
|
|
||||||
// start the deployed assignment
|
// start the deployed assignment
|
||||||
AssignmentThread* workerThread = new AssignmentThread(_currentAssignment, this);
|
QThread* workerThread = new QThread;
|
||||||
workerThread->setObjectName("worker");
|
workerThread->setObjectName("ThreadedAssignment Worker");
|
||||||
|
|
||||||
connect(workerThread, &QThread::started, _currentAssignment.data(), &ThreadedAssignment::run);
|
connect(workerThread, &QThread::started, _currentAssignment.data(), &ThreadedAssignment::run);
|
||||||
connect(_currentAssignment.data(), &ThreadedAssignment::finished, workerThread, &QThread::quit);
|
|
||||||
connect(_currentAssignment.data(), &ThreadedAssignment::finished,
|
// once the ThreadedAssignment says it is finished - we ask it to deleteLater
|
||||||
this, &AssignmentClient::assignmentCompleted);
|
connect(_currentAssignment.data(), &ThreadedAssignment::finished, _currentAssignment.data(),
|
||||||
|
&ThreadedAssignment::deleteLater);
|
||||||
|
|
||||||
|
// once it is deleted, we quit the worker thread
|
||||||
|
connect(_currentAssignment.data(), &ThreadedAssignment::destroyed, workerThread, &QThread::quit);
|
||||||
|
|
||||||
|
// have the worker thread remove itself once it is done
|
||||||
connect(workerThread, &QThread::finished, workerThread, &QThread::deleteLater);
|
connect(workerThread, &QThread::finished, workerThread, &QThread::deleteLater);
|
||||||
|
|
||||||
|
// once the worker thread says it is done, we consider the assignment completed
|
||||||
|
connect(workerThread, &QThread::destroyed, this, &AssignmentClient::assignmentCompleted);
|
||||||
|
|
||||||
_currentAssignment->moveToThread(workerThread);
|
_currentAssignment->moveToThread(workerThread);
|
||||||
|
|
||||||
// move the NodeList to the thread used for the _current assignment
|
// move the NodeList to the thread used for the _current assignment
|
||||||
|
@ -243,8 +263,9 @@ void AssignmentClient::readPendingDatagrams() {
|
||||||
} else if (packetTypeForPacket(receivedPacket) == PacketTypeStopNode) {
|
} else if (packetTypeForPacket(receivedPacket) == PacketTypeStopNode) {
|
||||||
if (senderSockAddr.getAddress() == QHostAddress::LocalHost ||
|
if (senderSockAddr.getAddress() == QHostAddress::LocalHost ||
|
||||||
senderSockAddr.getAddress() == QHostAddress::LocalHostIPv6) {
|
senderSockAddr.getAddress() == QHostAddress::LocalHostIPv6) {
|
||||||
qDebug() << "Network told me to exit.";
|
qDebug() << "AssignmentClientMonitor at" << senderSockAddr << "requested stop via PacketTypeStopNode.";
|
||||||
emit stopAssignmentClient();
|
|
||||||
|
QCoreApplication::quit();
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "Got a stop packet from other than localhost.";
|
qDebug() << "Got a stop packet from other than localhost.";
|
||||||
}
|
}
|
||||||
|
@ -281,20 +302,22 @@ void AssignmentClient::handleAuthenticationRequest() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssignmentClient::assignmentCompleted() {
|
void AssignmentClient::assignmentCompleted() {
|
||||||
|
|
||||||
|
// we expect that to be here the previous assignment has completely cleaned up
|
||||||
|
assert(_currentAssignment.isNull());
|
||||||
|
|
||||||
|
// reset our current assignment pointer to NULL now that it has been deleted
|
||||||
|
_currentAssignment = NULL;
|
||||||
|
|
||||||
// reset the logging target to the the CHILD_TARGET_NAME
|
// reset the logging target to the the CHILD_TARGET_NAME
|
||||||
LogHandler::getInstance().setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME);
|
LogHandler::getInstance().setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME);
|
||||||
|
|
||||||
qDebug("Assignment finished or never started - waiting for new assignment.");
|
qDebug() << "Assignment finished or never started - waiting for new assignment.";
|
||||||
|
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
|
|
||||||
// have us handle incoming NodeList datagrams again
|
// have us handle incoming NodeList datagrams again, and make sure our ThreadedAssignment isn't handling them
|
||||||
disconnect(&nodeList->getNodeSocket(), 0, _currentAssignment.data(), 0);
|
connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, this, &AssignmentClient::readPendingDatagrams);
|
||||||
connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, this, &AssignmentClient::readPendingDatagrams);
|
|
||||||
|
|
||||||
// clear our current assignment shared pointer now that we're done with it
|
|
||||||
// if the assignment thread is still around it has its own shared pointer to the assignment
|
|
||||||
_currentAssignment.clear();
|
|
||||||
|
|
||||||
// reset our NodeList by switching back to unassigned and clearing the list
|
// reset our NodeList by switching back to unassigned and clearing the list
|
||||||
nodeList->setOwnerType(NodeType::Unassigned);
|
nodeList->setOwnerType(NodeType::Unassigned);
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#define hifi_AssignmentClient_h
|
#define hifi_AssignmentClient_h
|
||||||
|
|
||||||
#include <QtCore/QCoreApplication>
|
#include <QtCore/QCoreApplication>
|
||||||
|
#include <QtCore/QPointer>
|
||||||
|
|
||||||
#include "ThreadedAssignment.h"
|
#include "ThreadedAssignment.h"
|
||||||
|
|
||||||
|
@ -22,10 +23,9 @@ class AssignmentClient : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
|
||||||
AssignmentClient(int ppid, Assignment::Type requestAssignmentType, QString assignmentPool,
|
AssignmentClient(Assignment::Type requestAssignmentType, QString assignmentPool,
|
||||||
QUuid walletUUID, QString assignmentServerHostname, quint16 assignmentServerPort);
|
QUuid walletUUID, QString assignmentServerHostname, quint16 assignmentServerPort,
|
||||||
static const SharedAssignmentPointer& getCurrentAssignment() { return _currentAssignment; }
|
quint16 assignmentMonitorPort);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void sendAssignmentRequest();
|
void sendAssignmentRequest();
|
||||||
void readPendingDatagrams();
|
void readPendingDatagrams();
|
||||||
|
@ -38,13 +38,13 @@ public slots:
|
||||||
void aboutToQuit();
|
void aboutToQuit();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setUpStatsToMonitor(int ppid);
|
void setUpStatsToMonitor();
|
||||||
|
|
||||||
Assignment _requestAssignment;
|
Assignment _requestAssignment;
|
||||||
static SharedAssignmentPointer _currentAssignment;
|
QPointer<ThreadedAssignment> _currentAssignment;
|
||||||
QString _assignmentServerHostname;
|
QString _assignmentServerHostname;
|
||||||
HifiSockAddr _assignmentServerSocket;
|
HifiSockAddr _assignmentServerSocket;
|
||||||
QSharedMemory* _localASPortSharedMem; // memory shared with domain server
|
QSharedMemory* _localASPortSharedMem; // memory shared with domain server
|
||||||
QSharedMemory* _localACMPortSharedMem; // memory shared with assignment client monitor
|
|
||||||
QTimer _requestTimer; // timer for requesting and assignment
|
QTimer _requestTimer; // timer for requesting and assignment
|
||||||
QTimer _statsTimerACM; // timer for sending stats to assignment client monitor
|
QTimer _statsTimerACM; // timer for sending stats to assignment client monitor
|
||||||
|
|
||||||
|
|
|
@ -79,9 +79,8 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) :
|
||||||
const QCommandLineOption maxChildsOption(ASSIGNMENT_MAX_FORKS_OPTION, "maximum number of children", "child-count");
|
const QCommandLineOption maxChildsOption(ASSIGNMENT_MAX_FORKS_OPTION, "maximum number of children", "child-count");
|
||||||
parser.addOption(maxChildsOption);
|
parser.addOption(maxChildsOption);
|
||||||
|
|
||||||
const QCommandLineOption ppidOption(PARENT_PID_OPTION, "parent's process id", "pid");
|
const QCommandLineOption monitorPortOption(ASSIGNMENT_CLIENT_MONITOR_PORT_OPTION, "assignment-client monitor port", "port");
|
||||||
parser.addOption(ppidOption);
|
parser.addOption(monitorPortOption);
|
||||||
|
|
||||||
|
|
||||||
if (!parser.parse(QCoreApplication::arguments())) {
|
if (!parser.parse(QCoreApplication::arguments())) {
|
||||||
qCritical() << parser.errorText() << endl;
|
qCritical() << parser.errorText() << endl;
|
||||||
|
@ -113,9 +112,9 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) :
|
||||||
maxForks = parser.value(maxChildsOption).toInt();
|
maxForks = parser.value(maxChildsOption).toInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
int ppid = 0;
|
unsigned short monitorPort = 0;
|
||||||
if (parser.isSet(ppidOption)) {
|
if (parser.isSet(monitorPortOption)) {
|
||||||
ppid = parser.value(ppidOption).toInt();
|
monitorPort = parser.value(monitorPortOption).toUShort();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!numForks && minForks) {
|
if (!numForks && minForks) {
|
||||||
|
@ -162,12 +161,11 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) :
|
||||||
if (argumentVariantMap.contains(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION)) {
|
if (argumentVariantMap.contains(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION)) {
|
||||||
assignmentServerPort = argumentVariantMap.value(CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION).toString().toUInt();
|
assignmentServerPort = argumentVariantMap.value(CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION).toString().toUInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parser.isSet(assignmentServerPortOption)) {
|
if (parser.isSet(assignmentServerPortOption)) {
|
||||||
assignmentServerPort = parser.value(assignmentServerPortOption).toInt();
|
assignmentServerPort = parser.value(assignmentServerPortOption).toInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (parser.isSet(numChildsOption)) {
|
if (parser.isSet(numChildsOption)) {
|
||||||
if (minForks && minForks > numForks) {
|
if (minForks && minForks > numForks) {
|
||||||
qCritical() << "--min can't be more than -n";
|
qCritical() << "--min can't be more than -n";
|
||||||
|
@ -186,14 +184,17 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) :
|
||||||
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
|
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
|
||||||
|
|
||||||
if (numForks || minForks || maxForks) {
|
if (numForks || minForks || maxForks) {
|
||||||
AssignmentClientMonitor monitor(numForks, minForks, maxForks, requestAssignmentType, assignmentPool,
|
AssignmentClientMonitor* monitor = new AssignmentClientMonitor(numForks, minForks, maxForks,
|
||||||
walletUUID, assignmentServerHostname, assignmentServerPort);
|
requestAssignmentType, assignmentPool,
|
||||||
connect(this, &QCoreApplication::aboutToQuit, &monitor, &AssignmentClientMonitor::aboutToQuit);
|
walletUUID, assignmentServerHostname,
|
||||||
exec();
|
assignmentServerPort);
|
||||||
|
monitor->setParent(this);
|
||||||
|
connect(this, &QCoreApplication::aboutToQuit, monitor, &AssignmentClientMonitor::aboutToQuit);
|
||||||
} else {
|
} else {
|
||||||
AssignmentClient client(ppid, requestAssignmentType, assignmentPool,
|
AssignmentClient* client = new AssignmentClient(requestAssignmentType, assignmentPool,
|
||||||
walletUUID, assignmentServerHostname, assignmentServerPort);
|
walletUUID, assignmentServerHostname,
|
||||||
connect(this, &QCoreApplication::aboutToQuit, &client, &AssignmentClient::aboutToQuit);
|
assignmentServerPort, monitorPort);
|
||||||
exec();
|
client->setParent(this);
|
||||||
|
connect(this, &QCoreApplication::aboutToQuit, client, &AssignmentClient::aboutToQuit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ const QString CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION = "p";
|
||||||
const QString ASSIGNMENT_NUM_FORKS_OPTION = "n";
|
const QString ASSIGNMENT_NUM_FORKS_OPTION = "n";
|
||||||
const QString ASSIGNMENT_MIN_FORKS_OPTION = "min";
|
const QString ASSIGNMENT_MIN_FORKS_OPTION = "min";
|
||||||
const QString ASSIGNMENT_MAX_FORKS_OPTION = "max";
|
const QString ASSIGNMENT_MAX_FORKS_OPTION = "max";
|
||||||
const QString PARENT_PID_OPTION = "ppid";
|
const QString ASSIGNMENT_CLIENT_MONITOR_PORT_OPTION = "monitor-port";
|
||||||
|
|
||||||
|
|
||||||
class AssignmentClientApp : public QCoreApplication {
|
class AssignmentClientApp : public QCoreApplication {
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
|
|
||||||
|
|
||||||
const QString ASSIGNMENT_CLIENT_MONITOR_TARGET_NAME = "assignment-client-monitor";
|
const QString ASSIGNMENT_CLIENT_MONITOR_TARGET_NAME = "assignment-client-monitor";
|
||||||
const int WAIT_FOR_CHILD_MSECS = 500;
|
const int WAIT_FOR_CHILD_MSECS = 1000;
|
||||||
|
|
||||||
AssignmentClientMonitor::AssignmentClientMonitor(const unsigned int numAssignmentClientForks,
|
AssignmentClientMonitor::AssignmentClientMonitor(const unsigned int numAssignmentClientForks,
|
||||||
const unsigned int minAssignmentClientForks,
|
const unsigned int minAssignmentClientForks,
|
||||||
|
@ -41,22 +41,20 @@ AssignmentClientMonitor::AssignmentClientMonitor(const unsigned int numAssignmen
|
||||||
_assignmentServerPort(assignmentServerPort)
|
_assignmentServerPort(assignmentServerPort)
|
||||||
{
|
{
|
||||||
qDebug() << "_requestAssignmentType =" << _requestAssignmentType;
|
qDebug() << "_requestAssignmentType =" << _requestAssignmentType;
|
||||||
|
|
||||||
// start the Logging class with the parent's target name
|
// start the Logging class with the parent's target name
|
||||||
LogHandler::getInstance().setTargetName(ASSIGNMENT_CLIENT_MONITOR_TARGET_NAME);
|
LogHandler::getInstance().setTargetName(ASSIGNMENT_CLIENT_MONITOR_TARGET_NAME);
|
||||||
|
|
||||||
|
// make sure we output process IDs for a monitor otherwise it's insane to parse
|
||||||
|
LogHandler::getInstance().setShouldOutputPID(true);
|
||||||
|
|
||||||
// create a NodeList so we can receive stats from children
|
// create a NodeList so we can receive stats from children
|
||||||
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
|
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
|
||||||
auto addressManager = DependencyManager::set<AddressManager>();
|
auto addressManager = DependencyManager::set<AddressManager>();
|
||||||
auto nodeList = DependencyManager::set<LimitedNodeList>(DEFAULT_ASSIGNMENT_CLIENT_MONITOR_PORT);
|
auto nodeList = DependencyManager::set<LimitedNodeList>();
|
||||||
|
|
||||||
connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, this, &AssignmentClientMonitor::readPendingDatagrams);
|
connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, this, &AssignmentClientMonitor::readPendingDatagrams);
|
||||||
|
|
||||||
qint64 pid = QCoreApplication::applicationPid ();
|
|
||||||
|
|
||||||
nodeList->putLocalPortIntoSharedMemory(QString(ASSIGNMENT_CLIENT_MONITOR_LOCAL_PORT_SMEM_KEY) + "-" + QString::number(pid),
|
|
||||||
this, nodeList->getNodeSocket().localPort());
|
|
||||||
|
|
||||||
// use QProcess to fork off a process for each of the child assignment clients
|
// use QProcess to fork off a process for each of the child assignment clients
|
||||||
for (unsigned int i = 0; i < _numAssignmentClientForks; i++) {
|
for (unsigned int i = 0; i < _numAssignmentClientForks; i++) {
|
||||||
spawnChildClient();
|
spawnChildClient();
|
||||||
|
@ -71,61 +69,60 @@ AssignmentClientMonitor::~AssignmentClientMonitor() {
|
||||||
stopChildProcesses();
|
stopChildProcesses();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssignmentClientMonitor::waitOnChildren(int msecs) {
|
void AssignmentClientMonitor::simultaneousWaitOnChildren(int waitMsecs) {
|
||||||
QMutableListIterator<QProcess*> i(_childProcesses);
|
QElapsedTimer waitTimer;
|
||||||
while (i.hasNext()) {
|
waitTimer.start();
|
||||||
QProcess* childProcess = i.next();
|
|
||||||
bool finished = childProcess->waitForFinished(msecs);
|
// loop as long as we still have processes around and we're inside the wait window
|
||||||
if (finished) {
|
while(_childProcesses.size() > 0 && !waitTimer.hasExpired(waitMsecs)) {
|
||||||
i.remove();
|
// continue processing events so we can handle a process finishing up
|
||||||
}
|
QCoreApplication::processEvents();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssignmentClientMonitor::childProcessFinished() {
|
||||||
|
QProcess* childProcess = qobject_cast<QProcess*>(sender());
|
||||||
|
qint64 processID = _childProcesses.key(childProcess);
|
||||||
|
|
||||||
|
if (processID > 0) {
|
||||||
|
qDebug() << "Child process" << processID << "has finished. Removing from internal map.";
|
||||||
|
_childProcesses.remove(processID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssignmentClientMonitor::stopChildProcesses() {
|
void AssignmentClientMonitor::stopChildProcesses() {
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
|
|
||||||
nodeList->eachNode([&](const SharedNodePointer& node) {
|
// ask child processes to terminate
|
||||||
qDebug() << "asking child" << node->getUUID() << "to exit.";
|
foreach(QProcess* childProcess, _childProcesses) {
|
||||||
node->activateLocalSocket();
|
qDebug() << "Attempting to terminate child process" << childProcess->processId();
|
||||||
QByteArray diePacket = nodeList->byteArrayWithPopulatedHeader(PacketTypeStopNode);
|
|
||||||
nodeList->writeUnverifiedDatagram(diePacket, *node->getActiveSocket());
|
|
||||||
});
|
|
||||||
|
|
||||||
// try to give all the children time to shutdown
|
|
||||||
waitOnChildren(WAIT_FOR_CHILD_MSECS);
|
|
||||||
|
|
||||||
// ask more firmly
|
|
||||||
QMutableListIterator<QProcess*> i(_childProcesses);
|
|
||||||
while (i.hasNext()) {
|
|
||||||
QProcess* childProcess = i.next();
|
|
||||||
childProcess->terminate();
|
childProcess->terminate();
|
||||||
}
|
}
|
||||||
|
|
||||||
// try to give all the children time to shutdown
|
simultaneousWaitOnChildren(WAIT_FOR_CHILD_MSECS);
|
||||||
waitOnChildren(WAIT_FOR_CHILD_MSECS);
|
|
||||||
|
if (_childProcesses.size() > 0) {
|
||||||
// ask even more firmly
|
// ask even more firmly
|
||||||
QMutableListIterator<QProcess*> j(_childProcesses);
|
foreach(QProcess* childProcess, _childProcesses) {
|
||||||
while (j.hasNext()) {
|
qDebug() << "Attempting to kill child process" << childProcess->processId();
|
||||||
QProcess* childProcess = j.next();
|
childProcess->kill();
|
||||||
childProcess->kill();
|
}
|
||||||
|
|
||||||
|
simultaneousWaitOnChildren(WAIT_FOR_CHILD_MSECS);
|
||||||
}
|
}
|
||||||
|
|
||||||
waitOnChildren(WAIT_FOR_CHILD_MSECS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssignmentClientMonitor::aboutToQuit() {
|
void AssignmentClientMonitor::aboutToQuit() {
|
||||||
stopChildProcesses();
|
stopChildProcesses();
|
||||||
|
|
||||||
// clear the log handler so that Qt doesn't call the destructor on LogHandler
|
// clear the log handler so that Qt doesn't call the destructor on LogHandler
|
||||||
qInstallMessageHandler(0);
|
qInstallMessageHandler(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssignmentClientMonitor::spawnChildClient() {
|
void AssignmentClientMonitor::spawnChildClient() {
|
||||||
QProcess *assignmentClient = new QProcess(this);
|
QProcess* assignmentClient = new QProcess(this);
|
||||||
|
|
||||||
_childProcesses.append(assignmentClient);
|
|
||||||
|
|
||||||
|
|
||||||
// unparse the parts of the command-line that the child cares about
|
// unparse the parts of the command-line that the child cares about
|
||||||
QStringList _childArguments;
|
QStringList _childArguments;
|
||||||
if (_assignmentPool != "") {
|
if (_assignmentPool != "") {
|
||||||
|
@ -149,17 +146,21 @@ void AssignmentClientMonitor::spawnChildClient() {
|
||||||
_childArguments.append(QString::number(_requestAssignmentType));
|
_childArguments.append(QString::number(_requestAssignmentType));
|
||||||
}
|
}
|
||||||
|
|
||||||
// tell children which shared memory key to use
|
// tell children which assignment monitor port to use
|
||||||
qint64 pid = QCoreApplication::applicationPid ();
|
// for now they simply talk to us on localhost
|
||||||
_childArguments.append("--" + PARENT_PID_OPTION);
|
_childArguments.append("--" + ASSIGNMENT_CLIENT_MONITOR_PORT_OPTION);
|
||||||
_childArguments.append(QString::number(pid));
|
_childArguments.append(QString::number(DependencyManager::get<NodeList>()->getLocalSockAddr().getPort()));
|
||||||
|
|
||||||
// make sure that the output from the child process appears in our output
|
// make sure that the output from the child process appears in our output
|
||||||
assignmentClient->setProcessChannelMode(QProcess::ForwardedChannels);
|
assignmentClient->setProcessChannelMode(QProcess::ForwardedChannels);
|
||||||
|
|
||||||
assignmentClient->start(QCoreApplication::applicationFilePath(), _childArguments);
|
assignmentClient->start(QCoreApplication::applicationFilePath(), _childArguments);
|
||||||
|
|
||||||
|
// make sure we hear that this process has finished when it does
|
||||||
|
connect(assignmentClient, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(childProcessFinished()));
|
||||||
|
|
||||||
qDebug() << "Spawned a child client with PID" << assignmentClient->pid();
|
qDebug() << "Spawned a child client with PID" << assignmentClient->pid();
|
||||||
|
_childProcesses.insert(assignmentClient->processId(), assignmentClient);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssignmentClientMonitor::checkSpares() {
|
void AssignmentClientMonitor::checkSpares() {
|
||||||
|
@ -193,12 +194,11 @@ void AssignmentClientMonitor::checkSpares() {
|
||||||
qDebug() << "asking child" << aSpareId << "to exit.";
|
qDebug() << "asking child" << aSpareId << "to exit.";
|
||||||
SharedNodePointer childNode = nodeList->nodeWithUUID(aSpareId);
|
SharedNodePointer childNode = nodeList->nodeWithUUID(aSpareId);
|
||||||
childNode->activateLocalSocket();
|
childNode->activateLocalSocket();
|
||||||
|
|
||||||
QByteArray diePacket = nodeList->byteArrayWithPopulatedHeader(PacketTypeStopNode);
|
QByteArray diePacket = nodeList->byteArrayWithPopulatedHeader(PacketTypeStopNode);
|
||||||
nodeList->writeUnverifiedDatagram(diePacket, childNode);
|
nodeList->writeUnverifiedDatagram(diePacket, childNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
waitOnChildren(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -33,17 +33,19 @@ public:
|
||||||
quint16 assignmentServerPort);
|
quint16 assignmentServerPort);
|
||||||
~AssignmentClientMonitor();
|
~AssignmentClientMonitor();
|
||||||
|
|
||||||
void waitOnChildren(int msecs);
|
|
||||||
void stopChildProcesses();
|
void stopChildProcesses();
|
||||||
private slots:
|
private slots:
|
||||||
void readPendingDatagrams();
|
void readPendingDatagrams();
|
||||||
void checkSpares();
|
void checkSpares();
|
||||||
|
void childProcessFinished();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void aboutToQuit();
|
void aboutToQuit();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void spawnChildClient();
|
void spawnChildClient();
|
||||||
|
void simultaneousWaitOnChildren(int waitMsecs);
|
||||||
|
|
||||||
QTimer _checkSparesTimer; // every few seconds see if it need fewer or more spare children
|
QTimer _checkSparesTimer; // every few seconds see if it need fewer or more spare children
|
||||||
|
|
||||||
const unsigned int _numAssignmentClientForks;
|
const unsigned int _numAssignmentClientForks;
|
||||||
|
@ -56,7 +58,7 @@ private:
|
||||||
QString _assignmentServerHostname;
|
QString _assignmentServerHostname;
|
||||||
quint16 _assignmentServerPort;
|
quint16 _assignmentServerPort;
|
||||||
|
|
||||||
QList<QProcess*> _childProcesses;
|
QMap<qint64, QProcess*> _childProcesses;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_AssignmentClientMonitor_h
|
#endif // hifi_AssignmentClientMonitor_h
|
||||||
|
|
|
@ -1,19 +0,0 @@
|
||||||
//
|
|
||||||
// AssignmentThread.cpp
|
|
||||||
// assignment-client/src
|
|
||||||
//
|
|
||||||
// Created by Stephen Birarda on 2014.
|
|
||||||
// Copyright 2014 High Fidelity, Inc.
|
|
||||||
//
|
|
||||||
// Distributed under the Apache License, Version 2.0.
|
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "AssignmentThread.h"
|
|
||||||
|
|
||||||
AssignmentThread::AssignmentThread(const SharedAssignmentPointer& assignment, QObject* parent) :
|
|
||||||
QThread(parent),
|
|
||||||
_assignment(assignment)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
//
|
|
||||||
// AssignmentThread.h
|
|
||||||
// assignment-client/src
|
|
||||||
//
|
|
||||||
// Created by Stephen Birarda on 2014.
|
|
||||||
// Copyright 2014 High Fidelity, Inc.
|
|
||||||
//
|
|
||||||
// Distributed under the Apache License, Version 2.0.
|
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef hifi_AssignmentThread_h
|
|
||||||
#define hifi_AssignmentThread_h
|
|
||||||
|
|
||||||
#include <QtCore/QThread>
|
|
||||||
|
|
||||||
#include <ThreadedAssignment.h>
|
|
||||||
|
|
||||||
class AssignmentThread : public QThread {
|
|
||||||
public:
|
|
||||||
AssignmentThread(const SharedAssignmentPointer& assignment, QObject* parent);
|
|
||||||
private:
|
|
||||||
SharedAssignmentPointer _assignment;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // hifi_AssignmentThread_h
|
|
|
@ -851,7 +851,7 @@ void AudioMixer::run() {
|
||||||
++_numStatFrames;
|
++_numStatFrames;
|
||||||
|
|
||||||
QCoreApplication::processEvents();
|
QCoreApplication::processEvents();
|
||||||
|
|
||||||
if (_isFinished) {
|
if (_isFinished) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,6 +52,7 @@ AvatarMixer::~AvatarMixer() {
|
||||||
if (_broadcastTimer) {
|
if (_broadcastTimer) {
|
||||||
_broadcastTimer->deleteLater();
|
_broadcastTimer->deleteLater();
|
||||||
}
|
}
|
||||||
|
|
||||||
_broadcastThread.quit();
|
_broadcastThread.quit();
|
||||||
_broadcastThread.wait();
|
_broadcastThread.wait();
|
||||||
}
|
}
|
||||||
|
@ -517,7 +518,7 @@ void AvatarMixer::run() {
|
||||||
};
|
};
|
||||||
|
|
||||||
// setup the timer that will be fired on the broadcast thread
|
// setup the timer that will be fired on the broadcast thread
|
||||||
_broadcastTimer = new QTimer();
|
_broadcastTimer = new QTimer;
|
||||||
_broadcastTimer->setInterval(AVATAR_DATA_SEND_INTERVAL_MSECS);
|
_broadcastTimer->setInterval(AVATAR_DATA_SEND_INTERVAL_MSECS);
|
||||||
_broadcastTimer->moveToThread(&_broadcastThread);
|
_broadcastTimer->moveToThread(&_broadcastThread);
|
||||||
|
|
||||||
|
|
|
@ -9,10 +9,15 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
#include "AssignmentClientApp.h"
|
#include "AssignmentClientApp.h"
|
||||||
|
|
||||||
|
#include <QtCore/QDebug>
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
AssignmentClientApp app(argc, argv);
|
AssignmentClientApp app(argc, argv);
|
||||||
return 0;
|
|
||||||
|
int acReturn = app.exec();
|
||||||
|
qDebug() << "assignment-client process" << app.applicationPid() << "exiting with status code" << acReturn;
|
||||||
|
|
||||||
|
return acReturn;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,11 +9,15 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "PacketHeaders.h"
|
|
||||||
#include "SharedUtil.h"
|
|
||||||
#include "OctreeQueryNode.h"
|
#include "OctreeQueryNode.h"
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
|
#include <PacketHeaders.h>
|
||||||
|
#include <SharedUtil.h>
|
||||||
|
#include <UUID.h>
|
||||||
|
|
||||||
#include "OctreeSendThread.h"
|
#include "OctreeSendThread.h"
|
||||||
|
|
||||||
OctreeQueryNode::OctreeQueryNode() :
|
OctreeQueryNode::OctreeQueryNode() :
|
||||||
|
@ -91,8 +95,8 @@ void OctreeQueryNode::sendThreadFinished() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OctreeQueryNode::initializeOctreeSendThread(const SharedAssignmentPointer& myAssignment, const SharedNodePointer& node) {
|
void OctreeQueryNode::initializeOctreeSendThread(OctreeServer* myServer, const SharedNodePointer& node) {
|
||||||
_octreeSendThread = new OctreeSendThread(myAssignment, node);
|
_octreeSendThread = new OctreeSendThread(myServer, node);
|
||||||
|
|
||||||
// we want to be notified when the thread finishes
|
// we want to be notified when the thread finishes
|
||||||
connect(_octreeSendThread, &GenericThread::finished, this, &OctreeQueryNode::sendThreadFinished);
|
connect(_octreeSendThread, &GenericThread::finished, this, &OctreeQueryNode::sendThreadFinished);
|
||||||
|
|
|
@ -22,11 +22,11 @@
|
||||||
#include <OctreePacketData.h>
|
#include <OctreePacketData.h>
|
||||||
#include <OctreeQuery.h>
|
#include <OctreeQuery.h>
|
||||||
#include <OctreeSceneStats.h>
|
#include <OctreeSceneStats.h>
|
||||||
#include <ThreadedAssignment.h> // for SharedAssignmentPointer
|
|
||||||
#include "SentPacketHistory.h"
|
#include "SentPacketHistory.h"
|
||||||
#include <qqueue.h>
|
#include <qqueue.h>
|
||||||
|
|
||||||
class OctreeSendThread;
|
class OctreeSendThread;
|
||||||
|
class OctreeServer;
|
||||||
|
|
||||||
class OctreeQueryNode : public OctreeQuery {
|
class OctreeQueryNode : public OctreeQuery {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -89,7 +89,7 @@ public:
|
||||||
|
|
||||||
OctreeSceneStats stats;
|
OctreeSceneStats stats;
|
||||||
|
|
||||||
void initializeOctreeSendThread(const SharedAssignmentPointer& myAssignment, const SharedNodePointer& node);
|
void initializeOctreeSendThread(OctreeServer* myServer, const SharedNodePointer& node);
|
||||||
bool isOctreeSendThreadInitalized() { return _octreeSendThread; }
|
bool isOctreeSendThreadInitalized() { return _octreeSendThread; }
|
||||||
|
|
||||||
void dumpOutOfView();
|
void dumpOutOfView();
|
||||||
|
|
|
@ -21,9 +21,8 @@
|
||||||
quint64 startSceneSleepTime = 0;
|
quint64 startSceneSleepTime = 0;
|
||||||
quint64 endSceneSleepTime = 0;
|
quint64 endSceneSleepTime = 0;
|
||||||
|
|
||||||
OctreeSendThread::OctreeSendThread(const SharedAssignmentPointer& myAssignment, const SharedNodePointer& node) :
|
OctreeSendThread::OctreeSendThread(OctreeServer* myServer, const SharedNodePointer& node) :
|
||||||
_myAssignment(myAssignment),
|
_myServer(myServer),
|
||||||
_myServer(static_cast<OctreeServer*>(myAssignment.data())),
|
|
||||||
_node(node),
|
_node(node),
|
||||||
_nodeUUID(node->getUUID()),
|
_nodeUUID(node->getUUID()),
|
||||||
_packetData(),
|
_packetData(),
|
||||||
|
@ -31,9 +30,14 @@ OctreeSendThread::OctreeSendThread(const SharedAssignmentPointer& myAssignment,
|
||||||
_isShuttingDown(false)
|
_isShuttingDown(false)
|
||||||
{
|
{
|
||||||
QString safeServerName("Octree");
|
QString safeServerName("Octree");
|
||||||
|
|
||||||
|
// set our QThread object name so we can identify this thread while debugging
|
||||||
|
setObjectName(QString("Octree Send Thread (%1)").arg(uuidStringWithoutCurlyBraces(node->getUUID())));
|
||||||
|
|
||||||
if (_myServer) {
|
if (_myServer) {
|
||||||
safeServerName = _myServer->getMyServerName();
|
safeServerName = _myServer->getMyServerName();
|
||||||
}
|
}
|
||||||
|
|
||||||
qDebug() << qPrintable(safeServerName) << "server [" << _myServer << "]: client connected "
|
qDebug() << qPrintable(safeServerName) << "server [" << _myServer << "]: client connected "
|
||||||
"- starting sending thread [" << this << "]";
|
"- starting sending thread [" << this << "]";
|
||||||
|
|
||||||
|
@ -53,7 +57,6 @@ OctreeSendThread::~OctreeSendThread() {
|
||||||
OctreeServer::stopTrackingThread(this);
|
OctreeServer::stopTrackingThread(this);
|
||||||
|
|
||||||
_node.clear();
|
_node.clear();
|
||||||
_myAssignment.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OctreeSendThread::setIsShuttingDown() {
|
void OctreeSendThread::setIsShuttingDown() {
|
||||||
|
@ -66,15 +69,13 @@ bool OctreeSendThread::process() {
|
||||||
return false; // exit early if we're shutting down
|
return false; // exit early if we're shutting down
|
||||||
}
|
}
|
||||||
|
|
||||||
// check that our server and assignment is still valid
|
|
||||||
if (!_myServer || !_myAssignment) {
|
|
||||||
return false; // exit early if it's not, it means the server is shutting down
|
|
||||||
}
|
|
||||||
|
|
||||||
OctreeServer::didProcess(this);
|
OctreeServer::didProcess(this);
|
||||||
|
|
||||||
quint64 start = usecTimestampNow();
|
quint64 start = usecTimestampNow();
|
||||||
|
|
||||||
|
// we'd better have a server at this point, or we're in trouble
|
||||||
|
assert(_myServer);
|
||||||
|
|
||||||
// don't do any send processing until the initial load of the octree is complete...
|
// don't do any send processing until the initial load of the octree is complete...
|
||||||
if (_myServer->isInitialLoadComplete()) {
|
if (_myServer->isInitialLoadComplete()) {
|
||||||
if (_node) {
|
if (_node) {
|
||||||
|
|
|
@ -26,7 +26,7 @@ class OctreeServer;
|
||||||
class OctreeSendThread : public GenericThread {
|
class OctreeSendThread : public GenericThread {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
OctreeSendThread(const SharedAssignmentPointer& myAssignment, const SharedNodePointer& node);
|
OctreeSendThread(OctreeServer* myServer, const SharedNodePointer& node);
|
||||||
virtual ~OctreeSendThread();
|
virtual ~OctreeSendThread();
|
||||||
|
|
||||||
void setIsShuttingDown();
|
void setIsShuttingDown();
|
||||||
|
@ -43,7 +43,6 @@ protected:
|
||||||
virtual bool process();
|
virtual bool process();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SharedAssignmentPointer _myAssignment;
|
|
||||||
OctreeServer* _myServer;
|
OctreeServer* _myServer;
|
||||||
SharedNodePointer _node;
|
SharedNodePointer _node;
|
||||||
QUuid _nodeUUID;
|
QUuid _nodeUUID;
|
||||||
|
|
|
@ -828,42 +828,42 @@ void OctreeServer::parsePayload() {
|
||||||
|
|
||||||
void OctreeServer::readPendingDatagram(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr) {
|
void OctreeServer::readPendingDatagram(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr) {
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
|
|
||||||
|
// If we know we're shutting down we just drop these packets on the floor.
|
||||||
|
// This stops us from initializing send threads we just shut down.
|
||||||
|
|
||||||
if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
|
if (!_isShuttingDown) {
|
||||||
PacketType packetType = packetTypeForPacket(receivedPacket);
|
if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
|
||||||
SharedNodePointer matchingNode = nodeList->sendingNodeForPacket(receivedPacket);
|
PacketType packetType = packetTypeForPacket(receivedPacket);
|
||||||
if (packetType == getMyQueryMessageType()) {
|
SharedNodePointer matchingNode = nodeList->sendingNodeForPacket(receivedPacket);
|
||||||
// If we got a query packet, then we're talking to an agent, and we
|
if (packetType == getMyQueryMessageType()) {
|
||||||
// need to make sure we have it in our nodeList.
|
// If we got a query packet, then we're talking to an agent, and we
|
||||||
if (matchingNode) {
|
// need to make sure we have it in our nodeList.
|
||||||
nodeList->updateNodeWithDataFromPacket(matchingNode, receivedPacket);
|
if (matchingNode) {
|
||||||
OctreeQueryNode* nodeData = (OctreeQueryNode*)matchingNode->getLinkedData();
|
nodeList->updateNodeWithDataFromPacket(matchingNode, receivedPacket);
|
||||||
if (nodeData && !nodeData->isOctreeSendThreadInitalized()) {
|
|
||||||
|
|
||||||
// NOTE: this is an important aspect of the proper ref counting. The send threads/node data need to
|
OctreeQueryNode* nodeData = (OctreeQueryNode*) matchingNode->getLinkedData();
|
||||||
// know that the OctreeServer/Assignment will not get deleted on it while it's still active. The
|
if (nodeData && !nodeData->isOctreeSendThreadInitalized()) {
|
||||||
// solution is to get the shared pointer for the current assignment. We need to make sure this is the
|
nodeData->initializeOctreeSendThread(this, matchingNode);
|
||||||
// same SharedAssignmentPointer that was ref counted by the assignment client.
|
}
|
||||||
SharedAssignmentPointer sharedAssignment = AssignmentClient::getCurrentAssignment();
|
|
||||||
nodeData->initializeOctreeSendThread(sharedAssignment, matchingNode);
|
|
||||||
}
|
}
|
||||||
}
|
} else if (packetType == PacketTypeOctreeDataNack) {
|
||||||
} else if (packetType == PacketTypeOctreeDataNack) {
|
// If we got a nack packet, then we're talking to an agent, and we
|
||||||
// If we got a nack packet, then we're talking to an agent, and we
|
// need to make sure we have it in our nodeList.
|
||||||
// need to make sure we have it in our nodeList.
|
if (matchingNode) {
|
||||||
if (matchingNode) {
|
OctreeQueryNode* nodeData = (OctreeQueryNode*)matchingNode->getLinkedData();
|
||||||
OctreeQueryNode* nodeData = (OctreeQueryNode*)matchingNode->getLinkedData();
|
if (nodeData) {
|
||||||
if (nodeData) {
|
nodeData->parseNackPacket(receivedPacket);
|
||||||
nodeData->parseNackPacket(receivedPacket);
|
}
|
||||||
}
|
}
|
||||||
|
} else if (packetType == PacketTypeJurisdictionRequest) {
|
||||||
|
_jurisdictionSender->queueReceivedPacket(matchingNode, receivedPacket);
|
||||||
|
} else if (_octreeInboundPacketProcessor && getOctree()->handlesEditPacketType(packetType)) {
|
||||||
|
_octreeInboundPacketProcessor->queueReceivedPacket(matchingNode, receivedPacket);
|
||||||
|
} else {
|
||||||
|
// let processNodeData handle it.
|
||||||
|
DependencyManager::get<NodeList>()->processNodeData(senderSockAddr, receivedPacket);
|
||||||
}
|
}
|
||||||
} else if (packetType == PacketTypeJurisdictionRequest) {
|
|
||||||
_jurisdictionSender->queueReceivedPacket(matchingNode, receivedPacket);
|
|
||||||
} else if (_octreeInboundPacketProcessor && getOctree()->handlesEditPacketType(packetType)) {
|
|
||||||
_octreeInboundPacketProcessor->queueReceivedPacket(matchingNode, receivedPacket);
|
|
||||||
} else {
|
|
||||||
// let processNodeData handle it.
|
|
||||||
DependencyManager::get<NodeList>()->processNodeData(senderSockAddr, receivedPacket);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1216,8 +1216,16 @@ void OctreeServer::forceNodeShutdown(SharedNodePointer node) {
|
||||||
|
|
||||||
void OctreeServer::aboutToFinish() {
|
void OctreeServer::aboutToFinish() {
|
||||||
qDebug() << qPrintable(_safeServerName) << "server STARTING about to finish...";
|
qDebug() << qPrintable(_safeServerName) << "server STARTING about to finish...";
|
||||||
|
|
||||||
|
_isShuttingDown = true;
|
||||||
|
|
||||||
qDebug() << qPrintable(_safeServerName) << "inform Octree Inbound Packet Processor that we are shutting down...";
|
qDebug() << qPrintable(_safeServerName) << "inform Octree Inbound Packet Processor that we are shutting down...";
|
||||||
|
|
||||||
|
// we're going down - set the NodeList linkedDataCallback to NULL so we do not create any more OctreeQueryNode objects.
|
||||||
|
// This ensures that when we forceNodeShutdown below for each node we don't get any more newly connecting nodes
|
||||||
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
|
nodeList->linkedDataCreateCallback = NULL;
|
||||||
|
|
||||||
if (_octreeInboundPacketProcessor) {
|
if (_octreeInboundPacketProcessor) {
|
||||||
_octreeInboundPacketProcessor->terminating();
|
_octreeInboundPacketProcessor->terminating();
|
||||||
}
|
}
|
||||||
|
@ -1226,7 +1234,9 @@ void OctreeServer::aboutToFinish() {
|
||||||
_jurisdictionSender->terminating();
|
_jurisdictionSender->terminating();
|
||||||
}
|
}
|
||||||
|
|
||||||
DependencyManager::get<NodeList>()->eachNode([this](const SharedNodePointer& node) {
|
// force a shutdown of all of our OctreeSendThreads - at this point it has to be impossible for a
|
||||||
|
// linkedDataCreateCallback to be called for a new node
|
||||||
|
nodeList->eachNode([this](const SharedNodePointer& node) {
|
||||||
qDebug() << qPrintable(_safeServerName) << "server about to finish while node still connected node:" << *node;
|
qDebug() << qPrintable(_safeServerName) << "server about to finish while node still connected node:" << *node;
|
||||||
forceNodeShutdown(node);
|
forceNodeShutdown(node);
|
||||||
});
|
});
|
||||||
|
|
|
@ -144,12 +144,14 @@ protected:
|
||||||
QString getStatusLink();
|
QString getStatusLink();
|
||||||
|
|
||||||
void setupDatagramProcessingThread();
|
void setupDatagramProcessingThread();
|
||||||
|
|
||||||
int _argc;
|
int _argc;
|
||||||
const char** _argv;
|
const char** _argv;
|
||||||
char** _parsedArgV;
|
char** _parsedArgV;
|
||||||
QJsonObject _settings;
|
QJsonObject _settings;
|
||||||
|
|
||||||
|
bool _isShuttingDown = false;
|
||||||
|
|
||||||
HTTPManager* _httpManager;
|
HTTPManager* _httpManager;
|
||||||
int _statusPort;
|
int _statusPort;
|
||||||
QString _statusHost;
|
QString _statusHost;
|
||||||
|
|
|
@ -69,6 +69,7 @@ DomainServer::DomainServer(int argc, char* argv[]) :
|
||||||
_iceServerSocket(ICE_SERVER_DEFAULT_HOSTNAME, ICE_SERVER_DEFAULT_PORT)
|
_iceServerSocket(ICE_SERVER_DEFAULT_HOSTNAME, ICE_SERVER_DEFAULT_PORT)
|
||||||
{
|
{
|
||||||
LogUtils::init();
|
LogUtils::init();
|
||||||
|
Setting::init();
|
||||||
|
|
||||||
setOrganizationName("High Fidelity");
|
setOrganizationName("High Fidelity");
|
||||||
setOrganizationDomain("highfidelity.io");
|
setOrganizationDomain("highfidelity.io");
|
||||||
|
|
68
examples/utilities/diagnostics/loadTestServers.js
Normal file
68
examples/utilities/diagnostics/loadTestServers.js
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
//
|
||||||
|
// loadTestServers.js
|
||||||
|
// examples/utilities/diagnostics
|
||||||
|
//
|
||||||
|
// Created by Stephen Birarda on 05/08/15.
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
// This script is made for load testing HF servers. It connects to the HF servers and sends/receives data.
|
||||||
|
// Run this on an assignment-client.
|
||||||
|
//
|
||||||
|
|
||||||
|
var count = 0;
|
||||||
|
var yawDirection = -1;
|
||||||
|
var yaw = 45;
|
||||||
|
var yawMax = 70;
|
||||||
|
var yawMin = 20;
|
||||||
|
var vantagePoint = {x: 5000, y: 500, z: 5000};
|
||||||
|
|
||||||
|
var isLocal = false;
|
||||||
|
|
||||||
|
// set up our EntityViewer with a position and orientation
|
||||||
|
var orientation = Quat.fromPitchYawRollDegrees(0, yaw, 0);
|
||||||
|
|
||||||
|
EntityViewer.setPosition(vantagePoint);
|
||||||
|
EntityViewer.setOrientation(orientation);
|
||||||
|
EntityViewer.queryOctree();
|
||||||
|
|
||||||
|
Agent.isListeningToAudioStream = true;
|
||||||
|
Agent.isAvatar = true;
|
||||||
|
|
||||||
|
function getRandomInt(min, max) {
|
||||||
|
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||||
|
}
|
||||||
|
|
||||||
|
function keepLooking(deltaTime) {
|
||||||
|
count++;
|
||||||
|
|
||||||
|
if (count % getRandomInt(5, 15) == 0) {
|
||||||
|
yaw += yawDirection;
|
||||||
|
orientation = Quat.fromPitchYawRollDegrees(0, yaw, 0);
|
||||||
|
|
||||||
|
if (yaw > yawMax || yaw < yawMin) {
|
||||||
|
yawDirection = yawDirection * -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
EntityViewer.setOrientation(orientation);
|
||||||
|
EntityViewer.queryOctree();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// approximately every second, consider stopping
|
||||||
|
if (count % 60 == 0) {
|
||||||
|
print("considering stop.... elementCount:" + EntityViewer.getOctreeElementsCount());
|
||||||
|
|
||||||
|
var stopProbability = 0.05; // 5% chance of stopping
|
||||||
|
|
||||||
|
if (Math.random() < stopProbability) {
|
||||||
|
print("stopping.... elementCount:" + EntityViewer.getOctreeElementsCount());
|
||||||
|
Script.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// register the call back so it fires before each data send
|
||||||
|
Script.update.connect(keepLooking);
|
|
@ -26,6 +26,7 @@
|
||||||
#include <QAbstractNativeEventFilter>
|
#include <QAbstractNativeEventFilter>
|
||||||
#include <QActionGroup>
|
#include <QActionGroup>
|
||||||
#include <QColorDialog>
|
#include <QColorDialog>
|
||||||
|
#include <QCoreApplication>
|
||||||
#include <QDesktopWidget>
|
#include <QDesktopWidget>
|
||||||
#include <QCheckBox>
|
#include <QCheckBox>
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
|
@ -250,6 +251,8 @@ bool setupEssentials(int& argc, char** argv) {
|
||||||
|
|
||||||
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
|
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
|
||||||
DependencyManager::registerInheritance<AvatarHashMap, AvatarManager>();
|
DependencyManager::registerInheritance<AvatarHashMap, AvatarManager>();
|
||||||
|
|
||||||
|
Setting::init();
|
||||||
|
|
||||||
// Set dependencies
|
// Set dependencies
|
||||||
auto addressManager = DependencyManager::set<AddressManager>();
|
auto addressManager = DependencyManager::set<AddressManager>();
|
||||||
|
@ -341,7 +344,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
installNativeEventFilter(&MyNativeEventFilter::getInstance());
|
installNativeEventFilter(&MyNativeEventFilter::getInstance());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
_logger = new FileLogger(this); // After setting organization name in order to get correct directory
|
_logger = new FileLogger(this); // After setting organization name in order to get correct directory
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,6 @@ static BOOL CALLBACK enumWindowsCallback(HWND hWnd, LPARAM lParam) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, const char* argv[]) {
|
int main(int argc, const char* argv[]) {
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
// Run only one instance of Interface at a time.
|
// Run only one instance of Interface at a time.
|
||||||
|
|
|
@ -52,10 +52,8 @@ const unsigned short STUN_SERVER_PORT = 3478;
|
||||||
const QString DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY = "domain-server.local-port";
|
const QString DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY = "domain-server.local-port";
|
||||||
const QString DOMAIN_SERVER_LOCAL_HTTP_PORT_SMEM_KEY = "domain-server.local-http-port";
|
const QString DOMAIN_SERVER_LOCAL_HTTP_PORT_SMEM_KEY = "domain-server.local-http-port";
|
||||||
const QString DOMAIN_SERVER_LOCAL_HTTPS_PORT_SMEM_KEY = "domain-server.local-https-port";
|
const QString DOMAIN_SERVER_LOCAL_HTTPS_PORT_SMEM_KEY = "domain-server.local-https-port";
|
||||||
const QString ASSIGNMENT_CLIENT_MONITOR_LOCAL_PORT_SMEM_KEY = "assignment-client-monitor.local-port";
|
|
||||||
|
|
||||||
const char DEFAULT_ASSIGNMENT_CLIENT_MONITOR_HOSTNAME[] = "localhost";
|
const QHostAddress DEFAULT_ASSIGNMENT_CLIENT_MONITOR_HOSTNAME = QHostAddress::LocalHost;
|
||||||
const unsigned short DEFAULT_ASSIGNMENT_CLIENT_MONITOR_PORT = 40104;
|
|
||||||
|
|
||||||
const QString USERNAME_UUID_REPLACEMENT_STATS_KEY = "$username";
|
const QString USERNAME_UUID_REPLACEMENT_STATS_KEY = "$username";
|
||||||
|
|
||||||
|
|
|
@ -150,7 +150,11 @@ void NodeList::timePingReply(const QByteArray& packet, const SharedNodePointer&
|
||||||
void NodeList::processNodeData(const HifiSockAddr& senderSockAddr, const QByteArray& packet) {
|
void NodeList::processNodeData(const HifiSockAddr& senderSockAddr, const QByteArray& packet) {
|
||||||
switch (packetTypeForPacket(packet)) {
|
switch (packetTypeForPacket(packet)) {
|
||||||
case PacketTypeDomainList: {
|
case PacketTypeDomainList: {
|
||||||
processDomainServerList(packet);
|
if (!_domainHandler.getSockAddr().isNull()) {
|
||||||
|
// only process a list from domain-server if we're talking to a domain
|
||||||
|
// TODO: how do we make sure this is actually the domain we want the list from (DTLS probably)
|
||||||
|
processDomainServerList(packet);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PacketTypeDomainServerRequireDTLS: {
|
case PacketTypeDomainServerRequireDTLS: {
|
||||||
|
|
|
@ -27,40 +27,47 @@ ThreadedAssignment::ThreadedAssignment(const QByteArray& packet) :
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThreadedAssignment::setFinished(bool isFinished) {
|
void ThreadedAssignment::setFinished(bool isFinished) {
|
||||||
_isFinished = isFinished;
|
if (_isFinished != isFinished) {
|
||||||
|
_isFinished = isFinished;
|
||||||
|
|
||||||
if (_isFinished) {
|
if (_isFinished) {
|
||||||
if (_domainServerTimer) {
|
|
||||||
_domainServerTimer->stop();
|
|
||||||
delete _domainServerTimer;
|
|
||||||
_domainServerTimer = nullptr;
|
|
||||||
}
|
|
||||||
if (_statsTimer) {
|
|
||||||
_statsTimer->stop();
|
|
||||||
delete _statsTimer;
|
|
||||||
_statsTimer = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
aboutToFinish();
|
qDebug() << "ThreadedAssignment::setFinished(true) called - finishing up.";
|
||||||
|
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
if (_domainServerTimer) {
|
||||||
|
_domainServerTimer->stop();
|
||||||
// if we have a datagram processing thread, quit it and wait on it to make sure that
|
}
|
||||||
// the node socket is back on the same thread as the NodeList
|
|
||||||
|
if (_statsTimer) {
|
||||||
if (_datagramProcessingThread) {
|
_statsTimer->stop();
|
||||||
// tell the datagram processing thread to quit and wait until it is done, then return the node socket to the NodeList
|
}
|
||||||
_datagramProcessingThread->quit();
|
|
||||||
_datagramProcessingThread->wait();
|
|
||||||
|
|
||||||
// set node socket parent back to NodeList
|
// stop processing datagrams from the node socket
|
||||||
nodeList->getNodeSocket().setParent(nodeList.data());
|
// this ensures we won't process a domain list while we are going down
|
||||||
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
|
disconnect(&nodeList->getNodeSocket(), 0, this, 0);
|
||||||
|
|
||||||
|
// call our virtual aboutToFinish method - this gives the ThreadedAssignment subclass a chance to cleanup
|
||||||
|
aboutToFinish();
|
||||||
|
|
||||||
|
// if we have a datagram processing thread, quit it and wait on it to make sure that
|
||||||
|
// the node socket is back on the same thread as the NodeList
|
||||||
|
|
||||||
|
if (_datagramProcessingThread) {
|
||||||
|
// tell the datagram processing thread to quit and wait until it is done,
|
||||||
|
// then return the node socket to the NodeList
|
||||||
|
_datagramProcessingThread->quit();
|
||||||
|
_datagramProcessingThread->wait();
|
||||||
|
|
||||||
|
// set node socket parent back to NodeList
|
||||||
|
nodeList->getNodeSocket().setParent(nodeList.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
// move the NodeList back to the QCoreApplication instance's thread
|
||||||
|
nodeList->moveToThread(QCoreApplication::instance()->thread());
|
||||||
|
|
||||||
|
emit finished();
|
||||||
}
|
}
|
||||||
|
|
||||||
// move the NodeList back to the QCoreApplication instance's thread
|
|
||||||
nodeList->moveToThread(QCoreApplication::instance()->thread());
|
|
||||||
|
|
||||||
emit finished();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ class ThreadedAssignment : public Assignment {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
ThreadedAssignment(const QByteArray& packet);
|
ThreadedAssignment(const QByteArray& packet);
|
||||||
|
~ThreadedAssignment() { stop(); }
|
||||||
|
|
||||||
void setFinished(bool isFinished);
|
void setFinished(bool isFinished);
|
||||||
virtual void aboutToFinish() { };
|
virtual void aboutToFinish() { };
|
||||||
|
@ -32,11 +33,6 @@ public slots:
|
||||||
virtual void readPendingDatagrams() = 0;
|
virtual void readPendingDatagrams() = 0;
|
||||||
virtual void sendStatsPacket();
|
virtual void sendStatsPacket();
|
||||||
|
|
||||||
public slots:
|
|
||||||
virtual void aboutToQuit() {
|
|
||||||
QMetaObject::invokeMethod(this, "stop");
|
|
||||||
}
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void finished();
|
void finished();
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,9 @@ void GenericThread::initialize(bool isThreaded) {
|
||||||
if (_isThreaded) {
|
if (_isThreaded) {
|
||||||
_thread = new QThread(this);
|
_thread = new QThread(this);
|
||||||
|
|
||||||
|
// match the thread name to our object name
|
||||||
|
_thread->setObjectName(objectName());
|
||||||
|
|
||||||
// when the worker thread is started, call our engine's run..
|
// when the worker thread is started, call our engine's run..
|
||||||
connect(_thread, SIGNAL(started()), this, SLOT(threadRoutine()));
|
connect(_thread, SIGNAL(started()), this, SLOT(threadRoutine()));
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@ namespace Setting {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets up the settings private instance. Should only be run once at startup
|
// Sets up the settings private instance. Should only be run once at startup
|
||||||
void setupPrivateInstance() {
|
void init() {
|
||||||
// read the ApplicationInfo.ini file for Name/Version/Domain information
|
// read the ApplicationInfo.ini file for Name/Version/Domain information
|
||||||
QSettings::setDefaultFormat(QSettings::IniFormat);
|
QSettings::setDefaultFormat(QSettings::IniFormat);
|
||||||
QSettings applicationInfo(PathUtils::resourcesPath() + "info/ApplicationInfo.ini", QSettings::IniFormat);
|
QSettings applicationInfo(PathUtils::resourcesPath() + "info/ApplicationInfo.ini", QSettings::IniFormat);
|
||||||
|
@ -59,14 +59,11 @@ namespace Setting {
|
||||||
QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
|
QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
|
||||||
privateInstance->moveToThread(thread);
|
privateInstance->moveToThread(thread);
|
||||||
thread->start();
|
thread->start();
|
||||||
qCDebug(shared) << "Settings thread started.";
|
qCDebug(shared) << "Settings thread started.";
|
||||||
|
|
||||||
// Register cleanupPrivateInstance to run inside QCoreApplication's destructor.
|
// Register cleanupPrivateInstance to run inside QCoreApplication's destructor.
|
||||||
qAddPostRoutine(cleanupPrivateInstance);
|
qAddPostRoutine(cleanupPrivateInstance);
|
||||||
}
|
}
|
||||||
// Register setupPrivateInstance to run after QCoreApplication's constructor.
|
|
||||||
Q_COREAPP_STARTUP_FUNCTION(setupPrivateInstance)
|
|
||||||
|
|
||||||
|
|
||||||
Interface::~Interface() {
|
Interface::~Interface() {
|
||||||
if (privateInstance) {
|
if (privateInstance) {
|
||||||
|
@ -76,16 +73,20 @@ namespace Setting {
|
||||||
|
|
||||||
void Interface::init() {
|
void Interface::init() {
|
||||||
if (!privateInstance) {
|
if (!privateInstance) {
|
||||||
qWarning() << "Setting::Interface::init(): Manager not yet created, bailing";
|
// WARNING: As long as we are using QSettings this should always be triggered for each Setting::Handle
|
||||||
return;
|
// in an assignment-client - the QSettings backing we use for this means persistence of these
|
||||||
|
// settings from an AC (when there can be multiple terminating at same time on one machine)
|
||||||
|
// is currently not supported
|
||||||
|
qWarning() << "Setting::Interface::init() for key" << _key << "- Manager not yet created." <<
|
||||||
|
"Settings persistence disabled.";
|
||||||
|
} else {
|
||||||
|
// Register Handle
|
||||||
|
privateInstance->registerHandle(this);
|
||||||
|
_isInitialized = true;
|
||||||
|
|
||||||
|
// Load value from disk
|
||||||
|
load();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register Handle
|
|
||||||
privateInstance->registerHandle(this);
|
|
||||||
_isInitialized = true;
|
|
||||||
|
|
||||||
// Load value from disk
|
|
||||||
load();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interface::maybeInit() {
|
void Interface::maybeInit() {
|
||||||
|
|
|
@ -16,11 +16,14 @@
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
|
|
||||||
namespace Setting {
|
namespace Setting {
|
||||||
|
void init();
|
||||||
|
void cleanupSettings();
|
||||||
|
|
||||||
class Interface {
|
class Interface {
|
||||||
public:
|
public:
|
||||||
QString getKey() const { return _key; }
|
QString getKey() const { return _key; }
|
||||||
bool isSet() const { return _isSet; }
|
bool isSet() const { return _isSet; }
|
||||||
|
|
||||||
virtual void setVariant(const QVariant& variant) = 0;
|
virtual void setVariant(const QVariant& variant) = 0;
|
||||||
virtual QVariant getVariant() = 0;
|
virtual QVariant getVariant() = 0;
|
||||||
|
|
||||||
|
|
|
@ -18,11 +18,12 @@ namespace Setting {
|
||||||
Manager::~Manager() {
|
Manager::~Manager() {
|
||||||
// Cleanup timer
|
// Cleanup timer
|
||||||
stopTimer();
|
stopTimer();
|
||||||
disconnect(_saveTimer, 0, 0, 0);
|
delete _saveTimer;
|
||||||
|
|
||||||
// Save all settings before exit
|
// Save all settings before exit
|
||||||
saveAll();
|
saveAll();
|
||||||
sync();
|
|
||||||
|
// sync will be called in the QSettings destructor
|
||||||
}
|
}
|
||||||
|
|
||||||
void Manager::registerHandle(Setting::Interface* handle) {
|
void Manager::registerHandle(Setting::Interface* handle) {
|
||||||
|
|
Loading…
Reference in a new issue