diff options
author | Timothy Pearson <[email protected]> | 2015-04-12 16:34:00 -0500 |
---|---|---|
committer | Timothy Pearson <[email protected]> | 2015-04-12 16:34:00 -0500 |
commit | 85126bf580edb675048843910c0e0c1c56c9ff89 (patch) | |
tree | ff20456bfbf57b108f2e105713694d530194cdc9 | |
parent | 751c96f9b1fc01675a1a9d34831104f98adfd84f (diff) | |
download | tdebase-85126bf580edb675048843910c0e0c1c56c9ff89.tar.gz tdebase-85126bf580edb675048843910c0e0c1c56c9ff89.zip |
Fix sporadic kdesktop hang due to unsafe usage of asynchronous POSIX signals in the main GUI thread
-rw-r--r-- | kdesktop/lockeng.cc | 67 | ||||
-rw-r--r-- | kdesktop/lockeng.h | 29 |
2 files changed, 74 insertions, 22 deletions
diff --git a/kdesktop/lockeng.cc b/kdesktop/lockeng.cc index 8e59b9e72..6ce26cf4e 100644 --- a/kdesktop/lockeng.cc +++ b/kdesktop/lockeng.cc @@ -18,6 +18,7 @@ #include <tdelocale.h> #include <tqfile.h> #include <tqtimer.h> +#include <tqeventloop.h> #include <dcopclient.h> #include <assert.h> @@ -49,13 +50,13 @@ SaverEngine* m_masterSaverEngine = NULL; static void sigusr1_handler(int) { if (m_masterSaverEngine) { - m_masterSaverEngine->slotLockProcessWaiting(); + m_masterSaverEngine->m_threadHelperObject->slotLockProcessWaiting(); } } static void sigusr2_handler(int) { if (m_masterSaverEngine) { - m_masterSaverEngine->slotLockProcessFullyActivated(); + m_masterSaverEngine->m_threadHelperObject->slotLockProcessFullyActivated(); } } static void sigttin_handler(int) @@ -114,6 +115,14 @@ SaverEngine::SaverEngine() mXAutoLock = 0; mEnabled = false; + m_helperThread = new TQEventLoopThread; + m_helperThread->start(); + m_threadHelperObject = new SaverEngineThreadHelperObject; + m_threadHelperObject->moveToThread(m_helperThread); + connect(this, TQT_SIGNAL(terminateHelperThread()), m_threadHelperObject, TQT_SLOT(terminateThread())); + connect(m_threadHelperObject, TQT_SIGNAL(lockProcessWaiting()), this, TQT_SLOT(lockProcessWaiting())); + connect(m_threadHelperObject, TQT_SIGNAL(lockProcessFullyActivated()), this, TQT_SLOT(lockProcessFullyActivated())); + connect(&mLockProcess, TQT_SIGNAL(processExited(TDEProcess *)), TQT_SLOT(lockProcessExited())); @@ -138,6 +147,13 @@ SaverEngine::SaverEngine() kdDebug( 1204 ) << "Failed to start kdesktop_lock!" << endl; } + // Prevent kdesktop_lock signals from being handled by the wrong (GUI) thread + sigemptyset(&mThreadBlockSet); + sigaddset(&mThreadBlockSet, SIGUSR1); + sigaddset(&mThreadBlockSet, SIGUSR2); + sigaddset(&mThreadBlockSet, SIGTTIN); + pthread_sigmask(SIG_BLOCK, &mThreadBlockSet, NULL); + dBusConnect(); } @@ -159,6 +175,11 @@ SaverEngine::~SaverEngine() // Restore X screensaver parameters XSetScreenSaver(tqt_xdisplay(), mXTimeout, mXInterval, mXBlanking, mXExposures); + + terminateHelperThread(); + m_helperThread->wait(); + delete m_threadHelperObject; + delete m_helperThread; } //--------------------------------------------------------------------------- @@ -557,14 +578,19 @@ void SaverEngine::lockProcessExited() } } -void SaverEngine::slotLockProcessWaiting() +void SaverEngineThreadHelperObject::slotLockProcessWaiting() { // lockProcessWaiting cannot be called directly from a signal handler, as it will hang in certain obscure circumstances // Instead we use a single-shot timer to immediately call lockProcessWaiting once control has returned to the Qt main loop - TQTimer::singleShot(0, this, SLOT(lockProcessWaiting())); + lockProcessWaiting(); +} + +void SaverEngineThreadHelperObject::slotLockProcessFullyActivated() +{ + lockProcessFullyActivated(); } -void SaverEngine::slotLockProcessFullyActivated() +void SaverEngine::lockProcessFullyActivated() { mState = Saving; @@ -795,7 +821,8 @@ void SaverEngine::handleDBusSignal(const TQT_DBusMessage& msg) { bool SaverEngine::waitForLockProcessStart() { sigset_t new_mask; - sigset_t orig_mask; + sigset_t empty_mask; + sigemptyset(&empty_mask); // wait for SIGUSR1, SIGUSR2, SIGTTIN, SIGCHLD sigemptyset(&new_mask); @@ -804,30 +831,32 @@ bool SaverEngine::waitForLockProcessStart() { sigaddset(&new_mask, SIGTTIN); sigaddset(&new_mask, SIGCHLD); - sigprocmask(SIG_BLOCK, &new_mask, &orig_mask); + pthread_sigmask(SIG_BLOCK, &new_mask, NULL); while ((mLockProcess.isRunning()) && (!mSaverProcessReady)) { - sigsuspend(&orig_mask); + sigsuspend(&empty_mask); } - sigprocmask(SIG_UNBLOCK, &new_mask, NULL); + pthread_sigmask(SIG_UNBLOCK, &new_mask, NULL); return mLockProcess.isRunning(); } bool SaverEngine::waitForLockEngage() { - sigset_t new_mask; - sigset_t orig_mask; + sigset_t empty_mask; + sigemptyset(&empty_mask); // wait for SIGUSR1, SIGUSR2, SIGTTIN - sigemptyset(&new_mask); - sigaddset(&new_mask, SIGUSR1); - sigaddset(&new_mask, SIGUSR2); - sigaddset(&new_mask, SIGTTIN); - - sigprocmask(SIG_BLOCK, &new_mask, &orig_mask); + pthread_sigmask(SIG_BLOCK, &mThreadBlockSet, NULL); while ((mLockProcess.isRunning()) && (mState != Waiting) && (mState != Saving)) { - sigsuspend(&orig_mask); + sigsuspend(&empty_mask); } - sigprocmask(SIG_UNBLOCK, &new_mask, NULL); + pthread_sigmask(SIG_UNBLOCK, &mThreadBlockSet, NULL); return mLockProcess.isRunning(); +} + +void SaverEngineThreadHelperObject::terminateThread() { + TQEventLoop* eventLoop = TQApplication::eventLoop(); + if (eventLoop) { + eventLoop->exit(0); + } }
\ No newline at end of file diff --git a/kdesktop/lockeng.h b/kdesktop/lockeng.h index 782f779a3..9827090b4 100644 --- a/kdesktop/lockeng.h +++ b/kdesktop/lockeng.h @@ -9,6 +9,7 @@ #define __LOCKENG_H__ #include <tqwidget.h> +#include <tqthread.h> #include <kprocess.h> #include <tqvaluevector.h> #include "KScreensaverIface.h" @@ -21,6 +22,20 @@ class DCOPClientTransaction; class TQT_DBusMessage; class TQT_DBusProxy; +class SaverEngineThreadHelperObject : public TQObject +{ + Q_OBJECT + +public slots: + void terminateThread(); + void slotLockProcessWaiting(); + void slotLockProcessFullyActivated(); + +signals: + void lockProcessWaiting(); + void lockProcessFullyActivated(); +}; + //=========================================================================== /** * Screen saver engine. Handles screensaver window, starting screensaver @@ -91,16 +106,19 @@ public: */ bool waitForLockEngage(); +signals: + void terminateHelperThread(); + void asyncLock(); + public slots: - void slotLockProcessWaiting(); - void slotLockProcessFullyActivated(); void slotLockProcessReady(); + void lockProcessWaiting(); + void lockProcessFullyActivated(); void handleDBusSignal(const TQT_DBusMessage&); protected slots: void idleTimeout(); void lockProcessExited(); - void lockProcessWaiting(); private slots: void handleSecureDialog(); @@ -148,7 +166,12 @@ protected: bool mBlankOnly; // only use the blanker, not the defined saver TQValueVector< DCOPClientTransaction* > mLockTransactions; +public: + SaverEngineThreadHelperObject* m_threadHelperObject; + private: + TQEventLoopThread* m_helperThread; + sigset_t mThreadBlockSet; TDEProcess* mSAKProcess; bool mTerminationRequested; bool mSaverProcessReady; |