From 54f29b951bd046705c68d936d8f2e3ce98d1b24d Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen <miikka.heikkinen@theqtcompany.com> Date: Tue, 6 Oct 2015 13:44:54 +0300 Subject: [PATCH] Fix deadlock when trying to schedule a sync job for hidden window MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I0685e6b7c1b0eb89ab5332db8746cf85639c9db4 Reviewed-by: Pasi Keränen <pasi.keranen@digia.com> --- src/imports/qtcanvas3d/context3d.cpp | 12 +++++++++--- src/imports/qtcanvas3d/renderjob.cpp | 18 +++++++++++++++--- src/imports/qtcanvas3d/renderjob_p.h | 6 +++++- 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/imports/qtcanvas3d/context3d.cpp b/src/imports/qtcanvas3d/context3d.cpp index 1592dc3..829d5a9 100644 --- a/src/imports/qtcanvas3d/context3d.cpp +++ b/src/imports/qtcanvas3d/context3d.cpp @@ -5754,19 +5754,25 @@ void CanvasContext::scheduleSyncCommand(GlSyncCommand *command) if (m_canvas->window() && m_canvas->renderer()) { QOpenGLContext *ctx = m_canvas->window()->openglContext(); if (ctx) { + bool jobDeleted = false; if (ctx->thread() != QThread::currentThread()) { // In case of threaded renderer, we block the main thread until the job is done CanvasRenderJob *syncJob = new CanvasRenderJob(command, &m_renderJobMutex, &m_renderJobCondition, - m_canvas->renderer()); + m_canvas->renderer(), + &jobDeleted); m_renderJobMutex.lock(); m_canvas->window()->scheduleRenderJob(syncJob, QQuickWindow::NoStage); - m_renderJobCondition.wait(&m_renderJobMutex); + // scheduleRenderJob will delete the job if the window is not exposed + if (!jobDeleted) + m_renderJobCondition.wait(&m_renderJobMutex); m_renderJobMutex.unlock(); + } else { // In case of non-threaded renderer, scheduling a job executes it immediately, // so we don't need synchronization. - CanvasRenderJob *syncJob = new CanvasRenderJob(command, 0, 0, m_canvas->renderer()); + CanvasRenderJob *syncJob = new CanvasRenderJob(command, 0, 0, m_canvas->renderer(), + &jobDeleted); m_canvas->window()->scheduleRenderJob(syncJob, QQuickWindow::NoStage); } } diff --git a/src/imports/qtcanvas3d/renderjob.cpp b/src/imports/qtcanvas3d/renderjob.cpp index dfb891b..754aacb 100644 --- a/src/imports/qtcanvas3d/renderjob.cpp +++ b/src/imports/qtcanvas3d/renderjob.cpp @@ -49,14 +49,26 @@ QT_CANVAS3D_BEGIN_NAMESPACE */ CanvasRenderJob::CanvasRenderJob(GlSyncCommand *command, QMutex *mutex, QWaitCondition *condition, - CanvasRenderer *renderer) - : m_command(command), m_mutex(mutex), m_condition(condition), m_renderer(renderer) + CanvasRenderer *renderer, bool *deleted) + : m_command(command), + m_mutex(mutex), + m_condition(condition), + m_renderer(renderer), + m_deleted(deleted), + m_creationThread(QThread::currentThread()) { } CanvasRenderJob::~CanvasRenderJob() { - notifyGuiThread(); + if (m_creationThread != QThread::currentThread()) { + notifyGuiThread(); + } else { + // If the job is deleted in the thread it was created in, we can assume the scheduling + // failed and notify the context that we got deleted via the m_deleted flag, + // so it won't start waiting for job to complete. + *m_deleted = true; + } } void CanvasRenderJob::run() diff --git a/src/imports/qtcanvas3d/renderjob_p.h b/src/imports/qtcanvas3d/renderjob_p.h index 7d0e50b..e4c0ff1 100644 --- a/src/imports/qtcanvas3d/renderjob_p.h +++ b/src/imports/qtcanvas3d/renderjob_p.h @@ -53,6 +53,7 @@ #include <QtCore/QWaitCondition> #include <QtCore/QMutex> #include <QtCore/QRunnable> +#include <QtCore/QThread> QT_BEGIN_NAMESPACE QT_CANVAS3D_BEGIN_NAMESPACE @@ -63,7 +64,8 @@ class CanvasRenderJob : public QRunnable { public: CanvasRenderJob(GlSyncCommand *command, QMutex *mutex, - QWaitCondition *condition, QtCanvas3D::CanvasRenderer *renderer); + QWaitCondition *condition, QtCanvas3D::CanvasRenderer *renderer, + bool *deleted); ~CanvasRenderJob(); void run(); @@ -76,6 +78,8 @@ private: QMutex *m_mutex; QWaitCondition *m_condition; CanvasRenderer *m_renderer; + bool *m_deleted; + QThread *m_creationThread; }; QT_CANVAS3D_END_NAMESPACE -- GitLab