From 3a90cf6d46dc6f34ccedb7f02515573d1db4704a Mon Sep 17 00:00:00 2001 From: "Lubomir I. Ivanov (VMware)" Date: Wed, 30 May 2018 00:49:58 +0200 Subject: win32: remove usage of QFuture in qbluetoothservicediscoveryagent Introduce usage of QThread for service discovery instead of QFuture. Details: - Make _q_nextSdpScan() accept arguments. - Make QBluetoothServiceDiscoveryAgentPrivate inherit QObject for QT_WIN_BLUETOOTH. - Remove usage of the member variables 'systemError', 'hSearch'. Pass values around, instead. - Add the helper structs 'FindServiceArguments' and 'FindServiceResult'. Change-Id: I4e2178b2a7b333c30a235a02807dd64526db4685 Reviewed-by: Oliver Wolff Reviewed-by: Alex Blasche --- src/bluetooth/qbluetoothservicediscoveryagent.h | 3 +- src/bluetooth/qbluetoothservicediscoveryagent_p.h | 27 ++-- .../qbluetoothservicediscoveryagent_win.cpp | 137 +++++++++++++-------- 3 files changed, 111 insertions(+), 56 deletions(-) diff --git a/src/bluetooth/qbluetoothservicediscoveryagent.h b/src/bluetooth/qbluetoothservicediscoveryagent.h index 4b1a72c1..6a3f8f03 100644 --- a/src/bluetooth/qbluetoothservicediscoveryagent.h +++ b/src/bluetooth/qbluetoothservicediscoveryagent.h @@ -43,6 +43,7 @@ #include #include +#include #include #include @@ -130,7 +131,7 @@ private: Q_PRIVATE_SLOT(d_func(), void _q_hostModeStateChanged(QBluetoothLocalDevice::HostMode state)) #endif #ifdef QT_WIN_BLUETOOTH - Q_PRIVATE_SLOT(d_func(), void _q_nextSdpScan()) + Q_PRIVATE_SLOT(d_func(), void _q_nextSdpScan(QVariant input)) #endif }; diff --git a/src/bluetooth/qbluetoothservicediscoveryagent_p.h b/src/bluetooth/qbluetoothservicediscoveryagent_p.h index 3805ea44..cbaab458 100644 --- a/src/bluetooth/qbluetoothservicediscoveryagent_p.h +++ b/src/bluetooth/qbluetoothservicediscoveryagent_p.h @@ -73,7 +73,22 @@ QT_END_NAMESPACE #endif #ifdef QT_WIN_BLUETOOTH -#include +#include + +QT_BEGIN_NAMESPACE +class QThread; + +class ThreadWorkerFind : public QObject +{ + Q_OBJECT +public: + Q_INVOKABLE void findFirst(const QVariant data); + Q_INVOKABLE void findNext(const QVariant data); +signals: + void findFinished(QVariant result); +}; +QT_END_NAMESPACE + #elif defined(QT_WINRT_BLUETOOTH) #include #endif @@ -93,7 +108,7 @@ class QWinRTBluetoothServiceDiscoveryWorker; #endif class QBluetoothServiceDiscoveryAgentPrivate -#if defined QT_WINRT_BLUETOOTH +#if defined QT_WINRT_BLUETOOTH || defined QT_WIN_BLUETOOTH : public QObject { Q_OBJECT @@ -152,7 +167,7 @@ public: void _q_hostModeStateChanged(QBluetoothLocalDevice::HostMode state); #endif #ifdef QT_WIN_BLUETOOTH - void _q_nextSdpScan(); + void _q_nextSdpScan(QVariant input); #endif private: @@ -207,13 +222,11 @@ private: #ifdef QT_WIN_BLUETOOTH private: - int systemError; bool pendingStop; bool pendingFinish; - QFutureWatcher *searchWatcher; - - Qt::HANDLE hSearch; + QThread *threadFind = nullptr; + ThreadWorkerFind *threadWorkerFind = nullptr; #endif #ifdef QT_WINRT_BLUETOOTH diff --git a/src/bluetooth/qbluetoothservicediscoveryagent_win.cpp b/src/bluetooth/qbluetoothservicediscoveryagent_win.cpp index cae7968b..8ee0f663 100644 --- a/src/bluetooth/qbluetoothservicediscoveryagent_win.cpp +++ b/src/bluetooth/qbluetoothservicediscoveryagent_win.cpp @@ -41,7 +41,10 @@ #include "qbluetoothservicediscoveryagent_p.h" #include -#include +#include +#include +#include +#include #include #include @@ -64,6 +67,18 @@ DEFINEFUNC(DWORD, BluetoothSdpGetElementData, LPBYTE, ULONG, PSDP_ELEMENT_DATA) QT_BEGIN_NAMESPACE +struct FindServiceArguments { + QBluetoothAddress address; + Qt::HANDLE hSearch; + int systemError; +}; + +struct FindServiceResult { + QBluetoothServiceInfo info; + Qt::HANDLE hSearch; + int systemError; +}; + Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINDOWS) static inline QFunctionPointer resolveFunction(QLibrary *library, const char *func) @@ -276,9 +291,11 @@ enum { | LUP_RETURN_COMMENT }; -static QBluetoothServiceInfo findNextService(HANDLE hSearch, int *systemError) +static FindServiceResult findNextService(HANDLE hSearch, int systemError) { - QBluetoothServiceInfo result; + FindServiceResult result; + result.systemError = systemError; + result.hSearch = INVALID_HANDLE_VALUE; QByteArray resultBuffer(2048, 0); WSAQUERYSET *resultQuery = reinterpret_cast(resultBuffer.data()); @@ -289,34 +306,36 @@ static QBluetoothServiceInfo findNextService(HANDLE hSearch, int *systemError) resultQuery); if (resultCode == SOCKET_ERROR) { - *systemError = ::WSAGetLastError(); - if (*systemError == WSA_E_NO_MORE) + result.systemError = ::WSAGetLastError(); + if (result.systemError == WSA_E_NO_MORE) cleanupServiceDiscovery(hSearch); - return QBluetoothServiceInfo(); + return result; } if (resultQuery->lpBlob && BluetoothSdpEnumAttributes(resultQuery->lpBlob->pBlobData, resultQuery->lpBlob->cbSize, bluetoothSdpCallback, - &result)) { + &result.info)) { return result; } else { - *systemError = GetLastError(); + result.systemError = GetLastError(); } - return result; } -static QBluetoothServiceInfo findFirstService(LPHANDLE hSearch, const QBluetoothAddress &address, int *systemError) +static FindServiceResult findFirstService(HANDLE hSearch, const QBluetoothAddress &address) { //### should we try for 2.2 on all platforms ?? WSAData wsadata; + FindServiceResult result; + result.systemError = NO_ERROR; + result.hSearch = INVALID_HANDLE_VALUE; // IPv6 requires Winsock v2.0 or better. if (WSAStartup(MAKEWORD(2, 0), &wsadata) != 0) { - *systemError = ::WSAGetLastError(); - return QBluetoothServiceInfo(); + result.systemError = ::WSAGetLastError(); + return result; } const QString addressAsString = QStringLiteral("(%1)").arg(address.toString()); @@ -336,14 +355,14 @@ static QBluetoothServiceInfo findFirstService(LPHANDLE hSearch, const QBluetooth const int resultCode = WSALookupServiceBegin(&serviceQuery, WSAControlFlags, - hSearch); + &hSearch); if (resultCode == SOCKET_ERROR) { - *systemError = ::WSAGetLastError(); - cleanupServiceDiscovery(hSearch); - return QBluetoothServiceInfo(); + result.systemError = ::WSAGetLastError(); + cleanupServiceDiscovery(&hSearch); + return result; } - *systemError = NO_ERROR; - return findNextService(*hSearch, systemError); + result.systemError = NO_ERROR; + return findNextService(hSearch, result.systemError); } QBluetoothServiceDiscoveryAgentPrivate::QBluetoothServiceDiscoveryAgentPrivate( @@ -353,41 +372,43 @@ QBluetoothServiceDiscoveryAgentPrivate::QBluetoothServiceDiscoveryAgentPrivate( deviceDiscoveryAgent(0), mode(QBluetoothServiceDiscoveryAgent::MinimalDiscovery), singleDevice(false), - systemError(NO_ERROR), pendingStop(false), pendingFinish(false), - searchWatcher(Q_NULLPTR), - hSearch(INVALID_HANDLE_VALUE), q_ptr(qp) { Q_UNUSED(deviceAdapter); + resolveFunctions(bluetoothapis()); - searchWatcher = new QFutureWatcher(); + + threadFind = new QThread; + threadWorkerFind = new ThreadWorkerFind; + threadWorkerFind->moveToThread(threadFind); + connect(threadWorkerFind, &ThreadWorkerFind::findFinished, this, &QBluetoothServiceDiscoveryAgentPrivate::_q_nextSdpScan); + connect(threadFind, &QThread::finished, threadWorkerFind, &ThreadWorkerFind::deleteLater); + connect(threadFind, &QThread::finished, threadFind, &QThread::deleteLater); + threadFind->start(); } QBluetoothServiceDiscoveryAgentPrivate::~QBluetoothServiceDiscoveryAgentPrivate() { if (pendingFinish) { stop(); - searchWatcher->waitForFinished(); } - delete searchWatcher; + if (threadFind) + threadFind->quit(); } void QBluetoothServiceDiscoveryAgentPrivate::start(const QBluetoothAddress &address) { - Q_Q(QBluetoothServiceDiscoveryAgent); if (!pendingFinish) { pendingFinish = true; pendingStop = false; - QObject::connect(searchWatcher, SIGNAL(finished()), q, SLOT(_q_nextSdpScan()), Qt::UniqueConnection); - const QFuture future = - QtConcurrent::run(&findFirstService, - &hSearch, - address, - &systemError); - searchWatcher->setFuture(future); + FindServiceArguments data; + data.address = address; + data.hSearch = INVALID_HANDLE_VALUE; + QMetaObject::invokeMethod(threadWorkerFind, "findFirst", Qt::QueuedConnection, + Q_ARG(QVariant, QVariant::fromValue(data))); } } @@ -396,42 +417,62 @@ void QBluetoothServiceDiscoveryAgentPrivate::stop() pendingStop = true; } -void QBluetoothServiceDiscoveryAgentPrivate::_q_nextSdpScan() +void QBluetoothServiceDiscoveryAgentPrivate::_q_nextSdpScan(QVariant input) { Q_Q(QBluetoothServiceDiscoveryAgent); + auto result = input.value(); if (pendingStop) { pendingStop = false; pendingFinish = false; emit q->canceled(); } else { - if (systemError == WSA_E_NO_MORE) { - systemError = NO_ERROR; - } else if (systemError != NO_ERROR) { - error = (systemError == ERROR_INVALID_HANDLE) ? + if (result.systemError == WSA_E_NO_MORE) { + result.systemError = NO_ERROR; + } else if (result.systemError != NO_ERROR) { + error = (result.systemError == ERROR_INVALID_HANDLE) ? QBluetoothServiceDiscoveryAgent::InvalidBluetoothAdapterError : QBluetoothServiceDiscoveryAgent::InputOutputError; - errorString = qt_error_string(systemError); + errorString = qt_error_string(result.systemError); qCWarning(QT_BT_WINDOWS) << errorString; emit q->error(this->error); } else { - QBluetoothServiceInfo serviceInfo = searchWatcher->result(); - serviceInfo.setDevice(discoveredDevices.at(0)); - if (serviceInfo.isValid()) { - if (!isDuplicatedService(serviceInfo)) { - discoveredServices.append(serviceInfo); - emit q->serviceDiscovered(serviceInfo); + result.info.setDevice(discoveredDevices.at(0)); + if (result.info.isValid()) { + if (!isDuplicatedService(result.info)) { + discoveredServices.append(result.info); + emit q->serviceDiscovered(result.info); } } - const QFuture future = - QtConcurrent::run(&findNextService, hSearch, &systemError); - searchWatcher->setFuture(future); + FindServiceArguments data; + data.hSearch = result.hSearch; + data.systemError = result.systemError; + QMetaObject::invokeMethod(threadWorkerFind, "findNext", Qt::QueuedConnection, + Q_ARG(QVariant, QVariant::fromValue(data))); return; } - hSearch = INVALID_HANDLE_VALUE; pendingFinish = false; _q_serviceDiscoveryFinished(); } } +void ThreadWorkerFind::findFirst(const QVariant data) +{ + auto args = data.value(); + FindServiceResult result = findFirstService(args.hSearch, args.address); + result.hSearch = args.hSearch; + emit findFinished(QVariant::fromValue(result)); +} + + void ThreadWorkerFind::findNext(const QVariant data) +{ + auto args = data.value(); + FindServiceResult result = findNextService(args.hSearch, args.systemError); + result.hSearch = args.hSearch; + emit findFinished(QVariant::fromValue(result)); +} + QT_END_NAMESPACE + +Q_DECLARE_METATYPE(FindServiceArguments) +Q_DECLARE_METATYPE(FindServiceResult) -- cgit v1.2.3