-
Gabriel Krisman Bertazi authored
This is a new futex operation, called FUTEX_WAIT_MULTIPLE, which allows a thread to wait on several futexes at the same time, and be awoken by any of them. In a sense, it implements one of the features that was supported by pooling on the old FUTEX_FD interface. My use case for this operation lies in Wine, where we want to implement a similar interface available in Windows, used mainly for event handling. The wine folks have an implementation that uses eventfd, but it suffers from FD exhaustion (I was told they have application that go to the order of multi-milion FDs), and higher CPU utilization. In time, we are also proposing modifications to glibc and libpthread to make this feature available for Linux native multithreaded applications using libpthread, which can benefit from the behavior of waiting on any of a group of futexes. In particular, using futexes in our Wine use case reduced the CPU utilization by 4% for the game Beat Saber and by 1.5% for the game Shadow of Tomb Raider, both running over Proton (a wine based solution for Windows emulation), when compared to the eventfd interface. This implementation also doesn't rely of file descriptors, so it doesn't risk overflowing the resource. Technically, the existing FUTEX_WAIT implementation can be easily reworked by using do_futex_wait_multiple with a count of one, and I have a patch showing how it works. I'm not proposing it, since futex is such a tricky code, that I'd be more confortable to have FUTEX_WAIT_MULTIPLE running upstream for a couple development cycles, before considering modifying FUTEX_WAIT. From an implementation perspective, the futex list is passed as an array of (pointer,value,bitset) to the kernel, which will enqueue all of them and sleep if none was already triggered. It returns a hint of which futex caused the wake up event to userspace, but the hint doesn't guarantee that is the only futex triggered. Before calling the syscall again, userspace should traverse the list, trying to re-acquire any of the other futexes, to prevent an immediate -EWOULDBLOCK return code from the kernel. This was tested using three mechanisms: 1) By reimplementing FUTEX_WAIT in terms of FUTEX_WAIT_MULTIPLE and running the unmodified tools/testing/selftests/futex and a full linux distro on top of this kernel. 2) By an example code that exercises the FUTEX_WAIT_MULTIPLE path on a multi-threaded, event-handling setup. 3) By running the Wine fsync implementation and executing multi-threaded applications, in particular the modern games mentioned above, on top of this implementation. Signed-off-by: Zebediah Figura <z.figura12@gmail.com> Signed-off-by: Steven Noonan <steven@valvesoftware.com> Signed-off-by: Pierre-Loup A. Griffais <pgriffais@valvesoftware.com> Signed-off-by: Gabriel Krisman Bertazi <krisman@collabora.com>
d0ab2008