Hold input lock for deviceProc

This ensures that the deviceProc is never called while the input
thread is processing data from the device.

Signed-off-by: Keith Packard <keithp@keithp.com>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
Keith Packard 2016-09-08 11:02:30 -06:00 committed by Peter Hutterer
parent dfc91f0f63
commit 52d6a1e832

View File

@ -399,9 +399,11 @@ EnableDevice(DeviceIntPtr dev, BOOL sendevent)
} }
} }
input_lock();
if ((*prev != dev) || !dev->inited || if ((*prev != dev) || !dev->inited ||
((ret = (*dev->deviceProc) (dev, DEVICE_ON)) != Success)) { ((ret = (*dev->deviceProc) (dev, DEVICE_ON)) != Success)) {
ErrorF("[dix] couldn't enable device %d\n", dev->id); ErrorF("[dix] couldn't enable device %d\n", dev->id);
input_unlock();
return FALSE; return FALSE;
} }
dev->enabled = TRUE; dev->enabled = TRUE;
@ -410,6 +412,7 @@ EnableDevice(DeviceIntPtr dev, BOOL sendevent)
for (prev = &inputInfo.devices; *prev; prev = &(*prev)->next); for (prev = &inputInfo.devices; *prev; prev = &(*prev)->next);
*prev = dev; *prev = dev;
dev->next = NULL; dev->next = NULL;
input_unlock();
enabled = TRUE; enabled = TRUE;
XIChangeDeviceProperty(dev, XIGetKnownProperty(XI_PROP_ENABLED), XIChangeDeviceProperty(dev, XIGetKnownProperty(XI_PROP_ENABLED),
@ -488,20 +491,20 @@ DisableDevice(DeviceIntPtr dev, BOOL sendevent)
if (dev->spriteInfo->paired) if (dev->spriteInfo->paired)
dev->spriteInfo->paired = NULL; dev->spriteInfo->paired = NULL;
input_lock();
(void) (*dev->deviceProc) (dev, DEVICE_OFF); (void) (*dev->deviceProc) (dev, DEVICE_OFF);
dev->enabled = FALSE; dev->enabled = FALSE;
FreeSprite(dev);
/* now that the device is disabled, we can reset the event reader's /* now that the device is disabled, we can reset the event reader's
* last.slave */ * last.slave */
input_lock();
for (other = inputInfo.devices; other; other = other->next) { for (other = inputInfo.devices; other; other = other->next) {
if (other->last.slave == dev) if (other->last.slave == dev)
other->last.slave = NULL; other->last.slave = NULL;
} }
input_unlock(); input_unlock();
FreeSprite(dev);
LeaveWindow(dev); LeaveWindow(dev);
SetFocusOut(dev); SetFocusOut(dev);
@ -569,7 +572,9 @@ ActivateDevice(DeviceIntPtr dev, BOOL sendevent)
if (!dev || !dev->deviceProc) if (!dev || !dev->deviceProc)
return BadImplementation; return BadImplementation;
input_lock();
ret = (*dev->deviceProc) (dev, DEVICE_INIT); ret = (*dev->deviceProc) (dev, DEVICE_INIT);
input_unlock();
dev->inited = (ret == Success); dev->inited = (ret == Success);
if (!dev->inited) if (!dev->inited)
return ret; return ret;
@ -935,6 +940,8 @@ FreeAllDeviceClasses(ClassesPtr classes)
* enable it again and free associated structs. If you want the device to just * enable it again and free associated structs. If you want the device to just
* be disabled, DisableDevice(). * be disabled, DisableDevice().
* Don't call this function directly, use RemoveDevice() instead. * Don't call this function directly, use RemoveDevice() instead.
*
* Called with input lock held.
*/ */
static void static void
CloseDevice(DeviceIntPtr dev) CloseDevice(DeviceIntPtr dev)
@ -1071,6 +1078,11 @@ void
AbortDevices(void) AbortDevices(void)
{ {
DeviceIntPtr dev; DeviceIntPtr dev;
/* Do not call input_lock as we don't know what
* state the input thread might be in, and that could
* cause a dead-lock.
*/
nt_list_for_each_entry(dev, inputInfo.devices, next) { nt_list_for_each_entry(dev, inputInfo.devices, next) {
if (!IsMaster(dev)) if (!IsMaster(dev))
(*dev->deviceProc) (dev, DEVICE_ABORT); (*dev->deviceProc) (dev, DEVICE_ABORT);
@ -1135,6 +1147,8 @@ RemoveDevice(DeviceIntPtr dev, BOOL sendevent)
flags[dev->id] = XIDeviceDisabled; flags[dev->id] = XIDeviceDisabled;
} }
input_lock();
prev = NULL; prev = NULL;
for (tmp = inputInfo.devices; tmp; (prev = tmp), (tmp = next)) { for (tmp = inputInfo.devices; tmp; (prev = tmp), (tmp = next)) {
next = tmp->next; next = tmp->next;
@ -1167,6 +1181,8 @@ RemoveDevice(DeviceIntPtr dev, BOOL sendevent)
} }
} }
input_unlock();
if (ret == Success && initialized) { if (ret == Success && initialized) {
inputInfo.numDevices--; inputInfo.numDevices--;
SendDevicePresenceEvent(deviceid, DeviceRemoved); SendDevicePresenceEvent(deviceid, DeviceRemoved);