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
- USR2: the lock/screensaver has been activated
- 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") {}
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;
/** Save the screen now. If the user has locking enabled, the screen is
* locked also. */
/** Start the screensaver now. If the user has locking enabled, the screen is locked also */
virtual void save() = 0;
/** Quit the screensaver if it is running */
@ -29,22 +28,23 @@ k_dcop:
* Enable/disable the screensaver
* returns true if the action succeeded
*/
virtual bool enable( bool e ) = 0;
virtual bool enable(bool e) = 0;
/** Is the screen currently blanked? */
virtual bool isBlanked() = 0;
/** Reload the screensaver configuration. */
/** Reload the screensaver configuration */
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;
/***
* @internal
*/
*/
virtual void saverLockReady() = 0;
};

@ -106,9 +106,6 @@ class LockProcess : public TQWidget
TDECryptographicCardDevice* cryptographicCardDevice();
signals:
void terminateHelperThread();
public slots:
void quitSaver();
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>
//
@ -8,7 +7,6 @@
#ifndef __LOCKENG_H__
#define __LOCKENG_H__
#include <tqwidget.h>
#include <tqthread.h>
#include <tdeprocess.h>
#include <tqvaluevector.h>
@ -23,31 +21,48 @@ class TDECryptographicCardDevice;
#else
#define TDECryptographicCardDevice void
#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 TQT_DBusMessage;
class TQT_DBusProxy;
class SaverEngineEventHandler;
class SaverEngineThreadHelperObject : public TQObject
// Type of lock screen
enum LockType : int
{
TQ_OBJECT
public slots:
void terminateThread();
void slotLockProcessWaiting();
void slotLockProcessFullyActivated();
DontLock = 0,
DefaultLock,
ForceLock,
SecureDialog
};
signals:
void lockProcessWaiting();
void lockProcessFullyActivated();
enum SaverState
{
Waiting,
Preparing,
Engaging,
Saving
};
//===========================================================================
/**
* Screen saver engine. Handles screensaver window, starting screensaver
* hacks, and password entry.
*/
class SaverEngine : public TQWidget, public KScreensaverIface
class SaverEngine : public TQObject, public KScreensaverIface
{
friend class SaverEngineEventHandler;
TQ_OBJECT
public:
SaverEngine();
@ -100,80 +115,53 @@ public:
*/
virtual void saverLockReady();
/**
* @internal
*/
void lockScreen(bool DCOP = false);
/**
* Called by KDesktop to wait for saver engage
* @internal
*/
bool waitForLockEngage();
/**
* @internal
*/
void lockScreenAndDoNewSession();
/**
* @internal
*/
void lockScreenAndSwitchSession(int vt);
void enableExports(); // Enable wallpaper exports
signals:
void terminateHelperThread();
void asyncLock();
void activateSaverOrLockSignal(LockType lock_type);
void lockScreenSignal(bool);
void terminateEventHandlerThread();
public slots:
void slotLockProcessReady();
void lockProcessWaiting();
void lockProcessFullyActivated();
void handleDBusSignal(const TQT_DBusMessage&);
void terminateTDESession();
protected slots:
void idleTimeout();
void lockProcessExited();
private slots:
void handleSecureDialog();
void slotSAKProcessExited();
void cryptographicCardInserted(TDECryptographicCardDevice*);
void cryptographicCardRemoved(TDECryptographicCardDevice*);
/**
* Enable wallpaper exports
*/
void enableExports();
void recoverFromHackingAttempt();
void cardStartupTimeout();
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:
bool restartDesktopLockProcess();
void dBusClose();
bool dBusConnect();
void onDBusServiceRegistered(const TQString&);
void onDBusServiceUnregistered(const TQString&);
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();
xautolock_corner_t applyManualSettings(int);
protected:
bool mEnabled;
SaverState mState;
XAutoLock *mXAutoLock;
TDEProcess mLockProcess;
int mTimeout;
// the original X screensaver parameters
@ -182,26 +170,60 @@ protected:
int mXBlanking;
int mXExposures;
bool mBlankOnly; // only use the blanker, not the defined saver
TQValueVector< DCOPClientTransaction* > mLockTransactions;
public:
SaverEngineThreadHelperObject* m_threadHelperObject;
bool mBlankOnly; // only use the blanker, not the defined saver // protected
SaverEngineEventHandler *m_saverEngineEventHandler;
private:
TQEventLoopThread* m_helperThread;
sigset_t mThreadBlockSet;
TDEProcess* mSAKProcess;
bool mTerminationRequested;
bool mSaverProcessReady;
TQEventLoopThread* m_eventHandlerThread;
bool mNewVTAfterLockEngage;
bool mValidCryptoCardInserted;
int mSwitchVTAfterLockEngage;
struct sigaction mSignalAction;
TQT_DBusConnection dBusConn;
TQT_DBusProxy* dBusLocal;
TQT_DBusProxy* dBusWatch;
TQT_DBusProxy* systemdSession;
TQT_DBusProxy *dBusLocal;
TQT_DBusProxy *dBusWatch;
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

@ -71,7 +71,7 @@ static TDECmdLineOptions options[] =
};
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
XCloseDisplay( dpy );
}
if( myApp == NULL )
if (!myApp)
myApp = new KDesktopApp;
#else
myApp = new KDesktopApp;
@ -260,9 +260,6 @@ extern "C" TDE_EXPORT int kdemain( int argc, char **argv )
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
SaverEngine saver;
@ -279,16 +276,15 @@ extern "C" TDE_EXPORT int kdemain( int argc, char **argv )
myApp->config()->reparseConfiguration();
}
// for the KDE-already-running check in starttde
TDESelectionOwner kde_running( "_KDE_RUNNING", 0 );
kde_running.claim( false );
// for the TDE-already-running check in starttde
TDESelectionOwner tde_running( "_KDE_RUNNING", 0 );
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 );
args->clear();
myApp->dcopClient()->setDefaultObject( "KDesktopIface" );
return myApp->exec();
}

Loading…
Cancel
Save