Commit c6cc00cc authored by Lukas Appelhans's avatar Lukas Appelhans

Basically fix the heisenbug

parent 7d3af61e
......@@ -98,7 +98,8 @@ SQLiteResource PolKitSQLiteConnection::query(const QString &q)
return SQLiteResource(list);
}
} else {
qDebug() << "Authorization not granted" << PolkitQt1::Authority::instance()->errorDetails();//TODO: error handling
Akabei::ErrorQueue::instance()->appendError(
Akabei::Error(Akabei::Error::PermissionError, PolkitQt1::Authority::instance()->errorDetails()));
}
return SQLiteResource(QList<Row>());
}
......@@ -116,7 +117,8 @@ void PolKitSQLiteConnection::query(const QString &q, const QVariantMap &bindings
QDBusMessage mes = iface.call("query", q, bindings);
d->lastQueryDBus = true;
} else {
qDebug() << "Authorization not granted" << PolkitQt1::Authority::instance()->errorDetails();//TODO: error handling
Akabei::ErrorQueue::instance()->appendError(
Akabei::Error(Akabei::Error::PermissionError, PolkitQt1::Authority::instance()->errorDetails()));
}
}
......
......@@ -227,13 +227,15 @@ void Backend::setStatus(Backend::Status s, QObject * cO, const char * cS)
if (Akabei::Helpers::checkAuthorizationSync("org.chakraproject.akabeicorehelper.filesystem.lock")) {
setStatus(Backend::StatusWaitingForLock);
qDebug() << "Authorization granted";
QDBusInterface iface("org.chakraproject.akabeicorehelper", "/filesystem", "org.chakraproject.akabeicorehelper.filesystem", QDBusConnection::systemBus());
iface.setProperty("root", Config::instance()->root());
iface.connection().connect("org.chakraproject.akabeicorehelper", "/filesystem", "org.chakraproject.akabeicorehelper.filesystem", "lockGranted", this, SLOT(__k__lockGranted(qint64)));
if (!d->iface) {
d->iface = new QDBusInterface("org.chakraproject.akabeicorehelper", "/filesystem", "org.chakraproject.akabeicorehelper.filesystem", QDBusConnection::systemBus());
}
d->iface->setProperty("root", Config::instance()->root());
QDBusMessage mes = iface.call("getLock", QCoreApplication::applicationPid());
connect(d->iface, SIGNAL(lockGranted(qlonglong)), SLOT(__k__lockGranted(qlonglong)));
QDBusMessage mes = d->iface->call("getLock", QCoreApplication::applicationPid());
} else {
qDebug() << "Authorization not granted" << PolkitQt1::Authority::instance()->errorDetails();
Akabei::ErrorQueue::instance()->appendError(Error(Error::PermissionError, tr("An authorization error occurred: %1").arg(PolkitQt1::Authority::instance()->errorDetails())));
......@@ -260,7 +262,6 @@ void Backend::setStatus(Backend::Status s, QObject * cO, const char * cS)
lockinfo.l_start = 0;
lockinfo.l_len = 0;
setStatus(Backend::StatusWaitingForLock);
if (fcntl(d->lockFileHandle->handle(), F_SETLK, &lockinfo) == -1) {
......@@ -280,27 +281,28 @@ void Backend::setStatus(Backend::Status s, QObject * cO, const char * cS)
qDebug() << "We need privileges to remove lock";
if (Akabei::Helpers::checkAuthorizationSync("org.chakraproject.akabeicorehelper.filesystem.lock")) {
qDebug() << "Authorization granted";
QDBusInterface iface("org.chakraproject.akabeicorehelper", "/filesystem", "org.chakraproject.akabeicorehelper.filesystem", QDBusConnection::systemBus());
QDBusMessage mes = iface.call("removeLock", QCoreApplication::applicationPid());
disconnect(d->iface, SIGNAL(lockGranted(qlonglong)), this, SLOT(__k__lockGranted(qlonglong)));
QDBusMessage mes = d->iface->call("removeLock", QCoreApplication::applicationPid());
} else {
qDebug() << "Authorization not granted" << PolkitQt1::Authority::instance()->errorDetails();
setStatus(Backend::StatusBroken);
Akabei::ErrorQueue::instance()->appendError(Error(Error::PermissionError, PolkitQt1::Authority::instance()->errorDetails()));
return;
}
return;
}
struct flock lockinfo;
memset(&lockinfo, 0, sizeof(struct flock));
lockinfo.l_type = F_UNLCK;
lockinfo.l_whence = SEEK_SET;
lockinfo.l_start = 0;
lockinfo.l_len = 0;
} else {
struct flock lockinfo;
memset(&lockinfo, 0, sizeof(struct flock));
lockinfo.l_type = F_UNLCK;
lockinfo.l_whence = SEEK_SET;
lockinfo.l_start = 0;
lockinfo.l_len = 0;
if (fcntl(d->lockFileHandle->handle(), F_SETLK, &lockinfo) == -1) {
Akabei::ErrorQueue::instance()->appendError(Error(Error::FilesystemError, tr("Could not remove lock file properly!")));
akabeiDebug() << "lock could not get released?!";
if (fcntl(d->lockFileHandle->handle(), F_SETLK, &lockinfo) == -1) {
Akabei::ErrorQueue::instance()->appendError(Error(Error::FilesystemError, tr("Could not remove lock file properly!")));
akabeiDebug() << "lock could not get released?!";
}
return;
}
}
......@@ -416,14 +418,14 @@ void BackendPrivate::groupQueryFinished()
emit q->queryGroupsCompleted(uuid, result);
}
void BackendPrivate::__k__lockGranted(qint64 pid)
void BackendPrivate::__k__lockGranted(qlonglong pid)
{
Q_Q(Backend);
qDebug() << "LOCK GRANTED TO" << pid << "We got" << QCoreApplication::applicationPid();
if (pid != QCoreApplication::applicationPid())
return;
q->setStatus(Backend::StatusOnTransaction);
if (callbackObject && callbackSlot)
QMetaObject::invokeMethod(callbackObject, callbackSlot);
}
......
......@@ -247,7 +247,7 @@ class AKABEICORESHARED_EXPORT Backend : public QObject
BackendPrivate * const d_ptr;
Q_PRIVATE_SLOT(d_func(), void __k__initializationFinished())
Q_PRIVATE_SLOT(d_func(), void __k__lockGranted(qint64))
Q_PRIVATE_SLOT(d_func(), void __k__lockGranted(qlonglong))
Q_PRIVATE_SLOT(d_func(), void __k__lockGranted())
friend class DatabasePrivate;
......
......@@ -22,6 +22,7 @@
#include <QFile>
#include <QReadWriteLock>
#include <QCoreApplication>
#include <QDBusInterface>
namespace Akabei
{
......@@ -60,13 +61,15 @@ class BackendPrivate : public QObject
, lockFileHandle(0)
, fsWatcher(new QFileSystemWatcher(p))
, groupPool(new GroupPool)
, runner(new OperationRunner(p)) {}
, runner(new OperationRunner(p))
, iface(0) {}
~BackendPrivate() {
delete lockFileHandle;
qDeleteAll(databases);
delete localDatabase;
delete groupPool;
delete mutex;
delete iface;
}
Backend::Status status;
......@@ -91,7 +94,7 @@ class BackendPrivate : public QObject
const char * callbackSlot;
void __k__initializationFinished();
void __k__lockGranted(qint64 pid);
void __k__lockGranted(qlonglong pid);
void __k__lockGranted() { __k__lockGranted(QCoreApplication::applicationPid()); }
void getLock();
......@@ -99,6 +102,8 @@ class BackendPrivate : public QObject
void addDatabase(const QString &name);
Package* parseInfoFile();
QDBusInterface * iface;
public slots:
void packageQueryFinished();
......
......@@ -126,6 +126,13 @@ class Error
QSharedDataPointer<Private> d;
};
/**
* \class ErrorQueue akabeierror.h "akabeierror.h"
*
* \brief Class for registering errors
*
* This class is thread-safe.
*/
class ErrorQueue
{
Q_DISABLE_COPY(ErrorQueue)
......@@ -133,16 +140,41 @@ class ErrorQueue
public:
virtual ~ErrorQueue();
/**
* @returns the static ErrorQueue object
*/
static ErrorQueue* instance();
/**
* Takes an error off the queue
* @returns the error taken off
*/
Error takeError();
/**
* @returns the type of the error which sits at the first position of the queue
*/
Error::Type headType() const;
/**
* @returns true when the queue is empty
*/
bool isEmpty() const;
/**
* Appends an error onto the queue
*/
void appendError(const Error &);
/**
* Appends a list of errors onto the queue
*/
void appendErrors(const Error::List &);
/**
* Registers an error handler for a certain error type
*/
void registerForErrorType(Error::Type, QObject *, const char *);
/**
* Registers an error handler for all errors
*/
void registerForAllErrors(QObject *, const char *);
private:
......
......@@ -420,8 +420,10 @@ bool checkAuthorizationSync(const QString &action)
PolkitQt1::Authority::AllowUserInteraction);
e.exec();
QObject::disconnect(PolkitQt1::Authority::instance(), SIGNAL(checkAuthorizationFinished(PolkitQt1::Authority::Result)), &e, SLOT(quit(PolkitQt1::Authority::Result)));
return e.result() == PolkitQt1::Authority::Yes;//(auth == PolkitQt1::Authority::Yes);
return e.result() == PolkitQt1::Authority::Yes;
}
///////
......
......@@ -36,9 +36,6 @@ void OperationPrivate::concurrentValidate()
status = Operation::StatusValidating;
q->validate();
if (status == Operation::StatusValidating) {
//runLoop.data()->processEvents();
//QCoreApplication::processEvents();
//QCoreApplication::sendPostedEvents();
validateLoop.data()->exec();
}
validateLoop.data()->deleteLater();
......@@ -47,16 +44,10 @@ void OperationPrivate::concurrentValidate()
void OperationPrivate::concurrentRun()
{
Q_Q(Operation);
//QEventLoop loop;
runLoop = new QEventLoop;
setStatus(Operation::StatusRunning);
q->run();//FIXME: Try to catch all events posted from and to the operation and redo them with the eventloop
qDebug() << "Start event loop from?!" << q->description() << QTime::currentTime().msec();
q->run();
if (status == Operation::StatusRunning) {
qDebug() << "Really start it";
//runLoop.data()->processEvents();
//QCoreApplication::processEvents();
//QCoreApplication::sendPostedEvents();
runLoop.data()->exec();
}
runLoop.data()->deleteLater();
......@@ -77,7 +68,7 @@ void OperationPrivate::setProcessingOptions(ProcessingOptions options)
}
Operation::Operation(const QString &targetName)
: d_ptr(new OperationPrivate(this, targetName))
: QObject(0), d_ptr(new OperationPrivate(this, targetName))
{
}
......@@ -276,7 +267,6 @@ void Operation::setProgress(int percentage)
{
Q_D(Operation);
if (d->runner) {
qDebug() << "Start emit progress at" << QTime::currentTime().toString();
d->runner->d_func()->emitProgress(this, qBound(0, percentage, 100));
}
}
......@@ -296,7 +286,6 @@ void Operation::setFinished(bool result)
d->runner->d_func()->emitFinished(this, result);
}
if (!d->runLoop.isNull()) {
qDebug() << "Quit event loop";
d->runLoop.data()->quit();
}
}
......@@ -344,3 +333,5 @@ void Operation::setEta(int eta)
}
}
#include "akabeioperation.moc"
......@@ -76,10 +76,11 @@ class OperationPrivate;
* @see run
* @see validate
*/
class Operation
class Operation : public QObject
{
friend class ArchiveHandler;
Q_OBJECT
Q_DISABLE_COPY(Operation)
Q_DECLARE_PRIVATE(Operation)
public:
......
......@@ -232,7 +232,7 @@ void OperationRunnerPrivate::__k__doValidate()
QObject::connect(valThread.data(), SIGNAL(ready()), q, SLOT(__k__connectToValidationStatus()), Qt::DirectConnection);
QThreadPool::globalInstance()->start(valThread.data());
valThread.data()->run();
}
void OperationRunnerPrivate::__k__connectToValidationStatus()
......@@ -266,7 +266,7 @@ void OperationRunner::run()
QObject::connect(d->runThread.data(), SIGNAL(ready()), this, SLOT(__k__connectToRunnerStatus()), Qt::DirectConnection);
QThreadPool::globalInstance()->start(d->runThread.data());
d->runThread.data()->run();
}
void OperationRunnerPrivate::__k__connectToRunnerStatus()
......
......@@ -17,6 +17,8 @@
#include <QtConcurrentMap>
#include <QFutureWatcher>
#include <QEventLoop>
#include <QTimer>
#include <QCoreApplication>
static QWeakPointer<QFutureWatcher< void > > s_runFutureWatcher;
static Akabei::ProcessingOptions s_options;
......@@ -119,6 +121,11 @@ void RunnerWorker::processNextPhase()
m_currentPhase = Operation::Phase5;
break;
case Operation::Phase5:
//Now we need to move all ops back to the main app thread
foreach (QList<Operation*> ops, m_operations.values()) {
foreach (Operation * op, ops)
op->moveToThread(QCoreApplication::instance()->thread());
}
// If we're here, we're successfully over.
emit runFinished(true);
return;
......@@ -203,9 +210,9 @@ void RunnerWorker::run()
RunnerRunnable::RunnerRunnable(const QHash<Operation::Phase, QList< Operation* > > &ops, ProcessingOptions processingOptions, QObject* parent)
: QObject(parent)
, QRunnable()
, m_operations(ops)
, m_worker(0)
, m_thread(new QThread())
{
s_options = processingOptions;
}
......@@ -214,9 +221,9 @@ RunnerRunnable::~RunnerRunnable()
{
if (m_worker)
m_worker->deleteLater();
delete m_thread;
}
void RunnerRunnable::requestCancel()
{
......@@ -226,8 +233,14 @@ void RunnerRunnable::run()
{
//Don't parent, otherwise we break thread-affinity!!!
m_worker = new RunnerWorker(m_operations);
m_worker->moveToThread(m_thread);
foreach (QList<Operation*> ops, m_operations.values()) {
foreach (Operation * op, ops)
op->moveToThread(m_thread);
}
emit ready();
m_worker->run();
QTimer::singleShot(0, m_worker, SLOT(run()));
m_thread->start();
}
RunnerWorker * RunnerRunnable::worker()
......
......@@ -14,7 +14,6 @@
#include <QThread>
#include <QHash>
#include <QWeakPointer>
#include <QRunnable>
#include <akabeierror.h>
#include <akabeioperation.h>
......@@ -54,7 +53,7 @@ class RunnerWorker : public QObject
friend class RunnerRunnable;
};
class RunnerRunnable : public QObject, public QRunnable
class RunnerRunnable : public QObject
{
Q_OBJECT
public:
......@@ -64,9 +63,7 @@ class RunnerRunnable : public QObject, public QRunnable
RunnerWorker * worker();
void requestCancel();
protected:
virtual void run();
void run();
Q_SIGNALS:
void ready();
......@@ -74,6 +71,7 @@ class RunnerRunnable : public QObject, public QRunnable
private:
QHash<Operation::Phase, QList< Operation* > > m_operations;
RunnerWorker * m_worker;
QThread * m_thread;
};
}
......
......@@ -26,6 +26,8 @@
#include <QEventLoop>
#include <QFutureWatcher>
#include <QDir>
#include <QTimer>
#include <QCoreApplication>
#define ERRORS_CHECKPOINT() if (!errors.isEmpty()) { \
manageErrors(errors); \
......@@ -139,6 +141,11 @@ void ValidatorWorker::processNextPhase()
m_currentPhase = Operation::Phase5;
break;
case Operation::Phase5:
//Now we need to move all ops back to the main app thread
foreach (QList<Operation*> ops, m_operations.values()) {
foreach (Operation * op, ops)
op->moveToThread(QCoreApplication::instance()->thread());
}
// If we're here, we're successfully over.
emit validationFinished(true, m_operations);
return;
......@@ -429,6 +436,7 @@ ValidatorRunnable::ValidatorRunnable(const QHash<Operation::Phase, QList< Operat
, QRunnable()
, m_operations(ops)
, m_worker(0)
, m_thread(new QThread())
{
s_options = processingOptions;
}
......@@ -437,6 +445,7 @@ ValidatorRunnable::~ValidatorRunnable()
{
if (m_worker)
m_worker->deleteLater();
delete m_thread;
}
ValidatorWorker* ValidatorRunnable::worker()
......@@ -453,8 +462,15 @@ void ValidatorRunnable::run()
{
//Don't use a parent here, otherwise we break thread affinity!!!
m_worker = new ValidatorWorker(m_operations);
m_worker->moveToThread(m_thread);
foreach (QList<Operation*> ops, m_operations.values()) {
foreach (Operation * op, ops)
op->moveToThread(m_thread);
}
emit ready();
m_worker->run();
// m_worker->run();
QTimer::singleShot(0, m_worker, SLOT(run()));
m_thread->start();
}
}
......
......@@ -17,6 +17,7 @@
#include <QRunnable>
#include <QHash>
#include <QThread>
namespace Akabei {
class OperationPrivate;
......@@ -68,16 +69,15 @@ class ValidatorRunnable : public QObject, public QRunnable
ValidatorWorker * worker();
void requestCancel();
void run();
Q_SIGNALS:
void ready();
protected:
virtual void run();
private:
OpsHash m_operations;
ValidatorWorker * m_worker;
QThread * m_thread;
};
}
......
......@@ -59,8 +59,7 @@ PlainHookOperation *PlainHookOperation::instance()
}
PlainHookOperation::PlainHookOperation()
: QObject(0),
Operation("Hooks"),
: Operation("Hooks"),
d(new Private(this))
{
Q_ASSERT(!s_globalHookOp()->q);
......
......@@ -16,7 +16,7 @@
namespace Akabei {
class Database;
class AKABEICORESHARED_EXPORT PlainHookOperation : public QObject, public Operation
class AKABEICORESHARED_EXPORT PlainHookOperation : public Operation
{
Q_OBJECT
public:
......
......@@ -86,8 +86,7 @@ class PlainScriptletOperation::Private
};
PlainScriptletOperation::PlainScriptletOperation(Package *p, const QStringList& args)
: QObject(0)
, Operation("Script for " + p->name())
: Operation("Script for " + p->name())
, d(new Private)
{
d->package = p;
......
......@@ -18,7 +18,7 @@
namespace Akabei {
class Package;
class AKABEICORESHARED_EXPORT PlainScriptletOperation : public QObject, public Operation
class AKABEICORESHARED_EXPORT PlainScriptletOperation : public Operation
{
Q_OBJECT
public:
......
......@@ -48,8 +48,7 @@ class PolkitInstallOperation::Private
};
PolkitInstallOperation::PolkitInstallOperation(Package *package, Akabei::Package::InstallReason installReason)
: QObject(0)
, Operation(package->name())
: Operation(package->name())
, d(new Private(package, installReason, this))
{
setPhase(Phase3); // Installation happens in phase 3.
......
......@@ -15,13 +15,12 @@
#include <akabeicore_global.h>
#include <akabeioperation.h>
#include <akabeipackage.h>
#include <QObject>
namespace Akabei {
class Package;
class AKABEICORESHARED_EXPORT PolkitInstallOperation : public QObject, public Operation
class AKABEICORESHARED_EXPORT PolkitInstallOperation : public Operation
{
Q_OBJECT
Q_DISABLE_COPY(PolkitInstallOperation)
......
......@@ -47,8 +47,7 @@ public:
};
PolkitReInstallOperation::PolkitReInstallOperation(Package * package, Package * localPackage)
: QObject(0),
Operation(package->name()),
: Operation(package->name()),
d(new Private(package, localPackage, this))
{
setPhase(Phase3);// Reinstall happens in phase 3.
......
......@@ -14,12 +14,11 @@
#include <akabeioperation.h>
#include <akabeicore_global.h>
#include <QObject>
#include <QStringList>
namespace Akabei {
class Package;
class AKABEICORESHARED_EXPORT PolkitReInstallOperation : public QObject, public Operation
class AKABEICORESHARED_EXPORT PolkitReInstallOperation : public Operation
{
Q_OBJECT
Q_DISABLE_COPY(PolkitReInstallOperation)
......
......@@ -39,8 +39,7 @@ class PolkitRemoveOperation::Private
};
PolkitRemoveOperation::PolkitRemoveOperation(Package* package)
: QObject(0),
Operation(package->name()),
: Operation(package->name()),
d(new Private(package, this))
{
setPhase(Phase3); // Removal happens in phase 3.
......
......@@ -14,7 +14,6 @@
#include <akabeicore_global.h>
#include <akabeioperation.h>
#include <QObject>
namespace Akabei
{
......@@ -24,7 +23,7 @@ class Package;
* @class PolkitRemoveOperation
* @brief Operation to remove a package from the system using polkit.
*/
class AKABEICORESHARED_EXPORT PolkitRemoveOperation : public QObject, public Operation
class AKABEICORESHARED_EXPORT PolkitRemoveOperation : public Operation
{
Q_OBJECT
Q_DISABLE_COPY(PolkitRemoveOperation)
......
......@@ -50,8 +50,7 @@ class PolkitUpgradeOperation::Private
QDBusInterface * iface;
};
PolkitUpgradeOperation::PolkitUpgradeOperation(Package* from, Package* to)
: QObject(0)
, Operation(to->name())
: Operation(to->name())
, d(new Private(from, to, this))
{
setPhase(Phase3); // Upgrade happens in phase 3.
......
......@@ -15,12 +15,11 @@
#include <akabeioperation.h>
#include <akabeicore_global.h>
#include <QObject>
namespace Akabei {
class Package;
class AKABEICORESHARED_EXPORT PolkitUpgradeOperation : public QObject, public Operation
class AKABEICORESHARED_EXPORT PolkitUpgradeOperation : public Operation
{
Q_OBJECT
Q_DISABLE_COPY(PolkitUpgradeOperation)
......