Update NTSync patches
This commit is contained in:
parent
5719eb10bc
commit
21b7898ff9
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -1,107 +0,0 @@
|
||||||
This corresponds to the NT syscall NtReleaseMutant().
|
|
||||||
|
|
||||||
Signed-off-by: Elizabeth Figura <zfigura@codeweavers.com>
|
|
||||||
---
|
|
||||||
drivers/misc/ntsync.c | 67 +++++++++++++++++++++++++++++++++++++
|
|
||||||
include/uapi/linux/ntsync.h | 2 ++
|
|
||||||
2 files changed, 69 insertions(+)
|
|
||||||
|
|
||||||
diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c
|
|
||||||
index d48f2ef41341..28f43768d1c3 100644
|
|
||||||
--- a/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)
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
+/*
|
|
||||||
+ * Actually change the mutex state, returning -EPERM if not the owner.
|
|
||||||
+ */
|
|
||||||
+static int put_mutex_state(struct ntsync_obj *mutex,
|
|
||||||
+ const struct ntsync_mutex_args *args)
|
|
||||||
+{
|
|
||||||
+ lockdep_assert_held(&mutex->lock);
|
|
||||||
+
|
|
||||||
+ if (mutex->u.mutex.owner != args->owner)
|
|
||||||
+ return -EPERM;
|
|
||||||
+
|
|
||||||
+ if (!--mutex->u.mutex.count)
|
|
||||||
+ mutex->u.mutex.owner = 0;
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int ntsync_put_mutex(struct ntsync_device *dev, void __user *argp)
|
|
||||||
+{
|
|
||||||
+ struct ntsync_mutex_args __user *user_args = argp;
|
|
||||||
+ struct ntsync_mutex_args args;
|
|
||||||
+ struct ntsync_obj *mutex;
|
|
||||||
+ __u32 prev_count;
|
|
||||||
+ int ret;
|
|
||||||
+
|
|
||||||
+ if (copy_from_user(&args, argp, sizeof(args)))
|
|
||||||
+ return -EFAULT;
|
|
||||||
+ if (!args.owner)
|
|
||||||
+ return -EINVAL;
|
|
||||||
+
|
|
||||||
+ mutex = get_obj_typed(dev, args.mutex, NTSYNC_TYPE_MUTEX);
|
|
||||||
+ if (!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);
|
|
||||||
+
|
|
||||||
+ prev_count = mutex->u.mutex.count;
|
|
||||||
+ ret = put_mutex_state(mutex, &args);
|
|
||||||
+ 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);
|
|
||||||
+
|
|
||||||
+ prev_count = mutex->u.mutex.count;
|
|
||||||
+ ret = put_mutex_state(mutex, &args);
|
|
||||||
+ if (!ret)
|
|
||||||
+ try_wake_any_mutex(mutex);
|
|
||||||
+
|
|
||||||
+ spin_unlock(&mutex->lock);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ put_obj(mutex);
|
|
||||||
+
|
|
||||||
+ if (!ret && put_user(prev_count, &user_args->count))
|
|
||||||
+ ret = -EFAULT;
|
|
||||||
+
|
|
||||||
+ return ret;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
static int ntsync_schedule(const struct ntsync_q *q, ktime_t *timeout)
|
|
||||||
{
|
|
||||||
int ret = 0;
|
|
||||||
@@ -738,6 +803,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_MUTEX:
|
|
||||||
+ return ntsync_put_mutex(dev, argp);
|
|
||||||
case NTSYNC_IOC_PUT_SEM:
|
|
||||||
return ntsync_put_sem(dev, argp);
|
|
||||||
case NTSYNC_IOC_WAIT_ALL:
|
|
||||||
diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h
|
|
||||||
index 26d1b3d4847f..2e44e7e77776 100644
|
|
||||||
--- a/include/uapi/linux/ntsync.h
|
|
||||||
+++ b/include/uapi/linux/ntsync.h
|
|
||||||
@@ -46,5 +46,7 @@ struct ntsync_wait_args {
|
|
||||||
struct ntsync_wait_args)
|
|
||||||
#define NTSYNC_IOC_CREATE_MUTEX _IOWR(NTSYNC_IOC_BASE, 5, \
|
|
||||||
struct ntsync_mutex_args)
|
|
||||||
+#define NTSYNC_IOC_PUT_MUTEX _IOWR(NTSYNC_IOC_BASE, 6, \
|
|
||||||
+ struct ntsync_mutex_args)
|
|
||||||
|
|
||||||
#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
|
|
|
@ -1,3 +1,13 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 1/29] ntsync: Introduce the ntsync driver and
|
||||||
|
character device.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:28 -0600
|
||||||
|
Message-Id: <20240131021356.10322-2-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
ntsync uses a misc device as the simplest and least intrusive uAPI interface.
|
ntsync uses a misc device as the simplest and least intrusive uAPI interface.
|
||||||
|
|
||||||
Each file description on the device represents an isolated NT instance, intended
|
Each file description on the device represents an isolated NT instance, intended
|
||||||
|
@ -7,8 +17,8 @@ Signed-off-by: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
---
|
---
|
||||||
drivers/misc/Kconfig | 9 ++++++++
|
drivers/misc/Kconfig | 9 ++++++++
|
||||||
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, 62 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
|
||||||
|
@ -45,15 +55,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..e4969ef90722
|
||||||
--- /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
|
||||||
+ */
|
+ */
|
||||||
+
|
+
|
||||||
+#include <linux/fs.h>
|
+#include <linux/fs.h>
|
||||||
|
@ -86,7 +96,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,
|
||||||
+};
|
+};
|
||||||
+
|
+
|
||||||
|
@ -101,6 +111,6 @@ index 000000000000..9424c6210e51
|
||||||
+MODULE_AUTHOR("Elizabeth Figura");
|
+MODULE_AUTHOR("Elizabeth Figura");
|
||||||
+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
|
||||||
|
|
|
@ -0,0 +1,224 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 2/29] ntsync: Introduce NTSYNC_IOC_CREATE_SEM.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:29 -0600
|
||||||
|
Message-Id: <20240131021356.10322-3-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
This corresponds to the NT syscall NtCreateSemaphore().
|
||||||
|
|
||||||
|
Semaphores are one of three types of object to be implemented in this driver,
|
||||||
|
the others being mutexes and events.
|
||||||
|
|
||||||
|
An NT semaphore contains a 32-bit counter, and is signaled and can be acquired
|
||||||
|
when the counter is nonzero. The counter has a maximum value which is specified
|
||||||
|
at creation time. The initial value of the semaphore is also specified at
|
||||||
|
creation time. There are no restrictions on the maximum and initial value.
|
||||||
|
|
||||||
|
Each object is exposed as an file, to which any number of fds may be opened.
|
||||||
|
When all fds are closed, the object is deleted.
|
||||||
|
|
||||||
|
Signed-off-by: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
---
|
||||||
|
.../userspace-api/ioctl/ioctl-number.rst | 2 +
|
||||||
|
drivers/misc/ntsync.c | 120 ++++++++++++++++++
|
||||||
|
include/uapi/linux/ntsync.h | 21 +++
|
||||||
|
3 files changed, 143 insertions(+)
|
||||||
|
create mode 100644 include/uapi/linux/ntsync.h
|
||||||
|
|
||||||
|
diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst
|
||||||
|
index 457e16f06e04..2f5c6994f042 100644
|
||||||
|
--- a/Documentation/userspace-api/ioctl/ioctl-number.rst
|
||||||
|
+++ b/Documentation/userspace-api/ioctl/ioctl-number.rst
|
||||||
|
@@ -173,6 +173,8 @@ Code Seq# Include File Comments
|
||||||
|
'M' 00-0F drivers/video/fsl-diu-fb.h conflict!
|
||||||
|
'N' 00-1F drivers/usb/scanner.h
|
||||||
|
'N' 40-7F drivers/block/nvme.c
|
||||||
|
+'N' 80-8F uapi/linux/ntsync.h NT synchronization primitives
|
||||||
|
+ <mailto: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 e4969ef90722..3ad86d98b82d 100644
|
||||||
|
--- a/drivers/misc/ntsync.c
|
||||||
|
+++ b/drivers/misc/ntsync.c
|
||||||
|
@@ -5,26 +5,146 @@
|
||||||
|
* Copyright (C) 2024 Elizabeth Figura
|
||||||
|
*/
|
||||||
|
|
||||||
|
+#include <linux/anon_inodes.h>
|
||||||
|
+#include <linux/file.h>
|
||||||
|
#include <linux/fs.h>
|
||||||
|
#include <linux/miscdevice.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
+#include <linux/slab.h>
|
||||||
|
+#include <uapi/linux/ntsync.h>
|
||||||
|
|
||||||
|
#define NTSYNC_NAME "ntsync"
|
||||||
|
|
||||||
|
+enum ntsync_type {
|
||||||
|
+ NTSYNC_TYPE_SEM,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+struct ntsync_obj {
|
||||||
|
+ enum ntsync_type type;
|
||||||
|
+
|
||||||
|
+ union {
|
||||||
|
+ struct {
|
||||||
|
+ __u32 count;
|
||||||
|
+ __u32 max;
|
||||||
|
+ } sem;
|
||||||
|
+ } u;
|
||||||
|
+
|
||||||
|
+ struct file *file;
|
||||||
|
+ struct ntsync_device *dev;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+struct ntsync_device {
|
||||||
|
+ struct file *file;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+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..f38818e7759d
|
||||||
|
--- /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
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#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
|
||||||
|
|
|
@ -0,0 +1,145 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 3/29] ntsync: Introduce NTSYNC_IOC_SEM_POST.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:30 -0600
|
||||||
|
Message-Id: <20240131021356.10322-4-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
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 | 68 +++++++++++++++++++++++++++++++++++--
|
||||||
|
include/uapi/linux/ntsync.h | 2 ++
|
||||||
|
2 files changed, 67 insertions(+), 3 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c
|
||||||
|
index 3ad86d98b82d..1af38969f9a2 100644
|
||||||
|
--- a/drivers/misc/ntsync.c
|
||||||
|
+++ b/drivers/misc/ntsync.c
|
||||||
|
@@ -20,23 +20,68 @@ 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)
|
||||||
|
+{
|
||||||
|
+ 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_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;
|
||||||
|
@@ -47,9 +92,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,
|
||||||
|
};
|
||||||
|
|
||||||
|
@@ -64,6 +125,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 f38818e7759d..878ec4f0f2e8 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,31 +1,52 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 4/29] ntsync: Introduce NTSYNC_IOC_WAIT_ANY.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:31 -0600
|
||||||
|
Message-Id: <20240131021356.10322-5-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
This corresponds to part of the functionality of the NT syscall
|
This corresponds to part of the functionality of the NT syscall
|
||||||
NtWaitForMultipleObjects(). Specifically, it implements the behaviour where
|
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.
|
||||||
|
|
||||||
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 | 232 ++++++++++++++++++++++++++++++++++++
|
||||||
include/uapi/linux/ntsync.h | 13 ++
|
include/uapi/linux/ntsync.h | 12 ++
|
||||||
2 files changed, 242 insertions(+)
|
2 files changed, 244 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 1af38969f9a2..0a0ab755d57f 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 {
|
@@ -34,12 +34,55 @@ struct ntsync_obj {
|
||||||
struct kref refcount;
|
__u32 max;
|
||||||
spinlock_t lock;
|
} sem;
|
||||||
|
|
||||||
+ struct list_head any_waiters;
|
|
||||||
+
|
|
||||||
enum ntsync_type type;
|
|
||||||
|
|
||||||
/* The following fields are protected by the object lock. */
|
|
||||||
@@ -34,6 +36,28 @@ struct ntsync_obj {
|
|
||||||
} 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 +67,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,22 +90,58 @@ 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.
|
||||||
|
@@ -73,6 +116,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)
|
@@ -126,6 +171,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;
|
||||||
|
}
|
||||||
|
@@ -176,6 +222,190 @@ static int ntsync_create_sem(struct ntsync_device *dev, void __user *argp)
|
||||||
|
return put_user(fd, &user_args->sem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+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, ktime_t *timeout)
|
+static int ntsync_schedule(const struct ntsync_q *q, ktime_t *timeout)
|
||||||
+{
|
+{
|
||||||
+ int ret = 0;
|
+ int ret = 0;
|
||||||
|
@ -115,16 +166,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 +182,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 +196,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 +206,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;
|
||||||
+}
|
+}
|
||||||
|
@ -210,7 +237,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 +267,8 @@ index d1c91c2a4f1a..2e8d3c2d51a4 100644
|
||||||
+
|
+
|
||||||
+ /* sleep */
|
+ /* sleep */
|
||||||
+
|
+
|
||||||
+ ret = ntsync_schedule(q, args.timeout ? &timeout : NULL);
|
+ timeout = ns_to_ktime(args.timeout);
|
||||||
|
+ ret = ntsync_schedule(q, args.timeout == U64_MAX ? NULL : &timeout);
|
||||||
+
|
+
|
||||||
+ /* and finally, unqueue */
|
+ /* and finally, unqueue */
|
||||||
+
|
+
|
||||||
|
@ -272,23 +300,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);
|
@@ -207,6 +437,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 878ec4f0f2e8..9cd1dd05d971 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 +331,11 @@ 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,29 @@
|
||||||
This corresponds to part of the functionality of the NT syscall
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
NtWaitForMultipleObjects(). Specifically, it implements the behaviour where
|
Subject: [PATCH RFC v2 5/29] ntsync: Introduce NTSYNC_IOC_WAIT_ALL.
|
||||||
the third argument (wait_any) is FALSE, and it does not yet handle alertable
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
waits.
|
Date: Tue, 30 Jan 2024 20:13:32 -0600
|
||||||
|
Message-Id: <20240131021356.10322-6-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
This is similar to NTSYNC_IOC_WAIT_ANY, but waits until all of the objects are
|
||||||
|
simultaneously signaled, and then acquires all of them as a single atomic
|
||||||
|
operation.
|
||||||
|
|
||||||
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 | 244 ++++++++++++++++++++++++++++++++++--
|
||||||
include/uapi/linux/ntsync.h | 2 +
|
include/uapi/linux/ntsync.h | 1 +
|
||||||
2 files changed, 235 insertions(+), 8 deletions(-)
|
2 files changed, 237 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 0a0ab755d57f..b86d62094344 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 {
|
@@ -35,7 +35,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 +41,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 {
|
||||||
|
@@ -56,14 +83,99 @@ struct ntsync_q {
|
||||||
@@ -54,11 +81,25 @@ struct ntsync_q {
|
|
||||||
*/
|
*/
|
||||||
atomic_t signaled;
|
atomic_t signaled;
|
||||||
|
|
||||||
|
@ -60,9 +68,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 +79,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 +151,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;
|
||||||
|
@@ -101,6 +213,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;
|
||||||
|
@@ -112,14 +225,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 +174,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 +191,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;
|
||||||
|
@@ -172,6 +300,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.
|
}
|
||||||
|
@@ -274,7 +404,7 @@ static int ntsync_schedule(const struct ntsync_q *q, ktime_t *timeout)
|
||||||
|
* 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,
|
@@ -298,6 +428,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 +226,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,
|
@@ -307,6 +438,16 @@ static int setup_wait(struct ntsync_device *dev,
|
||||||
if (!obj)
|
if (!obj)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
|
@ -235,16 +243,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)
|
@@ -343,7 +484,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)
|
@@ -406,6 +547,89 @@ static int ntsync_wait_any(struct ntsync_device *dev, void __user *argp)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,7 +268,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 +284,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 +298,8 @@ index 2e8d3c2d51a4..2685363fae9e 100644
|
||||||
+
|
+
|
||||||
+ /* sleep */
|
+ /* sleep */
|
||||||
+
|
+
|
||||||
+ ret = ntsync_schedule(q, args.timeout ? &timeout : NULL);
|
+ timeout = ns_to_ktime(args.timeout);
|
||||||
|
+ ret = ntsync_schedule(q, args.timeout == U64_MAX ? NULL : &timeout);
|
||||||
+
|
+
|
||||||
+ /* and finally, unqueue */
|
+ /* and finally, unqueue */
|
||||||
+
|
+
|
||||||
|
@ -329,29 +339,39 @@ 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);
|
@@ -414,6 +638,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);
|
||||||
|
@@ -437,6 +663,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 9cd1dd05d971..524404f6aceb 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,16 +1,35 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 6/29] ntsync: Introduce NTSYNC_IOC_CREATE_MUTEX.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:33 -0600
|
||||||
|
Message-Id: <20240131021356.10322-7-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
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 b86d62094344..484219a266ae 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 @@
|
@@ -17,6 +17,7 @@
|
||||||
|
|
||||||
enum ntsync_type {
|
enum ntsync_type {
|
||||||
NTSYNC_TYPE_SEM,
|
NTSYNC_TYPE_SEM,
|
||||||
|
@ -18,7 +37,7 @@ index 2685363fae9e..d48f2ef41341 100644
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ntsync_obj {
|
struct ntsync_obj {
|
||||||
@@ -60,6 +61,10 @@ struct ntsync_obj {
|
@@ -33,6 +34,10 @@ struct ntsync_obj {
|
||||||
__u32 count;
|
__u32 count;
|
||||||
__u32 max;
|
__u32 max;
|
||||||
} sem;
|
} sem;
|
||||||
|
@ -27,9 +46,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)
|
/*
|
||||||
|
@@ -112,6 +117,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 +59,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,
|
@@ -154,6 +163,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 +70,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)
|
@@ -195,6 +208,28 @@ static void try_wake_any_sem(struct ntsync_obj *sem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,11 +96,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)
|
@@ -352,6 +387,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 +108,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 +116,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)
|
@@ -469,6 +531,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 +143,7 @@ index 2685363fae9e..d48f2ef41341 100644
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -662,6 +732,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd,
|
@@ -661,6 +726,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 +151,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 524404f6aceb..d68f24fd75a2 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 +169,14 @@ 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
|
||||||
|
|
|
@ -0,0 +1,117 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 7/29] ntsync: Introduce NTSYNC_IOC_MUTEX_UNLOCK.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:34 -0600
|
||||||
|
Message-Id: <20240131021356.10322-8-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
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>
|
||||||
|
---
|
||||||
|
drivers/misc/ntsync.c | 64 +++++++++++++++++++++++++++++++++++++
|
||||||
|
include/uapi/linux/ntsync.h | 1 +
|
||||||
|
2 files changed, 65 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c
|
||||||
|
index 484219a266ae..1770ec4008af 100644
|
||||||
|
--- a/drivers/misc/ntsync.c
|
||||||
|
+++ b/drivers/misc/ntsync.c
|
||||||
|
@@ -290,6 +290,68 @@ static int ntsync_sem_post(struct ntsync_obj *sem, void __user *argp)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
+/*
|
||||||
|
+ * Actually change the mutex state, returning -EPERM if not the owner.
|
||||||
|
+ */
|
||||||
|
+static int unlock_mutex_state(struct ntsync_obj *mutex,
|
||||||
|
+ const struct ntsync_mutex_args *args)
|
||||||
|
+{
|
||||||
|
+ lockdep_assert_held(&mutex->lock);
|
||||||
|
+
|
||||||
|
+ if (mutex->u.mutex.owner != args->owner)
|
||||||
|
+ return -EPERM;
|
||||||
|
+
|
||||||
|
+ if (!--mutex->u.mutex.count)
|
||||||
|
+ mutex->u.mutex.owner = 0;
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int ntsync_mutex_unlock(struct ntsync_obj *mutex, void __user *argp)
|
||||||
|
+{
|
||||||
|
+ struct ntsync_mutex_args __user *user_args = argp;
|
||||||
|
+ struct ntsync_device *dev = mutex->dev;
|
||||||
|
+ struct ntsync_mutex_args args;
|
||||||
|
+ __u32 prev_count;
|
||||||
|
+ int ret;
|
||||||
|
+
|
||||||
|
+ if (copy_from_user(&args, argp, sizeof(args)))
|
||||||
|
+ return -EFAULT;
|
||||||
|
+ if (!args.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);
|
||||||
|
+
|
||||||
|
+ prev_count = mutex->u.mutex.count;
|
||||||
|
+ ret = unlock_mutex_state(mutex, &args);
|
||||||
|
+ 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);
|
||||||
|
+
|
||||||
|
+ prev_count = mutex->u.mutex.count;
|
||||||
|
+ ret = unlock_mutex_state(mutex, &args);
|
||||||
|
+ if (!ret)
|
||||||
|
+ try_wake_any_mutex(mutex);
|
||||||
|
+
|
||||||
|
+ spin_unlock(&mutex->lock);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (!ret && put_user(prev_count, &user_args->count))
|
||||||
|
+ ret = -EFAULT;
|
||||||
|
+
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static int ntsync_obj_release(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
struct ntsync_obj *obj = file->private_data;
|
||||||
|
@@ -309,6 +371,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_MUTEX_UNLOCK:
|
||||||
|
+ return ntsync_mutex_unlock(obj, argp);
|
||||||
|
default:
|
||||||
|
return -ENOIOCTLCMD;
|
||||||
|
}
|
||||||
|
diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h
|
||||||
|
index d68f24fd75a2..a3f5f4f13798 100644
|
||||||
|
--- a/include/uapi/linux/ntsync.h
|
||||||
|
+++ b/include/uapi/linux/ntsync.h
|
||||||
|
@@ -39,5 +39,6 @@ struct ntsync_wait_args {
|
||||||
|
#define NTSYNC_IOC_CREATE_MUTEX _IOWR('N', 0x84, struct ntsync_sem_args)
|
||||||
|
|
||||||
|
#define NTSYNC_IOC_SEM_POST _IOWR('N', 0x81, __u32)
|
||||||
|
+#define NTSYNC_IOC_MUTEX_UNLOCK _IOWR('N', 0x85, struct ntsync_mutex_args)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
--
|
||||||
|
2.43.0
|
||||||
|
|
|
@ -0,0 +1,176 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 8/29] ntsync: Introduce NTSYNC_IOC_MUTEX_KILL.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:35 -0600
|
||||||
|
Message-Id: <20240131021356.10322-9-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
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 1770ec4008af..aadf01c65ca0 100644
|
||||||
|
--- a/drivers/misc/ntsync.c
|
||||||
|
+++ b/drivers/misc/ntsync.c
|
||||||
|
@@ -37,6 +37,7 @@ struct ntsync_obj {
|
||||||
|
struct {
|
||||||
|
__u32 count;
|
||||||
|
__u32 owner;
|
||||||
|
+ bool ownerdead;
|
||||||
|
} mutex;
|
||||||
|
} u;
|
||||||
|
|
||||||
|
@@ -89,6 +90,7 @@ struct ntsync_q {
|
||||||
|
atomic_t signaled;
|
||||||
|
|
||||||
|
bool all;
|
||||||
|
+ bool ownerdead;
|
||||||
|
__u32 count;
|
||||||
|
struct ntsync_q_entry entries[];
|
||||||
|
};
|
||||||
|
@@ -164,6 +166,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;
|
||||||
|
@@ -223,6 +228,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);
|
||||||
|
@@ -352,6 +360,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;
|
||||||
|
@@ -373,6 +437,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;
|
||||||
|
}
|
||||||
|
@@ -555,6 +621,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++) {
|
||||||
|
@@ -664,7 +731,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;
|
||||||
|
@@ -747,7 +814,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 a3f5f4f13798..3861397c6c2f 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
|
||||||
|
|
|
@ -0,0 +1,175 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 9/29] ntsync: Introduce NTSYNC_IOC_CREATE_EVENT.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:36 -0600
|
||||||
|
Message-Id: <20240131021356.10322-10-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
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 aadf01c65ca0..c719ddd9f6d7 100644
|
||||||
|
--- a/drivers/misc/ntsync.c
|
||||||
|
+++ b/drivers/misc/ntsync.c
|
||||||
|
@@ -18,6 +18,7 @@
|
||||||
|
enum ntsync_type {
|
||||||
|
NTSYNC_TYPE_SEM,
|
||||||
|
NTSYNC_TYPE_MUTEX,
|
||||||
|
+ NTSYNC_TYPE_EVENT,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ntsync_obj {
|
||||||
|
@@ -39,6 +40,10 @@ struct ntsync_obj {
|
||||||
|
__u32 owner;
|
||||||
|
bool ownerdead;
|
||||||
|
} mutex;
|
||||||
|
+ struct {
|
||||||
|
+ bool manual;
|
||||||
|
+ bool signaled;
|
||||||
|
+ } event;
|
||||||
|
} u;
|
||||||
|
|
||||||
|
/*
|
||||||
|
@@ -123,6 +128,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);
|
||||||
|
@@ -172,6 +179,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);
|
||||||
|
@@ -238,6 +249,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.
|
||||||
|
@@ -544,6 +575,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);
|
||||||
|
@@ -665,6 +720,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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -857,6 +915,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 3861397c6c2f..b8cf503365ef 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,88 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 10/29] ntsync: Introduce NTSYNC_IOC_EVENT_SET.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:37 -0600
|
||||||
|
Message-Id: <20240131021356.10322-11-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
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 c719ddd9f6d7..b2da50989953 100644
|
||||||
|
--- a/drivers/misc/ntsync.c
|
||||||
|
+++ b/drivers/misc/ntsync.c
|
||||||
|
@@ -447,6 +447,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;
|
||||||
|
@@ -470,6 +505,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 b8cf503365ef..782057552483 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,73 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 11/29] ntsync: Introduce NTSYNC_IOC_EVENT_RESET.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:38 -0600
|
||||||
|
Message-Id: <20240131021356.10322-12-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
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 b2da50989953..009d927739b8 100644
|
||||||
|
--- a/drivers/misc/ntsync.c
|
||||||
|
+++ b/drivers/misc/ntsync.c
|
||||||
|
@@ -482,6 +482,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;
|
||||||
|
@@ -507,6 +527,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 782057552483..f2d7507d8438 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,80 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 12/29] ntsync: Introduce NTSYNC_IOC_EVENT_PULSE.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:39 -0600
|
||||||
|
Message-Id: <20240131021356.10322-13-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
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 009d927739b8..240ae858fa96 100644
|
||||||
|
--- a/drivers/misc/ntsync.c
|
||||||
|
+++ b/drivers/misc/ntsync.c
|
||||||
|
@@ -447,7 +447,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;
|
||||||
|
@@ -463,6 +463,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);
|
||||||
|
@@ -472,6 +474,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);
|
||||||
|
}
|
||||||
|
@@ -526,9 +530,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 f2d7507d8438..598f894f868d 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,72 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 13/29] ntsync: Introduce NTSYNC_IOC_SEM_READ.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:40 -0600
|
||||||
|
Message-Id: <20240131021356.10322-14-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
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 240ae858fa96..6dccfbfb2512 100644
|
||||||
|
--- a/drivers/misc/ntsync.c
|
||||||
|
+++ b/drivers/misc/ntsync.c
|
||||||
|
@@ -506,6 +506,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;
|
||||||
|
@@ -525,6 +544,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 598f894f868d..6017f621687e 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,74 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 14/29] ntsync: Introduce NTSYNC_IOC_MUTEX_READ.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:41 -0600
|
||||||
|
Message-Id: <20240131021356.10322-15-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
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 6dccfbfb2512..7f5f96ec7c69 100644
|
||||||
|
--- a/drivers/misc/ntsync.c
|
||||||
|
+++ b/drivers/misc/ntsync.c
|
||||||
|
@@ -525,6 +525,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;
|
||||||
|
@@ -550,6 +571,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 6017f621687e..a1d0ef581212 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,72 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 15/29] ntsync: Introduce NTSYNC_IOC_EVENT_READ.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:42 -0600
|
||||||
|
Message-Id: <20240131021356.10322-16-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
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 7f5f96ec7c69..5439c1c9e90f 100644
|
||||||
|
--- a/drivers/misc/ntsync.c
|
||||||
|
+++ b/drivers/misc/ntsync.c
|
||||||
|
@@ -546,6 +546,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;
|
||||||
|
@@ -579,6 +598,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 a1d0ef581212..582d33b0dcac 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,194 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 16/29] ntsync: Introduce alertable waits.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:43 -0600
|
||||||
|
Message-Id: <20240131021356.10322-17-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
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 5439c1c9e90f..1e619e1ce6a6 100644
|
||||||
|
--- a/drivers/misc/ntsync.c
|
||||||
|
+++ b/drivers/misc/ntsync.c
|
||||||
|
@@ -784,22 +784,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;
|
||||||
|
@@ -809,7 +816,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]);
|
||||||
|
|
||||||
|
@@ -860,9 +867,9 @@ static int ntsync_wait_any(struct ntsync_device *dev, void __user *argp)
|
||||||
|
{
|
||||||
|
struct ntsync_wait_args args;
|
||||||
|
struct ntsync_q *q;
|
||||||
|
+ __u32 i, total_count;
|
||||||
|
ktime_t timeout;
|
||||||
|
int signaled;
|
||||||
|
- __u32 i;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (copy_from_user(&args, argp, sizeof(args)))
|
||||||
|
@@ -872,9 +879,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;
|
||||||
|
|
||||||
|
@@ -883,9 +894,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)
|
||||||
|
@@ -903,7 +920,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;
|
||||||
|
|
||||||
|
@@ -964,6 +981,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 */
|
||||||
|
|
||||||
|
@@ -971,6 +996,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 */
|
||||||
|
|
||||||
|
timeout = ns_to_ktime(args.timeout);
|
||||||
|
@@ -994,6 +1034,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 582d33b0dcac..7c91af7011e4 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,213 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 17/29] selftests: ntsync: Add some tests for
|
||||||
|
semaphore state.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:44 -0600
|
||||||
|
Message-Id: <20240131021356.10322-18-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
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 | 143 ++++++++++++++++++
|
||||||
|
4 files changed, 153 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..6ceb48fb42e3
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
@@ -0,0 +1,143 @@
|
||||||
|
+// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
+/*
|
||||||
|
+ * Various unit tests for the "ntsync" synchronization primitive driver.
|
||||||
|
+ *
|
||||||
|
+ * Copyright (C) 2021-2022 Elizabeth Figura
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#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);
|
||||||
|
+
|
||||||
|
+ close(sem);
|
||||||
|
+
|
||||||
|
+ close(fd);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+TEST_HARNESS_MAIN
|
||||||
|
--
|
||||||
|
2.43.0
|
||||||
|
|
|
@ -0,0 +1,218 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 18/29] selftests: ntsync: Add some tests for mutex
|
||||||
|
state.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:45 -0600
|
||||||
|
Message-Id: <20240131021356.10322-19-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
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 | 181 ++++++++++++++++++
|
||||||
|
1 file changed, 181 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
index 6ceb48fb42e3..80c8bd409d68 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};
|
||||||
|
@@ -140,4 +173,152 @@ 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);
|
||||||
|
+
|
||||||
|
+ close(fd);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
TEST_HARNESS_MAIN
|
||||||
|
--
|
||||||
|
2.43.0
|
||||||
|
|
|
@ -0,0 +1,136 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 19/29] selftests: ntsync: Add some tests for
|
||||||
|
NTSYNC_IOC_WAIT_ANY.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:46 -0600
|
||||||
|
Message-Id: <20240131021356.10322-20-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
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 | 105 ++++++++++++++++++
|
||||||
|
1 file changed, 105 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
index 80c8bd409d68..13e7c9d7441e 100644
|
||||||
|
--- a/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
+++ b/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
@@ -321,4 +321,109 @@ TEST(mutex_state)
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
+TEST(test_wait_any)
|
||||||
|
+{
|
||||||
|
+ struct ntsync_mutex_args mutex_args = {0};
|
||||||
|
+ struct ntsync_wait_args wait_args = {0};
|
||||||
|
+ struct ntsync_sem_args sem_args = {0};
|
||||||
|
+ __u32 owner, index, count;
|
||||||
|
+ struct timespec timeout;
|
||||||
|
+ int objs[2], fd, ret;
|
||||||
|
+
|
||||||
|
+ 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, wait_args.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);
|
||||||
|
+
|
||||||
|
+ close(sem_args.sem);
|
||||||
|
+ close(mutex_args.mutex);
|
||||||
|
+
|
||||||
|
+ close(fd);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
TEST_HARNESS_MAIN
|
||||||
|
--
|
||||||
|
2.43.0
|
||||||
|
|
|
@ -0,0 +1,147 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 20/29] selftests: ntsync: Add some tests for
|
||||||
|
NTSYNC_IOC_WAIT_ALL.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:47 -0600
|
||||||
|
Message-Id: <20240131021356.10322-21-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
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 13e7c9d7441e..77f1b7e42d76 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;
|
||||||
|
@@ -426,4 +437,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,182 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 21/29] selftests: ntsync: Add some tests for wakeup
|
||||||
|
signaling with WINESYNC_IOC_WAIT_ANY.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:48 -0600
|
||||||
|
Message-Id: <20240131021356.10322-22-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
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 | 152 ++++++++++++++++++
|
||||||
|
1 file changed, 152 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
index 77f1b7e42d76..96a866ef235f 100644
|
||||||
|
--- a/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
+++ b/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
@@ -521,4 +521,156 @@ 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,129 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 22/29] selftests: ntsync: Add some tests for wakeup
|
||||||
|
signaling with WINESYNC_IOC_WAIT_ALL.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:49 -0600
|
||||||
|
Message-Id: <20240131021356.10322-23-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
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 96a866ef235f..7776fe71b8ef 100644
|
||||||
|
--- a/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
+++ b/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
@@ -673,4 +673,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,129 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 23/29] selftests: ntsync: Add some tests for
|
||||||
|
manual-reset event state.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:50 -0600
|
||||||
|
Message-Id: <20240131021356.10322-24-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
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 7776fe71b8ef..98fc70a9a58b 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)
|
||||||
|
{
|
||||||
|
@@ -332,6 +353,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)
|
||||||
|
{
|
||||||
|
struct ntsync_mutex_args mutex_args = {0};
|
||||||
|
--
|
||||||
|
2.43.0
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 24/29] selftests: ntsync: Add some tests for
|
||||||
|
auto-reset event state.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:51 -0600
|
||||||
|
Message-Id: <20240131021356.10322-25-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
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 98fc70a9a58b..f1fb28949367 100644
|
||||||
|
--- a/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
+++ b/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
@@ -421,6 +421,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)
|
||||||
|
{
|
||||||
|
struct ntsync_mutex_args mutex_args = {0};
|
||||||
|
--
|
||||||
|
2.43.0
|
||||||
|
|
|
@ -0,0 +1,270 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 25/29] selftests: ntsync: Add some tests for wakeup
|
||||||
|
signaling with events.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:52 -0600
|
||||||
|
Message-Id: <20240131021356.10322-26-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
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 f1fb28949367..598333df3e6d 100644
|
||||||
|
--- a/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
+++ b/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
@@ -587,6 +587,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;
|
||||||
|
@@ -609,6 +610,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;
|
||||||
|
|
||||||
|
@@ -657,6 +663,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);
|
||||||
|
@@ -665,6 +679,7 @@ TEST(test_wait_all)
|
||||||
|
|
||||||
|
close(sem_args.sem);
|
||||||
|
close(mutex_args.mutex);
|
||||||
|
+ close(event_args.event);
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
@@ -713,12 +728,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);
|
||||||
|
@@ -800,10 +816,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);
|
||||||
|
|
||||||
|
@@ -823,12 +930,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);
|
||||||
|
@@ -848,12 +957,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;
|
||||||
|
@@ -887,12 +1008,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);
|
||||||
|
@@ -910,6 +1051,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,234 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 26/29] selftests: ntsync: Add tests for alertable
|
||||||
|
waits.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:53 -0600
|
||||||
|
Message-Id: <20240131021356.10322-27-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
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 598333df3e6d..6c00a55909aa 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)
|
||||||
|
@@ -1062,4 +1077,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,121 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 27/29] selftests: ntsync: Add some tests for wakeup
|
||||||
|
signaling via alerts.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:54 -0600
|
||||||
|
Message-Id: <20240131021356.10322-28-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
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 6c00a55909aa..09153d0686ac 100644
|
||||||
|
--- a/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
+++ b/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
@@ -1080,9 +1080,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);
|
||||||
|
@@ -1130,6 +1133,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 */
|
||||||
|
@@ -1166,9 +1197,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);
|
||||||
|
@@ -1202,6 +1236,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,39 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 28/29] maintainers: Add an entry for ntsync.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:55 -0600
|
||||||
|
Message-Id: <20240131021356.10322-29-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
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 8d1052fa6a69..7924127d351b 100644
|
||||||
|
--- a/MAINTAINERS
|
||||||
|
+++ b/MAINTAINERS
|
||||||
|
@@ -15585,6 +15585,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
|
||||||
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -1,107 +0,0 @@
|
||||||
This corresponds to the NT syscall NtReleaseMutant().
|
|
||||||
|
|
||||||
Signed-off-by: Elizabeth Figura <zfigura@codeweavers.com>
|
|
||||||
---
|
|
||||||
drivers/misc/ntsync.c | 67 +++++++++++++++++++++++++++++++++++++
|
|
||||||
include/uapi/linux/ntsync.h | 2 ++
|
|
||||||
2 files changed, 69 insertions(+)
|
|
||||||
|
|
||||||
diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c
|
|
||||||
index d48f2ef41341..28f43768d1c3 100644
|
|
||||||
--- a/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)
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
+/*
|
|
||||||
+ * Actually change the mutex state, returning -EPERM if not the owner.
|
|
||||||
+ */
|
|
||||||
+static int put_mutex_state(struct ntsync_obj *mutex,
|
|
||||||
+ const struct ntsync_mutex_args *args)
|
|
||||||
+{
|
|
||||||
+ lockdep_assert_held(&mutex->lock);
|
|
||||||
+
|
|
||||||
+ if (mutex->u.mutex.owner != args->owner)
|
|
||||||
+ return -EPERM;
|
|
||||||
+
|
|
||||||
+ if (!--mutex->u.mutex.count)
|
|
||||||
+ mutex->u.mutex.owner = 0;
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int ntsync_put_mutex(struct ntsync_device *dev, void __user *argp)
|
|
||||||
+{
|
|
||||||
+ struct ntsync_mutex_args __user *user_args = argp;
|
|
||||||
+ struct ntsync_mutex_args args;
|
|
||||||
+ struct ntsync_obj *mutex;
|
|
||||||
+ __u32 prev_count;
|
|
||||||
+ int ret;
|
|
||||||
+
|
|
||||||
+ if (copy_from_user(&args, argp, sizeof(args)))
|
|
||||||
+ return -EFAULT;
|
|
||||||
+ if (!args.owner)
|
|
||||||
+ return -EINVAL;
|
|
||||||
+
|
|
||||||
+ mutex = get_obj_typed(dev, args.mutex, NTSYNC_TYPE_MUTEX);
|
|
||||||
+ if (!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);
|
|
||||||
+
|
|
||||||
+ prev_count = mutex->u.mutex.count;
|
|
||||||
+ ret = put_mutex_state(mutex, &args);
|
|
||||||
+ 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);
|
|
||||||
+
|
|
||||||
+ prev_count = mutex->u.mutex.count;
|
|
||||||
+ ret = put_mutex_state(mutex, &args);
|
|
||||||
+ if (!ret)
|
|
||||||
+ try_wake_any_mutex(mutex);
|
|
||||||
+
|
|
||||||
+ spin_unlock(&mutex->lock);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ put_obj(mutex);
|
|
||||||
+
|
|
||||||
+ if (!ret && put_user(prev_count, &user_args->count))
|
|
||||||
+ ret = -EFAULT;
|
|
||||||
+
|
|
||||||
+ return ret;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
static int ntsync_schedule(const struct ntsync_q *q, ktime_t *timeout)
|
|
||||||
{
|
|
||||||
int ret = 0;
|
|
||||||
@@ -738,6 +803,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_MUTEX:
|
|
||||||
+ return ntsync_put_mutex(dev, argp);
|
|
||||||
case NTSYNC_IOC_PUT_SEM:
|
|
||||||
return ntsync_put_sem(dev, argp);
|
|
||||||
case NTSYNC_IOC_WAIT_ALL:
|
|
||||||
diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h
|
|
||||||
index 26d1b3d4847f..2e44e7e77776 100644
|
|
||||||
--- a/include/uapi/linux/ntsync.h
|
|
||||||
+++ b/include/uapi/linux/ntsync.h
|
|
||||||
@@ -46,5 +46,7 @@ struct ntsync_wait_args {
|
|
||||||
struct ntsync_wait_args)
|
|
||||||
#define NTSYNC_IOC_CREATE_MUTEX _IOWR(NTSYNC_IOC_BASE, 5, \
|
|
||||||
struct ntsync_mutex_args)
|
|
||||||
+#define NTSYNC_IOC_PUT_MUTEX _IOWR(NTSYNC_IOC_BASE, 6, \
|
|
||||||
+ struct ntsync_mutex_args)
|
|
||||||
|
|
||||||
#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
|
|
|
@ -1,3 +1,13 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 1/29] ntsync: Introduce the ntsync driver and
|
||||||
|
character device.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:28 -0600
|
||||||
|
Message-Id: <20240131021356.10322-2-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
ntsync uses a misc device as the simplest and least intrusive uAPI interface.
|
ntsync uses a misc device as the simplest and least intrusive uAPI interface.
|
||||||
|
|
||||||
Each file description on the device represents an isolated NT instance, intended
|
Each file description on the device represents an isolated NT instance, intended
|
||||||
|
@ -7,8 +17,8 @@ Signed-off-by: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
---
|
---
|
||||||
drivers/misc/Kconfig | 9 ++++++++
|
drivers/misc/Kconfig | 9 ++++++++
|
||||||
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, 62 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
|
||||||
|
@ -45,15 +55,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..e4969ef90722
|
||||||
--- /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
|
||||||
+ */
|
+ */
|
||||||
+
|
+
|
||||||
+#include <linux/fs.h>
|
+#include <linux/fs.h>
|
||||||
|
@ -86,7 +96,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,
|
||||||
+};
|
+};
|
||||||
+
|
+
|
||||||
|
@ -101,6 +111,6 @@ index 000000000000..9424c6210e51
|
||||||
+MODULE_AUTHOR("Elizabeth Figura");
|
+MODULE_AUTHOR("Elizabeth Figura");
|
||||||
+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
|
||||||
|
|
|
@ -0,0 +1,224 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 2/29] ntsync: Introduce NTSYNC_IOC_CREATE_SEM.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:29 -0600
|
||||||
|
Message-Id: <20240131021356.10322-3-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
This corresponds to the NT syscall NtCreateSemaphore().
|
||||||
|
|
||||||
|
Semaphores are one of three types of object to be implemented in this driver,
|
||||||
|
the others being mutexes and events.
|
||||||
|
|
||||||
|
An NT semaphore contains a 32-bit counter, and is signaled and can be acquired
|
||||||
|
when the counter is nonzero. The counter has a maximum value which is specified
|
||||||
|
at creation time. The initial value of the semaphore is also specified at
|
||||||
|
creation time. There are no restrictions on the maximum and initial value.
|
||||||
|
|
||||||
|
Each object is exposed as an file, to which any number of fds may be opened.
|
||||||
|
When all fds are closed, the object is deleted.
|
||||||
|
|
||||||
|
Signed-off-by: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
---
|
||||||
|
.../userspace-api/ioctl/ioctl-number.rst | 2 +
|
||||||
|
drivers/misc/ntsync.c | 120 ++++++++++++++++++
|
||||||
|
include/uapi/linux/ntsync.h | 21 +++
|
||||||
|
3 files changed, 143 insertions(+)
|
||||||
|
create mode 100644 include/uapi/linux/ntsync.h
|
||||||
|
|
||||||
|
diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst
|
||||||
|
index 457e16f06e04..2f5c6994f042 100644
|
||||||
|
--- a/Documentation/userspace-api/ioctl/ioctl-number.rst
|
||||||
|
+++ b/Documentation/userspace-api/ioctl/ioctl-number.rst
|
||||||
|
@@ -173,6 +173,8 @@ Code Seq# Include File Comments
|
||||||
|
'M' 00-0F drivers/video/fsl-diu-fb.h conflict!
|
||||||
|
'N' 00-1F drivers/usb/scanner.h
|
||||||
|
'N' 40-7F drivers/block/nvme.c
|
||||||
|
+'N' 80-8F uapi/linux/ntsync.h NT synchronization primitives
|
||||||
|
+ <mailto: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 e4969ef90722..3ad86d98b82d 100644
|
||||||
|
--- a/drivers/misc/ntsync.c
|
||||||
|
+++ b/drivers/misc/ntsync.c
|
||||||
|
@@ -5,26 +5,146 @@
|
||||||
|
* Copyright (C) 2024 Elizabeth Figura
|
||||||
|
*/
|
||||||
|
|
||||||
|
+#include <linux/anon_inodes.h>
|
||||||
|
+#include <linux/file.h>
|
||||||
|
#include <linux/fs.h>
|
||||||
|
#include <linux/miscdevice.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
+#include <linux/slab.h>
|
||||||
|
+#include <uapi/linux/ntsync.h>
|
||||||
|
|
||||||
|
#define NTSYNC_NAME "ntsync"
|
||||||
|
|
||||||
|
+enum ntsync_type {
|
||||||
|
+ NTSYNC_TYPE_SEM,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+struct ntsync_obj {
|
||||||
|
+ enum ntsync_type type;
|
||||||
|
+
|
||||||
|
+ union {
|
||||||
|
+ struct {
|
||||||
|
+ __u32 count;
|
||||||
|
+ __u32 max;
|
||||||
|
+ } sem;
|
||||||
|
+ } u;
|
||||||
|
+
|
||||||
|
+ struct file *file;
|
||||||
|
+ struct ntsync_device *dev;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+struct ntsync_device {
|
||||||
|
+ struct file *file;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+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..f38818e7759d
|
||||||
|
--- /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
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#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
|
||||||
|
|
|
@ -0,0 +1,145 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 3/29] ntsync: Introduce NTSYNC_IOC_SEM_POST.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:30 -0600
|
||||||
|
Message-Id: <20240131021356.10322-4-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
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 | 68 +++++++++++++++++++++++++++++++++++--
|
||||||
|
include/uapi/linux/ntsync.h | 2 ++
|
||||||
|
2 files changed, 67 insertions(+), 3 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c
|
||||||
|
index 3ad86d98b82d..1af38969f9a2 100644
|
||||||
|
--- a/drivers/misc/ntsync.c
|
||||||
|
+++ b/drivers/misc/ntsync.c
|
||||||
|
@@ -20,23 +20,68 @@ 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)
|
||||||
|
+{
|
||||||
|
+ 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_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;
|
||||||
|
@@ -47,9 +92,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,
|
||||||
|
};
|
||||||
|
|
||||||
|
@@ -64,6 +125,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 f38818e7759d..878ec4f0f2e8 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,31 +1,52 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 4/29] ntsync: Introduce NTSYNC_IOC_WAIT_ANY.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:31 -0600
|
||||||
|
Message-Id: <20240131021356.10322-5-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
This corresponds to part of the functionality of the NT syscall
|
This corresponds to part of the functionality of the NT syscall
|
||||||
NtWaitForMultipleObjects(). Specifically, it implements the behaviour where
|
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.
|
||||||
|
|
||||||
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 | 232 ++++++++++++++++++++++++++++++++++++
|
||||||
include/uapi/linux/ntsync.h | 13 ++
|
include/uapi/linux/ntsync.h | 12 ++
|
||||||
2 files changed, 242 insertions(+)
|
2 files changed, 244 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 1af38969f9a2..0a0ab755d57f 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 {
|
@@ -34,12 +34,55 @@ struct ntsync_obj {
|
||||||
struct kref refcount;
|
__u32 max;
|
||||||
spinlock_t lock;
|
} sem;
|
||||||
|
|
||||||
+ struct list_head any_waiters;
|
|
||||||
+
|
|
||||||
enum ntsync_type type;
|
|
||||||
|
|
||||||
/* The following fields are protected by the object lock. */
|
|
||||||
@@ -34,6 +36,28 @@ struct ntsync_obj {
|
|
||||||
} 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 +67,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,22 +90,58 @@ 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.
|
||||||
|
@@ -73,6 +116,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)
|
@@ -126,6 +171,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;
|
||||||
|
}
|
||||||
|
@@ -176,6 +222,190 @@ static int ntsync_create_sem(struct ntsync_device *dev, void __user *argp)
|
||||||
|
return put_user(fd, &user_args->sem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+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, ktime_t *timeout)
|
+static int ntsync_schedule(const struct ntsync_q *q, ktime_t *timeout)
|
||||||
+{
|
+{
|
||||||
+ int ret = 0;
|
+ int ret = 0;
|
||||||
|
@ -115,16 +166,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 +182,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 +196,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 +206,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;
|
||||||
+}
|
+}
|
||||||
|
@ -210,7 +237,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 +267,8 @@ index d1c91c2a4f1a..2e8d3c2d51a4 100644
|
||||||
+
|
+
|
||||||
+ /* sleep */
|
+ /* sleep */
|
||||||
+
|
+
|
||||||
+ ret = ntsync_schedule(q, args.timeout ? &timeout : NULL);
|
+ timeout = ns_to_ktime(args.timeout);
|
||||||
|
+ ret = ntsync_schedule(q, args.timeout == U64_MAX ? NULL : &timeout);
|
||||||
+
|
+
|
||||||
+ /* and finally, unqueue */
|
+ /* and finally, unqueue */
|
||||||
+
|
+
|
||||||
|
@ -272,23 +300,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);
|
@@ -207,6 +437,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 878ec4f0f2e8..9cd1dd05d971 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 +331,11 @@ 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,29 @@
|
||||||
This corresponds to part of the functionality of the NT syscall
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
NtWaitForMultipleObjects(). Specifically, it implements the behaviour where
|
Subject: [PATCH RFC v2 5/29] ntsync: Introduce NTSYNC_IOC_WAIT_ALL.
|
||||||
the third argument (wait_any) is FALSE, and it does not yet handle alertable
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
waits.
|
Date: Tue, 30 Jan 2024 20:13:32 -0600
|
||||||
|
Message-Id: <20240131021356.10322-6-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
This is similar to NTSYNC_IOC_WAIT_ANY, but waits until all of the objects are
|
||||||
|
simultaneously signaled, and then acquires all of them as a single atomic
|
||||||
|
operation.
|
||||||
|
|
||||||
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 | 244 ++++++++++++++++++++++++++++++++++--
|
||||||
include/uapi/linux/ntsync.h | 2 +
|
include/uapi/linux/ntsync.h | 1 +
|
||||||
2 files changed, 235 insertions(+), 8 deletions(-)
|
2 files changed, 237 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 0a0ab755d57f..b86d62094344 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 {
|
@@ -35,7 +35,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 +41,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 {
|
||||||
|
@@ -56,14 +83,99 @@ struct ntsync_q {
|
||||||
@@ -54,11 +81,25 @@ struct ntsync_q {
|
|
||||||
*/
|
*/
|
||||||
atomic_t signaled;
|
atomic_t signaled;
|
||||||
|
|
||||||
|
@ -60,9 +68,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 +79,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 +151,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;
|
||||||
|
@@ -101,6 +213,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;
|
||||||
|
@@ -112,14 +225,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 +174,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 +191,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;
|
||||||
|
@@ -172,6 +300,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.
|
}
|
||||||
|
@@ -274,7 +404,7 @@ static int ntsync_schedule(const struct ntsync_q *q, ktime_t *timeout)
|
||||||
|
* 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,
|
@@ -298,6 +428,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 +226,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,
|
@@ -307,6 +438,16 @@ static int setup_wait(struct ntsync_device *dev,
|
||||||
if (!obj)
|
if (!obj)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
|
@ -235,16 +243,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)
|
@@ -343,7 +484,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)
|
@@ -406,6 +547,89 @@ static int ntsync_wait_any(struct ntsync_device *dev, void __user *argp)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,7 +268,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 +284,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 +298,8 @@ index 2e8d3c2d51a4..2685363fae9e 100644
|
||||||
+
|
+
|
||||||
+ /* sleep */
|
+ /* sleep */
|
||||||
+
|
+
|
||||||
+ ret = ntsync_schedule(q, args.timeout ? &timeout : NULL);
|
+ timeout = ns_to_ktime(args.timeout);
|
||||||
|
+ ret = ntsync_schedule(q, args.timeout == U64_MAX ? NULL : &timeout);
|
||||||
+
|
+
|
||||||
+ /* and finally, unqueue */
|
+ /* and finally, unqueue */
|
||||||
+
|
+
|
||||||
|
@ -329,29 +339,39 @@ 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);
|
@@ -414,6 +638,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);
|
||||||
|
@@ -437,6 +663,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 9cd1dd05d971..524404f6aceb 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,16 +1,35 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 6/29] ntsync: Introduce NTSYNC_IOC_CREATE_MUTEX.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:33 -0600
|
||||||
|
Message-Id: <20240131021356.10322-7-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
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 b86d62094344..484219a266ae 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 @@
|
@@ -17,6 +17,7 @@
|
||||||
|
|
||||||
enum ntsync_type {
|
enum ntsync_type {
|
||||||
NTSYNC_TYPE_SEM,
|
NTSYNC_TYPE_SEM,
|
||||||
|
@ -18,7 +37,7 @@ index 2685363fae9e..d48f2ef41341 100644
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ntsync_obj {
|
struct ntsync_obj {
|
||||||
@@ -60,6 +61,10 @@ struct ntsync_obj {
|
@@ -33,6 +34,10 @@ struct ntsync_obj {
|
||||||
__u32 count;
|
__u32 count;
|
||||||
__u32 max;
|
__u32 max;
|
||||||
} sem;
|
} sem;
|
||||||
|
@ -27,9 +46,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)
|
/*
|
||||||
|
@@ -112,6 +117,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 +59,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,
|
@@ -154,6 +163,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 +70,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)
|
@@ -195,6 +208,28 @@ static void try_wake_any_sem(struct ntsync_obj *sem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,11 +96,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)
|
@@ -352,6 +387,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 +108,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 +116,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)
|
@@ -469,6 +531,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 +143,7 @@ index 2685363fae9e..d48f2ef41341 100644
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -662,6 +732,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd,
|
@@ -661,6 +726,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 +151,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 524404f6aceb..d68f24fd75a2 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 +169,14 @@ 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
|
||||||
|
|
|
@ -0,0 +1,117 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 7/29] ntsync: Introduce NTSYNC_IOC_MUTEX_UNLOCK.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:34 -0600
|
||||||
|
Message-Id: <20240131021356.10322-8-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
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>
|
||||||
|
---
|
||||||
|
drivers/misc/ntsync.c | 64 +++++++++++++++++++++++++++++++++++++
|
||||||
|
include/uapi/linux/ntsync.h | 1 +
|
||||||
|
2 files changed, 65 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c
|
||||||
|
index 484219a266ae..1770ec4008af 100644
|
||||||
|
--- a/drivers/misc/ntsync.c
|
||||||
|
+++ b/drivers/misc/ntsync.c
|
||||||
|
@@ -290,6 +290,68 @@ static int ntsync_sem_post(struct ntsync_obj *sem, void __user *argp)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
+/*
|
||||||
|
+ * Actually change the mutex state, returning -EPERM if not the owner.
|
||||||
|
+ */
|
||||||
|
+static int unlock_mutex_state(struct ntsync_obj *mutex,
|
||||||
|
+ const struct ntsync_mutex_args *args)
|
||||||
|
+{
|
||||||
|
+ lockdep_assert_held(&mutex->lock);
|
||||||
|
+
|
||||||
|
+ if (mutex->u.mutex.owner != args->owner)
|
||||||
|
+ return -EPERM;
|
||||||
|
+
|
||||||
|
+ if (!--mutex->u.mutex.count)
|
||||||
|
+ mutex->u.mutex.owner = 0;
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int ntsync_mutex_unlock(struct ntsync_obj *mutex, void __user *argp)
|
||||||
|
+{
|
||||||
|
+ struct ntsync_mutex_args __user *user_args = argp;
|
||||||
|
+ struct ntsync_device *dev = mutex->dev;
|
||||||
|
+ struct ntsync_mutex_args args;
|
||||||
|
+ __u32 prev_count;
|
||||||
|
+ int ret;
|
||||||
|
+
|
||||||
|
+ if (copy_from_user(&args, argp, sizeof(args)))
|
||||||
|
+ return -EFAULT;
|
||||||
|
+ if (!args.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);
|
||||||
|
+
|
||||||
|
+ prev_count = mutex->u.mutex.count;
|
||||||
|
+ ret = unlock_mutex_state(mutex, &args);
|
||||||
|
+ 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);
|
||||||
|
+
|
||||||
|
+ prev_count = mutex->u.mutex.count;
|
||||||
|
+ ret = unlock_mutex_state(mutex, &args);
|
||||||
|
+ if (!ret)
|
||||||
|
+ try_wake_any_mutex(mutex);
|
||||||
|
+
|
||||||
|
+ spin_unlock(&mutex->lock);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (!ret && put_user(prev_count, &user_args->count))
|
||||||
|
+ ret = -EFAULT;
|
||||||
|
+
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static int ntsync_obj_release(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
struct ntsync_obj *obj = file->private_data;
|
||||||
|
@@ -309,6 +371,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_MUTEX_UNLOCK:
|
||||||
|
+ return ntsync_mutex_unlock(obj, argp);
|
||||||
|
default:
|
||||||
|
return -ENOIOCTLCMD;
|
||||||
|
}
|
||||||
|
diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h
|
||||||
|
index d68f24fd75a2..a3f5f4f13798 100644
|
||||||
|
--- a/include/uapi/linux/ntsync.h
|
||||||
|
+++ b/include/uapi/linux/ntsync.h
|
||||||
|
@@ -39,5 +39,6 @@ struct ntsync_wait_args {
|
||||||
|
#define NTSYNC_IOC_CREATE_MUTEX _IOWR('N', 0x84, struct ntsync_sem_args)
|
||||||
|
|
||||||
|
#define NTSYNC_IOC_SEM_POST _IOWR('N', 0x81, __u32)
|
||||||
|
+#define NTSYNC_IOC_MUTEX_UNLOCK _IOWR('N', 0x85, struct ntsync_mutex_args)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
--
|
||||||
|
2.43.0
|
||||||
|
|
|
@ -0,0 +1,176 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 8/29] ntsync: Introduce NTSYNC_IOC_MUTEX_KILL.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:35 -0600
|
||||||
|
Message-Id: <20240131021356.10322-9-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
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 1770ec4008af..aadf01c65ca0 100644
|
||||||
|
--- a/drivers/misc/ntsync.c
|
||||||
|
+++ b/drivers/misc/ntsync.c
|
||||||
|
@@ -37,6 +37,7 @@ struct ntsync_obj {
|
||||||
|
struct {
|
||||||
|
__u32 count;
|
||||||
|
__u32 owner;
|
||||||
|
+ bool ownerdead;
|
||||||
|
} mutex;
|
||||||
|
} u;
|
||||||
|
|
||||||
|
@@ -89,6 +90,7 @@ struct ntsync_q {
|
||||||
|
atomic_t signaled;
|
||||||
|
|
||||||
|
bool all;
|
||||||
|
+ bool ownerdead;
|
||||||
|
__u32 count;
|
||||||
|
struct ntsync_q_entry entries[];
|
||||||
|
};
|
||||||
|
@@ -164,6 +166,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;
|
||||||
|
@@ -223,6 +228,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);
|
||||||
|
@@ -352,6 +360,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;
|
||||||
|
@@ -373,6 +437,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;
|
||||||
|
}
|
||||||
|
@@ -555,6 +621,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++) {
|
||||||
|
@@ -664,7 +731,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;
|
||||||
|
@@ -747,7 +814,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 a3f5f4f13798..3861397c6c2f 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
|
||||||
|
|
|
@ -0,0 +1,175 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 9/29] ntsync: Introduce NTSYNC_IOC_CREATE_EVENT.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:36 -0600
|
||||||
|
Message-Id: <20240131021356.10322-10-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
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 aadf01c65ca0..c719ddd9f6d7 100644
|
||||||
|
--- a/drivers/misc/ntsync.c
|
||||||
|
+++ b/drivers/misc/ntsync.c
|
||||||
|
@@ -18,6 +18,7 @@
|
||||||
|
enum ntsync_type {
|
||||||
|
NTSYNC_TYPE_SEM,
|
||||||
|
NTSYNC_TYPE_MUTEX,
|
||||||
|
+ NTSYNC_TYPE_EVENT,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ntsync_obj {
|
||||||
|
@@ -39,6 +40,10 @@ struct ntsync_obj {
|
||||||
|
__u32 owner;
|
||||||
|
bool ownerdead;
|
||||||
|
} mutex;
|
||||||
|
+ struct {
|
||||||
|
+ bool manual;
|
||||||
|
+ bool signaled;
|
||||||
|
+ } event;
|
||||||
|
} u;
|
||||||
|
|
||||||
|
/*
|
||||||
|
@@ -123,6 +128,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);
|
||||||
|
@@ -172,6 +179,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);
|
||||||
|
@@ -238,6 +249,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.
|
||||||
|
@@ -544,6 +575,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);
|
||||||
|
@@ -665,6 +720,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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -857,6 +915,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 3861397c6c2f..b8cf503365ef 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,88 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 10/29] ntsync: Introduce NTSYNC_IOC_EVENT_SET.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:37 -0600
|
||||||
|
Message-Id: <20240131021356.10322-11-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
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 c719ddd9f6d7..b2da50989953 100644
|
||||||
|
--- a/drivers/misc/ntsync.c
|
||||||
|
+++ b/drivers/misc/ntsync.c
|
||||||
|
@@ -447,6 +447,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;
|
||||||
|
@@ -470,6 +505,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 b8cf503365ef..782057552483 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,73 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 11/29] ntsync: Introduce NTSYNC_IOC_EVENT_RESET.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:38 -0600
|
||||||
|
Message-Id: <20240131021356.10322-12-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
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 b2da50989953..009d927739b8 100644
|
||||||
|
--- a/drivers/misc/ntsync.c
|
||||||
|
+++ b/drivers/misc/ntsync.c
|
||||||
|
@@ -482,6 +482,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;
|
||||||
|
@@ -507,6 +527,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 782057552483..f2d7507d8438 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,80 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 12/29] ntsync: Introduce NTSYNC_IOC_EVENT_PULSE.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:39 -0600
|
||||||
|
Message-Id: <20240131021356.10322-13-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
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 009d927739b8..240ae858fa96 100644
|
||||||
|
--- a/drivers/misc/ntsync.c
|
||||||
|
+++ b/drivers/misc/ntsync.c
|
||||||
|
@@ -447,7 +447,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;
|
||||||
|
@@ -463,6 +463,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);
|
||||||
|
@@ -472,6 +474,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);
|
||||||
|
}
|
||||||
|
@@ -526,9 +530,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 f2d7507d8438..598f894f868d 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,72 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 13/29] ntsync: Introduce NTSYNC_IOC_SEM_READ.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:40 -0600
|
||||||
|
Message-Id: <20240131021356.10322-14-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
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 240ae858fa96..6dccfbfb2512 100644
|
||||||
|
--- a/drivers/misc/ntsync.c
|
||||||
|
+++ b/drivers/misc/ntsync.c
|
||||||
|
@@ -506,6 +506,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;
|
||||||
|
@@ -525,6 +544,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 598f894f868d..6017f621687e 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,74 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 14/29] ntsync: Introduce NTSYNC_IOC_MUTEX_READ.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:41 -0600
|
||||||
|
Message-Id: <20240131021356.10322-15-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
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 6dccfbfb2512..7f5f96ec7c69 100644
|
||||||
|
--- a/drivers/misc/ntsync.c
|
||||||
|
+++ b/drivers/misc/ntsync.c
|
||||||
|
@@ -525,6 +525,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;
|
||||||
|
@@ -550,6 +571,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 6017f621687e..a1d0ef581212 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,72 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 15/29] ntsync: Introduce NTSYNC_IOC_EVENT_READ.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:42 -0600
|
||||||
|
Message-Id: <20240131021356.10322-16-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
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 7f5f96ec7c69..5439c1c9e90f 100644
|
||||||
|
--- a/drivers/misc/ntsync.c
|
||||||
|
+++ b/drivers/misc/ntsync.c
|
||||||
|
@@ -546,6 +546,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;
|
||||||
|
@@ -579,6 +598,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 a1d0ef581212..582d33b0dcac 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,194 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 16/29] ntsync: Introduce alertable waits.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:43 -0600
|
||||||
|
Message-Id: <20240131021356.10322-17-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
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 5439c1c9e90f..1e619e1ce6a6 100644
|
||||||
|
--- a/drivers/misc/ntsync.c
|
||||||
|
+++ b/drivers/misc/ntsync.c
|
||||||
|
@@ -784,22 +784,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;
|
||||||
|
@@ -809,7 +816,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]);
|
||||||
|
|
||||||
|
@@ -860,9 +867,9 @@ static int ntsync_wait_any(struct ntsync_device *dev, void __user *argp)
|
||||||
|
{
|
||||||
|
struct ntsync_wait_args args;
|
||||||
|
struct ntsync_q *q;
|
||||||
|
+ __u32 i, total_count;
|
||||||
|
ktime_t timeout;
|
||||||
|
int signaled;
|
||||||
|
- __u32 i;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (copy_from_user(&args, argp, sizeof(args)))
|
||||||
|
@@ -872,9 +879,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;
|
||||||
|
|
||||||
|
@@ -883,9 +894,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)
|
||||||
|
@@ -903,7 +920,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;
|
||||||
|
|
||||||
|
@@ -964,6 +981,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 */
|
||||||
|
|
||||||
|
@@ -971,6 +996,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 */
|
||||||
|
|
||||||
|
timeout = ns_to_ktime(args.timeout);
|
||||||
|
@@ -994,6 +1034,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 582d33b0dcac..7c91af7011e4 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,213 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 17/29] selftests: ntsync: Add some tests for
|
||||||
|
semaphore state.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:44 -0600
|
||||||
|
Message-Id: <20240131021356.10322-18-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
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 | 143 ++++++++++++++++++
|
||||||
|
4 files changed, 153 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..6ceb48fb42e3
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
@@ -0,0 +1,143 @@
|
||||||
|
+// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
+/*
|
||||||
|
+ * Various unit tests for the "ntsync" synchronization primitive driver.
|
||||||
|
+ *
|
||||||
|
+ * Copyright (C) 2021-2022 Elizabeth Figura
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#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);
|
||||||
|
+
|
||||||
|
+ close(sem);
|
||||||
|
+
|
||||||
|
+ close(fd);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+TEST_HARNESS_MAIN
|
||||||
|
--
|
||||||
|
2.43.0
|
||||||
|
|
|
@ -0,0 +1,218 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 18/29] selftests: ntsync: Add some tests for mutex
|
||||||
|
state.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:45 -0600
|
||||||
|
Message-Id: <20240131021356.10322-19-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
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 | 181 ++++++++++++++++++
|
||||||
|
1 file changed, 181 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
index 6ceb48fb42e3..80c8bd409d68 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};
|
||||||
|
@@ -140,4 +173,152 @@ 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);
|
||||||
|
+
|
||||||
|
+ close(fd);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
TEST_HARNESS_MAIN
|
||||||
|
--
|
||||||
|
2.43.0
|
||||||
|
|
|
@ -0,0 +1,136 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 19/29] selftests: ntsync: Add some tests for
|
||||||
|
NTSYNC_IOC_WAIT_ANY.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:46 -0600
|
||||||
|
Message-Id: <20240131021356.10322-20-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
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 | 105 ++++++++++++++++++
|
||||||
|
1 file changed, 105 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
index 80c8bd409d68..13e7c9d7441e 100644
|
||||||
|
--- a/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
+++ b/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
@@ -321,4 +321,109 @@ TEST(mutex_state)
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
+TEST(test_wait_any)
|
||||||
|
+{
|
||||||
|
+ struct ntsync_mutex_args mutex_args = {0};
|
||||||
|
+ struct ntsync_wait_args wait_args = {0};
|
||||||
|
+ struct ntsync_sem_args sem_args = {0};
|
||||||
|
+ __u32 owner, index, count;
|
||||||
|
+ struct timespec timeout;
|
||||||
|
+ int objs[2], fd, ret;
|
||||||
|
+
|
||||||
|
+ 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, wait_args.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);
|
||||||
|
+
|
||||||
|
+ close(sem_args.sem);
|
||||||
|
+ close(mutex_args.mutex);
|
||||||
|
+
|
||||||
|
+ close(fd);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
TEST_HARNESS_MAIN
|
||||||
|
--
|
||||||
|
2.43.0
|
||||||
|
|
|
@ -0,0 +1,147 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 20/29] selftests: ntsync: Add some tests for
|
||||||
|
NTSYNC_IOC_WAIT_ALL.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:47 -0600
|
||||||
|
Message-Id: <20240131021356.10322-21-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
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 13e7c9d7441e..77f1b7e42d76 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;
|
||||||
|
@@ -426,4 +437,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,182 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 21/29] selftests: ntsync: Add some tests for wakeup
|
||||||
|
signaling with WINESYNC_IOC_WAIT_ANY.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:48 -0600
|
||||||
|
Message-Id: <20240131021356.10322-22-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
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 | 152 ++++++++++++++++++
|
||||||
|
1 file changed, 152 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
index 77f1b7e42d76..96a866ef235f 100644
|
||||||
|
--- a/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
+++ b/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
@@ -521,4 +521,156 @@ 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,129 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 22/29] selftests: ntsync: Add some tests for wakeup
|
||||||
|
signaling with WINESYNC_IOC_WAIT_ALL.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:49 -0600
|
||||||
|
Message-Id: <20240131021356.10322-23-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
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 96a866ef235f..7776fe71b8ef 100644
|
||||||
|
--- a/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
+++ b/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
@@ -673,4 +673,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,129 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 23/29] selftests: ntsync: Add some tests for
|
||||||
|
manual-reset event state.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:50 -0600
|
||||||
|
Message-Id: <20240131021356.10322-24-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
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 7776fe71b8ef..98fc70a9a58b 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)
|
||||||
|
{
|
||||||
|
@@ -332,6 +353,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)
|
||||||
|
{
|
||||||
|
struct ntsync_mutex_args mutex_args = {0};
|
||||||
|
--
|
||||||
|
2.43.0
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 24/29] selftests: ntsync: Add some tests for
|
||||||
|
auto-reset event state.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:51 -0600
|
||||||
|
Message-Id: <20240131021356.10322-25-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
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 98fc70a9a58b..f1fb28949367 100644
|
||||||
|
--- a/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
+++ b/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
@@ -421,6 +421,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)
|
||||||
|
{
|
||||||
|
struct ntsync_mutex_args mutex_args = {0};
|
||||||
|
--
|
||||||
|
2.43.0
|
||||||
|
|
|
@ -0,0 +1,270 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 25/29] selftests: ntsync: Add some tests for wakeup
|
||||||
|
signaling with events.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:52 -0600
|
||||||
|
Message-Id: <20240131021356.10322-26-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
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 f1fb28949367..598333df3e6d 100644
|
||||||
|
--- a/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
+++ b/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
@@ -587,6 +587,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;
|
||||||
|
@@ -609,6 +610,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;
|
||||||
|
|
||||||
|
@@ -657,6 +663,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);
|
||||||
|
@@ -665,6 +679,7 @@ TEST(test_wait_all)
|
||||||
|
|
||||||
|
close(sem_args.sem);
|
||||||
|
close(mutex_args.mutex);
|
||||||
|
+ close(event_args.event);
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
@@ -713,12 +728,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);
|
||||||
|
@@ -800,10 +816,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);
|
||||||
|
|
||||||
|
@@ -823,12 +930,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);
|
||||||
|
@@ -848,12 +957,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;
|
||||||
|
@@ -887,12 +1008,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);
|
||||||
|
@@ -910,6 +1051,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,234 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 26/29] selftests: ntsync: Add tests for alertable
|
||||||
|
waits.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:53 -0600
|
||||||
|
Message-Id: <20240131021356.10322-27-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
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 598333df3e6d..6c00a55909aa 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)
|
||||||
|
@@ -1062,4 +1077,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,121 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 27/29] selftests: ntsync: Add some tests for wakeup
|
||||||
|
signaling via alerts.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:54 -0600
|
||||||
|
Message-Id: <20240131021356.10322-28-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
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 6c00a55909aa..09153d0686ac 100644
|
||||||
|
--- a/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
+++ b/tools/testing/selftests/drivers/ntsync/ntsync.c
|
||||||
|
@@ -1080,9 +1080,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);
|
||||||
|
@@ -1130,6 +1133,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 */
|
||||||
|
@@ -1166,9 +1197,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);
|
||||||
|
@@ -1202,6 +1236,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,39 @@
|
||||||
|
From git@z Thu Jan 1 00:00:00 1970
|
||||||
|
Subject: [PATCH RFC v2 28/29] maintainers: Add an entry for ntsync.
|
||||||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||||||
|
Date: Tue, 30 Jan 2024 20:13:55 -0600
|
||||||
|
Message-Id: <20240131021356.10322-29-zfigura@codeweavers.com>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
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 8d1052fa6a69..7924127d351b 100644
|
||||||
|
--- a/MAINTAINERS
|
||||||
|
+++ b/MAINTAINERS
|
||||||
|
@@ -15585,6 +15585,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
|
||||||
|
|
Loading…
Reference in New Issue