kdesktop: fix deadlock condition between kdesktop and kdesktop lock.

The logic to handle communication with kdesktop_lock is now running
completely in a separate thread and event loop, meaning the main GUI
thread remains responsive all the time and can handle interaction with
X11, DCOP and DBUS calls. This resolves issue #589.
The commit also solves the first problem reported in issue #640 and
loosely related to PR #526.

Signed-off-by: Michele Calgaro <michele.calgaro@yahoo.it>
pull/641/head
Michele Calgaro 4 months ago
parent a3f0904f6a
commit 409442c1ea
Signed by: MicheleC
GPG Key ID: 2A75B7CA8ADED5CF

@ -124,3 +124,16 @@ kdesktop_lock to kdesktop communication:
- TTIN: the lock process is ready. This is sent after the process has been created/respawned - TTIN: the lock process is ready. This is sent after the process has been created/respawned
- USR2: the lock/screensaver has been activated - USR2: the lock/screensaver has been activated
- USR1: the lock/screensaver has been unlocked/stopped - USR1: the lock/screensaver has been unlocked/stopped
Communication is handled by the screen saver engine defined in 'lockeng.{h,cpp}'.
The engine is split into two parts, the 'SaverEngine' running in the GUI thread and
the 'SaverEngineEventHandler' running in a separate thread and eventloop.
The 'SaverEngine' handles communication with X11, DCOP and DBUS while the
'SaverEngineEventHandler' handles communication with the actual lock process.
Several actions require cooperation of the two parts, so in various methods
there will be inter-thread calls (using timers or by emitting signals) to
trigger the other side remaining logic.
This complex design is necessary to avoid blocking the main GUI application event loop,
which has several tasks to manage and therefore can't affort to wait in a suspended state.
This was previously leading to deadlock when DCOP calls where executed on the secondary
thread/eventloop, for example when changing desktop while the lock process was restarting.

@ -12,11 +12,10 @@ public:
KScreensaverIface() : DCOPObject("KScreensaverIface") {} KScreensaverIface() : DCOPObject("KScreensaverIface") {}
k_dcop: k_dcop:
/** Lock the screen now even if the screensaver does not lock by default. */ /** Lock the screen now even if the screensaver does not lock by default */
virtual void lock() = 0; virtual void lock() = 0;
/** Save the screen now. If the user has locking enabled, the screen is /** Start the screensaver now. If the user has locking enabled, the screen is locked also */
* locked also. */
virtual void save() = 0; virtual void save() = 0;
/** Quit the screensaver if it is running */ /** Quit the screensaver if it is running */
@ -34,11 +33,12 @@ k_dcop:
/** Is the screen currently blanked? */ /** Is the screen currently blanked? */
virtual bool isBlanked() = 0; virtual bool isBlanked() = 0;
/** Reload the screensaver configuration. */ /** Reload the screensaver configuration */
virtual void configure() = 0; virtual void configure() = 0;
/** Only blank the screen (and possibly lock). Do not use a custom /**
* screen saver in the interest of saving battery. * Set the screensaver to blank (and possibly lock).
* This method does not actually start the screensaver.
*/ */
virtual void setBlankOnly(bool blankOnly) = 0; virtual void setBlankOnly(bool blankOnly) = 0;

@ -106,9 +106,6 @@ class LockProcess : public TQWidget
TDECryptographicCardDevice* cryptographicCardDevice(); TDECryptographicCardDevice* cryptographicCardDevice();
signals:
void terminateHelperThread();
public slots: public slots:
void quitSaver(); void quitSaver();
void preparePopup(); void preparePopup();

File diff suppressed because it is too large Load Diff

