2024-03-29 00:05:53 +00:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
|
|
|
|
/*
|
|
|
|
|
* Kernel support for NT synchronization primitive emulation
|
|
|
|
|
*
|
|
|
|
|
* Copyright (C) 2021-2022 Elizabeth Figura <zfigura@codeweavers.com>
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifndef __LINUX_NTSYNC_H
|
|
|
|
|
#define __LINUX_NTSYNC_H
|
|
|
|
|
|
|
|
|
|
#include <linux/types.h>
|
|
|
|
|
|
|
|
|
|
struct ntsync_sem_args {
|
|
|
|
|
__u32 count;
|
|
|
|
|
__u32 max;
|
|
|
|
|
};
|
|
|
|
|
|
2024-12-13 19:34:46 +00:00
|
|
|
struct ntsync_mutex_args {
|
|
|
|
|
__u32 owner;
|
|
|
|
|
__u32 count;
|
|
|
|
|
};
|
|
|
|
|
|
2024-12-13 19:34:49 +00:00
|
|
|
struct ntsync_event_args {
|
|
|
|
|
__u32 manual;
|
|
|
|
|
__u32 signaled;
|
|
|
|
|
};
|
|
|
|
|
|
ntsync: Introduce NTSYNC_IOC_WAIT_ANY.
This corresponds to part of the functionality of the NT syscall
NtWaitForMultipleObjects(). Specifically, it implements the behaviour where
the third argument (wait_any) is TRUE, and it does not handle alertable waits.
Those features have been split out into separate patches to ease review.
This patch therefore implements the wait/wake infrastructure which comprises the
core of ntsync's functionality.
NTSYNC_IOC_WAIT_ANY is a vectored wait function similar to poll(). Unlike
poll(), it "consumes" objects when they are signaled. For semaphores, this means
decreasing one from the internal counter. At most one object can be consumed by
this function.
This wait/wake model is fundamentally different from that used anywhere else in
the kernel, and for that reason ntsync does not use any existing infrastructure,
such as futexes, kernel mutexes or semaphores, or wait_event().
Up to 64 objects can be waited on at once. As soon as one is signaled, the
object with the lowest index is consumed, and that index is returned via the
"index" field.
A timeout is supported. The timeout is passed as a u64 nanosecond value, which
represents absolute time measured against either the MONOTONIC or REALTIME clock
(controlled by the flags argument). If U64_MAX is passed, the ioctl waits
indefinitely.
This ioctl validates that all objects belong to the relevant device. This is not
necessary for any technical reason related to NTSYNC_IOC_WAIT_ANY, but will be
necessary for NTSYNC_IOC_WAIT_ALL introduced in the following patch.
Some padding fields are added for alignment and for fields which will be added
in future patches (split out to ease review).
Signed-off-by: Elizabeth Figura <zfigura@codeweavers.com>
Link: https://lore.kernel.org/r/20241213193511.457338-4-zfigura@codeweavers.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2024-12-13 19:34:44 +00:00
|
|
|
#define NTSYNC_WAIT_REALTIME 0x1
|
|
|
|
|
|
|
|
|
|
struct ntsync_wait_args {
|
|
|
|
|
__u64 timeout;
|
|
|
|
|
__u64 objs;
|
|
|
|
|
__u32 count;
|
|
|
|
|
__u32 index;
|
|
|
|
|
__u32 flags;
|
2024-12-13 19:34:46 +00:00
|
|
|
__u32 owner;
|
2024-12-13 19:34:56 +00:00
|
|
|
__u32 alert;
|
|
|
|
|
__u32 pad;
|
ntsync: Introduce NTSYNC_IOC_WAIT_ANY.
This corresponds to part of the functionality of the NT syscall
NtWaitForMultipleObjects(). Specifically, it implements the behaviour where
the third argument (wait_any) is TRUE, and it does not handle alertable waits.
Those features have been split out into separate patches to ease review.
This patch therefore implements the wait/wake infrastructure which comprises the
core of ntsync's functionality.
NTSYNC_IOC_WAIT_ANY is a vectored wait function similar to poll(). Unlike
poll(), it "consumes" objects when they are signaled. For semaphores, this means
decreasing one from the internal counter. At most one object can be consumed by
this function.
This wait/wake model is fundamentally different from that used anywhere else in
the kernel, and for that reason ntsync does not use any existing infrastructure,
such as futexes, kernel mutexes or semaphores, or wait_event().
Up to 64 objects can be waited on at once. As soon as one is signaled, the
object with the lowest index is consumed, and that index is returned via the
"index" field.
A timeout is supported. The timeout is passed as a u64 nanosecond value, which
represents absolute time measured against either the MONOTONIC or REALTIME clock
(controlled by the flags argument). If U64_MAX is passed, the ioctl waits
indefinitely.
This ioctl validates that all objects belong to the relevant device. This is not
necessary for any technical reason related to NTSYNC_IOC_WAIT_ANY, but will be
necessary for NTSYNC_IOC_WAIT_ALL introduced in the following patch.
Some padding fields are added for alignment and for fields which will be added
in future patches (split out to ease review).
Signed-off-by: Elizabeth Figura <zfigura@codeweavers.com>
Link: https://lore.kernel.org/r/20241213193511.457338-4-zfigura@codeweavers.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2024-12-13 19:34:44 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#define NTSYNC_MAX_WAIT_COUNT 64
|
|
|
|
|
|
2024-12-13 19:34:42 +00:00
|
|
|
#define NTSYNC_IOC_CREATE_SEM _IOW ('N', 0x80, struct ntsync_sem_args)
|
ntsync: Introduce NTSYNC_IOC_WAIT_ANY.
This corresponds to part of the functionality of the NT syscall
NtWaitForMultipleObjects(). Specifically, it implements the behaviour where
the third argument (wait_any) is TRUE, and it does not handle alertable waits.
Those features have been split out into separate patches to ease review.
This patch therefore implements the wait/wake infrastructure which comprises the
core of ntsync's functionality.
NTSYNC_IOC_WAIT_ANY is a vectored wait function similar to poll(). Unlike
poll(), it "consumes" objects when they are signaled. For semaphores, this means
decreasing one from the internal counter. At most one object can be consumed by
this function.
This wait/wake model is fundamentally different from that used anywhere else in
the kernel, and for that reason ntsync does not use any existing infrastructure,
such as futexes, kernel mutexes or semaphores, or wait_event().
Up to 64 objects can be waited on at once. As soon as one is signaled, the
object with the lowest index is consumed, and that index is returned via the
"index" field.
A timeout is supported. The timeout is passed as a u64 nanosecond value, which
represents absolute time measured against either the MONOTONIC or REALTIME clock
(controlled by the flags argument). If U64_MAX is passed, the ioctl waits
indefinitely.
This ioctl validates that all objects belong to the relevant device. This is not
necessary for any technical reason related to NTSYNC_IOC_WAIT_ANY, but will be
necessary for NTSYNC_IOC_WAIT_ALL introduced in the following patch.
Some padding fields are added for alignment and for fields which will be added
in future patches (split out to ease review).
Signed-off-by: Elizabeth Figura <zfigura@codeweavers.com>
Link: https://lore.kernel.org/r/20241213193511.457338-4-zfigura@codeweavers.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2024-12-13 19:34:44 +00:00
|
|
|
#define NTSYNC_IOC_WAIT_ANY _IOWR('N', 0x82, struct ntsync_wait_args)
|
ntsync: Introduce NTSYNC_IOC_WAIT_ALL.
This is similar to NTSYNC_IOC_WAIT_ANY, but waits until all of the objects are
simultaneously signaled, and then acquires all of them as a single atomic
operation.
Because acquisition of multiple objects is atomic, some complex locking is
required. We cannot simply spin-lock multiple objects simultaneously, as that
may disable preëmption for a problematically long time.
Instead, modifying any object which may be involved in a wait-all operation takes
a device-wide sleeping mutex, "wait_all_lock", instead of the normal object
spinlock.
Because wait-for-all is a rare operation, in order to optimize wait-for-any,
this lock is only taken when necessary. "all_hint" is used to mark objects which
are involved in a wait-for-all operation, and if an object is not, only its
spinlock is taken.
The locking scheme used here was written by Peter Zijlstra.
Signed-off-by: Elizabeth Figura <zfigura@codeweavers.com>
Link: https://lore.kernel.org/r/20241213193511.457338-5-zfigura@codeweavers.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2024-12-13 19:34:45 +00:00
|
|
|
#define NTSYNC_IOC_WAIT_ALL _IOWR('N', 0x83, struct ntsync_wait_args)
|
2024-12-13 19:34:46 +00:00
|
|
|
#define NTSYNC_IOC_CREATE_MUTEX _IOW ('N', 0x84, struct ntsync_mutex_args)
|
2024-12-13 19:34:49 +00:00
|
|
|
#define NTSYNC_IOC_CREATE_EVENT _IOW ('N', 0x87, struct ntsync_event_args)
|
2024-03-29 00:05:53 +00:00
|
|
|
|
2024-12-13 19:34:43 +00:00
|
|
|
#define NTSYNC_IOC_SEM_RELEASE _IOWR('N', 0x81, __u32)
|
2024-12-13 19:34:47 +00:00
|
|
|
#define NTSYNC_IOC_MUTEX_UNLOCK _IOWR('N', 0x85, struct ntsync_mutex_args)
|
2024-12-13 19:34:48 +00:00
|
|
|
#define NTSYNC_IOC_MUTEX_KILL _IOW ('N', 0x86, __u32)
|
2024-12-13 19:34:50 +00:00
|
|
|
#define NTSYNC_IOC_EVENT_SET _IOR ('N', 0x88, __u32)
|
2024-12-13 19:34:51 +00:00
|
|
|
#define NTSYNC_IOC_EVENT_RESET _IOR ('N', 0x89, __u32)
|
2024-12-13 19:34:52 +00:00
|
|
|
#define NTSYNC_IOC_EVENT_PULSE _IOR ('N', 0x8a, __u32)
|
2024-12-13 19:34:53 +00:00
|
|
|
#define NTSYNC_IOC_SEM_READ _IOR ('N', 0x8b, struct ntsync_sem_args)
|
2024-12-13 19:34:54 +00:00
|
|
|
#define NTSYNC_IOC_MUTEX_READ _IOR ('N', 0x8c, struct ntsync_mutex_args)
|
2024-12-13 19:34:55 +00:00
|
|
|
#define NTSYNC_IOC_EVENT_READ _IOR ('N', 0x8d, struct ntsync_event_args)
|
2024-03-29 00:05:54 +00:00
|
|
|
|
2024-03-29 00:05:53 +00:00
|
|
|
#endif
|