167 lines
4.4 KiB
Diff
167 lines
4.4 KiB
Diff
|
From 3f3bbc85f1e613364261d685b8197c32ffdeaad0 Mon Sep 17 00:00:00 2001
|
||
|
From: Elizabeth Figura <zfigura@codeweavers.com>
|
||
|
Date: Sun, 19 May 2024 15:24:32 -0500
|
||
|
Subject: ntsync: Introduce NTSYNC_IOC_CREATE_EVENT.
|
||
|
|
||
|
This correspond to the NT syscall NtCreateEvent().
|
||
|
|
||
|
An NT event holds a single bit of state denoting whether it is signaled or
|
||
|
unsignaled.
|
||
|
|
||
|
There are two types of events: manual-reset and automatic-reset. When an
|
||
|
automatic-reset event is acquired via a wait function, its state is reset to
|
||
|
unsignaled. Manual-reset events are not affected by wait functions.
|
||
|
|
||
|
Whether the event is manual-reset, and its initial state, are specified at
|
||
|
creation time.
|
||
|
|
||
|
Signed-off-by: Elizabeth Figura <zfigura@codeweavers.com>
|
||
|
---
|
||
|
drivers/misc/ntsync.c | 62 +++++++++++++++++++++++++++++++++++++
|
||
|
include/uapi/linux/ntsync.h | 7 +++++
|
||
|
2 files changed, 69 insertions(+)
|
||
|
|
||
|
--- a/drivers/misc/ntsync.c
|
||
|
+++ b/drivers/misc/ntsync.c
|
||
|
@@ -26,6 +26,7 @@
|
||
|
enum ntsync_type {
|
||
|
NTSYNC_TYPE_SEM,
|
||
|
NTSYNC_TYPE_MUTEX,
|
||
|
+ NTSYNC_TYPE_EVENT,
|
||
|
};
|
||
|
|
||
|
/*
|
||
|
@@ -61,6 +62,10 @@ struct ntsync_obj {
|
||
|
pid_t owner;
|
||
|
bool ownerdead;
|
||
|
} mutex;
|
||
|
+ struct {
|
||
|
+ bool manual;
|
||
|
+ bool signaled;
|
||
|
+ } event;
|
||
|
} u;
|
||
|
|
||
|
/*
|
||
|
@@ -233,6 +238,8 @@ static bool is_signaled(struct ntsync_ob
|
||
|
if (obj->u.mutex.owner && obj->u.mutex.owner != owner)
|
||
|
return false;
|
||
|
return obj->u.mutex.count < UINT_MAX;
|
||
|
+ case NTSYNC_TYPE_EVENT:
|
||
|
+ return obj->u.event.signaled;
|
||
|
}
|
||
|
|
||
|
WARN(1, "bad object type %#x\n", obj->type);
|
||
|
@@ -283,6 +290,10 @@ static void try_wake_all(struct ntsync_d
|
||
|
obj->u.mutex.count++;
|
||
|
obj->u.mutex.owner = q->owner;
|
||
|
break;
|
||
|
+ case NTSYNC_TYPE_EVENT:
|
||
|
+ if (!obj->u.event.manual)
|
||
|
+ obj->u.event.signaled = false;
|
||
|
+ break;
|
||
|
}
|
||
|
}
|
||
|
wake_up_process(q->task);
|
||
|
@@ -353,6 +364,28 @@ static void try_wake_any_mutex(struct nt
|
||
|
}
|
||
|
}
|
||
|
|
||
|
+static void try_wake_any_event(struct ntsync_obj *event)
|
||
|
+{
|
||
|
+ struct ntsync_q_entry *entry;
|
||
|
+
|
||
|
+ ntsync_assert_held(event);
|
||
|
+ lockdep_assert(event->type == NTSYNC_TYPE_EVENT);
|
||
|
+
|
||
|
+ list_for_each_entry(entry, &event->any_waiters, node) {
|
||
|
+ struct ntsync_q *q = entry->q;
|
||
|
+ int signaled = -1;
|
||
|
+
|
||
|
+ if (!event->u.event.signaled)
|
||
|
+ break;
|
||
|
+
|
||
|
+ if (atomic_try_cmpxchg(&q->signaled, &signaled, entry->index)) {
|
||
|
+ if (!event->u.event.manual)
|
||
|
+ event->u.event.signaled = false;
|
||
|
+ wake_up_process(q->task);
|
||
|
+ }
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
/*
|
||
|
* Actually change the semaphore state, returning -EOVERFLOW if it is made
|
||
|
* invalid.
|
||
|
@@ -629,6 +662,30 @@ static int ntsync_create_mutex(struct nt
|
||
|
return put_user(fd, &user_args->mutex);
|
||
|
}
|
||
|
|
||
|
+static int ntsync_create_event(struct ntsync_device *dev, void __user *argp)
|
||
|
+{
|
||
|
+ struct ntsync_event_args __user *user_args = argp;
|
||
|
+ struct ntsync_event_args args;
|
||
|
+ struct ntsync_obj *event;
|
||
|
+ int fd;
|
||
|
+
|
||
|
+ if (copy_from_user(&args, argp, sizeof(args)))
|
||
|
+ return -EFAULT;
|
||
|
+
|
||
|
+ event = ntsync_alloc_obj(dev, NTSYNC_TYPE_EVENT);
|
||
|
+ if (!event)
|
||
|
+ return -ENOMEM;
|
||
|
+ event->u.event.manual = args.manual;
|
||
|
+ event->u.event.signaled = args.signaled;
|
||
|
+ fd = ntsync_obj_get_fd(event);
|
||
|
+ if (fd < 0) {
|
||
|
+ kfree(event);
|
||
|
+ return fd;
|
||
|
+ }
|
||
|
+
|
||
|
+ return put_user(fd, &user_args->event);
|
||
|
+}
|
||
|
+
|
||
|
static struct ntsync_obj *get_obj(struct ntsync_device *dev, int fd)
|
||
|
{
|
||
|
struct file *file = fget(fd);
|
||
|
@@ -759,6 +816,9 @@ static void try_wake_any_obj(struct ntsy
|
||
|
case NTSYNC_TYPE_MUTEX:
|
||
|
try_wake_any_mutex(obj);
|
||
|
break;
|
||
|
+ case NTSYNC_TYPE_EVENT:
|
||
|
+ try_wake_any_event(obj);
|
||
|
+ break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@@ -948,6 +1008,8 @@ static long ntsync_char_ioctl(struct fil
|
||
|
void __user *argp = (void __user *)parm;
|
||
|
|
||
|
switch (cmd) {
|
||
|
+ case NTSYNC_IOC_CREATE_EVENT:
|
||
|
+ return ntsync_create_event(dev, argp);
|
||
|
case NTSYNC_IOC_CREATE_MUTEX:
|
||
|
return ntsync_create_mutex(dev, argp);
|
||
|
case NTSYNC_IOC_CREATE_SEM:
|
||
|
--- a/include/uapi/linux/ntsync.h
|
||
|
+++ b/include/uapi/linux/ntsync.h
|
||
|
@@ -22,6 +22,12 @@ struct ntsync_mutex_args {
|
||
|
__u32 count;
|
||
|
};
|
||
|
|
||
|
+struct ntsync_event_args {
|
||
|
+ __u32 event;
|
||
|
+ __u32 manual;
|
||
|
+ __u32 signaled;
|
||
|
+};
|
||
|
+
|
||
|
#define NTSYNC_WAIT_REALTIME 0x1
|
||
|
|
||
|
struct ntsync_wait_args {
|
||
|
@@ -40,6 +46,7 @@ struct ntsync_wait_args {
|
||
|
#define NTSYNC_IOC_WAIT_ANY _IOWR('N', 0x82, struct ntsync_wait_args)
|
||
|
#define NTSYNC_IOC_WAIT_ALL _IOWR('N', 0x83, struct ntsync_wait_args)
|
||
|
#define NTSYNC_IOC_CREATE_MUTEX _IOWR('N', 0x84, struct ntsync_sem_args)
|
||
|
+#define NTSYNC_IOC_CREATE_EVENT _IOWR('N', 0x87, struct ntsync_event_args)
|
||
|
|
||
|
#define NTSYNC_IOC_SEM_POST _IOWR('N', 0x81, __u32)
|
||
|
#define NTSYNC_IOC_MUTEX_UNLOCK _IOWR('N', 0x85, struct ntsync_mutex_args)
|