From f6bd3c27201274641eab95197f565127e6e079ff Mon Sep 17 00:00:00 2001 From: Mihail Konev Date: Fri, 23 Sep 2016 15:04:26 +0000 Subject: [PATCH xserver] input: fix VT switching disabling input devices Make sure device removes are processed before doing a VT switch, so that no removes are "overwritten" with attachments afterwards (before the main thread releases the input lock, letting them be processed), which would leave affected devices disabled. Pass a timeout to input poll instead of telling it to wait forever, so that no deadlock before VT switch is possible if main thread waits for release processing only by the time input thread is already done and does another poll. Now X server could have annoying stalls on VT switches (depending on poll timeout), but they at least work. Bugzilla: #97880 Signed-off-by: Mihail Konev --- hw/xfree86/common/xf86Events.c | 1 + include/input.h | 2 ++ os/inputthread.c | 26 +++++++++++++++++++++++++- 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/hw/xfree86/common/xf86Events.c b/hw/xfree86/common/xf86Events.c index 9a8f432a0556..92b1ec5c00cb 100644 --- a/hw/xfree86/common/xf86Events.c +++ b/hw/xfree86/common/xf86Events.c @@ -438,6 +438,7 @@ xf86VTLeave(void) } for (pInfo = xf86InputDevs; pInfo; pInfo = pInfo->next) xf86DisableInputDeviceForVTSwitch(pInfo); + input_wait_for_processing_all_removes(); input_lock(); for (i = 0; i < xf86NumScreens; i++) diff --git a/include/input.h b/include/input.h index e0f6b9b01d97..3635b8ab4e97 100644 --- a/include/input.h +++ b/include/input.h @@ -719,6 +719,8 @@ extern _X_EXPORT void input_lock(void); extern _X_EXPORT void input_unlock(void); extern _X_EXPORT void input_force_unlock(void); +extern _X_EXPORT void input_wait_for_processing_all_removes(void); + extern void InputThreadPreInit(void); extern void InputThreadInit(void); extern void InputThreadFini(void); diff --git a/os/inputthread.c b/os/inputthread.c index 6aa0a9ce6fb5..da9be6ce408a 100644 --- a/os/inputthread.c +++ b/os/inputthread.c @@ -39,6 +39,8 @@ #include "opaque.h" #include "osdep.h" +#define INPUT_THREAD_POLL_TIMEOUT_MS 200 + #if INPUTTHREAD Bool InputThreadEnable = TRUE; @@ -90,6 +92,17 @@ static pthread_mutex_t input_mutex; static Bool input_mutex_initialized; #endif +static Bool waiting_for_processing_all_removes = FALSE; +static int unprocessed_removes_count = 0; +static pthread_barrier_t all_removes_processed_barrier; + +void +input_wait_for_processing_all_removes(void) +{ + waiting_for_processing_all_removes = TRUE; + pthread_barrier_wait(&all_removes_processed_barrier); +} + void input_lock(void) { @@ -267,6 +280,7 @@ InputThreadUnregisterDev(int fd) dev->state = device_state_removed; inputThreadInfo->changed = TRUE; + unprocessed_removes_count++; input_unlock(); @@ -348,13 +362,19 @@ InputThreadDoWork(void *arg) ospoll_remove(inputThreadInfo->fds, dev->fd); xorg_list_del(&dev->node); free(dev); + unprocessed_removes_count--; break; } } input_unlock(); } - if (ospoll_wait(inputThreadInfo->fds, -1) < 0) { + if (waiting_for_processing_all_removes && !unprocessed_removes_count) { + waiting_for_processing_all_removes = FALSE; + pthread_barrier_wait(&all_removes_processed_barrier); + } + + if (ospoll_wait(inputThreadInfo->fds, INPUT_THREAD_POLL_TIMEOUT_MS) < 0) { if (errno == EINVAL) FatalError("input-thread: %s (%s)", __func__, strerror(errno)); else if (errno != EINTR) @@ -400,6 +420,8 @@ InputThreadPreInit(void) if (!inputThreadInfo) FatalError("input-thread: could not allocate memory"); + pthread_barrier_init(&all_removes_processed_barrier, NULL, 2); + inputThreadInfo->thread = 0; xorg_list_init(&inputThreadInfo->devs); inputThreadInfo->fds = ospoll_create(); @@ -517,6 +539,8 @@ int xthread_sigmask(int how, const sigset_t *set, sigset_t *oldset) Bool InputThreadEnable = FALSE; +void input_wait_for_processing_all_removes(void) {}; + void input_lock(void) {} void input_unlock(void) {} void input_force_unlock(void) {} -- 2.9.2