diff options
author | Sven Gothel <[email protected]> | 2022-04-18 01:11:43 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2022-04-18 01:11:43 +0200 |
commit | 272904f82a15fbaa29b63b8771f3fbc6ee46bb81 (patch) | |
tree | 27aa3ca285cc479a44e1e4196bb450c449cbc99b /src/direct_bt/BTGattHandler.cpp | |
parent | 6a485caa282123fe927f0c8cb2a34c6845098a2f (diff) |
[L2CAP, HCI]Comm: Hold external interrupted delegate from service_runner for complete interrupted() query; At tear down, first stop service_runner, then close the comm instance; Minor method renaming.
Covering [L2CAP, HCI]Comm and service_runner usage in BTManager, HCIHandler, GattHandler and BTAdapter.
- Hold external interrupted delegate from service_runner for complete interrupted() query
- This ensures service_runner stop will work on blocking comm calls like read and accept
- At tear down, first stop service_runner, then close the comm instance; Minor method renaming.
- Naturally, first stop the background thread using the comm instance (read, accept),
then close the comm instance.
Lack of proper delegation of interrupted was found by analyzing BTAdapter's l2cap_att_srv L2CAPServer socket,
which gets start- and stopped w/o closing in between operations and didn't close the instance at close.
This patch completes the introduction of service_runner, using its interrupted signal (shall_stop) for the comm instances.
Diffstat (limited to 'src/direct_bt/BTGattHandler.cpp')
-rw-r--r-- | src/direct_bt/BTGattHandler.cpp | 21 |
1 files changed, 10 insertions, 11 deletions
diff --git a/src/direct_bt/BTGattHandler.cpp b/src/direct_bt/BTGattHandler.cpp index 1f665b0d..b147eddf 100644 --- a/src/direct_bt/BTGattHandler.cpp +++ b/src/direct_bt/BTGattHandler.cpp @@ -84,7 +84,7 @@ BTDeviceRef BTGattHandler::getDeviceChecked() const { } bool BTGattHandler::validateConnected() noexcept { - const bool l2capIsConnected = l2cap.isOpen(); + const bool l2capIsConnected = l2cap.is_open(); const bool l2capHasIOError = l2cap.hasIOError(); if( has_ioerror || l2capHasIOError ) { @@ -507,7 +507,7 @@ void BTGattHandler::l2capReaderWork(jau::service_runner& sr) noexcept { } else { ERR_PRINT("Unhandled: %s", attPDU->toString().c_str()); } - } else if( 0 > len && ETIMEDOUT != errno && !sr.shall_stop() ) { // expected exits + } else if( 0 > len && ETIMEDOUT != errno && !l2cap.interrupted() ) { // expected exits IRQ_PRINT("GATTHandler::reader: l2cap read error -> Stop; l2cap.read %d (%s); %s", len, L2CAPClient::getRWExitCodeString(len).c_str(), getStateString().c_str()); @@ -547,7 +547,7 @@ BTGattHandler::BTGattHandler(const BTDeviceRef &device, L2CAPClient& l2cap_att, l2cap(l2cap_att), deviceString(device->getAddressAndType().address.toString()), rbuffer(number(Defaults::MAX_ATT_MTU), jau::endian::little), - is_connected(l2cap.isOpen()), has_ioerror(false), + is_connected(l2cap.is_open()), has_ioerror(false), l2cap_reader_service("GATTHandler::reader_"+deviceString, THREAD_SHUTDOWN_TIMEOUT_MS, jau::bindMemberFunc(this, &BTGattHandler::l2capReaderWork), jau::service_runner::Callback() /* init */, @@ -569,6 +569,7 @@ BTGattHandler::BTGattHandler(const BTDeviceRef &device, L2CAPClient& l2cap_att, * We utilize DBTManager's mgmthandler_sigaction SIGALRM handler, * as we only can install one handler. */ + l2cap.set_interupt( jau::bindMemberFunc(&l2cap_reader_service, &jau::service_runner::shall_stop2) ); l2cap_reader_service.start(); if( GATTRole::Client == getRole() ) { @@ -622,16 +623,13 @@ bool BTGattHandler::disconnect(const bool disconnectDevice, const bool ioErrorCa return false; } PERF3_TS_T0(); - // Interrupt GATT's L2CAP::connect(..) and L2CAP::read(..), avoiding prolonged hang - // and pull all underlying l2cap read operations! - // l2cap is owned by BTDevice. - l2cap.close(); // Avoid disconnect re-entry -> potential deadlock bool expConn = true; // C++11, exp as value since C++20 if( !is_connected.compare_exchange_strong(expConn, false) ) { // not connected const bool l2cap_service_stopped = l2cap_reader_service.join(); // [data] race: wait until disconnecting thread has stopped service + l2cap.close(); // owned by BTDevice. DBG_PRINT("GATTHandler::disconnect: Not connected: disconnectDevice %d, ioErrorCause %d: GattHandler[%s], l2cap[%s], stopped %d: %s", disconnectDevice, ioErrorCause, getStateString().c_str(), l2cap.getStateString().c_str(), l2cap_service_stopped, toString().c_str()); @@ -640,6 +638,11 @@ bool BTGattHandler::disconnect(const bool disconnectDevice, const bool ioErrorCa return false; } + PERF3_TS_TD("GATTHandler::disconnect.1"); + const bool l2cap_service_stop_res = l2cap_reader_service.stop(); + l2cap.close(); // owned by BTDevice. + PERF3_TS_TD("GATTHandler::disconnect.X"); + gattServerHandler->close(); // Lock to avoid other threads using instance while disconnecting @@ -649,10 +652,6 @@ bool BTGattHandler::disconnect(const bool disconnectDevice, const bool ioErrorCa btGattCharListenerList.clear(); nativeGattCharListenerList.clear(); - PERF3_TS_TD("GATTHandler::disconnect.1"); - const bool l2cap_service_stop_res = l2cap_reader_service.stop(); - PERF3_TS_TD("GATTHandler::disconnect.X"); - clientMTUExchanged = false; DBG_PRINT("GATTHandler::disconnect: End: stopped %d, disconnectDevice %d, %s", |