Deleted qtipc autotest from qtbase

The qtipc autotest needs to live in qtscript due to dependencies
to that module. This commit is the first of two steps to move qtipc.
The second step is a commit in qtscript that adds qtipc there
(with a proper reference to the first commit, i.e. this one).

Change-Id: I233ee459be76fd1938868c05232ce732cfc913a8
Reviewed-by: Jason McDonald <jason.mcdonald@nokia.com>
This commit is contained in:
Jo Asplin 2011-11-08 13:19:16 +01:00 committed by Qt by Nokia
parent 145357bf58
commit 540e368e04
28 changed files with 0 additions and 2886 deletions

View File

@ -14,7 +14,6 @@ SUBDIRS=\
qsignalmapper \
qsocketnotifier \
qtimer \
# qtipc \ # needs to be moved to qtscript (and note that it uses private API)
qtranslator \
qvariant \
qwineventnotifier

View File

@ -1,16 +0,0 @@
include(../qsharedmemory/src/src.pri)
QT = core-private script testlib
DESTDIR = ./
win32: CONFIG += console
mac:CONFIG -= app_bundle
DEFINES += QSHAREDMEMORY_DEBUG
DEFINES += QSYSTEMSEMAPHORE_DEBUG
SOURCES += main.cpp
TARGET = lackey

View File

@ -1,370 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <qscriptengine.h>
#include <QtCore/QFile>
#include <QtCore/QTextStream>
#include <QTest>
#include <qstringlist.h>
#include <stdlib.h>
#include <qsharedmemory.h>
#include <qsystemsemaphore.h>
#include <qsystemlock.h>
class ScriptSystemSemaphore : public QObject
{
Q_OBJECT
public:
ScriptSystemSemaphore(QObject *parent = 0) : QObject(parent), ss(QString())
{
}
public slots:
bool acquire()
{
return ss.acquire();
};
bool release(int n = 1)
{
return ss.release(n);
};
void setKey(const QString &key, int n = 0)
{
ss.setKey(key, n);
};
QString key() const
{
return ss.key();
}
private:
QSystemSemaphore ss;
};
class ScriptSystemLock : public QObject
{
Q_OBJECT
Q_PROPERTY(QString key WRITE setKey READ key)
public:
ScriptSystemLock(QObject *parent = 0) : QObject(parent), sl(QString())
{
}
public slots:
bool lockReadOnly()
{
return sl.lock(QSystemLock::ReadOnly);
}
bool lock()
{
return sl.lock();
};
bool unlock()
{
return sl.unlock();
};
void setKey(const QString &key)
{
sl.setKey(key);
};
QString key() const
{
return sl.key();
}
private:
QSystemLock sl;
};
class ScriptSharedMemory : public QObject
{
Q_OBJECT
Q_PROPERTY(bool attached READ isAttached)
Q_PROPERTY(QString key WRITE setKey READ key)
public:
enum SharedMemoryError
{
NoError = 0,
PermissionDenied = 1,
InvalidSize = 2,
KeyError = 3,
AlreadyExists = 4,
NotFound = 5,
LockError = 6,
OutOfResources = 7,
UnknownError = 8
};
ScriptSharedMemory(QObject *parent = 0) : QObject(parent)
{
}
public slots:
void sleep(int x) const
{
QTest::qSleep(x);
}
bool create(int size)
{
return sm.create(size);
};
bool createReadOnly(int size)
{
return sm.create(size, QSharedMemory::ReadOnly);
};
int size() const
{
return sm.size();
};
bool attach()
{
return sm.attach();
};
bool attachReadOnly()
{
return sm.attach(QSharedMemory::ReadOnly);
};
bool isAttached() const
{
return sm.isAttached();
};
bool detach()
{
return sm.detach();
};
int error() const
{
return (int)sm.error();
};
QString errorString() const
{
return sm.errorString();
};
void set(int i, QChar value)
{
((char*)sm.data())[i] = value.toLatin1();
}
QString get(int i)
{
return QChar::fromLatin1(((char*)sm.data())[i]);
}
char *data() const
{
return (char*)sm.data();
};
void setKey(const QString &key)
{
sm.setKey(key);
};
QString key() const
{
return sm.key();
}
bool lock()
{
return sm.lock();
}
bool unlock()
{
return sm.unlock();
}
private:
QSharedMemory sm;
};
QT_BEGIN_NAMESPACE
Q_SCRIPT_DECLARE_QMETAOBJECT(ScriptSharedMemory, QObject*);
Q_SCRIPT_DECLARE_QMETAOBJECT(ScriptSystemLock, QObject*);
Q_SCRIPT_DECLARE_QMETAOBJECT(ScriptSystemSemaphore, QObject*);
QT_END_NAMESPACE
static void interactive(QScriptEngine &eng)
{
#ifdef Q_OS_WINCE
fprintf(stderr, "Interactive mode not supported on Windows CE\n");
return;
#endif
QTextStream qin(stdin, QFile::ReadOnly);
const char *qscript_prompt = "qs> ";
const char *dot_prompt = ".... ";
const char *prompt = qscript_prompt;
QString code;
forever {
QString line;
printf("%s", prompt);
fflush(stdout);
line = qin.readLine();
if (line.isNull())
break;
code += line;
code += QLatin1Char('\n');
if (line.trimmed().isEmpty()) {
continue;
} else if (! eng.canEvaluate(code)) {
prompt = dot_prompt;
} else {
QScriptValue result = eng.evaluate(code);
code.clear();
prompt = qscript_prompt;
if (!result.isUndefined())
fprintf(stderr, "%s\n", qPrintable(result.toString()));
}
}
}
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
QScriptEngine eng;
QScriptValue globalObject = eng.globalObject();
QScriptValue sm = qScriptValueFromQMetaObject<ScriptSharedMemory>(&eng);
eng.globalObject().setProperty("ScriptSharedMemory", sm);
QScriptValue sl = qScriptValueFromQMetaObject<ScriptSystemLock>(&eng);
eng.globalObject().setProperty("ScriptSystemLock", sl);
QScriptValue ss = qScriptValueFromQMetaObject<ScriptSystemSemaphore>(&eng);
eng.globalObject().setProperty("ScriptSystemSemaphore", ss);
if (! *++argv) {
interactive(eng);
return EXIT_SUCCESS;
}
QStringList arguments = app.arguments();
arguments.takeFirst();
while (!arguments.isEmpty()) {
QString fn = arguments.takeFirst();
if (fn == QLatin1String("-i")) {
interactive(eng);
break;
}
QString contents;
if (fn == QLatin1String("-")) {
QTextStream stream(stdin, QFile::ReadOnly);
contents = stream.readAll();
} else {
QFile file(fn);
if (!file.exists()) {
fprintf(stderr, "%s doesn't exists\n", qPrintable(fn));
return EXIT_FAILURE;
}
if (file.open(QFile::ReadOnly)) {
QTextStream stream(&file);
contents = stream.readAll();
file.close();
}
}
if (contents.isEmpty())
continue;
if (contents[0] == '#') {
contents.prepend("//");
QScriptValue args = eng.newArray();
args.setProperty("0", QScriptValue(&eng, fn));
int i = 1;
while (!arguments.isEmpty())
args.setProperty(i++, QScriptValue(&eng, arguments.takeFirst()));
eng.currentContext()->activationObject().setProperty("args", args);
}
QScriptValue r = eng.evaluate(contents);
if (eng.hasUncaughtException()) {
int line = eng.uncaughtExceptionLineNumber();
fprintf(stderr, "%d: %s\n\t%s\n\n", line, qPrintable(fn), qPrintable(r.toString()));
return EXIT_FAILURE;
}
if (r.isNumber())
return r.toInt32();
}
return EXIT_SUCCESS;
}
#include "main.moc"

View File

@ -1,41 +0,0 @@
function QVERIFY(x, debugInfo) {
if (!(x)) {
print(debugInfo);
throw(debugInfo);
}
}
var consumer = new ScriptSharedMemory;
consumer.setKey("market");
//print("consumer starting");
var tries = 0;;
while(!consumer.attach()) {
if (tries == 5000) {
var message = "consumer exiting, waiting too long";
print(message);
throw(message);
}
++tries;
consumer.sleep(1);
}
//print("consumer attached");
var i = 0;
while(true) {
QVERIFY(consumer.lock(), "lock");
if (consumer.get(0) == 'Q') {
consumer.set(0, ++i);
//print ("consumer sets" + i);
}
if (consumer.get(0) == 'E') {
QVERIFY(consumer.unlock(), "unlock");
break;
}
QVERIFY(consumer.unlock(), "unlock");
consumer.sleep(10);
}
//print("consumer detaching");
QVERIFY(consumer.detach());

