Update for 6.7.6, update NTSync patches and remaster build files
This commit is contained in:
parent
2f2ac440b5
commit
f5cd997d27
|
@ -1,24 +1,24 @@
|
||||||
#
|
#
|
||||||
# Automatically generated file; DO NOT EDIT.
|
# Automatically generated file; DO NOT EDIT.
|
||||||
# Linux/x86 6.7.0-zen1 Kernel Configuration
|
# Linux/x86 6.7.6-zen1 Kernel Configuration
|
||||||
#
|
#
|
||||||
CONFIG_CC_VERSION_TEXT="gcc (GCC) 12.2.0"
|
CONFIG_CC_VERSION_TEXT="gcc (GCC) 13.2.1 20231205 (Red Hat 13.2.1-6)"
|
||||||
CONFIG_CC_IS_GCC=y
|
CONFIG_CC_IS_GCC=y
|
||||||
CONFIG_GCC_VERSION=120200
|
CONFIG_GCC_VERSION=130201
|
||||||
CONFIG_CLANG_VERSION=0
|
CONFIG_CLANG_VERSION=0
|
||||||
CONFIG_AS_IS_GNU=y
|
CONFIG_AS_IS_GNU=y
|
||||||
CONFIG_AS_VERSION=23900
|
CONFIG_AS_VERSION=24000
|
||||||
CONFIG_LD_IS_BFD=y
|
CONFIG_LD_IS_BFD=y
|
||||||
CONFIG_LD_VERSION=23900
|
CONFIG_LD_VERSION=24000
|
||||||
CONFIG_LLD_VERSION=0
|
CONFIG_LLD_VERSION=0
|
||||||
CONFIG_CC_CAN_LINK=y
|
CONFIG_CC_CAN_LINK=y
|
||||||
CONFIG_CC_CAN_LINK_STATIC=y
|
|
||||||
CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y
|
CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y
|
||||||
CONFIG_CC_HAS_ASM_GOTO_TIED_OUTPUT=y
|
CONFIG_CC_HAS_ASM_GOTO_TIED_OUTPUT=y
|
||||||
|
CONFIG_GCC_ASM_GOTO_OUTPUT_WORKAROUND=y
|
||||||
CONFIG_TOOLS_SUPPORT_RELR=y
|
CONFIG_TOOLS_SUPPORT_RELR=y
|
||||||
CONFIG_CC_HAS_ASM_INLINE=y
|
CONFIG_CC_HAS_ASM_INLINE=y
|
||||||
CONFIG_CC_HAS_NO_PROFILE_FN_ATTR=y
|
CONFIG_CC_HAS_NO_PROFILE_FN_ATTR=y
|
||||||
CONFIG_PAHOLE_VERSION=0
|
CONFIG_PAHOLE_VERSION=125
|
||||||
CONFIG_IRQ_WORK=y
|
CONFIG_IRQ_WORK=y
|
||||||
CONFIG_BUILDTIME_TABLE_SORT=y
|
CONFIG_BUILDTIME_TABLE_SORT=y
|
||||||
CONFIG_THREAD_INFO_IN_TASK=y
|
CONFIG_THREAD_INFO_IN_TASK=y
|
||||||
|
@ -400,6 +400,7 @@ CONFIG_INTEL_TDX_GUEST=y
|
||||||
# CONFIG_MZEN is not set
|
# CONFIG_MZEN is not set
|
||||||
# CONFIG_MZEN2 is not set
|
# CONFIG_MZEN2 is not set
|
||||||
# CONFIG_MZEN3 is not set
|
# CONFIG_MZEN3 is not set
|
||||||
|
# CONFIG_MZEN4 is not set
|
||||||
# CONFIG_MPSC is not set
|
# CONFIG_MPSC is not set
|
||||||
# CONFIG_MCORE2 is not set
|
# CONFIG_MCORE2 is not set
|
||||||
# CONFIG_MATOM is not set
|
# CONFIG_MATOM is not set
|
||||||
|
@ -422,6 +423,9 @@ CONFIG_INTEL_TDX_GUEST=y
|
||||||
# CONFIG_MSAPPHIRERAPIDS is not set
|
# CONFIG_MSAPPHIRERAPIDS is not set
|
||||||
# CONFIG_MROCKETLAKE is not set
|
# CONFIG_MROCKETLAKE is not set
|
||||||
# CONFIG_MALDERLAKE is not set
|
# CONFIG_MALDERLAKE is not set
|
||||||
|
# CONFIG_MRAPTORLAKE is not set
|
||||||
|
# CONFIG_MMETEORLAKE is not set
|
||||||
|
# CONFIG_MEMERALDRAPIDS is not set
|
||||||
# CONFIG_GENERIC_CPU is not set
|
# CONFIG_GENERIC_CPU is not set
|
||||||
# CONFIG_GENERIC_CPU2 is not set
|
# CONFIG_GENERIC_CPU2 is not set
|
||||||
# CONFIG_GENERIC_CPU3 is not set
|
# CONFIG_GENERIC_CPU3 is not set
|
||||||
|
@ -899,9 +903,9 @@ CONFIG_SOFTIRQ_ON_OWN_STACK=y
|
||||||
CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
|
CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
|
||||||
CONFIG_HAVE_ARCH_MMAP_RND_BITS=y
|
CONFIG_HAVE_ARCH_MMAP_RND_BITS=y
|
||||||
CONFIG_HAVE_EXIT_THREAD=y
|
CONFIG_HAVE_EXIT_THREAD=y
|
||||||
CONFIG_ARCH_MMAP_RND_BITS=28
|
CONFIG_ARCH_MMAP_RND_BITS=32
|
||||||
CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS=y
|
CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS=y
|
||||||
CONFIG_ARCH_MMAP_RND_COMPAT_BITS=8
|
CONFIG_ARCH_MMAP_RND_COMPAT_BITS=16
|
||||||
CONFIG_HAVE_ARCH_COMPAT_MMAP_BASES=y
|
CONFIG_HAVE_ARCH_COMPAT_MMAP_BASES=y
|
||||||
CONFIG_PAGE_SIZE_LESS_THAN_64KB=y
|
CONFIG_PAGE_SIZE_LESS_THAN_64KB=y
|
||||||
CONFIG_PAGE_SIZE_LESS_THAN_256KB=y
|
CONFIG_PAGE_SIZE_LESS_THAN_256KB=y
|
||||||
|
@ -950,7 +954,6 @@ CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y
|
||||||
# end of GCOV-based kernel profiling
|
# end of GCOV-based kernel profiling
|
||||||
|
|
||||||
CONFIG_HAVE_GCC_PLUGINS=y
|
CONFIG_HAVE_GCC_PLUGINS=y
|
||||||
# CONFIG_GCC_PLUGINS is not set
|
|
||||||
CONFIG_FUNCTION_ALIGNMENT_4B=y
|
CONFIG_FUNCTION_ALIGNMENT_4B=y
|
||||||
CONFIG_FUNCTION_ALIGNMENT_16B=y
|
CONFIG_FUNCTION_ALIGNMENT_16B=y
|
||||||
CONFIG_FUNCTION_ALIGNMENT=16
|
CONFIG_FUNCTION_ALIGNMENT=16
|
||||||
|
@ -4235,7 +4238,6 @@ CONFIG_TOUCHSCREEN_PENMOUNT=m
|
||||||
CONFIG_TOUCHSCREEN_EDT_FT5X06=m
|
CONFIG_TOUCHSCREEN_EDT_FT5X06=m
|
||||||
CONFIG_TOUCHSCREEN_TOUCHRIGHT=m
|
CONFIG_TOUCHSCREEN_TOUCHRIGHT=m
|
||||||
CONFIG_TOUCHSCREEN_TOUCHWIN=m
|
CONFIG_TOUCHSCREEN_TOUCHWIN=m
|
||||||
CONFIG_TOUCHSCREEN_TI_AM335X_TSC=m
|
|
||||||
CONFIG_TOUCHSCREEN_PIXCIR=m
|
CONFIG_TOUCHSCREEN_PIXCIR=m
|
||||||
CONFIG_TOUCHSCREEN_WDT87XX_I2C=m
|
CONFIG_TOUCHSCREEN_WDT87XX_I2C=m
|
||||||
# CONFIG_TOUCHSCREEN_WM831X is not set
|
# CONFIG_TOUCHSCREEN_WM831X is not set
|
||||||
|
@ -5491,7 +5493,6 @@ CONFIG_MFD_SM501=m
|
||||||
CONFIG_MFD_SM501_GPIO=y
|
CONFIG_MFD_SM501_GPIO=y
|
||||||
CONFIG_MFD_SKY81452=m
|
CONFIG_MFD_SKY81452=m
|
||||||
CONFIG_MFD_SYSCON=y
|
CONFIG_MFD_SYSCON=y
|
||||||
CONFIG_MFD_TI_AM335X_TSCADC=m
|
|
||||||
CONFIG_MFD_LP3943=m
|
CONFIG_MFD_LP3943=m
|
||||||
# CONFIG_MFD_LP8788 is not set
|
# CONFIG_MFD_LP8788 is not set
|
||||||
# CONFIG_MFD_TI_LMU is not set
|
# CONFIG_MFD_TI_LMU is not set
|
||||||
|
@ -7081,7 +7082,6 @@ CONFIG_SND_SOC_FSL_AUDMIX=m
|
||||||
CONFIG_SND_SOC_FSL_MICFIL=m
|
CONFIG_SND_SOC_FSL_MICFIL=m
|
||||||
# CONFIG_SND_SOC_FSL_XCVR is not set
|
# CONFIG_SND_SOC_FSL_XCVR is not set
|
||||||
CONFIG_SND_SOC_FSL_UTILS=m
|
CONFIG_SND_SOC_FSL_UTILS=m
|
||||||
CONFIG_SND_SOC_FSL_RPMSG=m
|
|
||||||
# CONFIG_SND_SOC_IMX_AUDMUX is not set
|
# CONFIG_SND_SOC_IMX_AUDMUX is not set
|
||||||
# end of SoC Audio for Freescale CPUs
|
# end of SoC Audio for Freescale CPUs
|
||||||
|
|
||||||
|
@ -9382,7 +9382,6 @@ CONFIG_TI_ADS8344=m
|
||||||
CONFIG_TI_ADS8688=m
|
CONFIG_TI_ADS8688=m
|
||||||
CONFIG_TI_ADS124S08=m
|
CONFIG_TI_ADS124S08=m
|
||||||
CONFIG_TI_ADS131E08=m
|
CONFIG_TI_ADS131E08=m
|
||||||
CONFIG_TI_AM335X_ADC=m
|
|
||||||
# CONFIG_TI_LMP92064 is not set
|
# CONFIG_TI_LMP92064 is not set
|
||||||
CONFIG_TI_TLC4541=m
|
CONFIG_TI_TLC4541=m
|
||||||
CONFIG_TI_TSC2046=m
|
CONFIG_TI_TSC2046=m
|
||||||
|
@ -10972,6 +10971,10 @@ CONFIG_DEBUG_INFO_COMPRESSED_NONE=y
|
||||||
# CONFIG_DEBUG_INFO_COMPRESSED_ZLIB is not set
|
# CONFIG_DEBUG_INFO_COMPRESSED_ZLIB is not set
|
||||||
# CONFIG_DEBUG_INFO_SPLIT is not set
|
# CONFIG_DEBUG_INFO_SPLIT is not set
|
||||||
CONFIG_DEBUG_INFO_BTF=y
|
CONFIG_DEBUG_INFO_BTF=y
|
||||||
|
CONFIG_PAHOLE_HAS_SPLIT_BTF=y
|
||||||
|
CONFIG_PAHOLE_HAS_LANG_EXCLUDE=y
|
||||||
|
CONFIG_DEBUG_INFO_BTF_MODULES=y
|
||||||
|
# CONFIG_MODULE_ALLOW_BTF_MISMATCH is not set
|
||||||
# CONFIG_GDB_SCRIPTS is not set
|
# CONFIG_GDB_SCRIPTS is not set
|
||||||
CONFIG_FRAME_WARN=1024
|
CONFIG_FRAME_WARN=1024
|
||||||
CONFIG_STRIP_ASM_SYMS=y
|
CONFIG_STRIP_ASM_SYMS=y
|
||||||
|
|
|
@ -5,19 +5,19 @@ to correspond to a single NT virtual machine.
|
||||||
|
|
||||||
Signed-off-by: Elizabeth Figura <zfigura@codeweavers.com>
|
Signed-off-by: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
---
|
---
|
||||||
drivers/misc/Kconfig | 9 ++++++++
|
drivers/misc/Kconfig | 11 +++++++++
|
||||||
drivers/misc/Makefile | 1 +
|
drivers/misc/Makefile | 1 +
|
||||||
drivers/misc/ntsync.c | 53 +++++++++++++++++++++++++++++++++++++++++++
|
drivers/misc/ntsync.c | 52 +++++++++++++++++++++++++++++++++++++++++++
|
||||||
3 files changed, 63 insertions(+)
|
3 files changed, 64 insertions(+)
|
||||||
create mode 100644 drivers/misc/ntsync.c
|
create mode 100644 drivers/misc/ntsync.c
|
||||||
|
|
||||||
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
|
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
|
||||||
index 4fb291f0bf7c..bdd8a71bd853 100644
|
index 4fb291f0bf7c..801ed229ed7d 100644
|
||||||
--- a/drivers/misc/Kconfig
|
--- a/drivers/misc/Kconfig
|
||||||
+++ b/drivers/misc/Kconfig
|
+++ b/drivers/misc/Kconfig
|
||||||
@@ -504,6 +504,15 @@ config OPEN_DICE
|
@@ -506,6 +506,17 @@ config OPEN_DICE
|
||||||
measured boot flow. Userspace can use CDIs for remote attestation
|
|
||||||
and sealing.
|
If unsure, say N.
|
||||||
|
|
||||||
+config NTSYNC
|
+config NTSYNC
|
||||||
+ tristate "NT synchronization primitive emulation"
|
+ tristate "NT synchronization primitive emulation"
|
||||||
|
@ -28,9 +28,11 @@ index 4fb291f0bf7c..bdd8a71bd853 100644
|
||||||
+ To compile this driver as a module, choose M here: the
|
+ To compile this driver as a module, choose M here: the
|
||||||
+ module will be called ntsync.
|
+ module will be called ntsync.
|
||||||
+
|
+
|
||||||
If unsure, say N.
|
+ If unsure, say N.
|
||||||
|
+
|
||||||
config VCPU_STALL_DETECTOR
|
config VCPU_STALL_DETECTOR
|
||||||
|
tristate "Guest vCPU stall detector"
|
||||||
|
depends on OF && HAS_IOMEM
|
||||||
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
|
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
|
||||||
index ea6ea5bbbc9c..153a3f4837e8 100644
|
index ea6ea5bbbc9c..153a3f4837e8 100644
|
||||||
--- a/drivers/misc/Makefile
|
--- a/drivers/misc/Makefile
|
||||||
|
@ -45,15 +47,15 @@ index ea6ea5bbbc9c..153a3f4837e8 100644
|
||||||
obj-$(CONFIG_GP_PCI1XXXX) += mchp_pci1xxxx/
|
obj-$(CONFIG_GP_PCI1XXXX) += mchp_pci1xxxx/
|
||||||
diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c
|
diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c
|
||||||
new file mode 100644
|
new file mode 100644
|
||||||
index 000000000000..9424c6210e51
|
index 000000000000..bd76e653d83e
|
||||||
--- /dev/null
|
--- /dev/null
|
||||||
+++ b/drivers/misc/ntsync.c
|
+++ b/drivers/misc/ntsync.c
|
||||||
@@ -0,0 +1,53 @@
|
@@ -0,0 +1,52 @@
|
||||||
+// SPDX-License-Identifier: GPL-2.0-only
|
+// SPDX-License-Identifier: GPL-2.0-only
|
||||||
+/*
|
+/*
|
||||||
+ * ntsync.c - Kernel driver for NT synchronization primitives
|
+ * ntsync.c - Kernel driver for NT synchronization primitives
|
||||||
+ *
|
+ *
|
||||||
+ * Copyright (C) 2021-2022 Elizabeth Figura
|
+ * Copyright (C) 2024 Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
+ */
|
+ */
|
||||||
+
|
+
|
||||||
+#include <linux/fs.h>
|
+#include <linux/fs.h>
|
||||||
|
@ -86,7 +88,7 @@ index 000000000000..9424c6210e51
|
||||||
+ .open = ntsync_char_open,
|
+ .open = ntsync_char_open,
|
||||||
+ .release = ntsync_char_release,
|
+ .release = ntsync_char_release,
|
||||||
+ .unlocked_ioctl = ntsync_char_ioctl,
|
+ .unlocked_ioctl = ntsync_char_ioctl,
|
||||||
+ .compat_ioctl = ntsync_char_ioctl,
|
+ .compat_ioctl = compat_ptr_ioctl,
|
||||||
+ .llseek = no_llseek,
|
+ .llseek = no_llseek,
|
||||||
+};
|
+};
|
||||||
+
|
+
|
||||||
|
@ -98,9 +100,8 @@ index 000000000000..9424c6210e51
|
||||||
+
|
+
|
||||||
+module_misc_device(ntsync_misc);
|
+module_misc_device(ntsync_misc);
|
||||||
+
|
+
|
||||||
+MODULE_AUTHOR("Elizabeth Figura");
|
+MODULE_AUTHOR("Elizabeth Figura <zfigura@codeweavers.com>");
|
||||||
+MODULE_DESCRIPTION("Kernel driver for NT synchronization primitives");
|
+MODULE_DESCRIPTION("Kernel driver for NT synchronization primitives");
|
||||||
+MODULE_LICENSE("GPL");
|
+MODULE_LICENSE("GPL");
|
||||||
+MODULE_ALIAS("devname:" NTSYNC_NAME);
|
|
||||||
--
|
--
|
||||||
2.43.0
|
2.43.0
|
|
@ -1,68 +0,0 @@
|
||||||
Signed-off-by: Elizabeth Figura <zfigura@codeweavers.com>
|
|
||||||
---
|
|
||||||
Documentation/admin-guide/devices.txt | 3 ++-
|
|
||||||
Documentation/userspace-api/ioctl/ioctl-number.rst | 2 ++
|
|
||||||
drivers/misc/ntsync.c | 3 ++-
|
|
||||||
include/linux/miscdevice.h | 1 +
|
|
||||||
4 files changed, 7 insertions(+), 2 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/Documentation/admin-guide/devices.txt b/Documentation/admin-guide/devices.txt
|
|
||||||
index 94c98be1329a..041404397ee5 100644
|
|
||||||
--- a/Documentation/admin-guide/devices.txt
|
|
||||||
+++ b/Documentation/admin-guide/devices.txt
|
|
||||||
@@ -376,8 +376,9 @@
|
|
||||||
240 = /dev/userio Serio driver testing device
|
|
||||||
241 = /dev/vhost-vsock Host kernel driver for virtio vsock
|
|
||||||
242 = /dev/rfkill Turning off radio transmissions (rfkill)
|
|
||||||
+ 243 = /dev/ntsync NT synchronization primitive device
|
|
||||||
|
|
||||||
- 243-254 Reserved for local use
|
|
||||||
+ 244-254 Reserved for local use
|
|
||||||
255 Reserved for MISC_DYNAMIC_MINOR
|
|
||||||
|
|
||||||
11 char Raw keyboard device (Linux/SPARC only)
|
|
||||||
diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst
|
|
||||||
index 457e16f06e04..a1326a5bc2e0 100644
|
|
||||||
--- a/Documentation/userspace-api/ioctl/ioctl-number.rst
|
|
||||||
+++ b/Documentation/userspace-api/ioctl/ioctl-number.rst
|
|
||||||
@@ -378,6 +378,8 @@ Code Seq# Include File Comments
|
|
||||||
<mailto:thomas@winischhofer.net>
|
|
||||||
0xF6 all LTTng Linux Trace Toolkit Next Generation
|
|
||||||
<mailto:mathieu.desnoyers@efficios.com>
|
|
||||||
+0xF7 00-1F uapi/linux/ntsync.h NT synchronization primitives
|
|
||||||
+ <mailto:wine-devel@winehq.org>
|
|
||||||
0xF8 all arch/x86/include/uapi/asm/amd_hsmp.h AMD HSMP EPYC system management interface driver
|
|
||||||
<mailto:nchatrad@amd.com>
|
|
||||||
0xFD all linux/dm-ioctl.h
|
|
||||||
diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c
|
|
||||||
index 9424c6210e51..84b498e2b2d5 100644
|
|
||||||
--- a/drivers/misc/ntsync.c
|
|
||||||
+++ b/drivers/misc/ntsync.c
|
|
||||||
@@ -40,7 +40,7 @@ static const struct file_operations ntsync_fops = {
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct miscdevice ntsync_misc = {
|
|
||||||
- .minor = MISC_DYNAMIC_MINOR,
|
|
||||||
+ .minor = NTSYNC_MINOR,
|
|
||||||
.name = NTSYNC_NAME,
|
|
||||||
.fops = &ntsync_fops,
|
|
||||||
};
|
|
||||||
@@ -51,3 +51,4 @@ MODULE_AUTHOR("Elizabeth Figura");
|
|
||||||
MODULE_DESCRIPTION("Kernel driver for NT synchronization primitives");
|
|
||||||
MODULE_LICENSE("GPL");
|
|
||||||
MODULE_ALIAS("devname:" NTSYNC_NAME);
|
|
||||||
+MODULE_ALIAS_MISCDEV(NTSYNC_MINOR);
|
|
||||||
diff --git a/include/linux/miscdevice.h b/include/linux/miscdevice.h
|
|
||||||
index c0fea6ca5076..fe5d9366fdf7 100644
|
|
||||||
--- a/include/linux/miscdevice.h
|
|
||||||
+++ b/include/linux/miscdevice.h
|
|
||||||
@@ -71,6 +71,7 @@
|
|
||||||
#define USERIO_MINOR 240
|
|
||||||
#define VHOST_VSOCK_MINOR 241
|
|
||||||
#define RFKILL_MINOR 242
|
|
||||||
+#define NTSYNC_MINOR 243
|
|
||||||
#define MISC_DYNAMIC_MINOR 255
|
|
||||||
|
|
||||||
struct device;
|
|
||||||
--
|
|
||||||
2.43.0
|
|
|
@ -0,0 +1,228 @@
|
||||||
|
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.
|
||||||
|
|
||||||
|
Objects hold a pointer to the ntsync_device that created them. The device's
|
||||||
|
reference count is driven by struct file.
|
||||||
|
|
||||||
|
Signed-off-by: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
---
|
||||||
|
.../userspace-api/ioctl/ioctl-number.rst | 2 +
|
||||||
|
drivers/misc/ntsync.c | 131 ++++++++++++++++++
|
||||||
|
include/uapi/linux/ntsync.h | 21 +++
|
||||||
|
3 files changed, 154 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:wine-devel@winehq.org>
|
||||||
|
'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 bd76e653d83e..20158ec148bc 100644
|
||||||
|
--- a/drivers/misc/ntsync.c
|
||||||
|
+++ b/drivers/misc/ntsync.c
|
||||||
|
@@ -5,26 +5,157 @@
|
||||||
|
* Copyright (C) 2024 Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
+#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,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * Individual synchronization primitives are represented by
|
||||||
|
+ * struct ntsync_obj, and each primitive is backed by a file.
|
||||||
|
+ *
|
||||||
|
+ * The whole namespace is represented by a struct ntsync_device also
|
||||||
|
+ * backed by a file.
|
||||||
|
+ *
|
||||||
|
+ * Both rely on struct file for reference counting. Individual
|
||||||
|
+ * ntsync_obj objects take a reference to the device when created.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+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;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static int ntsync_obj_release(struct inode *inode, struct file *file)
|
||||||
|
+{
|
||||||
|
+ struct ntsync_obj *obj = file->private_data;
|
||||||
|
+
|
||||||
|
+ fput(obj->dev->file);
|
||||||
|
+ kfree(obj);
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static const struct file_operations ntsync_obj_fops = {
|
||||||
|
+ .owner = THIS_MODULE,
|
||||||
|
+ .release = ntsync_obj_release,
|
||||||
|
+ .llseek = no_llseek,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct ntsync_obj *ntsync_alloc_obj(struct ntsync_device *dev,
|
||||||
|
+ enum ntsync_type type)
|
||||||
|
+{
|
||||||
|
+ struct ntsync_obj *obj;
|
||||||
|
+
|
||||||
|
+ obj = kzalloc(sizeof(*obj), GFP_KERNEL);
|
||||||
|
+ if (!obj)
|
||||||
|
+ return NULL;
|
||||||
|
+ obj->type = type;
|
||||||
|
+ obj->dev = dev;
|
||||||
|
+ get_file(dev->file);
|
||||||
|
+
|
||||||
|
+ return obj;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int ntsync_obj_get_fd(struct ntsync_obj *obj)
|
||||||
|
+{
|
||||||
|
+ struct file *file;
|
||||||
|
+ int fd;
|
||||||
|
+
|
||||||
|
+ fd = get_unused_fd_flags(O_CLOEXEC);
|
||||||
|
+ if (fd < 0)
|
||||||
|
+ return fd;
|
||||||
|
+ file = anon_inode_getfile("ntsync", &ntsync_obj_fops, obj, O_RDWR);
|
||||||
|
+ if (IS_ERR(file)) {
|
||||||
|
+ put_unused_fd(fd);
|
||||||
|
+ return PTR_ERR(file);
|
||||||
|
+ }
|
||||||
|
+ obj->file = file;
|
||||||
|
+ fd_install(fd, file);
|
||||||
|
+
|
||||||
|
+ return fd;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int ntsync_create_sem(struct ntsync_device *dev, void __user *argp)
|
||||||
|
+{
|
||||||
|
+ struct ntsync_sem_args __user *user_args = argp;
|
||||||
|
+ struct ntsync_sem_args args;
|
||||||
|
+ struct ntsync_obj *sem;
|
||||||
|
+ int fd;
|
||||||
|
+
|
||||||
|
+ if (copy_from_user(&args, argp, sizeof(args)))
|
||||||
|
+ return -EFAULT;
|
||||||
|
+
|
||||||
|
+ if (args.count > args.max)
|
||||||
|
+ return -EINVAL;
|
||||||
|
+
|
||||||
|
+ sem = ntsync_alloc_obj(dev, NTSYNC_TYPE_SEM);
|
||||||
|
+ if (!sem)
|
||||||
|
+ return -ENOMEM;
|
||||||
|
+ sem->u.sem.count = args.count;
|
||||||
|
+ sem->u.sem.max = args.max;
|
||||||
|
+ fd = ntsync_obj_get_fd(sem);
|
||||||
|
+ if (fd < 0) {
|
||||||
|
+ kfree(sem);
|
||||||
|
+ return fd;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return put_user(fd, &user_args->sem);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static int ntsync_char_open(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
+ struct ntsync_device *dev;
|
||||||
|
+
|
||||||
|
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
|
||||||
|
+ if (!dev)
|
||||||
|
+ return -ENOMEM;
|
||||||
|
+
|
||||||
|
+ file->private_data = dev;
|
||||||
|
+ dev->file = file;
|
||||||
|
return nonseekable_open(inode, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ntsync_char_release(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
+ struct ntsync_device *dev = file->private_data;
|
||||||
|
+
|
||||||
|
+ kfree(dev);
|
||||||
|
+
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long ntsync_char_ioctl(struct file *file, unsigned int cmd,
|
||||||
|
unsigned long parm)
|
||||||
|
{
|
||||||
|
+ struct ntsync_device *dev = file->private_data;
|
||||||
|
+ void __user *argp = (void __user *)parm;
|
||||||
|
+
|
||||||
|
switch (cmd) {
|
||||||
|
+ case NTSYNC_IOC_CREATE_SEM:
|
||||||
|
+ return ntsync_create_sem(dev, argp);
|
||||||
|
default:
|
||||||
|
return -ENOIOCTLCMD;
|
||||||
|
}
|
||||||
|
diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h
|
||||||
|
new file mode 100644
|
||||||
|
index 000000000000..6a4867a6c97b
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/include/uapi/linux/ntsync.h
|
||||||
|
@@ -0,0 +1,21 @@
|
||||||
|
+/* 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 sem;
|
||||||
|
+ __u32 count;
|
||||||
|
+ __u32 max;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+#define NTSYNC_IOC_CREATE_SEM _IOWR('N', 0x80, struct ntsync_sem_args)
|
||||||
|
+
|
||||||
|
+#endif
|
||||||
|
--
|
||||||
|
2.43.0
|
|
@ -1,191 +0,0 @@
|
||||||
These correspond to the NT syscalls NtCreateSemaphore() and NtClose().
|
|
||||||
Unlike those functions, however, these ioctls do not handle object names, or
|
|
||||||
lookup of existing objects, or handle reference counting, but simply create the
|
|
||||||
underlying primitive. The user space emulator is expected to implement those
|
|
||||||
functions if they are required.
|
|
||||||
|
|
||||||
Signed-off-by: Elizabeth Figura <zfigura@codeweavers.com>
|
|
||||||
---
|
|
||||||
drivers/misc/ntsync.c | 117 ++++++++++++++++++++++++++++++++++++
|
|
||||||
include/uapi/linux/ntsync.h | 25 ++++++++
|
|
||||||
2 files changed, 142 insertions(+)
|
|
||||||
create mode 100644 include/uapi/linux/ntsync.h
|
|
||||||
|
|
||||||
diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c
|
|
||||||
index 84b498e2b2d5..3287b94be351 100644
|
|
||||||
--- a/drivers/misc/ntsync.c
|
|
||||||
+++ b/drivers/misc/ntsync.c
|
|
||||||
@@ -8,23 +8,140 @@
|
|
||||||
#include <linux/fs.h>
|
|
||||||
#include <linux/miscdevice.h>
|
|
||||||
#include <linux/module.h>
|
|
||||||
+#include <linux/slab.h>
|
|
||||||
+#include <linux/xarray.h>
|
|
||||||
+#include <uapi/linux/ntsync.h>
|
|
||||||
|
|
||||||
#define NTSYNC_NAME "ntsync"
|
|
||||||
|
|
||||||
+enum ntsync_type {
|
|
||||||
+ NTSYNC_TYPE_SEM,
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+struct ntsync_obj {
|
|
||||||
+ struct rcu_head rhead;
|
|
||||||
+ struct kref refcount;
|
|
||||||
+
|
|
||||||
+ enum ntsync_type type;
|
|
||||||
+
|
|
||||||
+ union {
|
|
||||||
+ struct {
|
|
||||||
+ __u32 count;
|
|
||||||
+ __u32 max;
|
|
||||||
+ } sem;
|
|
||||||
+ } u;
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+struct ntsync_device {
|
|
||||||
+ struct xarray objects;
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static void destroy_obj(struct kref *ref)
|
|
||||||
+{
|
|
||||||
+ struct ntsync_obj *obj = container_of(ref, struct ntsync_obj, refcount);
|
|
||||||
+
|
|
||||||
+ kfree_rcu(obj, rhead);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void put_obj(struct ntsync_obj *obj)
|
|
||||||
+{
|
|
||||||
+ kref_put(&obj->refcount, destroy_obj);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
static int ntsync_char_open(struct inode *inode, struct file *file)
|
|
||||||
{
|
|
||||||
+ struct ntsync_device *dev;
|
|
||||||
+
|
|
||||||
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
|
|
||||||
+ if (!dev)
|
|
||||||
+ return -ENOMEM;
|
|
||||||
+
|
|
||||||
+ xa_init_flags(&dev->objects, XA_FLAGS_ALLOC);
|
|
||||||
+
|
|
||||||
+ file->private_data = dev;
|
|
||||||
return nonseekable_open(inode, file);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ntsync_char_release(struct inode *inode, struct file *file)
|
|
||||||
{
|
|
||||||
+ struct ntsync_device *dev = file->private_data;
|
|
||||||
+ struct ntsync_obj *obj;
|
|
||||||
+ unsigned long id;
|
|
||||||
+
|
|
||||||
+ xa_for_each(&dev->objects, id, obj)
|
|
||||||
+ put_obj(obj);
|
|
||||||
+
|
|
||||||
+ xa_destroy(&dev->objects);
|
|
||||||
+
|
|
||||||
+ kfree(dev);
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void init_obj(struct ntsync_obj *obj)
|
|
||||||
+{
|
|
||||||
+ kref_init(&obj->refcount);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int ntsync_create_sem(struct ntsync_device *dev, void __user *argp)
|
|
||||||
+{
|
|
||||||
+ struct ntsync_sem_args __user *user_args = argp;
|
|
||||||
+ struct ntsync_sem_args args;
|
|
||||||
+ struct ntsync_obj *sem;
|
|
||||||
+ __u32 id;
|
|
||||||
+ int ret;
|
|
||||||
+
|
|
||||||
+ if (copy_from_user(&args, argp, sizeof(args)))
|
|
||||||
+ return -EFAULT;
|
|
||||||
+
|
|
||||||
+ if (args.count > args.max)
|
|
||||||
+ return -EINVAL;
|
|
||||||
+
|
|
||||||
+ sem = kzalloc(sizeof(*sem), GFP_KERNEL);
|
|
||||||
+ if (!sem)
|
|
||||||
+ return -ENOMEM;
|
|
||||||
+
|
|
||||||
+ init_obj(sem);
|
|
||||||
+ sem->type = NTSYNC_TYPE_SEM;
|
|
||||||
+ sem->u.sem.count = args.count;
|
|
||||||
+ sem->u.sem.max = args.max;
|
|
||||||
+
|
|
||||||
+ ret = xa_alloc(&dev->objects, &id, sem, xa_limit_32b, GFP_KERNEL);
|
|
||||||
+ if (ret < 0) {
|
|
||||||
+ kfree(sem);
|
|
||||||
+ return ret;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ return put_user(id, &user_args->sem);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int ntsync_delete(struct ntsync_device *dev, void __user *argp)
|
|
||||||
+{
|
|
||||||
+ struct ntsync_obj *obj;
|
|
||||||
+ __u32 id;
|
|
||||||
+
|
|
||||||
+ if (get_user(id, (__u32 __user *)argp))
|
|
||||||
+ return -EFAULT;
|
|
||||||
+
|
|
||||||
+ obj = xa_erase(&dev->objects, id);
|
|
||||||
+ if (!obj)
|
|
||||||
+ return -EINVAL;
|
|
||||||
+
|
|
||||||
+ put_obj(obj);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static long ntsync_char_ioctl(struct file *file, unsigned int cmd,
|
|
||||||
unsigned long parm)
|
|
||||||
{
|
|
||||||
+ struct ntsync_device *dev = file->private_data;
|
|
||||||
+ void __user *argp = (void __user *)parm;
|
|
||||||
+
|
|
||||||
switch (cmd) {
|
|
||||||
+ case NTSYNC_IOC_CREATE_SEM:
|
|
||||||
+ return ntsync_create_sem(dev, argp);
|
|
||||||
+ case NTSYNC_IOC_DELETE:
|
|
||||||
+ return ntsync_delete(dev, argp);
|
|
||||||
default:
|
|
||||||
return -ENOIOCTLCMD;
|
|
||||||
}
|
|
||||||
diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h
|
|
||||||
new file mode 100644
|
|
||||||
index 000000000000..d97afc138dcc
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/include/uapi/linux/ntsync.h
|
|
||||||
@@ -0,0 +1,25 @@
|
|
||||||
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
|
||||||
+/*
|
|
||||||
+ * Kernel support for NT synchronization primitive emulation
|
|
||||||
+ *
|
|
||||||
+ * Copyright (C) 2021-2022 Elizabeth Figura
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+#ifndef __LINUX_NTSYNC_H
|
|
||||||
+#define __LINUX_NTSYNC_H
|
|
||||||
+
|
|
||||||
+#include <linux/types.h>
|
|
||||||
+
|
|
||||||
+struct ntsync_sem_args {
|
|
||||||
+ __u32 sem;
|
|
||||||
+ __u32 count;
|
|
||||||
+ __u32 max;
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+#define NTSYNC_IOC_BASE 0xf7
|
|
||||||
+
|
|
||||||
+#define NTSYNC_IOC_CREATE_SEM _IOWR(NTSYNC_IOC_BASE, 0, \
|
|
||||||
+ struct ntsync_sem_args)
|
|
||||||
+#define NTSYNC_IOC_DELETE _IOW (NTSYNC_IOC_BASE, 1, __u32)
|
|
||||||
+
|
|
||||||
+#endif
|
|
||||||
--
|
|
||||||
2.43.0
|
|
|
@ -0,0 +1,147 @@
|
||||||
|
This corresponds to the NT syscall NtReleaseSemaphore().
|
||||||
|
|
||||||
|
This increases the semaphore's internal counter by the given value, and returns
|
||||||
|
the previous value. If the counter would overflow the defined maximum, the
|
||||||
|
function instead fails and returns -EOVERFLOW.
|
||||||
|
|
||||||
|
Signed-off-by: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
---
|
||||||
|
drivers/misc/ntsync.c | 72 +++++++++++++++++++++++++++++++++++--
|
||||||
|
include/uapi/linux/ntsync.h | 2 ++
|
||||||
|
2 files changed, 71 insertions(+), 3 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c
|
||||||
|
index 20158ec148bc..3c2f743c58b0 100644
|
||||||
|
--- a/drivers/misc/ntsync.c
|
||||||
|
+++ b/drivers/misc/ntsync.c
|
||||||
|
@@ -10,7 +10,9 @@
|
||||||
|
#include <linux/fs.h>
|
||||||
|
#include <linux/miscdevice.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
+#include <linux/overflow.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
+#include <linux/spinlock.h>
|
||||||
|
#include <uapi/linux/ntsync.h>
|
||||||
|
|
||||||
|
#define NTSYNC_NAME "ntsync"
|
||||||
|
@@ -31,23 +33,70 @@ enum ntsync_type {
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct ntsync_obj {
|
||||||
|
+ spinlock_t lock;
|
||||||
|
+
|
||||||
|
enum ntsync_type type;
|
||||||
|
|
||||||
|
+ struct file *file;
|
||||||
|
+ struct ntsync_device *dev;
|
||||||
|
+
|
||||||
|
+ /* The following fields are protected by the object lock. */
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
__u32 count;
|
||||||
|
__u32 max;
|
||||||
|
} sem;
|
||||||
|
} u;
|
||||||
|
-
|
||||||
|
- struct file *file;
|
||||||
|
- struct ntsync_device *dev;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ntsync_device {
|
||||||
|
struct file *file;
|
||||||
|
};
|
||||||
|
|
||||||
|
+/*
|
||||||
|
+ * Actually change the semaphore state, returning -EOVERFLOW if it is made
|
||||||
|
+ * invalid.
|
||||||
|
+ */
|
||||||
|
+static int post_sem_state(struct ntsync_obj *sem, __u32 count)
|
||||||
|
+{
|
||||||
|
+ __u32 sum;
|
||||||
|
+
|
||||||
|
+ lockdep_assert_held(&sem->lock);
|
||||||
|
+
|
||||||
|
+ if (check_add_overflow(sem->u.sem.count, count, &sum) ||
|
||||||
|
+ sum > sem->u.sem.max)
|
||||||
|
+ return -EOVERFLOW;
|
||||||
|
+
|
||||||
|
+ sem->u.sem.count = sum;
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int ntsync_sem_post(struct ntsync_obj *sem, void __user *argp)
|
||||||
|
+{
|
||||||
|
+ __u32 __user *user_args = argp;
|
||||||
|
+ __u32 prev_count;
|
||||||
|
+ __u32 args;
|
||||||
|
+ int ret;
|
||||||
|
+
|
||||||
|
+ if (copy_from_user(&args, argp, sizeof(args)))
|
||||||
|
+ return -EFAULT;
|
||||||
|
+
|
||||||
|
+ if (sem->type != NTSYNC_TYPE_SEM)
|
||||||
|
+ return -EINVAL;
|
||||||
|
+
|
||||||
|
+ spin_lock(&sem->lock);
|
||||||
|
+
|
||||||
|
+ prev_count = sem->u.sem.count;
|
||||||
|
+ ret = post_sem_state(sem, args);
|
||||||
|
+
|
||||||
|
+ spin_unlock(&sem->lock);
|
||||||
|
+
|
||||||
|
+ if (!ret && put_user(prev_count, user_args))
|
||||||
|
+ ret = -EFAULT;
|
||||||
|
+
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static int ntsync_obj_release(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
struct ntsync_obj *obj = file->private_data;
|
||||||
|
@@ -58,9 +107,25 @@ static int ntsync_obj_release(struct inode *inode, struct file *file)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static long ntsync_obj_ioctl(struct file *file, unsigned int cmd,
|
||||||
|
+ unsigned long parm)
|
||||||
|
+{
|
||||||
|
+ struct ntsync_obj *obj = file->private_data;
|
||||||
|
+ void __user *argp = (void __user *)parm;
|
||||||
|
+
|
||||||
|
+ switch (cmd) {
|
||||||
|
+ case NTSYNC_IOC_SEM_POST:
|
||||||
|
+ return ntsync_sem_post(obj, argp);
|
||||||
|
+ default:
|
||||||
|
+ return -ENOIOCTLCMD;
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static const struct file_operations ntsync_obj_fops = {
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.release = ntsync_obj_release,
|
||||||
|
+ .unlocked_ioctl = ntsync_obj_ioctl,
|
||||||
|
+ .compat_ioctl = compat_ptr_ioctl,
|
||||||
|
.llseek = no_llseek,
|
||||||
|
};
|
||||||
|
|
||||||
|
@@ -75,6 +140,7 @@ static struct ntsync_obj *ntsync_alloc_obj(struct ntsync_device *dev,
|
||||||
|
obj->type = type;
|
||||||
|
obj->dev = dev;
|
||||||
|
get_file(dev->file);
|
||||||
|
+ spin_lock_init(&obj->lock);
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h
|
||||||
|
index 6a4867a6c97b..dcfa38fdc93c 100644
|
||||||
|
--- a/include/uapi/linux/ntsync.h
|
||||||
|
+++ b/include/uapi/linux/ntsync.h
|
||||||
|
@@ -18,4 +18,6 @@ struct ntsync_sem_args {
|
||||||
|
|
||||||
|
#define NTSYNC_IOC_CREATE_SEM _IOWR('N', 0x80, struct ntsync_sem_args)
|
||||||
|
|
||||||
|
+#define NTSYNC_IOC_SEM_POST _IOWR('N', 0x81, __u32)
|
||||||
|
+
|
||||||
|
#endif
|
||||||
|
--
|
||||||
|
2.43.0
|
|
@ -1,147 +0,0 @@
|
||||||
This corresponds to the NT syscall NtReleaseSemaphore().
|
|
||||||
|
|
||||||
Signed-off-by: Elizabeth Figura <zfigura@codeweavers.com>
|
|
||||||
---
|
|
||||||
drivers/misc/ntsync.c | 76 +++++++++++++++++++++++++++++++++++++
|
|
||||||
include/uapi/linux/ntsync.h | 2 +
|
|
||||||
2 files changed, 78 insertions(+)
|
|
||||||
|
|
||||||
diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c
|
|
||||||
index 3287b94be351..d1c91c2a4f1a 100644
|
|
||||||
--- a/drivers/misc/ntsync.c
|
|
||||||
+++ b/drivers/misc/ntsync.c
|
|
||||||
@@ -21,9 +21,11 @@ enum ntsync_type {
|
|
||||||
struct ntsync_obj {
|
|
||||||
struct rcu_head rhead;
|
|
||||||
struct kref refcount;
|
|
||||||
+ spinlock_t lock;
|
|
||||||
|
|
||||||
enum ntsync_type type;
|
|
||||||
|
|
||||||
+ /* The following fields are protected by the object lock. */
|
|
||||||
union {
|
|
||||||
struct {
|
|
||||||
__u32 count;
|
|
||||||
@@ -36,6 +38,19 @@ struct ntsync_device {
|
|
||||||
struct xarray objects;
|
|
||||||
};
|
|
||||||
|
|
||||||
+static struct ntsync_obj *get_obj(struct ntsync_device *dev, __u32 id)
|
|
||||||
+{
|
|
||||||
+ struct ntsync_obj *obj;
|
|
||||||
+
|
|
||||||
+ rcu_read_lock();
|
|
||||||
+ obj = xa_load(&dev->objects, id);
|
|
||||||
+ if (obj && !kref_get_unless_zero(&obj->refcount))
|
|
||||||
+ obj = NULL;
|
|
||||||
+ rcu_read_unlock();
|
|
||||||
+
|
|
||||||
+ return obj;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
static void destroy_obj(struct kref *ref)
|
|
||||||
{
|
|
||||||
struct ntsync_obj *obj = container_of(ref, struct ntsync_obj, refcount);
|
|
||||||
@@ -48,6 +63,18 @@ static void put_obj(struct ntsync_obj *obj)
|
|
||||||
kref_put(&obj->refcount, destroy_obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
+static struct ntsync_obj *get_obj_typed(struct ntsync_device *dev, __u32 id,
|
|
||||||
+ enum ntsync_type type)
|
|
||||||
+{
|
|
||||||
+ struct ntsync_obj *obj = get_obj(dev, id);
|
|
||||||
+
|
|
||||||
+ if (obj && obj->type != type) {
|
|
||||||
+ put_obj(obj);
|
|
||||||
+ return NULL;
|
|
||||||
+ }
|
|
||||||
+ return obj;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
static int ntsync_char_open(struct inode *inode, struct file *file)
|
|
||||||
{
|
|
||||||
struct ntsync_device *dev;
|
|
||||||
@@ -81,6 +108,7 @@ static int ntsync_char_release(struct inode *inode, struct file *file)
|
|
||||||
static void init_obj(struct ntsync_obj *obj)
|
|
||||||
{
|
|
||||||
kref_init(&obj->refcount);
|
|
||||||
+ spin_lock_init(&obj->lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ntsync_create_sem(struct ntsync_device *dev, void __user *argp)
|
|
||||||
@@ -131,6 +159,52 @@ static int ntsync_delete(struct ntsync_device *dev, void __user *argp)
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
+/*
|
|
||||||
+ * Actually change the semaphore state, returning -EOVERFLOW if it is made
|
|
||||||
+ * invalid.
|
|
||||||
+ */
|
|
||||||
+static int put_sem_state(struct ntsync_obj *sem, __u32 count)
|
|
||||||
+{
|
|
||||||
+ lockdep_assert_held(&sem->lock);
|
|
||||||
+
|
|
||||||
+ if (sem->u.sem.count + count < sem->u.sem.count ||
|
|
||||||
+ sem->u.sem.count + count > sem->u.sem.max)
|
|
||||||
+ return -EOVERFLOW;
|
|
||||||
+
|
|
||||||
+ sem->u.sem.count += count;
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int ntsync_put_sem(struct ntsync_device *dev, void __user *argp)
|
|
||||||
+{
|
|
||||||
+ struct ntsync_sem_args __user *user_args = argp;
|
|
||||||
+ struct ntsync_sem_args args;
|
|
||||||
+ struct ntsync_obj *sem;
|
|
||||||
+ __u32 prev_count;
|
|
||||||
+ int ret;
|
|
||||||
+
|
|
||||||
+ if (copy_from_user(&args, argp, sizeof(args)))
|
|
||||||
+ return -EFAULT;
|
|
||||||
+
|
|
||||||
+ sem = get_obj_typed(dev, args.sem, NTSYNC_TYPE_SEM);
|
|
||||||
+ if (!sem)
|
|
||||||
+ return -EINVAL;
|
|
||||||
+
|
|
||||||
+ spin_lock(&sem->lock);
|
|
||||||
+
|
|
||||||
+ prev_count = sem->u.sem.count;
|
|
||||||
+ ret = put_sem_state(sem, args.count);
|
|
||||||
+
|
|
||||||
+ spin_unlock(&sem->lock);
|
|
||||||
+
|
|
||||||
+ put_obj(sem);
|
|
||||||
+
|
|
||||||
+ if (!ret && put_user(prev_count, &user_args->count))
|
|
||||||
+ ret = -EFAULT;
|
|
||||||
+
|
|
||||||
+ return ret;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
static long ntsync_char_ioctl(struct file *file, unsigned int cmd,
|
|
||||||
unsigned long parm)
|
|
||||||
{
|
|
||||||
@@ -142,6 +216,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd,
|
|
||||||
return ntsync_create_sem(dev, argp);
|
|
||||||
case NTSYNC_IOC_DELETE:
|
|
||||||
return ntsync_delete(dev, argp);
|
|
||||||
+ case NTSYNC_IOC_PUT_SEM:
|
|
||||||
+ return ntsync_put_sem(dev, argp);
|
|
||||||
default:
|
|
||||||
return -ENOIOCTLCMD;
|
|
||||||
}
|
|
||||||
diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h
|
|
||||||
index d97afc138dcc..8c610d65f8ef 100644
|
|
||||||
--- a/include/uapi/linux/ntsync.h
|
|
||||||
+++ b/include/uapi/linux/ntsync.h
|
|
||||||
@@ -21,5 +21,7 @@ struct ntsync_sem_args {
|
|
||||||
#define NTSYNC_IOC_CREATE_SEM _IOWR(NTSYNC_IOC_BASE, 0, \
|
|
||||||
struct ntsync_sem_args)
|
|
||||||
#define NTSYNC_IOC_DELETE _IOW (NTSYNC_IOC_BASE, 1, __u32)
|
|
||||||
+#define NTSYNC_IOC_PUT_SEM _IOWR(NTSYNC_IOC_BASE, 2, \
|
|
||||||
+ struct ntsync_sem_args)
|
|
||||||
|
|
||||||
#endif
|
|
||||||
--
|
|
||||||
2.43.0
|
|
|
@ -3,29 +3,70 @@ NtWaitForMultipleObjects(). Specifically, it implements the behaviour where
|
||||||
the third argument (wait_any) is TRUE, and it does not handle alertable waits.
|
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.
|
Those features have been split out into separate patches to ease review.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
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 the MONOTONIC clock. 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.
|
||||||
|
|
||||||
|
Wait ioctls need to take a temporary reference to each object being waited on.
|
||||||
|
As with the device, the reference count of struct file is used for ntsync_obj.
|
||||||
|
|
||||||
Signed-off-by: Elizabeth Figura <zfigura@codeweavers.com>
|
Signed-off-by: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
---
|
---
|
||||||
drivers/misc/ntsync.c | 229 ++++++++++++++++++++++++++++++++++++
|
drivers/misc/ntsync.c | 239 ++++++++++++++++++++++++++++++++++++
|
||||||
include/uapi/linux/ntsync.h | 13 ++
|
include/uapi/linux/ntsync.h | 12 ++
|
||||||
2 files changed, 242 insertions(+)
|
2 files changed, 251 insertions(+)
|
||||||
|
|
||||||
diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c
|
diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c
|
||||||
index d1c91c2a4f1a..2e8d3c2d51a4 100644
|
index 3c2f743c58b0..ad93ca0f8b84 100644
|
||||||
--- a/drivers/misc/ntsync.c
|
--- a/drivers/misc/ntsync.c
|
||||||
+++ b/drivers/misc/ntsync.c
|
+++ b/drivers/misc/ntsync.c
|
||||||
@@ -23,6 +23,8 @@ struct ntsync_obj {
|
@@ -6,11 +6,16 @@
|
||||||
struct kref refcount;
|
*/
|
||||||
spinlock_t lock;
|
|
||||||
|
|
||||||
+ struct list_head any_waiters;
|
#include <linux/anon_inodes.h>
|
||||||
+
|
+#include <linux/atomic.h>
|
||||||
enum ntsync_type type;
|
#include <linux/file.h>
|
||||||
|
#include <linux/fs.h>
|
||||||
|
+#include <linux/hrtimer.h>
|
||||||
|
+#include <linux/ktime.h>
|
||||||
|
#include <linux/miscdevice.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/overflow.h>
|
||||||
|
+#include <linux/sched.h>
|
||||||
|
+#include <linux/sched/signal.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
#include <uapi/linux/ntsync.h>
|
||||||
|
@@ -30,6 +35,8 @@ enum ntsync_type {
|
||||||
|
*
|
||||||
|
* Both rely on struct file for reference counting. Individual
|
||||||
|
* ntsync_obj objects take a reference to the device when created.
|
||||||
|
+ * Wait operations take a reference to each object being waited on for
|
||||||
|
+ * the duration of the wait.
|
||||||
|
*/
|
||||||
|
|
||||||
/* The following fields are protected by the object lock. */
|
struct ntsync_obj {
|
||||||
@@ -34,6 +36,28 @@ struct ntsync_obj {
|
@@ -47,12 +54,55 @@ struct ntsync_obj {
|
||||||
|
__u32 max;
|
||||||
|
} sem;
|
||||||
} u;
|
} u;
|
||||||
};
|
+
|
||||||
|
+ struct list_head any_waiters;
|
||||||
|
+};
|
||||||
|
+
|
||||||
+struct ntsync_q_entry {
|
+struct ntsync_q_entry {
|
||||||
+ struct list_head node;
|
+ struct list_head node;
|
||||||
+ struct ntsync_q *q;
|
+ struct ntsync_q *q;
|
||||||
|
@ -46,18 +87,12 @@ index d1c91c2a4f1a..2e8d3c2d51a4 100644
|
||||||
+
|
+
|
||||||
+ __u32 count;
|
+ __u32 count;
|
||||||
+ struct ntsync_q_entry entries[];
|
+ struct ntsync_q_entry entries[];
|
||||||
+};
|
|
||||||
+
|
|
||||||
struct ntsync_device {
|
|
||||||
struct xarray objects;
|
|
||||||
};
|
};
|
||||||
@@ -109,6 +133,26 @@ static void init_obj(struct ntsync_obj *obj)
|
|
||||||
{
|
struct ntsync_device {
|
||||||
kref_init(&obj->refcount);
|
struct file *file;
|
||||||
spin_lock_init(&obj->lock);
|
};
|
||||||
+ INIT_LIST_HEAD(&obj->any_waiters);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void try_wake_any_sem(struct ntsync_obj *sem)
|
+static void try_wake_any_sem(struct ntsync_obj *sem)
|
||||||
+{
|
+{
|
||||||
+ struct ntsync_q_entry *entry;
|
+ struct ntsync_q_entry *entry;
|
||||||
|
@ -75,26 +110,64 @@ index d1c91c2a4f1a..2e8d3c2d51a4 100644
|
||||||
+ wake_up_process(q->task);
|
+ wake_up_process(q->task);
|
||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
}
|
+}
|
||||||
|
+
|
||||||
static int ntsync_create_sem(struct ntsync_device *dev, void __user *argp)
|
/*
|
||||||
@@ -194,6 +238,8 @@ static int ntsync_put_sem(struct ntsync_device *dev, void __user *argp)
|
* Actually change the semaphore state, returning -EOVERFLOW if it is made
|
||||||
|
* invalid.
|
||||||
|
@@ -88,6 +138,8 @@ static int ntsync_sem_post(struct ntsync_obj *sem, void __user *argp)
|
||||||
|
|
||||||
prev_count = sem->u.sem.count;
|
prev_count = sem->u.sem.count;
|
||||||
ret = put_sem_state(sem, args.count);
|
ret = post_sem_state(sem, args);
|
||||||
+ if (!ret)
|
+ if (!ret)
|
||||||
+ try_wake_any_sem(sem);
|
+ try_wake_any_sem(sem);
|
||||||
|
|
||||||
spin_unlock(&sem->lock);
|
spin_unlock(&sem->lock);
|
||||||
|
|
||||||
@@ -205,6 +251,187 @@ static int ntsync_put_sem(struct ntsync_device *dev, void __user *argp)
|
@@ -141,6 +193,7 @@ static struct ntsync_obj *ntsync_alloc_obj(struct ntsync_device *dev,
|
||||||
return ret;
|
obj->dev = dev;
|
||||||
|
get_file(dev->file);
|
||||||
|
spin_lock_init(&obj->lock);
|
||||||
|
+ INIT_LIST_HEAD(&obj->any_waiters);
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
@@ -191,6 +244,190 @@ static int ntsync_create_sem(struct ntsync_device *dev, void __user *argp)
|
||||||
|
return put_user(fd, &user_args->sem);
|
||||||
}
|
}
|
||||||
|
|
||||||
+static int ntsync_schedule(const struct ntsync_q *q, ktime_t *timeout)
|
+static struct ntsync_obj *get_obj(struct ntsync_device *dev, int fd)
|
||||||
+{
|
+{
|
||||||
|
+ struct file *file = fget(fd);
|
||||||
|
+ struct ntsync_obj *obj;
|
||||||
|
+
|
||||||
|
+ if (file->f_op != &ntsync_obj_fops) {
|
||||||
|
+ fput(file);
|
||||||
|
+ return NULL;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ obj = file->private_data;
|
||||||
|
+ if (obj->dev != dev) {
|
||||||
|
+ fput(file);
|
||||||
|
+ return NULL;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return obj;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void put_obj(struct ntsync_obj *obj)
|
||||||
|
+{
|
||||||
|
+ fput(obj->file);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int ntsync_schedule(const struct ntsync_q *q, const struct ntsync_wait_args *args)
|
||||||
|
+{
|
||||||
|
+ ktime_t timeout = ns_to_ktime(args->timeout);
|
||||||
|
+ ktime_t *timeout_ptr;
|
||||||
+ int ret = 0;
|
+ int ret = 0;
|
||||||
+
|
+
|
||||||
|
+ timeout_ptr = (args->timeout == U64_MAX ? NULL : &timeout);
|
||||||
|
+
|
||||||
+ do {
|
+ do {
|
||||||
+ if (signal_pending(current)) {
|
+ if (signal_pending(current)) {
|
||||||
+ ret = -ERESTARTSYS;
|
+ ret = -ERESTARTSYS;
|
||||||
|
@ -106,7 +179,7 @@ index d1c91c2a4f1a..2e8d3c2d51a4 100644
|
||||||
+ ret = 0;
|
+ ret = 0;
|
||||||
+ break;
|
+ break;
|
||||||
+ }
|
+ }
|
||||||
+ ret = schedule_hrtimeout(timeout, HRTIMER_MODE_ABS);
|
+ ret = schedule_hrtimeout(timeout_ptr, HRTIMER_MODE_ABS);
|
||||||
+ } while (ret < 0);
|
+ } while (ret < 0);
|
||||||
+ __set_current_state(TASK_RUNNING);
|
+ __set_current_state(TASK_RUNNING);
|
||||||
+
|
+
|
||||||
|
@ -115,16 +188,14 @@ index d1c91c2a4f1a..2e8d3c2d51a4 100644
|
||||||
+
|
+
|
||||||
+/*
|
+/*
|
||||||
+ * Allocate and initialize the ntsync_q structure, but do not queue us yet.
|
+ * Allocate and initialize the ntsync_q structure, but do not queue us yet.
|
||||||
+ * Also, calculate the relative timeout.
|
|
||||||
+ */
|
+ */
|
||||||
+static int setup_wait(struct ntsync_device *dev,
|
+static int setup_wait(struct ntsync_device *dev,
|
||||||
+ const struct ntsync_wait_args *args,
|
+ const struct ntsync_wait_args *args,
|
||||||
+ ktime_t *ret_timeout, struct ntsync_q **ret_q)
|
+ struct ntsync_q **ret_q)
|
||||||
+{
|
+{
|
||||||
+ const __u32 count = args->count;
|
+ const __u32 count = args->count;
|
||||||
|
+ int fds[NTSYNC_MAX_WAIT_COUNT];
|
||||||
+ struct ntsync_q *q;
|
+ struct ntsync_q *q;
|
||||||
+ ktime_t timeout = 0;
|
|
||||||
+ __u32 *ids;
|
|
||||||
+ __u32 i, j;
|
+ __u32 i, j;
|
||||||
+
|
+
|
||||||
+ if (!args->owner || args->pad)
|
+ if (!args->owner || args->pad)
|
||||||
|
@ -133,31 +204,13 @@ index d1c91c2a4f1a..2e8d3c2d51a4 100644
|
||||||
+ if (args->count > NTSYNC_MAX_WAIT_COUNT)
|
+ if (args->count > NTSYNC_MAX_WAIT_COUNT)
|
||||||
+ return -EINVAL;
|
+ return -EINVAL;
|
||||||
+
|
+
|
||||||
+ if (args->timeout) {
|
+ if (copy_from_user(fds, u64_to_user_ptr(args->objs),
|
||||||
+ struct timespec64 to;
|
+ array_size(count, sizeof(*fds))))
|
||||||
+
|
|
||||||
+ if (get_timespec64(&to, u64_to_user_ptr(args->timeout)))
|
|
||||||
+ return -EFAULT;
|
+ return -EFAULT;
|
||||||
+ if (!timespec64_valid(&to))
|
|
||||||
+ return -EINVAL;
|
|
||||||
+
|
|
||||||
+ timeout = timespec64_to_ns(&to);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ ids = kmalloc_array(count, sizeof(*ids), GFP_KERNEL);
|
|
||||||
+ if (!ids)
|
|
||||||
+ return -ENOMEM;
|
|
||||||
+ if (copy_from_user(ids, u64_to_user_ptr(args->objs),
|
|
||||||
+ array_size(count, sizeof(*ids)))) {
|
|
||||||
+ kfree(ids);
|
|
||||||
+ return -EFAULT;
|
|
||||||
+ }
|
|
||||||
+
|
+
|
||||||
+ q = kmalloc(struct_size(q, entries, count), GFP_KERNEL);
|
+ q = kmalloc(struct_size(q, entries, count), GFP_KERNEL);
|
||||||
+ if (!q) {
|
+ if (!q)
|
||||||
+ kfree(ids);
|
|
||||||
+ return -ENOMEM;
|
+ return -ENOMEM;
|
||||||
+ }
|
|
||||||
+ q->task = current;
|
+ q->task = current;
|
||||||
+ q->owner = args->owner;
|
+ q->owner = args->owner;
|
||||||
+ atomic_set(&q->signaled, -1);
|
+ atomic_set(&q->signaled, -1);
|
||||||
|
@ -165,7 +218,7 @@ index d1c91c2a4f1a..2e8d3c2d51a4 100644
|
||||||
+
|
+
|
||||||
+ for (i = 0; i < count; i++) {
|
+ for (i = 0; i < count; i++) {
|
||||||
+ struct ntsync_q_entry *entry = &q->entries[i];
|
+ struct ntsync_q_entry *entry = &q->entries[i];
|
||||||
+ struct ntsync_obj *obj = get_obj(dev, ids[i]);
|
+ struct ntsync_obj *obj = get_obj(dev, fds[i]);
|
||||||
+
|
+
|
||||||
+ if (!obj)
|
+ if (!obj)
|
||||||
+ goto err;
|
+ goto err;
|
||||||
|
@ -175,16 +228,12 @@ index d1c91c2a4f1a..2e8d3c2d51a4 100644
|
||||||
+ entry->index = i;
|
+ entry->index = i;
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ kfree(ids);
|
|
||||||
+
|
|
||||||
+ *ret_q = q;
|
+ *ret_q = q;
|
||||||
+ *ret_timeout = timeout;
|
|
||||||
+ return 0;
|
+ return 0;
|
||||||
+
|
+
|
||||||
+err:
|
+err:
|
||||||
+ for (j = 0; j < i; j++)
|
+ for (j = 0; j < i; j++)
|
||||||
+ put_obj(q->entries[j].obj);
|
+ put_obj(q->entries[j].obj);
|
||||||
+ kfree(ids);
|
|
||||||
+ kfree(q);
|
+ kfree(q);
|
||||||
+ return -EINVAL;
|
+ return -EINVAL;
|
||||||
+}
|
+}
|
||||||
|
@ -202,7 +251,6 @@ index d1c91c2a4f1a..2e8d3c2d51a4 100644
|
||||||
+{
|
+{
|
||||||
+ struct ntsync_wait_args args;
|
+ struct ntsync_wait_args args;
|
||||||
+ struct ntsync_q *q;
|
+ struct ntsync_q *q;
|
||||||
+ ktime_t timeout;
|
|
||||||
+ int signaled;
|
+ int signaled;
|
||||||
+ __u32 i;
|
+ __u32 i;
|
||||||
+ int ret;
|
+ int ret;
|
||||||
|
@ -210,7 +258,7 @@ index d1c91c2a4f1a..2e8d3c2d51a4 100644
|
||||||
+ if (copy_from_user(&args, argp, sizeof(args)))
|
+ if (copy_from_user(&args, argp, sizeof(args)))
|
||||||
+ return -EFAULT;
|
+ return -EFAULT;
|
||||||
+
|
+
|
||||||
+ ret = setup_wait(dev, &args, &timeout, &q);
|
+ ret = setup_wait(dev, &args, &q);
|
||||||
+ if (ret < 0)
|
+ if (ret < 0)
|
||||||
+ return ret;
|
+ return ret;
|
||||||
+
|
+
|
||||||
|
@ -240,7 +288,7 @@ index d1c91c2a4f1a..2e8d3c2d51a4 100644
|
||||||
+
|
+
|
||||||
+ /* sleep */
|
+ /* sleep */
|
||||||
+
|
+
|
||||||
+ ret = ntsync_schedule(q, args.timeout ? &timeout : NULL);
|
+ ret = ntsync_schedule(q, &args);
|
||||||
+
|
+
|
||||||
+ /* and finally, unqueue */
|
+ /* and finally, unqueue */
|
||||||
+
|
+
|
||||||
|
@ -272,23 +320,23 @@ index d1c91c2a4f1a..2e8d3c2d51a4 100644
|
||||||
+ return ret;
|
+ return ret;
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
static long ntsync_char_ioctl(struct file *file, unsigned int cmd,
|
static int ntsync_char_open(struct inode *inode, struct file *file)
|
||||||
unsigned long parm)
|
|
||||||
{
|
{
|
||||||
@@ -218,6 +445,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd,
|
struct ntsync_device *dev;
|
||||||
return ntsync_delete(dev, argp);
|
@@ -222,6 +459,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd,
|
||||||
case NTSYNC_IOC_PUT_SEM:
|
switch (cmd) {
|
||||||
return ntsync_put_sem(dev, argp);
|
case NTSYNC_IOC_CREATE_SEM:
|
||||||
|
return ntsync_create_sem(dev, argp);
|
||||||
+ case NTSYNC_IOC_WAIT_ANY:
|
+ case NTSYNC_IOC_WAIT_ANY:
|
||||||
+ return ntsync_wait_any(dev, argp);
|
+ return ntsync_wait_any(dev, argp);
|
||||||
default:
|
default:
|
||||||
return -ENOIOCTLCMD;
|
return -ENOIOCTLCMD;
|
||||||
}
|
}
|
||||||
diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h
|
diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h
|
||||||
index 8c610d65f8ef..10f07da7864e 100644
|
index dcfa38fdc93c..56b643fab611 100644
|
||||||
--- a/include/uapi/linux/ntsync.h
|
--- a/include/uapi/linux/ntsync.h
|
||||||
+++ b/include/uapi/linux/ntsync.h
|
+++ b/include/uapi/linux/ntsync.h
|
||||||
@@ -16,6 +16,17 @@ struct ntsync_sem_args {
|
@@ -16,7 +16,19 @@ struct ntsync_sem_args {
|
||||||
__u32 max;
|
__u32 max;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -303,16 +351,10 @@ index 8c610d65f8ef..10f07da7864e 100644
|
||||||
+
|
+
|
||||||
+#define NTSYNC_MAX_WAIT_COUNT 64
|
+#define NTSYNC_MAX_WAIT_COUNT 64
|
||||||
+
|
+
|
||||||
#define NTSYNC_IOC_BASE 0xf7
|
#define NTSYNC_IOC_CREATE_SEM _IOWR('N', 0x80, struct ntsync_sem_args)
|
||||||
|
+#define NTSYNC_IOC_WAIT_ANY _IOWR('N', 0x82, struct ntsync_wait_args)
|
||||||
|
|
||||||
#define NTSYNC_IOC_CREATE_SEM _IOWR(NTSYNC_IOC_BASE, 0, \
|
#define NTSYNC_IOC_SEM_POST _IOWR('N', 0x81, __u32)
|
||||||
@@ -23,5 +34,7 @@ struct ntsync_sem_args {
|
|
||||||
#define NTSYNC_IOC_DELETE _IOW (NTSYNC_IOC_BASE, 1, __u32)
|
|
||||||
#define NTSYNC_IOC_PUT_SEM _IOWR(NTSYNC_IOC_BASE, 2, \
|
|
||||||
struct ntsync_sem_args)
|
|
||||||
+#define NTSYNC_IOC_WAIT_ANY _IOWR(NTSYNC_IOC_BASE, 3, \
|
|
||||||
+ struct ntsync_wait_args)
|
|
||||||
|
|
||||||
#endif
|
|
||||||
--
|
--
|
||||||
2.43.0
|
2.43.0
|
|
@ -1,21 +1,20 @@
|
||||||
This corresponds to part of the functionality of the NT syscall
|
This is similar to NTSYNC_IOC_WAIT_ANY, but waits until all of the objects are
|
||||||
NtWaitForMultipleObjects(). Specifically, it implements the behaviour where
|
simultaneously signaled, and then acquires all of them as a single atomic
|
||||||
the third argument (wait_any) is FALSE, and it does not yet handle alertable
|
operation.
|
||||||
waits.
|
|
||||||
|
|
||||||
Signed-off-by: Elizabeth Figura <zfigura@codeweavers.com>
|
Signed-off-by: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
---
|
---
|
||||||
drivers/misc/ntsync.c | 241 ++++++++++++++++++++++++++++++++++--
|
drivers/misc/ntsync.c | 242 ++++++++++++++++++++++++++++++++++--
|
||||||
include/uapi/linux/ntsync.h | 2 +
|
include/uapi/linux/ntsync.h | 1 +
|
||||||
2 files changed, 235 insertions(+), 8 deletions(-)
|
2 files changed, 235 insertions(+), 8 deletions(-)
|
||||||
|
|
||||||
diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c
|
diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c
|
||||||
index 2e8d3c2d51a4..2685363fae9e 100644
|
index ad93ca0f8b84..d5759e9a3a8e 100644
|
||||||
--- a/drivers/misc/ntsync.c
|
--- a/drivers/misc/ntsync.c
|
||||||
+++ b/drivers/misc/ntsync.c
|
+++ b/drivers/misc/ntsync.c
|
||||||
@@ -23,7 +23,34 @@ struct ntsync_obj {
|
@@ -55,7 +55,34 @@ struct ntsync_obj {
|
||||||
struct kref refcount;
|
} sem;
|
||||||
spinlock_t lock;
|
} u;
|
||||||
|
|
||||||
+ /*
|
+ /*
|
||||||
+ * any_waiters is protected by the object lock, but all_waiters is
|
+ * any_waiters is protected by the object lock, but all_waiters is
|
||||||
|
@ -33,22 +32,22 @@ index 2e8d3c2d51a4..2685363fae9e 100644
|
||||||
+ * lock all of the objects, and that means grabbing the wait_all_lock
|
+ * lock all of the objects, and that means grabbing the wait_all_lock
|
||||||
+ * below (and, due to lock ordering rules, before locking this object).
|
+ * below (and, due to lock ordering rules, before locking this object).
|
||||||
+ * However, wait-all is a rare operation, and grabbing the wait-all
|
+ * However, wait-all is a rare operation, and grabbing the wait-all
|
||||||
+ * lock for every wake would create unnecessary contention. Therefore we
|
+ * lock for every wake would create unnecessary contention.
|
||||||
+ * first check whether all_hint is zero, and, if it is, we skip trying
|
+ * Therefore we first check whether all_hint is zero, and, if it is,
|
||||||
+ * to wake "all" waiters.
|
+ * we skip trying to wake "all" waiters.
|
||||||
+ *
|
+ *
|
||||||
+ * This hint isn't protected by any lock. It might change during the
|
+ * This hint isn't protected by any lock. It might change during the
|
||||||
+ * course of a wake, but there's no meaningful race there; it's only a
|
+ * course of a wake, but there's no meaningful race there; it's only a
|
||||||
+ * hint.
|
+ * hint.
|
||||||
+ *
|
+ *
|
||||||
+ * Since wait requests must originate from user-space threads, we're
|
+ * Since wait requests must originate from user-space threads, we're
|
||||||
+ * limited here by PID_MAX_LIMIT, so there's no risk of saturation.
|
+ * limited here by PID_MAX_LIMIT, so there's no risk of overflow.
|
||||||
+ */
|
+ */
|
||||||
+ atomic_t all_hint;
|
+ atomic_t all_hint;
|
||||||
|
};
|
||||||
|
|
||||||
enum ntsync_type type;
|
struct ntsync_q_entry {
|
||||||
|
@@ -76,14 +103,99 @@ struct ntsync_q {
|
||||||
@@ -54,11 +81,25 @@ struct ntsync_q {
|
|
||||||
*/
|
*/
|
||||||
atomic_t signaled;
|
atomic_t signaled;
|
||||||
|
|
||||||
|
@ -60,9 +59,9 @@ index 2e8d3c2d51a4..2685363fae9e 100644
|
||||||
struct ntsync_device {
|
struct ntsync_device {
|
||||||
+ /*
|
+ /*
|
||||||
+ * Wait-all operations must atomically grab all objects, and be totally
|
+ * Wait-all operations must atomically grab all objects, and be totally
|
||||||
+ * ordered with respect to each other and wait-any operations. If one
|
+ * ordered with respect to each other and wait-any operations.
|
||||||
+ * thread is trying to acquire several objects, another thread cannot
|
+ * If one thread is trying to acquire several objects, another thread
|
||||||
+ * touch the object at the same time.
|
+ * cannot touch the object at the same time.
|
||||||
+ *
|
+ *
|
||||||
+ * We achieve this by grabbing multiple object locks at the same time.
|
+ * We achieve this by grabbing multiple object locks at the same time.
|
||||||
+ * However, this creates a lock ordering problem. To solve that problem,
|
+ * However, this creates a lock ordering problem. To solve that problem,
|
||||||
|
@ -71,28 +70,9 @@ index 2e8d3c2d51a4..2685363fae9e 100644
|
||||||
+ */
|
+ */
|
||||||
+ spinlock_t wait_all_lock;
|
+ spinlock_t wait_all_lock;
|
||||||
+
|
+
|
||||||
struct xarray objects;
|
struct file *file;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -107,6 +148,8 @@ static int ntsync_char_open(struct inode *inode, struct file *file)
|
|
||||||
if (!dev)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
+ spin_lock_init(&dev->wait_all_lock);
|
|
||||||
+
|
|
||||||
xa_init_flags(&dev->objects, XA_FLAGS_ALLOC);
|
|
||||||
|
|
||||||
file->private_data = dev;
|
|
||||||
@@ -132,8 +175,81 @@ static int ntsync_char_release(struct inode *inode, struct file *file)
|
|
||||||
static void init_obj(struct ntsync_obj *obj)
|
|
||||||
{
|
|
||||||
kref_init(&obj->refcount);
|
|
||||||
+ atomic_set(&obj->all_hint, 0);
|
|
||||||
spin_lock_init(&obj->lock);
|
|
||||||
INIT_LIST_HEAD(&obj->any_waiters);
|
|
||||||
+ INIT_LIST_HEAD(&obj->all_waiters);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static bool is_signaled(struct ntsync_obj *obj, __u32 owner)
|
+static bool is_signaled(struct ntsync_obj *obj, __u32 owner)
|
||||||
+{
|
+{
|
||||||
+ lockdep_assert_held(&obj->lock);
|
+ lockdep_assert_held(&obj->lock);
|
||||||
|
@ -162,11 +142,21 @@ index 2e8d3c2d51a4..2685363fae9e 100644
|
||||||
+
|
+
|
||||||
+ list_for_each_entry(entry, &obj->all_waiters, node)
|
+ list_for_each_entry(entry, &obj->all_waiters, node)
|
||||||
+ try_wake_all(dev, entry->q, obj);
|
+ try_wake_all(dev, entry->q, obj);
|
||||||
}
|
+}
|
||||||
|
+
|
||||||
static void try_wake_any_sem(struct ntsync_obj *sem)
|
static void try_wake_any_sem(struct ntsync_obj *sem)
|
||||||
@@ -234,14 +350,29 @@ static int ntsync_put_sem(struct ntsync_device *dev, void __user *argp)
|
{
|
||||||
if (!sem)
|
struct ntsync_q_entry *entry;
|
||||||
|
@@ -123,6 +235,7 @@ static int post_sem_state(struct ntsync_obj *sem, __u32 count)
|
||||||
|
|
||||||
|
static int ntsync_sem_post(struct ntsync_obj *sem, void __user *argp)
|
||||||
|
{
|
||||||
|
+ struct ntsync_device *dev = sem->dev;
|
||||||
|
__u32 __user *user_args = argp;
|
||||||
|
__u32 prev_count;
|
||||||
|
__u32 args;
|
||||||
|
@@ -134,14 +247,29 @@ static int ntsync_sem_post(struct ntsync_obj *sem, void __user *argp)
|
||||||
|
if (sem->type != NTSYNC_TYPE_SEM)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
- spin_lock(&sem->lock);
|
- spin_lock(&sem->lock);
|
||||||
|
@ -175,11 +165,11 @@ index 2e8d3c2d51a4..2685363fae9e 100644
|
||||||
+ spin_lock_nest_lock(&sem->lock, &dev->wait_all_lock);
|
+ spin_lock_nest_lock(&sem->lock, &dev->wait_all_lock);
|
||||||
|
|
||||||
- prev_count = sem->u.sem.count;
|
- prev_count = sem->u.sem.count;
|
||||||
- ret = put_sem_state(sem, args.count);
|
- ret = post_sem_state(sem, args);
|
||||||
- if (!ret)
|
- if (!ret)
|
||||||
- try_wake_any_sem(sem);
|
- try_wake_any_sem(sem);
|
||||||
+ prev_count = sem->u.sem.count;
|
+ prev_count = sem->u.sem.count;
|
||||||
+ ret = put_sem_state(sem, args.count);
|
+ ret = post_sem_state(sem, args);
|
||||||
+ if (!ret) {
|
+ if (!ret) {
|
||||||
+ try_wake_all_obj(dev, sem);
|
+ try_wake_all_obj(dev, sem);
|
||||||
+ try_wake_any_sem(sem);
|
+ try_wake_any_sem(sem);
|
||||||
|
@ -192,25 +182,34 @@ index 2e8d3c2d51a4..2685363fae9e 100644
|
||||||
+ spin_lock(&sem->lock);
|
+ spin_lock(&sem->lock);
|
||||||
+
|
+
|
||||||
+ prev_count = sem->u.sem.count;
|
+ prev_count = sem->u.sem.count;
|
||||||
+ ret = put_sem_state(sem, args.count);
|
+ ret = post_sem_state(sem, args);
|
||||||
+ if (!ret)
|
+ if (!ret)
|
||||||
+ try_wake_any_sem(sem);
|
+ try_wake_any_sem(sem);
|
||||||
+
|
+
|
||||||
+ spin_unlock(&sem->lock);
|
+ spin_unlock(&sem->lock);
|
||||||
+ }
|
+ }
|
||||||
|
|
||||||
put_obj(sem);
|
if (!ret && put_user(prev_count, user_args))
|
||||||
|
ret = -EFAULT;
|
||||||
|
@@ -194,6 +322,8 @@ static struct ntsync_obj *ntsync_alloc_obj(struct ntsync_device *dev,
|
||||||
|
get_file(dev->file);
|
||||||
|
spin_lock_init(&obj->lock);
|
||||||
|
INIT_LIST_HEAD(&obj->any_waiters);
|
||||||
|
+ INIT_LIST_HEAD(&obj->all_waiters);
|
||||||
|
+ atomic_set(&obj->all_hint, 0);
|
||||||
|
|
||||||
@@ -278,7 +409,7 @@ static int ntsync_schedule(const struct ntsync_q *q, ktime_t *timeout)
|
return obj;
|
||||||
* Also, calculate the relative timeout.
|
}
|
||||||
|
@@ -298,7 +428,7 @@ static int ntsync_schedule(const struct ntsync_q *q, const struct ntsync_wait_ar
|
||||||
|
* Allocate and initialize the ntsync_q structure, but do not queue us yet.
|
||||||
*/
|
*/
|
||||||
static int setup_wait(struct ntsync_device *dev,
|
static int setup_wait(struct ntsync_device *dev,
|
||||||
- const struct ntsync_wait_args *args,
|
- const struct ntsync_wait_args *args,
|
||||||
+ const struct ntsync_wait_args *args, bool all,
|
+ const struct ntsync_wait_args *args, bool all,
|
||||||
ktime_t *ret_timeout, struct ntsync_q **ret_q)
|
struct ntsync_q **ret_q)
|
||||||
{
|
{
|
||||||
const __u32 count = args->count;
|
const __u32 count = args->count;
|
||||||
@@ -321,6 +452,7 @@ static int setup_wait(struct ntsync_device *dev,
|
@@ -322,6 +452,7 @@ static int setup_wait(struct ntsync_device *dev,
|
||||||
q->task = current;
|
q->task = current;
|
||||||
q->owner = args->owner;
|
q->owner = args->owner;
|
||||||
atomic_set(&q->signaled, -1);
|
atomic_set(&q->signaled, -1);
|
||||||
|
@ -218,7 +217,7 @@ index 2e8d3c2d51a4..2685363fae9e 100644
|
||||||
q->count = count;
|
q->count = count;
|
||||||
|
|
||||||
for (i = 0; i < count; i++) {
|
for (i = 0; i < count; i++) {
|
||||||
@@ -330,6 +462,16 @@ static int setup_wait(struct ntsync_device *dev,
|
@@ -331,6 +462,16 @@ static int setup_wait(struct ntsync_device *dev,
|
||||||
if (!obj)
|
if (!obj)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
|
@ -235,16 +234,16 @@ index 2e8d3c2d51a4..2685363fae9e 100644
|
||||||
entry->obj = obj;
|
entry->obj = obj;
|
||||||
entry->q = q;
|
entry->q = q;
|
||||||
entry->index = i;
|
entry->index = i;
|
||||||
@@ -370,7 +512,7 @@ static int ntsync_wait_any(struct ntsync_device *dev, void __user *argp)
|
@@ -366,7 +507,7 @@ static int ntsync_wait_any(struct ntsync_device *dev, void __user *argp)
|
||||||
if (copy_from_user(&args, argp, sizeof(args)))
|
if (copy_from_user(&args, argp, sizeof(args)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
- ret = setup_wait(dev, &args, &timeout, &q);
|
- ret = setup_wait(dev, &args, &q);
|
||||||
+ ret = setup_wait(dev, &args, false, &timeout, &q);
|
+ ret = setup_wait(dev, &args, false, &q);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@@ -432,6 +574,87 @@ static int ntsync_wait_any(struct ntsync_device *dev, void __user *argp)
|
@@ -428,6 +569,87 @@ static int ntsync_wait_any(struct ntsync_device *dev, void __user *argp)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,7 +251,6 @@ index 2e8d3c2d51a4..2685363fae9e 100644
|
||||||
+{
|
+{
|
||||||
+ struct ntsync_wait_args args;
|
+ struct ntsync_wait_args args;
|
||||||
+ struct ntsync_q *q;
|
+ struct ntsync_q *q;
|
||||||
+ ktime_t timeout;
|
|
||||||
+ int signaled;
|
+ int signaled;
|
||||||
+ __u32 i;
|
+ __u32 i;
|
||||||
+ int ret;
|
+ int ret;
|
||||||
|
@ -260,7 +258,7 @@ index 2e8d3c2d51a4..2685363fae9e 100644
|
||||||
+ if (copy_from_user(&args, argp, sizeof(args)))
|
+ if (copy_from_user(&args, argp, sizeof(args)))
|
||||||
+ return -EFAULT;
|
+ return -EFAULT;
|
||||||
+
|
+
|
||||||
+ ret = setup_wait(dev, &args, true, &timeout, &q);
|
+ ret = setup_wait(dev, &args, true, &q);
|
||||||
+ if (ret < 0)
|
+ if (ret < 0)
|
||||||
+ return ret;
|
+ return ret;
|
||||||
+
|
+
|
||||||
|
@ -276,7 +274,8 @@ index 2e8d3c2d51a4..2685363fae9e 100644
|
||||||
+
|
+
|
||||||
+ /*
|
+ /*
|
||||||
+ * obj->all_waiters is protected by dev->wait_all_lock rather
|
+ * obj->all_waiters is protected by dev->wait_all_lock rather
|
||||||
+ * than obj->lock, so there is no need to acquire it here.
|
+ * than obj->lock, so there is no need to acquire obj->lock
|
||||||
|
+ * here.
|
||||||
+ */
|
+ */
|
||||||
+ list_add_tail(&entry->node, &obj->all_waiters);
|
+ list_add_tail(&entry->node, &obj->all_waiters);
|
||||||
+ }
|
+ }
|
||||||
|
@ -289,7 +288,7 @@ index 2e8d3c2d51a4..2685363fae9e 100644
|
||||||
+
|
+
|
||||||
+ /* sleep */
|
+ /* sleep */
|
||||||
+
|
+
|
||||||
+ ret = ntsync_schedule(q, args.timeout ? &timeout : NULL);
|
+ ret = ntsync_schedule(q, &args);
|
||||||
+
|
+
|
||||||
+ /* and finally, unqueue */
|
+ /* and finally, unqueue */
|
||||||
+
|
+
|
||||||
|
@ -329,29 +328,38 @@ index 2e8d3c2d51a4..2685363fae9e 100644
|
||||||
+ return ret;
|
+ return ret;
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
static long ntsync_char_ioctl(struct file *file, unsigned int cmd,
|
static int ntsync_char_open(struct inode *inode, struct file *file)
|
||||||
unsigned long parm)
|
|
||||||
{
|
{
|
||||||
@@ -445,6 +668,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd,
|
struct ntsync_device *dev;
|
||||||
return ntsync_delete(dev, argp);
|
@@ -436,6 +658,8 @@ static int ntsync_char_open(struct inode *inode, struct file *file)
|
||||||
case NTSYNC_IOC_PUT_SEM:
|
if (!dev)
|
||||||
return ntsync_put_sem(dev, argp);
|
return -ENOMEM;
|
||||||
|
|
||||||
|
+ spin_lock_init(&dev->wait_all_lock);
|
||||||
|
+
|
||||||
|
file->private_data = dev;
|
||||||
|
dev->file = file;
|
||||||
|
return nonseekable_open(inode, file);
|
||||||
|
@@ -459,6 +683,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd,
|
||||||
|
switch (cmd) {
|
||||||
|
case NTSYNC_IOC_CREATE_SEM:
|
||||||
|
return ntsync_create_sem(dev, argp);
|
||||||
+ case NTSYNC_IOC_WAIT_ALL:
|
+ case NTSYNC_IOC_WAIT_ALL:
|
||||||
+ return ntsync_wait_all(dev, argp);
|
+ return ntsync_wait_all(dev, argp);
|
||||||
case NTSYNC_IOC_WAIT_ANY:
|
case NTSYNC_IOC_WAIT_ANY:
|
||||||
return ntsync_wait_any(dev, argp);
|
return ntsync_wait_any(dev, argp);
|
||||||
default:
|
default:
|
||||||
diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h
|
diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h
|
||||||
index 10f07da7864e..a5bed5a39b21 100644
|
index 56b643fab611..19c37e27a4f8 100644
|
||||||
--- a/include/uapi/linux/ntsync.h
|
--- a/include/uapi/linux/ntsync.h
|
||||||
+++ b/include/uapi/linux/ntsync.h
|
+++ b/include/uapi/linux/ntsync.h
|
||||||
@@ -36,5 +36,7 @@ struct ntsync_wait_args {
|
@@ -29,6 +29,7 @@ struct ntsync_wait_args {
|
||||||
struct ntsync_sem_args)
|
|
||||||
#define NTSYNC_IOC_WAIT_ANY _IOWR(NTSYNC_IOC_BASE, 3, \
|
#define NTSYNC_IOC_CREATE_SEM _IOWR('N', 0x80, struct ntsync_sem_args)
|
||||||
struct ntsync_wait_args)
|
#define NTSYNC_IOC_WAIT_ANY _IOWR('N', 0x82, struct ntsync_wait_args)
|
||||||
+#define NTSYNC_IOC_WAIT_ALL _IOWR(NTSYNC_IOC_BASE, 4, \
|
+#define NTSYNC_IOC_WAIT_ALL _IOWR('N', 0x83, struct ntsync_wait_args)
|
||||||
+ struct ntsync_wait_args)
|
|
||||||
|
#define NTSYNC_IOC_SEM_POST _IOWR('N', 0x81, __u32)
|
||||||
|
|
||||||
#endif
|
|
||||||
--
|
--
|
||||||
2.43.0
|
2.43.0
|
|
@ -1,24 +1,34 @@
|
||||||
This corresponds to the NT syscall NtCreateMutant().
|
This corresponds to the NT syscall NtCreateMutant().
|
||||||
|
|
||||||
|
An NT mutex is recursive, with a 32-bit recursion counter. When acquired via
|
||||||
|
NtWaitForMultipleObjects(), the recursion counter is incremented by one.
|
||||||
|
|
||||||
|
The OS records the thread which acquired it. However, in order to keep this
|
||||||
|
driver self-contained, the owning thread ID is managed by user-space, and passed
|
||||||
|
as a parameter to all relevant ioctls.
|
||||||
|
|
||||||
|
The initial owner and recursion count, if any, are specified when the mutex is
|
||||||
|
created.
|
||||||
|
|
||||||
Signed-off-by: Elizabeth Figura <zfigura@codeweavers.com>
|
Signed-off-by: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
---
|
---
|
||||||
drivers/misc/ntsync.c | 72 +++++++++++++++++++++++++++++++++++++
|
drivers/misc/ntsync.c | 67 +++++++++++++++++++++++++++++++++++++
|
||||||
include/uapi/linux/ntsync.h | 8 +++++
|
include/uapi/linux/ntsync.h | 7 ++++
|
||||||
2 files changed, 80 insertions(+)
|
2 files changed, 74 insertions(+)
|
||||||
|
|
||||||
diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c
|
diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c
|
||||||
index 2685363fae9e..d48f2ef41341 100644
|
index d5759e9a3a8e..6f7086d0440a 100644
|
||||||
--- a/drivers/misc/ntsync.c
|
--- a/drivers/misc/ntsync.c
|
||||||
+++ b/drivers/misc/ntsync.c
|
+++ b/drivers/misc/ntsync.c
|
||||||
@@ -16,6 +16,7 @@
|
@@ -24,6 +24,7 @@
|
||||||
|
|
||||||
enum ntsync_type {
|
enum ntsync_type {
|
||||||
NTSYNC_TYPE_SEM,
|
NTSYNC_TYPE_SEM,
|
||||||
+ NTSYNC_TYPE_MUTEX,
|
+ NTSYNC_TYPE_MUTEX,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ntsync_obj {
|
/*
|
||||||
@@ -60,6 +61,10 @@ struct ntsync_obj {
|
@@ -53,6 +54,10 @@ struct ntsync_obj {
|
||||||
__u32 count;
|
__u32 count;
|
||||||
__u32 max;
|
__u32 max;
|
||||||
} sem;
|
} sem;
|
||||||
|
@ -27,9 +37,9 @@ index 2685363fae9e..d48f2ef41341 100644
|
||||||
+ __u32 owner;
|
+ __u32 owner;
|
||||||
+ } mutex;
|
+ } mutex;
|
||||||
} u;
|
} u;
|
||||||
};
|
|
||||||
|
|
||||||
@@ -188,6 +193,10 @@ static bool is_signaled(struct ntsync_obj *obj, __u32 owner)
|
/*
|
||||||
|
@@ -132,6 +137,10 @@ static bool is_signaled(struct ntsync_obj *obj, __u32 owner)
|
||||||
switch (obj->type) {
|
switch (obj->type) {
|
||||||
case NTSYNC_TYPE_SEM:
|
case NTSYNC_TYPE_SEM:
|
||||||
return !!obj->u.sem.count;
|
return !!obj->u.sem.count;
|
||||||
|
@ -40,7 +50,7 @@ index 2685363fae9e..d48f2ef41341 100644
|
||||||
}
|
}
|
||||||
|
|
||||||
WARN(1, "bad object type %#x\n", obj->type);
|
WARN(1, "bad object type %#x\n", obj->type);
|
||||||
@@ -230,6 +239,10 @@ static void try_wake_all(struct ntsync_device *dev, struct ntsync_q *q,
|
@@ -174,6 +183,10 @@ static void try_wake_all(struct ntsync_device *dev, struct ntsync_q *q,
|
||||||
case NTSYNC_TYPE_SEM:
|
case NTSYNC_TYPE_SEM:
|
||||||
obj->u.sem.count--;
|
obj->u.sem.count--;
|
||||||
break;
|
break;
|
||||||
|
@ -51,7 +61,7 @@ index 2685363fae9e..d48f2ef41341 100644
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wake_up_process(q->task);
|
wake_up_process(q->task);
|
||||||
@@ -271,6 +284,28 @@ static void try_wake_any_sem(struct ntsync_obj *sem)
|
@@ -215,6 +228,28 @@ static void try_wake_any_sem(struct ntsync_obj *sem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,11 +87,11 @@ index 2685363fae9e..d48f2ef41341 100644
|
||||||
+ }
|
+ }
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
static int ntsync_create_sem(struct ntsync_device *dev, void __user *argp)
|
/*
|
||||||
{
|
* Actually change the semaphore state, returning -EOVERFLOW if it is made
|
||||||
struct ntsync_sem_args __user *user_args = argp;
|
* invalid.
|
||||||
@@ -303,6 +338,38 @@ static int ntsync_create_sem(struct ntsync_device *dev, void __user *argp)
|
@@ -374,6 +409,33 @@ static int ntsync_create_sem(struct ntsync_device *dev, void __user *argp)
|
||||||
return put_user(id, &user_args->sem);
|
return put_user(fd, &user_args->sem);
|
||||||
}
|
}
|
||||||
|
|
||||||
+static int ntsync_create_mutex(struct ntsync_device *dev, void __user *argp)
|
+static int ntsync_create_mutex(struct ntsync_device *dev, void __user *argp)
|
||||||
|
@ -89,8 +99,7 @@ index 2685363fae9e..d48f2ef41341 100644
|
||||||
+ struct ntsync_mutex_args __user *user_args = argp;
|
+ struct ntsync_mutex_args __user *user_args = argp;
|
||||||
+ struct ntsync_mutex_args args;
|
+ struct ntsync_mutex_args args;
|
||||||
+ struct ntsync_obj *mutex;
|
+ struct ntsync_obj *mutex;
|
||||||
+ __u32 id;
|
+ int fd;
|
||||||
+ int ret;
|
|
||||||
+
|
+
|
||||||
+ if (copy_from_user(&args, argp, sizeof(args)))
|
+ if (copy_from_user(&args, argp, sizeof(args)))
|
||||||
+ return -EFAULT;
|
+ return -EFAULT;
|
||||||
|
@ -98,28 +107,24 @@ index 2685363fae9e..d48f2ef41341 100644
|
||||||
+ if (!args.owner != !args.count)
|
+ if (!args.owner != !args.count)
|
||||||
+ return -EINVAL;
|
+ return -EINVAL;
|
||||||
+
|
+
|
||||||
+ mutex = kzalloc(sizeof(*mutex), GFP_KERNEL);
|
+ mutex = ntsync_alloc_obj(dev, NTSYNC_TYPE_MUTEX);
|
||||||
+ if (!mutex)
|
+ if (!mutex)
|
||||||
+ return -ENOMEM;
|
+ return -ENOMEM;
|
||||||
+
|
|
||||||
+ init_obj(mutex);
|
|
||||||
+ mutex->type = NTSYNC_TYPE_MUTEX;
|
|
||||||
+ mutex->u.mutex.count = args.count;
|
+ mutex->u.mutex.count = args.count;
|
||||||
+ mutex->u.mutex.owner = args.owner;
|
+ mutex->u.mutex.owner = args.owner;
|
||||||
+
|
+ fd = ntsync_obj_get_fd(mutex);
|
||||||
+ ret = xa_alloc(&dev->objects, &id, mutex, xa_limit_32b, GFP_KERNEL);
|
+ if (fd < 0) {
|
||||||
+ if (ret < 0) {
|
|
||||||
+ kfree(mutex);
|
+ kfree(mutex);
|
||||||
+ return ret;
|
+ return fd;
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ return put_user(id, &user_args->mutex);
|
+ return put_user(fd, &user_args->mutex);
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
static int ntsync_delete(struct ntsync_device *dev, void __user *argp)
|
static struct ntsync_obj *get_obj(struct ntsync_device *dev, int fd)
|
||||||
{
|
{
|
||||||
struct ntsync_obj *obj;
|
struct file *file = fget(fd);
|
||||||
@@ -497,6 +564,9 @@ static void try_wake_any_obj(struct ntsync_obj *obj)
|
@@ -493,6 +555,9 @@ static void try_wake_any_obj(struct ntsync_obj *obj)
|
||||||
case NTSYNC_TYPE_SEM:
|
case NTSYNC_TYPE_SEM:
|
||||||
try_wake_any_sem(obj);
|
try_wake_any_sem(obj);
|
||||||
break;
|
break;
|
||||||
|
@ -129,7 +134,7 @@ index 2685363fae9e..d48f2ef41341 100644
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -662,6 +732,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd,
|
@@ -681,6 +746,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd,
|
||||||
void __user *argp = (void __user *)parm;
|
void __user *argp = (void __user *)parm;
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
|
@ -137,9 +142,9 @@ index 2685363fae9e..d48f2ef41341 100644
|
||||||
+ return ntsync_create_mutex(dev, argp);
|
+ return ntsync_create_mutex(dev, argp);
|
||||||
case NTSYNC_IOC_CREATE_SEM:
|
case NTSYNC_IOC_CREATE_SEM:
|
||||||
return ntsync_create_sem(dev, argp);
|
return ntsync_create_sem(dev, argp);
|
||||||
case NTSYNC_IOC_DELETE:
|
case NTSYNC_IOC_WAIT_ALL:
|
||||||
diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h
|
diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h
|
||||||
index a5bed5a39b21..26d1b3d4847f 100644
|
index 19c37e27a4f8..8ac9d419c360 100644
|
||||||
--- a/include/uapi/linux/ntsync.h
|
--- a/include/uapi/linux/ntsync.h
|
||||||
+++ b/include/uapi/linux/ntsync.h
|
+++ b/include/uapi/linux/ntsync.h
|
||||||
@@ -16,6 +16,12 @@ struct ntsync_sem_args {
|
@@ -16,6 +16,12 @@ struct ntsync_sem_args {
|
||||||
|
@ -155,13 +160,13 @@ index a5bed5a39b21..26d1b3d4847f 100644
|
||||||
struct ntsync_wait_args {
|
struct ntsync_wait_args {
|
||||||
__u64 timeout;
|
__u64 timeout;
|
||||||
__u64 objs;
|
__u64 objs;
|
||||||
@@ -38,5 +44,7 @@ struct ntsync_wait_args {
|
@@ -30,6 +36,7 @@ struct ntsync_wait_args {
|
||||||
struct ntsync_wait_args)
|
#define NTSYNC_IOC_CREATE_SEM _IOWR('N', 0x80, struct ntsync_sem_args)
|
||||||
#define NTSYNC_IOC_WAIT_ALL _IOWR(NTSYNC_IOC_BASE, 4, \
|
#define NTSYNC_IOC_WAIT_ANY _IOWR('N', 0x82, struct ntsync_wait_args)
|
||||||
struct ntsync_wait_args)
|
#define NTSYNC_IOC_WAIT_ALL _IOWR('N', 0x83, struct ntsync_wait_args)
|
||||||
+#define NTSYNC_IOC_CREATE_MUTEX _IOWR(NTSYNC_IOC_BASE, 5, \
|
+#define NTSYNC_IOC_CREATE_MUTEX _IOWR('N', 0x84, struct ntsync_sem_args)
|
||||||
+ struct ntsync_mutex_args)
|
|
||||||
|
#define NTSYNC_IOC_SEM_POST _IOWR('N', 0x81, __u32)
|
||||||
|
|
||||||
#endif
|
|
||||||
--
|
--
|
||||||
2.43.0
|
2.43.0
|
|
@ -1,23 +1,27 @@
|
||||||
This corresponds to the NT syscall NtReleaseMutant().
|
This corresponds to the NT syscall NtReleaseMutant().
|
||||||
|
|
||||||
|
This syscall decrements the mutex's recursion count by one, and returns the
|
||||||
|
previous value. If the mutex is not owned by the given owner ID, the function
|
||||||
|
instead fails and returns -EPERM.
|
||||||
|
|
||||||
Signed-off-by: Elizabeth Figura <zfigura@codeweavers.com>
|
Signed-off-by: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
---
|
---
|
||||||
drivers/misc/ntsync.c | 67 +++++++++++++++++++++++++++++++++++++
|
drivers/misc/ntsync.c | 64 +++++++++++++++++++++++++++++++++++++
|
||||||
include/uapi/linux/ntsync.h | 2 ++
|
include/uapi/linux/ntsync.h | 1 +
|
||||||
2 files changed, 69 insertions(+)
|
2 files changed, 65 insertions(+)
|
||||||
|
|
||||||
diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c
|
diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c
|
||||||
index d48f2ef41341..28f43768d1c3 100644
|
index 6f7086d0440a..222ebead8eba 100644
|
||||||
--- a/drivers/misc/ntsync.c
|
--- a/drivers/misc/ntsync.c
|
||||||
+++ b/drivers/misc/ntsync.c
|
+++ b/drivers/misc/ntsync.c
|
||||||
@@ -449,6 +449,71 @@ static int ntsync_put_sem(struct ntsync_device *dev, void __user *argp)
|
@@ -312,6 +312,68 @@ static int ntsync_sem_post(struct ntsync_obj *sem, void __user *argp)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
+/*
|
+/*
|
||||||
+ * Actually change the mutex state, returning -EPERM if not the owner.
|
+ * Actually change the mutex state, returning -EPERM if not the owner.
|
||||||
+ */
|
+ */
|
||||||
+static int put_mutex_state(struct ntsync_obj *mutex,
|
+static int unlock_mutex_state(struct ntsync_obj *mutex,
|
||||||
+ const struct ntsync_mutex_args *args)
|
+ const struct ntsync_mutex_args *args)
|
||||||
+{
|
+{
|
||||||
+ lockdep_assert_held(&mutex->lock);
|
+ lockdep_assert_held(&mutex->lock);
|
||||||
|
@ -30,11 +34,11 @@ index d48f2ef41341..28f43768d1c3 100644
|
||||||
+ return 0;
|
+ return 0;
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
+static int ntsync_put_mutex(struct ntsync_device *dev, void __user *argp)
|
+static int ntsync_mutex_unlock(struct ntsync_obj *mutex, void __user *argp)
|
||||||
+{
|
+{
|
||||||
+ struct ntsync_mutex_args __user *user_args = argp;
|
+ struct ntsync_mutex_args __user *user_args = argp;
|
||||||
|
+ struct ntsync_device *dev = mutex->dev;
|
||||||
+ struct ntsync_mutex_args args;
|
+ struct ntsync_mutex_args args;
|
||||||
+ struct ntsync_obj *mutex;
|
|
||||||
+ __u32 prev_count;
|
+ __u32 prev_count;
|
||||||
+ int ret;
|
+ int ret;
|
||||||
+
|
+
|
||||||
|
@ -43,8 +47,7 @@ index d48f2ef41341..28f43768d1c3 100644
|
||||||
+ if (!args.owner)
|
+ if (!args.owner)
|
||||||
+ return -EINVAL;
|
+ return -EINVAL;
|
||||||
+
|
+
|
||||||
+ mutex = get_obj_typed(dev, args.mutex, NTSYNC_TYPE_MUTEX);
|
+ if (mutex->type != NTSYNC_TYPE_MUTEX)
|
||||||
+ if (!mutex)
|
|
||||||
+ return -EINVAL;
|
+ return -EINVAL;
|
||||||
+
|
+
|
||||||
+ if (atomic_read(&mutex->all_hint) > 0) {
|
+ if (atomic_read(&mutex->all_hint) > 0) {
|
||||||
|
@ -52,7 +55,7 @@ index d48f2ef41341..28f43768d1c3 100644
|
||||||
+ spin_lock_nest_lock(&mutex->lock, &dev->wait_all_lock);
|
+ spin_lock_nest_lock(&mutex->lock, &dev->wait_all_lock);
|
||||||
+
|
+
|
||||||
+ prev_count = mutex->u.mutex.count;
|
+ prev_count = mutex->u.mutex.count;
|
||||||
+ ret = put_mutex_state(mutex, &args);
|
+ ret = unlock_mutex_state(mutex, &args);
|
||||||
+ if (!ret) {
|
+ if (!ret) {
|
||||||
+ try_wake_all_obj(dev, mutex);
|
+ try_wake_all_obj(dev, mutex);
|
||||||
+ try_wake_any_mutex(mutex);
|
+ try_wake_any_mutex(mutex);
|
||||||
|
@ -64,43 +67,40 @@ index d48f2ef41341..28f43768d1c3 100644
|
||||||
+ spin_lock(&mutex->lock);
|
+ spin_lock(&mutex->lock);
|
||||||
+
|
+
|
||||||
+ prev_count = mutex->u.mutex.count;
|
+ prev_count = mutex->u.mutex.count;
|
||||||
+ ret = put_mutex_state(mutex, &args);
|
+ ret = unlock_mutex_state(mutex, &args);
|
||||||
+ if (!ret)
|
+ if (!ret)
|
||||||
+ try_wake_any_mutex(mutex);
|
+ try_wake_any_mutex(mutex);
|
||||||
+
|
+
|
||||||
+ spin_unlock(&mutex->lock);
|
+ spin_unlock(&mutex->lock);
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ put_obj(mutex);
|
|
||||||
+
|
|
||||||
+ if (!ret && put_user(prev_count, &user_args->count))
|
+ if (!ret && put_user(prev_count, &user_args->count))
|
||||||
+ ret = -EFAULT;
|
+ ret = -EFAULT;
|
||||||
+
|
+
|
||||||
+ return ret;
|
+ return ret;
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
static int ntsync_schedule(const struct ntsync_q *q, ktime_t *timeout)
|
static int ntsync_obj_release(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
struct ntsync_obj *obj = file->private_data;
|
||||||
@@ -738,6 +803,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd,
|
@@ -331,6 +393,8 @@ static long ntsync_obj_ioctl(struct file *file, unsigned int cmd,
|
||||||
return ntsync_create_sem(dev, argp);
|
switch (cmd) {
|
||||||
case NTSYNC_IOC_DELETE:
|
case NTSYNC_IOC_SEM_POST:
|
||||||
return ntsync_delete(dev, argp);
|
return ntsync_sem_post(obj, argp);
|
||||||
+ case NTSYNC_IOC_PUT_MUTEX:
|
+ case NTSYNC_IOC_MUTEX_UNLOCK:
|
||||||
+ return ntsync_put_mutex(dev, argp);
|
+ return ntsync_mutex_unlock(obj, argp);
|
||||||
case NTSYNC_IOC_PUT_SEM:
|
default:
|
||||||
return ntsync_put_sem(dev, argp);
|
return -ENOIOCTLCMD;
|
||||||
case NTSYNC_IOC_WAIT_ALL:
|
}
|
||||||
diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h
|
diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h
|
||||||
index 26d1b3d4847f..2e44e7e77776 100644
|
index 8ac9d419c360..265503d441b1 100644
|
||||||
--- a/include/uapi/linux/ntsync.h
|
--- a/include/uapi/linux/ntsync.h
|
||||||
+++ b/include/uapi/linux/ntsync.h
|
+++ b/include/uapi/linux/ntsync.h
|
||||||
@@ -46,5 +46,7 @@ struct ntsync_wait_args {
|
@@ -39,5 +39,6 @@ struct ntsync_wait_args {
|
||||||
struct ntsync_wait_args)
|
#define NTSYNC_IOC_CREATE_MUTEX _IOWR('N', 0x84, struct ntsync_sem_args)
|
||||||
#define NTSYNC_IOC_CREATE_MUTEX _IOWR(NTSYNC_IOC_BASE, 5, \
|
|
||||||
struct ntsync_mutex_args)
|
#define NTSYNC_IOC_SEM_POST _IOWR('N', 0x81, __u32)
|
||||||
+#define NTSYNC_IOC_PUT_MUTEX _IOWR(NTSYNC_IOC_BASE, 6, \
|
+#define NTSYNC_IOC_MUTEX_UNLOCK _IOWR('N', 0x85, struct ntsync_mutex_args)
|
||||||
+ struct ntsync_mutex_args)
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
--
|
--
|
|
@ -0,0 +1,166 @@
|
||||||
|
This does not correspond to any NT syscall. Rather, when a thread dies, it
|
||||||
|
should be called by the NT emulator for each mutex.
|
||||||
|
|
||||||
|
NT mutexes are robust (in the pthread sense). When an NT thread dies, any
|
||||||
|
mutexes it owned are immediately released. Acquisition of those mutexes by other
|
||||||
|
threads will return a special value indicating that the mutex was abandoned,
|
||||||
|
like EOWNERDEAD returned from pthread_mutex_lock(), and EOWNERDEAD is indeed
|
||||||
|
used here for that purpose.
|
||||||
|
|
||||||
|
Signed-off-by: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
---
|
||||||
|
drivers/misc/ntsync.c | 71 +++++++++++++++++++++++++++++++++++--
|
||||||
|
include/uapi/linux/ntsync.h | 1 +
|
||||||
|
2 files changed, 70 insertions(+), 2 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c
|
||||||
|
index 222ebead8eba..a3466be50c45 100644
|
||||||
|
--- a/drivers/misc/ntsync.c
|
||||||
|
+++ b/drivers/misc/ntsync.c
|
||||||
|
@@ -57,6 +57,7 @@ struct ntsync_obj {
|
||||||
|
struct {
|
||||||
|
__u32 count;
|
||||||
|
__u32 owner;
|
||||||
|
+ bool ownerdead;
|
||||||
|
} mutex;
|
||||||
|
} u;
|
||||||
|
|
||||||
|
@@ -109,6 +110,7 @@ struct ntsync_q {
|
||||||
|
atomic_t signaled;
|
||||||
|
|
||||||
|
bool all;
|
||||||
|
+ bool ownerdead;
|
||||||
|
__u32 count;
|
||||||
|
struct ntsync_q_entry entries[];
|
||||||
|
};
|
||||||
|
@@ -184,6 +186,9 @@ static void try_wake_all(struct ntsync_device *dev, struct ntsync_q *q,
|
||||||
|
obj->u.sem.count--;
|
||||||
|
break;
|
||||||
|
case NTSYNC_TYPE_MUTEX:
|
||||||
|
+ if (obj->u.mutex.ownerdead)
|
||||||
|
+ q->ownerdead = true;
|
||||||
|
+ obj->u.mutex.ownerdead = false;
|
||||||
|
obj->u.mutex.count++;
|
||||||
|
obj->u.mutex.owner = q->owner;
|
||||||
|
break;
|
||||||
|
@@ -243,6 +248,9 @@ static void try_wake_any_mutex(struct ntsync_obj *mutex)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (atomic_cmpxchg(&q->signaled, -1, entry->index) == -1) {
|
||||||
|
+ if (mutex->u.mutex.ownerdead)
|
||||||
|
+ q->ownerdead = true;
|
||||||
|
+ mutex->u.mutex.ownerdead = false;
|
||||||
|
mutex->u.mutex.count++;
|
||||||
|
mutex->u.mutex.owner = q->owner;
|
||||||
|
wake_up_process(q->task);
|
||||||
|
@@ -374,6 +382,62 @@ static int ntsync_mutex_unlock(struct ntsync_obj *mutex, void __user *argp)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
+/*
|
||||||
|
+ * Actually change the mutex state to mark its owner as dead,
|
||||||
|
+ * returning -EPERM if not the owner.
|
||||||
|
+ */
|
||||||
|
+static int kill_mutex_state(struct ntsync_obj *mutex, __u32 owner)
|
||||||
|
+{
|
||||||
|
+ lockdep_assert_held(&mutex->lock);
|
||||||
|
+
|
||||||
|
+ if (mutex->u.mutex.owner != owner)
|
||||||
|
+ return -EPERM;
|
||||||
|
+
|
||||||
|
+ mutex->u.mutex.ownerdead = true;
|
||||||
|
+ mutex->u.mutex.owner = 0;
|
||||||
|
+ mutex->u.mutex.count = 0;
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int ntsync_mutex_kill(struct ntsync_obj *mutex, void __user *argp)
|
||||||
|
+{
|
||||||
|
+ struct ntsync_device *dev = mutex->dev;
|
||||||
|
+ __u32 owner;
|
||||||
|
+ int ret;
|
||||||
|
+
|
||||||
|
+ if (get_user(owner, (__u32 __user *)argp))
|
||||||
|
+ return -EFAULT;
|
||||||
|
+ if (!owner)
|
||||||
|
+ return -EINVAL;
|
||||||
|
+
|
||||||
|
+ if (mutex->type != NTSYNC_TYPE_MUTEX)
|
||||||
|
+ return -EINVAL;
|
||||||
|
+
|
||||||
|
+ if (atomic_read(&mutex->all_hint) > 0) {
|
||||||
|
+ spin_lock(&dev->wait_all_lock);
|
||||||
|
+ spin_lock_nest_lock(&mutex->lock, &dev->wait_all_lock);
|
||||||
|
+
|
||||||
|
+ ret = kill_mutex_state(mutex, owner);
|
||||||
|
+ if (!ret) {
|
||||||
|
+ try_wake_all_obj(dev, mutex);
|
||||||
|
+ try_wake_any_mutex(mutex);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ spin_unlock(&mutex->lock);
|
||||||
|
+ spin_unlock(&dev->wait_all_lock);
|
||||||
|
+ } else {
|
||||||
|
+ spin_lock(&mutex->lock);
|
||||||
|
+
|
||||||
|
+ ret = kill_mutex_state(mutex, owner);
|
||||||
|
+ if (!ret)
|
||||||
|
+ try_wake_any_mutex(mutex);
|
||||||
|
+
|
||||||
|
+ spin_unlock(&mutex->lock);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static int ntsync_obj_release(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
struct ntsync_obj *obj = file->private_data;
|
||||||
|
@@ -395,6 +459,8 @@ static long ntsync_obj_ioctl(struct file *file, unsigned int cmd,
|
||||||
|
return ntsync_sem_post(obj, argp);
|
||||||
|
case NTSYNC_IOC_MUTEX_UNLOCK:
|
||||||
|
return ntsync_mutex_unlock(obj, argp);
|
||||||
|
+ case NTSYNC_IOC_MUTEX_KILL:
|
||||||
|
+ return ntsync_mutex_kill(obj, argp);
|
||||||
|
default:
|
||||||
|
return -ENOIOCTLCMD;
|
||||||
|
}
|
||||||
|
@@ -579,6 +645,7 @@ static int setup_wait(struct ntsync_device *dev,
|
||||||
|
q->owner = args->owner;
|
||||||
|
atomic_set(&q->signaled, -1);
|
||||||
|
q->all = all;
|
||||||
|
+ q->ownerdead = false;
|
||||||
|
q->count = count;
|
||||||
|
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
@@ -686,7 +753,7 @@ static int ntsync_wait_any(struct ntsync_device *dev, void __user *argp)
|
||||||
|
struct ntsync_wait_args __user *user_args = argp;
|
||||||
|
|
||||||
|
/* even if we caught a signal, we need to communicate success */
|
||||||
|
- ret = 0;
|
||||||
|
+ ret = q->ownerdead ? -EOWNERDEAD : 0;
|
||||||
|
|
||||||
|
if (put_user(signaled, &user_args->index))
|
||||||
|
ret = -EFAULT;
|
||||||
|
@@ -767,7 +834,7 @@ static int ntsync_wait_all(struct ntsync_device *dev, void __user *argp)
|
||||||
|
struct ntsync_wait_args __user *user_args = argp;
|
||||||
|
|
||||||
|
/* even if we caught a signal, we need to communicate success */
|
||||||
|
- ret = 0;
|
||||||
|
+ ret = q->ownerdead ? -EOWNERDEAD : 0;
|
||||||
|
|
||||||
|
if (put_user(signaled, &user_args->index))
|
||||||
|
ret = -EFAULT;
|
||||||
|
diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h
|
||||||
|
index 265503d441b1..4800941fcbda 100644
|
||||||
|
--- a/include/uapi/linux/ntsync.h
|
||||||
|
+++ b/include/uapi/linux/ntsync.h
|
||||||
|
@@ -40,5 +40,6 @@ struct ntsync_wait_args {
|
||||||
|
|
||||||
|
#define NTSYNC_IOC_SEM_POST _IOWR('N', 0x81, __u32)
|
||||||
|
#define NTSYNC_IOC_MUTEX_UNLOCK _IOWR('N', 0x85, struct ntsync_mutex_args)
|
||||||
|
+#define NTSYNC_IOC_MUTEX_KILL _IOW ('N', 0x86, __u32)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
--
|
||||||
|
2.43.0
|
|
@ -1,170 +0,0 @@
|
||||||
This does not correspond to any NT syscall, but rather should be called by the
|
|
||||||
user-space NT emulator when a thread dies. It is responsible for marking any
|
|
||||||
mutexes owned by that thread as abandoned.
|
|
||||||
|
|
||||||
Signed-off-by: Elizabeth Figura <zfigura@codeweavers.com>
|
|
||||||
---
|
|
||||||
drivers/misc/ntsync.c | 80 ++++++++++++++++++++++++++++++++++++-
|
|
||||||
include/uapi/linux/ntsync.h | 1 +
|
|
||||||
2 files changed, 79 insertions(+), 2 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c
|
|
||||||
index 28f43768d1c3..1173c750c106 100644
|
|
||||||
--- a/drivers/misc/ntsync.c
|
|
||||||
+++ b/drivers/misc/ntsync.c
|
|
||||||
@@ -64,6 +64,7 @@ struct ntsync_obj {
|
|
||||||
struct {
|
|
||||||
__u32 count;
|
|
||||||
__u32 owner;
|
|
||||||
+ bool ownerdead;
|
|
||||||
} mutex;
|
|
||||||
} u;
|
|
||||||
};
|
|
||||||
@@ -87,6 +88,7 @@ struct ntsync_q {
|
|
||||||
atomic_t signaled;
|
|
||||||
|
|
||||||
bool all;
|
|
||||||
+ bool ownerdead;
|
|
||||||
__u32 count;
|
|
||||||
struct ntsync_q_entry entries[];
|
|
||||||
};
|
|
||||||
@@ -240,6 +242,9 @@ static void try_wake_all(struct ntsync_device *dev, struct ntsync_q *q,
|
|
||||||
obj->u.sem.count--;
|
|
||||||
break;
|
|
||||||
case NTSYNC_TYPE_MUTEX:
|
|
||||||
+ if (obj->u.mutex.ownerdead)
|
|
||||||
+ q->ownerdead = true;
|
|
||||||
+ obj->u.mutex.ownerdead = false;
|
|
||||||
obj->u.mutex.count++;
|
|
||||||
obj->u.mutex.owner = q->owner;
|
|
||||||
break;
|
|
||||||
@@ -299,6 +304,9 @@ static void try_wake_any_mutex(struct ntsync_obj *mutex)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (atomic_cmpxchg(&q->signaled, -1, entry->index) == -1) {
|
|
||||||
+ if (mutex->u.mutex.ownerdead)
|
|
||||||
+ q->ownerdead = true;
|
|
||||||
+ mutex->u.mutex.ownerdead = false;
|
|
||||||
mutex->u.mutex.count++;
|
|
||||||
mutex->u.mutex.owner = q->owner;
|
|
||||||
wake_up_process(q->task);
|
|
||||||
@@ -514,6 +522,71 @@ static int ntsync_put_mutex(struct ntsync_device *dev, void __user *argp)
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
+/*
|
|
||||||
+ * Actually change the mutex state to mark its owner as dead.
|
|
||||||
+ */
|
|
||||||
+static void put_mutex_ownerdead_state(struct ntsync_obj *mutex)
|
|
||||||
+{
|
|
||||||
+ lockdep_assert_held(&mutex->lock);
|
|
||||||
+
|
|
||||||
+ mutex->u.mutex.ownerdead = true;
|
|
||||||
+ mutex->u.mutex.owner = 0;
|
|
||||||
+ mutex->u.mutex.count = 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int ntsync_kill_owner(struct ntsync_device *dev, void __user *argp)
|
|
||||||
+{
|
|
||||||
+ struct ntsync_obj *obj;
|
|
||||||
+ unsigned long id;
|
|
||||||
+ __u32 owner;
|
|
||||||
+
|
|
||||||
+ if (get_user(owner, (__u32 __user *)argp))
|
|
||||||
+ return -EFAULT;
|
|
||||||
+ if (!owner)
|
|
||||||
+ return -EINVAL;
|
|
||||||
+
|
|
||||||
+ rcu_read_lock();
|
|
||||||
+
|
|
||||||
+ xa_for_each(&dev->objects, id, obj) {
|
|
||||||
+ if (!kref_get_unless_zero(&obj->refcount))
|
|
||||||
+ continue;
|
|
||||||
+
|
|
||||||
+ if (obj->type != NTSYNC_TYPE_MUTEX) {
|
|
||||||
+ put_obj(obj);
|
|
||||||
+ continue;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (atomic_read(&obj->all_hint) > 0) {
|
|
||||||
+ spin_lock(&dev->wait_all_lock);
|
|
||||||
+ spin_lock_nest_lock(&obj->lock, &dev->wait_all_lock);
|
|
||||||
+
|
|
||||||
+ if (obj->u.mutex.owner == owner) {
|
|
||||||
+ put_mutex_ownerdead_state(obj);
|
|
||||||
+ try_wake_all_obj(dev, obj);
|
|
||||||
+ try_wake_any_mutex(obj);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ spin_unlock(&obj->lock);
|
|
||||||
+ spin_unlock(&dev->wait_all_lock);
|
|
||||||
+ } else {
|
|
||||||
+ spin_lock(&obj->lock);
|
|
||||||
+
|
|
||||||
+ if (obj->u.mutex.owner == owner) {
|
|
||||||
+ put_mutex_ownerdead_state(obj);
|
|
||||||
+ try_wake_any_mutex(obj);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ spin_unlock(&obj->lock);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ put_obj(obj);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ rcu_read_unlock();
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
static int ntsync_schedule(const struct ntsync_q *q, ktime_t *timeout)
|
|
||||||
{
|
|
||||||
int ret = 0;
|
|
||||||
@@ -585,6 +658,7 @@ static int setup_wait(struct ntsync_device *dev,
|
|
||||||
q->owner = args->owner;
|
|
||||||
atomic_set(&q->signaled, -1);
|
|
||||||
q->all = all;
|
|
||||||
+ q->ownerdead = false;
|
|
||||||
q->count = count;
|
|
||||||
|
|
||||||
for (i = 0; i < count; i++) {
|
|
||||||
@@ -697,7 +771,7 @@ static int ntsync_wait_any(struct ntsync_device *dev, void __user *argp)
|
|
||||||
struct ntsync_wait_args __user *user_args = argp;
|
|
||||||
|
|
||||||
/* even if we caught a signal, we need to communicate success */
|
|
||||||
- ret = 0;
|
|
||||||
+ ret = q->ownerdead ? -EOWNERDEAD : 0;
|
|
||||||
|
|
||||||
if (put_user(signaled, &user_args->index))
|
|
||||||
ret = -EFAULT;
|
|
||||||
@@ -778,7 +852,7 @@ static int ntsync_wait_all(struct ntsync_device *dev, void __user *argp)
|
|
||||||
struct ntsync_wait_args __user *user_args = argp;
|
|
||||||
|
|
||||||
/* even if we caught a signal, we need to communicate success */
|
|
||||||
- ret = 0;
|
|
||||||
+ ret = q->ownerdead ? -EOWNERDEAD : 0;
|
|
||||||
|
|
||||||
if (put_user(signaled, &user_args->index))
|
|
||||||
ret = -EFAULT;
|
|
||||||
@@ -803,6 +877,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd,
|
|
||||||
return ntsync_create_sem(dev, argp);
|
|
||||||
case NTSYNC_IOC_DELETE:
|
|
||||||
return ntsync_delete(dev, argp);
|
|
||||||
+ case NTSYNC_IOC_KILL_OWNER:
|
|
||||||
+ return ntsync_kill_owner(dev, argp);
|
|
||||||
case NTSYNC_IOC_PUT_MUTEX:
|
|
||||||
return ntsync_put_mutex(dev, argp);
|
|
||||||
case NTSYNC_IOC_PUT_SEM:
|
|
||||||
diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h
|
|
||||||
index 2e44e7e77776..fec9a3993322 100644
|
|
||||||
--- a/include/uapi/linux/ntsync.h
|
|
||||||
+++ b/include/uapi/linux/ntsync.h
|
|
||||||
@@ -48,5 +48,6 @@ struct ntsync_wait_args {
|
|
||||||
struct ntsync_mutex_args)
|
|
||||||
#define NTSYNC_IOC_PUT_MUTEX _IOWR(NTSYNC_IOC_BASE, 6, \
|
|
||||||
struct ntsync_mutex_args)
|
|
||||||
+#define NTSYNC_IOC_KILL_OWNER _IOW (NTSYNC_IOC_BASE, 7, __u32)
|
|
||||||
|
|
||||||
#endif
|
|
||||||
--
|
|
||||||
2.43.0
|
|
|
@ -0,0 +1,165 @@
|
||||||
|
This correspond to the NT syscall NtCreateEvent().
|
||||||
|
|
||||||
|
An NT event holds a single bit of state denoting whether it is signaled or
|
||||||
|
unsignaled.
|
||||||
|
|
||||||
|
There are two types of events: manual-reset and automatic-reset. When an
|
||||||
|
automatic-reset event is acquired via a wait function, its state is reset to
|
||||||
|
unsignaled. Manual-reset events are not affected by wait functions.
|
||||||
|
|
||||||
|
Whether the event is manual-reset, and its initial state, are specified at
|
||||||
|
creation time.
|
||||||
|
|
||||||
|
Signed-off-by: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
---
|
||||||
|
drivers/misc/ntsync.c | 60 +++++++++++++++++++++++++++++++++++++
|
||||||
|
include/uapi/linux/ntsync.h | 7 +++++
|
||||||
|
2 files changed, 67 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c
|
||||||
|
index a3466be50c45..17dd47d06e0a 100644
|
||||||
|
--- a/drivers/misc/ntsync.c
|
||||||
|
+++ b/drivers/misc/ntsync.c
|
||||||
|
@@ -25,6 +25,7 @@
|
||||||
|
enum ntsync_type {
|
||||||
|
NTSYNC_TYPE_SEM,
|
||||||
|
NTSYNC_TYPE_MUTEX,
|
||||||
|
+ NTSYNC_TYPE_EVENT,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
@@ -59,6 +60,10 @@ struct ntsync_obj {
|
||||||
|
__u32 owner;
|
||||||
|
bool ownerdead;
|
||||||
|
} mutex;
|
||||||
|
+ struct {
|
||||||
|
+ bool manual;
|
||||||
|
+ bool signaled;
|
||||||
|
+ } event;
|
||||||
|
} u;
|
||||||
|
|
||||||
|
/*
|
||||||
|
@@ -143,6 +148,8 @@ static bool is_signaled(struct ntsync_obj *obj, __u32 owner)
|
||||||
|
if (obj->u.mutex.owner && obj->u.mutex.owner != owner)
|
||||||
|
return false;
|
||||||
|
return obj->u.mutex.count < UINT_MAX;
|
||||||
|
+ case NTSYNC_TYPE_EVENT:
|
||||||
|
+ return obj->u.event.signaled;
|
||||||
|
}
|
||||||
|
|
||||||
|
WARN(1, "bad object type %#x\n", obj->type);
|
||||||
|
@@ -192,6 +199,10 @@ static void try_wake_all(struct ntsync_device *dev, struct ntsync_q *q,
|
||||||
|
obj->u.mutex.count++;
|
||||||
|
obj->u.mutex.owner = q->owner;
|
||||||
|
break;
|
||||||
|
+ case NTSYNC_TYPE_EVENT:
|
||||||
|
+ if (!obj->u.event.manual)
|
||||||
|
+ obj->u.event.signaled = false;
|
||||||
|
+ break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wake_up_process(q->task);
|
||||||
|
@@ -258,6 +269,26 @@ static void try_wake_any_mutex(struct ntsync_obj *mutex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+static void try_wake_any_event(struct ntsync_obj *event)
|
||||||
|
+{
|
||||||
|
+ struct ntsync_q_entry *entry;
|
||||||
|
+
|
||||||
|
+ lockdep_assert_held(&event->lock);
|
||||||
|
+
|
||||||
|
+ list_for_each_entry(entry, &event->any_waiters, node) {
|
||||||
|
+ struct ntsync_q *q = entry->q;
|
||||||
|
+
|
||||||
|
+ if (!event->u.event.signaled)
|
||||||
|
+ break;
|
||||||
|
+
|
||||||
|
+ if (atomic_cmpxchg(&q->signaled, -1, entry->index) == -1) {
|
||||||
|
+ if (!event->u.event.manual)
|
||||||
|
+ event->u.event.signaled = false;
|
||||||
|
+ wake_up_process(q->task);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* Actually change the semaphore state, returning -EOVERFLOW if it is made
|
||||||
|
* invalid.
|
||||||
|
@@ -566,6 +597,30 @@ static int ntsync_create_mutex(struct ntsync_device *dev, void __user *argp)
|
||||||
|
return put_user(fd, &user_args->mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int ntsync_create_event(struct ntsync_device *dev, void __user *argp)
|
||||||
|
+{
|
||||||
|
+ struct ntsync_event_args __user *user_args = argp;
|
||||||
|
+ struct ntsync_event_args args;
|
||||||
|
+ struct ntsync_obj *event;
|
||||||
|
+ int fd;
|
||||||
|
+
|
||||||
|
+ if (copy_from_user(&args, argp, sizeof(args)))
|
||||||
|
+ return -EFAULT;
|
||||||
|
+
|
||||||
|
+ event = ntsync_alloc_obj(dev, NTSYNC_TYPE_EVENT);
|
||||||
|
+ if (!event)
|
||||||
|
+ return -ENOMEM;
|
||||||
|
+ event->u.event.manual = args.manual;
|
||||||
|
+ event->u.event.signaled = args.signaled;
|
||||||
|
+ fd = ntsync_obj_get_fd(event);
|
||||||
|
+ if (fd < 0) {
|
||||||
|
+ kfree(event);
|
||||||
|
+ return fd;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return put_user(fd, &user_args->event);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static struct ntsync_obj *get_obj(struct ntsync_device *dev, int fd)
|
||||||
|
{
|
||||||
|
struct file *file = fget(fd);
|
||||||
|
@@ -689,6 +744,9 @@ static void try_wake_any_obj(struct ntsync_obj *obj)
|
||||||
|
case NTSYNC_TYPE_MUTEX:
|
||||||
|
try_wake_any_mutex(obj);
|
||||||
|
break;
|
||||||
|
+ case NTSYNC_TYPE_EVENT:
|
||||||
|
+ try_wake_any_event(obj);
|
||||||
|
+ break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -877,6 +935,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd,
|
||||||
|
void __user *argp = (void __user *)parm;
|
||||||
|
|
||||||
|
switch (cmd) {
|
||||||
|
+ case NTSYNC_IOC_CREATE_EVENT:
|
||||||
|
+ return ntsync_create_event(dev, argp);
|
||||||
|
case NTSYNC_IOC_CREATE_MUTEX:
|
||||||
|
return ntsync_create_mutex(dev, argp);
|
||||||
|
case NTSYNC_IOC_CREATE_SEM:
|
||||||
|
diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h
|
||||||
|
index 4800941fcbda..040cbdb39033 100644
|
||||||
|
--- a/include/uapi/linux/ntsync.h
|
||||||
|
+++ b/include/uapi/linux/ntsync.h
|
||||||
|
@@ -22,6 +22,12 @@ struct ntsync_mutex_args {
|
||||||
|
__u32 count;
|
||||||
|
};
|
||||||
|
|
||||||
|
+struct ntsync_event_args {
|
||||||
|
+ __u32 event;
|
||||||
|
+ __u32 manual;
|
||||||
|
+ __u32 signaled;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
struct ntsync_wait_args {
|
||||||
|
__u64 timeout;
|
||||||
|
__u64 objs;
|
||||||
|
@@ -37,6 +43,7 @@ struct ntsync_wait_args {
|
||||||
|
#define NTSYNC_IOC_WAIT_ANY _IOWR('N', 0x82, struct ntsync_wait_args)
|
||||||
|
#define NTSYNC_IOC_WAIT_ALL _IOWR('N', 0x83, struct ntsync_wait_args)
|
||||||
|
#define NTSYNC_IOC_CREATE_MUTEX _IOWR('N', 0x84, struct ntsync_sem_args)
|
||||||
|
+#define NTSYNC_IOC_CREATE_EVENT _IOWR('N', 0x87, struct ntsync_event_args)
|
||||||
|
|
||||||
|
#define NTSYNC_IOC_SEM_POST _IOWR('N', 0x81, __u32)
|
||||||
|
#define NTSYNC_IOC_MUTEX_UNLOCK _IOWR('N', 0x85, struct ntsync_mutex_args)
|
||||||
|
--
|
||||||
|
2.43.0
|
|
@ -0,0 +1,78 @@
|
||||||
|
This corresponds to the NT syscall NtSetEvent().
|
||||||
|
|
||||||
|
This sets the event to the signaled state, and returns its previous state.
|
||||||
|
|
||||||
|
Signed-off-by: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
---
|
||||||
|
drivers/misc/ntsync.c | 37 +++++++++++++++++++++++++++++++++++++
|
||||||
|
include/uapi/linux/ntsync.h | 1 +
|
||||||
|
2 files changed, 38 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c
|
||||||
|
index 17dd47d06e0a..edfbf11cafe0 100644
|
||||||
|
--- a/drivers/misc/ntsync.c
|
||||||
|
+++ b/drivers/misc/ntsync.c
|
||||||
|
@@ -469,6 +469,41 @@ static int ntsync_mutex_kill(struct ntsync_obj *mutex, void __user *argp)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int ntsync_event_set(struct ntsync_obj *event, void __user *argp)
|
||||||
|
+{
|
||||||
|
+ struct ntsync_device *dev = event->dev;
|
||||||
|
+ __u32 prev_state;
|
||||||
|
+
|
||||||
|
+ if (event->type != NTSYNC_TYPE_EVENT)
|
||||||
|
+ return -EINVAL;
|
||||||
|
+
|
||||||
|
+ if (atomic_read(&event->all_hint) > 0) {
|
||||||
|
+ spin_lock(&dev->wait_all_lock);
|
||||||
|
+ spin_lock_nest_lock(&event->lock, &dev->wait_all_lock);
|
||||||
|
+
|
||||||
|
+ prev_state = event->u.event.signaled;
|
||||||
|
+ event->u.event.signaled = true;
|
||||||
|
+ try_wake_all_obj(dev, event);
|
||||||
|
+ try_wake_any_event(event);
|
||||||
|
+
|
||||||
|
+ spin_unlock(&event->lock);
|
||||||
|
+ spin_unlock(&dev->wait_all_lock);
|
||||||
|
+ } else {
|
||||||
|
+ spin_lock(&event->lock);
|
||||||
|
+
|
||||||
|
+ prev_state = event->u.event.signaled;
|
||||||
|
+ event->u.event.signaled = true;
|
||||||
|
+ try_wake_any_event(event);
|
||||||
|
+
|
||||||
|
+ spin_unlock(&event->lock);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (put_user(prev_state, (__u32 __user *)argp))
|
||||||
|
+ return -EFAULT;
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static int ntsync_obj_release(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
struct ntsync_obj *obj = file->private_data;
|
||||||
|
@@ -492,6 +527,8 @@ static long ntsync_obj_ioctl(struct file *file, unsigned int cmd,
|
||||||
|
return ntsync_mutex_unlock(obj, argp);
|
||||||
|
case NTSYNC_IOC_MUTEX_KILL:
|
||||||
|
return ntsync_mutex_kill(obj, argp);
|
||||||
|
+ case NTSYNC_IOC_EVENT_SET:
|
||||||
|
+ return ntsync_event_set(obj, argp);
|
||||||
|
default:
|
||||||
|
return -ENOIOCTLCMD;
|
||||||
|
}
|
||||||
|
diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h
|
||||||
|
index 040cbdb39033..af518530bffd 100644
|
||||||
|
--- a/include/uapi/linux/ntsync.h
|
||||||
|
+++ b/include/uapi/linux/ntsync.h
|
||||||
|
@@ -48,5 +48,6 @@ struct ntsync_wait_args {
|
||||||
|
#define NTSYNC_IOC_SEM_POST _IOWR('N', 0x81, __u32)
|
||||||
|
#define NTSYNC_IOC_MUTEX_UNLOCK _IOWR('N', 0x85, struct ntsync_mutex_args)
|
||||||
|
#define NTSYNC_IOC_MUTEX_KILL _IOW ('N', 0x86, __u32)
|
||||||
|
+#define NTSYNC_IOC_EVENT_SET _IOR ('N', 0x88, __u32)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
--
|
||||||
|
2.43.0
|
|
@ -0,0 +1,63 @@
|
||||||
|
This corresponds to the NT syscall NtResetEvent().
|
||||||
|
|
||||||
|
This sets the event to the unsignaled state, and returns its previous state.
|
||||||
|
|
||||||
|
Signed-off-by: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
---
|
||||||
|
drivers/misc/ntsync.c | 22 ++++++++++++++++++++++
|
||||||
|
include/uapi/linux/ntsync.h | 1 +
|
||||||
|
2 files changed, 23 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c
|
||||||
|
index edfbf11cafe0..fa4c3fa1e496 100644
|
||||||
|
--- a/drivers/misc/ntsync.c
|
||||||
|
+++ b/drivers/misc/ntsync.c
|
||||||
|
@@ -504,6 +504,26 @@ static int ntsync_event_set(struct ntsync_obj *event, void __user *argp)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int ntsync_event_reset(struct ntsync_obj *event, void __user *argp)
|
||||||
|
+{
|
||||||
|
+ __u32 prev_state;
|
||||||
|
+
|
||||||
|
+ if (event->type != NTSYNC_TYPE_EVENT)
|
||||||
|
+ return -EINVAL;
|
||||||
|
+
|
||||||
|
+ spin_lock(&event->lock);
|
||||||
|
+
|
||||||
|
+ prev_state = event->u.event.signaled;
|
||||||
|
+ event->u.event.signaled = false;
|
||||||
|
+
|
||||||
|
+ spin_unlock(&event->lock);
|
||||||
|
+
|
||||||
|
+ if (put_user(prev_state, (__u32 __user *)argp))
|
||||||
|
+ return -EFAULT;
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static int ntsync_obj_release(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
struct ntsync_obj *obj = file->private_data;
|
||||||
|
@@ -529,6 +549,8 @@ static long ntsync_obj_ioctl(struct file *file, unsigned int cmd,
|
||||||
|
return ntsync_mutex_kill(obj, argp);
|
||||||
|
case NTSYNC_IOC_EVENT_SET:
|
||||||
|
return ntsync_event_set(obj, argp);
|
||||||
|
+ case NTSYNC_IOC_EVENT_RESET:
|
||||||
|
+ return ntsync_event_reset(obj, argp);
|
||||||
|
default:
|
||||||
|
return -ENOIOCTLCMD;
|
||||||
|
}
|
||||||
|
diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h
|
||||||
|
index af518530bffd..6963356ee3f7 100644
|
||||||
|
--- a/include/uapi/linux/ntsync.h
|
||||||
|
+++ b/include/uapi/linux/ntsync.h
|
||||||
|
@@ -49,5 +49,6 @@ struct ntsync_wait_args {
|
||||||
|
#define NTSYNC_IOC_MUTEX_UNLOCK _IOWR('N', 0x85, struct ntsync_mutex_args)
|
||||||
|
#define NTSYNC_IOC_MUTEX_KILL _IOW ('N', 0x86, __u32)
|
||||||
|
#define NTSYNC_IOC_EVENT_SET _IOR ('N', 0x88, __u32)
|
||||||
|
+#define NTSYNC_IOC_EVENT_RESET _IOR ('N', 0x89, __u32)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
--
|
||||||
|
2.43.0
|
|
@ -0,0 +1,70 @@
|
||||||
|
This corresponds to the NT syscall NtPulseEvent().
|
||||||
|
|
||||||
|
This wakes up any waiters as if the event had been set, but does not set the
|
||||||
|
event, instead resetting it if it had been signalled. Thus, for a manual-reset
|
||||||
|
event, all waiters are woken, whereas for an auto-reset event, at most one
|
||||||
|
waiter is woken.
|
||||||
|
|
||||||
|
Signed-off-by: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
---
|
||||||
|
drivers/misc/ntsync.c | 10 ++++++++--
|
||||||
|
include/uapi/linux/ntsync.h | 1 +
|
||||||
|
2 files changed, 9 insertions(+), 2 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c
|
||||||
|
index fa4c3fa1e496..b9b4127a6c9f 100644
|
||||||
|
--- a/drivers/misc/ntsync.c
|
||||||
|
+++ b/drivers/misc/ntsync.c
|
||||||
|
@@ -469,7 +469,7 @@ static int ntsync_mutex_kill(struct ntsync_obj *mutex, void __user *argp)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
-static int ntsync_event_set(struct ntsync_obj *event, void __user *argp)
|
||||||
|
+static int ntsync_event_set(struct ntsync_obj *event, void __user *argp, bool pulse)
|
||||||
|
{
|
||||||
|
struct ntsync_device *dev = event->dev;
|
||||||
|
__u32 prev_state;
|
||||||
|
@@ -485,6 +485,8 @@ static int ntsync_event_set(struct ntsync_obj *event, void __user *argp)
|
||||||
|
event->u.event.signaled = true;
|
||||||
|
try_wake_all_obj(dev, event);
|
||||||
|
try_wake_any_event(event);
|
||||||
|
+ if (pulse)
|
||||||
|
+ event->u.event.signaled = false;
|
||||||
|
|
||||||
|
spin_unlock(&event->lock);
|
||||||
|
spin_unlock(&dev->wait_all_lock);
|
||||||
|
@@ -494,6 +496,8 @@ static int ntsync_event_set(struct ntsync_obj *event, void __user *argp)
|
||||||
|
prev_state = event->u.event.signaled;
|
||||||
|
event->u.event.signaled = true;
|
||||||
|
try_wake_any_event(event);
|
||||||
|
+ if (pulse)
|
||||||
|
+ event->u.event.signaled = false;
|
||||||
|
|
||||||
|
spin_unlock(&event->lock);
|
||||||
|
}
|
||||||
|
@@ -548,9 +552,11 @@ static long ntsync_obj_ioctl(struct file *file, unsigned int cmd,
|
||||||
|
case NTSYNC_IOC_MUTEX_KILL:
|
||||||
|
return ntsync_mutex_kill(obj, argp);
|
||||||
|
case NTSYNC_IOC_EVENT_SET:
|
||||||
|
- return ntsync_event_set(obj, argp);
|
||||||
|
+ return ntsync_event_set(obj, argp, false);
|
||||||
|
case NTSYNC_IOC_EVENT_RESET:
|
||||||
|
return ntsync_event_reset(obj, argp);
|
||||||
|
+ case NTSYNC_IOC_EVENT_PULSE:
|
||||||
|
+ return ntsync_event_set(obj, argp, true);
|
||||||
|
default:
|
||||||
|
return -ENOIOCTLCMD;
|
||||||
|
}
|
||||||
|
diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h
|
||||||
|
index 6963356ee3f7..72047f36c45d 100644
|
||||||
|
--- a/include/uapi/linux/ntsync.h
|
||||||
|
+++ b/include/uapi/linux/ntsync.h
|
||||||
|
@@ -50,5 +50,6 @@ struct ntsync_wait_args {
|
||||||
|
#define NTSYNC_IOC_MUTEX_KILL _IOW ('N', 0x86, __u32)
|
||||||
|
#define NTSYNC_IOC_EVENT_SET _IOR ('N', 0x88, __u32)
|
||||||
|
#define NTSYNC_IOC_EVENT_RESET _IOR ('N', 0x89, __u32)
|
||||||
|
+#define NTSYNC_IOC_EVENT_PULSE _IOR ('N', 0x8a, __u32)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
--
|
||||||
|
2.43.0
|
|
@ -0,0 +1,62 @@
|
||||||
|
This corresponds to the NT syscall NtQuerySemaphore().
|
||||||
|
|
||||||
|
This returns the current count and maximum count of the semaphore.
|
||||||
|
|
||||||
|
Signed-off-by: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
---
|
||||||
|
drivers/misc/ntsync.c | 21 +++++++++++++++++++++
|
||||||
|
include/uapi/linux/ntsync.h | 1 +
|
||||||
|
2 files changed, 22 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c
|
||||||
|
index b9b4127a6c9f..0daaeeeba051 100644
|
||||||
|
--- a/drivers/misc/ntsync.c
|
||||||
|
+++ b/drivers/misc/ntsync.c
|
||||||
|
@@ -528,6 +528,25 @@ static int ntsync_event_reset(struct ntsync_obj *event, void __user *argp)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int ntsync_sem_read(struct ntsync_obj *sem, void __user *argp)
|
||||||
|
+{
|
||||||
|
+ struct ntsync_sem_args __user *user_args = argp;
|
||||||
|
+ struct ntsync_sem_args args;
|
||||||
|
+
|
||||||
|
+ if (sem->type != NTSYNC_TYPE_SEM)
|
||||||
|
+ return -EINVAL;
|
||||||
|
+
|
||||||
|
+ args.sem = 0;
|
||||||
|
+ spin_lock(&sem->lock);
|
||||||
|
+ args.count = sem->u.sem.count;
|
||||||
|
+ args.max = sem->u.sem.max;
|
||||||
|
+ spin_unlock(&sem->lock);
|
||||||
|
+
|
||||||
|
+ if (copy_to_user(user_args, &args, sizeof(args)))
|
||||||
|
+ return -EFAULT;
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static int ntsync_obj_release(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
struct ntsync_obj *obj = file->private_data;
|
||||||
|
@@ -547,6 +566,8 @@ static long ntsync_obj_ioctl(struct file *file, unsigned int cmd,
|
||||||
|
switch (cmd) {
|
||||||
|
case NTSYNC_IOC_SEM_POST:
|
||||||
|
return ntsync_sem_post(obj, argp);
|
||||||
|
+ case NTSYNC_IOC_SEM_READ:
|
||||||
|
+ return ntsync_sem_read(obj, argp);
|
||||||
|
case NTSYNC_IOC_MUTEX_UNLOCK:
|
||||||
|
return ntsync_mutex_unlock(obj, argp);
|
||||||
|
case NTSYNC_IOC_MUTEX_KILL:
|
||||||
|
diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h
|
||||||
|
index 72047f36c45d..42f51dc4e57e 100644
|
||||||
|
--- a/include/uapi/linux/ntsync.h
|
||||||
|
+++ b/include/uapi/linux/ntsync.h
|
||||||
|
@@ -51,5 +51,6 @@ struct ntsync_wait_args {
|
||||||
|
#define NTSYNC_IOC_EVENT_SET _IOR ('N', 0x88, __u32)
|
||||||
|
#define NTSYNC_IOC_EVENT_RESET _IOR ('N', 0x89, __u32)
|
||||||
|
#define NTSYNC_IOC_EVENT_PULSE _IOR ('N', 0x8a, __u32)
|
||||||
|
+#define NTSYNC_IOC_SEM_READ _IOR ('N', 0x8b, struct ntsync_sem_args)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
--
|
||||||
|
2.43.0
|
|
@ -0,0 +1,64 @@
|
||||||
|
This corresponds to the NT syscall NtQueryMutant().
|
||||||
|
|
||||||
|
This returns the recursion count, owner, and abandoned state of the mutex.
|
||||||
|
|
||||||
|
Signed-off-by: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
---
|
||||||
|
drivers/misc/ntsync.c | 23 +++++++++++++++++++++++
|
||||||
|
include/uapi/linux/ntsync.h | 1 +
|
||||||
|
2 files changed, 24 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c
|
||||||
|
index 0daaeeeba051..b07510035c1f 100644
|
||||||
|
--- a/drivers/misc/ntsync.c
|
||||||
|
+++ b/drivers/misc/ntsync.c
|
||||||
|
@@ -547,6 +547,27 @@ static int ntsync_sem_read(struct ntsync_obj *sem, void __user *argp)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int ntsync_mutex_read(struct ntsync_obj *mutex, void __user *argp)
|
||||||
|
+{
|
||||||
|
+ struct ntsync_mutex_args __user *user_args = argp;
|
||||||
|
+ struct ntsync_mutex_args args;
|
||||||
|
+ int ret;
|
||||||
|
+
|
||||||
|
+ if (mutex->type != NTSYNC_TYPE_MUTEX)
|
||||||
|
+ return -EINVAL;
|
||||||
|
+
|
||||||
|
+ args.mutex = 0;
|
||||||
|
+ spin_lock(&mutex->lock);
|
||||||
|
+ args.count = mutex->u.mutex.count;
|
||||||
|
+ args.owner = mutex->u.mutex.owner;
|
||||||
|
+ ret = mutex->u.mutex.ownerdead ? -EOWNERDEAD : 0;
|
||||||
|
+ spin_unlock(&mutex->lock);
|
||||||
|
+
|
||||||
|
+ if (copy_to_user(user_args, &args, sizeof(args)))
|
||||||
|
+ return -EFAULT;
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static int ntsync_obj_release(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
struct ntsync_obj *obj = file->private_data;
|
||||||
|
@@ -572,6 +593,8 @@ static long ntsync_obj_ioctl(struct file *file, unsigned int cmd,
|
||||||
|
return ntsync_mutex_unlock(obj, argp);
|
||||||
|
case NTSYNC_IOC_MUTEX_KILL:
|
||||||
|
return ntsync_mutex_kill(obj, argp);
|
||||||
|
+ case NTSYNC_IOC_MUTEX_READ:
|
||||||
|
+ return ntsync_mutex_read(obj, argp);
|
||||||
|
case NTSYNC_IOC_EVENT_SET:
|
||||||
|
return ntsync_event_set(obj, argp, false);
|
||||||
|
case NTSYNC_IOC_EVENT_RESET:
|
||||||
|
diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h
|
||||||
|
index 42f51dc4e57e..25f3296cfabf 100644
|
||||||
|
--- a/include/uapi/linux/ntsync.h
|
||||||
|
+++ b/include/uapi/linux/ntsync.h
|
||||||
|
@@ -52,5 +52,6 @@ struct ntsync_wait_args {
|
||||||
|
#define NTSYNC_IOC_EVENT_RESET _IOR ('N', 0x89, __u32)
|
||||||
|
#define NTSYNC_IOC_EVENT_PULSE _IOR ('N', 0x8a, __u32)
|
||||||
|
#define NTSYNC_IOC_SEM_READ _IOR ('N', 0x8b, struct ntsync_sem_args)
|
||||||
|
+#define NTSYNC_IOC_MUTEX_READ _IOR ('N', 0x8c, struct ntsync_mutex_args)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
--
|
||||||
|
2.43.0
|
|
@ -0,0 +1,62 @@
|
||||||
|
This corresponds to the NT syscall NtQueryEvent().
|
||||||
|
|
||||||
|
This returns the signaled state of the event and whether it is manual-reset.
|
||||||
|
|
||||||
|
Signed-off-by: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
---
|
||||||
|
drivers/misc/ntsync.c | 21 +++++++++++++++++++++
|
||||||
|
include/uapi/linux/ntsync.h | 1 +
|
||||||
|
2 files changed, 22 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c
|
||||||
|
index b07510035c1f..981a1545192c 100644
|
||||||
|
--- a/drivers/misc/ntsync.c
|
||||||
|
+++ b/drivers/misc/ntsync.c
|
||||||
|
@@ -568,6 +568,25 @@ static int ntsync_mutex_read(struct ntsync_obj *mutex, void __user *argp)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int ntsync_event_read(struct ntsync_obj *event, void __user *argp)
|
||||||
|
+{
|
||||||
|
+ struct ntsync_event_args __user *user_args = argp;
|
||||||
|
+ struct ntsync_event_args args;
|
||||||
|
+
|
||||||
|
+ if (event->type != NTSYNC_TYPE_EVENT)
|
||||||
|
+ return -EINVAL;
|
||||||
|
+
|
||||||
|
+ args.event = 0;
|
||||||
|
+ spin_lock(&event->lock);
|
||||||
|
+ args.manual = event->u.event.manual;
|
||||||
|
+ args.signaled = event->u.event.signaled;
|
||||||
|
+ spin_unlock(&event->lock);
|
||||||
|
+
|
||||||
|
+ if (copy_to_user(user_args, &args, sizeof(args)))
|
||||||
|
+ return -EFAULT;
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static int ntsync_obj_release(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
struct ntsync_obj *obj = file->private_data;
|
||||||
|
@@ -601,6 +620,8 @@ static long ntsync_obj_ioctl(struct file *file, unsigned int cmd,
|
||||||
|
return ntsync_event_reset(obj, argp);
|
||||||
|
case NTSYNC_IOC_EVENT_PULSE:
|
||||||
|
return ntsync_event_set(obj, argp, true);
|
||||||
|
+ case NTSYNC_IOC_EVENT_READ:
|
||||||
|
+ return ntsync_event_read(obj, argp);
|
||||||
|
default:
|
||||||
|
return -ENOIOCTLCMD;
|
||||||
|
}
|
||||||
|
diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h
|
||||||
|
index 25f3296cfabf..03c95e5a398f 100644
|
||||||
|
--- a/include/uapi/linux/ntsync.h
|
||||||
|
+++ b/include/uapi/linux/ntsync.h
|
||||||
|
@@ -53,5 +53,6 @@ struct ntsync_wait_args {
|
||||||
|
#define NTSYNC_IOC_EVENT_PULSE _IOR ('N', 0x8a, __u32)
|
||||||
|
#define NTSYNC_IOC_SEM_READ _IOR ('N', 0x8b, struct ntsync_sem_args)
|
||||||
|
#define NTSYNC_IOC_MUTEX_READ _IOR ('N', 0x8c, struct ntsync_mutex_args)
|
||||||
|
+#define NTSYNC_IOC_EVENT_READ _IOR ('N', 0x8d, struct ntsync_event_args)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
--
|
||||||
|
2.43.0
|
|
@ -0,0 +1,184 @@
|
||||||
|
NT waits can optionally be made "alertable". This is a special channel for
|
||||||
|
thread wakeup that is mildly similar to SIGIO. A thread has an internal single
|
||||||
|
bit of "alerted" state, and if a thread is made alerted while an alertable wait,
|
||||||
|
the wait will return a special value, consume the "alerted" state, and will not
|
||||||
|
consume any of its objects.
|
||||||
|
|
||||||
|
Alerts are implemented using events; the user-space NT emulator is expected to
|
||||||
|
create an internal ntsync event for each thread and pass that event to wait
|
||||||
|
functions.
|
||||||
|
|
||||||
|
Signed-off-by: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
---
|
||||||
|
drivers/misc/ntsync.c | 68 ++++++++++++++++++++++++++++++++-----
|
||||||
|
include/uapi/linux/ntsync.h | 2 +-
|
||||||
|
2 files changed, 60 insertions(+), 10 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c
|
||||||
|
index 981a1545192c..0055b4671808 100644
|
||||||
|
--- a/drivers/misc/ntsync.c
|
||||||
|
+++ b/drivers/misc/ntsync.c
|
||||||
|
@@ -808,22 +808,29 @@ static int setup_wait(struct ntsync_device *dev,
|
||||||
|
const struct ntsync_wait_args *args, bool all,
|
||||||
|
struct ntsync_q **ret_q)
|
||||||
|
{
|
||||||
|
+ int fds[NTSYNC_MAX_WAIT_COUNT + 1];
|
||||||
|
const __u32 count = args->count;
|
||||||
|
- int fds[NTSYNC_MAX_WAIT_COUNT];
|
||||||
|
struct ntsync_q *q;
|
||||||
|
+ __u32 total_count;
|
||||||
|
__u32 i, j;
|
||||||
|
|
||||||
|
- if (!args->owner || args->pad)
|
||||||
|
+ if (!args->owner)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (args->count > NTSYNC_MAX_WAIT_COUNT)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
+ total_count = count;
|
||||||
|
+ if (args->alert)
|
||||||
|
+ total_count++;
|
||||||
|
+
|
||||||
|
if (copy_from_user(fds, u64_to_user_ptr(args->objs),
|
||||||
|
array_size(count, sizeof(*fds))))
|
||||||
|
return -EFAULT;
|
||||||
|
+ if (args->alert)
|
||||||
|
+ fds[count] = args->alert;
|
||||||
|
|
||||||
|
- q = kmalloc(struct_size(q, entries, count), GFP_KERNEL);
|
||||||
|
+ q = kmalloc(struct_size(q, entries, total_count), GFP_KERNEL);
|
||||||
|
if (!q)
|
||||||
|
return -ENOMEM;
|
||||||
|
q->task = current;
|
||||||
|
@@ -833,7 +840,7 @@ static int setup_wait(struct ntsync_device *dev,
|
||||||
|
q->ownerdead = false;
|
||||||
|
q->count = count;
|
||||||
|
|
||||||
|
- for (i = 0; i < count; i++) {
|
||||||
|
+ for (i = 0; i < total_count; i++) {
|
||||||
|
struct ntsync_q_entry *entry = &q->entries[i];
|
||||||
|
struct ntsync_obj *obj = get_obj(dev, fds[i]);
|
||||||
|
|
||||||
|
@@ -883,9 +890,9 @@ static void try_wake_any_obj(struct ntsync_obj *obj)
|
||||||
|
static int ntsync_wait_any(struct ntsync_device *dev, void __user *argp)
|
||||||
|
{
|
||||||
|
struct ntsync_wait_args args;
|
||||||
|
+ __u32 i, total_count;
|
||||||
|
struct ntsync_q *q;
|
||||||
|
int signaled;
|
||||||
|
- __u32 i;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (copy_from_user(&args, argp, sizeof(args)))
|
||||||
|
@@ -895,9 +902,13 @@ static int ntsync_wait_any(struct ntsync_device *dev, void __user *argp)
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
+ total_count = args.count;
|
||||||
|
+ if (args.alert)
|
||||||
|
+ total_count++;
|
||||||
|
+
|
||||||
|
/* queue ourselves */
|
||||||
|
|
||||||
|
- for (i = 0; i < args.count; i++) {
|
||||||
|
+ for (i = 0; i < total_count; i++) {
|
||||||
|
struct ntsync_q_entry *entry = &q->entries[i];
|
||||||
|
struct ntsync_obj *obj = entry->obj;
|
||||||
|
|
||||||
|
@@ -906,9 +917,15 @@ static int ntsync_wait_any(struct ntsync_device *dev, void __user *argp)
|
||||||
|
spin_unlock(&obj->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
- /* check if we are already signaled */
|
||||||
|
+ /*
|
||||||
|
+ * Check if we are already signaled.
|
||||||
|
+ *
|
||||||
|
+ * Note that the API requires that normal objects are checked before
|
||||||
|
+ * the alert event. Hence we queue the alert event last, and check
|
||||||
|
+ * objects in order.
|
||||||
|
+ */
|
||||||
|
|
||||||
|
- for (i = 0; i < args.count; i++) {
|
||||||
|
+ for (i = 0; i < total_count; i++) {
|
||||||
|
struct ntsync_obj *obj = q->entries[i].obj;
|
||||||
|
|
||||||
|
if (atomic_read(&q->signaled) != -1)
|
||||||
|
@@ -925,7 +942,7 @@ static int ntsync_wait_any(struct ntsync_device *dev, void __user *argp)
|
||||||
|
|
||||||
|
/* and finally, unqueue */
|
||||||
|
|
||||||
|
- for (i = 0; i < args.count; i++) {
|
||||||
|
+ for (i = 0; i < total_count; i++) {
|
||||||
|
struct ntsync_q_entry *entry = &q->entries[i];
|
||||||
|
struct ntsync_obj *obj = entry->obj;
|
||||||
|
|
||||||
|
@@ -985,6 +1002,14 @@ static int ntsync_wait_all(struct ntsync_device *dev, void __user *argp)
|
||||||
|
*/
|
||||||
|
list_add_tail(&entry->node, &obj->all_waiters);
|
||||||
|
}
|
||||||
|
+ if (args.alert) {
|
||||||
|
+ struct ntsync_q_entry *entry = &q->entries[args.count];
|
||||||
|
+ struct ntsync_obj *obj = entry->obj;
|
||||||
|
+
|
||||||
|
+ spin_lock_nest_lock(&obj->lock, &dev->wait_all_lock);
|
||||||
|
+ list_add_tail(&entry->node, &obj->any_waiters);
|
||||||
|
+ spin_unlock(&obj->lock);
|
||||||
|
+ }
|
||||||
|
|
||||||
|
/* check if we are already signaled */
|
||||||
|
|
||||||
|
@@ -992,6 +1017,21 @@ static int ntsync_wait_all(struct ntsync_device *dev, void __user *argp)
|
||||||
|
|
||||||
|
spin_unlock(&dev->wait_all_lock);
|
||||||
|
|
||||||
|
+ /*
|
||||||
|
+ * Check if the alert event is signaled, making sure to do so only
|
||||||
|
+ * after checking if the other objects are signaled.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+ if (args.alert) {
|
||||||
|
+ struct ntsync_obj *obj = q->entries[args.count].obj;
|
||||||
|
+
|
||||||
|
+ if (atomic_read(&q->signaled) == -1) {
|
||||||
|
+ spin_lock(&obj->lock);
|
||||||
|
+ try_wake_any_obj(obj);
|
||||||
|
+ spin_unlock(&obj->lock);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
/* sleep */
|
||||||
|
|
||||||
|
ret = ntsync_schedule(q, &args);
|
||||||
|
@@ -1014,6 +1054,16 @@ static int ntsync_wait_all(struct ntsync_device *dev, void __user *argp)
|
||||||
|
|
||||||
|
put_obj(obj);
|
||||||
|
}
|
||||||
|
+ if (args.alert) {
|
||||||
|
+ struct ntsync_q_entry *entry = &q->entries[args.count];
|
||||||
|
+ struct ntsync_obj *obj = entry->obj;
|
||||||
|
+
|
||||||
|
+ spin_lock_nest_lock(&obj->lock, &dev->wait_all_lock);
|
||||||
|
+ list_del(&entry->node);
|
||||||
|
+ spin_unlock(&obj->lock);
|
||||||
|
+
|
||||||
|
+ put_obj(obj);
|
||||||
|
+ }
|
||||||
|
|
||||||
|
spin_unlock(&dev->wait_all_lock);
|
||||||
|
|
||||||
|
diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h
|
||||||
|
index 03c95e5a398f..555ae81b479a 100644
|
||||||
|
--- a/include/uapi/linux/ntsync.h
|
||||||
|
+++ b/include/uapi/linux/ntsync.h
|
||||||
|
@@ -34,7 +34,7 @@ struct ntsync_wait_args {
|
||||||
|
__u32 count;
|
||||||
|
__u32 owner;
|
||||||
|
__u32 index;
|
||||||
|
- __u32 pad;
|
||||||
|
+ __u32 alert;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define NTSYNC_MAX_WAIT_COUNT 64
|
||||||
|
--
|
||||||
|
2.43.0
|
|
@ -0,0 +1,79 @@
|
||||||
|
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@codeweavers.com>
|
||||||
|
---
|
||||||
|
drivers/misc/ntsync.c | 9 ++++++++-
|
||||||
|
include/uapi/linux/ntsync.h | 4 ++++
|
||||||
|
2 files changed, 12 insertions(+), 1 deletion(-)
|
||||||
|
|
||||||
|
diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c
|
||||||
|
index 0055b4671808..f54c81dada3d 100644
|
||||||
|
--- a/drivers/misc/ntsync.c
|
||||||
|
+++ b/drivers/misc/ntsync.c
|
||||||
|
@@ -778,11 +778,15 @@ static void put_obj(struct ntsync_obj *obj)
|
||||||
|
static int ntsync_schedule(const struct ntsync_q *q, const struct ntsync_wait_args *args)
|
||||||
|
{
|
||||||
|
ktime_t timeout = ns_to_ktime(args->timeout);
|
||||||
|
+ clockid_t clock = CLOCK_MONOTONIC;
|
||||||
|
ktime_t *timeout_ptr;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
timeout_ptr = (args->timeout == U64_MAX ? NULL : &timeout);
|
||||||
|
|
||||||
|
+ if (args->flags & NTSYNC_WAIT_REALTIME)
|
||||||
|
+ clock = CLOCK_REALTIME;
|
||||||
|
+
|
||||||
|
do {
|
||||||
|
if (signal_pending(current)) {
|
||||||
|
ret = -ERESTARTSYS;
|
||||||
|
@@ -794,7 +798,7 @@ static int ntsync_schedule(const struct ntsync_q *q, const struct ntsync_wait_ar
|
||||||
|
ret = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
- ret = schedule_hrtimeout(timeout_ptr, HRTIMER_MODE_ABS);
|
||||||
|
+ ret = schedule_hrtimeout_range_clock(timeout_ptr, 0, HRTIMER_MODE_ABS, clock);
|
||||||
|
} while (ret < 0);
|
||||||
|
__set_current_state(TASK_RUNNING);
|
||||||
|
|
||||||
|
@@ -817,6 +821,9 @@ static int setup_wait(struct ntsync_device *dev,
|
||||||
|
if (!args->owner)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
+ if (args->pad || (args->flags & ~NTSYNC_WAIT_REALTIME))
|
||||||
|
+ return -EINVAL;
|
||||||
|
+
|
||||||
|
if (args->count > NTSYNC_MAX_WAIT_COUNT)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h
|
||||||
|
index 555ae81b479a..b5e835d8dba8 100644
|
||||||
|
--- a/include/uapi/linux/ntsync.h
|
||||||
|
+++ b/include/uapi/linux/ntsync.h
|
||||||
|
@@ -28,6 +28,8 @@ struct ntsync_event_args {
|
||||||
|
__u32 signaled;
|
||||||
|
};
|
||||||
|
|
||||||
|
+#define NTSYNC_WAIT_REALTIME 0x1
|
||||||
|
+
|
||||||
|
struct ntsync_wait_args {
|
||||||
|
__u64 timeout;
|
||||||
|
__u64 objs;
|
||||||
|
@@ -35,6 +37,8 @@ struct ntsync_wait_args {
|
||||||
|
__u32 owner;
|
||||||
|
__u32 index;
|
||||||
|
__u32 alert;
|
||||||
|
+ __u32 flags;
|
||||||
|
+ __u32 pad;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define NTSYNC_MAX_WAIT_COUNT 64
|
||||||
|
--
|
||||||
|
2.43.0
|
|
@ -0,0 +1,208 @@
|
||||||
|
Wine has tests for its synchronization primitives, but these are more accessible
|
||||||
|
to kernel developers, and also allow us to test some edge cases that Wine does
|
||||||
|
not care about.
|
||||||
|
|
||||||
|
This patch adds tests for semaphore-specific ioctls NTSYNC_IOC_SEM_POST and
|
||||||
|
NTSYNC_IOC_SEM_READ, and waiting on semaphores.
|
||||||
|
|
||||||
|
Signed-off-by: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
---
|
||||||
|
tools/testing/selftests/Makefile | 1 +
|
||||||
|
.../testing/selftests/drivers/ntsync/Makefile | 8 +
|
||||||
|
tools/testing/selftests/drivers/ntsync/config | 1 +
|
||||||
|
.../testing/selftests/drivers/ntsync/ntsync.c | 149 ++++++++++++++++++
|
||||||
|
4 files changed, 159 insertions(+)
|
||||||
|
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
|
||||||
|
|
||||||
|
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
|
||||||
|
index 15b6a111c3be..6c714a4e6478 100644
|
||||||
|
--- a/tools/testing/selftests/Makefile
|
||||||
|
+++ b/tools/testing/selftests/Makefile
|
||||||
|
@@ -15,6 +15,7 @@ TARGETS += cpu-hotplug
|
||||||
|
TARGETS += damon
|
||||||
|
TARGETS += dmabuf-heaps
|
||||||
|
TARGETS += drivers/dma-buf
|
||||||
|
+TARGETS += drivers/ntsync
|
||||||
|
TARGETS += drivers/s390x/uvdevice
|
||||||
|
TARGETS += drivers/net/bonding
|
||||||
|
TARGETS += drivers/net/team
|
||||||
|
diff --git a/tools/testing/selftests/drivers/ntsync/Makefile b/tools/testing/selftests/drivers/ntsync/Makefile
|
||||||
|
new file mode 100644
|
||||||
|
index 000000000000..a34da5ccacf0
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/tools/testing/selftests/drivers/ntsync/Makefile
|
||||||
|
@@ -0,0 +1,8 @@
|
||||||
|
+# SPDX-LICENSE-IDENTIFIER: GPL-2.0-only
|
||||||
|
+TEST_GEN_PROGS := ntsync
|
||||||
|
+
|
||||||
|
+top_srcdir =../../../../..
|
||||||
|
+CFLAGS += -I$(top_srcdir)/usr/include
|
||||||
|
+LDLIBS += -lpthread
|
||||||
|
+
|
||||||
|
+include ../../lib.mk
|
||||||
|
diff --git a/tools/testing/selftests/drivers/ntsync/config b/tools/testing/selftests/drivers/ntsync/config
|
||||||
|
new file mode 100644
|
||||||
|
index 000000000000..60539c826d06
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/tools/testing/selftests/drivers/ntsync/config
|
||||||
|
@@ -0,0 +1 @@
|
||||||
|
+CONFIG_WINESYNC=y
|
||||||
|
diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
new file mode 100644
|
||||||
|
index 000000000000..1e145c6dfded
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
@@ -0,0 +1,149 @@
|
||||||
|
+// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
+/*
|
||||||
|
+ * Various unit tests for the "ntsync" synchronization primitive driver.
|
||||||
|
+ *
|
||||||
|
+ * Copyright (C) 2021-2022 Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#define _GNU_SOURCE
|
||||||
|
+#include <sys/ioctl.h>
|
||||||
|
+#include <sys/stat.h>
|
||||||
|
+#include <fcntl.h>
|
||||||
|
+#include <time.h>
|
||||||
|
+#include <pthread.h>
|
||||||
|
+#include <linux/ntsync.h>
|
||||||
|
+#include "../../kselftest_harness.h"
|
||||||
|
+
|
||||||
|
+static int read_sem_state(int sem, __u32 *count, __u32 *max)
|
||||||
|
+{
|
||||||
|
+ struct ntsync_sem_args args;
|
||||||
|
+ int ret;
|
||||||
|
+
|
||||||
|
+ memset(&args, 0xcc, sizeof(args));
|
||||||
|
+ ret = ioctl(sem, NTSYNC_IOC_SEM_READ, &args);
|
||||||
|
+ *count = args.count;
|
||||||
|
+ *max = args.max;
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#define check_sem_state(sem, count, max) \
|
||||||
|
+ ({ \
|
||||||
|
+ __u32 __count, __max; \
|
||||||
|
+ int ret = read_sem_state((sem), &__count, &__max); \
|
||||||
|
+ EXPECT_EQ(0, ret); \
|
||||||
|
+ EXPECT_EQ((count), __count); \
|
||||||
|
+ EXPECT_EQ((max), __max); \
|
||||||
|
+ })
|
||||||
|
+
|
||||||
|
+static int post_sem(int sem, __u32 *count)
|
||||||
|
+{
|
||||||
|
+ return ioctl(sem, NTSYNC_IOC_SEM_POST, count);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int wait_any(int fd, __u32 count, const int *objs, __u32 owner, __u32 *index)
|
||||||
|
+{
|
||||||
|
+ struct ntsync_wait_args args = {0};
|
||||||
|
+ struct timespec timeout;
|
||||||
|
+ int ret;
|
||||||
|
+
|
||||||
|
+ clock_gettime(CLOCK_MONOTONIC, &timeout);
|
||||||
|
+
|
||||||
|
+ args.timeout = timeout.tv_sec * 1000000000 + timeout.tv_nsec;
|
||||||
|
+ args.count = count;
|
||||||
|
+ args.objs = (uintptr_t)objs;
|
||||||
|
+ args.owner = owner;
|
||||||
|
+ args.index = 0xdeadbeef;
|
||||||
|
+ ret = ioctl(fd, NTSYNC_IOC_WAIT_ANY, &args);
|
||||||
|
+ *index = args.index;
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+TEST(semaphore_state)
|
||||||
|
+{
|
||||||
|
+ struct ntsync_sem_args sem_args;
|
||||||
|
+ struct timespec timeout;
|
||||||
|
+ __u32 count, index;
|
||||||
|
+ int fd, ret, sem;
|
||||||
|
+
|
||||||
|
+ clock_gettime(CLOCK_MONOTONIC, &timeout);
|
||||||
|
+
|
||||||
|
+ fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY);
|
||||||
|
+ ASSERT_LE(0, fd);
|
||||||
|
+
|
||||||
|
+ sem_args.count = 3;
|
||||||
|
+ sem_args.max = 2;
|
||||||
|
+ sem_args.sem = 0xdeadbeef;
|
||||||
|
+ ret = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args);
|
||||||
|
+ EXPECT_EQ(-1, ret);
|
||||||
|
+ EXPECT_EQ(EINVAL, errno);
|
||||||
|
+
|
||||||
|
+ sem_args.count = 2;
|
||||||
|
+ sem_args.max = 2;
|
||||||
|
+ sem_args.sem = 0xdeadbeef;
|
||||||
|
+ ret = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_NE(0xdeadbeef, sem_args.sem);
|
||||||
|
+ sem = sem_args.sem;
|
||||||
|
+ check_sem_state(sem, 2, 2);
|
||||||
|
+
|
||||||
|
+ count = 0;
|
||||||
|
+ ret = post_sem(sem, &count);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(2, count);
|
||||||
|
+ check_sem_state(sem, 2, 2);
|
||||||
|
+
|
||||||
|
+ count = 1;
|
||||||
|
+ ret = post_sem(sem, &count);
|
||||||
|
+ EXPECT_EQ(-1, ret);
|
||||||
|
+ EXPECT_EQ(EOVERFLOW, errno);
|
||||||
|
+ check_sem_state(sem, 2, 2);
|
||||||
|
+
|
||||||
|
+ ret = wait_any(fd, 1, &sem, 123, &index);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, index);
|
||||||
|
+ check_sem_state(sem, 1, 2);
|
||||||
|
+
|
||||||
|
+ ret = wait_any(fd, 1, &sem, 123, &index);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, index);
|
||||||
|
+ check_sem_state(sem, 0, 2);
|
||||||
|
+
|
||||||
|
+ ret = wait_any(fd, 1, &sem, 123, &index);
|
||||||
|
+ EXPECT_EQ(-1, ret);
|
||||||
|
+ EXPECT_EQ(ETIMEDOUT, errno);
|
||||||
|
+
|
||||||
|
+ count = 3;
|
||||||
|
+ ret = post_sem(sem, &count);
|
||||||
|
+ EXPECT_EQ(-1, ret);
|
||||||
|
+ EXPECT_EQ(EOVERFLOW, errno);
|
||||||
|
+ check_sem_state(sem, 0, 2);
|
||||||
|
+
|
||||||
|
+ count = 2;
|
||||||
|
+ ret = post_sem(sem, &count);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, count);
|
||||||
|
+ check_sem_state(sem, 2, 2);
|
||||||
|
+
|
||||||
|
+ ret = wait_any(fd, 1, &sem, 123, &index);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ ret = wait_any(fd, 1, &sem, 123, &index);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+
|
||||||
|
+ count = 1;
|
||||||
|
+ ret = post_sem(sem, &count);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, count);
|
||||||
|
+ check_sem_state(sem, 1, 2);
|
||||||
|
+
|
||||||
|
+ count = ~0u;
|
||||||
|
+ ret = post_sem(sem, &count);
|
||||||
|
+ EXPECT_EQ(-1, ret);
|
||||||
|
+ EXPECT_EQ(EOVERFLOW, errno);
|
||||||
|
+ check_sem_state(sem, 1, 2);
|
||||||
|
+
|
||||||
|
+ close(sem);
|
||||||
|
+
|
||||||
|
+ close(fd);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+TEST_HARNESS_MAIN
|
||||||
|
--
|
||||||
|
2.43.0
|
|
@ -0,0 +1,222 @@
|
||||||
|
Test mutex-specific ioctls NTSYNC_IOC_MUTEX_UNLOCK and NTSYNC_IOC_MUTEX_READ,
|
||||||
|
and waiting on mutexes.
|
||||||
|
|
||||||
|
Signed-off-by: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
---
|
||||||
|
.../testing/selftests/drivers/ntsync/ntsync.c | 196 ++++++++++++++++++
|
||||||
|
1 file changed, 196 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
index 1e145c6dfded..7cd0f40594fd 100644
|
||||||
|
--- a/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
+++ b/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
@@ -40,6 +40,39 @@ static int post_sem(int sem, __u32 *count)
|
||||||
|
return ioctl(sem, NTSYNC_IOC_SEM_POST, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int read_mutex_state(int mutex, __u32 *count, __u32 *owner)
|
||||||
|
+{
|
||||||
|
+ struct ntsync_mutex_args args;
|
||||||
|
+ int ret;
|
||||||
|
+
|
||||||
|
+ memset(&args, 0xcc, sizeof(args));
|
||||||
|
+ ret = ioctl(mutex, NTSYNC_IOC_MUTEX_READ, &args);
|
||||||
|
+ *count = args.count;
|
||||||
|
+ *owner = args.owner;
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#define check_mutex_state(mutex, count, owner) \
|
||||||
|
+ ({ \
|
||||||
|
+ __u32 __count, __owner; \
|
||||||
|
+ int ret = read_mutex_state((mutex), &__count, &__owner); \
|
||||||
|
+ EXPECT_EQ(0, ret); \
|
||||||
|
+ EXPECT_EQ((count), __count); \
|
||||||
|
+ EXPECT_EQ((owner), __owner); \
|
||||||
|
+ })
|
||||||
|
+
|
||||||
|
+static int unlock_mutex(int mutex, __u32 owner, __u32 *count)
|
||||||
|
+{
|
||||||
|
+ struct ntsync_mutex_args args;
|
||||||
|
+ int ret;
|
||||||
|
+
|
||||||
|
+ args.owner = owner;
|
||||||
|
+ args.count = 0xdeadbeef;
|
||||||
|
+ ret = ioctl(mutex, NTSYNC_IOC_MUTEX_UNLOCK, &args);
|
||||||
|
+ *count = args.count;
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static int wait_any(int fd, __u32 count, const int *objs, __u32 owner, __u32 *index)
|
||||||
|
{
|
||||||
|
struct ntsync_wait_args args = {0};
|
||||||
|
@@ -146,4 +179,167 @@ TEST(semaphore_state)
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
+TEST(mutex_state)
|
||||||
|
+{
|
||||||
|
+ struct ntsync_mutex_args mutex_args;
|
||||||
|
+ __u32 owner, count, index;
|
||||||
|
+ struct timespec timeout;
|
||||||
|
+ int fd, ret, mutex;
|
||||||
|
+
|
||||||
|
+ clock_gettime(CLOCK_MONOTONIC, &timeout);
|
||||||
|
+
|
||||||
|
+ fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY);
|
||||||
|
+ ASSERT_LE(0, fd);
|
||||||
|
+
|
||||||
|
+ mutex_args.owner = 123;
|
||||||
|
+ mutex_args.count = 0;
|
||||||
|
+ ret = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args);
|
||||||
|
+ EXPECT_EQ(-1, ret);
|
||||||
|
+ EXPECT_EQ(EINVAL, errno);
|
||||||
|
+
|
||||||
|
+ mutex_args.owner = 0;
|
||||||
|
+ mutex_args.count = 2;
|
||||||
|
+ ret = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args);
|
||||||
|
+ EXPECT_EQ(-1, ret);
|
||||||
|
+ EXPECT_EQ(EINVAL, errno);
|
||||||
|
+
|
||||||
|
+ mutex_args.owner = 123;
|
||||||
|
+ mutex_args.count = 2;
|
||||||
|
+ mutex_args.mutex = 0xdeadbeef;
|
||||||
|
+ ret = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_NE(0xdeadbeef, mutex_args.mutex);
|
||||||
|
+ mutex = mutex_args.mutex;
|
||||||
|
+ check_mutex_state(mutex, 2, 123);
|
||||||
|
+
|
||||||
|
+ ret = unlock_mutex(mutex, 0, &count);
|
||||||
|
+ EXPECT_EQ(-1, ret);
|
||||||
|
+ EXPECT_EQ(EINVAL, errno);
|
||||||
|
+
|
||||||
|
+ ret = unlock_mutex(mutex, 456, &count);
|
||||||
|
+ EXPECT_EQ(-1, ret);
|
||||||
|
+ EXPECT_EQ(EPERM, errno);
|
||||||
|
+ check_mutex_state(mutex, 2, 123);
|
||||||
|
+
|
||||||
|
+ ret = unlock_mutex(mutex, 123, &count);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(2, count);
|
||||||
|
+ check_mutex_state(mutex, 1, 123);
|
||||||
|
+
|
||||||
|
+ ret = unlock_mutex(mutex, 123, &count);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(1, count);
|
||||||
|
+ check_mutex_state(mutex, 0, 0);
|
||||||
|
+
|
||||||
|
+ ret = unlock_mutex(mutex, 123, &count);
|
||||||
|
+ EXPECT_EQ(-1, ret);
|
||||||
|
+ EXPECT_EQ(EPERM, errno);
|
||||||
|
+
|
||||||
|
+ ret = wait_any(fd, 1, &mutex, 456, &index);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, index);
|
||||||
|
+ check_mutex_state(mutex, 1, 456);
|
||||||
|
+
|
||||||
|
+ ret = wait_any(fd, 1, &mutex, 456, &index);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, index);
|
||||||
|
+ check_mutex_state(mutex, 2, 456);
|
||||||
|
+
|
||||||
|
+ ret = unlock_mutex(mutex, 456, &count);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(2, count);
|
||||||
|
+ check_mutex_state(mutex, 1, 456);
|
||||||
|
+
|
||||||
|
+ ret = wait_any(fd, 1, &mutex, 123, &index);
|
||||||
|
+ EXPECT_EQ(-1, ret);
|
||||||
|
+ EXPECT_EQ(ETIMEDOUT, errno);
|
||||||
|
+
|
||||||
|
+ owner = 0;
|
||||||
|
+ ret = ioctl(mutex, NTSYNC_IOC_MUTEX_KILL, &owner);
|
||||||
|
+ EXPECT_EQ(-1, ret);
|
||||||
|
+ EXPECT_EQ(EINVAL, errno);
|
||||||
|
+
|
||||||
|
+ owner = 123;
|
||||||
|
+ ret = ioctl(mutex, NTSYNC_IOC_MUTEX_KILL, &owner);
|
||||||
|
+ EXPECT_EQ(-1, ret);
|
||||||
|
+ EXPECT_EQ(EPERM, errno);
|
||||||
|
+ check_mutex_state(mutex, 1, 456);
|
||||||
|
+
|
||||||
|
+ owner = 456;
|
||||||
|
+ ret = ioctl(mutex, NTSYNC_IOC_MUTEX_KILL, &owner);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+
|
||||||
|
+ memset(&mutex_args, 0xcc, sizeof(mutex_args));
|
||||||
|
+ ret = ioctl(mutex, NTSYNC_IOC_MUTEX_READ, &mutex_args);
|
||||||
|
+ EXPECT_EQ(-1, ret);
|
||||||
|
+ EXPECT_EQ(EOWNERDEAD, errno);
|
||||||
|
+ EXPECT_EQ(0, mutex_args.count);
|
||||||
|
+ EXPECT_EQ(0, mutex_args.owner);
|
||||||
|
+
|
||||||
|
+ memset(&mutex_args, 0xcc, sizeof(mutex_args));
|
||||||
|
+ ret = ioctl(mutex, NTSYNC_IOC_MUTEX_READ, &mutex_args);
|
||||||
|
+ EXPECT_EQ(-1, ret);
|
||||||
|
+ EXPECT_EQ(EOWNERDEAD, errno);
|
||||||
|
+ EXPECT_EQ(0, mutex_args.count);
|
||||||
|
+ EXPECT_EQ(0, mutex_args.owner);
|
||||||
|
+
|
||||||
|
+ ret = wait_any(fd, 1, &mutex, 123, &index);
|
||||||
|
+ EXPECT_EQ(-1, ret);
|
||||||
|
+ EXPECT_EQ(EOWNERDEAD, errno);
|
||||||
|
+ EXPECT_EQ(0, index);
|
||||||
|
+ check_mutex_state(mutex, 1, 123);
|
||||||
|
+
|
||||||
|
+ owner = 123;
|
||||||
|
+ ret = ioctl(mutex, NTSYNC_IOC_MUTEX_KILL, &owner);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+
|
||||||
|
+ memset(&mutex_args, 0xcc, sizeof(mutex_args));
|
||||||
|
+ ret = ioctl(mutex, NTSYNC_IOC_MUTEX_READ, &mutex_args);
|
||||||
|
+ EXPECT_EQ(-1, ret);
|
||||||
|
+ EXPECT_EQ(EOWNERDEAD, errno);
|
||||||
|
+ EXPECT_EQ(0, mutex_args.count);
|
||||||
|
+ EXPECT_EQ(0, mutex_args.owner);
|
||||||
|
+
|
||||||
|
+ ret = wait_any(fd, 1, &mutex, 123, &index);
|
||||||
|
+ EXPECT_EQ(-1, ret);
|
||||||
|
+ EXPECT_EQ(EOWNERDEAD, errno);
|
||||||
|
+ EXPECT_EQ(0, index);
|
||||||
|
+ check_mutex_state(mutex, 1, 123);
|
||||||
|
+
|
||||||
|
+ close(mutex);
|
||||||
|
+
|
||||||
|
+ mutex_args.owner = 0;
|
||||||
|
+ mutex_args.count = 0;
|
||||||
|
+ mutex_args.mutex = 0xdeadbeef;
|
||||||
|
+ ret = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_NE(0xdeadbeef, mutex_args.mutex);
|
||||||
|
+ mutex = mutex_args.mutex;
|
||||||
|
+ check_mutex_state(mutex, 0, 0);
|
||||||
|
+
|
||||||
|
+ ret = wait_any(fd, 1, &mutex, 123, &index);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, index);
|
||||||
|
+ check_mutex_state(mutex, 1, 123);
|
||||||
|
+
|
||||||
|
+ close(mutex);
|
||||||
|
+
|
||||||
|
+ mutex_args.owner = 123;
|
||||||
|
+ mutex_args.count = ~0u;
|
||||||
|
+ mutex_args.mutex = 0xdeadbeef;
|
||||||
|
+ ret = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_NE(0xdeadbeef, mutex_args.mutex);
|
||||||
|
+ mutex = mutex_args.mutex;
|
||||||
|
+ check_mutex_state(mutex, ~0u, 123);
|
||||||
|
+
|
||||||
|
+ ret = wait_any(fd, 1, &mutex, 123, &index);
|
||||||
|
+ EXPECT_EQ(-1, ret);
|
||||||
|
+ EXPECT_EQ(ETIMEDOUT, errno);
|
||||||
|
+
|
||||||
|
+ close(mutex);
|
||||||
|
+
|
||||||
|
+ close(fd);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
TEST_HARNESS_MAIN
|
||||||
|
--
|
||||||
|
2.43.0
|
|
@ -0,0 +1,139 @@
|
||||||
|
Test basic synchronous functionality of NTSYNC_IOC_WAIT_ANY, when objects are
|
||||||
|
considered signaled or not signaled, and how they are affected by a successful
|
||||||
|
wait.
|
||||||
|
|
||||||
|
Signed-off-by: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
---
|
||||||
|
.../testing/selftests/drivers/ntsync/ntsync.c | 119 ++++++++++++++++++
|
||||||
|
1 file changed, 119 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
index 7cd0f40594fd..40ad8cbd3138 100644
|
||||||
|
--- a/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
+++ b/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
@@ -342,4 +342,123 @@ TEST(mutex_state)
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
+TEST(test_wait_any)
|
||||||
|
+{
|
||||||
|
+ int objs[NTSYNC_MAX_WAIT_COUNT + 1], fd, ret;
|
||||||
|
+ struct ntsync_mutex_args mutex_args = {0};
|
||||||
|
+ struct ntsync_sem_args sem_args = {0};
|
||||||
|
+ __u32 owner, index, count, i;
|
||||||
|
+ struct timespec timeout;
|
||||||
|
+
|
||||||
|
+ clock_gettime(CLOCK_MONOTONIC, &timeout);
|
||||||
|
+
|
||||||
|
+ fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY);
|
||||||
|
+ ASSERT_LE(0, fd);
|
||||||
|
+
|
||||||
|
+ sem_args.count = 2;
|
||||||
|
+ sem_args.max = 3;
|
||||||
|
+ sem_args.sem = 0xdeadbeef;
|
||||||
|
+ ret = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_NE(0xdeadbeef, sem_args.sem);
|
||||||
|
+
|
||||||
|
+ mutex_args.owner = 0;
|
||||||
|
+ mutex_args.count = 0;
|
||||||
|
+ mutex_args.mutex = 0xdeadbeef;
|
||||||
|
+ ret = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_NE(0xdeadbeef, mutex_args.mutex);
|
||||||
|
+
|
||||||
|
+ objs[0] = sem_args.sem;
|
||||||
|
+ objs[1] = mutex_args.mutex;
|
||||||
|
+
|
||||||
|
+ ret = wait_any(fd, 2, objs, 123, &index);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, index);
|
||||||
|
+ check_sem_state(sem_args.sem, 1, 3);
|
||||||
|
+ check_mutex_state(mutex_args.mutex, 0, 0);
|
||||||
|
+
|
||||||
|
+ ret = wait_any(fd, 2, objs, 123, &index);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, index);
|
||||||
|
+ check_sem_state(sem_args.sem, 0, 3);
|
||||||
|
+ check_mutex_state(mutex_args.mutex, 0, 0);
|
||||||
|
+
|
||||||
|
+ ret = wait_any(fd, 2, objs, 123, &index);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(1, index);
|
||||||
|
+ check_sem_state(sem_args.sem, 0, 3);
|
||||||
|
+ check_mutex_state(mutex_args.mutex, 1, 123);
|
||||||
|
+
|
||||||
|
+ count = 1;
|
||||||
|
+ ret = post_sem(sem_args.sem, &count);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, count);
|
||||||
|
+
|
||||||
|
+ ret = wait_any(fd, 2, objs, 123, &index);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, index);
|
||||||
|
+ check_sem_state(sem_args.sem, 0, 3);
|
||||||
|
+ check_mutex_state(mutex_args.mutex, 1, 123);
|
||||||
|
+
|
||||||
|
+ ret = wait_any(fd, 2, objs, 123, &index);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(1, index);
|
||||||
|
+ check_sem_state(sem_args.sem, 0, 3);
|
||||||
|
+ check_mutex_state(mutex_args.mutex, 2, 123);
|
||||||
|
+
|
||||||
|
+ ret = wait_any(fd, 2, objs, 456, &index);
|
||||||
|
+ EXPECT_EQ(-1, ret);
|
||||||
|
+ EXPECT_EQ(ETIMEDOUT, errno);
|
||||||
|
+
|
||||||
|
+ owner = 123;
|
||||||
|
+ ret = ioctl(mutex_args.mutex, NTSYNC_IOC_MUTEX_KILL, &owner);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+
|
||||||
|
+ ret = wait_any(fd, 2, objs, 456, &index);
|
||||||
|
+ EXPECT_EQ(-1, ret);
|
||||||
|
+ EXPECT_EQ(EOWNERDEAD, errno);
|
||||||
|
+ EXPECT_EQ(1, index);
|
||||||
|
+
|
||||||
|
+ ret = wait_any(fd, 2, objs, 456, &index);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(1, index);
|
||||||
|
+
|
||||||
|
+ /* test waiting on the same object twice */
|
||||||
|
+ count = 2;
|
||||||
|
+ ret = post_sem(sem_args.sem, &count);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, count);
|
||||||
|
+
|
||||||
|
+ objs[0] = objs[1] = sem_args.sem;
|
||||||
|
+ ret = wait_any(fd, 2, objs, 456, &index);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, index);
|
||||||
|
+ check_sem_state(sem_args.sem, 1, 3);
|
||||||
|
+
|
||||||
|
+ ret = wait_any(fd, 0, NULL, 456, &index);
|
||||||
|
+ EXPECT_EQ(-1, ret);
|
||||||
|
+ EXPECT_EQ(ETIMEDOUT, errno);
|
||||||
|
+
|
||||||
|
+ for (i = 0; i < NTSYNC_MAX_WAIT_COUNT + 1; ++i)
|
||||||
|
+ objs[i] = sem_args.sem;
|
||||||
|
+
|
||||||
|
+ ret = wait_any(fd, NTSYNC_MAX_WAIT_COUNT, objs, 123, &index);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, index);
|
||||||
|
+
|
||||||
|
+ ret = wait_any(fd, NTSYNC_MAX_WAIT_COUNT + 1, objs, 123, &index);
|
||||||
|
+ EXPECT_EQ(-1, ret);
|
||||||
|
+ EXPECT_EQ(EINVAL, errno);
|
||||||
|
+
|
||||||
|
+ ret = wait_any(fd, -1, objs, 123, &index);
|
||||||
|
+ EXPECT_EQ(-1, ret);
|
||||||
|
+ EXPECT_EQ(EINVAL, errno);
|
||||||
|
+
|
||||||
|
+ close(sem_args.sem);
|
||||||
|
+ close(mutex_args.mutex);
|
||||||
|
+
|
||||||
|
+ close(fd);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
TEST_HARNESS_MAIN
|
||||||
|
--
|
||||||
|
2.43.0
|
|
@ -0,0 +1,136 @@
|
||||||
|
Test basic synchronous functionality of NTSYNC_IOC_WAIT_ALL, and when objects
|
||||||
|
are considered simultaneously signaled.
|
||||||
|
|
||||||
|
Signed-off-by: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
---
|
||||||
|
.../testing/selftests/drivers/ntsync/ntsync.c | 99 ++++++++++++++++++-
|
||||||
|
1 file changed, 97 insertions(+), 2 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
index 40ad8cbd3138..c0f372167557 100644
|
||||||
|
--- a/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
+++ b/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
@@ -73,7 +73,8 @@ static int unlock_mutex(int mutex, __u32 owner, __u32 *count)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
-static int wait_any(int fd, __u32 count, const int *objs, __u32 owner, __u32 *index)
|
||||||
|
+static int wait_objs(int fd, unsigned long request, __u32 count,
|
||||||
|
+ const int *objs, __u32 owner, __u32 *index)
|
||||||
|
{
|
||||||
|
struct ntsync_wait_args args = {0};
|
||||||
|
struct timespec timeout;
|
||||||
|
@@ -86,11 +87,21 @@ static int wait_any(int fd, __u32 count, const int *objs, __u32 owner, __u32 *in
|
||||||
|
args.objs = (uintptr_t)objs;
|
||||||
|
args.owner = owner;
|
||||||
|
args.index = 0xdeadbeef;
|
||||||
|
- ret = ioctl(fd, NTSYNC_IOC_WAIT_ANY, &args);
|
||||||
|
+ ret = ioctl(fd, request, &args);
|
||||||
|
*index = args.index;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int wait_any(int fd, __u32 count, const int *objs, __u32 owner, __u32 *index)
|
||||||
|
+{
|
||||||
|
+ return wait_objs(fd, NTSYNC_IOC_WAIT_ANY, count, objs, owner, index);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int wait_all(int fd, __u32 count, const int *objs, __u32 owner, __u32 *index)
|
||||||
|
+{
|
||||||
|
+ return wait_objs(fd, NTSYNC_IOC_WAIT_ALL, count, objs, owner, index);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
TEST(semaphore_state)
|
||||||
|
{
|
||||||
|
struct ntsync_sem_args sem_args;
|
||||||
|
@@ -461,4 +472,88 @@ TEST(test_wait_any)
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
+TEST(test_wait_all)
|
||||||
|
+{
|
||||||
|
+ struct ntsync_mutex_args mutex_args = {0};
|
||||||
|
+ struct ntsync_sem_args sem_args = {0};
|
||||||
|
+ __u32 owner, index, count;
|
||||||
|
+ int objs[2], fd, ret;
|
||||||
|
+
|
||||||
|
+ fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY);
|
||||||
|
+ ASSERT_LE(0, fd);
|
||||||
|
+
|
||||||
|
+ sem_args.count = 2;
|
||||||
|
+ sem_args.max = 3;
|
||||||
|
+ sem_args.sem = 0xdeadbeef;
|
||||||
|
+ ret = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_NE(0xdeadbeef, sem_args.sem);
|
||||||
|
+
|
||||||
|
+ mutex_args.owner = 0;
|
||||||
|
+ mutex_args.count = 0;
|
||||||
|
+ mutex_args.mutex = 0xdeadbeef;
|
||||||
|
+ ret = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_NE(0xdeadbeef, mutex_args.mutex);
|
||||||
|
+
|
||||||
|
+ objs[0] = sem_args.sem;
|
||||||
|
+ objs[1] = mutex_args.mutex;
|
||||||
|
+
|
||||||
|
+ ret = wait_all(fd, 2, objs, 123, &index);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, index);
|
||||||
|
+ check_sem_state(sem_args.sem, 1, 3);
|
||||||
|
+ check_mutex_state(mutex_args.mutex, 1, 123);
|
||||||
|
+
|
||||||
|
+ ret = wait_all(fd, 2, objs, 456, &index);
|
||||||
|
+ EXPECT_EQ(-1, ret);
|
||||||
|
+ EXPECT_EQ(ETIMEDOUT, errno);
|
||||||
|
+ check_sem_state(sem_args.sem, 1, 3);
|
||||||
|
+ check_mutex_state(mutex_args.mutex, 1, 123);
|
||||||
|
+
|
||||||
|
+ ret = wait_all(fd, 2, objs, 123, &index);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, index);
|
||||||
|
+ check_sem_state(sem_args.sem, 0, 3);
|
||||||
|
+ check_mutex_state(mutex_args.mutex, 2, 123);
|
||||||
|
+
|
||||||
|
+ ret = wait_all(fd, 2, objs, 123, &index);
|
||||||
|
+ EXPECT_EQ(-1, ret);
|
||||||
|
+ EXPECT_EQ(ETIMEDOUT, errno);
|
||||||
|
+ check_sem_state(sem_args.sem, 0, 3);
|
||||||
|
+ check_mutex_state(mutex_args.mutex, 2, 123);
|
||||||
|
+
|
||||||
|
+ count = 3;
|
||||||
|
+ ret = post_sem(sem_args.sem, &count);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, count);
|
||||||
|
+
|
||||||
|
+ ret = wait_all(fd, 2, objs, 123, &index);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, index);
|
||||||
|
+ check_sem_state(sem_args.sem, 2, 3);
|
||||||
|
+ check_mutex_state(mutex_args.mutex, 3, 123);
|
||||||
|
+
|
||||||
|
+ owner = 123;
|
||||||
|
+ ret = ioctl(mutex_args.mutex, NTSYNC_IOC_MUTEX_KILL, &owner);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+
|
||||||
|
+ ret = wait_all(fd, 2, objs, 123, &index);
|
||||||
|
+ EXPECT_EQ(-1, ret);
|
||||||
|
+ EXPECT_EQ(EOWNERDEAD, errno);
|
||||||
|
+ check_sem_state(sem_args.sem, 1, 3);
|
||||||
|
+ check_mutex_state(mutex_args.mutex, 1, 123);
|
||||||
|
+
|
||||||
|
+ /* test waiting on the same object twice */
|
||||||
|
+ objs[0] = objs[1] = sem_args.sem;
|
||||||
|
+ ret = wait_all(fd, 2, objs, 123, &index);
|
||||||
|
+ EXPECT_EQ(-1, ret);
|
||||||
|
+ EXPECT_EQ(EINVAL, errno);
|
||||||
|
+
|
||||||
|
+ close(sem_args.sem);
|
||||||
|
+ close(mutex_args.mutex);
|
||||||
|
+
|
||||||
|
+ close(fd);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
TEST_HARNESS_MAIN
|
||||||
|
--
|
||||||
|
2.43.0
|
|
@ -0,0 +1,169 @@
|
||||||
|
Test contended "wait-for-any" waits, to make sure that scheduling and wakeup
|
||||||
|
logic works correctly.
|
||||||
|
|
||||||
|
Signed-off-by: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
---
|
||||||
|
.../testing/selftests/drivers/ntsync/ntsync.c | 150 ++++++++++++++++++
|
||||||
|
1 file changed, 150 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
index c0f372167557..993f5db23768 100644
|
||||||
|
--- a/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
+++ b/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
@@ -556,4 +556,154 @@ TEST(test_wait_all)
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
+struct wake_args {
|
||||||
|
+ int fd;
|
||||||
|
+ int obj;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+struct wait_args {
|
||||||
|
+ int fd;
|
||||||
|
+ unsigned long request;
|
||||||
|
+ struct ntsync_wait_args *args;
|
||||||
|
+ int ret;
|
||||||
|
+ int err;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static void *wait_thread(void *arg)
|
||||||
|
+{
|
||||||
|
+ struct wait_args *args = arg;
|
||||||
|
+
|
||||||
|
+ args->ret = ioctl(args->fd, args->request, args->args);
|
||||||
|
+ args->err = errno;
|
||||||
|
+ return NULL;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static __u64 get_abs_timeout(unsigned int ms)
|
||||||
|
+{
|
||||||
|
+ struct timespec timeout;
|
||||||
|
+ clock_gettime(CLOCK_MONOTONIC, &timeout);
|
||||||
|
+ return (timeout.tv_sec * 1000000000) + timeout.tv_nsec + (ms * 1000000);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int wait_for_thread(pthread_t thread, unsigned int ms)
|
||||||
|
+{
|
||||||
|
+ struct timespec timeout;
|
||||||
|
+
|
||||||
|
+ clock_gettime(CLOCK_REALTIME, &timeout);
|
||||||
|
+ timeout.tv_nsec += ms * 1000000;
|
||||||
|
+ timeout.tv_sec += (timeout.tv_nsec / 1000000000);
|
||||||
|
+ timeout.tv_nsec %= 1000000000;
|
||||||
|
+ return pthread_timedjoin_np(thread, NULL, &timeout);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+TEST(wake_any)
|
||||||
|
+{
|
||||||
|
+ struct ntsync_mutex_args mutex_args = {0};
|
||||||
|
+ struct ntsync_wait_args wait_args = {0};
|
||||||
|
+ struct ntsync_sem_args sem_args = {0};
|
||||||
|
+ struct wait_args thread_args;
|
||||||
|
+ int objs[2], fd, ret;
|
||||||
|
+ __u32 count, index;
|
||||||
|
+ pthread_t thread;
|
||||||
|
+
|
||||||
|
+ fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY);
|
||||||
|
+ ASSERT_LE(0, fd);
|
||||||
|
+
|
||||||
|
+ sem_args.count = 0;
|
||||||
|
+ sem_args.max = 3;
|
||||||
|
+ sem_args.sem = 0xdeadbeef;
|
||||||
|
+ ret = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_NE(0xdeadbeef, sem_args.sem);
|
||||||
|
+
|
||||||
|
+ mutex_args.owner = 123;
|
||||||
|
+ mutex_args.count = 1;
|
||||||
|
+ mutex_args.mutex = 0xdeadbeef;
|
||||||
|
+ ret = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_NE(0xdeadbeef, mutex_args.mutex);
|
||||||
|
+
|
||||||
|
+ objs[0] = sem_args.sem;
|
||||||
|
+ objs[1] = mutex_args.mutex;
|
||||||
|
+
|
||||||
|
+ /* test waking the semaphore */
|
||||||
|
+
|
||||||
|
+ wait_args.timeout = get_abs_timeout(1000);
|
||||||
|
+ wait_args.objs = (uintptr_t)objs;
|
||||||
|
+ wait_args.count = 2;
|
||||||
|
+ wait_args.owner = 456;
|
||||||
|
+ wait_args.index = 0xdeadbeef;
|
||||||
|
+ thread_args.fd = fd;
|
||||||
|
+ thread_args.args = &wait_args;
|
||||||
|
+ thread_args.request = NTSYNC_IOC_WAIT_ANY;
|
||||||
|
+ ret = pthread_create(&thread, NULL, wait_thread, &thread_args);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+
|
||||||
|
+ ret = wait_for_thread(thread, 100);
|
||||||
|
+ EXPECT_EQ(ETIMEDOUT, ret);
|
||||||
|
+
|
||||||
|
+ count = 1;
|
||||||
|
+ ret = post_sem(sem_args.sem, &count);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, count);
|
||||||
|
+ check_sem_state(sem_args.sem, 0, 3);
|
||||||
|
+
|
||||||
|
+ ret = wait_for_thread(thread, 100);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, thread_args.ret);
|
||||||
|
+ EXPECT_EQ(0, wait_args.index);
|
||||||
|
+
|
||||||
|
+ /* test waking the mutex */
|
||||||
|
+
|
||||||
|
+ /* first grab it again for owner 123 */
|
||||||
|
+ ret = wait_any(fd, 1, &mutex_args.mutex, 123, &index);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, index);
|
||||||
|
+
|
||||||
|
+ wait_args.timeout = get_abs_timeout(1000);
|
||||||
|
+ wait_args.owner = 456;
|
||||||
|
+ ret = pthread_create(&thread, NULL, wait_thread, &thread_args);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+
|
||||||
|
+ ret = wait_for_thread(thread, 100);
|
||||||
|
+ EXPECT_EQ(ETIMEDOUT, ret);
|
||||||
|
+
|
||||||
|
+ ret = unlock_mutex(mutex_args.mutex, 123, &count);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(2, count);
|
||||||
|
+
|
||||||
|
+ ret = pthread_tryjoin_np(thread, NULL);
|
||||||
|
+ EXPECT_EQ(EBUSY, ret);
|
||||||
|
+
|
||||||
|
+ ret = unlock_mutex(mutex_args.mutex, 123, &count);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(1, mutex_args.count);
|
||||||
|
+ check_mutex_state(mutex_args.mutex, 1, 456);
|
||||||
|
+
|
||||||
|
+ ret = wait_for_thread(thread, 100);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, thread_args.ret);
|
||||||
|
+ EXPECT_EQ(1, wait_args.index);
|
||||||
|
+
|
||||||
|
+ /* delete an object while it's being waited on */
|
||||||
|
+
|
||||||
|
+ wait_args.timeout = get_abs_timeout(200);
|
||||||
|
+ wait_args.owner = 123;
|
||||||
|
+ ret = pthread_create(&thread, NULL, wait_thread, &thread_args);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+
|
||||||
|
+ ret = wait_for_thread(thread, 100);
|
||||||
|
+ EXPECT_EQ(ETIMEDOUT, ret);
|
||||||
|
+
|
||||||
|
+ close(sem_args.sem);
|
||||||
|
+ close(mutex_args.mutex);
|
||||||
|
+
|
||||||
|
+ ret = wait_for_thread(thread, 200);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(-1, thread_args.ret);
|
||||||
|
+ EXPECT_EQ(ETIMEDOUT, thread_args.err);
|
||||||
|
+
|
||||||
|
+ close(fd);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
TEST_HARNESS_MAIN
|
||||||
|
--
|
||||||
|
2.43.0
|
|
@ -0,0 +1,118 @@
|
||||||
|
Test contended "wait-for-all" waits, to make sure that scheduling and wakeup
|
||||||
|
logic works correctly, and that the wait only exits once objects are all
|
||||||
|
simultaneously signaled.
|
||||||
|
|
||||||
|
Signed-off-by: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
---
|
||||||
|
.../testing/selftests/drivers/ntsync/ntsync.c | 98 +++++++++++++++++++
|
||||||
|
1 file changed, 98 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
index 993f5db23768..b77fb0b2c4b1 100644
|
||||||
|
--- a/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
+++ b/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
@@ -706,4 +706,102 @@ TEST(wake_any)
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
+TEST(wake_all)
|
||||||
|
+{
|
||||||
|
+ struct ntsync_mutex_args mutex_args = {0};
|
||||||
|
+ struct ntsync_wait_args wait_args = {0};
|
||||||
|
+ struct ntsync_sem_args sem_args = {0};
|
||||||
|
+ struct wait_args thread_args;
|
||||||
|
+ int objs[2], fd, ret;
|
||||||
|
+ __u32 count, index;
|
||||||
|
+ pthread_t thread;
|
||||||
|
+
|
||||||
|
+ fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY);
|
||||||
|
+ ASSERT_LE(0, fd);
|
||||||
|
+
|
||||||
|
+ sem_args.count = 0;
|
||||||
|
+ sem_args.max = 3;
|
||||||
|
+ sem_args.sem = 0xdeadbeef;
|
||||||
|
+ ret = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_NE(0xdeadbeef, sem_args.sem);
|
||||||
|
+
|
||||||
|
+ mutex_args.owner = 123;
|
||||||
|
+ mutex_args.count = 1;
|
||||||
|
+ mutex_args.mutex = 0xdeadbeef;
|
||||||
|
+ ret = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_NE(0xdeadbeef, mutex_args.mutex);
|
||||||
|
+
|
||||||
|
+ objs[0] = sem_args.sem;
|
||||||
|
+ objs[1] = mutex_args.mutex;
|
||||||
|
+
|
||||||
|
+ wait_args.timeout = get_abs_timeout(1000);
|
||||||
|
+ wait_args.objs = (uintptr_t)objs;
|
||||||
|
+ wait_args.count = 2;
|
||||||
|
+ wait_args.owner = 456;
|
||||||
|
+ thread_args.fd = fd;
|
||||||
|
+ thread_args.args = &wait_args;
|
||||||
|
+ thread_args.request = NTSYNC_IOC_WAIT_ALL;
|
||||||
|
+ ret = pthread_create(&thread, NULL, wait_thread, &thread_args);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+
|
||||||
|
+ ret = wait_for_thread(thread, 100);
|
||||||
|
+ EXPECT_EQ(ETIMEDOUT, ret);
|
||||||
|
+
|
||||||
|
+ count = 1;
|
||||||
|
+ ret = post_sem(sem_args.sem, &count);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, count);
|
||||||
|
+
|
||||||
|
+ ret = pthread_tryjoin_np(thread, NULL);
|
||||||
|
+ EXPECT_EQ(EBUSY, ret);
|
||||||
|
+
|
||||||
|
+ check_sem_state(sem_args.sem, 1, 3);
|
||||||
|
+
|
||||||
|
+ ret = wait_any(fd, 1, &sem_args.sem, 123, &index);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, index);
|
||||||
|
+
|
||||||
|
+ ret = unlock_mutex(mutex_args.mutex, 123, &count);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(1, count);
|
||||||
|
+
|
||||||
|
+ ret = pthread_tryjoin_np(thread, NULL);
|
||||||
|
+ EXPECT_EQ(EBUSY, ret);
|
||||||
|
+
|
||||||
|
+ check_mutex_state(mutex_args.mutex, 0, 0);
|
||||||
|
+
|
||||||
|
+ count = 2;
|
||||||
|
+ ret = post_sem(sem_args.sem, &count);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, count);
|
||||||
|
+ check_sem_state(sem_args.sem, 1, 3);
|
||||||
|
+ check_mutex_state(mutex_args.mutex, 1, 456);
|
||||||
|
+
|
||||||
|
+ ret = wait_for_thread(thread, 100);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, thread_args.ret);
|
||||||
|
+
|
||||||
|
+ /* delete an object while it's being waited on */
|
||||||
|
+
|
||||||
|
+ wait_args.timeout = get_abs_timeout(200);
|
||||||
|
+ wait_args.owner = 123;
|
||||||
|
+ ret = pthread_create(&thread, NULL, wait_thread, &thread_args);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+
|
||||||
|
+ ret = wait_for_thread(thread, 100);
|
||||||
|
+ EXPECT_EQ(ETIMEDOUT, ret);
|
||||||
|
+
|
||||||
|
+ close(sem_args.sem);
|
||||||
|
+ close(mutex_args.mutex);
|
||||||
|
+
|
||||||
|
+ ret = wait_for_thread(thread, 200);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(-1, thread_args.ret);
|
||||||
|
+ EXPECT_EQ(ETIMEDOUT, thread_args.err);
|
||||||
|
+
|
||||||
|
+ close(fd);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
TEST_HARNESS_MAIN
|
||||||
|
--
|
||||||
|
2.43.0
|
|
@ -0,0 +1,118 @@
|
||||||
|
Test event-specific ioctls NTSYNC_IOC_EVENT_SET, NTSYNC_IOC_EVENT_RESET,
|
||||||
|
NTSYNC_IOC_EVENT_PULSE, NTSYNC_IOC_EVENT_READ for manual-reset events, and
|
||||||
|
waiting on manual-reset events.
|
||||||
|
|
||||||
|
Signed-off-by: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
---
|
||||||
|
.../testing/selftests/drivers/ntsync/ntsync.c | 89 +++++++++++++++++++
|
||||||
|
1 file changed, 89 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
index b77fb0b2c4b1..b6481c2b85cc 100644
|
||||||
|
--- a/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
+++ b/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
@@ -73,6 +73,27 @@ static int unlock_mutex(int mutex, __u32 owner, __u32 *count)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int read_event_state(int event, __u32 *signaled, __u32 *manual)
|
||||||
|
+{
|
||||||
|
+ struct ntsync_event_args args;
|
||||||
|
+ int ret;
|
||||||
|
+
|
||||||
|
+ memset(&args, 0xcc, sizeof(args));
|
||||||
|
+ ret = ioctl(event, NTSYNC_IOC_EVENT_READ, &args);
|
||||||
|
+ *signaled = args.signaled;
|
||||||
|
+ *manual = args.manual;
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#define check_event_state(event, signaled, manual) \
|
||||||
|
+ ({ \
|
||||||
|
+ __u32 __signaled, __manual; \
|
||||||
|
+ int ret = read_event_state((event), &__signaled, &__manual); \
|
||||||
|
+ EXPECT_EQ(0, ret); \
|
||||||
|
+ EXPECT_EQ((signaled), __signaled); \
|
||||||
|
+ EXPECT_EQ((manual), __manual); \
|
||||||
|
+ })
|
||||||
|
+
|
||||||
|
static int wait_objs(int fd, unsigned long request, __u32 count,
|
||||||
|
const int *objs, __u32 owner, __u32 *index)
|
||||||
|
{
|
||||||
|
@@ -353,6 +374,74 @@ TEST(mutex_state)
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
+TEST(manual_event_state)
|
||||||
|
+{
|
||||||
|
+ struct ntsync_event_args event_args;
|
||||||
|
+ __u32 index, signaled;
|
||||||
|
+ int fd, event, ret;
|
||||||
|
+
|
||||||
|
+ fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY);
|
||||||
|
+ ASSERT_LE(0, fd);
|
||||||
|
+
|
||||||
|
+ event_args.manual = 1;
|
||||||
|
+ event_args.signaled = 0;
|
||||||
|
+ event_args.event = 0xdeadbeef;
|
||||||
|
+ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_NE(0xdeadbeef, event_args.event);
|
||||||
|
+ event = event_args.event;
|
||||||
|
+ check_event_state(event, 0, 1);
|
||||||
|
+
|
||||||
|
+ signaled = 0xdeadbeef;
|
||||||
|
+ ret = ioctl(event, NTSYNC_IOC_EVENT_SET, &signaled);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, signaled);
|
||||||
|
+ check_event_state(event, 1, 1);
|
||||||
|
+
|
||||||
|
+ ret = ioctl(event, NTSYNC_IOC_EVENT_SET, &signaled);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(1, signaled);
|
||||||
|
+ check_event_state(event, 1, 1);
|
||||||
|
+
|
||||||
|
+ ret = wait_any(fd, 1, &event, 123, &index);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, index);
|
||||||
|
+ check_event_state(event, 1, 1);
|
||||||
|
+
|
||||||
|
+ signaled = 0xdeadbeef;
|
||||||
|
+ ret = ioctl(event, NTSYNC_IOC_EVENT_RESET, &signaled);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(1, signaled);
|
||||||
|
+ check_event_state(event, 0, 1);
|
||||||
|
+
|
||||||
|
+ ret = ioctl(event, NTSYNC_IOC_EVENT_RESET, &signaled);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, signaled);
|
||||||
|
+ check_event_state(event, 0, 1);
|
||||||
|
+
|
||||||
|
+ ret = wait_any(fd, 1, &event, 123, &index);
|
||||||
|
+ EXPECT_EQ(-1, ret);
|
||||||
|
+ EXPECT_EQ(ETIMEDOUT, errno);
|
||||||
|
+
|
||||||
|
+ ret = ioctl(event, NTSYNC_IOC_EVENT_SET, &signaled);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, signaled);
|
||||||
|
+
|
||||||
|
+ ret = ioctl(event, NTSYNC_IOC_EVENT_PULSE, &signaled);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(1, signaled);
|
||||||
|
+ check_event_state(event, 0, 1);
|
||||||
|
+
|
||||||
|
+ ret = ioctl(event, NTSYNC_IOC_EVENT_PULSE, &signaled);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, signaled);
|
||||||
|
+ check_event_state(event, 0, 1);
|
||||||
|
+
|
||||||
|
+ close(event);
|
||||||
|
+
|
||||||
|
+ close(fd);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
TEST(test_wait_any)
|
||||||
|
{
|
||||||
|
int objs[NTSYNC_MAX_WAIT_COUNT + 1], fd, ret;
|
||||||
|
--
|
||||||
|
2.43.0
|
|
@ -0,0 +1,81 @@
|
||||||
|
Test event-specific ioctls NTSYNC_IOC_EVENT_SET, NTSYNC_IOC_EVENT_RESET,
|
||||||
|
NTSYNC_IOC_EVENT_PULSE, NTSYNC_IOC_EVENT_READ for auto-reset events, and
|
||||||
|
waiting on auto-reset events.
|
||||||
|
|
||||||
|
Signed-off-by: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
---
|
||||||
|
.../testing/selftests/drivers/ntsync/ntsync.c | 59 +++++++++++++++++++
|
||||||
|
1 file changed, 59 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
index b6481c2b85cc..12ccb4ec28e4 100644
|
||||||
|
--- a/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
+++ b/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
@@ -442,6 +442,65 @@ TEST(manual_event_state)
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
+TEST(auto_event_state)
|
||||||
|
+{
|
||||||
|
+ struct ntsync_event_args event_args;
|
||||||
|
+ __u32 index, signaled;
|
||||||
|
+ int fd, event, ret;
|
||||||
|
+
|
||||||
|
+ fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY);
|
||||||
|
+ ASSERT_LE(0, fd);
|
||||||
|
+
|
||||||
|
+ event_args.manual = 0;
|
||||||
|
+ event_args.signaled = 1;
|
||||||
|
+ event_args.event = 0xdeadbeef;
|
||||||
|
+ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_NE(0xdeadbeef, event_args.event);
|
||||||
|
+ event = event_args.event;
|
||||||
|
+
|
||||||
|
+ check_event_state(event, 1, 0);
|
||||||
|
+
|
||||||
|
+ signaled = 0xdeadbeef;
|
||||||
|
+ ret = ioctl(event, NTSYNC_IOC_EVENT_SET, &signaled);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(1, signaled);
|
||||||
|
+ check_event_state(event, 1, 0);
|
||||||
|
+
|
||||||
|
+ ret = wait_any(fd, 1, &event, 123, &index);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, index);
|
||||||
|
+ check_event_state(event, 0, 0);
|
||||||
|
+
|
||||||
|
+ signaled = 0xdeadbeef;
|
||||||
|
+ ret = ioctl(event, NTSYNC_IOC_EVENT_RESET, &signaled);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, signaled);
|
||||||
|
+ check_event_state(event, 0, 0);
|
||||||
|
+
|
||||||
|
+ ret = wait_any(fd, 1, &event, 123, &index);
|
||||||
|
+ EXPECT_EQ(-1, ret);
|
||||||
|
+ EXPECT_EQ(ETIMEDOUT, errno);
|
||||||
|
+
|
||||||
|
+ ret = ioctl(event, NTSYNC_IOC_EVENT_SET, &signaled);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, signaled);
|
||||||
|
+
|
||||||
|
+ ret = ioctl(event, NTSYNC_IOC_EVENT_PULSE, &signaled);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(1, signaled);
|
||||||
|
+ check_event_state(event, 0, 0);
|
||||||
|
+
|
||||||
|
+ ret = ioctl(event, NTSYNC_IOC_EVENT_PULSE, &signaled);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, signaled);
|
||||||
|
+ check_event_state(event, 0, 0);
|
||||||
|
+
|
||||||
|
+ close(event);
|
||||||
|
+
|
||||||
|
+ close(fd);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
TEST(test_wait_any)
|
||||||
|
{
|
||||||
|
int objs[NTSYNC_MAX_WAIT_COUNT + 1], fd, ret;
|
||||||
|
--
|
||||||
|
2.43.0
|
|
@ -0,0 +1,259 @@
|
||||||
|
Expand the contended wait tests, which previously only covered events and
|
||||||
|
semaphores, to cover events as well.
|
||||||
|
|
||||||
|
Signed-off-by: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
---
|
||||||
|
.../testing/selftests/drivers/ntsync/ntsync.c | 151 +++++++++++++++++-
|
||||||
|
1 file changed, 147 insertions(+), 4 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
index 12ccb4ec28e4..5d17eff6a370 100644
|
||||||
|
--- a/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
+++ b/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
@@ -622,6 +622,7 @@ TEST(test_wait_any)
|
||||||
|
|
||||||
|
TEST(test_wait_all)
|
||||||
|
{
|
||||||
|
+ struct ntsync_event_args event_args = {0};
|
||||||
|
struct ntsync_mutex_args mutex_args = {0};
|
||||||
|
struct ntsync_sem_args sem_args = {0};
|
||||||
|
__u32 owner, index, count;
|
||||||
|
@@ -644,6 +645,11 @@ TEST(test_wait_all)
|
||||||
|
EXPECT_EQ(0, ret);
|
||||||
|
EXPECT_NE(0xdeadbeef, mutex_args.mutex);
|
||||||
|
|
||||||
|
+ event_args.manual = true;
|
||||||
|
+ event_args.signaled = true;
|
||||||
|
+ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+
|
||||||
|
objs[0] = sem_args.sem;
|
||||||
|
objs[1] = mutex_args.mutex;
|
||||||
|
|
||||||
|
@@ -692,6 +698,14 @@ TEST(test_wait_all)
|
||||||
|
check_sem_state(sem_args.sem, 1, 3);
|
||||||
|
check_mutex_state(mutex_args.mutex, 1, 123);
|
||||||
|
|
||||||
|
+ objs[0] = sem_args.sem;
|
||||||
|
+ objs[1] = event_args.event;
|
||||||
|
+ ret = wait_all(fd, 2, objs, 123, &index);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, index);
|
||||||
|
+ check_sem_state(sem_args.sem, 0, 3);
|
||||||
|
+ check_event_state(event_args.event, 1, 1);
|
||||||
|
+
|
||||||
|
/* test waiting on the same object twice */
|
||||||
|
objs[0] = objs[1] = sem_args.sem;
|
||||||
|
ret = wait_all(fd, 2, objs, 123, &index);
|
||||||
|
@@ -700,6 +714,7 @@ TEST(test_wait_all)
|
||||||
|
|
||||||
|
close(sem_args.sem);
|
||||||
|
close(mutex_args.mutex);
|
||||||
|
+ close(event_args.event);
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
@@ -746,12 +761,13 @@ static int wait_for_thread(pthread_t thread, unsigned int ms)
|
||||||
|
|
||||||
|
TEST(wake_any)
|
||||||
|
{
|
||||||
|
+ struct ntsync_event_args event_args = {0};
|
||||||
|
struct ntsync_mutex_args mutex_args = {0};
|
||||||
|
struct ntsync_wait_args wait_args = {0};
|
||||||
|
struct ntsync_sem_args sem_args = {0};
|
||||||
|
struct wait_args thread_args;
|
||||||
|
+ __u32 count, index, signaled;
|
||||||
|
int objs[2], fd, ret;
|
||||||
|
- __u32 count, index;
|
||||||
|
pthread_t thread;
|
||||||
|
|
||||||
|
fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY);
|
||||||
|
@@ -833,10 +849,101 @@ TEST(wake_any)
|
||||||
|
EXPECT_EQ(0, thread_args.ret);
|
||||||
|
EXPECT_EQ(1, wait_args.index);
|
||||||
|
|
||||||
|
+ /* test waking events */
|
||||||
|
+
|
||||||
|
+ event_args.manual = false;
|
||||||
|
+ event_args.signaled = false;
|
||||||
|
+ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+
|
||||||
|
+ objs[1] = event_args.event;
|
||||||
|
+ wait_args.timeout = get_abs_timeout(1000);
|
||||||
|
+ ret = pthread_create(&thread, NULL, wait_thread, &thread_args);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+
|
||||||
|
+ ret = wait_for_thread(thread, 100);
|
||||||
|
+ EXPECT_EQ(ETIMEDOUT, ret);
|
||||||
|
+
|
||||||
|
+ ret = ioctl(event_args.event, NTSYNC_IOC_EVENT_SET, &signaled);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, signaled);
|
||||||
|
+ check_event_state(event_args.event, 0, 0);
|
||||||
|
+
|
||||||
|
+ ret = wait_for_thread(thread, 100);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, thread_args.ret);
|
||||||
|
+ EXPECT_EQ(1, wait_args.index);
|
||||||
|
+
|
||||||
|
+ wait_args.timeout = get_abs_timeout(1000);
|
||||||
|
+ ret = pthread_create(&thread, NULL, wait_thread, &thread_args);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+
|
||||||
|
+ ret = wait_for_thread(thread, 100);
|
||||||
|
+ EXPECT_EQ(ETIMEDOUT, ret);
|
||||||
|
+
|
||||||
|
+ ret = ioctl(event_args.event, NTSYNC_IOC_EVENT_PULSE, &signaled);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, signaled);
|
||||||
|
+ check_event_state(event_args.event, 0, 0);
|
||||||
|
+
|
||||||
|
+ ret = wait_for_thread(thread, 100);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, thread_args.ret);
|
||||||
|
+ EXPECT_EQ(1, wait_args.index);
|
||||||
|
+
|
||||||
|
+ close(event_args.event);
|
||||||
|
+
|
||||||
|
+ event_args.manual = true;
|
||||||
|
+ event_args.signaled = false;
|
||||||
|
+ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+
|
||||||
|
+ objs[1] = event_args.event;
|
||||||
|
+ wait_args.timeout = get_abs_timeout(1000);
|
||||||
|
+ ret = pthread_create(&thread, NULL, wait_thread, &thread_args);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+
|
||||||
|
+ ret = wait_for_thread(thread, 100);
|
||||||
|
+ EXPECT_EQ(ETIMEDOUT, ret);
|
||||||
|
+
|
||||||
|
+ ret = ioctl(event_args.event, NTSYNC_IOC_EVENT_SET, &signaled);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, signaled);
|
||||||
|
+ check_event_state(event_args.event, 1, 1);
|
||||||
|
+
|
||||||
|
+ ret = wait_for_thread(thread, 100);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, thread_args.ret);
|
||||||
|
+ EXPECT_EQ(1, wait_args.index);
|
||||||
|
+
|
||||||
|
+ ret = ioctl(event_args.event, NTSYNC_IOC_EVENT_RESET, &signaled);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(1, signaled);
|
||||||
|
+
|
||||||
|
+ wait_args.timeout = get_abs_timeout(1000);
|
||||||
|
+ ret = pthread_create(&thread, NULL, wait_thread, &thread_args);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+
|
||||||
|
+ ret = wait_for_thread(thread, 100);
|
||||||
|
+ EXPECT_EQ(ETIMEDOUT, ret);
|
||||||
|
+
|
||||||
|
+ ret = ioctl(event_args.event, NTSYNC_IOC_EVENT_PULSE, &signaled);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, signaled);
|
||||||
|
+ check_event_state(event_args.event, 0, 1);
|
||||||
|
+
|
||||||
|
+ ret = wait_for_thread(thread, 100);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, thread_args.ret);
|
||||||
|
+ EXPECT_EQ(1, wait_args.index);
|
||||||
|
+
|
||||||
|
+ close(event_args.event);
|
||||||
|
+
|
||||||
|
/* delete an object while it's being waited on */
|
||||||
|
|
||||||
|
wait_args.timeout = get_abs_timeout(200);
|
||||||
|
wait_args.owner = 123;
|
||||||
|
+ objs[1] = mutex_args.mutex;
|
||||||
|
ret = pthread_create(&thread, NULL, wait_thread, &thread_args);
|
||||||
|
EXPECT_EQ(0, ret);
|
||||||
|
|
||||||
|
@@ -856,12 +963,14 @@ TEST(wake_any)
|
||||||
|
|
||||||
|
TEST(wake_all)
|
||||||
|
{
|
||||||
|
+ struct ntsync_event_args manual_event_args = {0};
|
||||||
|
+ struct ntsync_event_args auto_event_args = {0};
|
||||||
|
struct ntsync_mutex_args mutex_args = {0};
|
||||||
|
struct ntsync_wait_args wait_args = {0};
|
||||||
|
struct ntsync_sem_args sem_args = {0};
|
||||||
|
struct wait_args thread_args;
|
||||||
|
- int objs[2], fd, ret;
|
||||||
|
- __u32 count, index;
|
||||||
|
+ __u32 count, index, signaled;
|
||||||
|
+ int objs[4], fd, ret;
|
||||||
|
pthread_t thread;
|
||||||
|
|
||||||
|
fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY);
|
||||||
|
@@ -881,12 +990,24 @@ TEST(wake_all)
|
||||||
|
EXPECT_EQ(0, ret);
|
||||||
|
EXPECT_NE(0xdeadbeef, mutex_args.mutex);
|
||||||
|
|
||||||
|
+ manual_event_args.manual = true;
|
||||||
|
+ manual_event_args.signaled = true;
|
||||||
|
+ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &manual_event_args);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+
|
||||||
|
+ auto_event_args.manual = false;
|
||||||
|
+ auto_event_args.signaled = true;
|
||||||
|
+ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &auto_event_args);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+
|
||||||
|
objs[0] = sem_args.sem;
|
||||||
|
objs[1] = mutex_args.mutex;
|
||||||
|
+ objs[2] = manual_event_args.event;
|
||||||
|
+ objs[3] = auto_event_args.event;
|
||||||
|
|
||||||
|
wait_args.timeout = get_abs_timeout(1000);
|
||||||
|
wait_args.objs = (uintptr_t)objs;
|
||||||
|
- wait_args.count = 2;
|
||||||
|
+ wait_args.count = 4;
|
||||||
|
wait_args.owner = 456;
|
||||||
|
thread_args.fd = fd;
|
||||||
|
thread_args.args = &wait_args;
|
||||||
|
@@ -920,12 +1041,32 @@ TEST(wake_all)
|
||||||
|
|
||||||
|
check_mutex_state(mutex_args.mutex, 0, 0);
|
||||||
|
|
||||||
|
+ ret = ioctl(manual_event_args.event, NTSYNC_IOC_EVENT_RESET, &signaled);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(1, signaled);
|
||||||
|
+
|
||||||
|
count = 2;
|
||||||
|
ret = post_sem(sem_args.sem, &count);
|
||||||
|
EXPECT_EQ(0, ret);
|
||||||
|
EXPECT_EQ(0, count);
|
||||||
|
+ check_sem_state(sem_args.sem, 2, 3);
|
||||||
|
+
|
||||||
|
+ ret = ioctl(auto_event_args.event, NTSYNC_IOC_EVENT_RESET, &signaled);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(1, signaled);
|
||||||
|
+
|
||||||
|
+ ret = ioctl(manual_event_args.event, NTSYNC_IOC_EVENT_SET, &signaled);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, signaled);
|
||||||
|
+
|
||||||
|
+ ret = ioctl(auto_event_args.event, NTSYNC_IOC_EVENT_SET, &signaled);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, signaled);
|
||||||
|
+
|
||||||
|
check_sem_state(sem_args.sem, 1, 3);
|
||||||
|
check_mutex_state(mutex_args.mutex, 1, 456);
|
||||||
|
+ check_event_state(manual_event_args.event, 1, 1);
|
||||||
|
+ check_event_state(auto_event_args.event, 0, 0);
|
||||||
|
|
||||||
|
ret = wait_for_thread(thread, 100);
|
||||||
|
EXPECT_EQ(0, ret);
|
||||||
|
@@ -943,6 +1084,8 @@ TEST(wake_all)
|
||||||
|
|
||||||
|
close(sem_args.sem);
|
||||||
|
close(mutex_args.mutex);
|
||||||
|
+ close(manual_event_args.event);
|
||||||
|
+ close(auto_event_args.event);
|
||||||
|
|
||||||
|
ret = wait_for_thread(thread, 200);
|
||||||
|
EXPECT_EQ(0, ret);
|
||||||
|
--
|
||||||
|
2.43.0
|
|
@ -0,0 +1,223 @@
|
||||||
|
Test the "alert" functionality of NTSYNC_IOC_WAIT_ALL and NTSYNC_IOC_WAIT_ANY,
|
||||||
|
when a wait is woken with an alert and when it is woken by an object.
|
||||||
|
|
||||||
|
Signed-off-by: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
---
|
||||||
|
.../testing/selftests/drivers/ntsync/ntsync.c | 179 +++++++++++++++++-
|
||||||
|
1 file changed, 176 insertions(+), 3 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
index 5d17eff6a370..5465a16d38b3 100644
|
||||||
|
--- a/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
+++ b/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
@@ -95,7 +95,7 @@ static int read_event_state(int event, __u32 *signaled, __u32 *manual)
|
||||||
|
})
|
||||||
|
|
||||||
|
static int wait_objs(int fd, unsigned long request, __u32 count,
|
||||||
|
- const int *objs, __u32 owner, __u32 *index)
|
||||||
|
+ const int *objs, __u32 owner, int alert, __u32 *index)
|
||||||
|
{
|
||||||
|
struct ntsync_wait_args args = {0};
|
||||||
|
struct timespec timeout;
|
||||||
|
@@ -108,6 +108,7 @@ static int wait_objs(int fd, unsigned long request, __u32 count,
|
||||||
|
args.objs = (uintptr_t)objs;
|
||||||
|
args.owner = owner;
|
||||||
|
args.index = 0xdeadbeef;
|
||||||
|
+ args.alert = alert;
|
||||||
|
ret = ioctl(fd, request, &args);
|
||||||
|
*index = args.index;
|
||||||
|
return ret;
|
||||||
|
@@ -115,12 +116,26 @@ static int wait_objs(int fd, unsigned long request, __u32 count,
|
||||||
|
|
||||||
|
static int wait_any(int fd, __u32 count, const int *objs, __u32 owner, __u32 *index)
|
||||||
|
{
|
||||||
|
- return wait_objs(fd, NTSYNC_IOC_WAIT_ANY, count, objs, owner, index);
|
||||||
|
+ return wait_objs(fd, NTSYNC_IOC_WAIT_ANY, count, objs, owner, 0, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int wait_all(int fd, __u32 count, const int *objs, __u32 owner, __u32 *index)
|
||||||
|
{
|
||||||
|
- return wait_objs(fd, NTSYNC_IOC_WAIT_ALL, count, objs, owner, index);
|
||||||
|
+ return wait_objs(fd, NTSYNC_IOC_WAIT_ALL, count, objs, owner, 0, index);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int wait_any_alert(int fd, __u32 count, const int *objs,
|
||||||
|
+ __u32 owner, int alert, __u32 *index)
|
||||||
|
+{
|
||||||
|
+ return wait_objs(fd, NTSYNC_IOC_WAIT_ANY,
|
||||||
|
+ count, objs, owner, alert, index);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int wait_all_alert(int fd, __u32 count, const int *objs,
|
||||||
|
+ __u32 owner, int alert, __u32 *index)
|
||||||
|
+{
|
||||||
|
+ return wait_objs(fd, NTSYNC_IOC_WAIT_ALL,
|
||||||
|
+ count, objs, owner, alert, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(semaphore_state)
|
||||||
|
@@ -1095,4 +1110,162 @@ TEST(wake_all)
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
+TEST(alert_any)
|
||||||
|
+{
|
||||||
|
+ struct ntsync_event_args event_args = {0};
|
||||||
|
+ struct ntsync_sem_args sem_args = {0};
|
||||||
|
+ __u32 index, count, signaled;
|
||||||
|
+ int objs[2], fd, ret;
|
||||||
|
+
|
||||||
|
+ fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY);
|
||||||
|
+ ASSERT_LE(0, fd);
|
||||||
|
+
|
||||||
|
+ sem_args.count = 0;
|
||||||
|
+ sem_args.max = 2;
|
||||||
|
+ sem_args.sem = 0xdeadbeef;
|
||||||
|
+ ret = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_NE(0xdeadbeef, sem_args.sem);
|
||||||
|
+ objs[0] = sem_args.sem;
|
||||||
|
+
|
||||||
|
+ sem_args.count = 1;
|
||||||
|
+ sem_args.max = 2;
|
||||||
|
+ sem_args.sem = 0xdeadbeef;
|
||||||
|
+ ret = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_NE(0xdeadbeef, sem_args.sem);
|
||||||
|
+ objs[1] = sem_args.sem;
|
||||||
|
+
|
||||||
|
+ event_args.manual = true;
|
||||||
|
+ event_args.signaled = true;
|
||||||
|
+ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+
|
||||||
|
+ ret = wait_any_alert(fd, 0, NULL, 123, event_args.event, &index);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, index);
|
||||||
|
+
|
||||||
|
+ ret = ioctl(event_args.event, NTSYNC_IOC_EVENT_RESET, &signaled);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+
|
||||||
|
+ ret = wait_any_alert(fd, 0, NULL, 123, event_args.event, &index);
|
||||||
|
+ EXPECT_EQ(-1, ret);
|
||||||
|
+ EXPECT_EQ(ETIMEDOUT, errno);
|
||||||
|
+
|
||||||
|
+ ret = ioctl(event_args.event, NTSYNC_IOC_EVENT_SET, &signaled);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+
|
||||||
|
+ ret = wait_any_alert(fd, 2, objs, 123, event_args.event, &index);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(1, index);
|
||||||
|
+
|
||||||
|
+ ret = wait_any_alert(fd, 2, objs, 123, event_args.event, &index);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(2, index);
|
||||||
|
+
|
||||||
|
+ close(event_args.event);
|
||||||
|
+
|
||||||
|
+ /* test with an auto-reset event */
|
||||||
|
+
|
||||||
|
+ event_args.manual = false;
|
||||||
|
+ event_args.signaled = true;
|
||||||
|
+ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+
|
||||||
|
+ count = 1;
|
||||||
|
+ ret = post_sem(objs[0], &count);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+
|
||||||
|
+ ret = wait_any_alert(fd, 2, objs, 123, event_args.event, &index);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, index);
|
||||||
|
+
|
||||||
|
+ ret = wait_any_alert(fd, 2, objs, 123, event_args.event, &index);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(2, index);
|
||||||
|
+
|
||||||
|
+ ret = wait_any_alert(fd, 2, objs, 123, event_args.event, &index);
|
||||||
|
+ EXPECT_EQ(-1, ret);
|
||||||
|
+ EXPECT_EQ(ETIMEDOUT, errno);
|
||||||
|
+
|
||||||
|
+ close(event_args.event);
|
||||||
|
+
|
||||||
|
+ close(objs[0]);
|
||||||
|
+ close(objs[1]);
|
||||||
|
+
|
||||||
|
+ close(fd);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+TEST(alert_all)
|
||||||
|
+{
|
||||||
|
+ struct ntsync_event_args event_args = {0};
|
||||||
|
+ struct ntsync_sem_args sem_args = {0};
|
||||||
|
+ __u32 index, count, signaled;
|
||||||
|
+ int objs[2], fd, ret;
|
||||||
|
+
|
||||||
|
+ fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY);
|
||||||
|
+ ASSERT_LE(0, fd);
|
||||||
|
+
|
||||||
|
+ sem_args.count = 2;
|
||||||
|
+ sem_args.max = 2;
|
||||||
|
+ sem_args.sem = 0xdeadbeef;
|
||||||
|
+ ret = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_NE(0xdeadbeef, sem_args.sem);
|
||||||
|
+ objs[0] = sem_args.sem;
|
||||||
|
+
|
||||||
|
+ sem_args.count = 1;
|
||||||
|
+ sem_args.max = 2;
|
||||||
|
+ sem_args.sem = 0xdeadbeef;
|
||||||
|
+ ret = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_NE(0xdeadbeef, sem_args.sem);
|
||||||
|
+ objs[1] = sem_args.sem;
|
||||||
|
+
|
||||||
|
+ event_args.manual = true;
|
||||||
|
+ event_args.signaled = true;
|
||||||
|
+ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+
|
||||||
|
+ ret = wait_all_alert(fd, 2, objs, 123, event_args.event, &index);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, index);
|
||||||
|
+
|
||||||
|
+ ret = wait_all_alert(fd, 2, objs, 123, event_args.event, &index);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(2, index);
|
||||||
|
+
|
||||||
|
+ close(event_args.event);
|
||||||
|
+
|
||||||
|
+ /* test with an auto-reset event */
|
||||||
|
+
|
||||||
|
+ event_args.manual = false;
|
||||||
|
+ event_args.signaled = true;
|
||||||
|
+ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+
|
||||||
|
+ count = 2;
|
||||||
|
+ ret = post_sem(objs[1], &count);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+
|
||||||
|
+ ret = wait_all_alert(fd, 2, objs, 123, event_args.event, &index);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, index);
|
||||||
|
+
|
||||||
|
+ ret = wait_all_alert(fd, 2, objs, 123, event_args.event, &index);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(2, index);
|
||||||
|
+
|
||||||
|
+ ret = wait_all_alert(fd, 2, objs, 123, event_args.event, &index);
|
||||||
|
+ EXPECT_EQ(-1, ret);
|
||||||
|
+ EXPECT_EQ(ETIMEDOUT, errno);
|
||||||
|
+
|
||||||
|
+ close(event_args.event);
|
||||||
|
+
|
||||||
|
+ close(objs[0]);
|
||||||
|
+ close(objs[1]);
|
||||||
|
+
|
||||||
|
+ close(fd);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
TEST_HARNESS_MAIN
|
||||||
|
--
|
||||||
|
2.43.0
|
|
@ -0,0 +1,110 @@
|
||||||
|
Expand the alert tests to cover alerting a thread mid-wait, to test that the
|
||||||
|
relevant scheduling logic works correctly.
|
||||||
|
|
||||||
|
Signed-off-by: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
---
|
||||||
|
.../testing/selftests/drivers/ntsync/ntsync.c | 62 +++++++++++++++++++
|
||||||
|
1 file changed, 62 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
index 5465a16d38b3..968874d7e325 100644
|
||||||
|
--- a/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
+++ b/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
@@ -1113,9 +1113,12 @@ TEST(wake_all)
|
||||||
|
TEST(alert_any)
|
||||||
|
{
|
||||||
|
struct ntsync_event_args event_args = {0};
|
||||||
|
+ struct ntsync_wait_args wait_args = {0};
|
||||||
|
struct ntsync_sem_args sem_args = {0};
|
||||||
|
__u32 index, count, signaled;
|
||||||
|
+ struct wait_args thread_args;
|
||||||
|
int objs[2], fd, ret;
|
||||||
|
+ pthread_t thread;
|
||||||
|
|
||||||
|
fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY);
|
||||||
|
ASSERT_LE(0, fd);
|
||||||
|
@@ -1163,6 +1166,34 @@ TEST(alert_any)
|
||||||
|
EXPECT_EQ(0, ret);
|
||||||
|
EXPECT_EQ(2, index);
|
||||||
|
|
||||||
|
+ /* test wakeup via alert */
|
||||||
|
+
|
||||||
|
+ ret = ioctl(event_args.event, NTSYNC_IOC_EVENT_RESET, &signaled);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+
|
||||||
|
+ wait_args.timeout = get_abs_timeout(1000);
|
||||||
|
+ wait_args.objs = (uintptr_t)objs;
|
||||||
|
+ wait_args.count = 2;
|
||||||
|
+ wait_args.owner = 123;
|
||||||
|
+ wait_args.index = 0xdeadbeef;
|
||||||
|
+ wait_args.alert = event_args.event;
|
||||||
|
+ thread_args.fd = fd;
|
||||||
|
+ thread_args.args = &wait_args;
|
||||||
|
+ thread_args.request = NTSYNC_IOC_WAIT_ANY;
|
||||||
|
+ ret = pthread_create(&thread, NULL, wait_thread, &thread_args);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+
|
||||||
|
+ ret = wait_for_thread(thread, 100);
|
||||||
|
+ EXPECT_EQ(ETIMEDOUT, ret);
|
||||||
|
+
|
||||||
|
+ ret = ioctl(event_args.event, NTSYNC_IOC_EVENT_SET, &signaled);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+
|
||||||
|
+ ret = wait_for_thread(thread, 100);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, thread_args.ret);
|
||||||
|
+ EXPECT_EQ(2, wait_args.index);
|
||||||
|
+
|
||||||
|
close(event_args.event);
|
||||||
|
|
||||||
|
/* test with an auto-reset event */
|
||||||
|
@@ -1199,9 +1230,12 @@ TEST(alert_any)
|
||||||
|
TEST(alert_all)
|
||||||
|
{
|
||||||
|
struct ntsync_event_args event_args = {0};
|
||||||
|
+ struct ntsync_wait_args wait_args = {0};
|
||||||
|
struct ntsync_sem_args sem_args = {0};
|
||||||
|
+ struct wait_args thread_args;
|
||||||
|
__u32 index, count, signaled;
|
||||||
|
int objs[2], fd, ret;
|
||||||
|
+ pthread_t thread;
|
||||||
|
|
||||||
|
fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY);
|
||||||
|
ASSERT_LE(0, fd);
|
||||||
|
@@ -1235,6 +1269,34 @@ TEST(alert_all)
|
||||||
|
EXPECT_EQ(0, ret);
|
||||||
|
EXPECT_EQ(2, index);
|
||||||
|
|
||||||
|
+ /* test wakeup via alert */
|
||||||
|
+
|
||||||
|
+ ret = ioctl(event_args.event, NTSYNC_IOC_EVENT_RESET, &signaled);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+
|
||||||
|
+ wait_args.timeout = get_abs_timeout(1000);
|
||||||
|
+ wait_args.objs = (uintptr_t)objs;
|
||||||
|
+ wait_args.count = 2;
|
||||||
|
+ wait_args.owner = 123;
|
||||||
|
+ wait_args.index = 0xdeadbeef;
|
||||||
|
+ wait_args.alert = event_args.event;
|
||||||
|
+ thread_args.fd = fd;
|
||||||
|
+ thread_args.args = &wait_args;
|
||||||
|
+ thread_args.request = NTSYNC_IOC_WAIT_ALL;
|
||||||
|
+ ret = pthread_create(&thread, NULL, wait_thread, &thread_args);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+
|
||||||
|
+ ret = wait_for_thread(thread, 100);
|
||||||
|
+ EXPECT_EQ(ETIMEDOUT, ret);
|
||||||
|
+
|
||||||
|
+ ret = ioctl(event_args.event, NTSYNC_IOC_EVENT_SET, &signaled);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+
|
||||||
|
+ ret = wait_for_thread(thread, 100);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ EXPECT_EQ(0, thread_args.ret);
|
||||||
|
+ EXPECT_EQ(2, wait_args.index);
|
||||||
|
+
|
||||||
|
close(event_args.event);
|
||||||
|
|
||||||
|
/* test with an auto-reset event */
|
||||||
|
--
|
||||||
|
2.43.0
|
|
@ -0,0 +1,97 @@
|
||||||
|
Test a more realistic usage pattern, and one with heavy contention, in order to
|
||||||
|
actually exercise ntsync's internal synchronization.
|
||||||
|
|
||||||
|
This test has several threads in a tight loop acquiring a mutex, modifying some
|
||||||
|
shared data, and then releasing the mutex. At the end we check if the data is
|
||||||
|
consistent.
|
||||||
|
|
||||||
|
Signed-off-by: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
---
|
||||||
|
.../testing/selftests/drivers/ntsync/ntsync.c | 74 +++++++++++++++++++
|
||||||
|
1 file changed, 74 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
index 968874d7e325..5fa2c9a0768c 100644
|
||||||
|
--- a/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
+++ b/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
@@ -1330,4 +1330,78 @@ TEST(alert_all)
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
+#define STRESS_LOOPS 10000
|
||||||
|
+#define STRESS_THREADS 4
|
||||||
|
+
|
||||||
|
+static unsigned int stress_counter;
|
||||||
|
+static int stress_device, stress_start_event, stress_mutex;
|
||||||
|
+
|
||||||
|
+static void *stress_thread(void *arg)
|
||||||
|
+{
|
||||||
|
+ struct ntsync_wait_args wait_args = {0};
|
||||||
|
+ __u32 index, count, i;
|
||||||
|
+ int ret;
|
||||||
|
+
|
||||||
|
+ wait_args.timeout = UINT64_MAX;
|
||||||
|
+ wait_args.count = 1;
|
||||||
|
+ wait_args.objs = (uintptr_t)&stress_start_event;
|
||||||
|
+ wait_args.owner = gettid();
|
||||||
|
+ wait_args.index = 0xdeadbeef;
|
||||||
|
+
|
||||||
|
+ ioctl(stress_device, NTSYNC_IOC_WAIT_ANY, &wait_args);
|
||||||
|
+
|
||||||
|
+ wait_args.objs = (uintptr_t)&stress_mutex;
|
||||||
|
+
|
||||||
|
+ for (i = 0; i < STRESS_LOOPS; ++i) {
|
||||||
|
+ ioctl(stress_device, NTSYNC_IOC_WAIT_ANY, &wait_args);
|
||||||
|
+
|
||||||
|
+ ++stress_counter;
|
||||||
|
+
|
||||||
|
+ unlock_mutex(stress_mutex, wait_args.owner, &count);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return NULL;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+TEST(stress_wait)
|
||||||
|
+{
|
||||||
|
+ struct ntsync_event_args event_args;
|
||||||
|
+ struct ntsync_mutex_args mutex_args;
|
||||||
|
+ pthread_t threads[STRESS_THREADS];
|
||||||
|
+ __u32 signaled, i;
|
||||||
|
+ int ret;
|
||||||
|
+
|
||||||
|
+ stress_device = open("/dev/ntsync", O_CLOEXEC | O_RDONLY);
|
||||||
|
+ ASSERT_LE(0, stress_device);
|
||||||
|
+
|
||||||
|
+ mutex_args.owner = 0;
|
||||||
|
+ mutex_args.count = 0;
|
||||||
|
+ ret = ioctl(stress_device, NTSYNC_IOC_CREATE_MUTEX, &mutex_args);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ stress_mutex = mutex_args.mutex;
|
||||||
|
+
|
||||||
|
+ event_args.manual = 1;
|
||||||
|
+ event_args.signaled = 0;
|
||||||
|
+ ret = ioctl(stress_device, NTSYNC_IOC_CREATE_EVENT, &event_args);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ stress_start_event = event_args.event;
|
||||||
|
+
|
||||||
|
+ for (i = 0; i < STRESS_THREADS; ++i)
|
||||||
|
+ pthread_create(&threads[i], NULL, stress_thread, NULL);
|
||||||
|
+
|
||||||
|
+ ret = ioctl(stress_start_event, NTSYNC_IOC_EVENT_SET, &signaled);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+
|
||||||
|
+ for (i = 0; i < STRESS_THREADS; ++i) {
|
||||||
|
+ ret = pthread_join(threads[i], NULL);
|
||||||
|
+ EXPECT_EQ(0, ret);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ EXPECT_EQ(STRESS_LOOPS * STRESS_THREADS, stress_counter);
|
||||||
|
+
|
||||||
|
+ close(stress_start_event);
|
||||||
|
+ close(stress_mutex);
|
||||||
|
+ close(stress_device);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
TEST_HARNESS_MAIN
|
||||||
|
--
|
||||||
|
2.43.0
|
|
@ -0,0 +1,29 @@
|
||||||
|
Add myself as maintainer, supported by CodeWeavers.
|
||||||
|
|
||||||
|
Signed-off-by: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
---
|
||||||
|
MAINTAINERS | 9 +++++++++
|
||||||
|
1 file changed, 9 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/MAINTAINERS b/MAINTAINERS
|
||||||
|
index 9ed4d3868539..d83dd35d9f73 100644
|
||||||
|
--- a/MAINTAINERS
|
||||||
|
+++ b/MAINTAINERS
|
||||||
|
@@ -15595,6 +15595,15 @@ T: git https://github.com/Paragon-Software-Group/linux-ntfs3.git
|
||||||
|
F: Documentation/filesystems/ntfs3.rst
|
||||||
|
F: fs/ntfs3/
|
||||||
|
|
||||||
|
+NTSYNC SYNCHRONIZATION PRIMITIVE DRIVER
|
||||||
|
+M: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
+L: wine-devel@winehq.org
|
||||||
|
+S: Supported
|
||||||
|
+F: Documentation/userspace-api/ntsync.rst
|
||||||
|
+F: drivers/misc/ntsync.c
|
||||||
|
+F: include/uapi/linux/ntsync.h
|
||||||
|
+F: tools/testing/selftests/drivers/ntsync/
|
||||||
|
+
|
||||||
|
NUBUS SUBSYSTEM
|
||||||
|
M: Finn Thain <fthain@linux-m68k.org>
|
||||||
|
L: linux-m68k@lists.linux-m68k.org
|
||||||
|
--
|
||||||
|
2.43.0
|
|
@ -0,0 +1,19 @@
|
||||||
|
diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h
|
||||||
|
index 4102108..72474d8 100644
|
||||||
|
--- a/kernel/rcu/tree_plugin.h
|
||||||
|
+++ b/kernel/rcu/tree_plugin.h
|
||||||
|
@@ -406,7 +406,7 @@ void __rcu_read_lock(void)
|
||||||
|
WRITE_ONCE(current->rcu_read_unlock_special.b.need_qs, true);
|
||||||
|
barrier(); /* critical section after entry code. */
|
||||||
|
}
|
||||||
|
-EXPORT_SYMBOL_GPL(__rcu_read_lock);
|
||||||
|
+EXPORT_SYMBOL(__rcu_read_lock);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Preemptible RCU implementation for rcu_read_unlock().
|
||||||
|
@@ -431,7 +431,7 @@ void __rcu_read_unlock(void)
|
||||||
|
WARN_ON_ONCE(rrln < 0 || rrln > RCU_NEST_PMAX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
-EXPORT_SYMBOL_GPL(__rcu_read_unlock);
|
||||||
|
+EXPORT_SYMBOL(__rcu_read_unlock);
|
|
@ -1,22 +1,13 @@
|
||||||
%global debug_package %{nil}
|
%global debug_package %{nil}
|
||||||
%global zen zen1
|
%global zen zen1
|
||||||
Name: linux-zen
|
Name: linux-zen
|
||||||
Version: 6.7.2
|
Version: 6.7.6
|
||||||
Release: 1%{?dist}
|
Release: 1%{?dist}
|
||||||
Summary: Linux kernel and modules with Zen patches
|
Summary: Linux kernel and modules with Zen patches
|
||||||
|
|
||||||
License: GPL-2.0-only
|
License: GPL-2.0-only
|
||||||
URL: http://www.zen-kernel.org/
|
URL: http://www.zen-kernel.org/
|
||||||
Source0: v%{version}-%{zen}.tar.gz
|
Source0: v%{version}-%{zen}.tar.gz
|
||||||
Patch0: 0000-NTPatch.patch
|
|
||||||
Patch1: 0001-NTPatch.patch
|
|
||||||
Patch2: 0002-NTPatch.patch
|
|
||||||
Patch3: 0003-NTPatch.patch
|
|
||||||
Patch4: 0004-NTPatch.patch
|
|
||||||
Patch5: 0005-NTPatch.patch
|
|
||||||
Patch6: 0006-NTPatch.patch
|
|
||||||
Patch7: 0007-NTPatch.patch
|
|
||||||
Patch8: 0008-NTPatch.patch
|
|
||||||
|
|
||||||
BuildRequires: gcc, make, flex, bison, ncurses-devel, elfutils-libelf-devel, openssl-devel
|
BuildRequires: gcc, make, flex, bison, ncurses-devel, elfutils-libelf-devel, openssl-devel
|
||||||
|
|
||||||
|
@ -27,15 +18,11 @@ Linux kernel and modules with Zen patches (%{version} series) compiled with Clan
|
||||||
%setup -q -n zen-kernel-%{version}-%{zen}
|
%setup -q -n zen-kernel-%{version}-%{zen}
|
||||||
cp %{_sourcedir}/.config .config
|
cp %{_sourcedir}/.config .config
|
||||||
|
|
||||||
%patch0 -p1
|
# Apply all patch files in a shell loop
|
||||||
%patch1 -p1
|
for patch in %{_sourcedir}/*.patch; do
|
||||||
%patch2 -p1
|
echo "Applying $patch"
|
||||||
%patch3 -p1
|
patch -p1 < $patch
|
||||||
%patch4 -p1
|
done
|
||||||
%patch5 -p1
|
|
||||||
%patch6 -p1
|
|
||||||
%patch7 -p1
|
|
||||||
%patch8 -p1
|
|
||||||
|
|
||||||
%build
|
%build
|
||||||
# Set environment variables for Clang and LLVM tools
|
# Set environment variables for Clang and LLVM tools
|
||||||
|
@ -72,22 +59,21 @@ make LLVM=1 %{?_smp_mflags}
|
||||||
%install
|
%install
|
||||||
make modules_install INSTALL_MOD_PATH=%{buildroot}
|
make modules_install INSTALL_MOD_PATH=%{buildroot}
|
||||||
|
|
||||||
# Define the path for vmlinuz file
|
|
||||||
VMLINUX_PATH=%{buildroot}/boot
|
VMLINUX_PATH=%{buildroot}/boot
|
||||||
|
|
||||||
# Create the boot directory
|
|
||||||
mkdir -p $VMLINUX_PATH
|
mkdir -p $VMLINUX_PATH
|
||||||
|
|
||||||
# Navigate to the directory where vmlinux is located
|
cd %{_builddir}/zen-kernel-%{version}-zen1/arch/x86/boot
|
||||||
cd %{_builddir}/zen-kernel-%{version}-%{zen}
|
|
||||||
|
|
||||||
# Compress vmlinux and move it to the vmlinuz path
|
cp bzImage $VMLINUX_PATH/vmlinuz-%{version}-%{zen}.fc39.x86_64
|
||||||
gzip -c vmlinux > $VMLINUX_PATH/vmlinuz-%{version}-%{zen}.fc39.x86_64
|
|
||||||
|
cd %{_builddir}/zen-kernel-%{version}-zen1
|
||||||
|
|
||||||
cp %{_sourcedir}/.config $VMLINUX_PATH/config-%{version}-%{zen}.fc39.x86_64
|
cp %{_sourcedir}/.config $VMLINUX_PATH/config-%{version}-%{zen}.fc39.x86_64
|
||||||
|
|
||||||
%files
|
%files
|
||||||
/boot/vmlinuz-%{version}-%{zen}
|
/boot/vmlinuz-%{version}-%{zen}.fc39.x86_64
|
||||||
|
/boot/config-%{version}-%{zen}.fc39.x86_64
|
||||||
/lib/modules/*
|
/lib/modules/*
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
kernel_version="6.7.2"
|
kernel_version="6.7.6"
|
||||||
zen_version="zen1"
|
zen_version="zen1"
|
||||||
source_url="https://github.com/zen-kernel/zen-kernel/archive/refs/tags/v${kernel_version}-${zen_version}.tar.gz"
|
source_url="https://github.com/zen-kernel/zen-kernel/archive/refs/tags/v${kernel_version}-${zen_version}.tar.gz"
|
||||||
source_file="v${kernel_version}-${zen_version}.tar.gz"
|
source_file="v${kernel_version}-${zen_version}.tar.gz"
|
||||||
|
@ -33,4 +33,3 @@ if [ ! -f "SOURCES/${source_file}" ]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
rpmbuild -ba --define "_topdir $PWD" SPECS/linux-zen.spec
|
rpmbuild -ba --define "_topdir $PWD" SPECS/linux-zen.spec
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
kernel_version="6.7.2"
|
kernel_version="6.7.6"
|
||||||
zen_version="zen1"
|
zen_version="zen1"
|
||||||
revision="1"
|
revision="1"
|
||||||
|
|
||||||
sudo dracut /boot/initramfs-${kernel_version}-${zen_version}.img ${zen_version}-zen1_${revision}
|
sudo dracut /boot/initramfs-${kernel_version}-${zen_version}.fc39.x86_64.img ${kernel_version}-${zen_version}_${revision}
|
||||||
|
|
Loading…
Reference in New Issue