diff options
Diffstat (limited to 'old/libqtuitest/qalternatestack_win.cpp')
-rw-r--r-- | old/libqtuitest/qalternatestack_win.cpp | 210 |
1 files changed, 210 insertions, 0 deletions
diff --git a/old/libqtuitest/qalternatestack_win.cpp b/old/libqtuitest/qalternatestack_win.cpp new file mode 100644 index 0000000..e0e600e --- /dev/null +++ b/old/libqtuitest/qalternatestack_win.cpp @@ -0,0 +1,210 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of QtUiTest. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qalternatestack_p.h" + +#include <QCoreApplication> +#include <QThread> + +#include <windows.h> + +struct QAlternateStackPrivate +{ + // All instances of QAlternateStack. + static QList<QAlternateStack*> instances; + + // Callback used to start each fiber. + static void CALLBACK startFiber(PVOID); + + static LPVOID mainFiber; + + QAlternateStackEntryPoint entryFunction; + QVariant entryData; + quint32 size; + + LPVOID fiber; +}; +QList<QAlternateStack*> QAlternateStackPrivate::instances; +LPVOID QAlternateStackPrivate::mainFiber = 0; + +/* + Given a Windows error code, return a C string with the corresponding error text. + The returned pointer points to static storage, hence this function is not thread safe. +*/ +const char* qstrwinerror(DWORD errorcode) +{ + static char out[256]; + DWORD ok = FormatMessageA( + FORMAT_MESSAGE_FROM_SYSTEM, + 0, + errorcode, + 0, + out, + sizeof(out)/sizeof(TCHAR), + 0 + ); + if (!ok) { + QByteArray realError = QByteArray::number((int)errorcode); + QByteArray nextError = QByteArray::number((int)GetLastError()); + QByteArray outString = "(error "; + outString += realError; + outString += "; additionally, error "; + outString += nextError; + outString += " while looking up error string)"; + qstrncpy(out, outString.constData(), sizeof(out)); + } + return out; +} + +void CALLBACK QAlternateStackPrivate::startFiber(PVOID _q) +{ + QAlternateStack* q = static_cast<QAlternateStack*>(_q); + QAlternateStackPrivate* d = q->d; + + d->entryFunction(q, d->entryData); + + /* Setting entryFunction to 0 tells main fiber we are done */ + d->entryFunction = 0; + d->entryData = QVariant(); + + q->switchFrom(); +} + +QAlternateStack::QAlternateStack(quint32 size, QObject* parent) + : QObject(parent), + d(new QAlternateStackPrivate) +{ + Q_ASSERT_X(QAlternateStack::isAvailable(), "QAlternateStack", + "QAlternateStack is not available on this platform!"); + + /* + Make sure we belong to the main thread to avoid keeping track of whether each thread has + been converted to a fiber. + */ + Q_ASSERT_X(QThread::currentThread() == QCoreApplication::instance()->thread(), + "QAlternateStack", "Alternate stacks must be created in the main thread!"); + + /* + The main thread must be a fiber before we can manage any other fibers. + Unfortunately, earlier than Windows Vista, it is not possible to test if a thread is + a fiber. So it is possible ConvertThreadToFiber will be called more than once for + the main thread. + */ + if (!QAlternateStackPrivate::mainFiber) { + QAlternateStackPrivate::mainFiber = ConvertThreadToFiber(0); + if (!QAlternateStackPrivate::mainFiber) { + qFatal("QAlternateStack: failed to convert thread to fiber: %s", + qstrwinerror(GetLastError())); + } + } + + d->entryFunction = 0; + d->size = size; + d->fiber = 0; + + QAlternateStackPrivate::instances << this; +} + +QAlternateStack::~QAlternateStack() +{ + delete d; + d = 0; + QAlternateStackPrivate::instances.removeAll(this); +} + +void QAlternateStack::start(QAlternateStackEntryPoint entry, const QVariant& data) +{ + Q_ASSERT_X(!isActive(), "QAlternateStack::start", + qPrintable(QString("`start' called while already active."))); + + d->fiber = CreateFiber(d->size, QAlternateStackPrivate::startFiber, this); + if (!d->fiber) { + qFatal("QAlternateStack: failed to create fiber: %s", qstrwinerror(GetLastError())); + } + + d->entryFunction = entry; + d->entryData = data; + SwitchToFiber(d->fiber); + + if (!d->entryFunction) { + DeleteFiber(d->fiber); + d->fiber = 0; + } +} + +void QAlternateStack::switchTo() +{ + // We must not be the currently active stack. + Q_ASSERT_X(!isCurrentStack(), "QAlternateStack::switchTo", + qPrintable(QString("`switchTo' called in currently active stack."))); + + // If not active, nothing to do + if (!isActive()) return; + + SwitchToFiber(d->fiber); + + if (!d->entryFunction) { + DeleteFiber(d->fiber); + d->fiber = 0; + } +} + +void QAlternateStack::switchFrom() +{ + // We must be the currently active stack. + Q_ASSERT_X(isCurrentStack(), "QAlternateStack::switchFrom", + qPrintable(QString("`switchFrom' called from wrong stack."))); + + SwitchToFiber(QAlternateStackPrivate::mainFiber); +} + +bool QAlternateStack::isActive() const +{ return d->fiber; } + +bool QAlternateStack::isCurrentStack() const +{ return GetFiberData() == this; } + +QList<QAlternateStack*> QAlternateStack::instances() +{ return QAlternateStackPrivate::instances; } + +bool QAlternateStack::isAvailable() +{ return true; } + |