diff options
Diffstat (limited to 'SOURCES/winesync.patch')
-rw-r--r-- | SOURCES/winesync.patch | 4375 |
1 files changed, 0 insertions, 4375 deletions
diff --git a/SOURCES/winesync.patch b/SOURCES/winesync.patch deleted file mode 100644 index f62b102..0000000 --- a/SOURCES/winesync.patch +++ /dev/null @@ -1,4375 +0,0 @@ -From b99219c187fa5933d0507b1ce67d33cf1e42be6a Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <z.figura12@gmail.com> -Date: Fri, 5 Mar 2021 10:50:45 -0600 -Subject: [PATCH 01/25] winesync: Introduce the winesync driver and character - device. - ---- - drivers/misc/Kconfig | 11 +++++++ - drivers/misc/Makefile | 1 + - drivers/misc/winesync.c | 64 +++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 76 insertions(+) - create mode 100644 drivers/misc/winesync.c - -diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig -index 0f5a49fc7c9e..e21e4424d6a2 100644 ---- a/drivers/misc/Kconfig -+++ b/drivers/misc/Kconfig -@@ -470,6 +470,17 @@ config HISI_HIKEY_USB - switching between the dual-role USB-C port and the USB-A host ports - using only one USB controller. - -+config WINESYNC -+ tristate "Synchronization primitives for Wine" -+ help -+ This module provides kernel support for synchronization primitives -+ used by Wine. It is not a hardware driver. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called winesync. -+ -+ If unsure, say N. -+ - source "drivers/misc/c2port/Kconfig" - source "drivers/misc/eeprom/Kconfig" - source "drivers/misc/cb710/Kconfig" -diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile -index a086197af544..1fb39bc4637b 100644 ---- a/drivers/misc/Makefile -+++ b/drivers/misc/Makefile -@@ -58,4 +58,5 @@ obj-$(CONFIG_HABANA_AI) += habanalabs/ - obj-$(CONFIG_UACCE) += uacce/ - obj-$(CONFIG_XILINX_SDFEC) += xilinx_sdfec.o - obj-$(CONFIG_HISI_HIKEY_USB) += hisi_hikey_usb.o -+obj-$(CONFIG_WINESYNC) += winesync.o - obj-$(CONFIG_HI6421V600_IRQ) += hi6421v600-irq.o -diff --git a/drivers/misc/winesync.c b/drivers/misc/winesync.c -new file mode 100644 -index 000000000000..111f33c5676e ---- /dev/null -+++ b/drivers/misc/winesync.c -@@ -0,0 +1,64 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+/* -+ * winesync.c - Kernel driver for Wine synchronization primitives -+ * -+ * Copyright (C) 2021 Zebediah Figura -+ */ -+ -+#include <linux/fs.h> -+#include <linux/miscdevice.h> -+#include <linux/module.h> -+ -+#define WINESYNC_NAME "winesync" -+ -+static int winesync_char_open(struct inode *inode, struct file *file) -+{ -+ return nonseekable_open(inode, file); -+} -+ -+static int winesync_char_release(struct inode *inode, struct file *file) -+{ -+ return 0; -+} -+ -+static long winesync_char_ioctl(struct file *file, unsigned int cmd, -+ unsigned long parm) -+{ -+ switch (cmd) { -+ default: -+ return -ENOSYS; -+ } -+} -+ -+static const struct file_operations winesync_fops = { -+ .owner = THIS_MODULE, -+ .open = winesync_char_open, -+ .release = winesync_char_release, -+ .unlocked_ioctl = winesync_char_ioctl, -+ .compat_ioctl = winesync_char_ioctl, -+ .llseek = no_llseek, -+}; -+ -+static struct miscdevice winesync_misc = { -+ .minor = MISC_DYNAMIC_MINOR, -+ .name = WINESYNC_NAME, -+ .fops = &winesync_fops, -+}; -+ -+static int __init winesync_init(void) -+{ -+ return misc_register(&winesync_misc); -+} -+ -+static void __exit winesync_exit(void) -+{ -+ misc_deregister(&winesync_misc); -+} -+ -+module_init(winesync_init); -+module_exit(winesync_exit); -+ -+MODULE_AUTHOR("Zebediah Figura"); -+MODULE_DESCRIPTION("Kernel driver for Wine synchronization primitives"); -+MODULE_LICENSE("GPL"); -+MODULE_ALIAS("devname:" WINESYNC_NAME); --- -2.34.1 - -From 0580c3831216d8795661f7863e57555096d0ab67 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <z.figura12@gmail.com> -Date: Fri, 5 Mar 2021 10:57:06 -0600 -Subject: [PATCH 02/25] winesync: Reserve a minor device number and ioctl - range. - ---- - Documentation/admin-guide/devices.txt | 3 ++- - Documentation/userspace-api/ioctl/ioctl-number.rst | 2 ++ - drivers/misc/winesync.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 922c23bb4372..ae39732318a7 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/winesync Wine 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 6655d929a351..9d5f1f87c2ee 100644 ---- a/Documentation/userspace-api/ioctl/ioctl-number.rst -+++ b/Documentation/userspace-api/ioctl/ioctl-number.rst -@@ -370,6 +370,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-0F uapi/linux/winesync.h Wine synchronization primitives -+ <mailto:wine-devel@winehq.org> - 0xFD all linux/dm-ioctl.h - 0xFE all linux/isst_if.h - ==== ===== ======================================================= ================================================================ -diff --git a/drivers/misc/winesync.c b/drivers/misc/winesync.c -index 111f33c5676e..85cb6ccaa077 100644 ---- a/drivers/misc/winesync.c -+++ b/drivers/misc/winesync.c -@@ -40,7 +40,7 @@ static const struct file_operations winesync_fops = { - }; - - static struct miscdevice winesync_misc = { -- .minor = MISC_DYNAMIC_MINOR, -+ .minor = WINESYNC_MINOR, - .name = WINESYNC_NAME, - .fops = &winesync_fops, - }; -@@ -62,3 +62,4 @@ MODULE_AUTHOR("Zebediah Figura"); - MODULE_DESCRIPTION("Kernel driver for Wine synchronization primitives"); - MODULE_LICENSE("GPL"); - MODULE_ALIAS("devname:" WINESYNC_NAME); -+MODULE_ALIAS_MISCDEV(WINESYNC_MINOR); -diff --git a/include/linux/miscdevice.h b/include/linux/miscdevice.h -index 0676f18093f9..350aecfcfb29 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 WINESYNC_MINOR 243 - #define MISC_DYNAMIC_MINOR 255 - - struct device; --- -2.34.1 - -From 67252a879ef5e0585d5be13182d31718c59d8947 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <z.figura12@gmail.com> -Date: Fri, 5 Mar 2021 11:15:39 -0600 -Subject: [PATCH 03/25] winesync: Introduce WINESYNC_IOC_CREATE_SEM and - WINESYNC_IOC_DELETE. - ---- - drivers/misc/winesync.c | 117 ++++++++++++++++++++++++++++++++++ - include/uapi/linux/winesync.h | 25 ++++++++ - 2 files changed, 142 insertions(+) - create mode 100644 include/uapi/linux/winesync.h - -diff --git a/drivers/misc/winesync.c b/drivers/misc/winesync.c -index 85cb6ccaa077..36e31bbe0390 100644 ---- a/drivers/misc/winesync.c -+++ b/drivers/misc/winesync.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/winesync.h> - - #define WINESYNC_NAME "winesync" - -+enum winesync_type { -+ WINESYNC_TYPE_SEM, -+}; -+ -+struct winesync_obj { -+ struct rcu_head rhead; -+ struct kref refcount; -+ -+ enum winesync_type type; -+ -+ union { -+ struct { -+ __u32 count; -+ __u32 max; -+ } sem; -+ } u; -+}; -+ -+struct winesync_device { -+ struct xarray objects; -+}; -+ -+static void destroy_obj(struct kref *ref) -+{ -+ struct winesync_obj *obj = container_of(ref, struct winesync_obj, refcount); -+ -+ kfree_rcu(obj, rhead); -+} -+ -+static void put_obj(struct winesync_obj *obj) -+{ -+ kref_put(&obj->refcount, destroy_obj); -+} -+ - static int winesync_char_open(struct inode *inode, struct file *file) - { -+ struct winesync_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 winesync_char_release(struct inode *inode, struct file *file) - { -+ struct winesync_device *dev = file->private_data; -+ struct winesync_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 winesync_obj *obj) -+{ -+ kref_init(&obj->refcount); -+} -+ -+static int winesync_create_sem(struct winesync_device *dev, void __user *argp) -+{ -+ struct winesync_sem_args __user *user_args = argp; -+ struct winesync_sem_args args; -+ struct winesync_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 = WINESYNC_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 winesync_delete(struct winesync_device *dev, void __user *argp) -+{ -+ struct winesync_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 winesync_char_ioctl(struct file *file, unsigned int cmd, - unsigned long parm) - { -+ struct winesync_device *dev = file->private_data; -+ void __user *argp = (void __user *)parm; -+ - switch (cmd) { -+ case WINESYNC_IOC_CREATE_SEM: -+ return winesync_create_sem(dev, argp); -+ case WINESYNC_IOC_DELETE: -+ return winesync_delete(dev, argp); - default: - return -ENOSYS; - } -diff --git a/include/uapi/linux/winesync.h b/include/uapi/linux/winesync.h -new file mode 100644 -index 000000000000..aabb491f39d2 ---- /dev/null -+++ b/include/uapi/linux/winesync.h -@@ -0,0 +1,25 @@ -+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -+/* -+ * Kernel support for Wine synchronization primitives -+ * -+ * Copyright (C) 2021 Zebediah Figura -+ */ -+ -+#ifndef __LINUX_WINESYNC_H -+#define __LINUX_WINESYNC_H -+ -+#include <linux/types.h> -+ -+struct winesync_sem_args { -+ __u32 sem; -+ __u32 count; -+ __u32 max; -+}; -+ -+#define WINESYNC_IOC_BASE 0xf7 -+ -+#define WINESYNC_IOC_CREATE_SEM _IOWR(WINESYNC_IOC_BASE, 0, \ -+ struct winesync_sem_args) -+#define WINESYNC_IOC_DELETE _IOW (WINESYNC_IOC_BASE, 1, __u32) -+ -+#endif --- -2.34.1 - -From be751be4f73c0b574c50789e0cfc2e9100d0e124 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <z.figura12@gmail.com> -Date: Fri, 5 Mar 2021 11:22:42 -0600 -Subject: [PATCH 04/25] winesync: Introduce WINESYNC_PUT_SEM. - ---- - drivers/misc/winesync.c | 68 +++++++++++++++++++++++++++++++++++ - include/uapi/linux/winesync.h | 2 ++ - 2 files changed, 70 insertions(+) - -diff --git a/drivers/misc/winesync.c b/drivers/misc/winesync.c -index 36e31bbe0390..2f048a39e4eb 100644 ---- a/drivers/misc/winesync.c -+++ b/drivers/misc/winesync.c -@@ -21,9 +21,11 @@ enum winesync_type { - struct winesync_obj { - struct rcu_head rhead; - struct kref refcount; -+ spinlock_t lock; - - enum winesync_type type; - -+ /* The following fields are protected by the object lock. */ - union { - struct { - __u32 count; -@@ -36,6 +38,19 @@ struct winesync_device { - struct xarray objects; - }; - -+static struct winesync_obj *get_obj(struct winesync_device *dev, __u32 id) -+{ -+ struct winesync_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 winesync_obj *obj = container_of(ref, struct winesync_obj, refcount); -@@ -81,6 +96,7 @@ static int winesync_char_release(struct inode *inode, struct file *file) - static void init_obj(struct winesync_obj *obj) - { - kref_init(&obj->refcount); -+ spin_lock_init(&obj->lock); - } - - static int winesync_create_sem(struct winesync_device *dev, void __user *argp) -@@ -131,6 +147,56 @@ static int winesync_delete(struct winesync_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 winesync_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 winesync_put_sem(struct winesync_device *dev, void __user *argp) -+{ -+ struct winesync_sem_args __user *user_args = argp; -+ struct winesync_sem_args args; -+ struct winesync_obj *sem; -+ __u32 prev_count; -+ int ret; -+ -+ if (copy_from_user(&args, argp, sizeof(args))) -+ return -EFAULT; -+ -+ sem = get_obj(dev, args.sem); -+ if (!sem) -+ return -EINVAL; -+ if (sem->type != WINESYNC_TYPE_SEM) { -+ put_obj(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 winesync_char_ioctl(struct file *file, unsigned int cmd, - unsigned long parm) - { -@@ -142,6 +208,8 @@ static long winesync_char_ioctl(struct file *file, unsigned int cmd, - return winesync_create_sem(dev, argp); - case WINESYNC_IOC_DELETE: - return winesync_delete(dev, argp); -+ case WINESYNC_IOC_PUT_SEM: -+ return winesync_put_sem(dev, argp); - default: - return -ENOSYS; - } -diff --git a/include/uapi/linux/winesync.h b/include/uapi/linux/winesync.h -index aabb491f39d2..7681a168eb92 100644 ---- a/include/uapi/linux/winesync.h -+++ b/include/uapi/linux/winesync.h -@@ -21,5 +21,7 @@ struct winesync_sem_args { - #define WINESYNC_IOC_CREATE_SEM _IOWR(WINESYNC_IOC_BASE, 0, \ - struct winesync_sem_args) - #define WINESYNC_IOC_DELETE _IOW (WINESYNC_IOC_BASE, 1, __u32) -+#define WINESYNC_IOC_PUT_SEM _IOWR(WINESYNC_IOC_BASE, 2, \ -+ struct winesync_sem_args) - - #endif --- -2.34.1 - -From c5327f5ecdcb94c6ada71c036a0be5accee390dc Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <z.figura12@gmail.com> -Date: Fri, 5 Mar 2021 11:31:44 -0600 -Subject: [PATCH 05/25] winesync: Introduce WINESYNC_IOC_WAIT_ANY. - ---- - drivers/misc/winesync.c | 225 ++++++++++++++++++++++++++++++++++ - include/uapi/linux/winesync.h | 11 ++ - 2 files changed, 236 insertions(+) - -diff --git a/drivers/misc/winesync.c b/drivers/misc/winesync.c -index 2f048a39e4eb..e74dba90d525 100644 ---- a/drivers/misc/winesync.c -+++ b/drivers/misc/winesync.c -@@ -23,6 +23,8 @@ struct winesync_obj { - struct kref refcount; - spinlock_t lock; - -+ struct list_head any_waiters; -+ - enum winesync_type type; - - /* The following fields are protected by the object lock. */ -@@ -34,6 +36,28 @@ struct winesync_obj { - } u; - }; - -+struct winesync_q_entry { -+ struct list_head node; -+ struct winesync_q *q; -+ struct winesync_obj *obj; -+ __u32 index; -+}; -+ -+struct winesync_q { -+ struct task_struct *task; -+ __u32 owner; -+ -+ /* -+ * Protected via atomic_cmpxchg(). Only the thread that wins the -+ * compare-and-swap may actually change object states and wake this -+ * task. -+ */ -+ atomic_t signaled; -+ -+ __u32 count; -+ struct winesync_q_entry entries[]; -+}; -+ - struct winesync_device { - struct xarray objects; - }; -@@ -97,6 +121,26 @@ static void init_obj(struct winesync_obj *obj) - { - kref_init(&obj->refcount); - spin_lock_init(&obj->lock); -+ INIT_LIST_HEAD(&obj->any_waiters); -+} -+ -+static void try_wake_any_sem(struct winesync_obj *sem) -+{ -+ struct winesync_q_entry *entry; -+ -+ lockdep_assert_held(&sem->lock); -+ -+ list_for_each_entry(entry, &sem->any_waiters, node) { -+ struct winesync_q *q = entry->q; -+ -+ if (!sem->u.sem.count) -+ break; -+ -+ if (atomic_cmpxchg(&q->signaled, -1, entry->index) == -1) { -+ sem->u.sem.count--; -+ wake_up_process(q->task); -+ } -+ } - } - - static int winesync_create_sem(struct winesync_device *dev, void __user *argp) -@@ -186,6 +230,8 @@ static int winesync_put_sem(struct winesync_device *dev, void __user *argp) - - prev_count = sem->u.sem.count; - ret = put_sem_state(sem, args.count); -+ if (!ret) -+ try_wake_any_sem(sem); - - spin_unlock(&sem->lock); - -@@ -197,6 +243,183 @@ static int winesync_put_sem(struct winesync_device *dev, void __user *argp) - return ret; - } - -+static int winesync_schedule(const struct winesync_q *q, ktime_t *timeout) -+{ -+ int ret = 0; -+ -+ do { -+ if (signal_pending(current)) { -+ ret = -ERESTARTSYS; -+ break; -+ } -+ -+ set_current_state(TASK_INTERRUPTIBLE); -+ if (atomic_read(&q->signaled) != -1) { -+ ret = 0; -+ break; -+ } -+ ret = schedule_hrtimeout(timeout, HRTIMER_MODE_ABS); -+ } while (ret < 0); -+ __set_current_state(TASK_RUNNING); -+ -+ return ret; -+} -+ -+/* -+ * Allocate and initialize the winesync_q structure, but do not queue us yet. -+ * Also, calculate the relative timeout. -+ */ -+static int setup_wait(struct winesync_device *dev, -+ const struct winesync_wait_args *args, -+ ktime_t *ret_timeout, struct winesync_q **ret_q) -+{ -+ const __u32 count = args->count; -+ struct winesync_q *q; -+ ktime_t timeout = 0; -+ __u32 *ids; -+ __u32 i, j; -+ -+ if (!args->owner) -+ return -EINVAL; -+ -+ if (args->timeout) { -+ struct timespec64 to; -+ -+ if (get_timespec64(&to, u64_to_user_ptr(args->timeout))) -+ return -EFAULT; -+ if (!timespec64_valid(&to)) -+ return -EINVAL; -+ -+ timeout = timespec64_to_ns(&to); -+ } -+ -+ ids = kmalloc_array(args->count, sizeof(*ids), GFP_KERNEL); -+ if (!ids) -+ return -ENOMEM; -+ if (copy_from_user(ids, u64_to_user_ptr(args->objs), -+ array_size(args->count, sizeof(*ids)))) { -+ kfree(ids); -+ return -EFAULT; -+ } -+ -+ q = kmalloc(struct_size(q, entries, count), GFP_KERNEL); -+ if (!q) { -+ kfree(ids); -+ return -ENOMEM; -+ } -+ q->task = current; -+ q->owner = args->owner; -+ atomic_set(&q->signaled, -1); -+ q->count = count; -+ -+ for (i = 0; i < count; i++) { -+ struct winesync_q_entry *entry = &q->entries[i]; -+ struct winesync_obj *obj = get_obj(dev, ids[i]); -+ -+ if (!obj) -+ goto err; -+ -+ entry->obj = obj; -+ entry->q = q; -+ entry->index = i; -+ } -+ -+ kfree(ids); -+ -+ *ret_q = q; -+ *ret_timeout = timeout; -+ return 0; -+ -+err: -+ for (j = 0; j < i; j++) -+ put_obj(q->entries[j].obj); -+ kfree(ids); -+ kfree(q); -+ return -EINVAL; -+} -+ -+static void try_wake_any_obj(struct winesync_obj *obj) -+{ -+ switch (obj->type) { -+ case WINESYNC_TYPE_SEM: -+ try_wake_any_sem(obj); -+ break; -+ } -+} -+ -+static int winesync_wait_any(struct winesync_device *dev, void __user *argp) -+{ -+ struct winesync_wait_args args; -+ struct winesync_q *q; -+ ktime_t timeout; -+ int signaled; -+ __u32 i; -+ int ret; -+ -+ if (copy_from_user(&args, argp, sizeof(args))) -+ return -EFAULT; -+ -+ ret = setup_wait(dev, &args, &timeout, &q); -+ if (ret < 0) -+ return ret; -+ -+ /* queue ourselves */ -+ -+ for (i = 0; i < args.count; i++) { -+ struct winesync_q_entry *entry = &q->entries[i]; -+ struct winesync_obj *obj = q->entries[i].obj; -+ -+ spin_lock(&obj->lock); -+ list_add_tail(&entry->node, &obj->any_waiters); -+ spin_unlock(&obj->lock); -+ } -+ -+ /* check if we are already signaled */ -+ -+ for (i = 0; i < args.count; i++) { -+ struct winesync_obj *obj = q->entries[i].obj; -+ -+ if (atomic_read(&q->signaled) != -1) -+ break; -+ -+ spin_lock(&obj->lock); -+ try_wake_any_obj(obj); -+ spin_unlock(&obj->lock); -+ } -+ -+ /* sleep */ -+ -+ ret = winesync_schedule(q, args.timeout ? &timeout : NULL); -+ -+ /* and finally, unqueue */ -+ -+ for (i = 0; i < args.count; i++) { -+ struct winesync_obj *obj = q->entries[i].obj; -+ -+ spin_lock(&obj->lock); -+ list_del(&q->entries[i].node); -+ spin_unlock(&obj->lock); -+ -+ put_obj(obj); -+ } -+ -+ signaled = atomic_read(&q->signaled); -+ if (signaled != -1) { -+ struct winesync_wait_args __user *user_args = argp; -+ -+ /* even if we caught a signal, we need to communicate success */ -+ ret = 0; -+ -+ if (put_user(signaled, &user_args->index)) -+ ret = -EFAULT; -+ } else if (!ret) { -+ ret = -ETIMEDOUT; -+ } -+ -+ kfree(q); -+ return ret; -+} -+ - static long winesync_char_ioctl(struct file *file, unsigned int cmd, - unsigned long parm) - { -@@ -210,6 +433,8 @@ static long winesync_char_ioctl(struct file *file, unsigned int cmd, - return winesync_delete(dev, argp); - case WINESYNC_IOC_PUT_SEM: - return winesync_put_sem(dev, argp); -+ case WINESYNC_IOC_WAIT_ANY: -+ return winesync_wait_any(dev, argp); - default: - return -ENOSYS; - } -diff --git a/include/uapi/linux/winesync.h b/include/uapi/linux/winesync.h -index 7681a168eb92..f57ebfbe1dd9 100644 ---- a/include/uapi/linux/winesync.h -+++ b/include/uapi/linux/winesync.h -@@ -16,6 +16,15 @@ struct winesync_sem_args { - __u32 max; - }; - -+struct winesync_wait_args { -+ __u64 timeout; -+ __u64 objs; -+ __u32 count; -+ __u32 owner; -+ __u32 index; -+ __u32 pad; -+}; -+ - #define WINESYNC_IOC_BASE 0xf7 - - #define WINESYNC_IOC_CREATE_SEM _IOWR(WINESYNC_IOC_BASE, 0, \ -@@ -23,5 +32,7 @@ struct winesync_sem_args { - #define WINESYNC_IOC_DELETE _IOW (WINESYNC_IOC_BASE, 1, __u32) - #define WINESYNC_IOC_PUT_SEM _IOWR(WINESYNC_IOC_BASE, 2, \ - struct winesync_sem_args) -+#define WINESYNC_IOC_WAIT_ANY _IOWR(WINESYNC_IOC_BASE, 3, \ -+ struct winesync_wait_args) - - #endif --- -2.34.1 - -From 1b56ce9253a1dce2f63252e3833a98da353eeb31 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <z.figura12@gmail.com> -Date: Fri, 5 Mar 2021 11:36:09 -0600 -Subject: [PATCH 06/25] winesync: Introduce WINESYNC_IOC_WAIT_ALL. - ---- - drivers/misc/winesync.c | 242 ++++++++++++++++++++++++++++++++-- - include/uapi/linux/winesync.h | 2 + - 2 files changed, 236 insertions(+), 8 deletions(-) - -diff --git a/drivers/misc/winesync.c b/drivers/misc/winesync.c -index e74dba90d525..a0ee4536165e 100644 ---- a/drivers/misc/winesync.c -+++ b/drivers/misc/winesync.c -@@ -23,7 +23,34 @@ struct winesync_obj { - struct kref refcount; - spinlock_t lock; - -+ /* -+ * any_waiters is protected by the object lock, but all_waiters is -+ * protected by the device wait_all_lock. -+ */ - struct list_head any_waiters; -+ struct list_head all_waiters; -+ -+ /* -+ * Hint describing how many tasks are queued on this object in a -+ * wait-all operation. -+ * -+ * Any time we do a wake, we may need to wake "all" waiters as well as -+ * "any" waiters. In order to atomically wake "all" waiters, we must -+ * lock all of the objects, and that means grabbing the wait_all_lock -+ * below (and, due to lock ordering rules, before locking this object). -+ * However, wait-all is a rare operation, and grabbing the wait-all -+ * lock for every wake would create unnecessary contention. Therefore we -+ * first check whether all_hint is zero, and, if it is, we skip trying -+ * to wake "all" waiters. -+ * -+ * 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 -+ * hint. -+ * -+ * Since wait requests must originate from user-space threads, we're -+ * limited here by PID_MAX_LIMIT, so there's no risk of saturation. -+ */ -+ atomic_t all_hint; - - enum winesync_type type; - -@@ -54,11 +81,25 @@ struct winesync_q { - */ - atomic_t signaled; - -+ bool all; - __u32 count; - struct winesync_q_entry entries[]; - }; - - struct winesync_device { -+ /* -+ * Wait-all operations must atomically grab all objects, and be totally -+ * ordered with respect to each other and wait-any operations. If one -+ * thread is trying to acquire several objects, another thread cannot -+ * touch the object 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, -+ * wait_all_lock is taken first whenever multiple objects must be locked -+ * at the same time. -+ */ -+ spinlock_t wait_all_lock; -+ - struct xarray objects; - }; - -@@ -95,6 +136,8 @@ static int winesync_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; -@@ -120,8 +163,82 @@ static int winesync_char_release(struct inode *inode, struct file *file) - static void init_obj(struct winesync_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 winesync_obj *obj, __u32 owner) -+{ -+ lockdep_assert_held(&obj->lock); -+ -+ switch (obj->type) { -+ case WINESYNC_TYPE_SEM: -+ return !!obj->u.sem.count; -+ } -+ -+ WARN(1, "bad object type %#x\n", obj->type); -+ return false; -+} -+ -+/* -+ * "locked_obj" is an optional pointer to an object which is already locked and -+ * should not be locked again. This is necessary so that changing an object's -+ * state and waking it can be a single atomic operation. -+ */ -+static void try_wake_all(struct winesync_device *dev, struct winesync_q *q, -+ struct winesync_obj *locked_obj) -+{ -+ __u32 count = q->count; -+ bool can_wake = true; -+ __u32 i; -+ -+ lockdep_assert_held(&dev->wait_all_lock); -+ if (locked_obj) -+ lockdep_assert_held(&locked_obj->lock); -+ -+ for (i = 0; i < count; i++) { -+ if (q->entries[i].obj != locked_obj) -+ spin_lock(&q->entries[i].obj->lock); -+ } -+ -+ for (i = 0; i < count; i++) { -+ if (!is_signaled(q->entries[i].obj, q->owner)) { -+ can_wake = false; -+ break; -+ } -+ } -+ -+ if (can_wake && atomic_cmpxchg(&q->signaled, -1, 0) == -1) { -+ for (i = 0; i < count; i++) { -+ struct winesync_obj *obj = q->entries[i].obj; -+ -+ switch (obj->type) { -+ case WINESYNC_TYPE_SEM: -+ obj->u.sem.count--; -+ break; -+ } -+ } -+ wake_up_process(q->task); -+ } -+ -+ for (i = 0; i < count; i++) { -+ if (q->entries[i].obj != locked_obj) -+ spin_unlock(&q->entries[i].obj->lock); -+ } -+} -+ -+static void try_wake_all_obj(struct winesync_device *dev, -+ struct winesync_obj *obj) -+{ -+ struct winesync_q_entry *entry; -+ -+ lockdep_assert_held(&dev->wait_all_lock); -+ lockdep_assert_held(&obj->lock); -+ -+ list_for_each_entry(entry, &obj->all_waiters, node) -+ try_wake_all(dev, entry->q, obj); - } - - static void try_wake_any_sem(struct winesync_obj *sem) -@@ -226,14 +343,29 @@ static int winesync_put_sem(struct winesync_device *dev, void __user *argp) - return -EINVAL; - } - -- spin_lock(&sem->lock); -+ if (atomic_read(&sem->all_hint) > 0) { -+ spin_lock(&dev->wait_all_lock); -+ spin_lock(&sem->lock); -+ -+ prev_count = sem->u.sem.count; -+ ret = put_sem_state(sem, args.count); -+ if (!ret) { -+ try_wake_all_obj(dev, sem); -+ try_wake_any_sem(sem); -+ } - -- prev_count = sem->u.sem.count; -- ret = put_sem_state(sem, args.count); -- if (!ret) -- try_wake_any_sem(sem); -+ spin_unlock(&sem->lock); -+ spin_unlock(&dev->wait_all_lock); -+ } else { -+ spin_lock(&sem->lock); - -- spin_unlock(&sem->lock); -+ prev_count = sem->u.sem.count; -+ ret = put_sem_state(sem, args.count); -+ if (!ret) -+ try_wake_any_sem(sem); -+ -+ spin_unlock(&sem->lock); -+ } - - put_obj(sem); - -@@ -270,7 +402,7 @@ static int winesync_schedule(const struct winesync_q *q, ktime_t *timeout) - * Also, calculate the relative timeout. - */ - static int setup_wait(struct winesync_device *dev, -- const struct winesync_wait_args *args, -+ const struct winesync_wait_args *args, bool all, - ktime_t *ret_timeout, struct winesync_q **ret_q) - { - const __u32 count = args->count; -@@ -310,6 +442,7 @@ static int setup_wait(struct winesync_device *dev, - q->task = current; - q->owner = args->owner; - atomic_set(&q->signaled, -1); -+ q->all = all; - q->count = count; - - for (i = 0; i < count; i++) { -@@ -319,6 +452,16 @@ static int setup_wait(struct winesync_device *dev, - if (!obj) - goto err; - -+ if (all) { -+ /* Check that the objects are all distinct. */ -+ for (j = 0; j < i; j++) { -+ if (obj == q->entries[j].obj) { -+ put_obj(obj); -+ goto err; -+ } -+ } -+ } -+ - entry->obj = obj; - entry->q = q; - entry->index = i; -@@ -359,7 +502,7 @@ static int winesync_wait_any(struct winesync_device *dev, void __user *argp) - if (copy_from_user(&args, argp, sizeof(args))) - return -EFAULT; - -- ret = setup_wait(dev, &args, &timeout, &q); -+ ret = setup_wait(dev, &args, false, &timeout, &q); - if (ret < 0) - return ret; - -@@ -420,6 +563,87 @@ static int winesync_wait_any(struct winesync_device *dev, void __user *argp) - return ret; - } - -+static int winesync_wait_all(struct winesync_device *dev, void __user *argp) -+{ -+ struct winesync_wait_args args; -+ struct winesync_q *q; -+ ktime_t timeout; -+ int signaled; -+ __u32 i; -+ int ret; -+ -+ if (copy_from_user(&args, argp, sizeof(args))) -+ return -EFAULT; -+ -+ ret = setup_wait(dev, &args, true, &timeout, &q); -+ if (ret < 0) -+ return ret; -+ -+ /* queue ourselves */ -+ -+ spin_lock(&dev->wait_all_lock); -+ -+ for (i = 0; i < args.count; i++) { -+ struct winesync_q_entry *entry = &q->entries[i]; -+ struct winesync_obj *obj = q->entries[i].obj; -+ -+ atomic_inc(&obj->all_hint); -+ -+ /* -+ * obj->all_waiters is protected by dev->wait_all_lock rather -+ * than obj->lock, so there is no need to acquire it here. -+ */ -+ list_add_tail(&entry->node, &obj->all_waiters); -+ } -+ -+ /* check if we are already signaled */ -+ -+ try_wake_all(dev, q, NULL); -+ -+ spin_unlock(&dev->wait_all_lock); -+ -+ /* sleep */ -+ -+ ret = winesync_schedule(q, args.timeout ? &timeout : NULL); -+ -+ /* and finally, unqueue */ -+ -+ spin_lock(&dev->wait_all_lock); -+ -+ for (i = 0; i < args.count; i++) { -+ struct winesync_q_entry *entry = &q->entries[i]; -+ struct winesync_obj *obj = q->entries[i].obj; -+ -+ /* -+ * obj->all_waiters is protected by dev->wait_all_lock rather -+ * than obj->lock, so there is no need to acquire it here. -+ */ -+ list_del(&entry->node); -+ -+ atomic_dec(&obj->all_hint); -+ -+ put_obj(obj); -+ } -+ -+ spin_unlock(&dev->wait_all_lock); -+ -+ signaled = atomic_read(&q->signaled); -+ if (signaled != -1) { -+ struct winesync_wait_args __user *user_args = argp; -+ -+ /* even if we caught a signal, we need to communicate success */ -+ ret = 0; -+ -+ if (put_user(signaled, &user_args->index)) -+ ret = -EFAULT; -+ } else if (!ret) { -+ ret = -ETIMEDOUT; -+ } -+ -+ kfree(q); -+ return ret; -+} -+ - static long winesync_char_ioctl(struct file *file, unsigned int cmd, - unsigned long parm) - { -@@ -435,6 +659,8 @@ static long winesync_char_ioctl(struct file *file, unsigned int cmd, - return winesync_put_sem(dev, argp); - case WINESYNC_IOC_WAIT_ANY: - return winesync_wait_any(dev, argp); -+ case WINESYNC_IOC_WAIT_ALL: -+ return winesync_wait_all(dev, argp); - default: - return -ENOSYS; - } -diff --git a/include/uapi/linux/winesync.h b/include/uapi/linux/winesync.h -index f57ebfbe1dd9..bcd21e53fa04 100644 ---- a/include/uapi/linux/winesync.h -+++ b/include/uapi/linux/winesync.h -@@ -34,5 +34,7 @@ struct winesync_wait_args { - struct winesync_sem_args) - #define WINESYNC_IOC_WAIT_ANY _IOWR(WINESYNC_IOC_BASE, 3, \ - struct winesync_wait_args) -+#define WINESYNC_IOC_WAIT_ALL _IOW (WINESYNC_IOC_BASE, 4, \ -+ struct winesync_wait_args) - - #endif --- -2.34.1 - -From 0a49b2023e8e4ffdafd6e862f3a7e59115dbdc18 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <zfigura@codeweavers.com> -Date: Tue, 30 Nov 2021 13:32:59 -0600 -Subject: [PATCH 07/25] winesync: Allow atomically changing the signal mask - when calling wait ioctls. - -Along the lines of pselect(2) et al. - -Wine will need, in some cases, to wait for either a winesync primitive to be -signaled, or for a signal to arrive, i.e. the exact use case that pselect(2) -was designed for. ---- - drivers/misc/winesync.c | 13 +++++++++++++ - include/uapi/linux/winesync.h | 2 ++ - kernel/signal.c | 3 +++ - 3 files changed, 18 insertions(+) - -diff --git a/drivers/misc/winesync.c b/drivers/misc/winesync.c -index a0ee4536165e..071d611f65a3 100644 ---- a/drivers/misc/winesync.c -+++ b/drivers/misc/winesync.c -@@ -5,9 +5,11 @@ - * Copyright (C) 2021 Zebediah Figura - */ - -+#include <linux/compat.h> - #include <linux/fs.h> - #include <linux/miscdevice.h> - #include <linux/module.h> -+#include <linux/sched/signal.h> - #include <linux/slab.h> - #include <linux/xarray.h> - #include <uapi/linux/winesync.h> -@@ -405,11 +407,20 @@ static int setup_wait(struct winesync_device *dev, - const struct winesync_wait_args *args, bool all, - ktime_t *ret_timeout, struct winesync_q **ret_q) - { -+ const void __user *sigmask = u64_to_user_ptr(args->sigmask); - const __u32 count = args->count; - struct winesync_q *q; - ktime_t timeout = 0; - __u32 *ids; - __u32 i, j; -+ int ret; -+ -+ if (in_compat_syscall()) -+ ret = set_compat_user_sigmask(sigmask, args->sigsetsize); -+ else -+ ret = set_user_sigmask(sigmask, args->sigsetsize); -+ if (ret < 0) -+ return ret; - - if (!args->owner) - return -EINVAL; -@@ -560,6 +571,7 @@ static int winesync_wait_any(struct winesync_device *dev, void __user *argp) - } - - kfree(q); -+ restore_saved_sigmask_unless(ret == -ERESTARTSYS); - return ret; - } - -@@ -641,6 +653,7 @@ static int winesync_wait_all(struct winesync_device *dev, void __user *argp) - } - - kfree(q); -+ restore_saved_sigmask_unless(ret == -ERESTARTSYS); - return ret; - } - -diff --git a/include/uapi/linux/winesync.h b/include/uapi/linux/winesync.h -index bcd21e53fa04..37a362fa9f1d 100644 ---- a/include/uapi/linux/winesync.h -+++ b/include/uapi/linux/winesync.h -@@ -17,6 +17,8 @@ struct winesync_sem_args { - }; - - struct winesync_wait_args { -+ __u64 sigmask; -+ __u64 sigsetsize; - __u64 timeout; - __u64 objs; - __u32 count; -diff --git a/kernel/signal.c b/kernel/signal.c -index 5892c91696f8..4ef90711610e 100644 ---- a/kernel/signal.c -+++ b/kernel/signal.c -@@ -3064,6 +3064,7 @@ void __set_current_blocked(const sigset_t *newset) - __set_task_blocked(tsk, newset); - spin_unlock_irq(&tsk->sighand->siglock); - } -+EXPORT_SYMBOL_GPL(__set_current_blocked); - - /* - * This is also useful for kernel threads that want to temporarily -@@ -3127,6 +3128,7 @@ int set_user_sigmask(const sigset_t __user *umask, size_t sigsetsize) - - return 0; - } -+EXPORT_SYMBOL_GPL(set_user_sigmask); - - #ifdef CONFIG_COMPAT - int set_compat_user_sigmask(const compat_sigset_t __user *umask, -@@ -3147,6 +3149,7 @@ int set_compat_user_sigmask(const compat_sigset_t __user *umask, - - return 0; - } -+EXPORT_SYMBOL_GPL(set_compat_user_sigmask); - #endif - - /** --- -2.34.1 - -From 839d4c5b7740071251bef01de70e0802df20de7d Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <z.figura12@gmail.com> -Date: Fri, 5 Mar 2021 11:41:10 -0600 -Subject: [PATCH 08/25] winesync: Introduce WINESYNC_IOC_CREATE_MUTEX. - ---- - drivers/misc/winesync.c | 72 +++++++++++++++++++++++++++++++++++ - include/uapi/linux/winesync.h | 8 ++++ - 2 files changed, 80 insertions(+) - -diff --git a/drivers/misc/winesync.c b/drivers/misc/winesync.c -index 071d611f65a3..f53ca84c39e8 100644 ---- a/drivers/misc/winesync.c -+++ b/drivers/misc/winesync.c -@@ -18,6 +18,7 @@ - - enum winesync_type { - WINESYNC_TYPE_SEM, -+ WINESYNC_TYPE_MUTEX, - }; - - struct winesync_obj { -@@ -62,6 +63,10 @@ struct winesync_obj { - __u32 count; - __u32 max; - } sem; -+ struct { -+ __u32 count; -+ __u32 owner; -+ } mutex; - } u; - }; - -@@ -178,6 +183,10 @@ static bool is_signaled(struct winesync_obj *obj, __u32 owner) - switch (obj->type) { - case WINESYNC_TYPE_SEM: - return !!obj->u.sem.count; -+ case WINESYNC_TYPE_MUTEX: -+ if (obj->u.mutex.owner && obj->u.mutex.owner != owner) -+ return false; -+ return obj->u.mutex.count < UINT_MAX; - } - - WARN(1, "bad object type %#x\n", obj->type); -@@ -220,6 +229,10 @@ static void try_wake_all(struct winesync_device *dev, struct winesync_q *q, - case WINESYNC_TYPE_SEM: - obj->u.sem.count--; - break; -+ case WINESYNC_TYPE_MUTEX: -+ obj->u.mutex.count++; -+ obj->u.mutex.owner = q->owner; -+ break; - } - } - wake_up_process(q->task); -@@ -262,6 +275,28 @@ static void try_wake_any_sem(struct winesync_obj *sem) - } - } - -+static void try_wake_any_mutex(struct winesync_obj *mutex) -+{ -+ struct winesync_q_entry *entry; -+ -+ lockdep_assert_held(&mutex->lock); -+ -+ list_for_each_entry(entry, &mutex->any_waiters, node) { -+ struct winesync_q *q = entry->q; -+ -+ if (mutex->u.mutex.count == UINT_MAX) -+ break; -+ if (mutex->u.mutex.owner && mutex->u.mutex.owner != q->owner) -+ continue; -+ -+ if (atomic_cmpxchg(&q->signaled, -1, entry->index) == -1) { -+ mutex->u.mutex.count++; -+ mutex->u.mutex.owner = q->owner; -+ wake_up_process(q->task); -+ } -+ } -+} -+ - static int winesync_create_sem(struct winesync_device *dev, void __user *argp) - { - struct winesync_sem_args __user *user_args = argp; -@@ -294,6 +329,38 @@ static int winesync_create_sem(struct winesync_device *dev, void __user *argp) - return put_user(id, &user_args->sem); - } - -+static int winesync_create_mutex(struct winesync_device *dev, void __user *argp) -+{ -+ struct winesync_mutex_args __user *user_args = argp; -+ struct winesync_mutex_args args; -+ struct winesync_obj *mutex; -+ __u32 id; -+ int ret; -+ -+ if (copy_from_user(&args, argp, sizeof(args))) -+ return -EFAULT; -+ -+ if (!args.owner != !args.count) -+ return -EINVAL; -+ -+ mutex = kzalloc(sizeof(*mutex), GFP_KERNEL); -+ if (!mutex) -+ return -ENOMEM; -+ -+ init_obj(mutex); -+ mutex->type = WINESYNC_TYPE_MUTEX; -+ mutex->u.mutex.count = args.count; -+ mutex->u.mutex.owner = args.owner; -+ -+ ret = xa_alloc(&dev->objects, &id, mutex, xa_limit_32b, GFP_KERNEL); -+ if (ret < 0) { -+ kfree(mutex); -+ return ret; -+ } -+ -+ return put_user(id, &user_args->mutex); -+} -+ - static int winesync_delete(struct winesync_device *dev, void __user *argp) - { - struct winesync_obj *obj; -@@ -498,6 +565,9 @@ static void try_wake_any_obj(struct winesync_obj *obj) - case WINESYNC_TYPE_SEM: - try_wake_any_sem(obj); - break; -+ case WINESYNC_TYPE_MUTEX: -+ try_wake_any_mutex(obj); -+ break; - } - } - -@@ -666,6 +736,8 @@ static long winesync_char_ioctl(struct file *file, unsigned int cmd, - switch (cmd) { - case WINESYNC_IOC_CREATE_SEM: - return winesync_create_sem(dev, argp); -+ case WINESYNC_IOC_CREATE_MUTEX: -+ return winesync_create_mutex(dev, argp); - case WINESYNC_IOC_DELETE: - return winesync_delete(dev, argp); - case WINESYNC_IOC_PUT_SEM: -diff --git a/include/uapi/linux/winesync.h b/include/uapi/linux/winesync.h -index 37a362fa9f1d..0c58181ae05c 100644 ---- a/include/uapi/linux/winesync.h -+++ b/include/uapi/linux/winesync.h -@@ -16,6 +16,12 @@ struct winesync_sem_args { - __u32 max; - }; - -+struct winesync_mutex_args { -+ __u32 mutex; -+ __u32 owner; -+ __u32 count; -+}; -+ - struct winesync_wait_args { - __u64 sigmask; - __u64 sigsetsize; -@@ -38,5 +44,7 @@ struct winesync_wait_args { - struct winesync_wait_args) - #define WINESYNC_IOC_WAIT_ALL _IOW (WINESYNC_IOC_BASE, 4, \ - struct winesync_wait_args) -+#define WINESYNC_IOC_CREATE_MUTEX _IOWR(WINESYNC_IOC_BASE, 5, \ -+ struct winesync_mutex_args) - - #endif --- -2.34.1 - -From 3d4007a2b75f991292d99b4b36159610da602a1b Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <z.figura12@gmail.com> -Date: Fri, 5 Mar 2021 11:44:41 -0600 -Subject: [PATCH 09/25] winesync: Introduce WINESYNC_IOC_PUT_MUTEX. - ---- - drivers/misc/winesync.c | 71 +++++++++++++++++++++++++++++++++++ - include/uapi/linux/winesync.h | 2 + - 2 files changed, 73 insertions(+) - -diff --git a/drivers/misc/winesync.c b/drivers/misc/winesync.c -index f53ca84c39e8..d07ebd4c8c1c 100644 ---- a/drivers/misc/winesync.c -+++ b/drivers/misc/winesync.c -@@ -444,6 +444,75 @@ static int winesync_put_sem(struct winesync_device *dev, void __user *argp) - return ret; - } - -+/* -+ * Actually change the mutex state, returning -EPERM if not the owner. -+ */ -+static int put_mutex_state(struct winesync_obj *mutex, -+ const struct winesync_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 winesync_put_mutex(struct winesync_device *dev, void __user *argp) -+{ -+ struct winesync_mutex_args __user *user_args = argp; -+ struct winesync_mutex_args args; -+ struct winesync_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(dev, args.mutex); -+ if (!mutex) -+ return -EINVAL; -+ if (mutex->type != WINESYNC_TYPE_MUTEX) { -+ put_obj(mutex); -+ return -EINVAL; -+ } -+ -+ if (atomic_read(&mutex->all_hint) > 0) { -+ spin_lock(&dev->wait_all_lock); -+ spin_lock(&mutex->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 winesync_schedule(const struct winesync_q *q, ktime_t *timeout) - { - int ret = 0; -@@ -742,6 +811,8 @@ static long winesync_char_ioctl(struct file *file, unsigned int cmd, - return winesync_delete(dev, argp); - case WINESYNC_IOC_PUT_SEM: - return winesync_put_sem(dev, argp); -+ case WINESYNC_IOC_PUT_MUTEX: -+ return winesync_put_mutex(dev, argp); - case WINESYNC_IOC_WAIT_ANY: - return winesync_wait_any(dev, argp); - case WINESYNC_IOC_WAIT_ALL: -diff --git a/include/uapi/linux/winesync.h b/include/uapi/linux/winesync.h -index 0c58181ae05c..c72149082828 100644 ---- a/include/uapi/linux/winesync.h -+++ b/include/uapi/linux/winesync.h -@@ -46,5 +46,7 @@ struct winesync_wait_args { - struct winesync_wait_args) - #define WINESYNC_IOC_CREATE_MUTEX _IOWR(WINESYNC_IOC_BASE, 5, \ - struct winesync_mutex_args) -+#define WINESYNC_IOC_PUT_MUTEX _IOWR(WINESYNC_IOC_BASE, 6, \ -+ struct winesync_mutex_args) - - #endif --- -2.34.1 - -From d24545c3b550a9e05878b8a478c0765f1d41cd82 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <z.figura12@gmail.com> -Date: Fri, 5 Mar 2021 11:46:46 -0600 -Subject: [PATCH 10/25] winesync: Introduce WINESYNC_IOC_KILL_OWNER. - ---- - drivers/misc/winesync.c | 80 ++++++++++++++++++++++++++++++++++- - include/uapi/linux/winesync.h | 1 + - 2 files changed, 79 insertions(+), 2 deletions(-) - -diff --git a/drivers/misc/winesync.c b/drivers/misc/winesync.c -index d07ebd4c8c1c..e6901ac6d949 100644 ---- a/drivers/misc/winesync.c -+++ b/drivers/misc/winesync.c -@@ -66,6 +66,7 @@ struct winesync_obj { - struct { - __u32 count; - __u32 owner; -+ bool ownerdead; - } mutex; - } u; - }; -@@ -89,6 +90,7 @@ struct winesync_q { - atomic_t signaled; - - bool all; -+ bool ownerdead; - __u32 count; - struct winesync_q_entry entries[]; - }; -@@ -230,6 +232,9 @@ static void try_wake_all(struct winesync_device *dev, struct winesync_q *q, - obj->u.sem.count--; - break; - case WINESYNC_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; -@@ -290,6 +295,9 @@ static void try_wake_any_mutex(struct winesync_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); -@@ -513,6 +521,71 @@ static int winesync_put_mutex(struct winesync_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 winesync_obj *mutex) -+{ -+ lockdep_assert_held(&mutex->lock); -+ -+ mutex->u.mutex.ownerdead = true; -+ mutex->u.mutex.owner = 0; -+ mutex->u.mutex.count = 0; -+} -+ -+static int winesync_kill_owner(struct winesync_device *dev, void __user *argp) -+{ -+ struct winesync_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 != WINESYNC_TYPE_MUTEX) { -+ put_obj(obj); -+ continue; -+ } -+ -+ if (atomic_read(&obj->all_hint) > 0) { -+ spin_lock(&dev->wait_all_lock); -+ spin_lock(&obj->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 winesync_schedule(const struct winesync_q *q, ktime_t *timeout) - { - int ret = 0; -@@ -590,6 +663,7 @@ static int setup_wait(struct winesync_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++) { -@@ -701,7 +775,7 @@ static int winesync_wait_any(struct winesync_device *dev, void __user *argp) - struct winesync_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; -@@ -783,7 +857,7 @@ static int winesync_wait_all(struct winesync_device *dev, void __user *argp) - struct winesync_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; -@@ -813,6 +887,8 @@ static long winesync_char_ioctl(struct file *file, unsigned int cmd, - return winesync_put_sem(dev, argp); - case WINESYNC_IOC_PUT_MUTEX: - return winesync_put_mutex(dev, argp); -+ case WINESYNC_IOC_KILL_OWNER: -+ return winesync_kill_owner(dev, argp); - case WINESYNC_IOC_WAIT_ANY: - return winesync_wait_any(dev, argp); - case WINESYNC_IOC_WAIT_ALL: -diff --git a/include/uapi/linux/winesync.h b/include/uapi/linux/winesync.h -index c72149082828..59b1cfcbf00a 100644 ---- a/include/uapi/linux/winesync.h -+++ b/include/uapi/linux/winesync.h -@@ -48,5 +48,6 @@ struct winesync_wait_args { - struct winesync_mutex_args) - #define WINESYNC_IOC_PUT_MUTEX _IOWR(WINESYNC_IOC_BASE, 6, \ - struct winesync_mutex_args) -+#define WINESYNC_IOC_KILL_OWNER _IOW (WINESYNC_IOC_BASE, 7, __u32) - - #endif --- -2.34.1 - -From 9826f3a3e702322335cb74e8c648f223a1be1ca6 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <z.figura12@gmail.com> -Date: Fri, 5 Mar 2021 11:47:55 -0600 -Subject: [PATCH 11/25] winesync: Introduce WINESYNC_IOC_READ_SEM. - ---- - drivers/misc/winesync.c | 33 +++++++++++++++++++++++++++++++++ - include/uapi/linux/winesync.h | 2 ++ - 2 files changed, 35 insertions(+) - -diff --git a/drivers/misc/winesync.c b/drivers/misc/winesync.c -index e6901ac6d949..aff9c5d9b48c 100644 ---- a/drivers/misc/winesync.c -+++ b/drivers/misc/winesync.c -@@ -521,6 +521,37 @@ static int winesync_put_mutex(struct winesync_device *dev, void __user *argp) - return ret; - } - -+static int winesync_read_sem(struct winesync_device *dev, void __user *argp) -+{ -+ struct winesync_sem_args __user *user_args = argp; -+ struct winesync_sem_args args; -+ struct winesync_obj *sem; -+ __u32 id; -+ -+ if (get_user(id, &user_args->sem)) -+ return -EFAULT; -+ -+ sem = get_obj(dev, id); -+ if (!sem) -+ return -EINVAL; -+ if (sem->type != WINESYNC_TYPE_SEM) { -+ put_obj(sem); -+ return -EINVAL; -+ } -+ -+ args.sem = id; -+ spin_lock(&sem->lock); -+ args.count = sem->u.sem.count; -+ args.max = sem->u.sem.max; -+ spin_unlock(&sem->lock); -+ -+ put_obj(sem); -+ -+ if (copy_to_user(user_args, &args, sizeof(args))) -+ return -EFAULT; -+ return 0; -+} -+ - /* - * Actually change the mutex state to mark its owner as dead. - */ -@@ -887,6 +918,8 @@ static long winesync_char_ioctl(struct file *file, unsigned int cmd, - return winesync_put_sem(dev, argp); - case WINESYNC_IOC_PUT_MUTEX: - return winesync_put_mutex(dev, argp); -+ case WINESYNC_IOC_READ_SEM: -+ return winesync_read_sem(dev, argp); - case WINESYNC_IOC_KILL_OWNER: - return winesync_kill_owner(dev, argp); - case WINESYNC_IOC_WAIT_ANY: -diff --git a/include/uapi/linux/winesync.h b/include/uapi/linux/winesync.h -index 59b1cfcbf00a..f18c42f6596b 100644 ---- a/include/uapi/linux/winesync.h -+++ b/include/uapi/linux/winesync.h -@@ -49,5 +49,7 @@ struct winesync_wait_args { - #define WINESYNC_IOC_PUT_MUTEX _IOWR(WINESYNC_IOC_BASE, 6, \ - struct winesync_mutex_args) - #define WINESYNC_IOC_KILL_OWNER _IOW (WINESYNC_IOC_BASE, 7, __u32) -+#define WINESYNC_IOC_READ_SEM _IOWR(WINESYNC_IOC_BASE, 8, \ -+ struct winesync_sem_args) - - #endif --- -2.34.1 - -From d07e942258dfa43a9785cdab1912e369e0b36e2c Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <z.figura12@gmail.com> -Date: Fri, 5 Mar 2021 11:48:10 -0600 -Subject: [PATCH 12/25] winesync: Introduce WINESYNC_IOC_READ_MUTEX. - ---- - drivers/misc/winesync.c | 35 +++++++++++++++++++++++++++++++++++ - include/uapi/linux/winesync.h | 2 ++ - 2 files changed, 37 insertions(+) - -diff --git a/drivers/misc/winesync.c b/drivers/misc/winesync.c -index aff9c5d9b48c..a9a6d1b7970a 100644 ---- a/drivers/misc/winesync.c -+++ b/drivers/misc/winesync.c -@@ -552,6 +552,39 @@ static int winesync_read_sem(struct winesync_device *dev, void __user *argp) - return 0; - } - -+static int winesync_read_mutex(struct winesync_device *dev, void __user *argp) -+{ -+ struct winesync_mutex_args __user *user_args = argp; -+ struct winesync_mutex_args args; -+ struct winesync_obj *mutex; -+ __u32 id; -+ int ret; -+ -+ if (get_user(id, &user_args->mutex)) -+ return -EFAULT; -+ -+ mutex = get_obj(dev, id); -+ if (!mutex) -+ return -EINVAL; -+ if (mutex->type != WINESYNC_TYPE_MUTEX) { -+ put_obj(mutex); -+ return -EINVAL; -+ } -+ -+ args.mutex = id; -+ 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); -+ -+ put_obj(mutex); -+ -+ if (copy_to_user(user_args, &args, sizeof(args))) -+ return -EFAULT; -+ return ret; -+} -+ - /* - * Actually change the mutex state to mark its owner as dead. - */ -@@ -920,6 +953,8 @@ static long winesync_char_ioctl(struct file *file, unsigned int cmd, - return winesync_put_mutex(dev, argp); - case WINESYNC_IOC_READ_SEM: - return winesync_read_sem(dev, argp); -+ case WINESYNC_IOC_READ_MUTEX: -+ return winesync_read_mutex(dev, argp); - case WINESYNC_IOC_KILL_OWNER: - return winesync_kill_owner(dev, argp); - case WINESYNC_IOC_WAIT_ANY: -diff --git a/include/uapi/linux/winesync.h b/include/uapi/linux/winesync.h -index f18c42f6596b..1dccdb3877ec 100644 ---- a/include/uapi/linux/winesync.h -+++ b/include/uapi/linux/winesync.h -@@ -51,5 +51,7 @@ struct winesync_wait_args { - #define WINESYNC_IOC_KILL_OWNER _IOW (WINESYNC_IOC_BASE, 7, __u32) - #define WINESYNC_IOC_READ_SEM _IOWR(WINESYNC_IOC_BASE, 8, \ - struct winesync_sem_args) -+#define WINESYNC_IOC_READ_MUTEX _IOWR(WINESYNC_IOC_BASE, 9, \ -+ struct winesync_mutex_args) - - #endif --- -2.34.1 - -From 1782cc3e3647cd8fe39fe6765f106b88d669d374 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <z.figura12@gmail.com> -Date: Fri, 5 Mar 2021 11:50:49 -0600 -Subject: [PATCH 13/25] doc: Add documentation for the winesync uAPI. - ---- - Documentation/userspace-api/index.rst | 1 + - Documentation/userspace-api/winesync.rst | 345 +++++++++++++++++++++++ - 2 files changed, 346 insertions(+) - create mode 100644 Documentation/userspace-api/winesync.rst - -diff --git a/Documentation/userspace-api/index.rst b/Documentation/userspace-api/index.rst -index c432be070f67..fde565a8005c 100644 ---- a/Documentation/userspace-api/index.rst -+++ b/Documentation/userspace-api/index.rst -@@ -28,6 +28,7 @@ place where this information is gathered. - sysfs-platform_profile - vduse - futex2 -+ winesync - - .. only:: subproject and html - -diff --git a/Documentation/userspace-api/winesync.rst b/Documentation/userspace-api/winesync.rst -new file mode 100644 -index 000000000000..009171a187b7 ---- /dev/null -+++ b/Documentation/userspace-api/winesync.rst -@@ -0,0 +1,345 @@ -+===================================== -+Wine synchronization primitive driver -+===================================== -+ -+This page documents the user-space API for the winesync driver. -+ -+winesync is a support driver for emulation of NT synchronization -+primitives by the Wine project. It exists because implementation in -+user-space, using existing tools, cannot simultaneously satisfy -+performance, correctness, and security constraints. It is implemented -+entirely in software, and does not drive any hardware device. -+ -+This interface is meant as a compatibility tool only, and should not -+be used for general synchronization. Instead use generic, versatile -+interfaces such as futex(2) and poll(2). -+ -+Synchronization primitives -+========================== -+ -+The winesync driver exposes two types of synchronization primitives, -+semaphores and mutexes. -+ -+A semaphore holds a single volatile 32-bit counter, and a static -+32-bit integer denoting the maximum value. It is considered signaled -+when the counter is nonzero. The counter is decremented by one when a -+wait is satisfied. Both the initial and maximum count are established -+when the semaphore is created. -+ -+A mutex holds a volatile 32-bit recursion count, and a volatile 32-bit -+identifier denoting its owner. A mutex is considered signaled when its -+owner is zero (indicating that it is not owned). The recursion count -+is incremented when a wait is satisfied, and ownership is set to the -+given identifier. -+ -+A mutex also holds an internal flag denoting whether its previous -+owner has died; such a mutex is said to be inconsistent. Owner death -+is not tracked automatically based on thread death, but rather must be -+communicated using ``WINESYNC_IOC_KILL_OWNER``. An inconsistent mutex -+is inherently considered unowned. -+ -+Except for the "unowned" semantics of zero, the actual value of the -+owner identifier is not interpreted by the winesync driver at all. The -+intended use is to store a thread identifier; however, the winesync -+driver does not actually validate that a calling thread provides -+consistent or unique identifiers. -+ -+Objects are represented by unsigned 32-bit integers. -+ -+Char device -+=========== -+ -+The winesync driver creates a single char device /dev/winesync. Each -+file description opened on the device represents a unique namespace. -+That is, objects created on one open file description are shared -+across all its individual descriptors, but are not shared with other -+open() calls on the same device. The same file description may be -+shared across multiple processes. -+ -+ioctl reference -+=============== -+ -+All operations on the device are done through ioctls. There are three -+structures used in ioctl calls:: -+ -+ struct winesync_sem_args { -+ __u32 sem; -+ __u32 count; -+ __u32 max; -+ }; -+ -+ struct winesync_mutex_args { -+ __u32 mutex; -+ __u32 owner; -+ __u32 count; -+ }; -+ -+ struct winesync_wait_args { -+ __u64 sigmask; -+ __u64 sigsetsize; -+ __u64 timeout; -+ __u64 objs; -+ __u32 count; -+ __u32 owner; -+ __u32 index; -+ __u32 pad; -+ }; -+ -+Depending on the ioctl, members of the structure may be used as input, -+output, or not at all. -+ -+All ioctls return 0 on success, and -1 on error, in which case `errno` -+will be set to a nonzero error code. -+ -+The ioctls are as follows: -+ -+.. c:macro:: WINESYNC_IOC_CREATE_SEM -+ -+ Create a semaphore object. Takes a pointer to struct -+ :c:type:`winesync_sem_args`, which is used as follows: -+ -+ ``count`` and ``max`` are input-only arguments, denoting the -+ initial and maximum count of the semaphore. -+ -+ ``sem`` is an output-only argument, which will be filled with the -+ identifier of the created semaphore if successful. -+ -+ Fails with ``EINVAL`` if ``count`` is greater than ``max``, or -+ ``ENOMEM`` if not enough memory is available. -+ -+.. c:macro:: WINESYNC_IOC_CREATE_MUTEX -+ -+ Create a mutex object. Takes a pointer to struct -+ :c:type:`winesync_mutex_args`, which is used as follows: -+ -+ ``owner`` is an input-only argument denoting the initial owner of -+ the mutex. -+ -+ ``count`` is an input-only argument denoting the initial recursion -+ count of the mutex. If ``owner`` is nonzero and ``count`` is zero, -+ or if ``owner`` is zero and ``count`` is nonzero, the function -+ fails with ``EINVAL``. -+ -+ ``mutex`` is an output-only argument, which will be filled with -+ the identifier of the created mutex if successful. -+ -+ Fails with ``ENOMEM`` if not enough memory is available. -+ -+.. c:macro:: WINESYNC_IOC_DELETE -+ -+ Delete an object of any type. Takes an input-only pointer to a -+ 32-bit integer denoting the object to delete. Fails with ``EINVAL`` -+ if the object is not valid. Further ioctls attempting to use the -+ object return ``EINVAL``, unless the object identifier is reused for -+ another object. -+ -+ Wait ioctls currently in progress are not interrupted, and behave as -+ if the object remains valid. -+ -+.. c:macro:: WINESYNC_IOC_PUT_SEM -+ -+ Post to a semaphore object. Takes a pointer to struct -+ :c:type:`winesync_sem_args`, which is used as follows: -+ -+ ``sem`` is an input-only argument denoting the semaphore object. -+ If ``sem`` does not identify a valid semaphore object, the ioctl -+ fails with ``EINVAL``. -+ -+ ``count`` contains on input the count to add to the semaphore, and -+ on output is filled with its previous count. -+ -+ ``max`` is not used. -+ -+ If adding ``count`` to the semaphore's current count would raise the -+ latter past the semaphore's maximum count, the ioctl fails with -+ ``EOVERFLOW`` and the semaphore is not affected. If raising the -+ semaphore's count causes it to become signaled, eligible threads -+ waiting on this semaphore will be woken and the semaphore's count -+ decremented appropriately. -+ -+ The operation is atomic and totally ordered with respect to other -+ operations on the same semaphore. -+ -+.. c:macro:: WINESYNC_IOC_PUT_MUTEX -+ -+ Release a mutex object. Takes a pointer to struct -+ :c:type:`winesync_mutex_args`, which is used as follows: -+ -+ ``mutex`` is an input-only argument denoting the mutex object. If -+ ``mutex`` does not identify a valid mutex object, the ioctl fails -+ with ``EINVAL``. -+ -+ ``owner`` is an input-only argument denoting the mutex owner. If -+ ``owner`` is zero, the ioctl fails with ``EINVAL``. If ``owner`` -+ is not the current owner of the mutex, the ioctl fails with -+ ``EPERM``. -+ -+ ``count`` is an output-only argument which will be filled on -+ success with the mutex's previous recursion count. -+ -+ The mutex's count will be decremented by one. If decrementing the -+ mutex's count causes it to become zero, the mutex is marked as -+ unowned and signaled, and eligible threads waiting on it will be -+ woken as appropriate. -+ -+ The operation is atomic and totally ordered with respect to other -+ operations on the same mutex. -+ -+.. c:macro:: WINESYNC_IOC_READ_SEM -+ -+ Read the current state of a semaphore object. Takes a pointer to -+ struct :c:type:`winesync_sem_args`, which is used as follows: -+ -+ ``sem`` is an input-only argument denoting the semaphore object. -+ If ``sem`` does not identify a valid semaphore object, the ioctl -+ fails with ``EINVAL``. -+ -+ ``count`` and ``max`` are output-only arguments, which will be -+ filled with the current and maximum count of the given semaphore. -+ -+ The operation is atomic and totally ordered with respect to other -+ operations on the same semaphore. -+ -+.. c:macro:: WINESYNC_IOC_READ_MUTEX -+ -+ Read the current state of a mutex object. Takes a pointer to struct -+ :c:type:`winesync_mutex_args`, which is used as follows: -+ -+ ``mutex`` is an input-only argument denoting the mutex object. If -+ ``mutex`` does not identify a valid mutex object, the ioctl fails -+ with ``EINVAL``. -+ -+ ``count`` and ``owner`` are output-only arguments, which will be -+ filled with the current recursion count and owner of the given -+ mutex. If the mutex is not owned, both ``count`` and ``owner`` are -+ set to zero. -+ -+ If the mutex is marked as inconsistent, the function fails with -+ ``EOWNERDEAD``. In this case, ``count`` and ``owner`` are set to -+ zero. -+ -+ The operation is atomic and totally ordered with respect to other -+ operations on the same mutex. -+ -+.. c:macro:: WINESYNC_IOC_KILL_OWNER -+ -+ Mark any mutexes owned by the given owner as unowned and -+ inconsistent. Takes an input-only pointer to a 32-bit integer -+ denoting the owner. If the owner is zero, the ioctl fails with -+ ``EINVAL``. -+ -+ For each mutex currently owned by the given owner, eligible threads -+ waiting on said mutex will be woken as appropriate (and such waits -+ will fail with ``EOWNERDEAD``, as described below). -+ -+ The operation as a whole is not atomic; however, the modification of -+ each mutex is atomic and totally ordered with respect to other -+ operations on the same mutex. -+ -+.. c:macro:: WINESYNC_IOC_WAIT_ANY -+ -+ Poll on any of a list of objects, atomically acquiring at most one. -+ Takes a pointer to struct :c:type:`winesync_wait_args`, which is -+ used as follows: -+ -+ ``sigmask`` is an optional input-only pointer to a -+ :c:type:`sigset_t` structure (specified as an integer so that the -+ :c:type:`winesync_wait_args` structure has the same size -+ regardless of architecture). If the pointer is not NULL, it holds -+ a signal mask which will be applied to the current thread for the -+ duration of the call, in the same fashion as ``pselect(2)``. -+ -+ ``sigsetsize`` specifies the size of the :c:type:`sigset_t` -+ structure passed in ``sigmask``. It is ignored if ``sigmask`` is -+ NULL. -+ -+ ``timeout`` is an optional input-only pointer to a 64-bit struct -+ :c:type:`timespec` (specified as an integer so that the structure -+ has the same size regardless of architecture). The timeout is -+ specified in absolute format, as measured against the MONOTONIC -+ clock. If the timeout is equal to or earlier than the current -+ time, the function returns immediately without sleeping. If -+ ``timeout`` is zero, i.e. NULL, the function will sleep until an -+ object is signaled, and will not fail with ``ETIMEDOUT``. -+ -+ ``objs`` is a input-only pointer to an array of ``count`` 32-bit -+ object identifiers (specified as an integer so that the structure -+ has the same size regardless of architecture). If any identifier -+ is invalid, the function fails with ``EINVAL``. -+ -+ ``owner`` is an input-only argument denoting the mutex owner -+ identifier. If any object in ``objs`` is a mutex, the ioctl will -+ attempt to acquire that mutex on behalf of ``owner``. If ``owner`` -+ is zero, the ioctl fails with ``EINVAL``. -+ -+ ``index`` is an output-only argument which, if the ioctl is -+ successful, is filled with the index of the object actually -+ signaled. If unsuccessful, ``index`` is not modified. -+ -+ ``pad`` is unused, and exists to keep a consistent structure size. -+ -+ This function attempts to acquire one of the given objects. If -+ unable to do so, it sleeps until an object becomes signaled, -+ subsequently acquiring it, or the timeout expires. In the latter -+ case the ioctl fails with ``ETIMEDOUT``. The function only acquires -+ one object, even if multiple objects are signaled. -+ -+ A semaphore is considered to be signaled if its count is nonzero, -+ and is acquired by decrementing its count by one. A mutex is -+ considered to be signaled if it is unowned or if its owner matches -+ the ``owner`` argument, and is acquired by incrementing its -+ recursion count by one and setting its owner to the ``owner`` -+ argument. -+ -+ Acquisition is atomic and totally ordered with respect to other -+ operations on the same object. If two wait operations (with -+ different ``owner`` identifiers) are queued on the same mutex, only -+ one is signaled. If two wait operations are queued on the same -+ semaphore, and a value of one is posted to it, only one is signaled. -+ The order in which threads are signaled is not specified. -+ -+ If an inconsistent mutex is acquired, the ioctl fails with -+ ``EOWNERDEAD``. Although this is a failure return, the function may -+ otherwise be considered successful. The mutex is marked as owned by -+ the given owner (with a recursion count of 1) and as no longer -+ inconsistent, and ``index`` is still set to the index of the mutex. -+ -+ It is valid to pass the same object more than once. If a wakeup -+ occurs due to that object being signaled, ``index`` is set to the -+ lowest index corresponding to that object. -+ -+ Fails with ``ENOMEM`` if not enough memory is available, or -+ ``EINTR`` if a signal is received. -+ -+.. c:macro:: WINESYNC_IOC_WAIT_ALL -+ -+ Poll on a list of objects, atomically acquiring all of them. Takes a -+ pointer to struct :c:type:`winesync_wait_args`, which is used -+ identically to ``WINESYNC_IOC_WAIT_ANY``, except that ``index`` is -+ always filled with zero on success. -+ -+ This function attempts to simultaneously acquire all of the given -+ objects. If unable to do so, it sleeps until all objects become -+ simultaneously signaled, subsequently acquiring them, or the timeout -+ expires. In the latter case the ioctl fails with ``ETIMEDOUT`` and -+ no objects are modified. -+ -+ Objects may become signaled and subsequently designaled (through -+ acquisition by other threads) while this thread is sleeping. Only -+ once all objects are simultaneously signaled does the ioctl acquire -+ them and return. The entire acquisition is atomic and totally -+ ordered with respect to other operations on any of the given -+ objects. -+ -+ If an inconsistent mutex is acquired, the ioctl fails with -+ ``EOWNERDEAD``. Similarly to ``WINESYNC_IOC_WAIT_ANY``, all objects -+ are nevertheless marked as acquired. Note that if multiple mutex -+ objects are specified, there is no way to know which were marked as -+ inconsistent. -+ -+ Unlike ``WINESYNC_IOC_WAIT_ANY``, it is not valid to pass the same -+ object more than once. If this is attempted, the function fails with -+ ``EINVAL``. -+ -+ Fails with ``ENOMEM`` if not enough memory is available, or -+ ``EINTR`` if a signal is received. --- -2.34.1 - -From 9453c81c3208b6fddeb80886f5ef7141b897640b Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <z.figura12@gmail.com> -Date: Fri, 5 Mar 2021 12:06:23 -0600 -Subject: [PATCH 14/25] selftests: winesync: Add some tests for semaphore - state. - ---- - tools/testing/selftests/Makefile | 1 + - .../selftests/drivers/winesync/Makefile | 8 + - .../testing/selftests/drivers/winesync/config | 1 + - .../selftests/drivers/winesync/winesync.c | 153 ++++++++++++++++++ - 4 files changed, 163 insertions(+) - create mode 100644 tools/testing/selftests/drivers/winesync/Makefile - create mode 100644 tools/testing/selftests/drivers/winesync/config - create mode 100644 tools/testing/selftests/drivers/winesync/winesync.c - -diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile -index c852eb40c4f7..a366016d6254 100644 ---- a/tools/testing/selftests/Makefile -+++ b/tools/testing/selftests/Makefile -@@ -9,6 +9,7 @@ TARGETS += core - TARGETS += cpufreq - TARGETS += cpu-hotplug - TARGETS += drivers/dma-buf -+TARGETS += drivers/winesync - TARGETS += efivarfs - TARGETS += exec - TARGETS += filesystems -diff --git a/tools/testing/selftests/drivers/winesync/Makefile b/tools/testing/selftests/drivers/winesync/Makefile -new file mode 100644 -index 000000000000..43b39fdeea10 ---- /dev/null -+++ b/tools/testing/selftests/drivers/winesync/Makefile -@@ -0,0 +1,8 @@ -+# SPDX-LICENSE-IDENTIFIER: GPL-2.0-only -+TEST_GEN_PROGS := winesync -+ -+top_srcdir =../../../../.. -+CFLAGS += -I$(top_srcdir)/usr/include -+LDLIBS += -lpthread -+ -+include ../../lib.mk -diff --git a/tools/testing/selftests/drivers/winesync/config b/tools/testing/selftests/drivers/winesync/config -new file mode 100644 -index 000000000000..60539c826d06 ---- /dev/null -+++ b/tools/testing/selftests/drivers/winesync/config -@@ -0,0 +1 @@ -+CONFIG_WINESYNC=y -diff --git a/tools/testing/selftests/drivers/winesync/winesync.c b/tools/testing/selftests/drivers/winesync/winesync.c -new file mode 100644 -index 000000000000..da3aa2c24671 ---- /dev/null -+++ b/tools/testing/selftests/drivers/winesync/winesync.c -@@ -0,0 +1,153 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Various unit tests for the "winesync" synchronization primitive driver. -+ * -+ * Copyright (C) 2021 Zebediah Figura -+ */ -+ -+#define _GNU_SOURCE -+#include <sys/ioctl.h> -+#include <sys/stat.h> -+#include <fcntl.h> -+#include <time.h> -+#include <pthread.h> -+#include <linux/winesync.h> -+#include "../../kselftest_harness.h" -+ -+TEST(semaphore_state) -+{ -+ struct winesync_wait_args wait_args = {0}; -+ struct winesync_sem_args sem_args; -+ struct timespec timeout; -+ int fd, ret; -+ -+ clock_gettime(CLOCK_MONOTONIC, &timeout); -+ -+ fd = open("/dev/winesync", O_CLOEXEC | O_RDONLY); -+ ASSERT_LE(0, fd); -+ -+ sem_args.count = 3; -+ sem_args.max = 2; -+ sem_args.sem = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_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, WINESYNC_IOC_CREATE_SEM, &sem_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_NE(0xdeadbeef, sem_args.sem); -+ -+ sem_args.count = 0xdeadbeef; -+ sem_args.max = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_READ_SEM, &sem_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(2, sem_args.count); -+ EXPECT_EQ(2, sem_args.max); -+ -+ sem_args.count = 0; -+ ret = ioctl(fd, WINESYNC_IOC_PUT_SEM, &sem_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(2, sem_args.count); -+ -+ sem_args.count = 0xdeadbeef; -+ sem_args.max = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_READ_SEM, &sem_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(2, sem_args.count); -+ EXPECT_EQ(2, sem_args.max); -+ -+ sem_args.count = 1; -+ ret = ioctl(fd, WINESYNC_IOC_PUT_SEM, &sem_args); -+ EXPECT_EQ(-1, ret); -+ EXPECT_EQ(EOVERFLOW, errno); -+ -+ sem_args.count = 0xdeadbeef; -+ sem_args.max = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_READ_SEM, &sem_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(2, sem_args.count); -+ EXPECT_EQ(2, sem_args.max); -+ -+ wait_args.timeout = (uintptr_t)&timeout; -+ wait_args.objs = (uintptr_t)&sem_args.sem; -+ wait_args.count = 1; -+ wait_args.owner = 123; -+ wait_args.index = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_WAIT_ANY, &wait_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(0, wait_args.index); -+ -+ sem_args.count = 0xdeadbeef; -+ sem_args.max = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_READ_SEM, &sem_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(1, sem_args.count); -+ EXPECT_EQ(2, sem_args.max); -+ -+ wait_args.index = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_WAIT_ANY, &wait_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(0, wait_args.index); -+ -+ sem_args.count = 0xdeadbeef; -+ sem_args.max = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_READ_SEM, &sem_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(0, sem_args.count); -+ EXPECT_EQ(2, sem_args.max); -+ -+ ret = ioctl(fd, WINESYNC_IOC_WAIT_ANY, &wait_args); -+ EXPECT_EQ(-1, ret); -+ EXPECT_EQ(ETIMEDOUT, errno); -+ -+ sem_args.count = 3; -+ ret = ioctl(fd, WINESYNC_IOC_PUT_SEM, &sem_args); -+ EXPECT_EQ(-1, ret); -+ EXPECT_EQ(EOVERFLOW, errno); -+ -+ sem_args.count = 0xdeadbeef; -+ sem_args.max = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_READ_SEM, &sem_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(0, sem_args.count); -+ EXPECT_EQ(2, sem_args.max); -+ -+ sem_args.count = 2; -+ ret = ioctl(fd, WINESYNC_IOC_PUT_SEM, &sem_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(0, sem_args.count); -+ -+ sem_args.count = 0xdeadbeef; -+ sem_args.max = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_READ_SEM, &sem_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(2, sem_args.count); -+ EXPECT_EQ(2, sem_args.max); -+ -+ ret = ioctl(fd, WINESYNC_IOC_WAIT_ANY, &wait_args); -+ EXPECT_EQ(0, ret); -+ ret = ioctl(fd, WINESYNC_IOC_WAIT_ANY, &wait_args); -+ EXPECT_EQ(0, ret); -+ -+ sem_args.count = 1; -+ ret = ioctl(fd, WINESYNC_IOC_PUT_SEM, &sem_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(0, sem_args.count); -+ -+ sem_args.count = 0xdeadbeef; -+ sem_args.max = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_READ_SEM, &sem_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(1, sem_args.count); -+ EXPECT_EQ(2, sem_args.max); -+ -+ ret = ioctl(fd, WINESYNC_IOC_DELETE, &sem_args.sem); -+ EXPECT_EQ(0, ret); -+ -+ close(fd); -+} -+ -+TEST_HARNESS_MAIN --- -2.34.1 - -From 2d2f5263338184cebd6166cbd9a16ec2484143dd Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <z.figura12@gmail.com> -Date: Fri, 5 Mar 2021 12:07:04 -0600 -Subject: [PATCH 15/25] selftests: winesync: Add some tests for mutex state. - ---- - .../selftests/drivers/winesync/winesync.c | 250 ++++++++++++++++++ - 1 file changed, 250 insertions(+) - -diff --git a/tools/testing/selftests/drivers/winesync/winesync.c b/tools/testing/selftests/drivers/winesync/winesync.c -index da3aa2c24671..f5562a645379 100644 ---- a/tools/testing/selftests/drivers/winesync/winesync.c -+++ b/tools/testing/selftests/drivers/winesync/winesync.c -@@ -150,4 +150,254 @@ TEST(semaphore_state) - close(fd); - } - -+TEST(mutex_state) -+{ -+ struct winesync_wait_args wait_args = {0}; -+ struct winesync_mutex_args mutex_args; -+ struct timespec timeout; -+ __u32 owner; -+ int fd, ret; -+ -+ clock_gettime(CLOCK_MONOTONIC, &timeout); -+ -+ fd = open("/dev/winesync", O_CLOEXEC | O_RDONLY); -+ ASSERT_LE(0, fd); -+ -+ mutex_args.owner = 123; -+ mutex_args.count = 0; -+ ret = ioctl(fd, WINESYNC_IOC_CREATE_MUTEX, &mutex_args); -+ EXPECT_EQ(-1, ret); -+ EXPECT_EQ(EINVAL, errno); -+ -+ mutex_args.owner = 0; -+ mutex_args.count = 2; -+ ret = ioctl(fd, WINESYNC_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, WINESYNC_IOC_CREATE_MUTEX, &mutex_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_NE(0xdeadbeef, mutex_args.mutex); -+ -+ mutex_args.count = 0xdeadbeef; -+ mutex_args.owner = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_READ_MUTEX, &mutex_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(2, mutex_args.count); -+ EXPECT_EQ(123, mutex_args.owner); -+ -+ mutex_args.count = 0xdeadbeef; -+ mutex_args.owner = 0; -+ ret = ioctl(fd, WINESYNC_IOC_PUT_MUTEX, &mutex_args); -+ EXPECT_EQ(-1, ret); -+ EXPECT_EQ(EINVAL, errno); -+ -+ mutex_args.count = 0xdeadbeef; -+ mutex_args.owner = 456; -+ ret = ioctl(fd, WINESYNC_IOC_PUT_MUTEX, &mutex_args); -+ EXPECT_EQ(-1, ret); -+ EXPECT_EQ(EPERM, errno); -+ -+ mutex_args.count = 0xdeadbeef; -+ mutex_args.owner = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_READ_MUTEX, &mutex_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(2, mutex_args.count); -+ EXPECT_EQ(123, mutex_args.owner); -+ -+ mutex_args.count = 0xdeadbeef; -+ mutex_args.owner = 123; -+ ret = ioctl(fd, WINESYNC_IOC_PUT_MUTEX, &mutex_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(2, mutex_args.count); -+ -+ mutex_args.count = 0xdeadbeef; -+ mutex_args.owner = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_READ_MUTEX, &mutex_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(1, mutex_args.count); -+ EXPECT_EQ(123, mutex_args.owner); -+ -+ mutex_args.count = 0xdeadbeef; -+ mutex_args.owner = 123; -+ ret = ioctl(fd, WINESYNC_IOC_PUT_MUTEX, &mutex_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(1, mutex_args.count); -+ -+ mutex_args.count = 0xdeadbeef; -+ mutex_args.owner = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_READ_MUTEX, &mutex_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(0, mutex_args.count); -+ EXPECT_EQ(0, mutex_args.owner); -+ -+ mutex_args.count = 0xdeadbeef; -+ mutex_args.owner = 123; -+ ret = ioctl(fd, WINESYNC_IOC_PUT_MUTEX, &mutex_args); -+ EXPECT_EQ(-1, ret); -+ EXPECT_EQ(EPERM, errno); -+ -+ wait_args.timeout = (uintptr_t)&timeout; -+ wait_args.objs = (uintptr_t)&mutex_args.mutex; -+ wait_args.count = 1; -+ wait_args.owner = 456; -+ wait_args.index = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_WAIT_ANY, &wait_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(0, wait_args.index); -+ -+ mutex_args.count = 0xdeadbeef; -+ mutex_args.owner = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_READ_MUTEX, &mutex_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(1, mutex_args.count); -+ EXPECT_EQ(456, mutex_args.owner); -+ -+ wait_args.owner = 456; -+ wait_args.index = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_WAIT_ANY, &wait_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(0, wait_args.index); -+ -+ mutex_args.count = 0xdeadbeef; -+ mutex_args.owner = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_READ_MUTEX, &mutex_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(2, mutex_args.count); -+ EXPECT_EQ(456, mutex_args.owner); -+ -+ mutex_args.count = 0xdeadbeef; -+ mutex_args.owner = 456; -+ ret = ioctl(fd, WINESYNC_IOC_PUT_MUTEX, &mutex_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(2, mutex_args.count); -+ -+ mutex_args.count = 0xdeadbeef; -+ mutex_args.owner = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_READ_MUTEX, &mutex_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(1, mutex_args.count); -+ EXPECT_EQ(456, mutex_args.owner); -+ -+ wait_args.owner = 123; -+ wait_args.index = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_WAIT_ANY, &wait_args); -+ EXPECT_EQ(-1, ret); -+ EXPECT_EQ(ETIMEDOUT, errno); -+ -+ owner = 0; -+ ret = ioctl(fd, WINESYNC_IOC_KILL_OWNER, &owner); -+ EXPECT_EQ(-1, ret); -+ EXPECT_EQ(EINVAL, errno); -+ -+ owner = 123; -+ ret = ioctl(fd, WINESYNC_IOC_KILL_OWNER, &owner); -+ EXPECT_EQ(0, ret); -+ -+ mutex_args.count = 0xdeadbeef; -+ mutex_args.owner = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_READ_MUTEX, &mutex_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(1, mutex_args.count); -+ EXPECT_EQ(456, mutex_args.owner); -+ -+ owner = 456; -+ ret = ioctl(fd, WINESYNC_IOC_KILL_OWNER, &owner); -+ EXPECT_EQ(0, ret); -+ -+ mutex_args.count = 0xdeadbeef; -+ mutex_args.owner = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_READ_MUTEX, &mutex_args); -+ EXPECT_EQ(-1, ret); -+ EXPECT_EQ(EOWNERDEAD, errno); -+ EXPECT_EQ(0, mutex_args.count); -+ EXPECT_EQ(0, mutex_args.owner); -+ -+ mutex_args.count = 0xdeadbeef; -+ mutex_args.owner = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_READ_MUTEX, &mutex_args); -+ EXPECT_EQ(-1, ret); -+ EXPECT_EQ(EOWNERDEAD, errno); -+ EXPECT_EQ(0, mutex_args.count); -+ EXPECT_EQ(0, mutex_args.owner); -+ -+ wait_args.owner = 123; -+ wait_args.index = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_WAIT_ANY, &wait_args); -+ EXPECT_EQ(-1, ret); -+ EXPECT_EQ(EOWNERDEAD, errno); -+ EXPECT_EQ(0, wait_args.index); -+ -+ mutex_args.count = 0xdeadbeef; -+ mutex_args.owner = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_READ_MUTEX, &mutex_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(1, mutex_args.count); -+ EXPECT_EQ(123, mutex_args.owner); -+ -+ owner = 123; -+ ret = ioctl(fd, WINESYNC_IOC_KILL_OWNER, &owner); -+ EXPECT_EQ(0, ret); -+ -+ mutex_args.count = 0xdeadbeef; -+ mutex_args.owner = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_READ_MUTEX, &mutex_args); -+ EXPECT_EQ(-1, ret); -+ EXPECT_EQ(EOWNERDEAD, errno); -+ EXPECT_EQ(0, mutex_args.count); -+ EXPECT_EQ(0, mutex_args.owner); -+ -+ wait_args.owner = 123; -+ wait_args.index = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_WAIT_ANY, &wait_args); -+ EXPECT_EQ(-1, ret); -+ EXPECT_EQ(EOWNERDEAD, errno); -+ EXPECT_EQ(0, wait_args.index); -+ -+ mutex_args.count = 0xdeadbeef; -+ mutex_args.owner = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_READ_MUTEX, &mutex_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(1, mutex_args.count); -+ EXPECT_EQ(123, mutex_args.owner); -+ -+ ret = ioctl(fd, WINESYNC_IOC_DELETE, &mutex_args.mutex); -+ EXPECT_EQ(0, ret); -+ -+ mutex_args.owner = 0; -+ mutex_args.count = 0; -+ mutex_args.mutex = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_CREATE_MUTEX, &mutex_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_NE(0xdeadbeef, mutex_args.mutex); -+ -+ mutex_args.count = 0xdeadbeef; -+ mutex_args.owner = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_READ_MUTEX, &mutex_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(0, mutex_args.count); -+ EXPECT_EQ(0, mutex_args.owner); -+ -+ wait_args.owner = 123; -+ wait_args.index = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_WAIT_ANY, &wait_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(0, wait_args.index); -+ -+ mutex_args.count = 0xdeadbeef; -+ mutex_args.owner = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_READ_MUTEX, &mutex_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(1, mutex_args.count); -+ EXPECT_EQ(123, mutex_args.owner); -+ -+ ret = ioctl(fd, WINESYNC_IOC_DELETE, &mutex_args.mutex); -+ EXPECT_EQ(0, ret); -+ -+ close(fd); -+} -+ - TEST_HARNESS_MAIN --- -2.34.1 - -From c5dbac5e814a4b73d98357fb010da08c28556e18 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <z.figura12@gmail.com> -Date: Fri, 5 Mar 2021 12:07:45 -0600 -Subject: [PATCH 16/25] selftests: winesync: Add some tests for - WINESYNC_IOC_WAIT_ANY. - ---- - .../selftests/drivers/winesync/winesync.c | 197 ++++++++++++++++++ - 1 file changed, 197 insertions(+) - -diff --git a/tools/testing/selftests/drivers/winesync/winesync.c b/tools/testing/selftests/drivers/winesync/winesync.c -index f5562a645379..1147ebb227da 100644 ---- a/tools/testing/selftests/drivers/winesync/winesync.c -+++ b/tools/testing/selftests/drivers/winesync/winesync.c -@@ -400,4 +400,201 @@ TEST(mutex_state) - close(fd); - } - -+TEST(wait_any) -+{ -+ struct winesync_mutex_args mutex_args = {0}; -+ struct winesync_wait_args wait_args = {0}; -+ struct winesync_sem_args sem_args = {0}; -+ struct timespec timeout; -+ __u32 objs[2], owner; -+ int fd, ret; -+ -+ clock_gettime(CLOCK_MONOTONIC, &timeout); -+ -+ fd = open("/dev/winesync", O_CLOEXEC | O_RDONLY); -+ ASSERT_LE(0, fd); -+ -+ sem_args.count = 2; -+ sem_args.max = 3; -+ sem_args.sem = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_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, WINESYNC_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 = (uintptr_t)&timeout; -+ wait_args.objs = (uintptr_t)objs; -+ wait_args.count = 2; -+ wait_args.owner = 123; -+ wait_args.index = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_WAIT_ANY, &wait_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(0, wait_args.index); -+ EXPECT_EQ((uintptr_t)objs, wait_args.objs); -+ EXPECT_EQ(2, wait_args.count); -+ EXPECT_EQ(123, wait_args.owner); -+ -+ sem_args.count = 0xdeadbeef; -+ sem_args.max = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_READ_SEM, &sem_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(1, sem_args.count); -+ EXPECT_EQ(3, sem_args.max); -+ -+ mutex_args.count = 0xdeadbeef; -+ mutex_args.owner = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_READ_MUTEX, &mutex_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(0, mutex_args.count); -+ EXPECT_EQ(0, mutex_args.owner); -+ -+ wait_args.owner = 123; -+ wait_args.index = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_WAIT_ANY, &wait_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(0, wait_args.index); -+ -+ sem_args.count = 0xdeadbeef; -+ sem_args.max = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_READ_SEM, &sem_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(0, sem_args.count); -+ EXPECT_EQ(3, sem_args.max); -+ -+ mutex_args.count = 0xdeadbeef; -+ mutex_args.owner = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_READ_MUTEX, &mutex_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(0, mutex_args.count); -+ EXPECT_EQ(0, mutex_args.owner); -+ -+ wait_args.owner = 123; -+ wait_args.index = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_WAIT_ANY, &wait_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(1, wait_args.index); -+ -+ sem_args.count = 0xdeadbeef; -+ sem_args.max = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_READ_SEM, &sem_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(0, sem_args.count); -+ EXPECT_EQ(3, sem_args.max); -+ -+ mutex_args.count = 0xdeadbeef; -+ mutex_args.owner = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_READ_MUTEX, &mutex_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(1, mutex_args.count); -+ EXPECT_EQ(123, mutex_args.owner); -+ -+ sem_args.count = 1; -+ ret = ioctl(fd, WINESYNC_IOC_PUT_SEM, &sem_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(0, sem_args.count); -+ -+ wait_args.owner = 123; -+ wait_args.index = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_WAIT_ANY, &wait_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(0, wait_args.index); -+ -+ sem_args.count = 0xdeadbeef; -+ sem_args.max = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_READ_SEM, &sem_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(0, sem_args.count); -+ EXPECT_EQ(3, sem_args.max); -+ -+ mutex_args.count = 0xdeadbeef; -+ mutex_args.owner = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_READ_MUTEX, &mutex_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(1, mutex_args.count); -+ EXPECT_EQ(123, mutex_args.owner); -+ -+ wait_args.owner = 123; -+ wait_args.index = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_WAIT_ANY, &wait_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(1, wait_args.index); -+ -+ sem_args.count = 0xdeadbeef; -+ sem_args.max = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_READ_SEM, &sem_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(0, sem_args.count); -+ EXPECT_EQ(3, sem_args.max); -+ -+ mutex_args.count = 0xdeadbeef; -+ mutex_args.owner = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_READ_MUTEX, &mutex_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(2, mutex_args.count); -+ EXPECT_EQ(123, mutex_args.owner); -+ -+ wait_args.owner = 456; -+ wait_args.index = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_WAIT_ANY, &wait_args); -+ EXPECT_EQ(-1, ret); -+ EXPECT_EQ(ETIMEDOUT, errno); -+ -+ owner = 123; -+ ret = ioctl(fd, WINESYNC_IOC_KILL_OWNER, &owner); -+ EXPECT_EQ(0, ret); -+ -+ wait_args.owner = 456; -+ wait_args.index = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_WAIT_ANY, &wait_args); -+ EXPECT_EQ(-1, ret); -+ EXPECT_EQ(EOWNERDEAD, errno); -+ EXPECT_EQ(1, wait_args.index); -+ -+ wait_args.owner = 456; -+ wait_args.index = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_WAIT_ANY, &wait_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(1, wait_args.index); -+ -+ /* test waiting on the same object twice */ -+ sem_args.count = 2; -+ ret = ioctl(fd, WINESYNC_IOC_PUT_SEM, &sem_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(0, sem_args.count); -+ -+ objs[0] = objs[1] = sem_args.sem; -+ ret = ioctl(fd, WINESYNC_IOC_WAIT_ANY, &wait_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(0, wait_args.index); -+ -+ sem_args.count = 0xdeadbeef; -+ sem_args.max = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_READ_SEM, &sem_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(1, sem_args.count); -+ EXPECT_EQ(3, sem_args.max); -+ -+ wait_args.count = 0; -+ wait_args.objs = (uintptr_t)NULL; -+ ret = ioctl(fd, WINESYNC_IOC_WAIT_ANY, &wait_args); -+ EXPECT_EQ(-1, ret); -+ EXPECT_EQ(ETIMEDOUT, errno); -+ -+ ret = ioctl(fd, WINESYNC_IOC_DELETE, &sem_args.sem); -+ EXPECT_EQ(0, ret); -+ ret = ioctl(fd, WINESYNC_IOC_DELETE, &mutex_args.mutex); -+ EXPECT_EQ(0, ret); -+ -+ close(fd); -+} -+ - TEST_HARNESS_MAIN --- -2.34.1 - -From 28fa83f6bb6a5fb7c03cbdc9805b793b7ffa8b54 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <z.figura12@gmail.com> -Date: Fri, 5 Mar 2021 12:08:25 -0600 -Subject: [PATCH 17/25] selftests: winesync: Add some tests for - WINESYNC_IOC_WAIT_ALL. - ---- - .../selftests/drivers/winesync/winesync.c | 151 ++++++++++++++++++ - 1 file changed, 151 insertions(+) - -diff --git a/tools/testing/selftests/drivers/winesync/winesync.c b/tools/testing/selftests/drivers/winesync/winesync.c -index 1147ebb227da..3c8ed06946db 100644 ---- a/tools/testing/selftests/drivers/winesync/winesync.c -+++ b/tools/testing/selftests/drivers/winesync/winesync.c -@@ -597,4 +597,155 @@ TEST(wait_any) - close(fd); - } - -+TEST(wait_all) -+{ -+ struct winesync_mutex_args mutex_args = {0}; -+ struct winesync_wait_args wait_args = {0}; -+ struct winesync_sem_args sem_args = {0}; -+ struct timespec timeout; -+ __u32 objs[2], owner; -+ int fd, ret; -+ -+ clock_gettime(CLOCK_MONOTONIC, &timeout); -+ -+ fd = open("/dev/winesync", O_CLOEXEC | O_RDONLY); -+ ASSERT_LE(0, fd); -+ -+ sem_args.count = 2; -+ sem_args.max = 3; -+ sem_args.sem = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_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, WINESYNC_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 = (uintptr_t)&timeout; -+ wait_args.objs = (uintptr_t)objs; -+ wait_args.count = 2; -+ wait_args.owner = 123; -+ ret = ioctl(fd, WINESYNC_IOC_WAIT_ALL, &wait_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ((uintptr_t)objs, wait_args.objs); -+ EXPECT_EQ(2, wait_args.count); -+ EXPECT_EQ(123, wait_args.owner); -+ -+ sem_args.count = 0xdeadbeef; -+ sem_args.max = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_READ_SEM, &sem_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(1, sem_args.count); -+ EXPECT_EQ(3, sem_args.max); -+ -+ mutex_args.count = 0xdeadbeef; -+ mutex_args.owner = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_READ_MUTEX, &mutex_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(1, mutex_args.count); -+ EXPECT_EQ(123, mutex_args.owner); -+ -+ wait_args.owner = 456; -+ ret = ioctl(fd, WINESYNC_IOC_WAIT_ALL, &wait_args); -+ EXPECT_EQ(-1, ret); -+ EXPECT_EQ(ETIMEDOUT, errno); -+ -+ sem_args.count = 0xdeadbeef; -+ sem_args.max = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_READ_SEM, &sem_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(1, sem_args.count); -+ EXPECT_EQ(3, sem_args.max); -+ -+ mutex_args.count = 0xdeadbeef; -+ mutex_args.owner = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_READ_MUTEX, &mutex_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(1, mutex_args.count); -+ EXPECT_EQ(123, mutex_args.owner); -+ -+ wait_args.owner = 123; -+ ret = ioctl(fd, WINESYNC_IOC_WAIT_ALL, &wait_args); -+ EXPECT_EQ(0, ret); -+ -+ sem_args.count = 0xdeadbeef; -+ sem_args.max = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_READ_SEM, &sem_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(0, sem_args.count); -+ EXPECT_EQ(3, sem_args.max); -+ -+ mutex_args.count = 0xdeadbeef; -+ mutex_args.owner = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_READ_MUTEX, &mutex_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(2, mutex_args.count); -+ EXPECT_EQ(123, mutex_args.owner); -+ -+ ret = ioctl(fd, WINESYNC_IOC_WAIT_ALL, &wait_args); -+ EXPECT_EQ(-1, ret); -+ EXPECT_EQ(ETIMEDOUT, errno); -+ -+ sem_args.count = 0xdeadbeef; -+ sem_args.max = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_READ_SEM, &sem_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(0, sem_args.count); -+ EXPECT_EQ(3, sem_args.max); -+ -+ mutex_args.count = 0xdeadbeef; -+ mutex_args.owner = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_READ_MUTEX, &mutex_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(2, mutex_args.count); -+ EXPECT_EQ(123, mutex_args.owner); -+ -+ sem_args.count = 3; -+ ret = ioctl(fd, WINESYNC_IOC_PUT_SEM, &sem_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(0, sem_args.count); -+ -+ owner = 123; -+ ret = ioctl(fd, WINESYNC_IOC_KILL_OWNER, &owner); -+ EXPECT_EQ(0, ret); -+ -+ ret = ioctl(fd, WINESYNC_IOC_WAIT_ALL, &wait_args); -+ EXPECT_EQ(-1, ret); -+ EXPECT_EQ(EOWNERDEAD, errno); -+ -+ sem_args.count = 0xdeadbeef; -+ sem_args.max = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_READ_SEM, &sem_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(2, sem_args.count); -+ EXPECT_EQ(3, sem_args.max); -+ -+ mutex_args.count = 0xdeadbeef; -+ mutex_args.owner = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_READ_MUTEX, &mutex_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(1, mutex_args.count); -+ EXPECT_EQ(123, mutex_args.owner); -+ -+ /* test waiting on the same object twice */ -+ objs[0] = objs[1] = sem_args.sem; -+ ret = ioctl(fd, WINESYNC_IOC_WAIT_ALL, &wait_args); -+ EXPECT_EQ(-1, ret); -+ EXPECT_EQ(EINVAL, errno); -+ -+ ret = ioctl(fd, WINESYNC_IOC_DELETE, &sem_args.sem); -+ EXPECT_EQ(0, ret); -+ ret = ioctl(fd, WINESYNC_IOC_DELETE, &mutex_args.mutex); -+ EXPECT_EQ(0, ret); -+ -+ close(fd); -+} -+ - TEST_HARNESS_MAIN --- -2.34.1 - -From 4da2c162de716164d8461479794391a2c0e042d1 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <z.figura12@gmail.com> -Date: Fri, 5 Mar 2021 12:08:54 -0600 -Subject: [PATCH 18/25] selftests: winesync: Add some tests for invalid object - handling. - ---- - .../selftests/drivers/winesync/winesync.c | 93 +++++++++++++++++++ - 1 file changed, 93 insertions(+) - -diff --git a/tools/testing/selftests/drivers/winesync/winesync.c b/tools/testing/selftests/drivers/winesync/winesync.c -index 3c8ed06946db..59ad45f46969 100644 ---- a/tools/testing/selftests/drivers/winesync/winesync.c -+++ b/tools/testing/selftests/drivers/winesync/winesync.c -@@ -748,4 +748,97 @@ TEST(wait_all) - close(fd); - } - -+TEST(invalid_objects) -+{ -+ struct winesync_mutex_args mutex_args = {0}; -+ struct winesync_wait_args wait_args = {0}; -+ struct winesync_sem_args sem_args = {0}; -+ __u32 objs[2] = {0}; -+ int fd, ret; -+ -+ fd = open("/dev/winesync", O_CLOEXEC | O_RDONLY); -+ ASSERT_LE(0, fd); -+ -+ ret = ioctl(fd, WINESYNC_IOC_PUT_SEM, &sem_args); -+ EXPECT_EQ(-1, ret); -+ EXPECT_EQ(EINVAL, errno); -+ -+ ret = ioctl(fd, WINESYNC_IOC_READ_SEM, &sem_args); -+ EXPECT_EQ(-1, ret); -+ EXPECT_EQ(EINVAL, errno); -+ -+ ret = ioctl(fd, WINESYNC_IOC_PUT_MUTEX, &mutex_args); -+ EXPECT_EQ(-1, ret); -+ EXPECT_EQ(EINVAL, errno); -+ -+ ret = ioctl(fd, WINESYNC_IOC_READ_MUTEX, &mutex_args); -+ EXPECT_EQ(-1, ret); -+ EXPECT_EQ(EINVAL, errno); -+ -+ wait_args.objs = (uintptr_t)objs; -+ wait_args.count = 1; -+ ret = ioctl(fd, WINESYNC_IOC_WAIT_ANY, &wait_args); -+ EXPECT_EQ(-1, ret); -+ EXPECT_EQ(EINVAL, errno); -+ ret = ioctl(fd, WINESYNC_IOC_WAIT_ALL, &wait_args); -+ EXPECT_EQ(-1, ret); -+ EXPECT_EQ(EINVAL, errno); -+ -+ ret = ioctl(fd, WINESYNC_IOC_DELETE, &objs[0]); -+ EXPECT_EQ(-1, ret); -+ EXPECT_EQ(EINVAL, errno); -+ -+ sem_args.max = 1; -+ ret = ioctl(fd, WINESYNC_IOC_CREATE_SEM, &sem_args); -+ EXPECT_EQ(0, ret); -+ -+ mutex_args.mutex = sem_args.sem; -+ ret = ioctl(fd, WINESYNC_IOC_PUT_MUTEX, &mutex_args); -+ EXPECT_EQ(-1, ret); -+ EXPECT_EQ(EINVAL, errno); -+ -+ ret = ioctl(fd, WINESYNC_IOC_READ_MUTEX, &mutex_args); -+ EXPECT_EQ(-1, ret); -+ EXPECT_EQ(EINVAL, errno); -+ -+ objs[0] = sem_args.sem; -+ objs[1] = sem_args.sem + 1; -+ wait_args.count = 2; -+ ret = ioctl(fd, WINESYNC_IOC_WAIT_ANY, &wait_args); -+ EXPECT_EQ(-1, ret); -+ EXPECT_EQ(EINVAL, errno); -+ ret = ioctl(fd, WINESYNC_IOC_WAIT_ALL, &wait_args); -+ EXPECT_EQ(-1, ret); -+ EXPECT_EQ(EINVAL, errno); -+ -+ objs[0] = sem_args.sem + 1; -+ objs[1] = sem_args.sem; -+ ret = ioctl(fd, WINESYNC_IOC_WAIT_ANY, &wait_args); -+ EXPECT_EQ(-1, ret); -+ EXPECT_EQ(EINVAL, errno); -+ ret = ioctl(fd, WINESYNC_IOC_WAIT_ALL, &wait_args); -+ EXPECT_EQ(-1, ret); -+ EXPECT_EQ(EINVAL, errno); -+ -+ ret = ioctl(fd, WINESYNC_IOC_DELETE, &sem_args.sem); -+ EXPECT_EQ(0, ret); -+ -+ ret = ioctl(fd, WINESYNC_IOC_CREATE_MUTEX, &mutex_args); -+ EXPECT_EQ(0, ret); -+ -+ sem_args.sem = mutex_args.mutex; -+ ret = ioctl(fd, WINESYNC_IOC_PUT_SEM, &sem_args); -+ EXPECT_EQ(-1, ret); -+ EXPECT_EQ(EINVAL, errno); -+ -+ ret = ioctl(fd, WINESYNC_IOC_READ_SEM, &sem_args); -+ EXPECT_EQ(-1, ret); -+ EXPECT_EQ(EINVAL, errno); -+ -+ ret = ioctl(fd, WINESYNC_IOC_DELETE, &mutex_args.mutex); -+ EXPECT_EQ(0, ret); -+ -+ close(fd); -+} -+ - TEST_HARNESS_MAIN --- -2.34.1 - -From 4f0f9ab195cd71122df16c613996088f10432477 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <z.figura12@gmail.com> -Date: Fri, 5 Mar 2021 12:09:32 -0600 -Subject: [PATCH 19/25] selftests: winesync: Add some tests for wakeup - signaling with WINESYNC_IOC_WAIT_ANY. - ---- - .../selftests/drivers/winesync/winesync.c | 166 ++++++++++++++++++ - 1 file changed, 166 insertions(+) - -diff --git a/tools/testing/selftests/drivers/winesync/winesync.c b/tools/testing/selftests/drivers/winesync/winesync.c -index 59ad45f46969..cdf69c9ff4a9 100644 ---- a/tools/testing/selftests/drivers/winesync/winesync.c -+++ b/tools/testing/selftests/drivers/winesync/winesync.c -@@ -841,4 +841,170 @@ TEST(invalid_objects) - close(fd); - } - -+struct wake_args -+{ -+ int fd; -+ __u32 obj; -+}; -+ -+struct wait_args -+{ -+ int fd; -+ unsigned long request; -+ struct winesync_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 void get_abs_timeout(struct timespec *timeout, clockid_t clock, -+ unsigned int ms) -+{ -+ clock_gettime(clock, timeout); -+ timeout->tv_nsec += ms * 1000000; -+ timeout->tv_sec += (timeout->tv_nsec / 1000000000); -+ timeout->tv_nsec %= 1000000000; -+} -+ -+static int wait_for_thread(pthread_t thread, unsigned int ms) -+{ -+ struct timespec timeout; -+ get_abs_timeout(&timeout, CLOCK_REALTIME, ms); -+ return pthread_timedjoin_np(thread, NULL, &timeout); -+} -+ -+TEST(wake_any) -+{ -+ struct winesync_mutex_args mutex_args = {0}; -+ struct winesync_wait_args wait_args = {0}; -+ struct winesync_sem_args sem_args = {0}; -+ struct wait_args thread_args; -+ struct timespec timeout; -+ __u32 objs[2], owner; -+ pthread_t thread; -+ int fd, ret; -+ -+ fd = open("/dev/winesync", O_CLOEXEC | O_RDONLY); -+ ASSERT_LE(0, fd); -+ -+ sem_args.count = 0; -+ sem_args.max = 3; -+ sem_args.sem = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_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, WINESYNC_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 */ -+ -+ get_abs_timeout(&timeout, CLOCK_MONOTONIC, 1000); -+ wait_args.timeout = (uintptr_t)&timeout; -+ 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 = WINESYNC_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); -+ -+ sem_args.count = 1; -+ ret = ioctl(fd, WINESYNC_IOC_PUT_SEM, &sem_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(0, sem_args.count); -+ -+ ret = ioctl(fd, WINESYNC_IOC_READ_SEM, &sem_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(0, sem_args.count); -+ -+ 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 */ -+ wait_args.owner = 123; -+ ret = ioctl(fd, WINESYNC_IOC_WAIT_ANY, &wait_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(1, wait_args.index); -+ -+ get_abs_timeout(&timeout, CLOCK_MONOTONIC, 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); -+ -+ mutex_args.owner = 123; -+ mutex_args.count = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_PUT_MUTEX, &mutex_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(2, mutex_args.count); -+ -+ ret = pthread_tryjoin_np(thread, NULL); -+ EXPECT_EQ(EBUSY, ret); -+ -+ mutex_args.owner = 123; -+ mutex_args.count = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_PUT_MUTEX, &mutex_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(1, mutex_args.count); -+ -+ ret = ioctl(fd, WINESYNC_IOC_READ_MUTEX, &mutex_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(1, mutex_args.count); -+ EXPECT_EQ(456, mutex_args.owner); -+ -+ 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 */ -+ -+ get_abs_timeout(&timeout, CLOCK_MONOTONIC, 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); -+ -+ ret = ioctl(fd, WINESYNC_IOC_DELETE, &sem_args.sem); -+ EXPECT_EQ(0, ret); -+ ret = ioctl(fd, WINESYNC_IOC_DELETE, &mutex_args.mutex); -+ EXPECT_EQ(0, ret); -+ -+ 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.34.1 - -From 0721111ee1f1b574f565101638b07952a5c6fe62 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <z.figura12@gmail.com> -Date: Fri, 5 Mar 2021 12:09:36 -0600 -Subject: [PATCH 20/25] selftests: winesync: Add some tests for wakeup - signaling with WINESYNC_IOC_WAIT_ALL. - ---- - .../selftests/drivers/winesync/winesync.c | 121 ++++++++++++++++++ - 1 file changed, 121 insertions(+) - -diff --git a/tools/testing/selftests/drivers/winesync/winesync.c b/tools/testing/selftests/drivers/winesync/winesync.c -index cdf69c9ff4a9..19b6bd6e4b9b 100644 ---- a/tools/testing/selftests/drivers/winesync/winesync.c -+++ b/tools/testing/selftests/drivers/winesync/winesync.c -@@ -1007,4 +1007,125 @@ TEST(wake_any) - close(fd); - } - -+TEST(wake_all) -+{ -+ struct winesync_wait_args wait_args = {0}, wait_args2 = {0}; -+ struct winesync_mutex_args mutex_args = {0}; -+ struct winesync_sem_args sem_args = {0}; -+ struct timespec timeout, timeout2; -+ struct wait_args thread_args; -+ __u32 objs[2], owner; -+ pthread_t thread; -+ int fd, ret; -+ -+ fd = open("/dev/winesync", O_CLOEXEC | O_RDONLY); -+ ASSERT_LE(0, fd); -+ -+ sem_args.count = 0; -+ sem_args.max = 3; -+ sem_args.sem = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_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, WINESYNC_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; -+ -+ get_abs_timeout(&timeout, CLOCK_MONOTONIC, 1000); -+ wait_args.timeout = (uintptr_t)&timeout; -+ 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 = WINESYNC_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); -+ -+ sem_args.count = 1; -+ ret = ioctl(fd, WINESYNC_IOC_PUT_SEM, &sem_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(0, sem_args.count); -+ -+ ret = pthread_tryjoin_np(thread, NULL); -+ EXPECT_EQ(EBUSY, ret); -+ -+ ret = ioctl(fd, WINESYNC_IOC_READ_SEM, &sem_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(1, sem_args.count); -+ -+ get_abs_timeout(&timeout2, CLOCK_MONOTONIC, 0); -+ wait_args2.timeout = (uintptr_t)&timeout2; -+ wait_args2.objs = (uintptr_t)&sem_args.sem; -+ wait_args2.count = 1; -+ wait_args2.owner = 123; -+ wait_args2.index = 0xdeadbeef; -+ ret = ioctl(fd, WINESYNC_IOC_WAIT_ANY, &wait_args2); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(0, wait_args2.index); -+ -+ mutex_args.owner = 123; -+ ret = ioctl(fd, WINESYNC_IOC_PUT_MUTEX, &mutex_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(1, mutex_args.count); -+ -+ ret = pthread_tryjoin_np(thread, NULL); -+ EXPECT_EQ(EBUSY, ret); -+ -+ ret = ioctl(fd, WINESYNC_IOC_READ_MUTEX, &mutex_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(0, mutex_args.count); -+ EXPECT_EQ(0, mutex_args.owner); -+ -+ sem_args.count = 2; -+ ret = ioctl(fd, WINESYNC_IOC_PUT_SEM, &sem_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(0, sem_args.count); -+ -+ ret = ioctl(fd, WINESYNC_IOC_READ_SEM, &sem_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(1, sem_args.count); -+ -+ ret = ioctl(fd, WINESYNC_IOC_READ_MUTEX, &mutex_args); -+ EXPECT_EQ(0, ret); -+ EXPECT_EQ(1, mutex_args.count); -+ EXPECT_EQ(456, mutex_args.owner); -+ -+ 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 */ -+ -+ get_abs_timeout(&timeout, CLOCK_MONOTONIC, 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); -+ -+ ret = ioctl(fd, WINESYNC_IOC_DELETE, &sem_args.sem); -+ EXPECT_EQ(0, ret); -+ ret = ioctl(fd, WINESYNC_IOC_DELETE, &mutex_args.mutex); -+ EXPECT_EQ(0, ret); -+ -+ 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.34.1 - -From 307a15f378dd5051608d9150dd8d0968a474a278 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <z.figura12@gmail.com> -Date: Fri, 5 Mar 2021 12:22:55 -0600 -Subject: [PATCH 21/25] maintainers: Add an entry for winesync. - ---- - MAINTAINERS | 9 +++++++++ - 1 file changed, 9 insertions(+) - -diff --git a/MAINTAINERS b/MAINTAINERS -index 3b79fd441dde..4f1b799f8302 100644 ---- a/MAINTAINERS -+++ b/MAINTAINERS -@@ -20227,6 +20227,15 @@ M: David Härdeman <david@hardeman.nu> - S: Maintained - F: drivers/media/rc/winbond-cir.c - -+WINESYNC SYNCHRONIZATION PRIMITIVE DRIVER -+M: Zebediah Figura <zfigura@codeweavers.com> -+L: wine-devel@winehq.org -+S: Supported -+F: Documentation/userspace-api/winesync.rst -+F: drivers/misc/winesync.c -+F: include/uapi/linux/winesync.h -+F: tools/testing/selftests/drivers/winesync/ -+ - WINSYSTEMS EBC-C384 WATCHDOG DRIVER - M: William Breathitt Gray <vilhelm.gray@gmail.com> - L: linux-watchdog@vger.kernel.org --- -2.34.1 - -From de7b97344dd087e85f01b88b31b23173821ddfe6 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <z.figura12@gmail.com> -Date: Thu, 10 Jun 2021 20:48:58 -0500 -Subject: [PATCH 22/25] winesync: Introduce the WINESYNC_WAIT_FLAG_GET flag. - ---- - drivers/misc/winesync.c | 49 +++++++----- - include/uapi/linux/winesync.h | 7 ++ - .../selftests/drivers/winesync/winesync.c | 80 ++++++++++++------- - 3 files changed, 87 insertions(+), 49 deletions(-) - -diff --git a/drivers/misc/winesync.c b/drivers/misc/winesync.c -index a9a6d1b7970a..7b7b0807765a 100644 ---- a/drivers/misc/winesync.c -+++ b/drivers/misc/winesync.c -@@ -75,6 +75,7 @@ struct winesync_q_entry { - struct list_head node; - struct winesync_q *q; - struct winesync_obj *obj; -+ __u32 flags; - __u32 index; - }; - -@@ -225,18 +226,23 @@ static void try_wake_all(struct winesync_device *dev, struct winesync_q *q, - - if (can_wake && atomic_cmpxchg(&q->signaled, -1, 0) == -1) { - for (i = 0; i < count; i++) { -- struct winesync_obj *obj = q->entries[i].obj; -+ struct winesync_q_entry *entry = &q->entries[i]; -+ struct winesync_obj *obj = entry->obj; - - switch (obj->type) { - case WINESYNC_TYPE_SEM: -- obj->u.sem.count--; -+ if (entry->flags & WINESYNC_WAIT_FLAG_GET) -+ obj->u.sem.count--; - break; - case WINESYNC_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; -+ -+ if (entry->flags & WINESYNC_WAIT_FLAG_GET) { -+ obj->u.mutex.ownerdead = false; -+ obj->u.mutex.count++; -+ obj->u.mutex.owner = q->owner; -+ } - break; - } - } -@@ -274,7 +280,8 @@ static void try_wake_any_sem(struct winesync_obj *sem) - break; - - if (atomic_cmpxchg(&q->signaled, -1, entry->index) == -1) { -- sem->u.sem.count--; -+ if (entry->flags & WINESYNC_WAIT_FLAG_GET) -+ sem->u.sem.count--; - wake_up_process(q->task); - } - } -@@ -297,9 +304,12 @@ static void try_wake_any_mutex(struct winesync_obj *mutex) - 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; -+ -+ if (entry->flags & WINESYNC_WAIT_FLAG_GET) { -+ mutex->u.mutex.ownerdead = false; -+ mutex->u.mutex.count++; -+ mutex->u.mutex.owner = q->owner; -+ } - wake_up_process(q->task); - } - } -@@ -682,9 +692,9 @@ static int setup_wait(struct winesync_device *dev, - { - const void __user *sigmask = u64_to_user_ptr(args->sigmask); - const __u32 count = args->count; -+ struct winesync_wait_obj *objs; - struct winesync_q *q; - ktime_t timeout = 0; -- __u32 *ids; - __u32 i, j; - int ret; - -@@ -709,18 +719,18 @@ static int setup_wait(struct winesync_device *dev, - timeout = timespec64_to_ns(&to); - } - -- ids = kmalloc_array(args->count, sizeof(*ids), GFP_KERNEL); -- if (!ids) -+ objs = kmalloc_array(args->count, sizeof(*objs), GFP_KERNEL); -+ if (!objs) - return -ENOMEM; -- if (copy_from_user(ids, u64_to_user_ptr(args->objs), -- array_size(args->count, sizeof(*ids)))) { -- kfree(ids); -+ if (copy_from_user(objs, u64_to_user_ptr(args->objs), -+ array_size(args->count, sizeof(*objs)))) { -+ kfree(objs); - return -EFAULT; - } - - q = kmalloc(struct_size(q, entries, count), GFP_KERNEL); - if (!q) { -- kfree(ids); -+ kfree(objs); - return -ENOMEM; - } - q->task = current; -@@ -732,7 +742,7 @@ static int setup_wait(struct winesync_device *dev, - - for (i = 0; i < count; i++) { - struct winesync_q_entry *entry = &q->entries[i]; -- struct winesync_obj *obj = get_obj(dev, ids[i]); -+ struct winesync_obj *obj = get_obj(dev, objs[i].obj); - - if (!obj) - goto err; -@@ -750,9 +760,10 @@ static int setup_wait(struct winesync_device *dev, - entry->obj = obj; - entry->q = q; - entry->index = i; -+ entry->flags = objs[i].flags; - } - -- kfree(ids); -+ kfree(objs); - - *ret_q = q; - *ret_timeout = timeout; -@@ -761,7 +772,7 @@ static int setup_wait(struct winesync_device *dev, - err: - for (j = 0; j < i; j++) - put_obj(q->entries[j].obj); -- kfree(ids); -+ kfree(objs); - kfree(q); - return -EINVAL; - } -diff --git a/include/uapi/linux/winesync.h b/include/uapi/linux/winesync.h -index 1dccdb3877ec..04f5006089ca 100644 ---- a/include/uapi/linux/winesync.h -+++ b/include/uapi/linux/winesync.h -@@ -22,6 +22,13 @@ struct winesync_mutex_args { - __u32 count; - }; - -+#define WINESYNC_WAIT_FLAG_GET (1 << 0) -+ -+struct winesync_wait_obj { -+ __u32 obj; -+ __u32 flags; -+}; -+ - struct winesync_wait_args { - __u64 sigmask; - __u64 sigsetsize; -diff --git a/tools/testing/selftests/drivers/winesync/winesync.c b/tools/testing/selftests/drivers/winesync/winesync.c -index 19b6bd6e4b9b..2a7008c9c198 100644 ---- a/tools/testing/selftests/drivers/winesync/winesync.c -+++ b/tools/testing/selftests/drivers/winesync/winesync.c -@@ -18,6 +18,7 @@ TEST(semaphore_state) - { - struct winesync_wait_args wait_args = {0}; - struct winesync_sem_args sem_args; -+ struct winesync_wait_obj wait_obj; - struct timespec timeout; - int fd, ret; - -@@ -71,8 +72,10 @@ TEST(semaphore_state) - EXPECT_EQ(2, sem_args.count); - EXPECT_EQ(2, sem_args.max); - -+ wait_obj.obj = sem_args.sem; -+ wait_obj.flags = WINESYNC_WAIT_FLAG_GET; - wait_args.timeout = (uintptr_t)&timeout; -- wait_args.objs = (uintptr_t)&sem_args.sem; -+ wait_args.objs = (uintptr_t)&wait_obj; - wait_args.count = 1; - wait_args.owner = 123; - wait_args.index = 0xdeadbeef; -@@ -154,6 +157,7 @@ TEST(mutex_state) - { - struct winesync_wait_args wait_args = {0}; - struct winesync_mutex_args mutex_args; -+ struct winesync_wait_obj wait_obj; - struct timespec timeout; - __u32 owner; - int fd, ret; -@@ -240,8 +244,10 @@ TEST(mutex_state) - EXPECT_EQ(-1, ret); - EXPECT_EQ(EPERM, errno); - -+ wait_obj.obj = mutex_args.mutex; -+ wait_obj.flags = WINESYNC_WAIT_FLAG_GET; - wait_args.timeout = (uintptr_t)&timeout; -- wait_args.objs = (uintptr_t)&mutex_args.mutex; -+ wait_args.objs = (uintptr_t)&wait_obj; - wait_args.count = 1; - wait_args.owner = 456; - wait_args.index = 0xdeadbeef; -@@ -405,8 +411,9 @@ TEST(wait_any) - struct winesync_mutex_args mutex_args = {0}; - struct winesync_wait_args wait_args = {0}; - struct winesync_sem_args sem_args = {0}; -+ struct winesync_wait_obj wait_objs[2]; - struct timespec timeout; -- __u32 objs[2], owner; -+ __u32 owner; - int fd, ret; - - clock_gettime(CLOCK_MONOTONIC, &timeout); -@@ -428,18 +435,20 @@ TEST(wait_any) - EXPECT_EQ(0, ret); - EXPECT_NE(0xdeadbeef, mutex_args.mutex); - -- objs[0] = sem_args.sem; -- objs[1] = mutex_args.mutex; -+ wait_objs[0].obj = sem_args.sem; -+ wait_objs[0].flags = WINESYNC_WAIT_FLAG_GET; -+ wait_objs[1].obj = mutex_args.mutex; -+ wait_objs[1].flags = WINESYNC_WAIT_FLAG_GET; - - wait_args.timeout = (uintptr_t)&timeout; -- wait_args.objs = (uintptr_t)objs; -+ wait_args.objs = (uintptr_t)wait_objs; - wait_args.count = 2; - wait_args.owner = 123; - wait_args.index = 0xdeadbeef; - ret = ioctl(fd, WINESYNC_IOC_WAIT_ANY, &wait_args); - EXPECT_EQ(0, ret); - EXPECT_EQ(0, wait_args.index); -- EXPECT_EQ((uintptr_t)objs, wait_args.objs); -+ EXPECT_EQ((uintptr_t)wait_objs, wait_args.objs); - EXPECT_EQ(2, wait_args.count); - EXPECT_EQ(123, wait_args.owner); - -@@ -571,7 +580,7 @@ TEST(wait_any) - EXPECT_EQ(0, ret); - EXPECT_EQ(0, sem_args.count); - -- objs[0] = objs[1] = sem_args.sem; -+ wait_objs[0].obj = wait_objs[1].obj = sem_args.sem; - ret = ioctl(fd, WINESYNC_IOC_WAIT_ANY, &wait_args); - EXPECT_EQ(0, ret); - EXPECT_EQ(0, wait_args.index); -@@ -602,8 +611,9 @@ TEST(wait_all) - struct winesync_mutex_args mutex_args = {0}; - struct winesync_wait_args wait_args = {0}; - struct winesync_sem_args sem_args = {0}; -+ struct winesync_wait_obj wait_objs[2]; - struct timespec timeout; -- __u32 objs[2], owner; -+ __u32 owner; - int fd, ret; - - clock_gettime(CLOCK_MONOTONIC, &timeout); -@@ -625,16 +635,18 @@ TEST(wait_all) - EXPECT_EQ(0, ret); - EXPECT_NE(0xdeadbeef, mutex_args.mutex); - -- objs[0] = sem_args.sem; -- objs[1] = mutex_args.mutex; -+ wait_objs[0].obj = sem_args.sem; -+ wait_objs[0].flags = WINESYNC_WAIT_FLAG_GET; -+ wait_objs[1].obj = mutex_args.mutex; -+ wait_objs[1].flags = WINESYNC_WAIT_FLAG_GET; - - wait_args.timeout = (uintptr_t)&timeout; -- wait_args.objs = (uintptr_t)objs; -+ wait_args.objs = (uintptr_t)wait_objs; - wait_args.count = 2; - wait_args.owner = 123; - ret = ioctl(fd, WINESYNC_IOC_WAIT_ALL, &wait_args); - EXPECT_EQ(0, ret); -- EXPECT_EQ((uintptr_t)objs, wait_args.objs); -+ EXPECT_EQ((uintptr_t)wait_objs, wait_args.objs); - EXPECT_EQ(2, wait_args.count); - EXPECT_EQ(123, wait_args.owner); - -@@ -735,7 +747,7 @@ TEST(wait_all) - EXPECT_EQ(123, mutex_args.owner); - - /* test waiting on the same object twice */ -- objs[0] = objs[1] = sem_args.sem; -+ wait_objs[0].obj = wait_objs[1].obj = sem_args.sem; - ret = ioctl(fd, WINESYNC_IOC_WAIT_ALL, &wait_args); - EXPECT_EQ(-1, ret); - EXPECT_EQ(EINVAL, errno); -@@ -751,9 +763,9 @@ TEST(wait_all) - TEST(invalid_objects) - { - struct winesync_mutex_args mutex_args = {0}; -+ struct winesync_wait_obj wait_objs[2] = {0}; - struct winesync_wait_args wait_args = {0}; - struct winesync_sem_args sem_args = {0}; -- __u32 objs[2] = {0}; - int fd, ret; - - fd = open("/dev/winesync", O_CLOEXEC | O_RDONLY); -@@ -775,7 +787,7 @@ TEST(invalid_objects) - EXPECT_EQ(-1, ret); - EXPECT_EQ(EINVAL, errno); - -- wait_args.objs = (uintptr_t)objs; -+ wait_args.objs = (uintptr_t)wait_objs; - wait_args.count = 1; - ret = ioctl(fd, WINESYNC_IOC_WAIT_ANY, &wait_args); - EXPECT_EQ(-1, ret); -@@ -784,7 +796,7 @@ TEST(invalid_objects) - EXPECT_EQ(-1, ret); - EXPECT_EQ(EINVAL, errno); - -- ret = ioctl(fd, WINESYNC_IOC_DELETE, &objs[0]); -+ ret = ioctl(fd, WINESYNC_IOC_DELETE, &sem_args.sem); - EXPECT_EQ(-1, ret); - EXPECT_EQ(EINVAL, errno); - -@@ -801,8 +813,8 @@ TEST(invalid_objects) - EXPECT_EQ(-1, ret); - EXPECT_EQ(EINVAL, errno); - -- objs[0] = sem_args.sem; -- objs[1] = sem_args.sem + 1; -+ wait_objs[0].obj = sem_args.sem; -+ wait_objs[1].obj = sem_args.sem + 1; - wait_args.count = 2; - ret = ioctl(fd, WINESYNC_IOC_WAIT_ANY, &wait_args); - EXPECT_EQ(-1, ret); -@@ -811,8 +823,8 @@ TEST(invalid_objects) - EXPECT_EQ(-1, ret); - EXPECT_EQ(EINVAL, errno); - -- objs[0] = sem_args.sem + 1; -- objs[1] = sem_args.sem; -+ wait_objs[0].obj = sem_args.sem + 1; -+ wait_objs[1].obj = sem_args.sem; - ret = ioctl(fd, WINESYNC_IOC_WAIT_ANY, &wait_args); - EXPECT_EQ(-1, ret); - EXPECT_EQ(EINVAL, errno); -@@ -886,10 +898,11 @@ TEST(wake_any) - struct winesync_mutex_args mutex_args = {0}; - struct winesync_wait_args wait_args = {0}; - struct winesync_sem_args sem_args = {0}; -+ struct winesync_wait_obj wait_objs[2]; - struct wait_args thread_args; - struct timespec timeout; -- __u32 objs[2], owner; - pthread_t thread; -+ __u32 owner; - int fd, ret; - - fd = open("/dev/winesync", O_CLOEXEC | O_RDONLY); -@@ -909,14 +922,16 @@ TEST(wake_any) - EXPECT_EQ(0, ret); - EXPECT_NE(0xdeadbeef, mutex_args.mutex); - -- objs[0] = sem_args.sem; -- objs[1] = mutex_args.mutex; -+ wait_objs[0].obj = sem_args.sem; -+ wait_objs[0].flags = WINESYNC_WAIT_FLAG_GET; -+ wait_objs[1].obj = mutex_args.mutex; -+ wait_objs[1].flags = WINESYNC_WAIT_FLAG_GET; - - /* test waking the semaphore */ - - get_abs_timeout(&timeout, CLOCK_MONOTONIC, 1000); - wait_args.timeout = (uintptr_t)&timeout; -- wait_args.objs = (uintptr_t)objs; -+ wait_args.objs = (uintptr_t)wait_objs; - wait_args.count = 2; - wait_args.owner = 456; - wait_args.index = 0xdeadbeef; -@@ -1010,12 +1025,13 @@ TEST(wake_any) - TEST(wake_all) - { - struct winesync_wait_args wait_args = {0}, wait_args2 = {0}; -+ struct winesync_wait_obj wait_objs[2], wait_obj2; - struct winesync_mutex_args mutex_args = {0}; - struct winesync_sem_args sem_args = {0}; - struct timespec timeout, timeout2; - struct wait_args thread_args; -- __u32 objs[2], owner; - pthread_t thread; -+ __u32 owner; - int fd, ret; - - fd = open("/dev/winesync", O_CLOEXEC | O_RDONLY); -@@ -1035,12 +1051,14 @@ TEST(wake_all) - EXPECT_EQ(0, ret); - EXPECT_NE(0xdeadbeef, mutex_args.mutex); - -- objs[0] = sem_args.sem; -- objs[1] = mutex_args.mutex; -+ wait_objs[0].obj = sem_args.sem; -+ wait_objs[0].flags = WINESYNC_WAIT_FLAG_GET; -+ wait_objs[1].obj = mutex_args.mutex; -+ wait_objs[1].flags = WINESYNC_WAIT_FLAG_GET; - - get_abs_timeout(&timeout, CLOCK_MONOTONIC, 1000); - wait_args.timeout = (uintptr_t)&timeout; -- wait_args.objs = (uintptr_t)objs; -+ wait_args.objs = (uintptr_t)wait_objs; - wait_args.count = 2; - wait_args.owner = 456; - thread_args.fd = fd; -@@ -1064,9 +1082,11 @@ TEST(wake_all) - EXPECT_EQ(0, ret); - EXPECT_EQ(1, sem_args.count); - -+ wait_obj2.obj = sem_args.sem; -+ wait_obj2.flags = WINESYNC_WAIT_FLAG_GET; - get_abs_timeout(&timeout2, CLOCK_MONOTONIC, 0); - wait_args2.timeout = (uintptr_t)&timeout2; -- wait_args2.objs = (uintptr_t)&sem_args.sem; -+ wait_args2.objs = (uintptr_t)&wait_obj2; - wait_args2.count = 1; - wait_args2.owner = 123; - wait_args2.index = 0xdeadbeef; --- -2.34.1 - -From fb2424bce2139f69ce38516525021e6288024569 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <z.figura12@gmail.com> -Date: Thu, 10 Jun 2021 20:49:21 -0500 -Subject: [PATCH 23/25] doc: Document the WINESYNC_WAIT_FLAG_GET flag. - ---- - Documentation/userspace-api/winesync.rst | 111 ++++++++++++++--------- - 1 file changed, 70 insertions(+), 41 deletions(-) - -diff --git a/Documentation/userspace-api/winesync.rst b/Documentation/userspace-api/winesync.rst -index 009171a187b7..bd63d8afc969 100644 ---- a/Documentation/userspace-api/winesync.rst -+++ b/Documentation/userspace-api/winesync.rst -@@ -59,7 +59,7 @@ shared across multiple processes. - ioctl reference - =============== - --All operations on the device are done through ioctls. There are three -+All operations on the device are done through ioctls. There are four - structures used in ioctl calls:: - - struct winesync_sem_args { -@@ -74,6 +74,12 @@ structures used in ioctl calls:: - __u32 count; - }; - -+ /* used in struct winesync_wait_args */ -+ struct winesync_wait_obj { -+ __u32 obj; -+ __u32 flags; -+ }; -+ - struct winesync_wait_args { - __u64 sigmask; - __u64 sigsetsize; -@@ -238,9 +244,9 @@ The ioctls are as follows: - - .. c:macro:: WINESYNC_IOC_WAIT_ANY - -- Poll on any of a list of objects, atomically acquiring at most one. -- Takes a pointer to struct :c:type:`winesync_wait_args`, which is -- used as follows: -+ Poll on any of a list of objects, possibly acquiring at most one of -+ them. Takes a pointer to struct :c:type:`winesync_wait_args`, which -+ is used as follows: - - ``sigmask`` is an optional input-only pointer to a - :c:type:`sigset_t` structure (specified as an integer so that the -@@ -262,10 +268,14 @@ The ioctls are as follows: - ``timeout`` is zero, i.e. NULL, the function will sleep until an - object is signaled, and will not fail with ``ETIMEDOUT``. - -- ``objs`` is a input-only pointer to an array of ``count`` 32-bit -- object identifiers (specified as an integer so that the structure -- has the same size regardless of architecture). If any identifier -- is invalid, the function fails with ``EINVAL``. -+ ``objs`` is a input-only pointer to an array of ``count`` -+ consecutive ``winesync_wait_obj`` structures (specified as an -+ integer so that the structure has the same size regardless of -+ architecture). In each structure, ``obj`` denotes an object to -+ wait for, and ``flags`` specifies a combination of zero or more -+ ``WINESYNC_WAIT_FLAG_*`` flags modifying the behaviour when -+ waiting for that object. If any identifier is invalid, the -+ function fails with ``EINVAL``. - - ``owner`` is an input-only argument denoting the mutex owner - identifier. If any object in ``objs`` is a mutex, the ioctl will -@@ -278,11 +288,15 @@ The ioctls are as follows: - - ``pad`` is unused, and exists to keep a consistent structure size. - -- This function attempts to acquire one of the given objects. If -- unable to do so, it sleeps until an object becomes signaled, -- subsequently acquiring it, or the timeout expires. In the latter -- case the ioctl fails with ``ETIMEDOUT``. The function only acquires -- one object, even if multiple objects are signaled. -+ This function sleeps until one or more of the given objects is -+ signaled, subsequently returning the index of the first signaled -+ object, or until the timeout expires. In the latter case it fails -+ with ``ETIMEDOUT``. -+ -+ Each object may optionally be accompanied by the -+ ``WINESYNC_WAIT_FLAG_GET`` flag. If an object marked with this flag -+ becomes signaled, the object will be atomically acquired by the -+ waiter. - - A semaphore is considered to be signaled if its count is nonzero, - and is acquired by decrementing its count by one. A mutex is -@@ -293,16 +307,27 @@ The ioctls are as follows: - - Acquisition is atomic and totally ordered with respect to other - operations on the same object. If two wait operations (with -- different ``owner`` identifiers) are queued on the same mutex, only -- one is signaled. If two wait operations are queued on the same -- semaphore, and a value of one is posted to it, only one is signaled. -- The order in which threads are signaled is not specified. -- -- If an inconsistent mutex is acquired, the ioctl fails with -- ``EOWNERDEAD``. Although this is a failure return, the function may -- otherwise be considered successful. The mutex is marked as owned by -- the given owner (with a recursion count of 1) and as no longer -- inconsistent, and ``index`` is still set to the index of the mutex. -+ different ``owner`` identifiers) are queued on the same mutex, both -+ with the ``WINESYNC_WAIT_FLAG_GET`` flag set, only one is signaled. -+ If two wait operations are queued on the same semaphore, both with -+ the ``WINESYNC_WAIT_FLAG_GET`` flag set, and a value of one is -+ posted to it, only one is signaled. The order in which threads are -+ signaled is not specified. -+ -+ On the other hand, if neither waiter specifies -+ ``WINESYNC_WAIT_FLAG_GET``, and the object becomes signaled, both -+ waiters will be woken, and the object will not be modified. If one -+ waiter specifies ``WINESYNC_WAIT_FLAG_GET``, that waiter will be -+ woken and will acquire the object; it is unspecified whether the -+ other waiter will be woken. -+ -+ If a mutex is inconsistent (in which case it is unacquired and -+ therefore signaled), the ioctl fails with ``EOWNERDEAD``. Although -+ this is a failure return, the function may otherwise be considered -+ successful, and ``index`` is still set to the index of the mutex. If -+ ``WINESYNC_WAIT_FLAG_GET`` is specified for said mutex, the mutex is -+ marked as owned by the given owner (with a recursion count of 1) and -+ as no longer inconsistent. - - It is valid to pass the same object more than once. If a wakeup - occurs due to that object being signaled, ``index`` is set to the -@@ -313,28 +338,32 @@ The ioctls are as follows: - - .. c:macro:: WINESYNC_IOC_WAIT_ALL - -- Poll on a list of objects, atomically acquiring all of them. Takes a -- pointer to struct :c:type:`winesync_wait_args`, which is used -- identically to ``WINESYNC_IOC_WAIT_ANY``, except that ``index`` is -- always filled with zero on success. -+ Poll on a list of objects, waiting until all of them are -+ simultaneously signaled. Takes a pointer to struct -+ :c:type:`winesync_wait_args`, which is used identically to -+ ``WINESYNC_IOC_WAIT_ANY``, except that ``index`` is always filled -+ with zero on success. - -- This function attempts to simultaneously acquire all of the given -- objects. If unable to do so, it sleeps until all objects become -- simultaneously signaled, subsequently acquiring them, or the timeout -- expires. In the latter case the ioctl fails with ``ETIMEDOUT`` and -- no objects are modified. -+ This function sleeps until all of the given objects are signaled. If -+ all objects are not simultaneously signaled at any point before the -+ timeout expires, it fails with ``ETIMEDOUT``. - - Objects may become signaled and subsequently designaled (through - acquisition by other threads) while this thread is sleeping. Only -- once all objects are simultaneously signaled does the ioctl acquire -- them and return. The entire acquisition is atomic and totally -- ordered with respect to other operations on any of the given -- objects. -- -- If an inconsistent mutex is acquired, the ioctl fails with -- ``EOWNERDEAD``. Similarly to ``WINESYNC_IOC_WAIT_ANY``, all objects -- are nevertheless marked as acquired. Note that if multiple mutex -- objects are specified, there is no way to know which were marked as -+ once all objects are simultaneously signaled does the ioctl return. -+ -+ The flag ``WINESYNC_WAIT_FLAG_GET`` may optionally be specified for -+ some or all of the objects, in which case the function will also -+ simultaneously acquire every object so marked. The entire -+ acquisition is atomic and totally ordered with respect to other -+ operations on any of the given objects. -+ -+ If any mutex waited for is inconsistent at the time the function -+ returns, the ioctl fails with ``EOWNERDEAD``. Similarly to -+ ``WINESYNC_IOC_WAIT_ANY``, the function may be considered to have -+ succeeded, and all objects marked with ``WINESYNC_WIAT_FLAG_GET`` -+ are still acquired. Note that if multiple mutex objects are -+ specified, there is no way to know which were marked as - inconsistent. - - Unlike ``WINESYNC_IOC_WAIT_ANY``, it is not valid to pass the same --- -2.34.1 - -From 2e364aabcb2fe2d117d00e498288fafee27250db Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <z.figura12@gmail.com> -Date: Fri, 5 Mar 2021 17:21:26 -0600 -Subject: [PATCH 24/25] winesync: Introduce WINESYNC_IOC_PULSE_SEM. - ---- - drivers/misc/winesync.c | 13 +++++++++++-- - include/uapi/linux/winesync.h | 2 ++ - 2 files changed, 13 insertions(+), 2 deletions(-) - -diff --git a/drivers/misc/winesync.c b/drivers/misc/winesync.c -index 7b7b0807765a..e9db3b199238 100644 ---- a/drivers/misc/winesync.c -+++ b/drivers/misc/winesync.c -@@ -411,7 +411,8 @@ static int put_sem_state(struct winesync_obj *sem, __u32 count) - return 0; - } - --static int winesync_put_sem(struct winesync_device *dev, void __user *argp) -+static int winesync_put_sem(struct winesync_device *dev, void __user *argp, -+ bool pulse) - { - struct winesync_sem_args __user *user_args = argp; - struct winesync_sem_args args; -@@ -441,6 +442,9 @@ static int winesync_put_sem(struct winesync_device *dev, void __user *argp) - try_wake_any_sem(sem); - } - -+ if (pulse) -+ sem->u.sem.count = 0; -+ - spin_unlock(&sem->lock); - spin_unlock(&dev->wait_all_lock); - } else { -@@ -451,6 +455,9 @@ static int winesync_put_sem(struct winesync_device *dev, void __user *argp) - if (!ret) - try_wake_any_sem(sem); - -+ if (pulse) -+ sem->u.sem.count = 0; -+ - spin_unlock(&sem->lock); - } - -@@ -959,7 +966,9 @@ static long winesync_char_ioctl(struct file *file, unsigned int cmd, - case WINESYNC_IOC_DELETE: - return winesync_delete(dev, argp); - case WINESYNC_IOC_PUT_SEM: -- return winesync_put_sem(dev, argp); -+ return winesync_put_sem(dev, argp, false); -+ case WINESYNC_IOC_PULSE_SEM: -+ return winesync_put_sem(dev, argp, true); - case WINESYNC_IOC_PUT_MUTEX: - return winesync_put_mutex(dev, argp); - case WINESYNC_IOC_READ_SEM: -diff --git a/include/uapi/linux/winesync.h b/include/uapi/linux/winesync.h -index 04f5006089ca..f2e1c85befa8 100644 ---- a/include/uapi/linux/winesync.h -+++ b/include/uapi/linux/winesync.h -@@ -60,5 +60,7 @@ struct winesync_wait_args { - struct winesync_sem_args) - #define WINESYNC_IOC_READ_MUTEX _IOWR(WINESYNC_IOC_BASE, 9, \ - struct winesync_mutex_args) -+#define WINESYNC_IOC_PULSE_SEM _IOWR(WINESYNC_IOC_BASE, 10, \ -+ struct winesync_sem_args) - - #endif --- -2.34.1 - -From ee18b220dde45003cd7ce7360fe3e633678b97df Mon Sep 17 00:00:00 2001 -From: Zebediah Figura <z.figura12@gmail.com> -Date: Fri, 5 Mar 2021 17:21:47 -0600 -Subject: [PATCH 25/25] doc: Document WINESYNC_IOC_PULSE_SEM. - ---- - Documentation/userspace-api/winesync.rst | 35 ++++++++++++++++++++++++ - 1 file changed, 35 insertions(+) - -diff --git a/Documentation/userspace-api/winesync.rst b/Documentation/userspace-api/winesync.rst -index bd63d8afc969..6e0dde2c5eef 100644 ---- a/Documentation/userspace-api/winesync.rst -+++ b/Documentation/userspace-api/winesync.rst -@@ -166,6 +166,41 @@ The ioctls are as follows: - The operation is atomic and totally ordered with respect to other - operations on the same semaphore. - -+.. c:macro:: WINESYNC_IOC_PULSE_SEM -+ -+ This operation is identical to ``WINESYNC_IOC_PUT_SEM``, with one -+ notable exception: the semaphore is always left in an *unsignaled* -+ state, regardless of the initial count or the count added by the -+ ioctl. That is, the count after a pulse operation will always be -+ zero. -+ -+ A pulse operation can be thought of as a put operation, followed by -+ clearing the semaphore's current count back to zero. Confer the -+ following examples: -+ -+ * If three eligible threads are waiting on a semaphore, all with -+ ``WINESYNC_WAIT_FLAG_GET``, and the semaphore is pulsed with a -+ count of 2, only two of them will be woken, and the third will -+ remain asleep. -+ -+ * If only one such thread is waiting, it will be woken up, but the -+ semaphore's count will remain at zero. -+ -+ * If three eligible threads are waiting and none of them specify -+ ``WINESYNC_WAIT_FLAG_GET``, all three threads will be woken, and -+ the semaphore's count will remain at zero. -+ -+ In either case, a simultaneous ``WINESYNC_IOC_READ_SEM`` ioctl from -+ another thread will always report a count of zero. -+ -+ If adding ``count`` to the semaphore's current count would raise the -+ latter past the semaphore's maximum count, the ioctl fails with -+ ``EOVERFLOW``. However, in this case the semaphore's count will -+ still be reset to zero. -+ -+ The operation is atomic and totally ordered with respect to other -+ operations on the same semaphore. -+ - .. c:macro:: WINESYNC_IOC_PUT_MUTEX - - Release a mutex object. Takes a pointer to struct --- -2.34.1 - |