@ -1,6 +1,5 @@
//===========================================================================
// //
// This file is part of the KDE project // This file is part of the TDE project
// //
// Copyright (c) 1999 Martin R. Jones <mjones@kde.org> // Copyright (c) 1999 Martin R. Jones <mjones@kde.org>
// //
@ -8,7 +7,6 @@
#ifndef __LOCKENG_H__ #ifndef __LOCKENG_H__
#define __LOCKENG_H__ #define __LOCKENG_H__
#include <tqwidget.h>
#include <tqthread.h> #include <tqthread.h>
#include <tdeprocess.h> #include <tdeprocess.h>
#include <tqvaluevector.h> #include <tqvaluevector.h>
@ -23,31 +21,48 @@ class TDECryptographicCardDevice;
#else #else
#define TDECryptographicCardDevice void #define TDECryptographicCardDevice void
#endif #endif
/**
* Screen saver engine. Handles communication with the lock process.
* The engine is split into two parts, the 'SaverEngine' running in the GUI thread and
* the 'SaverEngineEventHandler' running in a separate thread and eventloop.
* The 'SaverEngine' handles communication with X11, DCOP and DBUS while the
* 'SaverEngineEventHandler' handles communication with the actual lock process.
* Several actions require cooperation of the two parts, so in various methods
* there will be inter-thread calls (using timers or by emitting signals) to
* trigger the other side remaining logic.
* This complex design is necessary to avoid blocking the main GUI application event loop,
* which has several tasks to manage and therefore can't affort to wait in a suspended state.
* This was previously leading to deadlock when DCOP calls where executed on the secondary
* thread/eventloop, for example when changing desktop while the lock process was restarting.
*/
class DCOPClientTransaction; class DCOPClientTransaction;
class TQT_DBusMessage; class TQT_DBusMessage;
class TQT_DBusProxy; class TQT_DBusProxy;
class SaverEngineEventHandler;
class SaverEngineThreadHelperObject : public TQObject // Type of lock screen
enum LockType : int
{ {
TQ_OBJECT DontLock = 0,
DefaultLock,
public slots: ForceLock,
void terminateThread(); SecureDialog
void slotLockProcessWaiting(); };
void slotLockProcessFullyActivated();
signals: enum SaverState
void lockProcessWaiting(); {
void lockProcessFullyActivated(); Waiting,
Preparing,
Engaging,
Saving
}; };
//=========================================================================== class SaverEngine : public TQObject, public KScreensaverIface
/**
* Screen saver engine. Handles screensaver window, starting screensaver
* hacks, and password entry.
*/
class SaverEngine : public TQWidget, public KScreensaverIface
{ {
friend class SaverEngineEventHandler;
TQ_OBJECT TQ_OBJECT
public: public:
SaverEngine(); SaverEngine();
@ -100,80 +115,53 @@ public:
*/ */
virtual void saverLockReady(); virtual void saverLockReady();
/**
* @internal
*/
void lockScreen(bool DCOP = false); void lockScreen(bool DCOP = false);
/**
* Called by KDesktop to wait for saver engage
* @internal
*/
bool waitForLockEngage();
/**
* @internal
*/
void lockScreenAndDoNewSession(); void lockScreenAndDoNewSession();
/**
* @internal
*/
void lockScreenAndSwitchSession(int vt); void lockScreenAndSwitchSession(int vt);
void enableExports(); // Enable wallpaper exports
signals: signals:
void terminateHelperThread(); void activateSaverOrLockSignal(LockType lock_type);
void asyncLock(); void lockScreenSignal(bool);
void terminateEventHandlerThread();
public slots: public slots:
void slotLockProcessReady();
void lockProcessWaiting();
void lockProcessFullyActivated();
void handleDBusSignal(const TQT_DBusMessage&); void handleDBusSignal(const TQT_DBusMessage&);
void terminateTDESession();
protected slots: protected slots:
void idleTimeout(); void idleTimeout();
void lockProcessExited();
private slots: private slots:
void handleSecureDialog();
void slotSAKProcessExited();
void cryptographicCardInserted(TDECryptographicCardDevice*); void cryptographicCardInserted(TDECryptographicCardDevice*);
void cryptographicCardRemoved(TDECryptographicCardDevice*); void cryptographicCardRemoved(TDECryptographicCardDevice*);
/**
* Enable wallpaper exports
*/
void enableExports();
void recoverFromHackingAttempt();
void cardStartupTimeout(); void cardStartupTimeout();
bool dBusReconnect(); bool dBusReconnect();
// The following slots are invoked by corresponding methods named without the 'GUI' suffix
// in 'SaverEngineEventHandler' to complete the remaining X11 part of the actions
void activateSaverOrLockGUI();
void lockProcessFullyActivatedGUI();
void lockProcessWaitingGUI();
void lockScreenGUI();
void stopLockProcessGUI();
private: private:
bool restartDesktopLockProcess();
void dBusClose(); void dBusClose();
bool dBusConnect(); bool dBusConnect();
void onDBusServiceRegistered(const TQString&); void onDBusServiceRegistered(const TQString&);
void onDBusServiceUnregistered(const TQString&); void onDBusServiceUnregistered(const TQString&);
protected: protected:
enum SaverState { Waiting, Preparing, Engaging, Saving };
enum LockType { DontLock, DefaultLock, ForceLock, SecureDialog };
bool startLockProcess( LockType lock_type );
bool waitForLockProcessStart();
void stopLockProcess();
bool handleKeyPress(XKeyEvent *xke);
void processLockTransactions(); void processLockTransactions();
xautolock_corner_t applyManualSettings(int); xautolock_corner_t applyManualSettings(int);
protected: protected:
bool mEnabled; bool mEnabled;
SaverState mState;
XAutoLock *mXAutoLock; XAutoLock *mXAutoLock;
TDEProcess mLockProcess;
int mTimeout; int mTimeout;
// the original X screensaver parameters // the original X screensaver parameters
@ -182,18 +170,14 @@ protected:
int mXBlanking; int mXBlanking;
int mXExposures; int mXExposures;
bool mBlankOnly; // only use the blanker, not the defined saver
TQValueVector< DCOPClientTransaction* > mLockTransactions; TQValueVector< DCOPClientTransaction* > mLockTransactions;
public: public:
SaverEngineThreadHelperObject* m_threadHelperObject; bool mBlankOnly; // only use the blanker, not the defined saver // protected
SaverEngineEventHandler *m_saverEngineEventHandler;
private: private:
TQEventLoopThread* m_helperThread; TQEventLoopThread* m_eventHandlerThread;
sigset_t mThreadBlockSet;
TDEProcess* mSAKProcess;
bool mTerminationRequested;
bool mSaverProcessReady;
bool mNewVTAfterLockEngage; bool mNewVTAfterLockEngage;
bool mValidCryptoCardInserted; bool mValidCryptoCardInserted;
int mSwitchVTAfterLockEngage; int mSwitchVTAfterLockEngage;
@ -204,5 +188,43 @@ private:
TQT_DBusProxy *systemdSession; TQT_DBusProxy *systemdSession;
}; };
class SaverEngineEventHandler : public TQObject
{
TQ_OBJECT
public:
SaverEngineEventHandler(SaverEngine *engine);
SaverState getState() const { return m_state; }
void lockProcessExited();
void lockProcessFullyActivated();
void lockProcessReady();
void terminateLockProcess();
public slots:
bool activateSaverOrLock(LockType lock_type);
void lockScreen(bool DCOP = false);
bool restartLockProcess();
void saveScreen();
void stopLockProcess();
void terminateThread();
protected slots:
void slotLockProcessExited();
void slotSAKProcessExited();
protected:
void startSAKProcess();
bool m_saverProcessReady;
bool m_lockProcessRestarting;
bool m_terminationRequest;
SaverState m_state;
SaverEngine *m_saverEngine;
TDEProcess *m_SAKProcess;
TDEProcess m_lockProcess;
};
#endif #endif