View File

@ -1,44 +0,0 @@
function QVERIFY(x, debugInfo) {
if (!(x)) {
print(debugInfo);
throw(debugInfo);
}
}
var producer = new ScriptSharedMemory;
producer.setKey("market");
var size = 1024;
if (!producer.create(size)) {
QVERIFY(producer.error() == 4, "create");
QVERIFY(producer.attach());
}
//print ("producer created and attached");
QVERIFY(producer.lock());
producer.set(0, 'Q');
QVERIFY(producer.unlock());
var i = 0;
while(i < 5) {
QVERIFY(producer.lock(), "lock");
if (producer.get(0) == 'Q') {
QVERIFY(producer.unlock(), "unlock");
producer.sleep(1);
continue;
}
//print("producer: " + i);
++i;
producer.set(0, 'Q');
QVERIFY(producer.unlock(), "unlock");
producer.sleep(1);
}
QVERIFY(producer.lock());
producer.set(0, 'E');
QVERIFY(producer.unlock());
//print ("producer done");
// Sleep for a bit to let all consumers start, otherwise they will get stuck in the attach loop,
// because at least in Symbian the shared memory will be destroyed if there are no active handles to it.
producer.sleep(3000);

View File

@ -1,4 +0,0 @@
var sm = new ScriptSharedMemory;
sm.setKey("readonly_segfault");
sm.createReadOnly(1024);
var data = sm.set(0, "a");

View File

@ -1,11 +0,0 @@
function QVERIFY(x, debugInfo) {
if (!(x)) {
print(debugInfo);
throw(debugInfo);
}
}
var lock = new ScriptSystemLock;
lock.setKey("market");
QVERIFY(lock.lockReadOnly());
QVERIFY(lock.unlock());

View File

@ -1,11 +0,0 @@
function QVERIFY(x, debugInfo) {
if (!(x)) {
print(debugInfo);
throw(debugInfo);
}
}
var lock = new ScriptSystemLock;
lock.setKey("market");
QVERIFY(lock.lock());
QVERIFY(lock.unlock());

View File

@ -1,18 +0,0 @@
#/bin/qscript
function QVERIFY(x, debugInfo) {
if (!(x)) {
print(debugInfo);
throw(debugInfo);
}
}
var sem = new ScriptSystemSemaphore;
sem.setKey("store");
var count = Number(args[1]);
if (isNaN(count))
count = 1;
for (var i = 0; i < count; ++i)
QVERIFY(sem.acquire());
print("done aquiring");

View File

@ -1,11 +0,0 @@
function QVERIFY(x, debugInfo) {
if (!(x)) {
print(debugInfo);
throw(debugInfo);
}
}
var lock = new ScriptSystemSemaphore;
lock.setKey("store");
QVERIFY(lock.acquire());
QVERIFY(lock.release());

View File

@ -1,11 +0,0 @@
function QVERIFY(x, debugInfo) {
if (!(x)) {
print(debugInfo);
throw(debugInfo);
}
}
var sem = new ScriptSystemSemaphore;
sem.setKey("store");
QVERIFY(sem.release());
print ("done releasing");

View File

@ -1,3 +0,0 @@
tst_qsharedmemory
lackey/lackey.exe
qsystemlock/tst_qsystemlock.exe

View File

@ -1,4 +0,0 @@
TEMPLATE = subdirs
SUBDIRS = test qsystemlock

View File

@ -1,22 +0,0 @@
CONFIG += testcase
QT += gui-private testlib
include(../src/src.pri)
win32: CONFIG += console
mac:CONFIG -= app_bundle
wince* {
DEFINES += SRCDIR=\\\"\\\"
} else {
DEFINES += SRCDIR=\\\"$$PWD\\\"
}
DESTDIR = ./
DEFINES += QSHAREDMEMORY_DEBUG
DEFINES += QSYSTEMSEMAPHORE_DEBUG
SOURCES += tst_qsystemlock.cpp
TARGET = tst_qsystemlock

View File

@ -1,232 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QtTest/QtTest>
#include <qsystemlock.h>
//TESTED_CLASS=
//TESTED_FILES=
#define EXISTING_SHARE "existing"
class tst_QSystemLock : public QObject
{
Q_OBJECT
public:
tst_QSystemLock();
virtual ~tst_QSystemLock();
public Q_SLOTS:
void init();
void cleanup();
private slots:
void key_data();
void key();
void basicLock();
void complexLock();
void lockModes();
void sucessive();
void processes_data();
void processes();
private:
QSystemLock *existingLock;
};
tst_QSystemLock::tst_QSystemLock()
{
}
tst_QSystemLock::~tst_QSystemLock()
{
}
void tst_QSystemLock::init()
{
existingLock = new QSystemLock(EXISTING_SHARE);
}
void tst_QSystemLock::cleanup()
{
delete existingLock;
}
void tst_QSystemLock::key_data()
{
QTest::addColumn<QString>("constructorKey");
QTest::addColumn<QString>("setKey");
QTest::newRow("null, null") << QString() << QString();
QTest::newRow("null, one") << QString() << QString("one");
QTest::newRow("one, two") << QString("one") << QString("two");
}
/*!
Basic key testing
*/
void tst_QSystemLock::key()
{
QFETCH(QString, constructorKey);
QFETCH(QString, setKey);
QSystemLock sl(constructorKey);
QCOMPARE(sl.key(), constructorKey);
sl.setKey(setKey);
QCOMPARE(sl.key(), setKey);
}
void tst_QSystemLock::basicLock()
{
QSystemLock lock("foo");
QVERIFY(lock.lock());
QVERIFY(lock.unlock());
}
void tst_QSystemLock::complexLock()
{
QSystemLock lock("foo");
QVERIFY(lock.lock(QSystemLock::ReadOnly));
QVERIFY(lock.unlock());
QVERIFY(lock.lock(QSystemLock::ReadWrite));
QVERIFY(lock.unlock());
QVERIFY(lock.lock(QSystemLock::ReadOnly));
QVERIFY(lock.lock(QSystemLock::ReadOnly));
QVERIFY(lock.unlock());
QVERIFY(lock.unlock());
}
void tst_QSystemLock::lockModes()
{
QSystemLock reader1("library");
QSystemLock reader2("library");
QSystemLock librarian("library");
QVERIFY(reader1.lock(QSystemLock::ReadOnly));
QVERIFY(reader2.lock(QSystemLock::ReadOnly));
QVERIFY(reader1.unlock());
QVERIFY(reader2.unlock());
QVERIFY(librarian.lock(QSystemLock::ReadWrite));
QVERIFY(librarian.unlock());
}
void tst_QSystemLock::sucessive()
{
QSystemLock lock("library");
QVERIFY(lock.lock(QSystemLock::ReadOnly));
QVERIFY(lock.lock(QSystemLock::ReadOnly));
QVERIFY(lock.lock(QSystemLock::ReadOnly));
QVERIFY(lock.lock(QSystemLock::ReadOnly));
QVERIFY(lock.lock(QSystemLock::ReadOnly));
QVERIFY(lock.unlock());
QVERIFY(lock.unlock());
QVERIFY(lock.unlock());
QVERIFY(lock.unlock());
QVERIFY(lock.unlock());
QVERIFY(!lock.unlock());
}
void tst_QSystemLock::processes_data()
{
QTest::addColumn<int>("readOnly");
QTest::addColumn<int>("readWrite");
for (int i = 0; i < 5; ++i) {
QTest::newRow("1/0 process") << 1 << 0;
QTest::newRow("0/1 process") << 0 << 1;
QTest::newRow("0/4 process") << 0 << 4;
QTest::newRow("1/1 process") << 1 << 1;
QTest::newRow("10/1 process") << 10 << 1;
QTest::newRow("1/10 process") << 1 << 10;
QTest::newRow("10/10 processes") << 10 << 10;
}
}
/*!
Create external processes
*/
void tst_QSystemLock::processes()
{
QSKIP("This test takes about 15 minutes and needs to be trimmed down before we can re-enable it");
QFETCH(int, readOnly);
QFETCH(int, readWrite);
QStringList scripts;
for (int i = 0; i < readOnly; ++i)
scripts.append(QFileInfo(SRCDIR "/../lackey/scripts/systemlock_read.js").absoluteFilePath() );
for (int i = 0; i < readWrite; ++i)
scripts.append(QFileInfo(SRCDIR "/../lackey/scripts/systemlock_readwrite.js").absoluteFilePath());
QList<QProcess*> consumers;
unsigned int failedProcesses = 0;
for (int i = 0; i < scripts.count(); ++i) {
QStringList arguments = QStringList() << scripts.at(i);
QProcess *p = new QProcess;
p->setProcessChannelMode(QProcess::ForwardedChannels);
p->start("../lackey/lackey", arguments);
// test, if the process could be started.
if (p->waitForStarted(2000))
consumers.append(p);
else
++failedProcesses;
}
while (!consumers.isEmpty()) {
consumers.first()->waitForFinished(3000);
consumers.first()->kill();
QCOMPARE(consumers.first()->exitStatus(), QProcess::NormalExit);
QCOMPARE(consumers.first()->exitCode(), 0);
delete consumers.takeFirst();
}
QCOMPARE(failedProcesses, (unsigned int)(0));
}
QTEST_MAIN(tst_QSystemLock)
#include "tst_qsystemlock.moc"

