Files
spice2x.github.io/src/spice2x/rawinput/rawinput_handles.cpp
T
bicarus c080bbe301 rawinput: avoid deadlock when binding analog axis as a button (#809)
## Link to GitHub Issue or related Pull Request, if one exists
Regressed by #793

## Description of change
Due to lock inversion, when binding an analog axis as a button, spice
deadlocks. Fix that.

Also create a separate `unordered_map` that keeps track of device
handles so that `WM_INPUT` handle can look up devices without having to
acquire the larger `devices_mutex` which could be held by (potentially)
lengthy operations like hotplug.

Fix more synchronization issues around hotplug. Latent bug exposed by
MIDI 2.0 issues.

## Testing
2026-07-18 03:09:27 -07:00

32 lines
1.1 KiB
C++

#include "rawinput_handles.h"
void rawinput::RawInputHandles::add(Device *device) {
std::lock_guard<std::mutex> lock(this->mutex);
this->devices[device->handle] = device;
}
void rawinput::RawInputHandles::remove(Device *device) {
std::lock_guard<std::mutex> lock(this->mutex);
// teardown is shared by every device type, and handles can be reused; only erase
// an entry that still belongs to this exact RawInput device
auto it = this->devices.find(device->handle);
if (it != this->devices.end() && it->second == device) {
this->devices.erase(it);
}
}
rawinput::RawInputHandles::AcquiredDevice rawinput::RawInputHandles::acquire(HANDLE handle) {
std::lock_guard<std::mutex> index_lock(this->mutex);
auto it = this->devices.find(handle);
if (it == this->devices.end()) {
return {};
}
auto *device = it->second;
// take the device mutex while index_lock is still held so teardown can't free it
// between the lookup and the lock
return {device, std::unique_lock<std::mutex>(*device->mutex)};
}