[Pkg-owncloud-commits] [qtkeychain] 41/115: D-Bus: Serialize job execution. kwalletd gets lost in nested eventloops when we send multiple openWallet() dbus calls in parallel. Thus synchronize job execution using an internal JobExecutor singleton.

Sandro Knauß hefee-guest at moszumanska.debian.org
Sat Mar 15 19:25:44 UTC 2014


This is an automated email from the git hooks/post-receive script.

hefee-guest pushed a commit to branch master
in repository qtkeychain.

commit 42db0f2d4d3e315c1b36867f93988c540e5856a6
Author: Frank Osterfeld <osterfeld at kde.org>
Date:   Fri Jul 27 23:10:47 2012 +0200

    D-Bus: Serialize job execution.
    kwalletd gets lost in nested eventloops when we send multiple openWallet() dbus calls in parallel.
    Thus synchronize job execution using an internal JobExecutor singleton.
---
 CMakeLists.txt    |  3 ++-
 keychain.cpp      | 14 +++++-----
 keychain.h        | 26 +++++++++++++------
 keychain_dbus.cpp | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
 keychain_dbus_p.h | 45 ++++++++++++++++++++++++++++++++
 keychain_mac.cpp  |  4 +--
 keychain_p.h      | 22 ++++++++++------
 keychain_win.cpp  |  4 +--
 8 files changed, 160 insertions(+), 35 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 472110b..1442ae4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -41,9 +41,10 @@ if(UNIX AND NOT APPLE)
     list(APPEND qtkeychain_SOURCES keychain_dbus.cpp)
     qt4_add_dbus_interface(qtkeychain_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/org.kde.KWallet.xml kwallet_interface KWalletInterface)
     list(APPEND qtkeychain_LIBRARIES ${QT_QTDBUS_LIBRARY})
+    list(APPEND qtkeychain_EXTRA_MOC_HEADERS keychain_dbus_p.h)
 endif()
 
-QT4_WRAP_CPP(qtkeychain_MOC_OUTFILES keychain.h keychain_p.h)
+QT4_WRAP_CPP(qtkeychain_MOC_OUTFILES keychain.h keychain_p.h ${qtkeychain_EXTRA_MOC_HEADERS})
 
 if(NOT QTKEYCHAIN_STATIC)
     add_library(qtkeychain SHARED ${qtkeychain_SOURCES} ${qtkeychain_MOC_OUTFILES})
diff --git a/keychain.cpp b/keychain.cpp
index 3f275ee..1694036 100644
--- a/keychain.cpp
+++ b/keychain.cpp
@@ -13,7 +13,7 @@ using namespace QKeychain;
 
 Job::Job( const QString& service, QObject *parent )
     : QObject( parent )