View File

@ -1,246 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qsystemlock.h"
#include "qsystemlock_p.h"
#include <qdebug.h>
/*! \class QSystemLocker
\brief The QSystemLocker class is a convenience class that simplifies
locking and unlocking system locks.
The purpose of QSystemLocker is to simplify QSystemLock locking and
unlocking. Locking and unlocking a QSystemLock in complex functions and
statements or in exception handling code is error-prone and difficult to
debug. QSystemLocker can be used in such situations to ensure that the
state of the locks is always well-defined.
QSystemLocker should be created within a function where a QSystemLock needs
to be locked. The system lock is locked when QSystemLocker is created. If
locked, the system lock will be unlocked when the QSystemLocker is
destroyed. QSystemLocker can be unlocked with unlock() and relocked with
relock().
\sa QSystemLock
*/
/*! \fn QSystemLocker::QSystemLocker()
Constructs a QSystemLocker and locks \a lock. The \a lock will be
unlocked when the QSystemLocker is destroyed. If lock is zero,
QSystemLocker does nothing.
\sa QSystemLock::lock()
*/
/*! \fn QSystemLocker::~QSystemLocker()
Destroys the QSystemLocker and unlocks it if it was
locked in the constructor.
\sa QSystemLock::unlock()
*/
/*! \fn QSystemLocker::systemLock()
Returns a pointer to the lock that was locked in the constructor.
*/
/*! \fn QSystemLocker::relock()
Relocks an unlocked locker.
\sa unlock()
*/
/*! \fn QSystemLocker::unlock()
Unlocks this locker. You can use relock() to lock it again.
It does not need to be locked when destroyed.
\sa relock()
*/
/*! \class QSystemLock
\brief The QSystemLock class provides a system wide lock
that can be used between threads or processes.
The purpose of a QSystemLocker is to protect an object that can be
accessed by multiple threads or processes such as shared memory or a file.
For example, say there is a method which prints a message to a log file:
void log(const QString &logText)
{
QSystemLock systemLock(QLatin1String("logfile"));
systemLock.lock();
QFile file(QDir::temp() + QLatin1String("/log"));
if (file.open(QIODevice::Append)) {
QTextStream out(&file);
out << logText;
}
systemLock.unlock();
}
If this is called from two separate processes the resulting log file is
guaranteed to contain both lines.
When you call lock(), other threads or processes that try to call lock()
with the same key will block until the thread or process that got the lock
calls unlock().
A non-blocking alternative to lock() is tryLock().
*/
/*!
Constructs a new system lock with \a key. The lock is created in an
unlocked state.
\sa lock(), key().
*/
QSystemLock::QSystemLock(const QString &key)
{
d = new QSystemLockPrivate;
setKey(key);
}
/*!
Destroys a system lock.
warning: This will not unlock the system lock if it has been locked.
*/
QSystemLock::~QSystemLock()
{
d->cleanHandle();
delete d;
}
/*!
Sets a new key to this system lock.
\sa key()
*/
void QSystemLock::setKey(const QString &key)
{
if (key == d->key)
return;
d->cleanHandle();
d->lockCount = 0;
d->key = key;
// cache the file name so it doesn't have to be generated all the time.
d->fileName = d->makeKeyFileName();
d->error = QSystemLock::NoError;
d->errorString = QString();
d->handle();
}
/*!
Returns the key assigned to this system lock
\sa setKey()
*/
QString QSystemLock::key() const
{
return d->key;
}
/*!
Locks the system lock. Lock \a mode can either be ReadOnly or ReadWrite.
If a mode is ReadOnly, attempts by other processes to obtain
ReadOnly locks will succeed, and ReadWrite attempts will block until
all of the ReadOnly locks are unlocked. If locked as ReadWrite, all
other attempts to lock will block until the lock is unlocked. A given
QSystemLock can be locked multiple times without blocking, and will
only be unlocked after a corresponding number of unlock()
calls are made. Returns true on success; otherwise returns false.
\sa unlock(), tryLock()
*/
bool QSystemLock::lock(LockMode mode)
{
if (d->lockCount > 0 && mode == ReadOnly && d->lockedMode == ReadWrite) {
qWarning() << "QSystemLock::lock readwrite lock on top of readonly lock.";
return false;
}
return d->modifySemaphore(QSystemLockPrivate::Lock, mode);
}
/*!
Unlocks the system lock.
Returns true on success; otherwise returns false.
\sa lock()
*/
bool QSystemLock::unlock()
{
if (d->lockCount == 0) {
qWarning() << "QSystemLock::unlock: unlock with no lock.";
return false;
}
return d->modifySemaphore(QSystemLockPrivate::Unlock, d->lockedMode);
}
/*!
Returns the type of error that occurred last or NoError.
\sa errorString()
*/
QSystemLock::SystemLockError QSystemLock::error() const
{
return d->error;
}
/*!
Returns the human-readable message appropriate to the current error
reported by error(). If no suitable string is available, an empty
string is returned.
\sa error()
*/
QString QSystemLock::errorString() const
{
return d->errorString;
}

View File

@ -1,135 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QSYSTEMLOCK_H
#define QSYSTEMLOCK_H
#include <QtCore/qstring.h>
QT_BEGIN_HEADER
#ifndef QT_NO_SYSTEMLOCK
QT_FORWARD_DECLARE_CLASS(QSystemLockPrivate)
class QSystemLock
{
public:
enum SystemLockError
{
NoError,
UnknownError
};
QSystemLock(const QString &key);
~QSystemLock();
void setKey(const QString &key);
QString key() const;
enum LockMode
{
ReadOnly,
ReadWrite
};
bool lock(LockMode mode = ReadWrite);
bool unlock();
SystemLockError error() const;
QString errorString() const;
private:
Q_DISABLE_COPY(QSystemLock)
QSystemLockPrivate *d;
};
class QSystemLocker
{
public:
inline QSystemLocker(QSystemLock *systemLock,
QSystemLock::LockMode mode = QSystemLock::ReadWrite) : q_lock(systemLock)
{
autoUnLocked = relock(mode);
}
inline ~QSystemLocker()
{
if (autoUnLocked)
unlock();
}
inline QSystemLock *systemLock() const
{
return q_lock;
}
inline bool relock(QSystemLock::LockMode mode = QSystemLock::ReadWrite)
{
return (q_lock && q_lock->lock(mode));
}
inline bool unlock()
{
if (q_lock && q_lock->unlock()) {
autoUnLocked = false;
return true;
}
return false;
}
private:
Q_DISABLE_COPY(QSystemLocker)
bool autoUnLocked;
QSystemLock *q_lock;
};
#endif // QT_NO_SYSTEMLOCK
QT_END_HEADER
#endif // QSYSTEMLOCK_H

View File

@ -1,109 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QSYSTEMLOCK_P_H
#define QSYSTEMLOCK_P_H
#ifndef QT_NO_SYSTEMLOCK
#include "qsystemlock.h"
#include "private/qsharedmemory_p.h"
#ifndef Q_OS_WINCE
#include <sys/types.h>
#endif
#define MAX_LOCKS 64
class QSystemLockPrivate
{
public:
QSystemLockPrivate();
QString makeKeyFileName()
{
return QSharedMemoryPrivate::makePlatformSafeKey(key, QLatin1String("qipc_systemlock_"));
}
void setErrorString(const QString &function);
#ifdef Q_OS_WIN
HANDLE handle();
bool lock(HANDLE, int count);
bool unlock(HANDLE, int count);
#else
key_t handle();
#endif
void cleanHandle();
enum Operation {
Lock,
Unlock
};
bool modifySemaphore(Operation op, QSystemLock::LockMode mode = QSystemLock::ReadOnly);
QString key;
QString fileName;
#ifdef Q_OS_WIN
HANDLE semaphore;
HANDLE semaphoreLock;
#else
int semaphore;
#endif
int lockCount;
QSystemLock::LockMode lockedMode;
QSystemLock::SystemLockError error;
QString errorString;
private:
#ifndef Q_OS_WIN
key_t unix_key;
bool createdFile;
bool createdSemaphore;
#endif
};
#endif // QT_NO_SYSTEMLOCK
#endif // QSYSTEMLOCK_P_H

