From 1c5c34385ac10f42283197eaa798a502f6c34f1f Mon Sep 17 00:00:00 2001 From: Ivan Solovev Date: Tue, 20 Dec 2022 15:03:36 +0100 Subject: QWinRTLowEnergyServiceHandler: optimize behavior at disconnect The QWinRTLowEnergyServiceHandler helper class is used to query low energy service details. It works in a background thread and performs multiple async operations to get the results. As the class works in a background thread, we use QWinRTFunctions::await() to wait for the results of async operations. This allows to simplify the code. In practice the user might want to disconnect from the device while service details discovery is performed. Previously the background thread was still performing all the requests. This patch handles the already-existing QLowEnergyControllerPrivateWinRT::abortConnection() signal and provides the exit condition to all QWinRTFunctions::await() calls, so that the background thread does not do unnecessary work. Task-number: QTBUG-108461 Change-Id: I1db05c906beb0078de8a00fd5e32d589306f6665 Reviewed-by: Juha Vuolle (cherry picked from commit c68e5d0952036204b8d20b26f0de362b36c03511) Reviewed-by: Qt Cherry-pick Bot --- src/bluetooth/qlowenergycontroller_winrt.cpp | 37 ++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/src/bluetooth/qlowenergycontroller_winrt.cpp b/src/bluetooth/qlowenergycontroller_winrt.cpp index 3cebc697..8c61b4ee 100644 --- a/src/bluetooth/qlowenergycontroller_winrt.cpp +++ b/src/bluetooth/qlowenergycontroller_winrt.cpp @@ -131,6 +131,8 @@ public: public slots: void obtainCharList() { + auto exitCondition = [this]() { return mAbortRequested; }; + mIndicateChars.clear(); qCDebug(QT_BT_WINDOWS) << __FUNCTION__; ComPtr> characteristicsOp; @@ -138,7 +140,8 @@ public slots: HRESULT hr = mDeviceService->GetCharacteristicsAsync(&characteristicsOp); EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED(hr); hr = QWinRTFunctions::await(characteristicsOp, characteristicsResult.GetAddressOf(), - QWinRTFunctions::ProcessMainThreadEvents, 5000); + QWinRTFunctions::ProcessMainThreadEvents, 5000, + exitCondition); EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED(hr); GattCommunicationStatus status; hr = characteristicsResult->get_Status(&status); @@ -156,7 +159,7 @@ public slots: EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED(hr); mCharacteristicsCountToBeDiscovered = characteristicsCount; - for (uint i = 0; i < characteristicsCount; ++i) { + for (uint i = 0; !mAbortRequested && (i < characteristicsCount); ++i) { ComPtr characteristic; hr = characteristics->GetAt(i, &characteristic); if (FAILED(hr)) { @@ -182,7 +185,9 @@ public slots: DEC_CHAR_COUNT_AND_CONTINUE_IF_FAILED(hr, "Could not obtain list of descriptors") ComPtr descResult; - hr = QWinRTFunctions::await(descAsyncOp, descResult.GetAddressOf()); + hr = QWinRTFunctions::await(descAsyncOp, descResult.GetAddressOf(), + QWinRTFunctions::ProcessMainThreadEvents, 5000, + exitCondition); DEC_CHAR_COUNT_AND_CONTINUE_IF_FAILED(hr, "Could not obtain descriptor read result") quint16 handle; @@ -211,7 +216,9 @@ public slots: &readOp); DEC_CHAR_COUNT_AND_CONTINUE_IF_FAILED(hr, "Could not read characteristic") ComPtr readResult; - hr = QWinRTFunctions::await(readOp, readResult.GetAddressOf()); + hr = QWinRTFunctions::await(readOp, readResult.GetAddressOf(), + QWinRTFunctions::ProcessMainThreadEvents, 5000, + exitCondition); DEC_CHAR_COUNT_AND_CONTINUE_IF_FAILED(hr, "Could not obtain characteristic read result") if (!readResult) @@ -237,7 +244,7 @@ public slots: uint descriptorCount; hr = descriptors->get_Size(&descriptorCount); DEC_CHAR_COUNT_AND_CONTINUE_IF_FAILED(hr, "Could not obtain list of descriptors' size") - for (uint j = 0; j < descriptorCount; ++j) { + for (uint j = 0; !mAbortRequested && (j < descriptorCount); ++j) { QLowEnergyServicePrivate::DescData descData; ComPtr descriptor; hr = descriptors->GetAt(j, &descriptor); @@ -257,7 +264,9 @@ public slots: &readOp); WARN_AND_CONTINUE_IF_FAILED(hr, "Could not read descriptor value") ComPtr readResult; - hr = QWinRTFunctions::await(readOp, readResult.GetAddressOf()); + hr = QWinRTFunctions::await(readOp, readResult.GetAddressOf(), + QWinRTFunctions::ProcessMainThreadEvents, 5000, + exitCondition); WARN_AND_CONTINUE_IF_FAILED(hr, "Could not await descriptor read result") GattClientCharacteristicConfigurationDescriptorValue value; hr = readResult->get_ClientCharacteristicConfigurationDescriptor(&value); @@ -289,8 +298,10 @@ public slots: &readOp); WARN_AND_CONTINUE_IF_FAILED(hr, "Could not read descriptor value") ComPtr readResult; - hr = QWinRTFunctions::await(readOp, readResult.GetAddressOf()); - WARN_AND_CONTINUE_IF_FAILED(hr, "Could await descriptor read result") + hr = QWinRTFunctions::await(readOp, readResult.GetAddressOf(), + QWinRTFunctions::ProcessMainThreadEvents, 5000, + exitCondition); + WARN_AND_CONTINUE_IF_FAILED(hr, "Could not await descriptor read result") if (descData.uuid == QBluetoothUuid::DescriptorType::CharacteristicUserDescription) descData.value = byteArrayFromGattResult(readResult, true); else @@ -306,6 +317,11 @@ public slots: checkAllCharacteristicsDiscovered(); } + void setAbortRequested() + { + mAbortRequested = true; + } + private: bool checkAllCharacteristicsDiscovered(); void emitErrorAndQuitThread(HRESULT hr); @@ -320,6 +336,7 @@ public: quint16 mStartHandle = 0; quint16 mEndHandle = 0; QList mIndicateChars; + bool mAbortRequested = false; signals: void charListObtained(const QBluetoothUuid &service, @@ -336,6 +353,8 @@ bool QWinRTLowEnergyServiceHandler::checkAllCharacteristicsDiscovered() mStartHandle, mEndHandle); QThread::currentThread()->quit(); return true; + } else if (mAbortRequested) { + QThread::currentThread()->quit(); } return false; @@ -1281,6 +1300,8 @@ void QLowEnergyControllerPrivateWinRT::discoverServiceDetailsHelper( connect(thread, &QThread::started, worker, &QWinRTLowEnergyServiceHandler::obtainCharList); connect(thread, &QThread::finished, worker, &QObject::deleteLater); connect(worker, &QObject::destroyed, thread, &QObject::deleteLater); + connect(this, &QLowEnergyControllerPrivateWinRT::abortConnection, + worker, &QWinRTLowEnergyServiceHandler::setAbortRequested); connect(worker, &QWinRTLowEnergyServiceHandler::errorOccured, this, &QLowEnergyControllerPrivateWinRT::handleServiceHandlerError); connect(worker, &QWinRTLowEnergyServiceHandler::charListObtained, this, -- cgit v1.2.1