From c7a8b70b4e9afef864652cf98a934d99d49bb36f Mon Sep 17 00:00:00 2001
From: Giulio Camuffo <giulio.camuffo@jollamobile.com>
Date: Thu, 2 Oct 2014 10:48:09 +0300
Subject: [PATCH] Call ::exit() from the gui thread only

::exit() is not thread safe, so make sure to not call it more than one
time, once from the gui thread and once from the wayland event thread.

Change-Id: I80905c6d996cb827a5101ae6d6c9bc12a267ba71
Reviewed-by: Robin Burchell <robin.burchell@viroteck.net>
---
 src/client/qwaylanddisplay.cpp     | 18 ++++++++++++++----
 src/client/qwaylanddisplay_p.h     |  1 +
 src/client/qwaylandeventthread.cpp | 11 +++++++----
 src/client/qwaylandeventthread_p.h |  3 ++-
 4 files changed, 24 insertions(+), 9 deletions(-)

diff --git a/src/client/qwaylanddisplay.cpp b/src/client/qwaylanddisplay.cpp
index 3eac985f6..8649a497c 100644
--- a/src/client/qwaylanddisplay.cpp
+++ b/src/client/qwaylanddisplay.cpp
@@ -149,6 +149,7 @@ QWaylandDisplay::QWaylandDisplay(QWaylandIntegration *waylandIntegration)
     init(registry);
 
     connect(mEventThreadObject, SIGNAL(newEventsRead()), this, SLOT(flushRequests()));
+    connect(mEventThreadObject, &QWaylandEventThread::fatalError, this, &QWaylandDisplay::exitWithError);
 
     mWindowManagerIntegration.reset(new QWaylandWindowManagerIntegration(this));
 
@@ -167,8 +168,10 @@ QWaylandDisplay::~QWaylandDisplay(void)
 
 void QWaylandDisplay::flushRequests()
 {
-    if (wl_display_dispatch_queue_pending(mDisplay, mEventQueue) < 0)
-        mEventThreadObject->checkErrorAndExit();
+    if (wl_display_dispatch_queue_pending(mDisplay, mEventQueue) < 0) {
+        mEventThreadObject->checkError();
+        exitWithError();
+    }
 
     wl_display_flush(mDisplay);
 }
@@ -176,8 +179,15 @@ void QWaylandDisplay::flushRequests()
 
 void QWaylandDisplay::blockingReadEvents()
 {
-    if (wl_display_dispatch_queue(mDisplay, mEventQueue) < 0)
-        mEventThreadObject->checkErrorAndExit();
+    if (wl_display_dispatch_queue(mDisplay, mEventQueue) < 0) {
+        mEventThreadObject->checkError();
+        exitWithError();
+    }
+}
+
+void QWaylandDisplay::exitWithError()
+{
+    ::exit(1);
 }
 
 QWaylandScreen *QWaylandDisplay::screenForOutput(struct wl_output *output) const
diff --git a/src/client/qwaylanddisplay_p.h b/src/client/qwaylanddisplay_p.h
index b0142004e..796c54756 100644
--- a/src/client/qwaylanddisplay_p.h
+++ b/src/client/qwaylanddisplay_p.h
@@ -164,6 +164,7 @@ public slots:
 
 private:
     void waitForScreens();
+    void exitWithError();
 
     struct Listener {
         RegistryListener listener;
diff --git a/src/client/qwaylandeventthread.cpp b/src/client/qwaylandeventthread.cpp
index b7266765e..22efd6a2a 100644
--- a/src/client/qwaylandeventthread.cpp
+++ b/src/client/qwaylandeventthread.cpp
@@ -73,7 +73,7 @@ void QWaylandEventThread::displayConnect()
 
 // ### be careful what you do, this function may also be called from other
 // threads to clean up & exit.
-void QWaylandEventThread::checkErrorAndExit()
+void QWaylandEventThread::checkError() const
 {
     int ecode = wl_display_get_error(m_display);
     if ((ecode == EPIPE || ecode == ECONNRESET)) {
@@ -82,13 +82,16 @@ void QWaylandEventThread::checkErrorAndExit()
     } else {
         qErrnoWarning(ecode, "The Wayland connection experienced a fatal error");
     }
-    ::exit(1);
 }
 
 void QWaylandEventThread::readWaylandEvents()
 {
-    if (wl_display_dispatch(m_display) < 0)
-        checkErrorAndExit();
+    if (wl_display_dispatch(m_display) < 0) {
+        checkError();
+        m_readNotifier->setEnabled(false);
+        emit fatalError();
+        return;
+    }
 
     emit newEventsRead();
 }
diff --git a/src/client/qwaylandeventthread_p.h b/src/client/qwaylandeventthread_p.h
index d51d627b9..2df4b05c2 100644
--- a/src/client/qwaylandeventthread_p.h
+++ b/src/client/qwaylandeventthread_p.h
@@ -63,7 +63,7 @@ public:
 
     wl_display *display() const;
 
-    void checkErrorAndExit();
+    void checkError() const;
 
 private slots:
     void readWaylandEvents();
@@ -72,6 +72,7 @@ private slots:
 
 signals:
     void newEventsRead();
+    void fatalError();
 
 private:
 
-- 
GitLab