fix(keyboard-state): make device removal idempotent to stop libinput abort
On device unplug the inotify IN_DELETE handler removed the libinput device and unref'd it before erasing the entry from libinput_devices_. A repeated IN_DELETE event for the same path (observed as the "has been removed" log line printed twice) could reach an already-unlinked device and trigger a libinput list_remove assertion abort. Erase the map entry first (under devices_mutex_) so a second delete for the same path is a no-op, then call libinput_path_remove_device() and libinput_device_unref() exactly once per device pointer. Fixes #5143, #4443, #4566.
This commit is contained in:
@@ -268,10 +268,16 @@ waybar::modules::KeyboardState::KeyboardState(const std::string& id, const Bar&
|
|||||||
std::lock_guard<std::mutex> lock(devices_mutex_);
|
std::lock_guard<std::mutex> lock(devices_mutex_);
|
||||||
auto it = libinput_devices_.find(dev_path);
|
auto it = libinput_devices_.find(dev_path);
|
||||||
if (it != libinput_devices_.end()) {
|
if (it != libinput_devices_.end()) {
|
||||||
spdlog::info("Keyboard {} has been removed.", dev_path);
|
struct libinput_device* device = it->second;
|
||||||
libinput_path_remove_device(it->second);
|
// Erase from the map first so that a second IN_DELETE event for the
|
||||||
libinput_device_unref(it->second);
|
// same path becomes a no-op. This keeps removal idempotent and
|
||||||
|
// ensures libinput_path_remove_device()/libinput_device_unref() are
|
||||||
|
// called exactly once per device, avoiding a libinput list_remove
|
||||||
|
// assertion abort on double removal.
|
||||||
libinput_devices_.erase(it);
|
libinput_devices_.erase(it);
|
||||||
|
spdlog::info("Keyboard {} has been removed.", dev_path);
|
||||||
|
libinput_path_remove_device(device);
|
||||||
|
libinput_device_unref(device);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
i += sizeof(struct inotify_event) + event->len;
|
i += sizeof(struct inotify_event) + event->len;
|
||||||
|
|||||||
Reference in New Issue
Block a user