aboutsummaryrefslogtreecommitdiffstats
path: root/src/direct_bt/BTGattHandler.cpp
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2022-04-18 01:11:43 +0200
committerSven Gothel <[email protected]>2022-04-18 01:11:43 +0200
commit272904f82a15fbaa29b63b8771f3fbc6ee46bb81 (patch)
tree27aa3ca285cc479a44e1e4196bb450c449cbc99b /src/direct_bt/BTGattHandler.cpp
parent6a485caa282123fe927f0c8cb2a34c6845098a2f (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.cpp21
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",