Skip to content

Commit

Permalink
winesync: Introduce alertable waits.
Browse files Browse the repository at this point in the history
Signed-off-by: Alexandre Frade <kernel@xanmod.org>
  • Loading branch information
Zebediah Figura authored and xanmod committed Aug 2, 2022
1 parent 21aac1a commit 33fee21
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 10 deletions.
68 changes: 59 additions & 9 deletions drivers/misc/winesync.c
Original file line number Diff line number Diff line change
Expand Up @@ -841,10 +841,11 @@ static int setup_wait(struct winesync_device *dev,
const __u32 count = args->count;
struct winesync_q *q;
ktime_t timeout = 0;
__u32 total_count;
__u32 *ids;
__u32 i, j;

if (!args->owner || args->pad)
if (!args->owner)
return -EINVAL;

if (args->timeout) {
Expand All @@ -858,16 +859,22 @@ static int setup_wait(struct winesync_device *dev,
timeout = timespec64_to_ns(&to);
}

ids = kmalloc_array(count, sizeof(*ids), GFP_KERNEL);
total_count = count;
if (args->alert)
total_count++;

ids = kmalloc_array(total_count, sizeof(*ids), GFP_KERNEL);
if (!ids)
return -ENOMEM;
if (copy_from_user(ids, u64_to_user_ptr(args->objs),
array_size(count, sizeof(*ids)))) {
kfree(ids);
return -EFAULT;
}
if (args->alert)
ids[count] = args->alert;

q = kmalloc(struct_size(q, entries, count), GFP_KERNEL);
q = kmalloc(struct_size(q, entries, total_count), GFP_KERNEL);
if (!q) {
kfree(ids);
return -ENOMEM;
Expand All @@ -879,7 +886,7 @@ static int setup_wait(struct winesync_device *dev,
q->ownerdead = false;
q->count = count;

for (i = 0; i < count; i++) {
for (i = 0; i < total_count; i++) {
struct winesync_q_entry *entry = &q->entries[i];
struct winesync_obj *obj = get_obj(dev, ids[i]);

Expand Down Expand Up @@ -934,9 +941,9 @@ static int winesync_wait_any(struct winesync_device *dev, void __user *argp)
{
struct winesync_wait_args args;
struct winesync_q *q;
__u32 i, total_count;
ktime_t timeout;
int signaled;
__u32 i;
int ret;

if (copy_from_user(&args, argp, sizeof(args)))
Expand All @@ -946,9 +953,13 @@ static int winesync_wait_any(struct winesync_device *dev, void __user *argp)
if (ret < 0)
return ret;

total_count = args.count;
if (args.alert)
total_count++;

/* queue ourselves */

for (i = 0; i < args.count; i++) {
for (i = 0; i < total_count; i++) {
struct winesync_q_entry *entry = &q->entries[i];
struct winesync_obj *obj = entry->obj;

Expand All @@ -957,9 +968,15 @@ static int winesync_wait_any(struct winesync_device *dev, void __user *argp)
spin_unlock(&obj->lock);
}

/* check if we are already signaled */
/*
* Check if we are already signaled.
*
* Note that the API requires that normal objects are checked before
* the alert event. Hence we queue the alert event last, and check
* objects in order.
*/

for (i = 0; i < args.count; i++) {
for (i = 0; i < total_count; i++) {
struct winesync_obj *obj = q->entries[i].obj;

if (atomic_read(&q->signaled) != -1)
Expand All @@ -976,7 +993,7 @@ static int winesync_wait_any(struct winesync_device *dev, void __user *argp)

/* and finally, unqueue */

for (i = 0; i < args.count; i++) {
for (i = 0; i < total_count; i++) {
struct winesync_q_entry *entry = &q->entries[i];
struct winesync_obj *obj = entry->obj;

Expand Down Expand Up @@ -1036,13 +1053,36 @@ static int winesync_wait_all(struct winesync_device *dev, void __user *argp)
*/
list_add_tail(&entry->node, &obj->all_waiters);
}
if (args.alert) {
struct winesync_q_entry *entry = &q->entries[args.count];
struct winesync_obj *obj = entry->obj;

spin_lock(&obj->lock);
list_add_tail(&entry->node, &obj->any_waiters);
spin_unlock(&obj->lock);
}

/* check if we are already signaled */

try_wake_all(dev, q, NULL);

spin_unlock(&dev->wait_all_lock);

/*
* Check if the alert event is signaled, making sure to do so only
* after checking if the other objects are signaled.
*/

if (args.alert) {
struct winesync_obj *obj = q->entries[args.count].obj;

if (atomic_read(&q->signaled) == -1) {
spin_lock(&obj->lock);
try_wake_any_obj(obj);
spin_unlock(&obj->lock);
}
}

/* sleep */

ret = winesync_schedule(q, args.timeout ? &timeout : NULL);
Expand All @@ -1065,6 +1105,16 @@ static int winesync_wait_all(struct winesync_device *dev, void __user *argp)

put_obj(obj);
}
if (args.alert) {
struct winesync_q_entry *entry = &q->entries[args.count];
struct winesync_obj *obj = entry->obj;

spin_lock(&obj->lock);
list_del(&entry->node);
spin_unlock(&obj->lock);

put_obj(obj);
}

spin_unlock(&dev->wait_all_lock);

Expand Down
2 changes: 1 addition & 1 deletion include/uapi/linux/winesync.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ struct winesync_wait_args {
__u32 count;
__u32 owner;
__u32 index;
__u32 pad;
__u32 alert;
};

#define WINESYNC_IOC_BASE 0xf7
Expand Down

0 comments on commit 33fee21

Please sign in to comment.