-    , d ( new Private( service ) ) {
+    , d ( new JobPrivate( service ) ) {
 }
 
 Job::~Job() {
@@ -74,7 +74,7 @@ void Job::setErrorString( const QString& errorString ) {
 
 ReadPasswordJob::ReadPasswordJob( const QString& service, QObject* parent )
     : Job( service, parent )
-    , d( new Private( this ) )
+    , d( new ReadPasswordJobPrivate( this ) )
 {}
 
 ReadPasswordJob::~ReadPasswordJob() {
@@ -103,7 +103,7 @@ void ReadPasswordJob::doStart() {
 
 WritePasswordJob::WritePasswordJob( const QString& service, QObject* parent )
     : Job( service, parent )
-    , d( new Private( this ) ) {
+    , d( new WritePasswordJobPrivate( this ) ) {
 }
 
 WritePasswordJob::~WritePasswordJob() {
@@ -120,12 +120,12 @@ void WritePasswordJob::setKey( const QString& key ) {
 
 void WritePasswordJob::setBinaryData( const QByteArray& data ) {
     d->binaryData = data;
-    d->mode = Private::Binary;
+    d->mode = WritePasswordJobPrivate::Binary;
 }
 
 void WritePasswordJob::setTextData( const QString& data ) {
     d->textData = data;
-    d->mode = Private::Text;
+    d->mode = WritePasswordJobPrivate::Text;
 }
 
 void WritePasswordJob::doStart() {
@@ -134,7 +134,7 @@ void WritePasswordJob::doStart() {
 
 DeletePasswordJob::DeletePasswordJob( const QString& service, QObject* parent )
     : Job( service, parent )
-    , d( new Private( this ) ) {
+    , d( new DeletePasswordJobPrivate( this ) ) {
 }
 
 DeletePasswordJob::~DeletePasswordJob() {
@@ -158,7 +158,7 @@ void DeletePasswordJob::setKey( const QString& key ) {
     d->key = key;
 }
 
-void DeletePasswordJob::Private::jobFinished( Job* job ) {
+void DeletePasswordJobPrivate::jobFinished( Job* job ) {
     q->setError( job->error() );
     q->setErrorString( job->errorString() );
     q->emitFinished();
diff --git a/keychain.h b/keychain.h
index ffd3b8b..0eab557 100644
--- a/keychain.h
+++ b/keychain.h
@@ -32,6 +32,9 @@ enum Error {
     OtherError /**< Something else went wrong (errorString() might provide details) */
 };
 
+class JobExecutor;
+class JobPrivate;
+
 class QKEYCHAIN_EXPORT Job : public QObject {
     Q_OBJECT
 public:
@@ -63,10 +66,11 @@ protected:
     void emitFinishedWithError(Error, const QString& errorString);
 
 private:
-    class Private;
-    Private* const d;
+    JobPrivate* const d;
 };
 
+class ReadPasswordJobPrivate;
+
 class QKEYCHAIN_EXPORT ReadPasswordJob : public Job {
     Q_OBJECT
 public:
@@ -83,10 +87,13 @@ protected:
     void doStart();
 
 private:
-    class Private;
-    Private* const d;
+    friend class QKeychain::ReadPasswordJobPrivate;
+    friend class QKeychain::JobExecutor;
+    ReadPasswordJobPrivate* const d;
 };
 
+class WritePasswordJobPrivate;
+
 class QKEYCHAIN_EXPORT WritePasswordJob : public Job {
     Q_OBJECT
 public:
@@ -103,10 +110,13 @@ protected:
     void doStart();
 
 private:
-    class Private;
-    Private* const d;
+    friend class QKeychain::JobExecutor;
+    friend class QKeychain::WritePasswordJobPrivate;
+    WritePasswordJobPrivate* const d;
 };
 
+class DeletePasswordJobPrivate;
+
 class QKEYCHAIN_EXPORT DeletePasswordJob : public Job {
     Q_OBJECT
 public:
@@ -120,8 +130,8 @@ protected:
     void doStart();
 
 private:
-    class Private;
-    Private* const d;
+    friend class QKeychain::DeletePasswordJobPrivate;
+    DeletePasswordJobPrivate* const d;
 };
 
 } // namespace QtKeychain
diff --git a/keychain_dbus.cpp b/keychain_dbus.cpp
index 7273e74..c142507 100644
--- a/keychain_dbus.cpp
+++ b/keychain_dbus.cpp
@@ -7,19 +7,78 @@
  * details, check the accompanying file 'COPYING'.                            *
  *****************************************************************************/
 #include "keychain_p.h"
+#include "keychain_dbus_p.h"
 
 #include <QSettings>
 
 using namespace QKeychain;
 
-void ReadPasswordJob::Private::doStart() {
+JobExecutor::JobExecutor()
+    : QObject( 0 )
+    , m_runningJob( 0 )
+{
+}
+
+void JobExecutor::enqueue( Job* job ) {
+    m_queue.append( job );
+    startNextIfNoneRunning();
+}
+
+void JobExecutor::startNextIfNoneRunning() {
+    if ( m_queue.isEmpty() || m_runningJob )
+        return;
+    QPointer<Job> next;
+    while ( !next && !m_queue.isEmpty() ) {
+        next = m_queue.first();
+        m_queue.pop_front();
+    }
+    if ( next ) {
+        connect( next, SIGNAL(finished(QKeychain::Job*)), this, SLOT(jobFinished(QKeychain::Job*)) );
+        connect( next, SIGNAL(destroyed(QObject*)), this, SLOT(jobDestroyed(QObject*)) );
+        m_runningJob = next;
+        if ( ReadPasswordJob* rpj = qobject_cast<ReadPasswordJob*>( m_runningJob ) )
+            rpj->d->scheduledStart();
+        else if ( WritePasswordJob* wpj = qobject_cast<WritePasswordJob*>( m_runningJob) )
+            wpj->d->scheduledStart();
+    }
+}
+
+void JobExecutor::jobDestroyed( QObject* object ) {
+    Q_UNUSED( object ) // for release mode
+    Q_ASSERT( object == m_runningJob );
+    m_runningJob->disconnect( this );
+    m_runningJob = 0;
+    startNextIfNoneRunning();
+}
+
+void JobExecutor::jobFinished( Job* job ) {
+    Q_UNUSED( job ) // for release mode
+    Q_ASSERT( job == m_runningJob );
+    m_runningJob->disconnect( this );
+    m_runningJob = 0;
+    startNextIfNoneRunning();
+}
+
+JobExecutor* JobExecutor::s_instance = 0;
+
+JobExecutor* JobExecutor::instance() {
+    if ( !s_instance )
+        s_instance = new JobExecutor;
+    return s_instance;
+}
+
+void ReadPasswordJobPrivate::doStart() {
+    JobExecutor::instance()->enqueue( q );
+}
+
+void ReadPasswordJobPrivate::scheduledStart() {
     iface = new org::kde::KWallet( QLatin1String("org.kde.kwalletd"), QLatin1String("/modules/kwalletd"), QDBusConnection::sessionBus(), this );
     const QDBusPendingReply<int> reply = iface->open( QLatin1String("kdewallet"), 0, q->service() );
     QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher( reply, this );
     connect( watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(kwalletOpenFinished(QDBusPendingCallWatcher*)) );
 }
 
-void ReadPasswordJob::Private::kwalletOpenFinished( QDBusPendingCallWatcher* watcher ) {
+void ReadPasswordJobPrivate::kwalletOpenFinished( QDBusPendingCallWatcher* watcher ) {
     watcher->deleteLater();
     const QDBusPendingReply<int> reply = *watcher;
     if ( reply.isError() ) {
@@ -43,7 +102,7 @@ void ReadPasswordJob::Private::kwalletOpenFinished( QDBusPendingCallWatcher* wat
     connect( nextWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(kwalletEntryTypeFinished(QDBusPendingCallWatcher*)) );
 }
 
-void ReadPasswordJob::Private::kwalletEntryTypeFinished( QDBusPendingCallWatcher* watcher ) {
+void ReadPasswordJobPrivate::kwalletEntryTypeFinished( QDBusPendingCallWatcher* watcher ) {
     watcher->deleteLater();
     if ( watcher->isError() ) {
         const QDBusError err = watcher->error();
@@ -62,7 +121,7 @@ void ReadPasswordJob::Private::kwalletEntryTypeFinished( QDBusPendingCallWatcher
     connect( nextWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(kwalletReadFinished(QDBusPendingCallWatcher*)) );
 }
 
-void ReadPasswordJob::Private::kwalletReadFinished( QDBusPendingCallWatcher* watcher ) {
+void ReadPasswordJobPrivate::kwalletReadFinished( QDBusPendingCallWatcher* watcher ) {
     watcher->deleteLater();
     if ( watcher->isError() ) {
         const QDBusError err = watcher->error();
@@ -80,14 +139,18 @@ void ReadPasswordJob::Private::kwalletReadFinished( QDBusPendingCallWatcher* wat
     q->emitFinished();
 }
 
-void WritePasswordJob::Private::doStart() {
+void WritePasswordJobPrivate::doStart() {
+    JobExecutor::instance()->enqueue( q );
+}
+
+void WritePasswordJobPrivate::scheduledStart() {
     iface = new org::kde::KWallet( QLatin1String("org.kde.kwalletd"), QLatin1String("/modules/kwalletd"), QDBusConnection::sessionBus(), this );
     const QDBusPendingReply<int> reply = iface->open( QLatin1String("kdewallet"), 0, q->service() );
     QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher( reply, this );
     connect( watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(kwalletOpenFinished(QDBusPendingCallWatcher*)) );
 }
 
-void WritePasswordJob::Private::kwalletOpenFinished( QDBusPendingCallWatcher* watcher ) {
+void WritePasswordJobPrivate::kwalletOpenFinished( QDBusPendingCallWatcher* watcher ) {
     watcher->deleteLater();
     QDBusPendingReply<int> reply = *watcher;
     if ( reply.isError() ) {
@@ -116,7 +179,7 @@ void WritePasswordJob::Private::kwalletOpenFinished( QDBusPendingCallWatcher* wa
     connect( nextWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(kwalletWriteFinished(QDBusPendingCallWatcher*)) );
 }
 
-void WritePasswordJob::Private::kwalletWriteFinished( QDBusPendingCallWatcher* watcher ) {
+void WritePasswordJobPrivate::kwalletWriteFinished( QDBusPendingCallWatcher* watcher ) {
     watcher->deleteLater();
     QDBusPendingReply<int> reply = *watcher;
     if ( reply.isError() ) {
diff --git a/keychain_dbus_p.h b/keychain_dbus_p.h
new file mode 100644
index 0000000..fee59eb
--- /dev/null
+++ b/keychain_dbus_p.h
@@ -0,0 +1,45 @@
+/******************************************************************************
+ *   Copyright (C) 2012 Frank Osterfeld <frank.osterfeld at gmail.com>           *
+ *                                                                            *
+ * This program is distributed in the hope that it will be useful, but        *
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *
+ * or FITNESS FOR A PARTICULAR PURPOSE. For licensing and distribution        *
+ * details, check the accompanying file 'COPYING'.                            *
+ *****************************************************************************/
+
+#ifndef QTKEYCHAIN_KEYCHAIN_DBUS_P_H
+#define QTKEYCHAIN_KEYCHAIN_DBUS_P_H
+
+#include "keychain.h"
+
+#include <QPointer>
+#include <QVector>
+
+namespace QKeychain {
+
+class JobExecutor : public QObject {
+    Q_OBJECT
+public:
+
+    static JobExecutor* instance();
+
+    void enqueue( Job* job );
+
+private:
+    explicit JobExecutor();
+    void startNextIfNoneRunning();
+
+private Q_SLOTS:
+    void jobFinished( QKeychain::Job* );
+    void jobDestroyed( QObject* object );
+
+private:
+    static JobExecutor* s_instance;
+    Job* m_runningJob;
+    QVector<QPointer<Job> > m_queue;
+};
+
+}
+
+#endif
+
diff --git a/keychain_mac.cpp b/keychain_mac.cpp
index d81ecf5..4515f99 100644
--- a/keychain_mac.cpp
+++ b/keychain_mac.cpp
@@ -61,7 +61,7 @@ static OSStatus readPw( QByteArray* pw,
     return ret;
 }
 
-void ReadPasswordJob::Private::doStart()
+void ReadPasswordJobPrivate::doStart()
 {
     QString errorString;
     Error error = NoError;
@@ -141,7 +141,7 @@ static QKeychain::Error writeEntryImpl( const QString& service,
     return NoError;
 }
 
-void WritePasswordJob::Private::doStart()
+void WritePasswordJobPrivate::doStart()
 {
     QString errorString;
     Error error = NoError;
diff --git a/keychain_p.h b/keychain_p.h
index 0268aaf..c2a1dee 100644
--- a/keychain_p.h
+++ b/keychain_p.h
@@ -29,10 +29,12 @@ class QDBusPendingCallWatcher;
 
 namespace QKeychain {
 
-class Job::Private : public QObject {
+class JobExecutor;
+
+class JobPrivate : public QObject {
     Q_OBJECT
 public:
-    Private( const QString& service_ )
+    JobPrivate( const QString& service_ )
         : error( NoError )
         , service( service_ )
         , autoDelete( true ) {}
@@ -44,10 +46,10 @@ public:
     QPointer<QSettings> settings;
 };
 
-class ReadPasswordJob::Private : public QObject {
+class ReadPasswordJobPrivate : public QObject {
     Q_OBJECT
 public:
-    explicit Private( ReadPasswordJob* qq ) : q( qq ), walletHandle( 0 ), dataType( Text ) {}
+    explicit ReadPasswordJobPrivate( ReadPasswordJob* qq ) : q( qq ), walletHandle( 0 ), dataType( Text ) {}
     void doStart();
     ReadPasswordJob* const q;
     QByteArray data;
@@ -61,6 +63,8 @@ public:
 
 #if defined(Q_OS_UNIX) && !defined(Q_WS_MAC)
     org::kde::KWallet* iface;
+    friend class QKeychain::JobExecutor;
+    void scheduledStart();
 
 private Q_SLOTS:
     void kwalletOpenFinished( QDBusPendingCallWatcher* watcher );
@@ -75,10 +79,10 @@ private Q_SLOTS:
 
 };
 
-class WritePasswordJob::Private : public QObject {
+class WritePasswordJobPrivate : public QObject {
     Q_OBJECT
 public:
-    explicit Private( WritePasswordJob* qq ) : q( qq ), mode( Delete ) {}
+    explicit WritePasswordJobPrivate( WritePasswordJob* qq ) : q( qq ), mode( Delete ) {}
     void doStart();
     enum Mode {
         Delete,
@@ -93,6 +97,8 @@ public:
 
 #if defined(Q_OS_UNIX) && !defined(Q_WS_MAC)
     org::kde::KWallet* iface;
+    friend class QKeychain::JobExecutor;
+    void scheduledStart();
 
 private Q_SLOTS:
     void kwalletOpenFinished( QDBusPendingCallWatcher* watcher );
@@ -104,10 +110,10 @@ private Q_SLOTS:
 #endif
 };
 
-class DeletePasswordJob::Private : public QObject {
+class DeletePasswordJobPrivate : public QObject {
     Q_OBJECT
 public:
-    explicit Private( DeletePasswordJob* qq ) : q( qq ) {}
+    explicit DeletePasswordJobPrivate( DeletePasswordJob* qq ) : q( qq ) {}
     void doStart();
     DeletePasswordJob* const q;
     QString key;
diff --git a/keychain_win.cpp b/keychain_win.cpp
index 76b4116..509c0cb 100644
--- a/keychain_win.cpp
+++ b/keychain_win.cpp
@@ -17,7 +17,7 @@
 
 using namespace QKeychain;
 
-void ReadPasswordJob::Private::doStart() {
+void ReadPasswordJobPrivate::doStart() {
     //Use settings member if there, create local settings object if not
     std::auto_ptr<QSettings> local( !q->settings() ? new QSettings( q->service() ) : 0 );
     QSettings* actual = q->settings() ? q->settings() : local.get();
@@ -52,7 +52,7 @@ void ReadPasswordJob::Private::doStart() {
     q->emitFinished();
 }
 
-void WritePasswordJob::Private::doStart() {
+void WritePasswordJobPrivate::doStart() {
     if ( mode == Delete ) {
         //Use settings member if there, create local settings object if not
         std::auto_ptr<QSettings> local( !q->settings() ? new QSettings( q->service() ) : 0 );

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-owncloud/qtkeychain.git



More information about the Pkg-owncloud-commits mailing list