summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTimothy Pearson <kb9vqf@pearsoncomputing.net>2015-04-12 16:34:00 -0500
committerTimothy Pearson <kb9vqf@pearsoncomputing.net>2015-04-12 16:34:00 -0500
commit85126bf580edb675048843910c0e0c1c56c9ff89 (patch)
treeff20456bfbf57b108f2e105713694d530194cdc9
parent751c96f9b1fc01675a1a9d34831104f98adfd84f (diff)
downloadtdebase-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.cc67
-rw-r--r--kdesktop/lockeng.h29
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;