Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Kenny Levinsen and committed by
Dmitry Torokhov
4ba8b8ae 470d154a

+9 -10
+9 -10
drivers/input/evdev.c
··· 28 28 struct evdev { 29 29 int open; 30 30 struct input_handle handle; 31 - wait_queue_head_t wait; 32 31 struct evdev_client __rcu *grab; 33 32 struct list_head client_list; 34 33 spinlock_t client_lock; /* protects client_list */ ··· 42 43 unsigned int tail; 43 44 unsigned int packet_head; /* [future] position of the first element of next packet */ 44 45 spinlock_t buffer_lock; /* protects access to buffer, head and tail */ 46 + wait_queue_head_t wait; 45 47 struct fasync_struct *fasync; 46 48 struct evdev *evdev; 47 49 struct list_head node; ··· 245 245 const struct input_value *vals, unsigned int count, 246 246 ktime_t *ev_time) 247 247 { 248 - struct evdev *evdev = client->evdev; 249 248 const struct input_value *v; 250 249 struct input_event event; 251 250 struct timespec64 ts; ··· 281 282 spin_unlock(&client->buffer_lock); 282 283 283 284 if (wakeup) 284 - wake_up_interruptible_poll(&evdev->wait, 285 + wake_up_interruptible_poll(&client->wait, 285 286 EPOLLIN | EPOLLOUT | EPOLLRDNORM | EPOLLWRNORM); 286 287 } 287 288 ··· 425 426 struct evdev_client *client; 426 427 427 428 spin_lock(&evdev->client_lock); 428 - list_for_each_entry(client, &evdev->client_list, node) 429 + list_for_each_entry(client, &evdev->client_list, node) { 429 430 kill_fasync(&client->fasync, SIGIO, POLL_HUP); 431 + wake_up_interruptible_poll(&client->wait, EPOLLHUP | EPOLLERR); 432 + } 430 433 spin_unlock(&evdev->client_lock); 431 - 432 - wake_up_interruptible_poll(&evdev->wait, EPOLLHUP | EPOLLERR); 433 434 } 434 435 435 436 static int evdev_release(struct inode *inode, struct file *file) ··· 478 479 if (!client) 479 480 return -ENOMEM; 480 481 482 + init_waitqueue_head(&client->wait); 481 483 client->bufsize = bufsize; 482 484 spin_lock_init(&client->buffer_lock); 483 485 client->evdev = evdev; ··· 595 595 break; 596 596 597 597 if (!(file->f_flags & O_NONBLOCK)) { 598 - error = wait_event_interruptible(evdev->wait, 598 + error = wait_event_interruptible(client->wait, 599 599 client->packet_head != client->tail || 600 600 !evdev->exist || client->revoked); 601 601 if (error) ··· 613 613 struct evdev *evdev = client->evdev; 614 614 __poll_t mask; 615 615 616 - poll_wait(file, &evdev->wait, wait); 616 + poll_wait(file, &client->wait, wait); 617 617 618 618 if (evdev->exist && !client->revoked) 619 619 mask = EPOLLOUT | EPOLLWRNORM; ··· 946 946 client->revoked = true; 947 947 evdev_ungrab(evdev, client); 948 948 input_flush_device(&evdev->handle, file); 949 - wake_up_interruptible_poll(&evdev->wait, EPOLLHUP | EPOLLERR); 949 + wake_up_interruptible_poll(&client->wait, EPOLLHUP | EPOLLERR); 950 950 951 951 return 0; 952 952 } ··· 1358 1358 INIT_LIST_HEAD(&evdev->client_list); 1359 1359 spin_lock_init(&evdev->client_lock); 1360 1360 mutex_init(&evdev->mutex); 1361 - init_waitqueue_head(&evdev->wait); 1362 1361 evdev->exist = true; 1363 1362 1364 1363 dev_no = minor;