View File

@ -1,211 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qsystemlock.h"
#include "qsystemlock_p.h"
#include <qdebug.h>
#include <qfile.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/shm.h>
#include <unistd.h>
#include <sys/sem.h>
// We have to define this as on some sem.h will have it
union qt_semun {
int val; /* value for SETVAL */
struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* array for GETALL, SETALL */
};
#define tr(x) QT_TRANSLATE_NOOP(QLatin1String("QSystemLock"), (x))
QSystemLockPrivate::QSystemLockPrivate() :
semaphore(-1), lockCount(0),
error(QSystemLock::NoError), unix_key(-1), createdFile(false), createdSemaphore(false)
{
}
void QSystemLockPrivate::setErrorString(const QString &function)
{
switch (errno) {
case EIDRM:
errorString = function + QLatin1String(": ") + tr("The semaphore set was removed");
error = QSystemLock::UnknownError;
break;
default:
errorString = function + QLatin1String(": ") + tr("unknown error");
error = QSystemLock::UnknownError;
qWarning() << errorString << "key" << key << "errno" << errno << ERANGE << ENOMEM << EINVAL << EINTR << EFBIG << EFAULT << EAGAIN << EACCES << E2BIG;
}
}
/*!
\internal
Setup unix_key
*/
key_t QSystemLockPrivate::handle()
{
if (key.isEmpty())
return -1;
// ftok requires that an actual file exists somewhere
// If we have already made at some point in the past,
// double check that it is still there.
if (-1 != unix_key) {
int aNewunix_key = ftok(QFile::encodeName(fileName).constData(), 'Q');
if (aNewunix_key != unix_key) {
cleanHandle();
} else {
return unix_key;
}
}
// Create the file needed for ftok
int built = QSharedMemoryPrivate::createUnixKeyFile(fileName);
if (-1 == built)
return -1;
createdFile = (1 == built);
// Get the unix key for the created file
unix_key = ftok(QFile::encodeName(fileName).constData(), 'Q');
if (-1 == unix_key) {
setErrorString(QLatin1String("QSystemLock::handle ftok"));
return -1;
}
// Get semaphore
semaphore = semget(unix_key, 1, 0666 | IPC_CREAT | IPC_EXCL);
if (-1 == semaphore) {
if (errno == EEXIST)
semaphore = semget(unix_key, 1, 0666 | IPC_CREAT);
if (-1 == semaphore) {
setErrorString(QLatin1String("QSystemLock::handle semget"));
cleanHandle();
return -1;
}
} else {
// Created semaphore, initialize value.
createdSemaphore = true;
qt_semun init_op;
init_op.val = MAX_LOCKS;
if (-1 == semctl(semaphore, 0, SETVAL, init_op)) {
setErrorString(QLatin1String("QSystemLock::handle semctl"));
cleanHandle();
return -1;
}
}
return unix_key;
}
/*!
\internal
Cleanup the unix_key
*/
void QSystemLockPrivate::cleanHandle()
{
unix_key = -1;
// remove the file if we made it
if (createdFile) {
if (!QFile::remove(fileName))
setErrorString(QLatin1String("QSystemLock::cleanHandle QFile::remove"));
createdFile = false;
}
if (createdSemaphore) {
if (-1 != semaphore) {
if (-1 == semctl(semaphore, 0, IPC_RMID)) {
setErrorString(QLatin1String("QSystemLock::cleanHandle semctl"));
}
semaphore = -1;
}
createdSemaphore = false;
}
}
/*!
\internal
modifySemaphore generates operation.sem_op and handles recursive behavior.
*/
bool QSystemLockPrivate::modifySemaphore(QSystemLockPrivate::Operation op,
QSystemLock::LockMode mode)
{
if (-1 == handle())
return false;
if ((lockCount == 0 && op == Lock) || (lockCount > 0 && op == Unlock)) {
if (op == Unlock) {
--lockCount;
if (lockCount < 0)
qFatal("%s: lockCount must not be negative", Q_FUNC_INFO);
if (lockCount > 0)
return true;
}
struct sembuf operation;
operation.sem_num = 0;
operation.sem_op = (mode == QSystemLock::ReadWrite) ? MAX_LOCKS : 1;
if (op == Lock)
operation.sem_op *= -1;
operation.sem_flg = SEM_UNDO;
if (-1 == semop(semaphore, &operation, 1)) {
setErrorString(QLatin1String("QSystemLock::modify"));
return false;
}
lockedMode = mode;
}
if (op == Lock)
lockCount++;
return true;
}

View File

@ -1,183 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qsystemlock.h"
#include "qsystemlock_p.h"
#include <qdebug.h>
#include <QtCore>
QSystemLockPrivate::QSystemLockPrivate() :
semaphore(0), semaphoreLock(0),
lockCount(0), error(QSystemLock::NoError)
{
}
void QSystemLockPrivate::setErrorString(const QString &function)
{
BOOL windowsError = GetLastError();
if (windowsError == 0)
return;
errorString = function + QLatin1String(": ")
+ QLatin1String("Unknown error");
error = QSystemLock::UnknownError;
qWarning() << errorString << "key" << key << (int)windowsError << semaphore << semaphoreLock;
}
/*!
\internal
Setup the semaphore
*/
HANDLE QSystemLockPrivate::handle()
{
// don't allow making handles on empty keys
if (key.isEmpty())
return 0;
// Create it if it doesn't already exists.
if (semaphore == 0) {
QString safeName = makeKeyFileName();
semaphore = CreateSemaphore(0, MAX_LOCKS, MAX_LOCKS, (wchar_t*)safeName.utf16());
if (semaphore == 0) {
setErrorString(QLatin1String("QSystemLockPrivate::handle"));
return 0;
}
}
if (semaphoreLock == 0) {
QString safeLockName = QSharedMemoryPrivate::makePlatformSafeKey(key + QLatin1String("lock"), QLatin1String("qipc_systemlock_"));
semaphoreLock = CreateSemaphore(0, 1, 1, (wchar_t*)safeLockName.utf16());
if (semaphoreLock == 0) {
setErrorString(QLatin1String("QSystemLockPrivate::handle"));
return 0;
}
}
return semaphore;
}
/*!
\internal
Cleanup the semaphore
*/
void QSystemLockPrivate::cleanHandle()
{
if (semaphore && !CloseHandle(semaphore))
setErrorString(QLatin1String("QSystemLockPrivate::cleanHandle:"));
if (semaphoreLock && !CloseHandle(semaphoreLock))
setErrorString(QLatin1String("QSystemLockPrivate::cleanHandle:"));
semaphore = 0;
semaphoreLock = 0;
}
bool QSystemLockPrivate::lock(HANDLE handle, int count)
{
if (count == 1) {
WaitForSingleObject(handle, INFINITE);
return true;
}
int i = count;
while (i > 0) {
if (WAIT_OBJECT_0 == WaitForSingleObject(handle, 0)) {
--i;
} else {
// undo what we have done, sleep and then try again later
ReleaseSemaphore(handle, (count - i), 0);
i = count;
ReleaseSemaphore(semaphoreLock, 1, 0);
Sleep(1);
WaitForSingleObject(semaphoreLock, INFINITE);
}
}
return true;
}
bool QSystemLockPrivate::unlock(HANDLE handle, int count)
{
if (0 == ReleaseSemaphore(handle, count, 0)) {
setErrorString(QLatin1String("QSystemLockPrivate::unlock"));
return false;
}
return true;
}
/*!
\internal
modifySemaphore handles recursive behavior and modifies the semaphore.
*/
bool QSystemLockPrivate::modifySemaphore(QSystemLockPrivate::Operation op,
QSystemLock::LockMode mode)
{
if (0 == handle())
return false;
if ((lockCount == 0 && op == Lock) || (lockCount > 0 && op == Unlock)) {
if (op == Unlock) {
--lockCount;
if (lockCount < 0)
qFatal("%s: lockCount must not be negative", Q_FUNC_INFO);
if (lockCount > 0)
return true;
}
int count = (mode == QSystemLock::ReadWrite) ? MAX_LOCKS : 1;
if (op == Lock) {
lock(semaphoreLock, 1);
lock(semaphore, count);
if (count != MAX_LOCKS) unlock(semaphoreLock, 1);
lockedMode = mode;
} else {
if (count == MAX_LOCKS) unlock(semaphoreLock, 1);
unlock(semaphore, count);
}
}
if (op == Lock)
lockCount++;
return true;
}

