Merge pull request #7433 from zzmp/fix/long-qml-instantiation

Avoid triggering deadlock on long local qml component instantion
This commit is contained in:
Brad Hefta-Gaub 2016-03-23 08:30:50 -07:00
commit 03a12ecf5a
3 changed files with 21 additions and 13 deletions

View file

@ -239,11 +239,7 @@ class DeadlockWatchdogThread : public QThread {
public: public:
static const unsigned long HEARTBEAT_CHECK_INTERVAL_SECS = 1; static const unsigned long HEARTBEAT_CHECK_INTERVAL_SECS = 1;
static const unsigned long HEARTBEAT_UPDATE_INTERVAL_SECS = 1; static const unsigned long HEARTBEAT_UPDATE_INTERVAL_SECS = 1;
#ifdef DEBUG
static const unsigned long MAX_HEARTBEAT_AGE_USECS = 600 * USECS_PER_SECOND;
#else
static const unsigned long MAX_HEARTBEAT_AGE_USECS = 10 * USECS_PER_SECOND; static const unsigned long MAX_HEARTBEAT_AGE_USECS = 10 * USECS_PER_SECOND;
#endif
// Set the heartbeat on launch // Set the heartbeat on launch
DeadlockWatchdogThread() { DeadlockWatchdogThread() {
@ -511,8 +507,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
auto nodeList = DependencyManager::get<NodeList>(); auto nodeList = DependencyManager::get<NodeList>();
// Set up a watchdog thread to intentionally crash the application on deadlocks // Set up a watchdog thread to intentionally crash the application on deadlocks
auto deadlockWatchdog = new DeadlockWatchdogThread(); _deadlockWatchdogThread = new DeadlockWatchdogThread();
deadlockWatchdog->start(); _deadlockWatchdogThread->start();
qCDebug(interfaceapp) << "[VERSION] Build sequence:" << qPrintable(applicationVersion()); qCDebug(interfaceapp) << "[VERSION] Build sequence:" << qPrintable(applicationVersion());
@ -586,7 +582,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
ResourceManager::init(); ResourceManager::init();
// Make sure we don't time out during slow operations at startup // Make sure we don't time out during slow operations at startup
deadlockWatchdog->updateHeartbeat(); updateHeartbeat();
// Setup MessagesClient // Setup MessagesClient
auto messagesClient = DependencyManager::get<MessagesClient>(); auto messagesClient = DependencyManager::get<MessagesClient>();
@ -734,7 +730,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
initializeGL(); initializeGL();
_offscreenContext->makeCurrent(); _offscreenContext->makeCurrent();
// Make sure we don't time out during slow operations at startup // Make sure we don't time out during slow operations at startup
deadlockWatchdog->updateHeartbeat(); updateHeartbeat();
// Tell our entity edit sender about our known jurisdictions // Tell our entity edit sender about our known jurisdictions
_entityEditSender.setServerJurisdictions(&_entityServerJurisdictions); _entityEditSender.setServerJurisdictions(&_entityServerJurisdictions);
@ -746,7 +742,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
_overlays.init(); // do this before scripts load _overlays.init(); // do this before scripts load
// Make sure we don't time out during slow operations at startup // Make sure we don't time out during slow operations at startup
deadlockWatchdog->updateHeartbeat(); updateHeartbeat();
connect(this, SIGNAL(aboutToQuit()), this, SLOT(aboutToQuit())); connect(this, SIGNAL(aboutToQuit()), this, SLOT(aboutToQuit()));
@ -900,11 +896,11 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
// do this as late as possible so that all required subsystems are initialized // do this as late as possible so that all required subsystems are initialized
scriptEngines->loadScripts(); scriptEngines->loadScripts();
// Make sure we don't time out during slow operations at startup // Make sure we don't time out during slow operations at startup
deadlockWatchdog->updateHeartbeat(); updateHeartbeat();
loadSettings(); loadSettings();
// Make sure we don't time out during slow operations at startup // Make sure we don't time out during slow operations at startup
deadlockWatchdog->updateHeartbeat(); updateHeartbeat();
int SAVE_SETTINGS_INTERVAL = 10 * MSECS_PER_SECOND; // Let's save every seconds for now int SAVE_SETTINGS_INTERVAL = 10 * MSECS_PER_SECOND; // Let's save every seconds for now
connect(&_settingsTimer, &QTimer::timeout, this, &Application::saveSettings); connect(&_settingsTimer, &QTimer::timeout, this, &Application::saveSettings);
@ -1019,7 +1015,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
}); });
// Make sure we don't time out during slow operations at startup // Make sure we don't time out during slow operations at startup
deadlockWatchdog->updateHeartbeat(); updateHeartbeat();
connect(this, &Application::applicationStateChanged, this, &Application::activeChanged); connect(this, &Application::applicationStateChanged, this, &Application::activeChanged);
qCDebug(interfaceapp, "Startup time: %4.2f seconds.", (double)startupTimer.elapsed() / 1000.0); qCDebug(interfaceapp, "Startup time: %4.2f seconds.", (double)startupTimer.elapsed() / 1000.0);
@ -1060,6 +1056,10 @@ void Application::showCursor(const QCursor& cursor) {
_cursorNeedsChanging = true; _cursorNeedsChanging = true;
} }
void Application::updateHeartbeat() {
static_cast<DeadlockWatchdogThread*>(_deadlockWatchdogThread)->updateHeartbeat();
}
void Application::aboutToQuit() { void Application::aboutToQuit() {
emit beforeAboutToQuit(); emit beforeAboutToQuit();

View file

@ -271,6 +271,8 @@ public slots:
void reloadResourceCaches(); void reloadResourceCaches();
void updateHeartbeat();
void crashApplication(); void crashApplication();
void deadlockApplication(); void deadlockApplication();
@ -505,6 +507,8 @@ private:
mutable QMutex _changeCursorLock { QMutex::Recursive }; mutable QMutex _changeCursorLock { QMutex::Recursive };
QCursor _desiredCursor{ Qt::BlankCursor }; QCursor _desiredCursor{ Qt::BlankCursor };
bool _cursorNeedsChanging { false }; bool _cursorNeedsChanging { false };
QThread* _deadlockWatchdogThread;
}; };
#endif // hifi_Application_h #endif // hifi_Application_h

View file

@ -426,7 +426,11 @@ void OffscreenQmlSurface::setBaseUrl(const QUrl& baseUrl) {
} }
QObject* OffscreenQmlSurface::load(const QUrl& qmlSource, std::function<void(QQmlContext*, QObject*)> f) { QObject* OffscreenQmlSurface::load(const QUrl& qmlSource, std::function<void(QQmlContext*, QObject*)> f) {
_qmlComponent->loadUrl(qmlSource); // Synchronous loading may take a while; restart the deadlock timer
QMetaObject::invokeMethod(qApp, "updateHeartbeat", Qt::DirectConnection);
_qmlComponent->loadUrl(qmlSource, QQmlComponent::PreferSynchronous);
if (_qmlComponent->isLoading()) { if (_qmlComponent->isLoading()) {
connect(_qmlComponent, &QQmlComponent::statusChanged, this, connect(_qmlComponent, &QQmlComponent::statusChanged, this,
[this, f](QQmlComponent::Status){ [this, f](QQmlComponent::Status){