Skip to content

Commit 4ba8b8a

Browse files
kennylevinsendtor
authored andcommitted
Input: evdev - per-client waitgroups
All evdev clients share a common waitgroup. On new input events, all clients waiting on this waitgroup are woken up, even those filtering out the events, possibly more than once per event. This leads to duplicated and unwanted wakeups. Split the shared waitgroup into per-client waitgroups for more fine-grained wakeups. Signed-off-by: Kenny Levinsen <kl@kl.wtf> Link: https://lore.kernel.org/r/20200429184126.2155-1-kl@kl.wtf Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
1 parent 470d154 commit 4ba8b8a

1 file changed

Lines changed: 9 additions & 10 deletions

File tree

drivers/input/evdev.c

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
struct evdev {
2929
int open;
3030
struct input_handle handle;
31-
wait_queue_head_t wait;
3231
struct evdev_client __rcu *grab;
3332
struct list_head client_list;
3433
spinlock_t client_lock; /* protects client_list */
@@ -43,6 +42,7 @@ struct evdev_client {
4342
unsigned int tail;
4443
unsigned int packet_head; /* [future] position of the first element of next packet */
4544
spinlock_t buffer_lock; /* protects access to buffer, head and tail */
45+
wait_queue_head_t wait;
4646
struct fasync_struct *fasync;
4747
struct evdev *evdev;
4848
struct list_head node;
@@ -245,7 +245,6 @@ static void evdev_pass_values(struct evdev_client *client,
245245
const struct input_value *vals, unsigned int count,
246246
ktime_t *ev_time)
247247
{
248-
struct evdev *evdev = client->evdev;
249248
const struct input_value *v;
250249
struct input_event event;
251250
struct timespec64 ts;
@@ -282,7 +281,7 @@ static void evdev_pass_values(struct evdev_client *client,
282281
spin_unlock(&client->buffer_lock);
283282

284283
if (wakeup)
285-
wake_up_interruptible_poll(&evdev->wait,
284+
wake_up_interruptible_poll(&client->wait,
286285
EPOLLIN | EPOLLOUT | EPOLLRDNORM | EPOLLWRNORM);
287286
}
288287

@@ -426,11 +425,11 @@ static void evdev_hangup(struct evdev *evdev)
426425
struct evdev_client *client;
427426

428427
spin_lock(&evdev->client_lock);
429-
list_for_each_entry(client, &evdev->client_list, node)
428+
list_for_each_entry(client, &evdev->client_list, node) {
430429
kill_fasync(&client->fasync, SIGIO, POLL_HUP);
430+
wake_up_interruptible_poll(&client->wait, EPOLLHUP | EPOLLERR);
431+
}
431432
spin_unlock(&evdev->client_lock);
432-
433-
wake_up_interruptible_poll(&evdev->wait, EPOLLHUP | EPOLLERR);
434433
}
435434

436435
static int evdev_release(struct inode *inode, struct file *file)
@@ -479,6 +478,7 @@ static int evdev_open(struct inode *inode, struct file *file)
479478
if (!client)
480479
return -ENOMEM;
481480

481+
init_waitqueue_head(&client->wait);
482482
client->bufsize = bufsize;
483483
spin_lock_init(&client->buffer_lock);
484484
client->evdev = evdev;
@@ -595,7 +595,7 @@ static ssize_t evdev_read(struct file *file, char __user *buffer,
595595
break;
596596

597597
if (!(file->f_flags & O_NONBLOCK)) {
598-
error = wait_event_interruptible(evdev->wait,
598+
error = wait_event_interruptible(client->wait,
599599
client->packet_head != client->tail ||
600600
!evdev->exist || client->revoked);
601601
if (error)
@@ -613,7 +613,7 @@ static __poll_t evdev_poll(struct file *file, poll_table *wait)
613613
struct evdev *evdev = client->evdev;
614614
__poll_t mask;
615615

616-
poll_wait(file, &evdev->wait, wait);
616+
poll_wait(file, &client->wait, wait);
617617

618618
if (evdev->exist && !client->revoked)
619619
mask = EPOLLOUT | EPOLLWRNORM;
@@ -946,7 +946,7 @@ static int evdev_revoke(struct evdev *evdev, struct evdev_client *client,
946946
client->revoked = true;
947947
evdev_ungrab(evdev, client);
948948
input_flush_device(&evdev->handle, file);
949-
wake_up_interruptible_poll(&evdev->wait, EPOLLHUP | EPOLLERR);
949+
wake_up_interruptible_poll(&client->wait, EPOLLHUP | EPOLLERR);
950950

951951
return 0;
952952
}
@@ -1358,7 +1358,6 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
13581358
INIT_LIST_HEAD(&evdev->client_list);
13591359
spin_lock_init(&evdev->client_lock);
13601360
mutex_init(&evdev->mutex);
1361-
init_waitqueue_head(&evdev->wait);
13621361
evdev->exist = true;
13631362

13641363
dev_no = minor;

0 commit comments

Comments
 (0)