eventfd: EFD_STATE flag
PATCH 2/2 eventfd: EFD_STATE flag
In reply to a message not in the archiveThis implements a new EFD_STATE flag for eventfd.
When set, this flag changes eventfd behaviour in the following way:
- write simply stores the value written, and is always non-blocking
- read unblocks when the value written changes, and returns the value written
Motivation: we'd like to use eventfd in qemu to pass interrupts from (emulated or assigned) devices to guest. For level interrupts, the counter supported currently by eventfd is not a good match: we really need to set interrupt to a level, typically 0 or 1, and give the guest ability to see the last value written.
--- fs/eventfd.c | 41 ++++++++++++++++++++++++++++++++++------- include/linux/eventfd.h | 3 ++- 2 files changed, 36 insertions(+), 8 deletions(-)
fs/eventfd.c +34 -7
@@ -31,37 +31,59 @@ struct eventfd_ctx {* issue a wakeup. */ __u64 count; +/* +* When EF_STATE flag is set, eventfd behaves differently: +* value written gets stored in "count", read will copy +* "count" to "state". +*/ +__u64 state;unsigned int flags; };static inline int eventfd_readable (struct eventfd_ctx *ctx) { -return ctx->count >0 ; +if (ctx->flags &EFD_STATE ) +return ctx->state != ctx->count; +else +return ctx->count >0 ; }static inline int eventfd_writeable (struct eventfd_ctx *ctx,u64 n) { -return ULLONG_MAX - n > ctx->count; +if (ctx->flags &EFD_STATE ) +return 1 ; +else +return ULLONG_MAX - n > ctx->count; }static inline int eventfd_overflow (struct eventfd_ctx *ctx,u64 cnt) { -return cnt ==ULLONG_MAX ; +if (ctx->flags &EFD_STATE ) +return 0 ; +else +return cnt ==ULLONG_MAX ; }static inline void eventfd_dowrite (struct eventfd_ctx *ctx,u64 ucnt) { -if (eventfd_writeable (ctx, ucnt)) - ucnt =ULLONG_MAX - ctx->count; +if (ctx->flags &EFD_STATE ) + ctx->count = ucnt; +else { +if (ULLONG_MAX - ctx->count < ucnt) + ucnt =ULLONG_MAX - ctx->count; - ctx->count += ucnt; + ctx->count += ucnt; + } }static inline u64 eventfd_doread (struct eventfd_ctx *ctx) {u64 ucnt = (ctx->flags &EFD_SEMAPHORE ) ?1 : ctx->count; - ctx->count -= ucnt; +if (ctx->flags &EFD_STATE ) + ctx->state = ucnt; +else + ctx->count -= ucnt;return ucnt; }
@@ -337,6 +359,10 @@ SYSCALL_DEFINE2(eventfd2, unsigned int, count, int, flags)if (flags & ~EFD_FLAGS_SET )return -EINVAL ; +/* State together with semaphore does not make sense. */ +if ((flags &EFD_STATE ) && (flags &EFD_SEMAPHORE )) +return -EINVAL ; + ctx =kmalloc (sizeof (*ctx),GFP_KERNEL );if (!ctx)
@@ -344,6 +370,7 @@ SYSCALL_DEFINE2(eventfd2, unsigned int, count, int, flags)kref_init (&ctx->kref);init_waitqueue_head (&ctx->wqh); + ctx->state = count; ctx->count = count; ctx->flags = flags;
include/linux/eventfd.h +2 -1
@@ -19,11 +19,12 @@* shared O_* flags. */ #define EFD_SEMAPHORE (1 << 0) +#define EFD_STATE (1 << 1)#define EFD_CLOEXEC O_CLOEXEC#define EFD_NONBLOCK O_NONBLOCK#define EFD_SHARED_FCNTL_FLAGS (O_CLOEXEC | O_NONBLOCK) -#define EFD_FLAGS_SET (EFD_SHARED_FCNTL_FLAGS | EFD_SEMAPHORE) +#define EFD_FLAGS_SET (EFD_SHARED_FCNTL_FLAGS | EFD_SEMAPHORE | EFD_STATE)#ifdef CONFIG_EVENTFD
Signature · 1 line
1.6.2.5
PATCH 1/2 eventfd: reorganize the code to simplify new flags
In reply to a message not in the archiveThis slightly reorganizes the code in eventfd, encapsulating counter math in inline functions, so that it will be easier to add a new flag. No functional changes.
--- fs/eventfd.c | 56 ++++++++++++++++++++++++++++++++++++++++++-------------- 1 files changed, 42 insertions(+), 14 deletions(-)
fs/eventfd.c +42 -14
@@ -34,6 +34,37 @@ struct eventfd_ctx {unsigned int flags; }; + +static inline int eventfd_readable (struct eventfd_ctx *ctx) +{ +return ctx->count >0 ; +} + +static inline int eventfd_writeable (struct eventfd_ctx *ctx,u64 n) +{ +return ULLONG_MAX - n > ctx->count; +} + +static inline int eventfd_overflow (struct eventfd_ctx *ctx,u64 cnt) +{ +return cnt ==ULLONG_MAX ; +} + +static inline void eventfd_dowrite (struct eventfd_ctx *ctx,u64 ucnt) +{ +if (eventfd_writeable (ctx, ucnt)) + ucnt =ULLONG_MAX - ctx->count; + + ctx->count += ucnt; +} + +static inline u64 eventfd_doread (struct eventfd_ctx *ctx) +{ +u64 ucnt = (ctx->flags &EFD_SEMAPHORE ) ?1 : ctx->count; + ctx->count -= ucnt; +return ucnt; +} +/** * eventfd_signal - Adds @n to the eventfd counter. * @ctx: [in] Pointer to the eventfd context.
@@ -57,9 +88,7 @@ int eventfd_signal(struct eventfd_ctx *ctx, int n)if (n <0 )return -EINVAL ;spin_lock_irqsave (&ctx->wqh.lock, flags); -if (ULLONG_MAX - ctx->count < n) - n = (int ) (ULLONG_MAX - ctx->count); - ctx->count += n; +eventfd_dowrite (ctx, n);if (waitqueue_active (&ctx->wqh))wake_up_locked_poll (&ctx->wqh,POLLIN );spin_unlock_irqrestore (&ctx->wqh.lock, flags);
@@ -119,11 +148,11 @@ static unsigned int eventfd_poll(struct file *file, poll_table *wait)poll_wait (file, &ctx->wqh, wait);spin_lock_irqsave (&ctx->wqh.lock, flags); -if (ctx->count >0 ) +if (eventfd_readable (ctx)) events |=POLLIN ; -if (ctx->count ==ULLONG_MAX ) +if (eventfd_overflow (ctx, ctx->count)) events |=POLLERR ; -if (ULLONG_MAX -1 > ctx->count) +if (eventfd_writeable (ctx,1 )) events |=POLLOUT ;spin_unlock_irqrestore (&ctx->wqh.lock, flags);
@@ -142,13 +171,13 @@ static ssize_t eventfd_read(struct file *file, char __user *buf, size_t count,return -EINVAL ;spin_lock_irq (&ctx->wqh.lock); res = -EAGAIN ; -if (ctx->count >0 ) +if (eventfd_readable (ctx)) res =sizeof (ucnt);else if (!(file->f_flags &O_NONBLOCK )) {__add_wait_queue (&ctx->wqh, &wait);for (res =0 ;;) {set_current_state (TASK_INTERRUPTIBLE ); -if (ctx->count >0 ) { +if (eventfd_readable (ctx)) { res =sizeof (ucnt);break ; }
@@ -164,8 +193,7 @@ static ssize_t eventfd_read(struct file *file, char __user *buf, size_t count,__set_current_state (TASK_RUNNING ); }if (likely (res >0 )) { - ucnt = (ctx->flags &EFD_SEMAPHORE ) ?1 : ctx->count; - ctx->count -= ucnt; + ucnt =eventfd_doread (ctx);if (waitqueue_active (&ctx->wqh))wake_up_locked_poll (&ctx->wqh,POLLOUT ); }
@@ -188,17 +216,17 @@ static ssize_t eventfd_write(struct file *file, const char __user *buf, size_t creturn -EINVAL ;if (copy_from_user (&ucnt, buf,sizeof (ucnt)))return -EFAULT ; -if (ucnt ==ULLONG_MAX ) +if (eventfd_overflow (ctx, ucnt))return -EINVAL ;spin_lock_irq (&ctx->wqh.lock); res = -EAGAIN ; -if (ULLONG_MAX - ctx->count > ucnt) +if (eventfd_writeable (ctx, ucnt)) res =sizeof (ucnt);else if (!(file->f_flags &O_NONBLOCK )) {__add_wait_queue (&ctx->wqh, &wait);for (res =0 ;;) {set_current_state (TASK_INTERRUPTIBLE ); -if (ULLONG_MAX - ctx->count > ucnt) { +if (eventfd_writeable (ctx, ucnt)) { res =sizeof (ucnt);break ; }
@@ -214,7 +242,7 @@ static ssize_t eventfd_write(struct file *file, const char __user *buf, size_t c__set_current_state (TASK_RUNNING ); }if (likely (res >0 )) { - ctx->count += ucnt; +eventfd_dowrite (ctx, ucnt);if (waitqueue_active (&ctx->wqh))wake_up_locked_poll (&ctx->wqh,POLLIN ); }
Signature · 1 line
1.6.2.5
Quoted 16 lines · Michael S. Tsirkin
This implements a new
EFD_STATEflag for eventfd.
When set, this flag changes eventfd behaviour in the following way:
- write simply stores the value written, and is always non-blocking
- read unblocks when the value written changes, and returns the value writtenMotivation: we'd like to use eventfd in qemu to pass interrupts from (emulated or assigned) devices to guest. For level interrupts, the counter supported currently by eventfd is not a good match: we really need to set interrupt to a level, typically 0 or 1, and give the guest ability to see the last value written.
fs/eventfd.c +0
-0@@ -31,37 +31,59 @@ struct eventfd_ctx {* issue a wakeup. */
fs/eventfd.c struct eventfd_ctx { · line 42
Quoted 10 lines
fs/eventfd.c +6
-0__u64 count; +/* +* When EF_STATE flag is set, eventfd behaves differently: +* value written gets stored in "count", read will copy +* "count" to "state". +*/ +__u64 state;unsigned int flags; };
Why not write the new value into ->count directly?
Signature · 1 line
error compiling committee.c: too many arguments to function
Quoted 14 lines · Avi Kivity
Quoted 13 lines · Michael S. Tsirkin
This implements a new
EFD_STATEflag for eventfd.
When set, this flag changes eventfd behaviour in the following way:
- write simply stores the value written, and is always non-blocking
- read unblocks when the value written changes, and returns the value writtenMotivation: we'd like to use eventfd in qemu to pass interrupts from (emulated or assigned) devices to guest. For level interrupts, the counter supported currently by eventfd is not a good match: we really need to set interrupt to a level, typically 0 or 1, and give the guest ability to see the last value written.
Quoted 15 lines
fs/eventfd.c struct eventfd_ctx { · line 42
Quoted 13 lines
fs/eventfd.c +6
-0@@ -31,37 +31,59 @@ struct eventfd_ctx {* issue a wakeup. */ __u64 count; +/* +* When EF_STATE flag is set, eventfd behaves differently: +* value written gets stored in "count", read will copy +* "count" to "state". +*/ +__u64 state;unsigned int flags; };Why not write the new value into ->count directly?
That's what it says. state is ther to detect that value was changed after last read. Makes sense?
Quoted 2 lines
Signature · 1 line
error compiling committee.c: too many arguments to function
Quoted 34 lines · Michael S. Tsirkin
Quoted 15 lines · Avi Kivity
Quoted 13 lines · Michael S. Tsirkin
This implements a new
EFD_STATEflag for eventfd.
When set, this flag changes eventfd behaviour in the following way:
- write simply stores the value written, and is always non-blocking
- read unblocks when the value written changes, and returns the value writtenMotivation: we'd like to use eventfd in qemu to pass interrupts from (emulated or assigned) devices to guest. For level interrupts, the counter supported currently by eventfd is not a good match: we really need to set interrupt to a level, typically 0 or 1, and give the guest ability to see the last value written.
Quoted 16 lines
Quoted 4 lines
fs/eventfd.c +0
-0@@ -31,37 +31,59 @@ struct eventfd_ctx {* issue a wakeup. */ __u64 count;fs/eventfd.c struct eventfd_ctx { · line 43
Quoted 10 lines
fs/eventfd.c +6
-0+/* +* When EF_STATE flag is set, eventfd behaves differently: +* value written gets stored in "count", read will copy +* "count" to "state". +*/ +__u64 state;unsigned int flags; };Why not write the new value into ->count directly?
Quoted 3 lines
That's what it says. state is ther to detect that value was changed after last read. Makes sense?
Why not do it at the point of the write?
if (value != ctx->count) {
ctx->count = value;
wake_things_up();
}Signature · 1 line
error compiling committee.c: too many arguments to function
Quoted 39 lines · Avi Kivity
Quoted 34 lines · Michael S. Tsirkin
Quoted 15 lines · Avi Kivity
Quoted 13 lines · Michael S. Tsirkin
This implements a new
EFD_STATEflag for eventfd.
When set, this flag changes eventfd behaviour in the following way:
- write simply stores the value written, and is always non-blocking
- read unblocks when the value written changes, and returns the value writtenMotivation: we'd like to use eventfd in qemu to pass interrupts from (emulated or assigned) devices to guest. For level interrupts, the counter supported currently by eventfd is not a good match: we really need to set interrupt to a level, typically 0 or 1, and give the guest ability to see the last value written.
Quoted 16 lines
Quoted 4 lines
fs/eventfd.c +0
-0@@ -31,37 +31,59 @@ struct eventfd_ctx {* issue a wakeup. */ __u64 count;fs/eventfd.c struct eventfd_ctx { · line 43
Quoted 10 lines
fs/eventfd.c +6
-0+/* +* When EF_STATE flag is set, eventfd behaves differently: +* value written gets stored in "count", read will copy +* "count" to "state". +*/ +__u64 state;unsigned int flags; };Why not write the new value into ->count directly?
Quoted 3 lines
That's what it says. state is ther to detect that value was changed after last read. Makes sense?
Quoted 6 lines
Why not do it at the point of the write?
if (value != ctx->count) { ctx->count = value; wake_things_up(); }
What if write comes before read?
Quoted 2 lines
Signature · 1 line
error compiling committee.c: too many arguments to function
Quoted 10 lines · Michael S. Tsirkin
Quoted 7 lines
Why not do it at the point of the write?
if (value != ctx->count) { ctx->count = value; wake_things_up(); }What if write comes before read?
The read will get the new value.
Signature · 1 line
error compiling committee.c: too many arguments to function
Quoted 9 lines · Avi Kivity
Quoted 8 lines · Michael S. Tsirkin
Quoted 7 lines
Why not do it at the point of the write?
if (value != ctx->count) { ctx->count = value; wake_things_up(); }
Quoted 4 lines
Quoted 2 lines
What if write comes before read?
The read will get the new value.
Yes :) But how does read know it should not block?
Quoted 2 lines
Signature · 1 line
error compiling committee.c: too many arguments to function
Quoted 12 lines · Michael S. Tsirkin
Quoted 10 lines · Avi Kivity
Quoted 8 lines · Michael S. Tsirkin
Quoted 8 lines
Why not do it at the point of the write?
if (value != ctx->count) { ctx->count = value; wake_things_up(); }
Quoted 8 lines
Quoted 5 lines
Quoted 3 lines
What if write comes before read?
The read will get the new value.
Yes :) But how does read know it should not block?
If a different read comes after the write but after our read, it will have transferred the value, resulting in the same situation.
I think reads should never block with a state based mechanism.
Signature · 1 line
error compiling committee.c: too many arguments to function
Quoted 19 lines · Avi Kivity
Quoted 18 lines · Michael S. Tsirkin
Quoted 15 lines · Avi Kivity
Quoted 11 lines · Michael S. Tsirkin
Quoted 8 lines
Why not do it at the point of the write?
if (value != ctx->count) { ctx->count = value; wake_things_up(); }What if write comes before read?
The read will get the new value.
Quoted 8 lines
Quoted 2 lines
Yes :) But how does read know it should not block?
If a different read comes after the write but after our read, it will have transferred the value, resulting in the same situation.
I think reads should never block with a state based mechanism.
Reader may want to poll for the status change.
--
Gleb.
Quoted 8 lines · Gleb Natapov
Quoted 6 lines
If a different read comes after the write but after our read, it will have transferred the value, resulting in the same situation.
I think reads should never block with a state based mechanism.
Reader may want to poll for the status change.
Without epoll(), it's inherently racy since reads from other processes can clear the status.
The "last read value" needs to be maintained for each reader, which is not possible with read().
Signature · 1 line
error compiling committee.c: too many arguments to function
Quoted 4 lines · Avi Kivity
Quoted 3 lines · Gleb Natapov
Quoted 3 lines
If a different read comes after the write but after our read, it will have transferred the value, resulting in the same situation.
Quoted 9 lines
Quoted 5 lines
Quoted 3 lines
I think reads should never block with a state based mechanism.
Reader may want to poll for the status change.
Without
epoll(), it's inherently racy since reads from other processes can clear the status.
This is correct for any file descriptor. Multiple readers shouldn't simultaneously read from the same files descriptor if they expect to make any sense from a result.
Quoted 3 lines
The "last read value" needs to be maintained for each reader, which is not possible with
read().
Only one reader scenario is interesting. This is not some multiplexing device.
--
Gleb.
Quoted 14 lines · Gleb Natapov
Quoted 12 lines · Avi Kivity
Quoted 10 lines · Gleb Natapov
Quoted 7 lines
If a different read comes after the write but after our read, it will have transferred the value, resulting in the same situation.
I think reads should never block with a state based mechanism.
Reader may want to poll for the status change.
Quoted 8 lines
Quoted 4 lines
Without
epoll(), it's inherently racy since reads from other processes can clear the status.This is correct for any file descriptor. Multiple readers shouldn't simultaneously read from the same files descriptor if they expect to make any sense from a result.
I think counting eventfd is an exception, but in general you are right.
Signature · 1 line
error compiling committee.c: too many arguments to function
Quoted 19 lines · Avi Kivity
Quoted 18 lines · Gleb Natapov
Quoted 16 lines · Avi Kivity
Quoted 10 lines · Gleb Natapov
Quoted 7 lines
If a different read comes after the write but after our read, it will have transferred the value, resulting in the same situation.
I think reads should never block with a state based mechanism.
Reader may want to poll for the status change.
Without
epoll(), it's inherently racy since reads from other processes can clear the status.
Quoted 6 lines
Quoted 4 lines
This is correct for any file descriptor. Multiple readers shouldn't simultaneously read from the same files descriptor if they expect to make any sense from a result.
I think counting eventfd is an exception, but in general you are right.
How is it an exception? It seems that one reader get the counter, others will block until the next write.
Quoted 2 lines
Signature · 1 line
error compiling committee.c: too many arguments to function
Quoted 16 lines · Avi Kivity
Quoted 15 lines · Michael S. Tsirkin
Quoted 13 lines · Avi Kivity
Quoted 11 lines · Michael S. Tsirkin
Quoted 8 lines
Why not do it at the point of the write?
if (value != ctx->count) { ctx->count = value; wake_things_up(); }What if write comes before read?
Quoted 8 lines
Quoted 5 lines
Quoted 2 lines
The read will get the new value.
Yes :) But how does read know it should not block?
If a different read comes after the write but after our read, it will have transferred the value, resulting in the same situation.
Not the same: one reader wakes up, others sleep.
Multiple reads from the same fd behave this way for any file I can think of. Consider regular eventfd, or a pipe, a socket ... But if we want to support blocking reads, we probably should not require the readers to sync with writers.
Quoted 1 line
I think reads should never block with a state based mechanism.
Yes, with no support for blocking reads, we don't need the state. In that case, we probably want to error on open out unless O_NONBLOCK is specified. But why is this a good idea?
Quoted 2 lines
Signature · 1 line
error compiling committee.c: too many arguments to function
Quoted 3 lines · Michael S. Tsirkin
How is it an exception? It seems that one reader get the counter, others will block until the next write.
Right. I retract my comments....
Signature · 1 line
error compiling committee.c: too many arguments to function