From 02fd9987c7a6d340e0f5b207b3a07499974529df Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 28 Apr 2015 18:38:41 -0700 Subject: [PATCH 1/8] rework audio mixer so it can exit cleanly --- assignment-client/src/AssignmentClient.cpp | 12 +- assignment-client/src/AssignmentClient.h | 3 + assignment-client/src/AssignmentClientApp.cpp | 6 + .../src/AssignmentClientMonitor.cpp | 6 + .../src/AssignmentClientMonitor.h | 3 + assignment-client/src/audio/AudioMixer.cpp | 159 ++++++++++-------- assignment-client/src/audio/AudioMixer.h | 10 ++ libraries/networking/src/LimitedNodeList.h | 4 + .../networking/src/ThreadedAssignment.cpp | 23 ++- libraries/networking/src/ThreadedAssignment.h | 10 ++ 10 files changed, 155 insertions(+), 81 deletions(-) diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index a0da273462..5a6868e7e4 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -114,7 +114,16 @@ void AssignmentClient::stopAssignmentClient() { qDebug() << "Exiting."; _requestTimer.stop(); _statsTimerACM.stop(); - QCoreApplication::quit(); + if (_currentAssignment) { + _currentAssignment->aboutToQuit(); + // _currentAssignment->aboutToFinish(); + _currentAssignment->thread()->wait(); + } +} + + +void AssignmentClient::aboutToQuit() { + stopAssignmentClient(); } @@ -197,6 +206,7 @@ void AssignmentClient::readPendingDatagrams() { // start the deployed assignment AssignmentThread* workerThread = new AssignmentThread(_currentAssignment, this); + workerThread->setObjectName("worker"); connect(workerThread, &QThread::started, _currentAssignment.data(), &ThreadedAssignment::run); connect(_currentAssignment.data(), &ThreadedAssignment::finished, workerThread, &QThread::quit); diff --git a/assignment-client/src/AssignmentClient.h b/assignment-client/src/AssignmentClient.h index 08673ab04c..1ffb862dd3 100644 --- a/assignment-client/src/AssignmentClient.h +++ b/assignment-client/src/AssignmentClient.h @@ -34,6 +34,9 @@ private slots: void sendStatsPacketToACM(); void stopAssignmentClient(); +public slots: + void aboutToQuit(); + private: void setUpStatsToMonitor(int ppid); Assignment _requestAssignment; diff --git a/assignment-client/src/AssignmentClientApp.cpp b/assignment-client/src/AssignmentClientApp.cpp index 17f2eac70d..2fcbd67be1 100644 --- a/assignment-client/src/AssignmentClientApp.cpp +++ b/assignment-client/src/AssignmentClientApp.cpp @@ -10,6 +10,7 @@ // #include +#include #include #include @@ -180,14 +181,19 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : } } + QThread::currentThread()->setObjectName("main thread"); if (numForks || minForks || maxForks) { AssignmentClientMonitor monitor(numForks, minForks, maxForks, requestAssignmentType, assignmentPool, walletUUID, assignmentServerHostname, assignmentServerPort); + connect(this, &QCoreApplication::aboutToQuit, &monitor, &AssignmentClientMonitor::aboutToQuit); + + exec(); } else { AssignmentClient client(ppid, requestAssignmentType, assignmentPool, walletUUID, assignmentServerHostname, assignmentServerPort); + connect(this, &QCoreApplication::aboutToQuit, &client, &AssignmentClient::aboutToQuit); exec(); } } diff --git a/assignment-client/src/AssignmentClientMonitor.cpp b/assignment-client/src/AssignmentClientMonitor.cpp index d591087acd..14eb93ad6e 100644 --- a/assignment-client/src/AssignmentClientMonitor.cpp +++ b/assignment-client/src/AssignmentClientMonitor.cpp @@ -80,6 +80,12 @@ void AssignmentClientMonitor::stopChildProcesses() { }); } + +void AssignmentClientMonitor::aboutToQuit() { + stopChildProcesses(); +} + + void AssignmentClientMonitor::spawnChildClient() { QProcess *assignmentClient = new QProcess(this); diff --git a/assignment-client/src/AssignmentClientMonitor.h b/assignment-client/src/AssignmentClientMonitor.h index 996220b1b4..23f50ef67d 100644 --- a/assignment-client/src/AssignmentClientMonitor.h +++ b/assignment-client/src/AssignmentClientMonitor.h @@ -38,6 +38,9 @@ private slots: void readPendingDatagrams(); void checkSpares(); +public slots: + void aboutToQuit(); + private: void spawnChildClient(); QTimer _checkSparesTimer; // every few seconds see if it need fewer or more spare children diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 06e6f77f69..5d7601ba55 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -588,7 +588,6 @@ void AudioMixer::sendStatsPacket() { _sumMixes = 0; _numStatFrames = 0; - // NOTE: These stats can be too large to fit in an MTU, so we break it up into multiple packts... QJsonObject statsObject2; @@ -712,78 +711,90 @@ void AudioMixer::run() { // check the settings object to see if we have anything we can parse out parseSettingsObject(settingsObject); - int nextFrame = 0; - QElapsedTimer timer; - timer.start(); + _nextFrame = 0; + _timer.start(); - char clientMixBuffer[MAX_PACKET_SIZE]; - - int usecToSleep = AudioConstants::NETWORK_FRAME_USECS; - - const int TRAILING_AVERAGE_FRAMES = 100; - int framesSinceCutoffEvent = TRAILING_AVERAGE_FRAMES; + _idleTimer = new QTimer(); + connect(_idleTimer, SIGNAL(timeout()), this, SLOT(insideLoop())); + _idleTimer->start(0); +} - while (!_isFinished) { - const float STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.10f; - const float BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.20f; + +void AudioMixer::insideLoop() { + if (_isFinished) { + qDebug() << "AudioMixer::insideLoop stoping _idleTimer"; + _idleTimer->stop(); + delete _idleTimer; + _idleTimer = nullptr; + + QThread *thisThread = QThread::currentThread(); + thisThread->quit(); + + return; + } + + auto nodeList = DependencyManager::get(); + + const float STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.10f; + const float BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.20f; - const float RATIO_BACK_OFF = 0.02f; + const float RATIO_BACK_OFF = 0.02f; - const float CURRENT_FRAME_RATIO = 1.0f / TRAILING_AVERAGE_FRAMES; - const float PREVIOUS_FRAMES_RATIO = 1.0f - CURRENT_FRAME_RATIO; + const float CURRENT_FRAME_RATIO = 1.0f / TRAILING_AVERAGE_FRAMES; + const float PREVIOUS_FRAMES_RATIO = 1.0f - CURRENT_FRAME_RATIO; - if (usecToSleep < 0) { - usecToSleep = 0; - } + if (_usecToSleep < 0) { + _usecToSleep = 0; + } - _trailingSleepRatio = (PREVIOUS_FRAMES_RATIO * _trailingSleepRatio) - + (usecToSleep * CURRENT_FRAME_RATIO / (float) AudioConstants::NETWORK_FRAME_USECS); + _trailingSleepRatio = (PREVIOUS_FRAMES_RATIO * _trailingSleepRatio) + + (_usecToSleep * CURRENT_FRAME_RATIO / (float) AudioConstants::NETWORK_FRAME_USECS); - float lastCutoffRatio = _performanceThrottlingRatio; - bool hasRatioChanged = false; + float lastCutoffRatio = _performanceThrottlingRatio; + bool hasRatioChanged = false; - if (framesSinceCutoffEvent >= TRAILING_AVERAGE_FRAMES) { - if (_trailingSleepRatio <= STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD) { - // we're struggling - change our min required loudness to reduce some load - _performanceThrottlingRatio = _performanceThrottlingRatio + (0.5f * (1.0f - _performanceThrottlingRatio)); + if (_framesSinceCutoffEvent >= TRAILING_AVERAGE_FRAMES) { + if (_trailingSleepRatio <= STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD) { + // we're struggling - change our min required loudness to reduce some load + _performanceThrottlingRatio = _performanceThrottlingRatio + (0.5f * (1.0f - _performanceThrottlingRatio)); - qDebug() << "Mixer is struggling, sleeping" << _trailingSleepRatio * 100 << "% of frame time. Old cutoff was" - << lastCutoffRatio << "and is now" << _performanceThrottlingRatio; - hasRatioChanged = true; - } else if (_trailingSleepRatio >= BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD && _performanceThrottlingRatio != 0) { - // we've recovered and can back off the required loudness - _performanceThrottlingRatio = _performanceThrottlingRatio - RATIO_BACK_OFF; + qDebug() << "Mixer is struggling, sleeping" << _trailingSleepRatio * 100 << "% of frame time. Old cutoff was" + << lastCutoffRatio << "and is now" << _performanceThrottlingRatio; + hasRatioChanged = true; + } else if (_trailingSleepRatio >= BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD && _performanceThrottlingRatio != 0) { + // we've recovered and can back off the required loudness + _performanceThrottlingRatio = _performanceThrottlingRatio - RATIO_BACK_OFF; - if (_performanceThrottlingRatio < 0) { - _performanceThrottlingRatio = 0; - } - - qDebug() << "Mixer is recovering, sleeping" << _trailingSleepRatio * 100 << "% of frame time. Old cutoff was" - << lastCutoffRatio << "and is now" << _performanceThrottlingRatio; - hasRatioChanged = true; + if (_performanceThrottlingRatio < 0) { + _performanceThrottlingRatio = 0; } - - if (hasRatioChanged) { - // set out min audability threshold from the new ratio - _minAudibilityThreshold = LOUDNESS_TO_DISTANCE_RATIO / (2.0f * (1.0f - _performanceThrottlingRatio)); - qDebug() << "Minimum audability required to be mixed is now" << _minAudibilityThreshold; - framesSinceCutoffEvent = 0; - } + qDebug() << "Mixer is recovering, sleeping" << _trailingSleepRatio * 100 << "% of frame time. Old cutoff was" + << lastCutoffRatio << "and is now" << _performanceThrottlingRatio; + hasRatioChanged = true; } - - if (!hasRatioChanged) { - ++framesSinceCutoffEvent; - } - - quint64 now = usecTimestampNow(); - if (now - _lastPerSecondCallbackTime > USECS_PER_SECOND) { - perSecondActions(); - _lastPerSecondCallbackTime = now; - } - - nodeList->eachNode([&](const SharedNodePointer& node) { + if (hasRatioChanged) { + // set out min audability threshold from the new ratio + _minAudibilityThreshold = LOUDNESS_TO_DISTANCE_RATIO / (2.0f * (1.0f - _performanceThrottlingRatio)); + qDebug() << "Minimum audability required to be mixed is now" << _minAudibilityThreshold; + + _framesSinceCutoffEvent = 0; + } + } + + if (!hasRatioChanged) { + ++_framesSinceCutoffEvent; + } + + quint64 now = usecTimestampNow(); + if (now - _lastPerSecondCallbackTime > USECS_PER_SECOND) { + perSecondActions(); + _lastPerSecondCallbackTime = now; + } + + nodeList->eachNode([&](const SharedNodePointer& node) { + if (node->getLinkedData()) { AudioMixerClientData* nodeData = (AudioMixerClientData*)node->getLinkedData(); @@ -807,8 +818,8 @@ void AudioMixer::run() { char* mixDataAt; if (streamsMixed > 0) { // pack header - int numBytesMixPacketHeader = populatePacketHeader(clientMixBuffer, PacketTypeMixedAudio); - mixDataAt = clientMixBuffer + numBytesMixPacketHeader; + int numBytesMixPacketHeader = populatePacketHeader(_clientMixBuffer, PacketTypeMixedAudio); + mixDataAt = _clientMixBuffer + numBytesMixPacketHeader; // pack sequence number quint16 sequence = nodeData->getOutgoingSequenceNumber(); @@ -820,8 +831,8 @@ void AudioMixer::run() { mixDataAt += AudioConstants::NETWORK_FRAME_BYTES_STEREO; } else { // pack header - int numBytesPacketHeader = populatePacketHeader(clientMixBuffer, PacketTypeSilentAudioFrame); - mixDataAt = clientMixBuffer + numBytesPacketHeader; + int numBytesPacketHeader = populatePacketHeader(_clientMixBuffer, PacketTypeSilentAudioFrame); + mixDataAt = _clientMixBuffer + numBytesPacketHeader; // pack sequence number quint16 sequence = nodeData->getOutgoingSequenceNumber(); @@ -833,12 +844,12 @@ void AudioMixer::run() { memcpy(mixDataAt, &numSilentSamples, sizeof(quint16)); mixDataAt += sizeof(quint16); } - + // Send audio environment sendAudioEnvironmentPacket(node); // send mixed audio packet - nodeList->writeDatagram(clientMixBuffer, mixDataAt - clientMixBuffer, node); + nodeList->writeDatagram(_clientMixBuffer, mixDataAt - _clientMixBuffer, node); nodeData->incrementOutgoingMixedAudioSequenceNumber(); // send an audio stream stats packet if it's time @@ -852,22 +863,22 @@ void AudioMixer::run() { } }); - ++_numStatFrames; + ++_numStatFrames; - QCoreApplication::processEvents(); + QCoreApplication::processEvents(); - if (_isFinished) { - break; - } + if (_isFinished) { + return; + } - usecToSleep = (++nextFrame * AudioConstants::NETWORK_FRAME_USECS) - timer.nsecsElapsed() / 1000; // ns to us + _usecToSleep = (++_nextFrame * AudioConstants::NETWORK_FRAME_USECS) - _timer.nsecsElapsed() / 1000; // ns to us - if (usecToSleep > 0) { - usleep(usecToSleep); - } + if (_usecToSleep > 0) { + usleep(_usecToSleep); } } + void AudioMixer::perSecondActions() { _sendAudioStreamStats = true; diff --git a/assignment-client/src/audio/AudioMixer.h b/assignment-client/src/audio/AudioMixer.h index 6cee557ff9..a81225a0f2 100644 --- a/assignment-client/src/audio/AudioMixer.h +++ b/assignment-client/src/audio/AudioMixer.h @@ -32,6 +32,7 @@ public: public slots: /// threaded run of assignment void run(); + void insideLoop(); void readPendingDatagrams() { }; // this will not be called since our datagram processing thread will handle void readPendingDatagram(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr); @@ -110,6 +111,15 @@ private: MovingMinMaxAvg _timeSpentPerHashMatchCallStats; // update with usecs spent inside each packetVersionAndHashMatch call MovingMinMaxAvg _readPendingCallsPerSecondStats; // update with # of readPendingDatagrams calls in the last second + + // loop variables + QTimer* _idleTimer = nullptr; + int _nextFrame = 0; + QElapsedTimer _timer; + char _clientMixBuffer[MAX_PACKET_SIZE]; + int _usecToSleep = AudioConstants::NETWORK_FRAME_USECS; + const int TRAILING_AVERAGE_FRAMES = 100; + int _framesSinceCutoffEvent = TRAILING_AVERAGE_FRAMES; }; #endif // hifi_AudioMixer_h diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index 80ceccc407..cd45fbdbdf 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -221,6 +221,10 @@ protected: LimitedNodeList(unsigned short socketListenPort = 0, unsigned short dtlsListenPort = 0); LimitedNodeList(LimitedNodeList const&); // Don't implement, needed to avoid copies of singleton void operator=(LimitedNodeList const&); // Don't implement, needed to avoid copies of singleton + + ~LimitedNodeList() { + qDebug() << "XXXXXXXXXXXXXXXXXXXX ~LimitedNodeList called"; + } qint64 writeDatagram(const QByteArray& datagram, const HifiSockAddr& destinationSockAddr, const QUuid& connectionSecret); diff --git a/libraries/networking/src/ThreadedAssignment.cpp b/libraries/networking/src/ThreadedAssignment.cpp index 79b4e7f437..eda3da8479 100644 --- a/libraries/networking/src/ThreadedAssignment.cpp +++ b/libraries/networking/src/ThreadedAssignment.cpp @@ -30,6 +30,17 @@ void ThreadedAssignment::setFinished(bool isFinished) { _isFinished = isFinished; if (_isFinished) { + if (_domainServerTimer) { + _domainServerTimer->stop(); + delete _domainServerTimer; + _domainServerTimer = nullptr; + } + if (_statsTimer) { + _statsTimer->stop(); + delete _statsTimer; + _statsTimer = nullptr; + } + aboutToFinish(); auto nodeList = DependencyManager::get(); @@ -63,15 +74,15 @@ void ThreadedAssignment::commonInit(const QString& targetName, NodeType_t nodeTy // this is a temp fix for Qt 5.3 - rebinding the node socket gives us readyRead for the socket on this thread nodeList->rebindNodeSocket(); - QTimer* domainServerTimer = new QTimer(this); - connect(domainServerTimer, SIGNAL(timeout()), this, SLOT(checkInWithDomainServerOrExit())); - domainServerTimer->start(DOMAIN_SERVER_CHECK_IN_MSECS); + _domainServerTimer = new QTimer(this); + connect(_domainServerTimer, SIGNAL(timeout()), this, SLOT(checkInWithDomainServerOrExit())); + _domainServerTimer->start(DOMAIN_SERVER_CHECK_IN_MSECS); if (shouldSendStats) { // send a stats packet every 1 second - QTimer* statsTimer = new QTimer(this); - connect(statsTimer, &QTimer::timeout, this, &ThreadedAssignment::sendStatsPacket); - statsTimer->start(1000); + _statsTimer = new QTimer(this); + connect(_statsTimer, &QTimer::timeout, this, &ThreadedAssignment::sendStatsPacket); + _statsTimer->start(1000); } } diff --git a/libraries/networking/src/ThreadedAssignment.h b/libraries/networking/src/ThreadedAssignment.h index 454baa85f2..04bee08e62 100644 --- a/libraries/networking/src/ThreadedAssignment.h +++ b/libraries/networking/src/ThreadedAssignment.h @@ -28,8 +28,16 @@ public: public slots: /// threaded run of assignment virtual void run() = 0; + Q_INVOKABLE void stop() { setFinished(true); } virtual void readPendingDatagrams() = 0; virtual void sendStatsPacket(); + +public slots: + virtual void aboutToQuit() { + // emit finished(); + QMetaObject::invokeMethod(this, "stop"); + } + signals: void finished(); @@ -38,6 +46,8 @@ protected: void commonInit(const QString& targetName, NodeType_t nodeType, bool shouldSendStats = true); bool _isFinished; QThread* _datagramProcessingThread; + QTimer* _domainServerTimer = nullptr; + QTimer* _statsTimer = nullptr; private slots: void checkInWithDomainServerOrExit(); From d2cd4fc405f21691855099b8043a03f52f52cdb8 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 29 Apr 2015 11:56:45 -0700 Subject: [PATCH 2/8] types 0 and 1 exit cleanly, type 6 crashes --- assignment-client/src/AssignmentClient.cpp | 7 +- assignment-client/src/AssignmentClientApp.cpp | 2 + assignment-client/src/audio/AudioMixer.cpp | 153 ++++++++---------- assignment-client/src/audio/AudioMixer.h | 17 +- assignment-client/src/avatars/AvatarMixer.cpp | 32 +++- assignment-client/src/avatars/AvatarMixer.h | 5 + .../src/entities/EntityServer.cpp | 22 ++- assignment-client/src/entities/EntityServer.h | 2 + .../src/octree/OctreeInboundPacketProcessor.h | 3 +- assignment-client/src/octree/OctreeServer.cpp | 39 ++++- assignment-client/src/octree/OctreeServer.h | 1 + .../networking/src/ReceivedPacketProcessor.h | 4 +- .../networking/src/ThreadedAssignment.cpp | 18 +++ libraries/networking/src/ThreadedAssignment.h | 6 +- libraries/octree/src/OctreePersistThread.cpp | 1 + libraries/shared/src/DependencyManager.h | 10 +- 16 files changed, 211 insertions(+), 111 deletions(-) diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index 5a6868e7e4..dc4d06e52e 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -116,8 +116,11 @@ void AssignmentClient::stopAssignmentClient() { _statsTimerACM.stop(); if (_currentAssignment) { _currentAssignment->aboutToQuit(); - // _currentAssignment->aboutToFinish(); - _currentAssignment->thread()->wait(); + QThread* currentAssignmentThread = _currentAssignment->thread(); + qDebug() << "main thread waiting on _currentAssignment->thread()" << currentAssignmentThread->objectName(); + currentAssignmentThread->quit(); + currentAssignmentThread->wait(); + qDebug() << "done waiting."; } } diff --git a/assignment-client/src/AssignmentClientApp.cpp b/assignment-client/src/AssignmentClientApp.cpp index 2fcbd67be1..c234daac68 100644 --- a/assignment-client/src/AssignmentClientApp.cpp +++ b/assignment-client/src/AssignmentClientApp.cpp @@ -183,6 +183,8 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : QThread::currentThread()->setObjectName("main thread"); + DependencyManager::registerInheritance(); + if (numForks || minForks || maxForks) { AssignmentClientMonitor monitor(numForks, minForks, maxForks, requestAssignmentType, assignmentPool, walletUUID, assignmentServerHostname, assignmentServerPort); diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 5d7601ba55..06e6f77f69 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -588,6 +588,7 @@ void AudioMixer::sendStatsPacket() { _sumMixes = 0; _numStatFrames = 0; + // NOTE: These stats can be too large to fit in an MTU, so we break it up into multiple packts... QJsonObject statsObject2; @@ -711,90 +712,78 @@ void AudioMixer::run() { // check the settings object to see if we have anything we can parse out parseSettingsObject(settingsObject); - _nextFrame = 0; - _timer.start(); + int nextFrame = 0; + QElapsedTimer timer; + timer.start(); - _idleTimer = new QTimer(); - connect(_idleTimer, SIGNAL(timeout()), this, SLOT(insideLoop())); - _idleTimer->start(0); -} + char clientMixBuffer[MAX_PACKET_SIZE]; + + int usecToSleep = AudioConstants::NETWORK_FRAME_USECS; + + const int TRAILING_AVERAGE_FRAMES = 100; + int framesSinceCutoffEvent = TRAILING_AVERAGE_FRAMES; - -void AudioMixer::insideLoop() { - if (_isFinished) { - qDebug() << "AudioMixer::insideLoop stoping _idleTimer"; - _idleTimer->stop(); - delete _idleTimer; - _idleTimer = nullptr; - - QThread *thisThread = QThread::currentThread(); - thisThread->quit(); - - return; - } - - auto nodeList = DependencyManager::get(); - - const float STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.10f; - const float BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.20f; + while (!_isFinished) { + const float STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.10f; + const float BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.20f; - const float RATIO_BACK_OFF = 0.02f; + const float RATIO_BACK_OFF = 0.02f; - const float CURRENT_FRAME_RATIO = 1.0f / TRAILING_AVERAGE_FRAMES; - const float PREVIOUS_FRAMES_RATIO = 1.0f - CURRENT_FRAME_RATIO; + const float CURRENT_FRAME_RATIO = 1.0f / TRAILING_AVERAGE_FRAMES; + const float PREVIOUS_FRAMES_RATIO = 1.0f - CURRENT_FRAME_RATIO; - if (_usecToSleep < 0) { - _usecToSleep = 0; - } + if (usecToSleep < 0) { + usecToSleep = 0; + } - _trailingSleepRatio = (PREVIOUS_FRAMES_RATIO * _trailingSleepRatio) - + (_usecToSleep * CURRENT_FRAME_RATIO / (float) AudioConstants::NETWORK_FRAME_USECS); + _trailingSleepRatio = (PREVIOUS_FRAMES_RATIO * _trailingSleepRatio) + + (usecToSleep * CURRENT_FRAME_RATIO / (float) AudioConstants::NETWORK_FRAME_USECS); - float lastCutoffRatio = _performanceThrottlingRatio; - bool hasRatioChanged = false; + float lastCutoffRatio = _performanceThrottlingRatio; + bool hasRatioChanged = false; - if (_framesSinceCutoffEvent >= TRAILING_AVERAGE_FRAMES) { - if (_trailingSleepRatio <= STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD) { - // we're struggling - change our min required loudness to reduce some load - _performanceThrottlingRatio = _performanceThrottlingRatio + (0.5f * (1.0f - _performanceThrottlingRatio)); + if (framesSinceCutoffEvent >= TRAILING_AVERAGE_FRAMES) { + if (_trailingSleepRatio <= STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD) { + // we're struggling - change our min required loudness to reduce some load + _performanceThrottlingRatio = _performanceThrottlingRatio + (0.5f * (1.0f - _performanceThrottlingRatio)); - qDebug() << "Mixer is struggling, sleeping" << _trailingSleepRatio * 100 << "% of frame time. Old cutoff was" - << lastCutoffRatio << "and is now" << _performanceThrottlingRatio; - hasRatioChanged = true; - } else if (_trailingSleepRatio >= BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD && _performanceThrottlingRatio != 0) { - // we've recovered and can back off the required loudness - _performanceThrottlingRatio = _performanceThrottlingRatio - RATIO_BACK_OFF; + qDebug() << "Mixer is struggling, sleeping" << _trailingSleepRatio * 100 << "% of frame time. Old cutoff was" + << lastCutoffRatio << "and is now" << _performanceThrottlingRatio; + hasRatioChanged = true; + } else if (_trailingSleepRatio >= BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD && _performanceThrottlingRatio != 0) { + // we've recovered and can back off the required loudness + _performanceThrottlingRatio = _performanceThrottlingRatio - RATIO_BACK_OFF; - if (_performanceThrottlingRatio < 0) { - _performanceThrottlingRatio = 0; + if (_performanceThrottlingRatio < 0) { + _performanceThrottlingRatio = 0; + } + + qDebug() << "Mixer is recovering, sleeping" << _trailingSleepRatio * 100 << "% of frame time. Old cutoff was" + << lastCutoffRatio << "and is now" << _performanceThrottlingRatio; + hasRatioChanged = true; } - - qDebug() << "Mixer is recovering, sleeping" << _trailingSleepRatio * 100 << "% of frame time. Old cutoff was" - << lastCutoffRatio << "and is now" << _performanceThrottlingRatio; - hasRatioChanged = true; - } - if (hasRatioChanged) { - // set out min audability threshold from the new ratio - _minAudibilityThreshold = LOUDNESS_TO_DISTANCE_RATIO / (2.0f * (1.0f - _performanceThrottlingRatio)); - qDebug() << "Minimum audability required to be mixed is now" << _minAudibilityThreshold; + if (hasRatioChanged) { + // set out min audability threshold from the new ratio + _minAudibilityThreshold = LOUDNESS_TO_DISTANCE_RATIO / (2.0f * (1.0f - _performanceThrottlingRatio)); + qDebug() << "Minimum audability required to be mixed is now" << _minAudibilityThreshold; - _framesSinceCutoffEvent = 0; + framesSinceCutoffEvent = 0; + } } - } - if (!hasRatioChanged) { - ++_framesSinceCutoffEvent; - } + if (!hasRatioChanged) { + ++framesSinceCutoffEvent; + } - quint64 now = usecTimestampNow(); - if (now - _lastPerSecondCallbackTime > USECS_PER_SECOND) { - perSecondActions(); - _lastPerSecondCallbackTime = now; - } + quint64 now = usecTimestampNow(); + if (now - _lastPerSecondCallbackTime > USECS_PER_SECOND) { + perSecondActions(); + _lastPerSecondCallbackTime = now; + } - nodeList->eachNode([&](const SharedNodePointer& node) { - + nodeList->eachNode([&](const SharedNodePointer& node) { + if (node->getLinkedData()) { AudioMixerClientData* nodeData = (AudioMixerClientData*)node->getLinkedData(); @@ -818,8 +807,8 @@ void AudioMixer::insideLoop() { char* mixDataAt; if (streamsMixed > 0) { // pack header - int numBytesMixPacketHeader = populatePacketHeader(_clientMixBuffer, PacketTypeMixedAudio); - mixDataAt = _clientMixBuffer + numBytesMixPacketHeader; + int numBytesMixPacketHeader = populatePacketHeader(clientMixBuffer, PacketTypeMixedAudio); + mixDataAt = clientMixBuffer + numBytesMixPacketHeader; // pack sequence number quint16 sequence = nodeData->getOutgoingSequenceNumber(); @@ -831,8 +820,8 @@ void AudioMixer::insideLoop() { mixDataAt += AudioConstants::NETWORK_FRAME_BYTES_STEREO; } else { // pack header - int numBytesPacketHeader = populatePacketHeader(_clientMixBuffer, PacketTypeSilentAudioFrame); - mixDataAt = _clientMixBuffer + numBytesPacketHeader; + int numBytesPacketHeader = populatePacketHeader(clientMixBuffer, PacketTypeSilentAudioFrame); + mixDataAt = clientMixBuffer + numBytesPacketHeader; // pack sequence number quint16 sequence = nodeData->getOutgoingSequenceNumber(); @@ -844,12 +833,12 @@ void AudioMixer::insideLoop() { memcpy(mixDataAt, &numSilentSamples, sizeof(quint16)); mixDataAt += sizeof(quint16); } - + // Send audio environment sendAudioEnvironmentPacket(node); // send mixed audio packet - nodeList->writeDatagram(_clientMixBuffer, mixDataAt - _clientMixBuffer, node); + nodeList->writeDatagram(clientMixBuffer, mixDataAt - clientMixBuffer, node); nodeData->incrementOutgoingMixedAudioSequenceNumber(); // send an audio stream stats packet if it's time @@ -863,22 +852,22 @@ void AudioMixer::insideLoop() { } }); - ++_numStatFrames; + ++_numStatFrames; - QCoreApplication::processEvents(); + QCoreApplication::processEvents(); - if (_isFinished) { - return; - } + if (_isFinished) { + break; + } - _usecToSleep = (++_nextFrame * AudioConstants::NETWORK_FRAME_USECS) - _timer.nsecsElapsed() / 1000; // ns to us + usecToSleep = (++nextFrame * AudioConstants::NETWORK_FRAME_USECS) - timer.nsecsElapsed() / 1000; // ns to us - if (_usecToSleep > 0) { - usleep(_usecToSleep); + if (usecToSleep > 0) { + usleep(usecToSleep); + } } } - void AudioMixer::perSecondActions() { _sendAudioStreamStats = true; diff --git a/assignment-client/src/audio/AudioMixer.h b/assignment-client/src/audio/AudioMixer.h index a81225a0f2..4894f91e01 100644 --- a/assignment-client/src/audio/AudioMixer.h +++ b/assignment-client/src/audio/AudioMixer.h @@ -32,7 +32,6 @@ public: public slots: /// threaded run of assignment void run(); - void insideLoop(); void readPendingDatagrams() { }; // this will not be called since our datagram processing thread will handle void readPendingDatagram(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr); @@ -112,14 +111,14 @@ private: MovingMinMaxAvg _readPendingCallsPerSecondStats; // update with # of readPendingDatagrams calls in the last second - // loop variables - QTimer* _idleTimer = nullptr; - int _nextFrame = 0; - QElapsedTimer _timer; - char _clientMixBuffer[MAX_PACKET_SIZE]; - int _usecToSleep = AudioConstants::NETWORK_FRAME_USECS; - const int TRAILING_AVERAGE_FRAMES = 100; - int _framesSinceCutoffEvent = TRAILING_AVERAGE_FRAMES; + /* // loop variables */ + /* // QTimer* _idleTimer = nullptr; */ + /* int _nextFrame = 0; */ + /* QElapsedTimer _timer; */ + /* char _clientMixBuffer[MAX_PACKET_SIZE]; */ + /* int _usecToSleep = AudioConstants::NETWORK_FRAME_USECS; */ + /* const int TRAILING_AVERAGE_FRAMES = 100; */ + /* int _framesSinceCutoffEvent = TRAILING_AVERAGE_FRAMES; */ }; #endif // hifi_AudioMixer_h diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index dae6af3fc5..8cff7d705d 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -45,6 +45,10 @@ AvatarMixer::AvatarMixer(const QByteArray& packet) : } AvatarMixer::~AvatarMixer() { + qDebug() << "AvatarMixer::~AvatarMixer"; + if (_broadcastTimer) { + _broadcastTimer->deleteLater(); + } _broadcastThread.quit(); _broadcastThread.wait(); } @@ -61,9 +65,7 @@ const float BILLBOARD_AND_IDENTITY_SEND_PROBABILITY = 1.0f / 300.0f; // 1) use the view frustum to cull those avatars that are out of view. Since avatar data doesn't need to be present // if the avatar is not in view or in the keyhole. void AvatarMixer::broadcastAvatarData() { - int idleTime = QDateTime::currentMSecsSinceEpoch() - _lastFrameTimestamp; - ++_numStatFrames; const float STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.10f; @@ -334,6 +336,22 @@ void AvatarMixer::sendStatsPacket() { _numStatFrames = 0; } +// void AvatarMixer::stop() { +// qDebug() << "AvatarMixer::stop"; +// if (_broadcastTimer) { +// // _broadcastTimer->stop(); +// // delete _broadcastTimer; +// _broadcastTimer->deleteLater(); +// // _broadcastTimer = nullptr; +// } + +// _broadcastThread.quit(); +// _broadcastThread.wait(); + +// ThreadedAssignment::stop(); +// } + + void AvatarMixer::run() { ThreadedAssignment::commonInit(AVATAR_MIXER_LOGGING_NAME, NodeType::AvatarMixer); @@ -343,13 +361,13 @@ void AvatarMixer::run() { nodeList->linkedDataCreateCallback = attachAvatarDataToNode; // setup the timer that will be fired on the broadcast thread - QTimer* broadcastTimer = new QTimer(); - broadcastTimer->setInterval(AVATAR_DATA_SEND_INTERVAL_MSECS); - broadcastTimer->moveToThread(&_broadcastThread); + _broadcastTimer = new QTimer(); + _broadcastTimer->setInterval(AVATAR_DATA_SEND_INTERVAL_MSECS); + _broadcastTimer->moveToThread(&_broadcastThread); // connect appropriate signals and slots - connect(broadcastTimer, &QTimer::timeout, this, &AvatarMixer::broadcastAvatarData, Qt::DirectConnection); - connect(&_broadcastThread, SIGNAL(started()), broadcastTimer, SLOT(start())); + connect(_broadcastTimer, &QTimer::timeout, this, &AvatarMixer::broadcastAvatarData, Qt::DirectConnection); + connect(&_broadcastThread, SIGNAL(started()), _broadcastTimer, SLOT(start())); // start the broadcastThread _broadcastThread.start(); diff --git a/assignment-client/src/avatars/AvatarMixer.h b/assignment-client/src/avatars/AvatarMixer.h index a69019427b..2a659cface 100644 --- a/assignment-client/src/avatars/AvatarMixer.h +++ b/assignment-client/src/avatars/AvatarMixer.h @@ -25,6 +25,7 @@ public: public slots: /// runs the avatar mixer void run(); + // Q_INVOKABLE virtual void stop(); void nodeAdded(SharedNodePointer nodeAdded); void nodeKilled(SharedNodePointer killedNode); @@ -32,6 +33,8 @@ public slots: void readPendingDatagrams(); void sendStatsPacket(); + + void finished(); private: void broadcastAvatarData(); @@ -47,6 +50,8 @@ private: int _numStatFrames; int _sumBillboardPackets; int _sumIdentityPackets; + + QTimer* _broadcastTimer = nullptr; }; #endif // hifi_AvatarMixer_h diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index 85d0a7414c..e38d0e3c65 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -27,6 +27,13 @@ EntityServer::EntityServer(const QByteArray& packet) } EntityServer::~EntityServer() { + qDebug() << "EntityServer::~EntityServer"; + + if (_pruneDeletedEntitiesTimer) { + _pruneDeletedEntitiesTimer->stop(); + _pruneDeletedEntitiesTimer->deleteLater(); + } + EntityTree* tree = (EntityTree*)_tree; tree->removeNewlyCreatedHook(this); } @@ -48,10 +55,10 @@ Octree* EntityServer::createTree() { } void EntityServer::beforeRun() { - QTimer* pruneDeletedEntitiesTimer = new QTimer(this); - connect(pruneDeletedEntitiesTimer, SIGNAL(timeout()), this, SLOT(pruneDeletedEntities())); + _pruneDeletedEntitiesTimer = new QTimer(this); + connect(_pruneDeletedEntitiesTimer, SIGNAL(timeout()), this, SLOT(pruneDeletedEntities())); const int PRUNE_DELETED_MODELS_INTERVAL_MSECS = 1 * 1000; // once every second - pruneDeletedEntitiesTimer->start(PRUNE_DELETED_MODELS_INTERVAL_MSECS); + _pruneDeletedEntitiesTimer->start(PRUNE_DELETED_MODELS_INTERVAL_MSECS); } void EntityServer::entityCreated(const EntityItem& newEntity, const SharedNodePointer& senderNode) { @@ -158,3 +165,12 @@ void EntityServer::readAdditionalConfiguration(const QJsonObject& settingsSectio } +// void EntityServer::stop() { +// qDebug() << "EntityServer::stop"; +// if (_pruneDeletedEntitiesTimer) { +// _pruneDeletedEntitiesTimer->stop(); +// delete _pruneDeletedEntitiesTimer; +// _pruneDeletedEntitiesTimer = nullptr; +// } +// OctreeServer::stop(); +// } diff --git a/assignment-client/src/entities/EntityServer.h b/assignment-client/src/entities/EntityServer.h index d8c2e39f3b..78c20d039c 100644 --- a/assignment-client/src/entities/EntityServer.h +++ b/assignment-client/src/entities/EntityServer.h @@ -44,6 +44,7 @@ public: virtual void readAdditionalConfiguration(const QJsonObject& settingsSectionObject); public slots: + // Q_INVOKABLE virtual void stop(); void pruneDeletedEntities(); protected: @@ -51,6 +52,7 @@ protected: private: EntitySimulation* _entitySimulation; + QTimer* _pruneDeletedEntitiesTimer = nullptr; }; #endif // hifi_EntityServer_h diff --git a/assignment-client/src/octree/OctreeInboundPacketProcessor.h b/assignment-client/src/octree/OctreeInboundPacketProcessor.h index 8f07f9d566..2f9c060183 100644 --- a/assignment-client/src/octree/OctreeInboundPacketProcessor.h +++ b/assignment-client/src/octree/OctreeInboundPacketProcessor.h @@ -74,7 +74,8 @@ public: NodeToSenderStatsMap& getSingleSenderStats() { return _singleSenderStats; } - void shuttingDown() { _shuttingDown = true;} + // void shuttingDown() { _shuttingDown = true;} + virtual void terminating() { _shuttingDown = true; ReceivedPacketProcessor::terminating(); } protected: diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 266183745f..725f4eda2c 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -266,16 +266,19 @@ OctreeServer::~OctreeServer() { } if (_jurisdictionSender) { + _jurisdictionSender->terminating(); _jurisdictionSender->terminate(); _jurisdictionSender->deleteLater(); } if (_octreeInboundPacketProcessor) { + _octreeInboundPacketProcessor->terminating(); _octreeInboundPacketProcessor->terminate(); _octreeInboundPacketProcessor->deleteLater(); } if (_persistThread) { + _persistThread->terminating(); _persistThread->terminate(); _persistThread->deleteLater(); } @@ -1219,7 +1222,7 @@ void OctreeServer::forceNodeShutdown(SharedNodePointer node) { void OctreeServer::aboutToFinish() { qDebug() << qPrintable(_safeServerName) << "server STARTING about to finish..."; qDebug() << qPrintable(_safeServerName) << "inform Octree Inbound Packet Processor that we are shutting down..."; - _octreeInboundPacketProcessor->shuttingDown(); + _octreeInboundPacketProcessor->terminating(); DependencyManager::get()->eachNode([this](const SharedNodePointer& node) { qDebug() << qPrintable(_safeServerName) << "server about to finish while node still connected node:" << *node; @@ -1233,6 +1236,40 @@ void OctreeServer::aboutToFinish() { qDebug() << qPrintable(_safeServerName) << "server ENDING about to finish..."; } + +// void OctreeServer::stop() { +// qDebug() << "OctreeServer::stop"; +// // setFinished(true); +// // QThread *thisThread = QThread::currentThread(); +// // thisThread->quit(); + +// if (_jurisdictionSender) { +// _jurisdictionSender->terminating(); +// _jurisdictionSender->terminate(); +// // delete _jurisdictionSender; +// // _jurisdictionSender = nullptr; +// } + +// _datagramProcessingThread->quit(); +// if (_octreeInboundPacketProcessor) { +// _octreeInboundPacketProcessor->terminating(); +// _octreeInboundPacketProcessor->terminate(); +// // delete _octreeInboundPacketProcessor; +// // _octreeInboundPacketProcessor = nullptr; +// } + +// // _persistThread +// if (_persistThread) { +// _persistThread->terminating(); +// _persistThread->terminate(); +// // delete _persistThread; +// // _persistThread = nullptr; +// } + +// ThreadedAssignment::stop(); +// } + + QString OctreeServer::getUptime() { QString formattedUptime; quint64 now = usecTimestampNow(); diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h index 41cd3259cf..10c4e81262 100644 --- a/assignment-client/src/octree/OctreeServer.h +++ b/assignment-client/src/octree/OctreeServer.h @@ -123,6 +123,7 @@ public: public slots: /// runs the octree server assignment void run(); + // Q_INVOKABLE virtual void stop(); void nodeAdded(SharedNodePointer node); void nodeKilled(SharedNodePointer node); void sendStatsPacket(); diff --git a/libraries/networking/src/ReceivedPacketProcessor.h b/libraries/networking/src/ReceivedPacketProcessor.h index d5fc006882..bcc9f9a1f5 100644 --- a/libraries/networking/src/ReceivedPacketProcessor.h +++ b/libraries/networking/src/ReceivedPacketProcessor.h @@ -47,6 +47,8 @@ public: /// How many received packets waiting are to be processed int packetsToProcessCount() const { return _packets.size(); } + virtual void terminating(); + public slots: void nodeKilled(SharedNodePointer node); @@ -71,8 +73,6 @@ protected: /// Override to do work after the packets processing loop. Default does nothing. virtual void postProcess() { } - virtual void terminating(); - protected: QVector _packets; diff --git a/libraries/networking/src/ThreadedAssignment.cpp b/libraries/networking/src/ThreadedAssignment.cpp index eda3da8479..c212aab188 100644 --- a/libraries/networking/src/ThreadedAssignment.cpp +++ b/libraries/networking/src/ThreadedAssignment.cpp @@ -26,7 +26,14 @@ ThreadedAssignment::ThreadedAssignment(const QByteArray& packet) : } +ThreadedAssignment::~ThreadedAssignment() { + // setFinished(true); +} + void ThreadedAssignment::setFinished(bool isFinished) { + + qDebug() << "------------- ThreadedAssignment::setFinished" << isFinished << " -------------------"; + _isFinished = isFinished; if (_isFinished) { @@ -50,8 +57,10 @@ void ThreadedAssignment::setFinished(bool isFinished) { if (_datagramProcessingThread) { // tell the datagram processing thread to quit and wait until it is done, then return the node socket to the NodeList + qDebug() << "stopping datagramProcessingThread..."; _datagramProcessingThread->quit(); _datagramProcessingThread->wait(); + qDebug() << "done stopping datagramProcessingThread."; // set node socket parent back to NodeList nodeList->getNodeSocket().setParent(nodeList.data()); @@ -64,6 +73,15 @@ void ThreadedAssignment::setFinished(bool isFinished) { } } + +// void ThreadedAssignment::stop() { +// setFinished(true); +// qDebug() << "ThreadedAssignment::stop"; +// QThread *thisThread = QThread::currentThread(); +// thisThread->quit(); +// } + + void ThreadedAssignment::commonInit(const QString& targetName, NodeType_t nodeType, bool shouldSendStats) { // change the logging target name while the assignment is running LogHandler::getInstance().setTargetName(targetName); diff --git a/libraries/networking/src/ThreadedAssignment.h b/libraries/networking/src/ThreadedAssignment.h index 04bee08e62..e2c6e0a1b6 100644 --- a/libraries/networking/src/ThreadedAssignment.h +++ b/libraries/networking/src/ThreadedAssignment.h @@ -20,6 +20,7 @@ class ThreadedAssignment : public Assignment { Q_OBJECT public: ThreadedAssignment(const QByteArray& packet); + virtual ~ThreadedAssignment(); void setFinished(bool isFinished); virtual void aboutToFinish() { }; @@ -28,14 +29,13 @@ public: public slots: /// threaded run of assignment virtual void run() = 0; - Q_INVOKABLE void stop() { setFinished(true); } + Q_INVOKABLE virtual void stop() { setFinished(true); } virtual void readPendingDatagrams() = 0; virtual void sendStatsPacket(); public slots: virtual void aboutToQuit() { - // emit finished(); - QMetaObject::invokeMethod(this, "stop"); + QMetaObject::invokeMethod(this, "stop"); } signals: diff --git a/libraries/octree/src/OctreePersistThread.cpp b/libraries/octree/src/OctreePersistThread.cpp index 210d074001..52dd2aa4ca 100644 --- a/libraries/octree/src/OctreePersistThread.cpp +++ b/libraries/octree/src/OctreePersistThread.cpp @@ -228,6 +228,7 @@ void OctreePersistThread::aboutToFinish() { qCDebug(octree) << "Persist thread about to finish..."; persist(); qCDebug(octree) << "Persist thread done with about to finish..."; + _stopThread = true; } void OctreePersistThread::persist() { diff --git a/libraries/shared/src/DependencyManager.h b/libraries/shared/src/DependencyManager.h index 01b755fdd0..1d91872940 100644 --- a/libraries/shared/src/DependencyManager.h +++ b/libraries/shared/src/DependencyManager.h @@ -26,15 +26,21 @@ class Dependency { public: typedef std::function DeleterFunction; + const QString& getDependencyName() { return _name; } protected: - virtual ~Dependency() {} + virtual ~Dependency() { + qDebug() << "DESTRUCTING" << _name; + } virtual void customDeleter() { _customDeleter(this); } void setCustomDeleter(DeleterFunction customDeleter) { _customDeleter = customDeleter; } DeleterFunction _customDeleter = [](Dependency* pointer) { delete pointer; }; + + void setDependencyName(QString name) { _name = name; } + QString _name; friend class DependencyManager; }; @@ -95,6 +101,7 @@ QSharedPointer DependencyManager::set(Args&&... args) { QSharedPointer newInstance(new T(args...), &T::customDeleter); QSharedPointer storedInstance = qSharedPointerCast(newInstance); instance.swap(storedInstance); + newInstance->setDependencyName(typeid(T).name()); return newInstance; } @@ -102,6 +109,7 @@ QSharedPointer DependencyManager::set(Args&&... args) { template void DependencyManager::destroy() { static size_t hashCode = _manager.getHashCode(); + qDebug() << "DESTROYING" << _manager.safeGet(hashCode)->getDependencyName(); _manager.safeGet(hashCode).clear(); } From e7d8bccd5d299887792b613e44f555cf749d225c Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 29 Apr 2015 12:03:54 -0700 Subject: [PATCH 3/8] cleanups --- assignment-client/src/audio/AudioMixer.h | 9 ----- assignment-client/src/avatars/AvatarMixer.cpp | 18 ++-------- assignment-client/src/avatars/AvatarMixer.h | 3 -- .../src/entities/EntityServer.cpp | 11 ------ assignment-client/src/entities/EntityServer.h | 1 - assignment-client/src/octree/OctreeServer.cpp | 34 ------------------- assignment-client/src/octree/OctreeServer.h | 1 - .../networking/src/ThreadedAssignment.cpp | 9 ----- 8 files changed, 2 insertions(+), 84 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.h b/assignment-client/src/audio/AudioMixer.h index 4894f91e01..6cee557ff9 100644 --- a/assignment-client/src/audio/AudioMixer.h +++ b/assignment-client/src/audio/AudioMixer.h @@ -110,15 +110,6 @@ private: MovingMinMaxAvg _timeSpentPerHashMatchCallStats; // update with usecs spent inside each packetVersionAndHashMatch call MovingMinMaxAvg _readPendingCallsPerSecondStats; // update with # of readPendingDatagrams calls in the last second - - /* // loop variables */ - /* // QTimer* _idleTimer = nullptr; */ - /* int _nextFrame = 0; */ - /* QElapsedTimer _timer; */ - /* char _clientMixBuffer[MAX_PACKET_SIZE]; */ - /* int _usecToSleep = AudioConstants::NETWORK_FRAME_USECS; */ - /* const int TRAILING_AVERAGE_FRAMES = 100; */ - /* int _framesSinceCutoffEvent = TRAILING_AVERAGE_FRAMES; */ }; #endif // hifi_AudioMixer_h diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 8cff7d705d..5612450f1f 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -65,7 +65,9 @@ const float BILLBOARD_AND_IDENTITY_SEND_PROBABILITY = 1.0f / 300.0f; // 1) use the view frustum to cull those avatars that are out of view. Since avatar data doesn't need to be present // if the avatar is not in view or in the keyhole. void AvatarMixer::broadcastAvatarData() { + int idleTime = QDateTime::currentMSecsSinceEpoch() - _lastFrameTimestamp; + ++_numStatFrames; const float STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.10f; @@ -336,22 +338,6 @@ void AvatarMixer::sendStatsPacket() { _numStatFrames = 0; } -// void AvatarMixer::stop() { -// qDebug() << "AvatarMixer::stop"; -// if (_broadcastTimer) { -// // _broadcastTimer->stop(); -// // delete _broadcastTimer; -// _broadcastTimer->deleteLater(); -// // _broadcastTimer = nullptr; -// } - -// _broadcastThread.quit(); -// _broadcastThread.wait(); - -// ThreadedAssignment::stop(); -// } - - void AvatarMixer::run() { ThreadedAssignment::commonInit(AVATAR_MIXER_LOGGING_NAME, NodeType::AvatarMixer); diff --git a/assignment-client/src/avatars/AvatarMixer.h b/assignment-client/src/avatars/AvatarMixer.h index 2a659cface..4746f02d14 100644 --- a/assignment-client/src/avatars/AvatarMixer.h +++ b/assignment-client/src/avatars/AvatarMixer.h @@ -25,7 +25,6 @@ public: public slots: /// runs the avatar mixer void run(); - // Q_INVOKABLE virtual void stop(); void nodeAdded(SharedNodePointer nodeAdded); void nodeKilled(SharedNodePointer killedNode); @@ -33,8 +32,6 @@ public slots: void readPendingDatagrams(); void sendStatsPacket(); - - void finished(); private: void broadcastAvatarData(); diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index e38d0e3c65..b2a1c62ed4 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -163,14 +163,3 @@ void EntityServer::readAdditionalConfiguration(const QJsonObject& settingsSectio EntityTree* tree = static_cast(_tree); tree->setWantEditLogging(wantEditLogging); } - - -// void EntityServer::stop() { -// qDebug() << "EntityServer::stop"; -// if (_pruneDeletedEntitiesTimer) { -// _pruneDeletedEntitiesTimer->stop(); -// delete _pruneDeletedEntitiesTimer; -// _pruneDeletedEntitiesTimer = nullptr; -// } -// OctreeServer::stop(); -// } diff --git a/assignment-client/src/entities/EntityServer.h b/assignment-client/src/entities/EntityServer.h index 78c20d039c..9edec7b704 100644 --- a/assignment-client/src/entities/EntityServer.h +++ b/assignment-client/src/entities/EntityServer.h @@ -44,7 +44,6 @@ public: virtual void readAdditionalConfiguration(const QJsonObject& settingsSectionObject); public slots: - // Q_INVOKABLE virtual void stop(); void pruneDeletedEntities(); protected: diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 725f4eda2c..506733e13d 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -1236,40 +1236,6 @@ void OctreeServer::aboutToFinish() { qDebug() << qPrintable(_safeServerName) << "server ENDING about to finish..."; } - -// void OctreeServer::stop() { -// qDebug() << "OctreeServer::stop"; -// // setFinished(true); -// // QThread *thisThread = QThread::currentThread(); -// // thisThread->quit(); - -// if (_jurisdictionSender) { -// _jurisdictionSender->terminating(); -// _jurisdictionSender->terminate(); -// // delete _jurisdictionSender; -// // _jurisdictionSender = nullptr; -// } - -// _datagramProcessingThread->quit(); -// if (_octreeInboundPacketProcessor) { -// _octreeInboundPacketProcessor->terminating(); -// _octreeInboundPacketProcessor->terminate(); -// // delete _octreeInboundPacketProcessor; -// // _octreeInboundPacketProcessor = nullptr; -// } - -// // _persistThread -// if (_persistThread) { -// _persistThread->terminating(); -// _persistThread->terminate(); -// // delete _persistThread; -// // _persistThread = nullptr; -// } - -// ThreadedAssignment::stop(); -// } - - QString OctreeServer::getUptime() { QString formattedUptime; quint64 now = usecTimestampNow(); diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h index 10c4e81262..41cd3259cf 100644 --- a/assignment-client/src/octree/OctreeServer.h +++ b/assignment-client/src/octree/OctreeServer.h @@ -123,7 +123,6 @@ public: public slots: /// runs the octree server assignment void run(); - // Q_INVOKABLE virtual void stop(); void nodeAdded(SharedNodePointer node); void nodeKilled(SharedNodePointer node); void sendStatsPacket(); diff --git a/libraries/networking/src/ThreadedAssignment.cpp b/libraries/networking/src/ThreadedAssignment.cpp index c212aab188..6ec47d7cdd 100644 --- a/libraries/networking/src/ThreadedAssignment.cpp +++ b/libraries/networking/src/ThreadedAssignment.cpp @@ -73,15 +73,6 @@ void ThreadedAssignment::setFinished(bool isFinished) { } } - -// void ThreadedAssignment::stop() { -// setFinished(true); -// qDebug() << "ThreadedAssignment::stop"; -// QThread *thisThread = QThread::currentThread(); -// thisThread->quit(); -// } - - void ThreadedAssignment::commonInit(const QString& targetName, NodeType_t nodeType, bool shouldSendStats) { // change the logging target name while the assignment is running LogHandler::getInstance().setTargetName(targetName); From 009bb9dc710fe34376ff546050899e6320332457 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 29 Apr 2015 15:16:00 -0700 Subject: [PATCH 4/8] all 4 types of assignment-client appear to exit cleanly, now --- assignment-client/src/AssignmentClient.cpp | 8 ++++++++ assignment-client/src/AssignmentClientApp.cpp | 3 --- .../src/AssignmentClientMonitor.cpp | 2 ++ .../src/entities/EntityServer.cpp | 2 ++ assignment-client/src/octree/OctreeServer.cpp | 18 ++++++++++++++---- assignment-client/src/octree/OctreeServer.h | 3 +++ libraries/networking/src/LimitedNodeList.h | 4 +--- libraries/networking/src/NodeList.h | 5 +++++ libraries/shared/src/LogHandler.h | 6 ++++++ 9 files changed, 41 insertions(+), 10 deletions(-) diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index dc4d06e52e..4f00b30f42 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -126,7 +126,15 @@ void AssignmentClient::stopAssignmentClient() { void AssignmentClient::aboutToQuit() { + qDebug() << "AssignmentClient::aboutToQuit start"; stopAssignmentClient(); + qDebug() << "AssignmentClient::aboutToQuit end"; + // clear the log handler so that Qt doesn't call the destructor on LogHandler + 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(); } diff --git a/assignment-client/src/AssignmentClientApp.cpp b/assignment-client/src/AssignmentClientApp.cpp index c234daac68..d8e4306ec5 100644 --- a/assignment-client/src/AssignmentClientApp.cpp +++ b/assignment-client/src/AssignmentClientApp.cpp @@ -167,7 +167,6 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : } - if (parser.isSet(numChildsOption)) { if (minForks && minForks > numForks) { qCritical() << "--min can't be more than -n"; @@ -189,8 +188,6 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : AssignmentClientMonitor monitor(numForks, minForks, maxForks, requestAssignmentType, assignmentPool, walletUUID, assignmentServerHostname, assignmentServerPort); connect(this, &QCoreApplication::aboutToQuit, &monitor, &AssignmentClientMonitor::aboutToQuit); - - exec(); } else { AssignmentClient client(ppid, requestAssignmentType, assignmentPool, diff --git a/assignment-client/src/AssignmentClientMonitor.cpp b/assignment-client/src/AssignmentClientMonitor.cpp index 14eb93ad6e..31743ea630 100644 --- a/assignment-client/src/AssignmentClientMonitor.cpp +++ b/assignment-client/src/AssignmentClientMonitor.cpp @@ -83,6 +83,8 @@ void AssignmentClientMonitor::stopChildProcesses() { void AssignmentClientMonitor::aboutToQuit() { stopChildProcesses(); + // clear the log handler so that Qt doesn't call the destructor on LogHandler + qInstallMessageHandler(0); } diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index b2a1c62ed4..a175eef475 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -163,3 +163,5 @@ void EntityServer::readAdditionalConfiguration(const QJsonObject& settingsSectio EntityTree* tree = static_cast(_tree); tree->setWantEditLogging(wantEditLogging); } + + diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 506733e13d..11509192ad 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -239,8 +239,10 @@ OctreeServer::OctreeServer(const QByteArray& packet) : _octreeInboundPacketProcessor(NULL), _persistThread(NULL), _started(time(0)), - _startedUSecs(usecTimestampNow()) + _startedUSecs(usecTimestampNow()), + _nodeList(DependencyManager::get()) { + if (_instance) { qDebug() << "Octree Server starting... while old instance still running _instance=["<<_instance<<"] this=[" << this << "]"; } @@ -1098,7 +1100,7 @@ void OctreeServer::readConfiguration() { } void OctreeServer::run() { - qInstallMessageHandler(LogHandler::verboseMessageHandler); + // qInstallMessageHandler(LogHandler::verboseMessageHandler); _safeServerName = getMyServerName(); @@ -1222,8 +1224,15 @@ void OctreeServer::forceNodeShutdown(SharedNodePointer node) { void OctreeServer::aboutToFinish() { qDebug() << qPrintable(_safeServerName) << "server STARTING about to finish..."; qDebug() << qPrintable(_safeServerName) << "inform Octree Inbound Packet Processor that we are shutting down..."; - _octreeInboundPacketProcessor->terminating(); - + + if (_octreeInboundPacketProcessor) { + _octreeInboundPacketProcessor->terminating(); + } + + if (_jurisdictionSender) { + _jurisdictionSender->terminating(); + } + DependencyManager::get()->eachNode([this](const SharedNodePointer& node) { qDebug() << qPrintable(_safeServerName) << "server about to finish while node still connected node:" << *node; forceNodeShutdown(node); @@ -1231,6 +1240,7 @@ void OctreeServer::aboutToFinish() { if (_persistThread) { _persistThread->aboutToFinish(); + _persistThread->terminating(); } qDebug() << qPrintable(_safeServerName) << "server ENDING about to finish..."; diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h index 41cd3259cf..09368fbe4d 100644 --- a/assignment-client/src/octree/OctreeServer.h +++ b/assignment-client/src/octree/OctreeServer.h @@ -238,6 +238,9 @@ protected: static QMutex _threadsDidPacketDistributorMutex; static QMutex _threadsDidHandlePacketSendMutex; static QMutex _threadsDidCallWriteDatagramMutex; + + // keep a pointer to node list so that it doesn't get shut down before this class. + QSharedPointer _nodeList; }; #endif // hifi_OctreeServer_h diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index cd45fbdbdf..f541a29d01 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -222,7 +222,7 @@ protected: LimitedNodeList(LimitedNodeList const&); // Don't implement, needed to avoid copies of singleton void operator=(LimitedNodeList const&); // Don't implement, needed to avoid copies of singleton - ~LimitedNodeList() { + virtual ~LimitedNodeList() { qDebug() << "XXXXXXXXXXXXXXXXXXXX ~LimitedNodeList called"; } @@ -241,8 +241,6 @@ protected: HifiSockAddr _localSockAddr; HifiSockAddr _publicSockAddr; HifiSockAddr _stunSockAddr; - - QTimer* _silentNodeTimer; // XXX can BandwidthRecorder be used for this? int _numCollectedPackets; diff --git a/libraries/networking/src/NodeList.h b/libraries/networking/src/NodeList.h index ccfaa7a4cf..4cb3fb8ea2 100644 --- a/libraries/networking/src/NodeList.h +++ b/libraries/networking/src/NodeList.h @@ -45,6 +45,11 @@ class NodeList : public LimitedNodeList { SINGLETON_DEPENDENCY public: + virtual ~NodeList() { + qDebug() << "XXXXXXXXXXXXXXXXXXXX ~NodeList called"; + } + + NodeType_t getOwnerType() const { return _ownerType; } void setOwnerType(NodeType_t ownerType) { _ownerType = ownerType; } diff --git a/libraries/shared/src/LogHandler.h b/libraries/shared/src/LogHandler.h index 914cad212d..1e9567b4d7 100644 --- a/libraries/shared/src/LogHandler.h +++ b/libraries/shared/src/LogHandler.h @@ -19,6 +19,8 @@ #include #include +#include + const int VERBOSE_LOG_INTERVAL_SECONDS = 5; enum LogMsgType { @@ -34,6 +36,10 @@ class LogHandler : public QObject { Q_OBJECT public: static LogHandler& getInstance(); + + virtual ~LogHandler() { + std::cerr << "XXXXXXXX ~LogHandler()\n"; + } /// sets the target name to output via the verboseMessageHandler, called once before logging begins /// \param targetName the desired target name to output in logs From e985f56b122a883a767348aa0b911c5e915ab878 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 29 Apr 2015 15:30:13 -0700 Subject: [PATCH 5/8] cleanups --- assignment-client/src/AssignmentClient.cpp | 4 ---- assignment-client/src/AssignmentClientApp.cpp | 1 + .../src/octree/OctreeInboundPacketProcessor.h | 1 - assignment-client/src/octree/OctreeServer.cpp | 6 +----- assignment-client/src/octree/OctreeServer.h | 3 --- libraries/networking/src/LimitedNodeList.h | 4 ---- libraries/networking/src/NodeList.h | 5 ----- libraries/networking/src/ThreadedAssignment.cpp | 9 --------- libraries/networking/src/ThreadedAssignment.h | 1 - libraries/shared/src/DependencyManager.h | 10 +--------- libraries/shared/src/LogHandler.h | 6 ------ 11 files changed, 3 insertions(+), 47 deletions(-) diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index 4f00b30f42..594805c7c2 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -117,18 +117,14 @@ void AssignmentClient::stopAssignmentClient() { if (_currentAssignment) { _currentAssignment->aboutToQuit(); QThread* currentAssignmentThread = _currentAssignment->thread(); - qDebug() << "main thread waiting on _currentAssignment->thread()" << currentAssignmentThread->objectName(); currentAssignmentThread->quit(); currentAssignmentThread->wait(); - qDebug() << "done waiting."; } } void AssignmentClient::aboutToQuit() { - qDebug() << "AssignmentClient::aboutToQuit start"; stopAssignmentClient(); - qDebug() << "AssignmentClient::aboutToQuit end"; // clear the log handler so that Qt doesn't call the destructor on LogHandler qInstallMessageHandler(0); // clear out pointer to the assignment so the destructor gets called. if we don't do this here, diff --git a/assignment-client/src/AssignmentClientApp.cpp b/assignment-client/src/AssignmentClientApp.cpp index d8e4306ec5..2de349ca4e 100644 --- a/assignment-client/src/AssignmentClientApp.cpp +++ b/assignment-client/src/AssignmentClientApp.cpp @@ -167,6 +167,7 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : } + if (parser.isSet(numChildsOption)) { if (minForks && minForks > numForks) { qCritical() << "--min can't be more than -n"; diff --git a/assignment-client/src/octree/OctreeInboundPacketProcessor.h b/assignment-client/src/octree/OctreeInboundPacketProcessor.h index 2f9c060183..156e09b493 100644 --- a/assignment-client/src/octree/OctreeInboundPacketProcessor.h +++ b/assignment-client/src/octree/OctreeInboundPacketProcessor.h @@ -74,7 +74,6 @@ public: NodeToSenderStatsMap& getSingleSenderStats() { return _singleSenderStats; } - // void shuttingDown() { _shuttingDown = true;} virtual void terminating() { _shuttingDown = true; ReceivedPacketProcessor::terminating(); } protected: diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 11509192ad..f6f1c486b5 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -239,10 +239,8 @@ OctreeServer::OctreeServer(const QByteArray& packet) : _octreeInboundPacketProcessor(NULL), _persistThread(NULL), _started(time(0)), - _startedUSecs(usecTimestampNow()), - _nodeList(DependencyManager::get()) + _startedUSecs(usecTimestampNow()) { - if (_instance) { qDebug() << "Octree Server starting... while old instance still running _instance=["<<_instance<<"] this=[" << this << "]"; } @@ -1100,8 +1098,6 @@ void OctreeServer::readConfiguration() { } void OctreeServer::run() { - // qInstallMessageHandler(LogHandler::verboseMessageHandler); - _safeServerName = getMyServerName(); // Before we do anything else, create our tree... diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h index 09368fbe4d..41cd3259cf 100644 --- a/assignment-client/src/octree/OctreeServer.h +++ b/assignment-client/src/octree/OctreeServer.h @@ -238,9 +238,6 @@ protected: static QMutex _threadsDidPacketDistributorMutex; static QMutex _threadsDidHandlePacketSendMutex; static QMutex _threadsDidCallWriteDatagramMutex; - - // keep a pointer to node list so that it doesn't get shut down before this class. - QSharedPointer _nodeList; }; #endif // hifi_OctreeServer_h diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index f541a29d01..a7057b4ed8 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -221,10 +221,6 @@ protected: LimitedNodeList(unsigned short socketListenPort = 0, unsigned short dtlsListenPort = 0); LimitedNodeList(LimitedNodeList const&); // Don't implement, needed to avoid copies of singleton void operator=(LimitedNodeList const&); // Don't implement, needed to avoid copies of singleton - - virtual ~LimitedNodeList() { - qDebug() << "XXXXXXXXXXXXXXXXXXXX ~LimitedNodeList called"; - } qint64 writeDatagram(const QByteArray& datagram, const HifiSockAddr& destinationSockAddr, const QUuid& connectionSecret); diff --git a/libraries/networking/src/NodeList.h b/libraries/networking/src/NodeList.h index 4cb3fb8ea2..ccfaa7a4cf 100644 --- a/libraries/networking/src/NodeList.h +++ b/libraries/networking/src/NodeList.h @@ -45,11 +45,6 @@ class NodeList : public LimitedNodeList { SINGLETON_DEPENDENCY public: - virtual ~NodeList() { - qDebug() << "XXXXXXXXXXXXXXXXXXXX ~NodeList called"; - } - - NodeType_t getOwnerType() const { return _ownerType; } void setOwnerType(NodeType_t ownerType) { _ownerType = ownerType; } diff --git a/libraries/networking/src/ThreadedAssignment.cpp b/libraries/networking/src/ThreadedAssignment.cpp index 6ec47d7cdd..eda3da8479 100644 --- a/libraries/networking/src/ThreadedAssignment.cpp +++ b/libraries/networking/src/ThreadedAssignment.cpp @@ -26,14 +26,7 @@ ThreadedAssignment::ThreadedAssignment(const QByteArray& packet) : } -ThreadedAssignment::~ThreadedAssignment() { - // setFinished(true); -} - void ThreadedAssignment::setFinished(bool isFinished) { - - qDebug() << "------------- ThreadedAssignment::setFinished" << isFinished << " -------------------"; - _isFinished = isFinished; if (_isFinished) { @@ -57,10 +50,8 @@ void ThreadedAssignment::setFinished(bool isFinished) { if (_datagramProcessingThread) { // tell the datagram processing thread to quit and wait until it is done, then return the node socket to the NodeList - qDebug() << "stopping datagramProcessingThread..."; _datagramProcessingThread->quit(); _datagramProcessingThread->wait(); - qDebug() << "done stopping datagramProcessingThread."; // set node socket parent back to NodeList nodeList->getNodeSocket().setParent(nodeList.data()); diff --git a/libraries/networking/src/ThreadedAssignment.h b/libraries/networking/src/ThreadedAssignment.h index e2c6e0a1b6..590c2f56ca 100644 --- a/libraries/networking/src/ThreadedAssignment.h +++ b/libraries/networking/src/ThreadedAssignment.h @@ -20,7 +20,6 @@ class ThreadedAssignment : public Assignment { Q_OBJECT public: ThreadedAssignment(const QByteArray& packet); - virtual ~ThreadedAssignment(); void setFinished(bool isFinished); virtual void aboutToFinish() { }; diff --git a/libraries/shared/src/DependencyManager.h b/libraries/shared/src/DependencyManager.h index 1d91872940..cdda72438a 100644 --- a/libraries/shared/src/DependencyManager.h +++ b/libraries/shared/src/DependencyManager.h @@ -26,12 +26,9 @@ class Dependency { public: typedef std::function DeleterFunction; - const QString& getDependencyName() { return _name; } protected: - virtual ~Dependency() { - qDebug() << "DESTRUCTING" << _name; - } + virtual ~Dependency() {} virtual void customDeleter() { _customDeleter(this); } @@ -39,9 +36,6 @@ protected: void setCustomDeleter(DeleterFunction customDeleter) { _customDeleter = customDeleter; } DeleterFunction _customDeleter = [](Dependency* pointer) { delete pointer; }; - void setDependencyName(QString name) { _name = name; } - QString _name; - friend class DependencyManager; }; @@ -101,7 +95,6 @@ QSharedPointer DependencyManager::set(Args&&... args) { QSharedPointer newInstance(new T(args...), &T::customDeleter); QSharedPointer storedInstance = qSharedPointerCast(newInstance); instance.swap(storedInstance); - newInstance->setDependencyName(typeid(T).name()); return newInstance; } @@ -109,7 +102,6 @@ QSharedPointer DependencyManager::set(Args&&... args) { template void DependencyManager::destroy() { static size_t hashCode = _manager.getHashCode(); - qDebug() << "DESTROYING" << _manager.safeGet(hashCode)->getDependencyName(); _manager.safeGet(hashCode).clear(); } diff --git a/libraries/shared/src/LogHandler.h b/libraries/shared/src/LogHandler.h index 1e9567b4d7..914cad212d 100644 --- a/libraries/shared/src/LogHandler.h +++ b/libraries/shared/src/LogHandler.h @@ -19,8 +19,6 @@ #include #include -#include - const int VERBOSE_LOG_INTERVAL_SECONDS = 5; enum LogMsgType { @@ -36,10 +34,6 @@ class LogHandler : public QObject { Q_OBJECT public: static LogHandler& getInstance(); - - virtual ~LogHandler() { - std::cerr << "XXXXXXXX ~LogHandler()\n"; - } /// sets the target name to output via the verboseMessageHandler, called once before logging begins /// \param targetName the desired target name to output in logs From 69766f6e595328052468ea4adf4e6b5879865c0d Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 29 Apr 2015 15:34:31 -0700 Subject: [PATCH 6/8] cleanups --- assignment-client/src/avatars/AvatarMixer.cpp | 5 ++--- libraries/shared/src/DependencyManager.h | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 5612450f1f..6c8ba91f1b 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -45,7 +45,6 @@ AvatarMixer::AvatarMixer(const QByteArray& packet) : } AvatarMixer::~AvatarMixer() { - qDebug() << "AvatarMixer::~AvatarMixer"; if (_broadcastTimer) { _broadcastTimer->deleteLater(); } @@ -65,9 +64,9 @@ const float BILLBOARD_AND_IDENTITY_SEND_PROBABILITY = 1.0f / 300.0f; // 1) use the view frustum to cull those avatars that are out of view. Since avatar data doesn't need to be present // if the avatar is not in view or in the keyhole. void AvatarMixer::broadcastAvatarData() { - + int idleTime = QDateTime::currentMSecsSinceEpoch() - _lastFrameTimestamp; - + ++_numStatFrames; const float STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.10f; diff --git a/libraries/shared/src/DependencyManager.h b/libraries/shared/src/DependencyManager.h index cdda72438a..01b755fdd0 100644 --- a/libraries/shared/src/DependencyManager.h +++ b/libraries/shared/src/DependencyManager.h @@ -35,7 +35,7 @@ protected: void setCustomDeleter(DeleterFunction customDeleter) { _customDeleter = customDeleter; } DeleterFunction _customDeleter = [](Dependency* pointer) { delete pointer; }; - + friend class DependencyManager; }; From b041fd1b7f53336ef937bbe9f02b3c406ffe8c04 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 29 Apr 2015 15:58:56 -0700 Subject: [PATCH 7/8] AssignmentClientMonitor now waits() on children --- .../src/AssignmentClientMonitor.cpp | 22 +++++++++++++++---- .../src/AssignmentClientMonitor.h | 4 +++- .../src/entities/EntityServer.cpp | 2 -- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/assignment-client/src/AssignmentClientMonitor.cpp b/assignment-client/src/AssignmentClientMonitor.cpp index 31743ea630..df77e33ef0 100644 --- a/assignment-client/src/AssignmentClientMonitor.cpp +++ b/assignment-client/src/AssignmentClientMonitor.cpp @@ -69,6 +69,17 @@ AssignmentClientMonitor::~AssignmentClientMonitor() { stopChildProcesses(); } +void AssignmentClientMonitor::waitOnChildren(int msecs) { + QMutableListIterator i(_childProcesses); + while (i.hasNext()) { + QProcess* childProcess = i.next(); + bool finished = childProcess->waitForFinished(msecs); + if (finished) { + i.remove(); + } + } +} + void AssignmentClientMonitor::stopChildProcesses() { auto nodeList = DependencyManager::get(); @@ -78,8 +89,10 @@ void AssignmentClientMonitor::stopChildProcesses() { QByteArray diePacket = byteArrayWithPopulatedHeader(PacketTypeStopNode); nodeList->writeUnverifiedDatagram(diePacket, *node->getActiveSocket()); }); -} + // try to give all the children time to shutdown + waitOnChildren(15000); +} void AssignmentClientMonitor::aboutToQuit() { stopChildProcesses(); @@ -87,10 +100,11 @@ void AssignmentClientMonitor::aboutToQuit() { qInstallMessageHandler(0); } - void AssignmentClientMonitor::spawnChildClient() { QProcess *assignmentClient = new QProcess(this); + _childProcesses.append(assignmentClient); + // unparse the parts of the command-line that the child cares about QStringList _childArguments; if (_assignmentPool != "") { @@ -127,8 +141,6 @@ void AssignmentClientMonitor::spawnChildClient() { qDebug() << "Spawned a child client with PID" << assignmentClient->pid(); } - - void AssignmentClientMonitor::checkSpares() { auto nodeList = DependencyManager::get(); QUuid aSpareId = ""; @@ -164,6 +176,8 @@ void AssignmentClientMonitor::checkSpares() { nodeList->writeUnverifiedDatagram(diePacket, childNode); } } + + waitOnChildren(0); } diff --git a/assignment-client/src/AssignmentClientMonitor.h b/assignment-client/src/AssignmentClientMonitor.h index 23f50ef67d..e0129bd9b9 100644 --- a/assignment-client/src/AssignmentClientMonitor.h +++ b/assignment-client/src/AssignmentClientMonitor.h @@ -32,7 +32,8 @@ public: QString assignmentPool, QUuid walletUUID, QString assignmentServerHostname, quint16 assignmentServerPort); ~AssignmentClientMonitor(); - + + void waitOnChildren(int msecs); void stopChildProcesses(); private slots: void readPendingDatagrams(); @@ -55,6 +56,7 @@ private: QString _assignmentServerHostname; quint16 _assignmentServerPort; + QList _childProcesses; }; #endif // hifi_AssignmentClientMonitor_h diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index a175eef475..e202c17a7d 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -27,8 +27,6 @@ EntityServer::EntityServer(const QByteArray& packet) } EntityServer::~EntityServer() { - qDebug() << "EntityServer::~EntityServer"; - if (_pruneDeletedEntitiesTimer) { _pruneDeletedEntitiesTimer->stop(); _pruneDeletedEntitiesTimer->deleteLater(); From 09eea83461ac8b8cfb2718b65c4fa686daa369a6 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 29 Apr 2015 19:18:58 -0700 Subject: [PATCH 8/8] don't give timers owners while also keeping track of them in as class instance variables --- assignment-client/src/entities/EntityServer.cpp | 2 +- libraries/networking/src/ThreadedAssignment.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index e202c17a7d..bb5042f4b4 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -53,7 +53,7 @@ Octree* EntityServer::createTree() { } void EntityServer::beforeRun() { - _pruneDeletedEntitiesTimer = new QTimer(this); + _pruneDeletedEntitiesTimer = new QTimer(); connect(_pruneDeletedEntitiesTimer, SIGNAL(timeout()), this, SLOT(pruneDeletedEntities())); const int PRUNE_DELETED_MODELS_INTERVAL_MSECS = 1 * 1000; // once every second _pruneDeletedEntitiesTimer->start(PRUNE_DELETED_MODELS_INTERVAL_MSECS); diff --git a/libraries/networking/src/ThreadedAssignment.cpp b/libraries/networking/src/ThreadedAssignment.cpp index eda3da8479..43bcce4530 100644 --- a/libraries/networking/src/ThreadedAssignment.cpp +++ b/libraries/networking/src/ThreadedAssignment.cpp @@ -74,13 +74,13 @@ void ThreadedAssignment::commonInit(const QString& targetName, NodeType_t nodeTy // this is a temp fix for Qt 5.3 - rebinding the node socket gives us readyRead for the socket on this thread nodeList->rebindNodeSocket(); - _domainServerTimer = new QTimer(this); + _domainServerTimer = new QTimer(); connect(_domainServerTimer, SIGNAL(timeout()), this, SLOT(checkInWithDomainServerOrExit())); _domainServerTimer->start(DOMAIN_SERVER_CHECK_IN_MSECS); if (shouldSendStats) { // send a stats packet every 1 second - _statsTimer = new QTimer(this); + _statsTimer = new QTimer(); connect(_statsTimer, &QTimer::timeout, this, &ThreadedAssignment::sendStatsPacket); _statsTimer->start(1000); }