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:
parent
145357bf58
commit
540e368e04
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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"
|
@ -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());
|
@ -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);
|
@ -1,4 +0,0 @@
|
||||
var sm = new ScriptSharedMemory;
|
||||
sm.setKey("readonly_segfault");
|
||||
sm.createReadOnly(1024);
|
||||
var data = sm.set(0, "a");
|
@ -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());
|
@ -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());
|
@ -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");
|
@ -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());
|
@ -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");
|
@ -1,3 +0,0 @@
|
||||
tst_qsharedmemory
|
||||
lackey/lackey.exe
|
||||
qsystemlock/tst_qsystemlock.exe
|
@ -1,4 +0,0 @@
|
||||
TEMPLATE = subdirs
|
||||
SUBDIRS = test qsystemlock
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
@ -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/../\\\"
|
||||
}
|
@ -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"
|
||||
|
@ -1 +0,0 @@
|
||||
tst_qsystemsemaphore
|
@ -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>
|
@ -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
|
||||
}
|
@ -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"
|
||||
|
@ -1,6 +0,0 @@
|
||||
TEMPLATE=subdirs
|
||||
# lackey depends on qtscript and the tests depend on lackey :(
|
||||
#SUBDIRS=\
|
||||
# qsharedmemory \
|
||||
# qsystemsemaphore \
|
||||
# lackey
|
Loading…
Reference in New Issue
Block a user