diff --git a/src/ble/ctrlm_ble_rcu_interface.cpp b/src/ble/ctrlm_ble_rcu_interface.cpp index 36c9dbaf..f5e2dd3c 100644 --- a/src/ble/ctrlm_ble_rcu_interface.cpp +++ b/src/ble/ctrlm_ble_rcu_interface.cpp @@ -120,6 +120,14 @@ void ctrlm_ble_rcu_interface_t::shutdown() m_controller->shutdown(); } + // Tell ctrlm_ble_key_m to drop every managed device before destructing the controller/adapter. + // Without this, the key monitor thread is left polling an fd that bluez destroys. + if (m_controller) { + for (const BleAddress &address : m_controller->managedDevices()) { + removeDeviceKeyMonitorThread(address); + } + } + // delete the adapter and controller when going into deepsleep so that we don't // get notified of the remote disconnection that occurs when going to sleep. // Upon waking, these will be re-initialized. @@ -173,10 +181,7 @@ void ctrlm_ble_rcu_interface_t::initialize() { XLOGD_DEBUG("deviceRemovedSlot %s", address.toString().c_str()); - ctrlm_ble_key_queue_device_changed_msg_t msg; - msg.header.type = CTRLM_BLE_KEY_QUEUE_MSG_TYPE_DEVICE_REMOVED; - msg.address = address; - ctrlm_utils_queue_msg_push(m_keyThreadMsgQ, (const char *)&msg, sizeof(msg)); + removeDeviceKeyMonitorThread(address); ctrlm_hal_ble_IndUnPaired_params_t params; params.ieee_address = address.toUInt64(); @@ -283,9 +288,11 @@ bool ctrlm_ble_rcu_interface_t::handleAddedDevice(const BleAddress &address) { XLOGD_INFO("BLE RCU %s connected changed to <%s>", address.toString().c_str(), connected ? "TRUE" : "FALSE"); - if (connected) { - if (m_keyMonitorThread.running) { + if (m_keyMonitorThread.running) { + if (connected) { addNewDeviceKeyMonitorThread(address); + } else { + removeDeviceKeyMonitorThread(address); } } @@ -1448,6 +1455,13 @@ void ctrlm_ble_rcu_interface_t::addNewDeviceKeyMonitorThread(BleAddress address) msg.address = address; ctrlm_utils_queue_msg_push(m_keyThreadMsgQ, (const char *)&msg, sizeof(msg)); } + +void ctrlm_ble_rcu_interface_t::removeDeviceKeyMonitorThread(BleAddress address){ + ctrlm_ble_key_queue_device_changed_msg_t msg; + msg.header.type = CTRLM_BLE_KEY_QUEUE_MSG_TYPE_DEVICE_REMOVED; + msg.address = address; + ctrlm_utils_queue_msg_push(m_keyThreadMsgQ, (const char *)&msg, sizeof(msg)); +} //////////////////////////////////////////////////////////////////////////////////////////////////////////////// // BEGIN - Key Monitor Thread // ------------------------------------------------------------------------------------------------------------- @@ -1681,15 +1695,29 @@ void *KeyMonitorThread(void *data) } // loop the rcu fds to see if any has data to read - for (auto const &rcu : rcuKeypressFds) { + for (auto &rcu : rcuKeypressFds) { if (rcu.second >= 0) { if (FD_ISSET(rcu.second, &rfds)) { safec_rc = memset_s ((void*) &event, sizeof(event), 0, sizeof(event)); ERR_CHK(safec_rc); ret = read(rcu.second, (void*)&event, sizeof(event)); - if (ret < 0) { - // int errsv = errno; - // XLOGD_ERROR("Error reading event: error = <%d>, <%s>", errsv, strerror(errsv)); + if (ret == 0) { + // EOF - the underlying input device node is gone. + XLOGD_WARN("Input device for RCU <%s> hit EOF, closing fd <%d>", + rcu.first.toString().c_str(), rcu.second); + close(rcu.second); + rcu.second = -1; + } else if (ret < 0) { + int errsv = errno; + if (errsv == ENODEV || errsv == EBADF || errsv == EINVAL) { + // Device node was destroyed out from under us leaving 100% CPU spin. + // Close fd and FindRcuInputDevices() reopens the device node if it comes back. + XLOGD_WARN("Input device for RCU <%s> gone: error = <%d>, <%s>, closing fd <%d>", + rcu.first.toString().c_str(), errsv, strerror(errsv), rcu.second); + close(rcu.second); + rcu.second = -1; + } + // else: transient error (e.g. EAGAIN) - retry on the next wakeup. } else { HandleKeypress(metadata, &event, rcu.first); } diff --git a/src/ble/ctrlm_ble_rcu_interface.h b/src/ble/ctrlm_ble_rcu_interface.h index e29c7fc8..536e8eed 100644 --- a/src/ble/ctrlm_ble_rcu_interface.h +++ b/src/ble/ctrlm_ble_rcu_interface.h @@ -177,6 +177,7 @@ class ctrlm_ble_rcu_interface_t std::shared_ptr m_controller; void addNewDeviceKeyMonitorThread(BleAddress address); + void removeDeviceKeyMonitorThread(BleAddress address); }; #endif //__CTRLM_BLE_RCU_INTERFACE_H__ \ No newline at end of file diff --git a/src/ctrlm_main.cpp b/src/ctrlm_main.cpp index cfe02be9..8bfc1ab9 100644 --- a/src/ctrlm_main.cpp +++ b/src/ctrlm_main.cpp @@ -986,14 +986,13 @@ gboolean ctrlm_thread_monitor(gpointer user_data) { } #endif - if(ctrlm_was_cpu_halted()) { + if(ctrlm_was_cpu_halted() && !g_ctrlm.thread_monitor_active) { XLOGD_INFO("skipping response check due to power state <%s>",ctrlm_power_state_str(g_ctrlm.power_state)); - g_ctrlm.thread_monitor_active = false; // Deactivate thread monitoring } else if(!g_ctrlm.thread_monitor_active) { XLOGD_INFO("activate due to power state <%s>",ctrlm_power_state_str(g_ctrlm.power_state)); g_ctrlm.thread_monitor_active = true; // Activate thread monitoring again } else { - // Check the response from each thread on the previous attempt + // Check the response from each thread on the previous attempt, including final iteration before DEEP_SLEEP. for(vector::iterator it = g_ctrlm.monitor_threads.begin(); it != g_ctrlm.monitor_threads.end(); it++) { XLOGD_DEBUG("Checking %s", it->name); @@ -1024,6 +1023,12 @@ gboolean ctrlm_thread_monitor(gpointer user_data) { return (FALSE); } } + + if(ctrlm_was_cpu_halted()) { + // The DEEP_SLEEP transition has now been checked, go quiet until we wake. + XLOGD_INFO("power state <%s>: transition checked, deactivating thread monitor",ctrlm_power_state_str(g_ctrlm.power_state)); + g_ctrlm.thread_monitor_active = false; // Deactivate thread monitoring + } } if(g_ctrlm.thread_monitor_active) { // Thread monitoring is active