View File

@ -1,11 +0,0 @@
INCLUDEPATH += $$PWD
DEPENDPATH += $$PWD
QT += core-private
SOURCES += $$PWD/qsystemlock.cpp
HEADERS += $$PWD/qsystemlock.h \
$$PWD/qsystemlock_p.h
unix:SOURCES += $$PWD/qsystemlock_unix.cpp
win32:SOURCES += $$PWD/qsystemlock_win.cpp

View File

@ -1,29 +0,0 @@
CONFIG += testcase
include(../src/src.pri)
QT = core testlib
DEFINES += QSHAREDMEMORY_DEBUG
DEFINES += QSYSTEMSEMAPHORE_DEBUG
SOURCES += ../tst_qsharedmemory.cpp
TARGET = ../tst_qsharedmemory
!wince*:win32 {
CONFIG(debug, debug|release) {
TARGET = ../../debug/tst_qsharedmemory
} else {
TARGET = ../../release/tst_qsharedmemory
}
}
wince*:{
requires(contains(QT_CONFIG,script))
QT += gui script
addFiles.files = $$OUT_PWD/../../lackey/lackey.exe ../../lackey/scripts
addFiles.path = .
DEPLOYMENT += addFiles
DEFINES += SRCDIR=\\\".\\\"
} else {
DEFINES += SRCDIR=\\\"$$PWD/../\\\"
}

View File

