summaryrefslogtreecommitdiffstats
path: root/old/libqtuitest/qalternatestack_win.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'old/libqtuitest/qalternatestack_win.cpp')
-rw-r--r--old/libqtuitest/qalternatestack_win.cpp210
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; }
+