4
0
mirror of https://github.com/QuasarApp/qca.git synced 2025-05-07 08:19:33 +00:00

make SyncThread public

svn path=/trunk/kdesupport/qca/; revision=604527
This commit is contained in:
Justin Karneges 2006-11-13 05:59:14 +00:00
parent 0fb9275d6a
commit 3f52cfa037
4 changed files with 255 additions and 199 deletions

@ -35,13 +35,46 @@
#ifndef QCA_SUPPORT_H
#define QCA_SUPPORT_H
#include <QByteArray>
#include <QString>
#include <QObject>
#include <QVariant>
#include <QVariantList>
#include <QList>
#include <QMetaObject>
#include <QThread>
#include "qca_export.h"
#include "qca_tools.h"
namespace QCA
{
QCA_EXPORT QByteArray methodReturnType(const QMetaObject *obj, const QByteArray &method, const QList<QByteArray> argTypes);
QCA_EXPORT bool invokeMethodWithVariants(QObject *obj, const QByteArray &method, const QVariantList &args, QVariant *ret, Qt::ConnectionType type = Qt::AutoConnection);
class QCA_EXPORT SyncThread : public QThread
{
Q_OBJECT
public:
SyncThread(QObject *parent = 0);
~SyncThread();
void start();
void stop();
QVariant call(QObject *obj, const QByteArray &method, const QVariantList &args = QVariantList(), bool *ok = 0);
protected:
virtual void atStart() = 0;
virtual void atEnd() = 0;
// reimplemented
virtual void run();
private:
class Private;
friend class Private;
Private *d;
};
class QCA_EXPORT Synchronizer : public QObject
{
Q_OBJECT

@ -50,7 +50,9 @@ PUBLIC_HEADERS += \
HEADERS += $$PRIVATE_HEADERS $$PUBLIC_HEADERS
# do support first
SOURCES += $$QCA_CPP/support/synchronizer.cpp
SOURCES += \
$$QCA_CPP/support/syncthread.cpp \
$$QCA_CPP/support/synchronizer.cpp
include($$QCA_SRCBASE/support/dirwatch/dirwatch.pri)
SOURCES += \

@ -19,6 +19,9 @@
#include "qca_support.h"
#include <QtCore>
#include "qpipe.h"
#ifdef Q_OS_WIN
# include <windows.h>
#else
@ -27,206 +30,8 @@
# include <fcntl.h>
#endif
#include "qpipe.h"
namespace QCA {
//----------------------------------------------------------------------------
// SyncThread
//----------------------------------------------------------------------------
static QByteArray getReturnType(const QMetaObject *obj, const QByteArray &method, const QList<QByteArray> argTypes)
{
for(int n = 0; n < obj->methodCount(); ++n)
{
QMetaMethod m = obj->method(n);
QByteArray sig = m.signature();
int offset = sig.indexOf('(');
if(offset == -1)
continue;
QByteArray name = sig.mid(0, offset);
if(name != method)
continue;
if(m.parameterTypes() != argTypes)
continue;
return m.typeName();
}
return QByteArray();
}
static bool invokeMethodWithVariants(QObject *obj, const QByteArray &method, const QVariantList &args, QVariant *ret, Qt::ConnectionType type = Qt::AutoConnection)
{
// QMetaObject::invokeMethod() has a 10 argument maximum
if(args.count() > 10)
return false;
QList<QByteArray> argTypes;
for(int n = 0; n < args.count(); ++n)
argTypes += args[n].typeName();
// get return type
int metatype = 0;
QByteArray retTypeName = getReturnType(obj->metaObject(), method, argTypes);
if(!retTypeName.isEmpty())
{
metatype = QMetaType::type(retTypeName.data());
if(metatype == 0) // lookup failed
return false;
}
QGenericArgument arg[10];
for(int n = 0; n < args.count(); ++n)
arg[n] = QGenericArgument(args[n].typeName(), args[n].constData());
QGenericReturnArgument retarg;
QVariant retval;
if(metatype != 0)
{
retval = QVariant(metatype, (const void *)0);
retarg = QGenericReturnArgument(retval.typeName(), retval.data());
}
if(!QMetaObject::invokeMethod(obj, method.data(), type, retarg, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9]))
return false;
if(retval.isValid() && ret)
*ret = retval;
return true;
}
class SyncThreadAgent;
class SyncThread : public QThread
{
Q_OBJECT
private:
QMutex m;
QWaitCondition w;
QEventLoop *loop;
SyncThreadAgent *agent;
bool last_success;
QVariant last_ret;
public:
SyncThread(QObject *parent = 0);
~SyncThread();
void start();
void stop();
QVariant call(QObject *obj, const char *method, const QVariantList &args = QVariantList(), bool *ok = 0);
protected:
virtual void run();
virtual void atStart() = 0;
virtual void atEnd() = 0;
private slots:
void agent_started();
void agent_call_ret(bool success, const QVariant &ret);
};
class SyncThreadAgent : public QObject
{
Q_OBJECT
public:
SyncThreadAgent(QObject *parent = 0) : QObject(parent)
{
QMetaObject::invokeMethod(this, "started", Qt::QueuedConnection);
}
signals:
void started();
void call_ret(bool success, const QVariant &ret);
public slots:
void call_do(QObject *obj, const QByteArray &method, const QVariantList &args)
{
QVariant ret;
bool ok = invokeMethodWithVariants(obj, method, args, &ret, Qt::DirectConnection);
emit call_ret(ok, ret);
}
};
SyncThread::SyncThread(QObject *parent)
:QThread(parent)
{
qRegisterMetaType<QVariant>("QVariant");
qRegisterMetaType<QVariantList>("QVariantList");
loop = 0;
agent = 0;
}
SyncThread::~SyncThread()
{
stop();
}
void SyncThread::start()
{
QMutexLocker locker(&m);
Q_ASSERT(!loop);
QThread::start();
w.wait(&m);
}
void SyncThread::stop()
{
QMutexLocker locker(&m);
if(!loop)
return;
QMetaObject::invokeMethod(loop, "quit");
w.wait(&m);
wait();
}
QVariant SyncThread::call(QObject *obj, const char *method, const QVariantList &args, bool *ok)
{
QMutexLocker locker(&m);
Q_ASSERT(QMetaObject::invokeMethod(agent, "call_do", Qt::QueuedConnection,
Q_ARG(QObject*, obj), Q_ARG(QByteArray, QByteArray(method)), Q_ARG(QVariantList, args)));
w.wait(&m);
if(ok)
*ok = last_success;
QVariant v = last_ret;
last_ret = QVariant();
return v;
}
void SyncThread::run()
{
m.lock();
loop = new QEventLoop;
agent = new SyncThreadAgent;
connect(agent, SIGNAL(started()), SLOT(agent_started()), Qt::DirectConnection);
connect(agent, SIGNAL(call_ret(bool, const QVariant &)), SLOT(agent_call_ret(bool, const QVariant &)), Qt::DirectConnection);
loop->exec();
m.lock();
atEnd();
delete agent;
delete loop;
agent = 0;
loop = 0;
w.wakeOne();
m.unlock();
}
void SyncThread::agent_started()
{
atStart();
w.wakeOne();
m.unlock();
}
void SyncThread::agent_call_ret(bool success, const QVariant &ret)
{
QMutexLocker locker(&m);
last_success = success;
last_ret = ret;
w.wakeOne();
}
//----------------------------------------------------------------------------
// ConsoleWorker
//----------------------------------------------------------------------------

216
src/support/syncthread.cpp Normal file

@ -0,0 +1,216 @@
/*
* Copyright (C) 2006 Justin Karneges <justin@affinix.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "qca_support.h"
#include <QtCore>
namespace QCA {
QByteArray methodReturnType(const QMetaObject *obj, const QByteArray &method, const QList<QByteArray> argTypes)
{
for(int n = 0; n < obj->methodCount(); ++n)
{
QMetaMethod m = obj->method(n);
QByteArray sig = m.signature();
int offset = sig.indexOf('(');
if(offset == -1)
continue;
QByteArray name = sig.mid(0, offset);
if(name != method)
continue;
if(m.parameterTypes() != argTypes)
continue;
return m.typeName();
}
return QByteArray();
}
bool invokeMethodWithVariants(QObject *obj, const QByteArray &method, const QVariantList &args, QVariant *ret, Qt::ConnectionType type)
{
// QMetaObject::invokeMethod() has a 10 argument maximum
if(args.count() > 10)
return false;
QList<QByteArray> argTypes;
for(int n = 0; n < args.count(); ++n)
argTypes += args[n].typeName();
// get return type
int metatype = 0;
QByteArray retTypeName = methodReturnType(obj->metaObject(), method, argTypes);
if(!retTypeName.isEmpty())
{
metatype = QMetaType::type(retTypeName.data());
if(metatype == 0) // lookup failed
return false;
}
QGenericArgument arg[10];
for(int n = 0; n < args.count(); ++n)
arg[n] = QGenericArgument(args[n].typeName(), args[n].constData());
QGenericReturnArgument retarg;
QVariant retval;
if(metatype != 0)
{
retval = QVariant(metatype, (const void *)0);
retarg = QGenericReturnArgument(retval.typeName(), retval.data());
}
if(!QMetaObject::invokeMethod(obj, method.data(), type, retarg, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9]))
return false;
if(retval.isValid() && ret)
*ret = retval;
return true;
}
//----------------------------------------------------------------------------
// SyncThread
//----------------------------------------------------------------------------
class SyncThreadAgent;
class SyncThread::Private : public QObject
{
Q_OBJECT
public:
SyncThread *q;
QMutex m;
QWaitCondition w;
QEventLoop *loop;
SyncThreadAgent *agent;
bool last_success;
QVariant last_ret;
Private(SyncThread *_q) : QObject(_q), q(_q)
{
loop = 0;
agent = 0;
}
private slots:
void agent_started();
void agent_call_ret(bool success, const QVariant &ret);
};
class SyncThreadAgent : public QObject
{
Q_OBJECT
public:
SyncThreadAgent(QObject *parent = 0) : QObject(parent)
{
QMetaObject::invokeMethod(this, "started", Qt::QueuedConnection);
}
signals:
void started();
void call_ret(bool success, const QVariant &ret);
public slots:
void call_do(QObject *obj, const QByteArray &method, const QVariantList &args)
{
QVariant ret;
bool ok = invokeMethodWithVariants(obj, method, args, &ret, Qt::DirectConnection);
emit call_ret(ok, ret);
}
};
SyncThread::SyncThread(QObject *parent)
:QThread(parent)
{
d = new Private(this);
qRegisterMetaType<QVariant>("QVariant");
qRegisterMetaType<QVariantList>("QVariantList");
}
SyncThread::~SyncThread()
{
stop();
delete d;
}
void SyncThread::start()
{
QMutexLocker locker(&d->m);
Q_ASSERT(!d->loop);
QThread::start();
d->w.wait(&d->m);
}
void SyncThread::stop()
{
QMutexLocker locker(&d->m);
if(!d->loop)
return;
QMetaObject::invokeMethod(d->loop, "quit");
d->w.wait(&d->m);
wait();
}
QVariant SyncThread::call(QObject *obj, const QByteArray &method, const QVariantList &args, bool *ok)
{
QMutexLocker locker(&d->m);
Q_ASSERT(QMetaObject::invokeMethod(d->agent, "call_do", Qt::QueuedConnection,
Q_ARG(QObject*, obj), Q_ARG(QByteArray, QByteArray(method)), Q_ARG(QVariantList, args)));
d->w.wait(&d->m);
if(ok)
*ok = d->last_success;
QVariant v = d->last_ret;
d->last_ret = QVariant();
return v;
}
void SyncThread::run()
{
d->m.lock();
d->loop = new QEventLoop;
d->agent = new SyncThreadAgent;
connect(d->agent, SIGNAL(started()), d, SLOT(agent_started()), Qt::DirectConnection);
connect(d->agent, SIGNAL(call_ret(bool, const QVariant &)), d, SLOT(agent_call_ret(bool, const QVariant &)), Qt::DirectConnection);
d->loop->exec();
d->m.lock();
atEnd();
delete d->agent;
delete d->loop;
d->agent = 0;
d->loop = 0;
d->w.wakeOne();
d->m.unlock();
}
void SyncThread::Private::agent_started()
{
q->atStart();
w.wakeOne();
m.unlock();
}
void SyncThread::Private::agent_call_ret(bool success, const QVariant &ret)
{
QMutexLocker locker(&m);
last_success = success;
last_ret = ret;
w.wakeOne();
}
}
#include "syncthread.moc"