With GitLab and the spinning off of commit messages to wine-gitlab I
think the traffic estimates on the mailing list page need to be
updated... at least for wine-devel: it no longer has 50 messages per
day.
https://www.winehq.org/forums
(unfortunately there is no unit on the little per mailing-list graph)
--
Francois Gouget <fgouget(a)free.fr> http://fgouget.free.fr/
Theory is where you know everything but nothing works.
Practice is where everything works but nobody knows why.
Sometimes they go hand in hand: nothing works and nobody knows why.
This patch series introduces a new char misc driver, /dev/ntsync, which is used
to implement Windows NT synchronization primitives.
This was previously submitted as an RFC [1]. Since there were no major changes
requested to the last RFC revision, I've stripped the RFC prefix.
[1] https://lore.kernel.org/lkml/[email protected]/
== Background ==
The Wine project emulates the Windows API in user space. One particular part of
that API, namely the NT synchronization primitives, have historically been
implemented via RPC to a dedicated "kernel" process. However, more recent
applications use these APIs more strenuously, and the overhead of RPC has become
a bottleneck.
The NT synchronization APIs are too complex to implement on top of existing
primitives without sacrificing correctness. Certain operations, such as
NtPulseEvent() or the "wait-for-all" mode of NtWaitForMultipleObjects(), require
direct control over the underlying wait queue, and implementing a wait queue
sufficiently robust for Wine in user space is not possible. This proposed
driver, therefore, implements the problematic interfaces directly in the Linux
kernel.
This driver was presented at Linux Plumbers Conference 2023. For those further
interested in the history of synchronization in Wine and past attempts to solve
this problem in user space, a recording of the presentation can be viewed here:
https://www.youtube.com/watch?v=NjU4nyWyhU8
== Performance ==
The gain in performance varies wildly depending on the application in question
and the user's hardware. For some games NT synchronization is not a bottleneck
and no change can be observed, but for others frame rate improvements of 50 to
150 percent are not atypical. The following table lists frame rate measurements
from a variety of games on a variety of hardware, taken by users Dmitry
Skvortsov, FuzzyQuils, OnMars, and myself:
Game Upstream ntsync improvement
===========================================================================
Anger Foot 69 99 43%
Call of Juarez 99.8 224.1 125%
Dirt 3 110.6 860.7 678%
Forza Horizon 5 108 160 48%
Lara Croft: Temple of Osiris 141 326 131%
Metro 2033 164.4 199.2 21%
Resident Evil 2 26 77 196%
The Crew 26 51 96%
Tiny Tina's Wonderlands 130 360 177%
Total War Saga: Troy 109 146 34%
===========================================================================
== Patches ==
The intended semantics of the patches are broadly intended to match those of the
corresponding Windows functions. For those not already familiar with the Windows
functions (or their undocumented behaviour), patch 31/31 provides a detailed
specification, and individual patches also include a brief description of the
API they are implementing.
The patches making use of this driver in Wine can be retrieved or browsed here:
https://repo.or.cz/wine/zf.git/shortlog/refs/heads/ntsync5
== Implementation ==
Some aspects of the implementation may deserve particular comment:
* In the interest of performance, each object is governed only by a single
spinlock. However, NTSYNC_IOC_WAIT_ALL requires that the state of multiple
objects be changed as a single atomic operation. In order to achieve this, we
first take a device-wide lock ("wait_all_lock") any time we are going to lock
more than one object at a time.
The maximum number of objects that can be used in a vectored wait, and
therefore the maximum that can be locked simultaneously, is 64. This number is
NT's own limit.
The acquisition of multiple spinlocks will degrade performance. This is a
conscious choice, however. Wait-for-all is known to be a very rare operation
in practice, especially with counts that approach the maximum, and it is the
intent of the ntsync driver to optimize wait-for-any at the expense of
wait-for-all as much as possible.
* NT mutexes are tied to their threads on an OS level, and the kernel includes
builtin support for "robust" mutexes. In order to keep the ntsync driver
self-contained and avoid touching more code than necessary, it does not hook
into task exit nor use pids.
Instead, the user space emulator is expected to manage thread IDs and pass
them as an argument to any relevant functions; this is the "owner" field of
ntsync_wait_args and ntsync_mutex_args.
When the emulator detects that a thread dies, it should therefore call
NTSYNC_IOC_MUTEX_KILL on any open mutexes.
* ntsync is module-capable mostly because there was nothing preventing it, and
because it aided development. It is not a hard requirement, though.
== Previous versions ==
Changes from v1:
* Fix a broken rebase that stole part of the Kconfig documentation from the
neighbouring entry, per Randy Dunlap.
* Add my email address to copyright and MODULE_AUTHOR lines, per Randy Dunlap.
* Document the reference counting behaviour more clearly, per Greg
Kroah-Hartman.
* Hopefully submit all the patches this time the right way.
* Link to v1: https://lore.kernel.org/lkml/[email protected]/
* Link to RFC v2: https://lore.kernel.org/lkml/[email protected]/
* Link to RFC v1: https://lore.kernel.org/lkml/[email protected]/
Elizabeth Figura (31):
ntsync: Introduce the ntsync driver and character device.
ntsync: Introduce NTSYNC_IOC_CREATE_SEM.
ntsync: Introduce NTSYNC_IOC_SEM_POST.
ntsync: Introduce NTSYNC_IOC_WAIT_ANY.
ntsync: Introduce NTSYNC_IOC_WAIT_ALL.
ntsync: Introduce NTSYNC_IOC_CREATE_MUTEX.
ntsync: Introduce NTSYNC_IOC_MUTEX_UNLOCK.
ntsync: Introduce NTSYNC_IOC_MUTEX_KILL.
ntsync: Introduce NTSYNC_IOC_CREATE_EVENT.
ntsync: Introduce NTSYNC_IOC_EVENT_SET.
ntsync: Introduce NTSYNC_IOC_EVENT_RESET.
ntsync: Introduce NTSYNC_IOC_EVENT_PULSE.
ntsync: Introduce NTSYNC_IOC_SEM_READ.
ntsync: Introduce NTSYNC_IOC_MUTEX_READ.
ntsync: Introduce NTSYNC_IOC_EVENT_READ.
ntsync: Introduce alertable waits.
ntsync: Allow waits to use the REALTIME clock.
selftests: ntsync: Add some tests for semaphore state.
selftests: ntsync: Add some tests for mutex state.
selftests: ntsync: Add some tests for NTSYNC_IOC_WAIT_ANY.
selftests: ntsync: Add some tests for NTSYNC_IOC_WAIT_ALL.
selftests: ntsync: Add some tests for wakeup signaling with
WINESYNC_IOC_WAIT_ANY.
selftests: ntsync: Add some tests for wakeup signaling with
WINESYNC_IOC_WAIT_ALL.
selftests: ntsync: Add some tests for manual-reset event state.
selftests: ntsync: Add some tests for auto-reset event state.
selftests: ntsync: Add some tests for wakeup signaling with events.
selftests: ntsync: Add tests for alertable waits.
selftests: ntsync: Add some tests for wakeup signaling via alerts.
selftests: ntsync: Add a stress test for contended waits.
maintainers: Add an entry for ntsync.
docs: ntsync: Add documentation for the ntsync uAPI.
Elizabeth Figura (31):
ntsync: Introduce the ntsync driver and character device.
ntsync: Introduce NTSYNC_IOC_CREATE_SEM.
ntsync: Introduce NTSYNC_IOC_SEM_POST.
ntsync: Introduce NTSYNC_IOC_WAIT_ANY.
ntsync: Introduce NTSYNC_IOC_WAIT_ALL.
ntsync: Introduce NTSYNC_IOC_CREATE_MUTEX.
ntsync: Introduce NTSYNC_IOC_MUTEX_UNLOCK.
ntsync: Introduce NTSYNC_IOC_MUTEX_KILL.
ntsync: Introduce NTSYNC_IOC_CREATE_EVENT.
ntsync: Introduce NTSYNC_IOC_EVENT_SET.
ntsync: Introduce NTSYNC_IOC_EVENT_RESET.
ntsync: Introduce NTSYNC_IOC_EVENT_PULSE.
ntsync: Introduce NTSYNC_IOC_SEM_READ.
ntsync: Introduce NTSYNC_IOC_MUTEX_READ.
ntsync: Introduce NTSYNC_IOC_EVENT_READ.
ntsync: Introduce alertable waits.
ntsync: Allow waits to use the REALTIME clock.
selftests: ntsync: Add some tests for semaphore state.
selftests: ntsync: Add some tests for mutex state.
selftests: ntsync: Add some tests for NTSYNC_IOC_WAIT_ANY.
selftests: ntsync: Add some tests for NTSYNC_IOC_WAIT_ALL.
selftests: ntsync: Add some tests for wakeup signaling with
WINESYNC_IOC_WAIT_ANY.
selftests: ntsync: Add some tests for wakeup signaling with
WINESYNC_IOC_WAIT_ALL.
selftests: ntsync: Add some tests for manual-reset event state.
selftests: ntsync: Add some tests for auto-reset event state.
selftests: ntsync: Add some tests for wakeup signaling with events.
selftests: ntsync: Add tests for alertable waits.
selftests: ntsync: Add some tests for wakeup signaling via alerts.
selftests: ntsync: Add a stress test for contended waits.
maintainers: Add an entry for ntsync.
docs: ntsync: Add documentation for the ntsync uAPI.
Documentation/userspace-api/index.rst | 1 +
.../userspace-api/ioctl/ioctl-number.rst | 2 +
Documentation/userspace-api/ntsync.rst | 399 +++++
MAINTAINERS | 9 +
drivers/misc/Kconfig | 11 +
drivers/misc/Makefile | 1 +
drivers/misc/ntsync.c | 1159 ++++++++++++++
include/uapi/linux/ntsync.h | 62 +
tools/testing/selftests/Makefile | 1 +
.../testing/selftests/drivers/ntsync/Makefile | 8 +
tools/testing/selftests/drivers/ntsync/config | 1 +
.../testing/selftests/drivers/ntsync/ntsync.c | 1407 +++++++++++++++++
12 files changed, 3061 insertions(+)
create mode 100644 Documentation/userspace-api/ntsync.rst
create mode 100644 drivers/misc/ntsync.c
create mode 100644 include/uapi/linux/ntsync.h
create mode 100644 tools/testing/selftests/drivers/ntsync/Makefile
create mode 100644 tools/testing/selftests/drivers/ntsync/config
create mode 100644 tools/testing/selftests/drivers/ntsync/ntsync.c
base-commit: 8d11c6d9b14f7a87f65529cb33edc5fed846ed9d
--
2.43.0
Binary packages for various distributions will be available from:
https://www.winehq.org/download
Summary since last release
* Rebased to current wine 9.3 (473 patches are applied to wine vanilla)
Upstreamed (Either directly from staging or fixed with a similar patch).
* winex11.drv: Simplify XInput2 valuator lookup.
* winex11.drv: Split XInput2 thread initialization.
* winex11.drv: Advertise XInput2 version 2.1 support.
* shlwapi: Support ./ in UrlCanonicalize.
* shlwapi/tests: Add additional tests for UrlCombine and UrlCanonicalize
* shlwapi: UrlCombineW workaround for relative paths
* Revert "explorer: Set layered style on systray icons only when it's actually layered."
* Revert "explorer: Don't activate the systray icon when showing it."
* where: Implement search with default options.
* Try to retrieve the unix name on handles created from file descriptors.
Added:
* None.
Removed (No longer required)
* kernel32-Processor_Group
* ntdll-x86_64_Builtin_Frames
* wined3d-mesa_texture_download
* winex11-Vulkan_support
* winspool.drv-ClosePrinter
* ntdll-NtQuerySection
Updated:
* vkd3d-latest
* Compiler_Warnings
Where can you help
* Run Steam/Battle.net/GOG/UPlay/Epic
* Test your favorite game.
* Test your favorite applications.
* Improve staging patches and get them accepted upstream.
* Suggest patches to be included in staging.
As always, if you find a bug, please report it via
https://bugs.winehq.org
Best Regards
Alistair.
On Thursday, 22 February 2024 04:56:21 CST Geert Uytterhoeven wrote:
> > --- a/drivers/misc/Kconfig
> > +++ b/drivers/misc/Kconfig
> > @@ -506,6 +506,17 @@ config OPEN_DICE
> >
> > If unsure, say N.
> >
> > +config NTSYNC
> > + tristate "NT synchronization primitive emulation"
> > + help
> > + This module provides kernel support for emulation of Windows NT
> > + synchronization primitives. It is not a hardware driver.
> > +
> > + To compile this driver as a module, choose M here: the
> > + module will be called ntsync.
> > +
> > + If unsure, say N.
>
> Is it useful to have this feature on systems or architectures that
> are not supported by Windows NT?
>
> If not, this should depend on <something> || COMPILE_TEST.
Hmm, that's an interesting question. Currently only Wine supports x86 and ARM,
as the only architectures supported by modern Windows. On the other hand, that
hasn't always been the case, and there's been some desire to use Wine (as a
porting tool) on architectures that Windows doesn't support, and out-of-tree
ports to e.g. PowerPC to that end.
Perhaps more saliently, there's no reason I'm aware of that this code *can't*
run on any architecture, and Wine (or another NT emulator) may grow support
for more architectures in the future. I (with my limited experience) don't see
a reason to artificially limit ourselves, especially if the driver is disabled
by default.
--Zeb
On Tuesday, 20 February 2024 01:01:59 CST Arnd Bergmann wrote:
> On Mon, Feb 19, 2024, at 23:38, Elizabeth Figura wrote:
> > NtWaitForMultipleObjects() can receive a timeout in two forms, relative or
> > absolute. Relative timeouts are unaffected by changes to the system time and do
> > not count down while the system suspends; for absolute timeouts the opposite is
> > true.
> >
> > In order to make the interface and implementation simpler, the ntsync driver
> > only deals in absolute timeouts. However, we need to be able to emulate both
> > behaviours apropos suspension and time adjustment, which is achieved by allowing
> > either the MONOTONIC or REALTIME clock to be used.
> >
> > Signed-off-by: Elizabeth Figura <zfigura(a)codeweavers.com>
>
> I understand that there is no practical problem in building
> up the API one patch at a time in the initial merge, but
> it still feels wrong to have an incompatible ABI change in
> the middle of the series:
>
> > @@ -35,6 +37,8 @@ struct ntsync_wait_args {
> > __u32 owner;
> > __u32 index;
> > __u32 alert;
> > + __u32 flags;
> > + __u32 pad;
> > };
>
> If this was patch to get merged at any later point, you'd have
> to support both the shorter and the longer structure layout
> with their distinct ioctl command codes.
>
> If you do a v3 series, maybe just merge this patch into the
> one that introduces the struct ntsync_wait_args. Overall,
> you could probably have fewer but larger patches anyway
> without harming the review process, but other than this
> one that is not a problem.
Oops, yes, that does feel wrong now that you point it out.
I'll squash this in v3, assuming there's a need for one.
--Zeb
On Saturday, 17 February 2024 02:03:15 CST Greg Kroah-Hartman wrote:
> On Thu, Feb 15, 2024 at 01:22:01PM -0600, Elizabeth Figura wrote:
> > On Thursday, 15 February 2024 01:28:32 CST Greg Kroah-Hartman wrote:
> > > On Wed, Feb 14, 2024 at 05:36:38PM -0600, Elizabeth Figura wrote:
> > > > This corresponds to the NT syscall NtCreateSemaphore().
> > > >
> > > > Semaphores are one of three types of object to be implemented in this driver,
> > > > the others being mutexes and events.
> > > >
> > > > An NT semaphore contains a 32-bit counter, and is signaled and can be acquired
> > > > when the counter is nonzero. The counter has a maximum value which is specified
> > > > at creation time. The initial value of the semaphore is also specified at
> > > > creation time. There are no restrictions on the maximum and initial value.
> > > >
> > > > Each object is exposed as an file, to which any number of fds may be opened.
> > > > When all fds are closed, the object is deleted.
> > > >
> > > > Signed-off-by: Elizabeth Figura <zfigura(a)codeweavers.com>
> > > > ---
> > > > .../userspace-api/ioctl/ioctl-number.rst | 2 +
> > > > drivers/misc/ntsync.c | 120 ++++++++++++++++++
> > > > include/uapi/linux/ntsync.h | 21 +++
> > > > 3 files changed, 143 insertions(+)
> > > > create mode 100644 include/uapi/linux/ntsync.h
> > > >
> > > > diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst
> > > > index 457e16f06e04..2f5c6994f042 100644
> > > > --- a/Documentation/userspace-api/ioctl/ioctl-number.rst
> > > > +++ b/Documentation/userspace-api/ioctl/ioctl-number.rst
> > > > @@ -173,6 +173,8 @@ Code Seq# Include File Comments
> > > > 'M' 00-0F drivers/video/fsl-diu-fb.h conflict!
> > > > 'N' 00-1F drivers/usb/scanner.h
> > > > 'N' 40-7F drivers/block/nvme.c
> > > > +'N' 80-8F uapi/linux/ntsync.h NT synchronization primitives
> > > > + <mailto:[email protected]>
> > > > 'O' 00-06 mtd/ubi-user.h UBI
> > > > 'P' all linux/soundcard.h conflict!
> > > > 'P' 60-6F sound/sscape_ioctl.h conflict!
> > > > diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c
> > > > index e4969ef90722..3ad86d98b82d 100644
> > > > --- a/drivers/misc/ntsync.c
> > > > +++ b/drivers/misc/ntsync.c
> > > > @@ -5,26 +5,146 @@
> > > > * Copyright (C) 2024 Elizabeth Figura
> > > > */
> > > >
> > > > +#include <linux/anon_inodes.h>
> > > > +#include <linux/file.h>
> > > > #include <linux/fs.h>
> > > > #include <linux/miscdevice.h>
> > > > #include <linux/module.h>
> > > > +#include <linux/slab.h>
> > > > +#include <uapi/linux/ntsync.h>
> > > >
> > > > #define NTSYNC_NAME "ntsync"
> > > >
> > > > +enum ntsync_type {
> > > > + NTSYNC_TYPE_SEM,
> > > > +};
> > > > +
> > > > +struct ntsync_obj {
> > > > + enum ntsync_type type;
> > > > +
> > > > + union {
> > > > + struct {
> > > > + __u32 count;
> > > > + __u32 max;
> > > > + } sem;
> > > > + } u;
> > > > +
> > > > + struct file *file;
> > > > + struct ntsync_device *dev;
> > > > +};
> > > > +
> > > > +struct ntsync_device {
> > > > + struct file *file;
> > > > +};
> > >
> > > No reference counting is needed for your ntsync_device? Or are you
> > > relying on the reference counting of struct file here?
> > >
> > > You pass around pointers to this structure, and save it off into other
> > > structures, how do you know it is "safe" to do so?
> >
> > Yes, this relies on the reference counting of struct file. The sync
> > objects (semaphore etc.) grab a reference when they're created, via
> > get_file(), and release it when they're destroyed. This reference is
> > taken from within ioctls on the ntsync_device, so the file must be
> > valid when we grab a reference. Maybe I'm missing something, though?
>
> If the reference count is driven by struct file, that's fine, and great,
> otherwise you end up with two different reference counts and keeping
> them in sync is impossible.
>
> But as it wasn't obvious, a comment somewhere here would be helpful for
> reviewing and figuring out how this all works in 4 years when someone
> has to touch it again.
Ah, makes sense. I'll add comments to be clearer about the refcounting
relationships, thanks.
--Zeb
I'm starting the process of moving Wine Mono off of my personal Github
account and onto the Winehq Gitlab in the organization here:
https://gitlab.winehq.org/wine-mono
Obviously, I haven't gotten very far yet, as the main repo for Wine Mono
itself doesn't exist, but the intent is to move every submodule that we've
forked (as well as projects I've started just for Wine Mono) over to
Winehq, set up CI there, and archive my Github repos. The procedure for
contributing will be to fork the repository and create merge requests
(which I will also do for my own contributions, once we're set up for it).
I'm also rethinking the branch structure. The Mono repo will have three
mainline branches: upstream (the upstream project as it exists in the
official repos), main (upstream plus further development that I will review
and maintain), and wine-mono (main plus changes we have only in Wine). The
"upstream" and "main" branches should be the same for any upstream that is
responsive and cares about preserving ABI compatibility (right now that's
just FNA and monoDX). The wine-mono branch should only exist for projects
that have a general use case in which Wine's changes don't make sense (I
think that's just Mono, corefx, and FNA).
The answer to "which branch should I send my MR to?" will almost always be
main. There should be a very few changes on wine-mono only. The ones I can
think of off the top of my head are: enabling native dll loading without
coree hooks, renaming a bunch of assemblies to start with "WineMono.",
winforms hooks in FNA, and proprietary media formats in FNA. Over the years
we've been doing a lot of development on top of Mono that, in my opinion,
belongs upstream.
I will also accept changes to Mono that have nothing to do with Wine, such
as winforms changes, and I will try to keep the main branch working for use
cases outside of Wine and Windows, to the extent that it's feasible (there
are a bunch of configurations I can't easily test, like PowerPC, ARM,
Android, and iOS, and I can't see myself doing development to support new
platforms like M1). I don't know how much development interest there will
be, but I seem to be in a unique position to maintain Framework Mono, and I
think it is needed.
On Thursday, 15 February 2024 01:28:32 CST Greg Kroah-Hartman wrote:
> On Wed, Feb 14, 2024 at 05:36:38PM -0600, Elizabeth Figura wrote:
> > This corresponds to the NT syscall NtCreateSemaphore().
> >
> > Semaphores are one of three types of object to be implemented in this driver,
> > the others being mutexes and events.
> >
> > An NT semaphore contains a 32-bit counter, and is signaled and can be acquired
> > when the counter is nonzero. The counter has a maximum value which is specified
> > at creation time. The initial value of the semaphore is also specified at
> > creation time. There are no restrictions on the maximum and initial value.
> >
> > Each object is exposed as an file, to which any number of fds may be opened.
> > When all fds are closed, the object is deleted.
> >
> > Signed-off-by: Elizabeth Figura <zfigura(a)codeweavers.com>
> > ---
> > .../userspace-api/ioctl/ioctl-number.rst | 2 +
> > drivers/misc/ntsync.c | 120 ++++++++++++++++++
> > include/uapi/linux/ntsync.h | 21 +++
> > 3 files changed, 143 insertions(+)
> > create mode 100644 include/uapi/linux/ntsync.h
> >
> > diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst
> > index 457e16f06e04..2f5c6994f042 100644
> > --- a/Documentation/userspace-api/ioctl/ioctl-number.rst
> > +++ b/Documentation/userspace-api/ioctl/ioctl-number.rst
> > @@ -173,6 +173,8 @@ Code Seq# Include File Comments
> > 'M' 00-0F drivers/video/fsl-diu-fb.h conflict!
> > 'N' 00-1F drivers/usb/scanner.h
> > 'N' 40-7F drivers/block/nvme.c
> > +'N' 80-8F uapi/linux/ntsync.h NT synchronization primitives
> > + <mailto:[email protected]>
> > 'O' 00-06 mtd/ubi-user.h UBI
> > 'P' all linux/soundcard.h conflict!
> > 'P' 60-6F sound/sscape_ioctl.h conflict!
> > diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c
> > index e4969ef90722..3ad86d98b82d 100644
> > --- a/drivers/misc/ntsync.c
> > +++ b/drivers/misc/ntsync.c
> > @@ -5,26 +5,146 @@
> > * Copyright (C) 2024 Elizabeth Figura
> > */
> >
> > +#include <linux/anon_inodes.h>
> > +#include <linux/file.h>
> > #include <linux/fs.h>
> > #include <linux/miscdevice.h>
> > #include <linux/module.h>
> > +#include <linux/slab.h>
> > +#include <uapi/linux/ntsync.h>
> >
> > #define NTSYNC_NAME "ntsync"
> >
> > +enum ntsync_type {
> > + NTSYNC_TYPE_SEM,
> > +};
> > +
> > +struct ntsync_obj {
> > + enum ntsync_type type;
> > +
> > + union {
> > + struct {
> > + __u32 count;
> > + __u32 max;
> > + } sem;
> > + } u;
> > +
> > + struct file *file;
> > + struct ntsync_device *dev;
> > +};
> > +
> > +struct ntsync_device {
> > + struct file *file;
> > +};
>
> No reference counting is needed for your ntsync_device? Or are you
> relying on the reference counting of struct file here?
>
> You pass around pointers to this structure, and save it off into other
> structures, how do you know it is "safe" to do so?
Yes, this relies on the reference counting of struct file. The sync
objects (semaphore etc.) grab a reference when they're created, via
get_file(), and release it when they're destroyed. This reference is
taken from within ioctls on the ntsync_device, so the file must be
valid when we grab a reference. Maybe I'm missing something, though?
On Wednesday, 14 February 2024 19:57:23 CST Randy Dunlap wrote:
> Hi,
>
> On 2/14/24 15:36, Elizabeth Figura wrote:
> > ntsync uses a misc device as the simplest and least intrusive uAPI interface.
> >
> > Each file description on the device represents an isolated NT instance, intended
> > to correspond to a single NT virtual machine.
> >
> > Signed-off-by: Elizabeth Figura <zfigura(a)codeweavers.com>
> > ---
> > drivers/misc/Kconfig | 9 ++++++++
> > drivers/misc/Makefile | 1 +
> > drivers/misc/ntsync.c | 52 +++++++++++++++++++++++++++++++++++++++++++
> > 3 files changed, 62 insertions(+)
> > create mode 100644 drivers/misc/ntsync.c
> >
> > diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
> > index 4fb291f0bf7c..bdd8a71bd853 100644
> > --- a/drivers/misc/Kconfig
> > +++ b/drivers/misc/Kconfig
> > @@ -504,6 +504,15 @@ config OPEN_DICE
> > measured boot flow. Userspace can use CDIs for remote attestation
> > and sealing.
> >
> > +config NTSYNC
> > + tristate "NT synchronization primitive emulation"
> > + help
> > + This module provides kernel support for emulation of Windows NT
> > + synchronization primitives. It is not a hardware driver.
> > +
> > + To compile this driver as a module, choose M here: the
> > + module will be called ntsync.
> > +
> > If unsure, say N.
>
> It looks like the "If unsure" line belongs to the OPEN_DICE kconfig entry
> above here. If you want one for NTSYNC, please add one.
Oops, looks like that was a bad rebase :-(
>
> >
> > config VCPU_STALL_DETECTOR
>
>
> > diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c
> > new file mode 100644
> > index 000000000000..e4969ef90722
> > --- /dev/null
> > +++ b/drivers/misc/ntsync.c
> > @@ -0,0 +1,52 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +/*
> > + * ntsync.c - Kernel driver for NT synchronization primitives
> > + *
> > + * Copyright (C) 2024 Elizabeth Figura
>
> It would be nice to have your email address above...
>
> > + */
> > +
>
> > +
> > +MODULE_AUTHOR("Elizabeth Figura");
>
> but at least please add it in MODULE_AUTHOR(). Yes it's optional, but
> roughly 7900 of 10400 entries do include it (according to my rough
> grepping).
>
> Yes, I know that it's in MAINTAINERS.
Will add, thanks. As you guessed I did just pick an arbitrary module to copy.
This patch series introduces a new char misc driver, /dev/ntsync, which is used
to implement Windows NT synchronization primitives.
This was previously submitted as an RFC [1]. Since there were no major changes
requested to the last RFC revision, I've stripped the RFC prefix.
[1] https://lore.kernel.org/lkml/[email protected]/
== Background ==
The Wine project emulates the Windows API in user space. One particular part of
that API, namely the NT synchronization primitives, have historically been
implemented via RPC to a dedicated "kernel" process. However, more recent
applications use these APIs more strenuously, and the overhead of RPC has become
a bottleneck.
The NT synchronization APIs are too complex to implement on top of existing
primitives without sacrificing correctness. Certain operations, such as
NtPulseEvent() or the "wait-for-all" mode of NtWaitForMultipleObjects(), require
direct control over the underlying wait queue, and implementing a wait queue
sufficiently robust for Wine in user space is not possible. This proposed
driver, therefore, implements the problematic interfaces directly in the Linux
kernel.
This driver was presented at Linux Plumbers Conference 2023. For those further
interested in the history of synchronization in Wine and past attempts to solve
this problem in user space, a recording of the presentation can be viewed here:
https://www.youtube.com/watch?v=NjU4nyWyhU8
== Performance ==
The gain in performance varies wildly depending on the application in question
and the user's hardware. For some games NT synchronization is not a bottleneck
and no change can be observed, but for others frame rate improvements of 50 to
150 percent are not atypical. The following table lists frame rate measurements
from a variety of games on a variety of hardware, taken by users Dmitry
Skvortsov, FuzzyQuils, OnMars, and myself:
Game Upstream ntsync improvement
===========================================================================
Anger Foot 69 99 43%
Call of Juarez 99.8 224.1 125%
Dirt 3 110.6 860.7 678%
Forza Horizon 5 108 160 48%
Lara Croft: Temple of Osiris 141 326 131%
Metro 2033 164.4 199.2 21%
Resident Evil 2 26 77 196%
The Crew 26 51 96%
Tiny Tina's Wonderlands 130 360 177%
Total War Saga: Troy 109 146 34%
===========================================================================
== Patches ==
The intended semantics of the patches are broadly intended to match those of the
corresponding Windows functions. For those not already familiar with the Windows
functions (or their undocumented behaviour), patch 31/31 provides a detailed
specification, and individual patches also include a brief description of the
API they are implementing.
The patches making use of this driver in Wine can be retrieved or browsed here:
https://repo.or.cz/wine/zf.git/shortlog/refs/heads/ntsync5
== Implementation ==
Some aspects of the implementation may deserve particular comment:
* In the interest of performance, each object is governed only by a single
spinlock. However, NTSYNC_IOC_WAIT_ALL requires that the state of multiple
objects be changed as a single atomic operation. In order to achieve this, we
first take a device-wide lock ("wait_all_lock") any time we are going to lock
more than one object at a time.
The maximum number of objects that can be used in a vectored wait, and
therefore the maximum that can be locked simultaneously, is 64. This number is
NT's own limit.
The acquisition of multiple spinlocks will degrade performance. This is a
conscious choice, however. Wait-for-all is known to be a very rare operation
in practice, especially with counts that approach the maximum, and it is the
intent of the ntsync driver to optimize wait-for-any at the expense of
wait-for-all as much as possible.
* NT mutexes are tied to their threads on an OS level, and the kernel includes
builtin support for "robust" mutexes. In order to keep the ntsync driver
self-contained and avoid touching more code than necessary, it does not hook
into task exit nor use pids.
Instead, the user space emulator is expected to manage thread IDs and pass
them as an argument to any relevant functions; this is the "owner" field of
ntsync_wait_args and ntsync_mutex_args.
When the emulator detects that a thread dies, it should therefore call
NTSYNC_IOC_MUTEX_KILL on any open mutexes.
* ntsync is module-capable mostly because there was nothing preventing it, and
because it aided development. It is not a hard requirement, though.
== Previous versions ==
Changes from the last (v2) RFC:
* Add a new wait flag NTSYNC_WAIT_REALTIME. I had originally missed a corner
case in NtWaitForMultipleObjects() related to its interaction with system time
adjustments. Essentially the function is sometimes supposed to respect system
time adjustments and sometimes supposed to ignore them, so in order to achieve
this I've added a function that controls which flag is being synchronized to.
Thanks Piotr Caban for catching this.
* Add tests for overflowing semaphore and mutex counters, and a test for
exceeding NTSYNC_MAX_WAIT_COUNT, per Andi Kleen.
* Add a more intense and realistic test involving multiple threads using the
same mutex to access data, per Andi Kleen.
* Use check_add_overflow() instead of writing out overflow checking manually
[and thereby avoid relying on -fwrapv].
* Add some missing headers that were being implicitly included: atomic.h,
hrtimer.h, ktime.h, sched.h, sched/signal.h, spinlock.h.
* Link to RFC v2: https://lore.kernel.org/lkml/[email protected]/
* Link to RFC v1: https://lore.kernel.org/lkml/[email protected]/
Elizabeth Figura (31):
ntsync: Introduce the ntsync driver and character device.
ntsync: Introduce NTSYNC_IOC_CREATE_SEM.
ntsync: Introduce NTSYNC_IOC_SEM_POST.
ntsync: Introduce NTSYNC_IOC_WAIT_ANY.
ntsync: Introduce NTSYNC_IOC_WAIT_ALL.
ntsync: Introduce NTSYNC_IOC_CREATE_MUTEX.
ntsync: Introduce NTSYNC_IOC_MUTEX_UNLOCK.
ntsync: Introduce NTSYNC_IOC_MUTEX_KILL.
ntsync: Introduce NTSYNC_IOC_CREATE_EVENT.
ntsync: Introduce NTSYNC_IOC_EVENT_SET.
ntsync: Introduce NTSYNC_IOC_EVENT_RESET.
ntsync: Introduce NTSYNC_IOC_EVENT_PULSE.
ntsync: Introduce NTSYNC_IOC_SEM_READ.
ntsync: Introduce NTSYNC_IOC_MUTEX_READ.
ntsync: Introduce NTSYNC_IOC_EVENT_READ.
ntsync: Introduce alertable waits.
ntsync: Allow waits to use the REALTIME clock.
selftests: ntsync: Add some tests for semaphore state.
selftests: ntsync: Add some tests for mutex state.
selftests: ntsync: Add some tests for NTSYNC_IOC_WAIT_ANY.
selftests: ntsync: Add some tests for NTSYNC_IOC_WAIT_ALL.
selftests: ntsync: Add some tests for wakeup signaling with
WINESYNC_IOC_WAIT_ANY.
selftests: ntsync: Add some tests for wakeup signaling with
WINESYNC_IOC_WAIT_ALL.
selftests: ntsync: Add some tests for manual-reset event state.
selftests: ntsync: Add some tests for auto-reset event state.
selftests: ntsync: Add some tests for wakeup signaling with events.
selftests: ntsync: Add tests for alertable waits.
selftests: ntsync: Add some tests for wakeup signaling via alerts.
selftests: ntsync: Add a stress test for contended waits.
maintainers: Add an entry for ntsync.
docs: ntsync: Add documentation for the ntsync uAPI.
Documentation/userspace-api/index.rst | 1 +
.../userspace-api/ioctl/ioctl-number.rst | 2 +
Documentation/userspace-api/ntsync.rst | 399 +++++
MAINTAINERS | 9 +
drivers/misc/Kconfig | 9 +
drivers/misc/Makefile | 1 +
drivers/misc/ntsync.c | 1146 ++++++++++++++
include/uapi/linux/ntsync.h | 62 +
tools/testing/selftests/Makefile | 1 +
.../testing/selftests/drivers/ntsync/Makefile | 8 +
tools/testing/selftests/drivers/ntsync/config | 1 +
.../testing/selftests/drivers/ntsync/ntsync.c | 1407 +++++++++++++++++
12 files changed, 3046 insertions(+)
create mode 100644 Documentation/userspace-api/ntsync.rst
create mode 100644 drivers/misc/ntsync.c
create mode 100644 include/uapi/linux/ntsync.h
create mode 100644 tools/testing/selftests/drivers/ntsync/Makefile
create mode 100644 tools/testing/selftests/drivers/ntsync/config
create mode 100644 tools/testing/selftests/drivers/ntsync/ntsync.c
base-commit: e21817acb23ece75d41a4fa7b40c85550f147389
--
2.43.0