@ -71,7 +71,7 @@ static TDECmdLineOptions options[] =
}; };
bool argb_visual = false; bool argb_visual = false;
KDesktopApp *myApp = NULL; KDesktopApp *myApp = nullptr;
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -251,7 +251,7 @@ extern "C" TDE_EXPORT int kdemain( int argc, char **argv )
else else
XCloseDisplay( dpy ); XCloseDisplay( dpy );
} }
if( myApp == NULL ) if (!myApp)
myApp = new KDesktopApp; myApp = new KDesktopApp;
#else #else
myApp = new KDesktopApp; myApp = new KDesktopApp;
@ -260,9 +260,6 @@ extern "C" TDE_EXPORT int kdemain( int argc, char **argv )
KDesktopSettings::instance(kdesktop_name + "rc"); KDesktopSettings::instance(kdesktop_name + "rc");
bool x_root_hack = args->isSet("x-root");
bool wait_for_kded = args->isSet("waitforkded");
// This MUST be created before any widgets are created // This MUST be created before any widgets are created
SaverEngine saver; SaverEngine saver;
@ -279,16 +276,15 @@ extern "C" TDE_EXPORT int kdemain( int argc, char **argv )
myApp->config()->reparseConfiguration(); myApp->config()->reparseConfiguration();
} }
// for the KDE-already-running check in starttde // for the TDE-already-running check in starttde
TDESelectionOwner kde_running( "_KDE_RUNNING", 0 ); TDESelectionOwner tde_running( "_KDE_RUNNING", 0 );
kde_running.claim( false ); tde_running.claim( false );
bool x_root_hack = args->isSet("x-root");
bool wait_for_kded = args->isSet("waitforkded");
KDesktop desktop( &saver, x_root_hack, wait_for_kded ); KDesktop desktop( &saver, x_root_hack, wait_for_kded );
args->clear(); args->clear();
myApp->dcopClient()->setDefaultObject( "KDesktopIface" ); myApp->dcopClient()->setDefaultObject( "KDesktopIface" );
return myApp->exec(); return myApp->exec();
} }

Loading…
Cancel
Save