@ -1,815 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QtTest/QtTest>
#include <qsharedmemory.h>
#include <QtCore/QFile>
//TESTED_CLASS=
//TESTED_FILES=
#define EXISTING_SHARE "existing"
#define EXISTING_SIZE 1024
#if defined(Q_OS_WINCE)
#define LACKEYDIR SRCDIR
#else
#define LACKEYDIR "../lackey"
#endif
Q_DECLARE_METATYPE(QSharedMemory::SharedMemoryError)
Q_DECLARE_METATYPE(QSharedMemory::AccessMode)
class tst_QSharedMemory : public QObject
{
Q_OBJECT
public:
tst_QSharedMemory();
virtual ~tst_QSharedMemory();
public Q_SLOTS:
void init();
void cleanup();
private slots:
// basics
void constructor();
void key_data();
void key();
void create_data();
void create();
void attach_data();
void attach();
void lock();
// custom edge cases
#ifndef Q_OS_HPUX
void removeWhileAttached();
#endif
void emptyMemory();
#ifndef Q_OS_WIN
void readOnly();
#endif
// basics all together
#ifndef Q_OS_HPUX
void simpleProducerConsumer_data();
void simpleProducerConsumer();
void simpleDoubleProducerConsumer();
#endif
// with threads
void simpleThreadedProducerConsumer_data();
void simpleThreadedProducerConsumer();
// with processes
void simpleProcessProducerConsumer_data();
void simpleProcessProducerConsumer();
// extreme cases
void useTooMuchMemory();
#if !defined(Q_OS_HPUX) && !defined(Q_OS_WINCE)
void attachTooMuch();
#endif
// unique keys
void uniqueKey_data();
void uniqueKey();
protected:
int remove(const QString &key);
QString rememberKey(const QString &key)
{
if (key == EXISTING_SHARE)
return key;
if (!keys.contains(key)) {
keys.append(key);
remove(key);
}
return key;
}
QStringList keys;
QList<QSharedMemory*> jail;
QSharedMemory *existingSharedMemory;
};
tst_QSharedMemory::tst_QSharedMemory() : existingSharedMemory(0)
{
}
tst_QSharedMemory::~tst_QSharedMemory()
{
}
void tst_QSharedMemory::init()
{
existingSharedMemory = new QSharedMemory(EXISTING_SHARE);
if (!existingSharedMemory->create(EXISTING_SIZE)) {
QVERIFY(existingSharedMemory->error() == QSharedMemory::AlreadyExists);
}
}
void tst_QSharedMemory::cleanup()
{
delete existingSharedMemory;
qDeleteAll(jail.begin(), jail.end());
jail.clear();
keys.append(EXISTING_SHARE);
for (int i = 0; i < keys.count(); ++i) {
QSharedMemory sm(keys.at(i));
if (!sm.create(1024)) {
//if(sm.error() != QSharedMemory::KeyError)
// qWarning() << "test cleanup: remove failed:" << keys.at(i) << sm.error() << sm.errorString();
sm.attach();
sm.detach();
remove(keys.at(i));
}
}
}
#ifndef Q_OS_WIN
#include "private/qsharedmemory_p.h"
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#endif
int tst_QSharedMemory::remove(const QString &key)
{
#ifndef Q_OS_WIN
// On unix the shared memory might exists from a previously failed test
// or segfault, remove it it does
if (key.isEmpty())
return -1;
// ftok requires that an actual file exists somewhere
QString fileName = QSharedMemoryPrivate::makePlatformSafeKey(key);
if (!QFile::exists(fileName)) {
//qDebug() << "exits failed";
return -2;
}
int unix_key = ftok(fileName.toLatin1().constData(), 'Q');
if (-1 == unix_key) {
qDebug() << "ftok failed";
return -3;
}
int id = shmget(unix_key, 0, 0660);
if (-1 == id) {
qDebug() << "shmget failed";
return -4;
}
struct shmid_ds shmid_ds;
if (-1 == shmctl(id, IPC_RMID, &shmid_ds)) {
qDebug() << "shmctl failed";
return -5;
}
return QFile::remove(fileName);
#else
Q_UNUSED(key);
return 0;
#endif
}
/*!
Tests the default values
*/
void tst_QSharedMemory::constructor()
{
QSharedMemory sm;
QCOMPARE(sm.key(), QString());
QVERIFY(!sm.isAttached());
QVERIFY(sm.data() == 0);
QCOMPARE(sm.size(), 0);
QCOMPARE(sm.error(), QSharedMemory::NoError);
QVERIFY(sm.errorString() == QString());
}
void tst_QSharedMemory::key_data()
{
QTest::addColumn<QString>("constructorKey");
QTest::addColumn<QString>("setKey");
QTest::addColumn<QString>("setNativeKey");
QTest::newRow("null, null, null") << QString() << QString() << QString();
QTest::newRow("one, null, null") << QString("one") << QString() << QString();
QTest::newRow("null, one, null") << QString() << QString("one") << QString();
QTest::newRow("null, null, one") << QString() << QString() << QString("one");
QTest::newRow("one, two, null") << QString("one") << QString("two") << QString();
QTest::newRow("one, null, two") << QString("one") << QString() << QString("two");
QTest::newRow("null, one, two") << QString() << QString("one") << QString("two");
QTest::newRow("one, two, three") << QString("one") << QString("two") << QString("three");
QTest::newRow("invalid") << QString("o/e") << QString("t/o") << QString("|x");
}
/*!
Basic key testing
*/
void tst_QSharedMemory::key()
{
QFETCH(QString, constructorKey);
QFETCH(QString, setKey);
QFETCH(QString, setNativeKey);
QSharedMemory sm(constructorKey);
QCOMPARE(sm.key(), constructorKey);
QCOMPARE(sm.nativeKey().isEmpty(), constructorKey.isEmpty());
sm.setKey(setKey);
QCOMPARE(sm.key(), setKey);
QCOMPARE(sm.nativeKey().isEmpty(), setKey.isEmpty());
sm.setNativeKey(setNativeKey);
QVERIFY(sm.key().isNull());
QCOMPARE(sm.nativeKey(), setNativeKey);
QCOMPARE(sm.isAttached(), false);
QCOMPARE(sm.error(), QSharedMemory::NoError);
QVERIFY(sm.errorString() == QString());
QVERIFY(sm.data() == 0);
QCOMPARE(sm.size(), 0);
QCOMPARE(sm.detach(), false);
}
void tst_QSharedMemory::create_data()
{
QTest::addColumn<QString>("key");
QTest::addColumn<int>("size");
QTest::addColumn<bool>("canCreate");
QTest::addColumn<QSharedMemory::SharedMemoryError>("error");
QTest::newRow("null key") << QString() << 1024
<< false << QSharedMemory::KeyError;
QTest::newRow("-1 size") << QString("negsize") << -1
<< false << QSharedMemory::InvalidSize;
QTest::newRow("nor size") << QString("norsize") << 1024
<< true << QSharedMemory::NoError;
QTest::newRow("already exists") << QString(EXISTING_SHARE) << EXISTING_SIZE
<< false << QSharedMemory::AlreadyExists;
}
/*!
Basic create testing
*/
void tst_QSharedMemory::create()
{
QFETCH(QString, key);
QFETCH(int, size);
QFETCH(bool, canCreate);
QFETCH(QSharedMemory::SharedMemoryError, error);
QSharedMemory sm(rememberKey(key));
QCOMPARE(sm.create(size), canCreate);
if(sm.error() != error)
qDebug() << sm.errorString();
QCOMPARE(sm.key(), key);
if (canCreate) {
QVERIFY(sm.errorString() == QString());
QVERIFY(sm.data() != 0);
QVERIFY(sm.size() != 0);
} else {
QVERIFY(sm.data() == 0);
QVERIFY(sm.errorString() != QString());
}
}
void tst_QSharedMemory::attach_data()
{
QTest::addColumn<QString>("key");
QTest::addColumn<bool>("exists");
QTest::addColumn<QSharedMemory::SharedMemoryError>("error");
QTest::newRow("null key") << QString() << false << QSharedMemory::KeyError;
QTest::newRow("doesn't exists") << QString("doesntexists") << false << QSharedMemory::NotFound;
// HPUX doesn't allow for multiple attaches per process.
#ifndef Q_OS_HPUX
QTest::newRow("already exists") << QString(EXISTING_SHARE) << true << QSharedMemory::NoError;
#endif
}
/*!
Basic attach/detach testing
*/
void tst_QSharedMemory::attach()
{
QFETCH(QString, key);
QFETCH(bool, exists);
QFETCH(QSharedMemory::SharedMemoryError, error);
QSharedMemory sm(key);
QCOMPARE(sm.attach(), exists);
QCOMPARE(sm.isAttached(), exists);
QCOMPARE(sm.error(), error);
QCOMPARE(sm.key(), key);
if (exists) {
QVERIFY(sm.data() != 0);
QVERIFY(sm.size() != 0);
QCOMPARE(sm.errorString(), QString());
QVERIFY(sm.detach());
// Make sure detach doesn't screw up something and we can't re-attach.
QVERIFY(sm.attach());
QVERIFY(sm.data() != 0);
QVERIFY(sm.size() != 0);
QVERIFY(sm.detach());
QCOMPARE(sm.size(), 0);
QVERIFY(sm.data() == 0);
} else {
QVERIFY(sm.data() == 0);
QVERIFY(sm.size() == 0);
QVERIFY(sm.errorString() != QString());
QVERIFY(!sm.detach());
}
}
void tst_QSharedMemory::lock()
{
QSharedMemory shm;
QVERIFY(!shm.lock());
QCOMPARE(shm.error(), QSharedMemory::LockError);
shm.setKey(QLatin1String("qsharedmemory"));
QVERIFY(!shm.lock());
QCOMPARE(shm.error(), QSharedMemory::LockError);
QVERIFY(shm.create(100));
QVERIFY(shm.lock());
QTest::ignoreMessage(QtWarningMsg, "QSharedMemory::lock: already locked");
QVERIFY(shm.lock());
// we didn't unlock(), so ignore the warning from auto-detach in destructor
QTest::ignoreMessage(QtWarningMsg, "QSharedMemory::lock: already locked");
}
/*!
Other shared memory are allowed to be attached after we remove,
but new shared memory are not allowed to attach after a remove.
*/
// HPUX doesn't allow for multiple attaches per process.
#ifndef Q_OS_HPUX
void tst_QSharedMemory::removeWhileAttached()
{
rememberKey("one");
// attach 1
QSharedMemory *smOne = new QSharedMemory(QLatin1String("one"));
QVERIFY(smOne->create(1024));
QVERIFY(smOne->isAttached());
// attach 2
QSharedMemory *smTwo = new QSharedMemory(QLatin1String("one"));
QVERIFY(smTwo->attach());
QVERIFY(smTwo->isAttached());
// detach 1 and remove, remove one first to catch another error.
delete smOne;
delete smTwo;
// three shouldn't be able to attach
QSharedMemory smThree(QLatin1String("one"));
QVERIFY(!smThree.attach());
QCOMPARE(smThree.error(), QSharedMemory::NotFound);
}
#endif
/*!
The memory should be set to 0 after created.
*/
void tst_QSharedMemory::emptyMemory()
{
QSharedMemory sm(rememberKey(QLatin1String("voidland")));
int size = 1024;
QVERIFY(sm.create(size, QSharedMemory::ReadOnly));
char *get = (char*)sm.data();
char null = 0;
for (int i = 0; i < size; ++i)
QCOMPARE(get[i], null);
}
/*!
Verify that attach with ReadOnly is actually read only
by writing to data and causing a segfault.
*/
// This test opens a crash dialog on Windows.
#ifndef Q_OS_WIN
void tst_QSharedMemory::readOnly()
{
QString program = LACKEYDIR "/lackey";
QStringList arguments;
rememberKey("readonly_segfault");
arguments << SRCDIR "../lackey/scripts/readonly_segfault.js";
// ### on windows disable the popup somehow
QProcess p;
p.start(program, arguments);
p.setProcessChannelMode(QProcess::ForwardedChannels);
p.waitForFinished();
QCOMPARE(p.error(), QProcess::Crashed);
}
#endif
/*!
Keep making shared memory until the kernel stops us.
*/
void tst_QSharedMemory::useTooMuchMemory()
{
#ifdef Q_OS_LINUX
bool success = true;
int count = 0;
while (success) {
QString key = QString("maxmemorytest_%1").arg(count++);
QSharedMemory *sm = new QSharedMemory(rememberKey(key));
QVERIFY(sm);
jail.append(sm);
int size = 32768 * 1024;
success = sm->create(size);
if (!success && sm->error() == QSharedMemory::AlreadyExists) {
// left over from a crash, clean it up
sm->attach();
sm->detach();
success = sm->create(size);
}
if (!success) {
QVERIFY(!sm->isAttached());
QCOMPARE(sm->key(), key);
QCOMPARE(sm->size(), 0);
QVERIFY(sm->data() == 0);
if (sm->error() != QSharedMemory::OutOfResources)
qDebug() << sm->error() << sm->errorString();
// ### Linux wont return OutOfResources if there are not enough semaphores to use.
QVERIFY(sm->error() == QSharedMemory::OutOfResources
|| sm->error() == QSharedMemory::LockError);
QVERIFY(sm->errorString() != QString());
QVERIFY(!sm->attach());
QVERIFY(!sm->detach());
} else {
QVERIFY(sm->isAttached());
}
}
#endif
}
/*!
Create one shared memory (government) and see how many other shared memories (wars) we can
attach before the system runs out of resources.
*/
// HPUX doesn't allow for multiple attaches per process.
// For WinCE, this test nearly kills the system, so skip it.
#if !defined(Q_OS_HPUX) && !defined(Q_OS_WINCE)
void tst_QSharedMemory::attachTooMuch()
{
QSKIP("disabled");
QSharedMemory government(rememberKey("government"));
QVERIFY(government.create(1024));
while (true) {
QSharedMemory *war = new QSharedMemory(government.key());
QVERIFY(war);
jail.append(war);
if (!war->attach()) {
QVERIFY(!war->isAttached());
QCOMPARE(war->key(), government.key());
QCOMPARE(war->size(), 0);
QVERIFY(war->data() == 0);
QCOMPARE(war->error(), QSharedMemory::OutOfResources);
QVERIFY(war->errorString() != QString());
QVERIFY(!war->detach());
break;
} else {
QVERIFY(war->isAttached());
}
}
}
#endif
// HPUX doesn't allow for multiple attaches per process.
#ifndef Q_OS_HPUX
void tst_QSharedMemory::simpleProducerConsumer_data()
{
QTest::addColumn<QSharedMemory::AccessMode>("mode");
QTest::newRow("readonly") << QSharedMemory::ReadOnly;
QTest::newRow("readwrite") << QSharedMemory::ReadWrite;
}
/*!
The basic consumer producer that rounds out the basic testing.
If this fails then any muli-threading/process might fail (but be
harder to debug)
This doesn't require nor test any locking system.
*/
void tst_QSharedMemory::simpleProducerConsumer()
{
QFETCH(QSharedMemory::AccessMode, mode);
rememberKey(QLatin1String("market"));
QSharedMemory producer(QLatin1String("market"));
QSharedMemory consumer(QLatin1String("market"));
int size = 512;
QVERIFY(producer.create(size));
QVERIFY(consumer.attach(mode));
char *put = (char*)producer.data();
char *get = (char*)consumer.data();
// On Windows CE you always have ReadWrite access. Thus
// ViewMapOfFile returns the same pointer
#if !defined(Q_OS_WINCE)
QVERIFY(put != get);
#endif
for (int i = 0; i < size; ++i) {
put[i] = 'Q';
QCOMPARE(get[i], 'Q');
}
QVERIFY(consumer.detach());
}
#endif
// HPUX doesn't allow for multiple attaches per process.
#ifndef Q_OS_HPUX
void tst_QSharedMemory::simpleDoubleProducerConsumer()
{
rememberKey(QLatin1String("market"));
QSharedMemory producer(QLatin1String("market"));
int size = 512;
QVERIFY(producer.create(size));
QVERIFY(producer.detach());
QVERIFY(producer.create(size));
{
QSharedMemory consumer(QLatin1String("market"));
QVERIFY(consumer.attach());
}
}
#endif
class Consumer : public QThread
{
public:
void run()
{
QSharedMemory consumer(QLatin1String("market"));
while (!consumer.attach()) {
if (consumer.error() != QSharedMemory::NotFound)
qDebug() << "consumer: failed to connect" << consumer.error() << consumer.errorString();
QVERIFY(consumer.error() == QSharedMemory::NotFound || consumer.error() == QSharedMemory::KeyError);
QTest::qWait(1);
}
char *memory = (char*)consumer.data();
int i = 0;
while (true) {
if(!consumer.lock())
break;
if (memory[0] == 'Q')
memory[0] = ++i;
if (memory[0] == 'E') {
memory[1]++;
QVERIFY(consumer.unlock());
break;
}
QVERIFY(consumer.unlock());
QTest::qWait(1);
}
QVERIFY(consumer.detach());
}
};
class Producer : public QThread
{
public:
void run()
{
QSharedMemory producer(QLatin1String("market"));
int size = 1024;
if (!producer.create(size)) {
// left over from a crash...
if (producer.error() == QSharedMemory::AlreadyExists) {
producer.attach();
producer.detach();
QVERIFY(producer.create(size));
}
}
QVERIFY(producer.isAttached());
char *memory = (char*)producer.data();
memory[1] = '0';
QTime timer;
timer.start();
int i = 0;
while (i < 5 && timer.elapsed() < 5000) {
QVERIFY(producer.lock());
if (memory[0] == 'Q') {
QVERIFY(producer.unlock());
QTest::qWait(1);
continue;
}
++i;
memory[0] = 'Q';
QVERIFY(producer.unlock());
QTest::qWait(1);
}
// tell everyone to quit
QVERIFY(producer.lock());
memory[0] = 'E';
QVERIFY(producer.unlock());
}
private:
};
void tst_QSharedMemory::simpleThreadedProducerConsumer_data()
{
QTest::addColumn<bool>("producerIsThread");
QTest::addColumn<int>("threads");
for (int i = 0; i < 5; ++i) {
QTest::newRow("1 consumer, producer is thread") << true << 1;
QTest::newRow("1 consumer, producer is this") << false << 1;
QTest::newRow("5 consumers, producer is thread") << true << 5;
QTest::newRow("5 consumers, producer is this") << false << 5;
}
}
/*!
The basic producer/consumer, but this time using threads.
*/
void tst_QSharedMemory::simpleThreadedProducerConsumer()
{
QFETCH(bool, producerIsThread);
QFETCH(int, threads);
rememberKey(QLatin1String("market"));
#if defined Q_OS_HPUX && defined __ia64
QSKIP("This test locks up on gravlaks.troll.no");
#endif
Producer p;
if (producerIsThread)
p.start();
QList<Consumer*> consumers;
for (int i = 0; i < threads; ++i) {
consumers.append(new Consumer());
consumers.last()->start();
}
if (!producerIsThread)
p.run();
p.wait(5000);
while (!consumers.isEmpty()) {
QVERIFY(consumers.first()->wait(5000));
delete consumers.takeFirst();
}
}
void tst_QSharedMemory::simpleProcessProducerConsumer_data()
{
QTest::addColumn<int>("processes");
int tries = 5;
for (int i = 0; i < tries; ++i) {
QTest::newRow("1 process") << 1;
QTest::newRow("5 processes") << 5;
}
}
/*!
Create external processes that produce and consume.
*/
void tst_QSharedMemory::simpleProcessProducerConsumer()
{
QFETCH(int, processes);
rememberKey("market");
QStringList arguments = QStringList() << SRCDIR "../lackey/scripts/producer.js";
QProcess producer;
producer.setProcessChannelMode(QProcess::ForwardedChannels);
producer.start( LACKEYDIR "/lackey", arguments);
producer.waitForStarted();
QVERIFY(producer.error() != QProcess::FailedToStart);
QList<QProcess*> consumers;
unsigned int failedProcesses = 0;
for (int i = 0; i < processes; ++i) {
QStringList arguments = QStringList() << SRCDIR "../lackey/scripts/consumer.js";
QProcess *p = new QProcess;
p->setProcessChannelMode(QProcess::ForwardedChannels);
#ifdef Q_OS_WINCE
// We can't start the same executable twice on Windows CE.
// Create a copy instead.
QString lackeyCopy = QLatin1String(LACKEYDIR "/lackey");
lackeyCopy.append(QString::number(i));
lackeyCopy.append(QLatin1String(".exe"));
if (!QFile::exists(lackeyCopy))
QVERIFY(QFile::copy(LACKEYDIR "/lackey.exe", lackeyCopy));
p->start(lackeyCopy, arguments);
#else
p->start(LACKEYDIR "/lackey", arguments);
#endif
if (p->waitForStarted(2000))
consumers.append(p);
else
++failedProcesses;
}
QVERIFY(producer.waitForFinished(5000));
bool consumerFailed = false;
while (!consumers.isEmpty()) {
QVERIFY(consumers.first()->waitForFinished(3000));
if (consumers.first()->state() == QProcess::Running ||
consumers.first()->exitStatus() != QProcess::NormalExit ||
consumers.first()->exitCode() != 0) {
consumerFailed = true;
}
delete consumers.takeFirst();
}
QCOMPARE(consumerFailed, false);
QCOMPARE(failedProcesses, (unsigned int)(0));
}
void tst_QSharedMemory::uniqueKey_data()
{
QTest::addColumn<QString>("key1");
QTest::addColumn<QString>("key2");
QTest::newRow("null == null") << QString() << QString();
QTest::newRow("key == key") << QString("key") << QString("key");
QTest::newRow("key1 == key1") << QString("key1") << QString("key1");
QTest::newRow("key != key1") << QString("key") << QString("key1");
QTest::newRow("ke1y != key1") << QString("ke1y") << QString("key1");
QTest::newRow("key1 != key2") << QString("key1") << QString("key2");
}
void tst_QSharedMemory::uniqueKey()
{
QFETCH(QString, key1);
QFETCH(QString, key2);
QSharedMemory sm1(key1);
QSharedMemory sm2(key2);
bool setEqual = (key1 == key2);
bool keyEqual = (sm1.key() == sm2.key());
bool nativeEqual = (sm1.nativeKey() == sm2.nativeKey());
QCOMPARE(keyEqual, setEqual);
QCOMPARE(nativeEqual, setEqual);
}
QTEST_MAIN(tst_QSharedMemory)
#include "tst_qsharedmemory.moc"

