From 0723e14699704c35d5d61fa7f5e9f3bdbb378afa Mon Sep 17 00:00:00 2001 From: Jeff Kehres Date: Fri, 23 Mar 2012 10:43:44 -0400 Subject: Integrate Blackberry Platform Services (BPS) with Qt event loop. This ensures interoperability between the Blackbery C and C++ APIs and makes it easier to expose platform services in C++ that are exposed in BPS - since events from both APIs can be processed on the same thread. Change-Id: I7270adc64c26396f66d9126141500d5e58be51e7 Reviewed-by: Kevin Krammer Reviewed-by: Giuseppe D'Angelo Reviewed-by: Bradley T. Hughes --- src/corelib/kernel/kernel.pri | 7 + src/corelib/kernel/qcoreapplication.cpp | 14 +- src/corelib/kernel/qeventdispatcher_blackberry.cpp | 262 +++++++++++++++++++++ src/corelib/kernel/qeventdispatcher_blackberry_p.h | 96 ++++++++ src/corelib/thread/qthread_unix.cpp | 17 +- 5 files changed, 389 insertions(+), 7 deletions(-) create mode 100644 src/corelib/kernel/qeventdispatcher_blackberry.cpp create mode 100644 src/corelib/kernel/qeventdispatcher_blackberry_p.h diff --git a/src/corelib/kernel/kernel.pri b/src/corelib/kernel/kernel.pri index 4b81087e2f..bef2929214 100644 --- a/src/corelib/kernel/kernel.pri +++ b/src/corelib/kernel/kernel.pri @@ -136,3 +136,10 @@ vxworks { kernel/qfunctions_vxworks.h } +blackberry { + SOURCES += \ + kernel/qeventdispatcher_blackberry.cpp + HEADERS += \ + kernel/qeventdispatcher_blackberry_p.h +} + diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index d188ccbc9a..95c80cad20 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -67,10 +67,14 @@ #include #if defined(Q_OS_UNIX) -# if !defined(QT_NO_GLIB) -# include "qeventdispatcher_glib_p.h" +# if defined(Q_OS_BLACKBERRY) +# include "qeventdispatcher_blackberry_p.h" +# else +# if !defined(QT_NO_GLIB) +# include "qeventdispatcher_glib_p.h" +# endif +# include "qeventdispatcher_unix_p.h" # endif -# include "qeventdispatcher_unix_p.h" #endif #ifdef Q_OS_WIN @@ -328,12 +332,16 @@ void QCoreApplicationPrivate::createEventDispatcher() { Q_Q(QCoreApplication); #if defined(Q_OS_UNIX) +# if defined(Q_OS_BLACKBERRY) + eventDispatcher = new QEventDispatcherBlackberry(q); +# else # if !defined(QT_NO_GLIB) if (qgetenv("QT_NO_GLIB").isEmpty() && QEventDispatcherGlib::versionSupported()) eventDispatcher = new QEventDispatcherGlib(q); else # endif eventDispatcher = new QEventDispatcherUNIX(q); +# endif #elif defined(Q_OS_WIN) eventDispatcher = new QEventDispatcherWin32(q); #else diff --git a/src/corelib/kernel/qeventdispatcher_blackberry.cpp b/src/corelib/kernel/qeventdispatcher_blackberry.cpp new file mode 100644 index 0000000000..462e359bf3 --- /dev/null +++ b/src/corelib/kernel/qeventdispatcher_blackberry.cpp @@ -0,0 +1,262 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Research In Motion +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtCore module 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 "qeventdispatcher_blackberry_p.h" +#include "qsocketnotifier.h" +#include "qdebug.h" + +#include +#include + +struct bpsIOHandlerData { + bpsIOHandlerData() + : count(0), readfds(0), writefds(0), exceptfds(0) + { + } + + int count; + fd_set *readfds; + fd_set *writefds; + fd_set *exceptfds; +}; + +static int bpsIOReadyDomain = -1; + +static int bpsIOHandler(int fd, int io_events, void *data) +{ + // decode callback payload + bpsIOHandlerData *ioData = static_cast(data); + + // check if first file is ready + bool firstReady = (ioData->count == 0); + + // update ready state of file + if (io_events & BPS_IO_INPUT) { + FD_SET(fd, ioData->readfds); + ioData->count++; + } + + if (io_events & BPS_IO_OUTPUT) { + FD_SET(fd, ioData->writefds); + ioData->count++; + } + + if (io_events & BPS_IO_EXCEPT) { + FD_SET(fd, ioData->exceptfds); + ioData->count++; + } + + // force bps_get_event() to return immediately by posting an event to ourselves; + // but this only needs to happen once if multiple files become ready at the same time + if (firstReady) { + // create IO ready event + bps_event_t *event; + int result = bps_event_create(&event, bpsIOReadyDomain, 0, NULL, NULL); + if (result != BPS_SUCCESS) { + qWarning("QEventDispatcherBlackberryPrivate::QEventDispatcherBlackberry: bps_event_create() failed"); + return BPS_FAILURE; + } + + // post IO ready event to our thread + result = bps_push_event(event); + if (result != BPS_SUCCESS) { + qWarning("QEventDispatcherBlackberryPrivate::QEventDispatcherBlackberry: bps_push_event() failed"); + bps_event_destroy(event); + return BPS_FAILURE; + } + } + + return BPS_SUCCESS; +} + +QEventDispatcherBlackberryPrivate::QEventDispatcherBlackberryPrivate() + : ioData(new bpsIOHandlerData) +{ + // prepare to use BPS + int result = bps_initialize(); + if (result != BPS_SUCCESS) + qFatal("QEventDispatcherBlackberryPrivate::QEventDispatcherBlackberry: bps_initialize() failed"); + + // get domain for IO ready events - ignoring race condition here for now + if (bpsIOReadyDomain == -1) { + bpsIOReadyDomain = bps_register_domain(); + if (bpsIOReadyDomain == -1) + qWarning("QEventDispatcherBlackberryPrivate::QEventDispatcherBlackberry: bps_register_domain() failed"); + } + + // \TODO Reinstate this when bps is fixed. See comment in select() below. + // Register thread_pipe[0] with bps + /* + int io_events = BPS_IO_INPUT; + result = bps_add_fd(thread_pipe[0], io_events, &bpsIOHandler, ioData.data()); + if (result != BPS_SUCCESS) + qWarning() << Q_FUNC_INFO << "bps_add_fd() failed"; + */ +} + +QEventDispatcherBlackberryPrivate::~QEventDispatcherBlackberryPrivate() +{ + // we're done using BPS + bps_shutdown(); +} + +///////////////////////////////////////////////////////////////////////////// + +QEventDispatcherBlackberry::QEventDispatcherBlackberry(QObject *parent) + : QEventDispatcherUNIX(*new QEventDispatcherBlackberryPrivate, parent) +{ +} + +QEventDispatcherBlackberry::QEventDispatcherBlackberry(QEventDispatcherBlackberryPrivate &dd, QObject *parent) + : QEventDispatcherUNIX(dd, parent) +{ +} + +QEventDispatcherBlackberry::~QEventDispatcherBlackberry() +{ +} + +void QEventDispatcherBlackberry::registerSocketNotifier(QSocketNotifier *notifier) +{ + Q_ASSERT(notifier); + + // Call the base Unix implementation. Needed to allow select() to be called correctly + QEventDispatcherUNIX::registerSocketNotifier(notifier); + + // Register the fd with bps + int sockfd = notifier->socket(); + int type = notifier->type(); + + int io_events = 0; + switch (type) { + case QSocketNotifier::Read: + io_events |= BPS_IO_INPUT; + break; + case QSocketNotifier::Write: + io_events |= BPS_IO_OUTPUT; + break; + case QSocketNotifier::Exception: + default: + io_events |= BPS_IO_EXCEPT; + break; + } + + Q_D(QEventDispatcherBlackberry); + int result = bps_add_fd(sockfd, io_events, &bpsIOHandler, d->ioData.data()); + if (result != BPS_SUCCESS) + qWarning() << Q_FUNC_INFO << "bps_add_fd() failed"; +} + +void QEventDispatcherBlackberry::unregisterSocketNotifier(QSocketNotifier *notifier) +{ + // Unregister the fd with bps + int sockfd = notifier->socket(); + int result = bps_remove_fd(sockfd); + if (result != BPS_SUCCESS) + qWarning() << Q_FUNC_INFO << "bps_remove_fd() failed"; + + // Allow the base Unix implementation to unregister the fd too + QEventDispatcherUNIX::unregisterSocketNotifier(notifier); +} + +int QEventDispatcherBlackberry::select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, + timeval *timeout) +{ + Q_UNUSED(nfds); + + // prepare file sets for bps callback + Q_D(QEventDispatcherBlackberry); + d->ioData->count = 0; + d->ioData->readfds = readfds; + d->ioData->writefds = writefds; + d->ioData->exceptfds = exceptfds; + + // \TODO Remove this when bps is fixed + // + // Work around a bug in BPS with which if we register the thread_pipe[0] fd with bps in the + // private class' ctor once only then we get spurious notifications that thread_pipe[0] is + // ready for reading. The first time the notification is correct and the pipe is emptied in + // the calling doSelect() function. The 2nd notification is an error and the resulting attempt + // to read and call to wakeUps.testAndSetRelease(1, 0) fails as there has been no intervening + // call to QEventDispatcherUNIX::wakeUp(). + // + // Registering thread_pipe[0] here and unregistering it at the end of this call works around + // this issue. + int io_events = BPS_IO_INPUT; + int result = bps_add_fd(d->thread_pipe[0], io_events, &bpsIOHandler, d->ioData.data()); + if (result != BPS_SUCCESS) + qWarning() << Q_FUNC_INFO << "bps_add_fd() failed"; + + // reset all file sets + if (readfds) + FD_ZERO(readfds); + + if (writefds) + FD_ZERO(writefds); + + if (exceptfds) + FD_ZERO(exceptfds); + + // convert timeout to milliseconds + int timeout_ms = -1; + if (timeout) + timeout_ms = (timeout->tv_sec * 1000) + (timeout->tv_usec / 1000); + + // wait for event or file to be ready + bps_event_t *event = NULL; + result = bps_get_event(&event, timeout_ms); + if (result != BPS_SUCCESS) + qWarning("QEventDispatcherBlackberry::select: bps_get_event() failed"); + + // pass all received events through filter - except IO ready events + if (event && bps_event_get_domain(event) != bpsIOReadyDomain) + filterEvent((void*)event); + + // \TODO Remove this when bps is fixed (see comment above) + result = bps_remove_fd(d->thread_pipe[0]); + if (result != BPS_SUCCESS) + qWarning() << Q_FUNC_INFO << "bps_remove_fd() failed"; + + // the number of bits set in the file sets + return d->ioData->count; +} + +QT_END_NAMESPACE diff --git a/src/corelib/kernel/qeventdispatcher_blackberry_p.h b/src/corelib/kernel/qeventdispatcher_blackberry_p.h new file mode 100644 index 0000000000..b996bc7ee7 --- /dev/null +++ b/src/corelib/kernel/qeventdispatcher_blackberry_p.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Research In Motion +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtCore module 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 QEVENTDISPATCHER_BLACKBERRY_P_H +#define QEVENTDISPATCHER_BLACKBERRY_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "private/qeventdispatcher_unix_p.h" + +QT_BEGIN_NAMESPACE + +class QEventDispatcherBlackberryPrivate; + +class Q_CORE_EXPORT QEventDispatcherBlackberry : public QEventDispatcherUNIX +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QEventDispatcherBlackberry) + +public: + explicit QEventDispatcherBlackberry(QObject *parent = 0); + ~QEventDispatcherBlackberry(); + + void registerSocketNotifier(QSocketNotifier *notifier); + void unregisterSocketNotifier(QSocketNotifier *notifier); + +protected: + QEventDispatcherBlackberry(QEventDispatcherBlackberryPrivate &dd, QObject *parent = 0); + + int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, + timeval *timeout); +}; + +struct bpsIOHandlerData; + +class Q_CORE_EXPORT QEventDispatcherBlackberryPrivate : public QEventDispatcherUNIXPrivate +{ + Q_DECLARE_PUBLIC(QEventDispatcherBlackberry) + +public: + QEventDispatcherBlackberryPrivate(); + ~QEventDispatcherBlackberryPrivate(); + + QScopedPointer ioData; +}; + +QT_END_NAMESPACE + +#endif // QEVENTDISPATCHER_BLACKBERRY_P_H diff --git a/src/corelib/thread/qthread_unix.cpp b/src/corelib/thread/qthread_unix.cpp index 3af54c7fc7..a47115cfac 100644 --- a/src/corelib/thread/qthread_unix.cpp +++ b/src/corelib/thread/qthread_unix.cpp @@ -44,11 +44,15 @@ #include "qplatformdefs.h" #include -#if !defined(QT_NO_GLIB) -# include "../kernel/qeventdispatcher_glib_p.h" -#endif -#include +#if defined(Q_OS_BLACKBERRY) +# include +#else +# if !defined(QT_NO_GLIB) +# include "../kernel/qeventdispatcher_glib_p.h" +# endif +# include +#endif #include "qthreadstorage.h" @@ -248,6 +252,9 @@ typedef void*(*QtThreadCallback)(void*); void QThreadPrivate::createEventDispatcher(QThreadData *data) { +#if defined(Q_OS_BLACKBERRY) + data->eventDispatcher = new QEventDispatcherBlackberry; +#else #if !defined(QT_NO_GLIB) if (qgetenv("QT_NO_GLIB").isEmpty() && qgetenv("QT_NO_THREADED_GLIB").isEmpty() @@ -256,6 +263,8 @@ void QThreadPrivate::createEventDispatcher(QThreadData *data) else #endif data->eventDispatcher = new QEventDispatcherUNIX; +#endif + data->eventDispatcher->startingUp(); } -- cgit v1.2.3