View File

@ -1 +0,0 @@
tst_qsystemsemaphore

View File

@ -1,7 +0,0 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file alias="systemsemaphore_acquire.js">../lackey/scripts/systemsemaphore_acquire.js</file>
<file alias="systemsemaphore_release.js">../lackey/scripts/systemsemaphore_release.js</file>
<file alias="systemsemaphore_acquirerelease.js">../lackey/scripts/systemsemaphore_acquirerelease.js</file>
</qresource>
</RCC>

View File

@ -1,23 +0,0 @@
CONFIG += testcase
QT += testlib
include(../qsharedmemory/src/src.pri)
win32: CONFIG += console
DEFINES += QSHAREDMEMORY_DEBUG
DEFINES += QSYSTEMSEMAPHORE_DEBUG
SOURCES += tst_qsystemsemaphore.cpp
TARGET = tst_qsystemsemaphore
RESOURCES += files.qrc
wince*: {
requires(contains(QT_CONFIG,script))
# this test calls lackey, which then again depends on QtScript.
# let's add it here so that it gets deployed easily
QT += script
lackey.files = $$OUT_PWD/../lackey/lackey.exe ../lackey/scripts
lackey.path = .
DEPLOYMENT += lackey
}

View File

@ -1,311 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QtTest/QtTest>
#include <qsystemsemaphore.h>
//TESTED_CLASS=
//TESTED_FILES=
#define EXISTING_SHARE "existing"
#ifdef Q_OS_WINCE
#define LACKEYLOC "."
#else
#define LACKEYLOC "../lackey"
#endif
#define LACKYWAITTIME 10000
class tst_QSystemSemaphore : public QObject
{
Q_OBJECT
public:
tst_QSystemSemaphore();
virtual ~tst_QSystemSemaphore();
public Q_SLOTS:
void init();
void cleanup();
private slots:
void key_data();
void key();
void basicacquire();
void complexacquire();
void basicProcesses();
void processes_data();
void processes();
#ifndef Q_OS_WIN
void undo();
#endif
void initialValue();
private:
QSystemSemaphore *existingLock;
QString makeFile(const QString &resource)
{
QFile memory(resource);
if (!memory.open(QIODevice::ReadOnly)) {
qDebug() << "error reading resource" << resource;
return QString();
}
QTemporaryFile *file = new QTemporaryFile;
file->open();
file->write(memory.readAll());
tempFiles.append(file);
file->flush();
#ifdef Q_OS_WINCE
// flush does not flush to disk on Windows CE. It flushes it into its application
// cache. Thus we need to close the file to be able that other processes(lackey) can read it
QString fileName = file->fileName();
file->close();
return fileName;
#endif
return file->fileName();
}
QString acquire_js() { return makeFile(":/systemsemaphore_acquire.js"); }
QString release_js() { return makeFile(":/systemsemaphore_release.js"); }
QString acquirerelease_js() { return makeFile(":/systemsemaphore_acquirerelease.js"); }
QList<QTemporaryFile*> tempFiles;
};
tst_QSystemSemaphore::tst_QSystemSemaphore()
{
if (!QFile::exists(LACKEYLOC "/lackey"))
qWarning() << "lackey executable doesn't exists!";
}
tst_QSystemSemaphore::~tst_QSystemSemaphore()
{
qDeleteAll(tempFiles);
}
void tst_QSystemSemaphore::init()
{
existingLock = new QSystemSemaphore(EXISTING_SHARE, 1, QSystemSemaphore::Create);
}
void tst_QSystemSemaphore::cleanup()
{
delete existingLock;
}
void tst_QSystemSemaphore::key_data()
{
QTest::addColumn<QString>("constructorKey");
QTest::addColumn<QString>("setKey");
QTest::newRow("null, null") << QString() << QString();
QTest::newRow("null, one") << QString() << QString("one");
QTest::newRow("one, two") << QString("one") << QString("two");
}
/*!
Basic key testing
*/
void tst_QSystemSemaphore::key()
{
QFETCH(QString, constructorKey);
QFETCH(QString, setKey);
QSystemSemaphore sem(constructorKey);
QCOMPARE(sem.key(), constructorKey);
QCOMPARE(sem.error(), QSystemSemaphore::NoError);
QCOMPARE(sem.errorString(), QString());
sem.setKey(setKey);
QCOMPARE(sem.key(), setKey);
QCOMPARE(sem.error(), QSystemSemaphore::NoError);
QCOMPARE(sem.errorString(), QString());
}
void tst_QSystemSemaphore::basicacquire()
{
QSystemSemaphore sem("QSystemSemaphore_basicacquire", 1, QSystemSemaphore::Create);
QVERIFY(sem.acquire());
QCOMPARE(sem.error(), QSystemSemaphore::NoError);
QVERIFY(sem.release());
QCOMPARE(sem.error(), QSystemSemaphore::NoError);
QCOMPARE(sem.errorString(), QString());
}
void tst_QSystemSemaphore::complexacquire()
{
QSystemSemaphore sem("QSystemSemaphore_complexacquire", 2, QSystemSemaphore::Create);
QVERIFY(sem.acquire());
QVERIFY(sem.release());
QVERIFY(sem.acquire());
QVERIFY(sem.release());
QVERIFY(sem.acquire());
QVERIFY(sem.acquire());
QVERIFY(sem.release());
QVERIFY(sem.release());
QCOMPARE(sem.error(), QSystemSemaphore::NoError);
QCOMPARE(sem.errorString(), QString());
}
void tst_QSystemSemaphore::basicProcesses()
{
QSystemSemaphore sem("store", 0, QSystemSemaphore::Create);
QStringList acquireArguments = QStringList() << acquire_js();
QStringList releaseArguments = QStringList() << release_js();
QProcess acquire;
acquire.setProcessChannelMode(QProcess::ForwardedChannels);
QProcess release;
release.setProcessChannelMode(QProcess::ForwardedChannels);
acquire.start(LACKEYLOC "/lackey", acquireArguments);
acquire.waitForFinished(LACKYWAITTIME);
QVERIFY(acquire.state() == QProcess::Running);
acquire.kill();
release.start(LACKEYLOC "/lackey", releaseArguments);
acquire.waitForFinished(LACKYWAITTIME);
release.waitForFinished(LACKYWAITTIME);
QVERIFY(acquire.state() == QProcess::NotRunning);
}
void tst_QSystemSemaphore::processes_data()
{
QTest::addColumn<int>("processes");
for (int i = 0; i < 5; ++i) {
QTest::newRow("1 process") << 1;
QTest::newRow("3 process") << 3;
QTest::newRow("10 process") << 10;
}
}
void tst_QSystemSemaphore::processes()
{
QSystemSemaphore sem("store", 1, QSystemSemaphore::Create);
QFETCH(int, processes);
QStringList scripts;
for (int i = 0; i < processes; ++i)
scripts.append(acquirerelease_js());
QList<QProcess*> consumers;
for (int i = 0; i < scripts.count(); ++i) {
QStringList arguments = QStringList() << scripts.at(i);
QProcess *p = new QProcess;
p->setProcessChannelMode(QProcess::ForwardedChannels);
consumers.append(p);
#ifdef Q_OS_WINCE
// We can't start the same executable twice on Windows CE.
// Create a copy instead.
QString lackeyCopy = QLatin1String(LACKEYLOC "/lackey");
if (i > 0) {
lackeyCopy.append(QString::number(i));
lackeyCopy.append(QLatin1String(".exe"));
if (!QFile::exists(lackeyCopy))
QVERIFY(QFile::copy(LACKEYLOC "/lackey.exe", lackeyCopy));
}
p->start(lackeyCopy, arguments);
#else
p->start(LACKEYLOC "/lackey", arguments);
#endif
}
while (!consumers.isEmpty()) {
consumers.first()->waitForFinished();
QCOMPARE(consumers.first()->exitStatus(), QProcess::NormalExit);
QCOMPARE(consumers.first()->exitCode(), 0);
delete consumers.takeFirst();
}
}
// This test only checks a unix behavior.
#ifndef Q_OS_WIN
void tst_QSystemSemaphore::undo()
{
QSystemSemaphore sem("store", 1, QSystemSemaphore::Create);
QStringList acquireArguments = QStringList() << acquire_js();
QProcess acquire;
acquire.setProcessChannelMode(QProcess::ForwardedChannels);
acquire.start(LACKEYLOC "/lackey", acquireArguments);
acquire.waitForFinished(LACKYWAITTIME);
QVERIFY(acquire.state()== QProcess::NotRunning);
// At process exit the kernel should auto undo
acquire.start(LACKEYLOC "/lackey", acquireArguments);
acquire.waitForFinished(LACKYWAITTIME);
QVERIFY(acquire.state()== QProcess::NotRunning);
}
#endif
void tst_QSystemSemaphore::initialValue()
{
QSystemSemaphore sem("store", 1, QSystemSemaphore::Create);
QStringList acquireArguments = QStringList() << acquire_js();
QStringList releaseArguments = QStringList() << release_js();
QProcess acquire;
acquire.setProcessChannelMode(QProcess::ForwardedChannels);
QProcess release;
release.setProcessChannelMode(QProcess::ForwardedChannels);
acquire.start(LACKEYLOC "/lackey", acquireArguments);
acquire.waitForFinished(LACKYWAITTIME);
QVERIFY(acquire.state()== QProcess::NotRunning);
acquire.start(LACKEYLOC "/lackey", acquireArguments << "2");
acquire.waitForFinished(LACKYWAITTIME);
QVERIFY(acquire.state()== QProcess::Running);
acquire.kill();
release.start(LACKEYLOC "/lackey", releaseArguments);
acquire.waitForFinished(LACKYWAITTIME);
release.waitForFinished(LACKYWAITTIME);
QVERIFY(acquire.state()== QProcess::NotRunning);
}
QTEST_MAIN(tst_QSystemSemaphore)
#include "tst_qsystemsemaphore.moc"

View File

@ -1,6 +0,0 @@
TEMPLATE=subdirs
# lackey depends on qtscript and the tests depend on lackey :(
#SUBDIRS=\
# qsharedmemory \
# qsystemsemaphore \
# lackey