From patchwork Thu Jan 7 23:37:11 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Davide Libenzi X-Patchwork-Id: 71687 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter.kernel.org (8.14.3/8.14.2) with ESMTP id o07NbIQn032601 for ; Thu, 7 Jan 2010 23:37:18 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752553Ab0AGXhP (ORCPT ); Thu, 7 Jan 2010 18:37:15 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1752542Ab0AGXhP (ORCPT ); Thu, 7 Jan 2010 18:37:15 -0500 Received: from x35.xmailserver.org ([64.71.152.41]:47695 "EHLO x35.xmailserver.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752451Ab0AGXhN (ORCPT ); Thu, 7 Jan 2010 18:37:13 -0500 X-AuthUser: davidel@xmailserver.org Received: from makko.or.mcafeemobile.com by x35.xmailserver.org with [XMail 1.27 ESMTP Server] id for from ; Thu, 7 Jan 2010 18:36:18 -0500 Date: Thu, 7 Jan 2010 15:37:11 -0800 (PST) From: Davide Libenzi X-X-Sender: davide@makko.or.mcafeemobile.com To: "Michael S. Tsirkin" cc: Avi Kivity , kvm@vger.kernel.org Subject: Re: [PATCH 0/2] eventfd: new EFD_STATE flag In-Reply-To: <20100107103600.GD599@redhat.com> Message-ID: References: <20100106193347.GG4001@redhat.com> <20100106205526.GJ4001@redhat.com> <20100106222920.GB29200@redhat.com> <20100106234521.GA30515@redhat.com> <20100107064503.GA10379@redhat.com> <20100107103600.GD599@redhat.com> User-Agent: Alpine 2.00 (DEB 1167 2008-08-23) X-GPG-FINGRPRINT: CFAE 5BEE FD36 F65E E640 56FE 0974 BF23 270F 474E X-GPG-PUBLIC_KEY: http://www.xmailserver.org/davidel.asc MIME-Version: 1.0 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org Index: linux-2.6.mod/fs/eventfd.c =================================================================== --- linux-2.6.mod.orig/fs/eventfd.c 2010-01-06 12:37:28.000000000 -0800 +++ linux-2.6.mod/fs/eventfd.c 2010-01-06 17:43:09.000000000 -0800 @@ -135,26 +135,56 @@ static unsigned int eventfd_poll(struct return events; } -static ssize_t eventfd_read(struct file *file, char __user *buf, size_t count, - loff_t *ppos) +/** + * eventfd_ctx_peek_value - Reads the eventfd counter. + * @ctx: [in] Pointer to eventfd context. + * + * NOTE: Must be called with the wait queue lock held. Locking the + * eventfd_ctx interface is not actually exposed outside of the + * eventfd implementation, but when poll callback registers with the + * eventfd poll, such callbacks will be invoked with the wait queue + * lock held. IOW this means that this function can only be called from + * inside a registered poll callback at the moment. + * The function returns the current counter value, without consuming it. + */ +__u64 eventfd_ctx_peek_value(struct eventfd_ctx *ctx) +{ + assert_spin_locked(&ctx->wqh.lock); + + return ctx->count; +} +EXPORT_SYMBOL_GPL(eventfd_ctx_peek_value); + +/** + * eventfd_ctx_read - Reads the eventfd counter or wait if it is zero. + * @ctx: [in] Pointer to eventfd context. + * @no_wait: [in] Different from zero if the operation should not block. + * @cnt: [out] Pointer to the 64bit conter value. + * + * Returns zero if successful, or the following error codes: + * + * -EAGAIN : The operation would have blocked but @no_wait was nonzero. + * -ERESTARTSYS : A signal interrupted the wait operation. + * + * If @no_wait is zero, the function might sleep until the eventfd internal + * counter becomes greater than zero. + */ +ssize_t eventfd_ctx_read(struct eventfd_ctx *ctx, int no_wait, __u64 *cnt) { - struct eventfd_ctx *ctx = file->private_data; ssize_t res; - __u64 ucnt = 0; DECLARE_WAITQUEUE(wait, current); - if (count < sizeof(ucnt)) - return -EINVAL; spin_lock_irq(&ctx->wqh.lock); + *cnt = 0; res = -EAGAIN; if (ctx->count > 0) - res = sizeof(ucnt); - else if (!(file->f_flags & O_NONBLOCK)) { + res = 0; + else if (!no_wait) { __add_wait_queue(&ctx->wqh, &wait); - for (res = 0;;) { + for (;;) { set_current_state(TASK_INTERRUPTIBLE); if (ctx->count > 0) { - res = sizeof(ucnt); + res = 0; break; } if (signal_pending(current)) { @@ -168,18 +198,32 @@ static ssize_t eventfd_read(struct file __remove_wait_queue(&ctx->wqh, &wait); __set_current_state(TASK_RUNNING); } - if (likely(res > 0)) { - ucnt = (ctx->flags & EFD_SEMAPHORE) ? 1 : ctx->count; - ctx->count -= ucnt; + if (likely(res == 0)) { + *cnt = (ctx->flags & EFD_SEMAPHORE) ? 1: ctx->count; + ctx->count -= *cnt; if (waitqueue_active(&ctx->wqh)) wake_up_locked_poll(&ctx->wqh, POLLOUT); } spin_unlock_irq(&ctx->wqh.lock); - if (res > 0 && put_user(ucnt, (__u64 __user *) buf)) - return -EFAULT; return res; } +EXPORT_SYMBOL_GPL(eventfd_ctx_read); + +static ssize_t eventfd_read(struct file *file, char __user *buf, size_t count, + loff_t *ppos) +{ + struct eventfd_ctx *ctx = file->private_data; + ssize_t res; + __u64 cnt; + + if (count < sizeof(cnt)) + return -EINVAL; + if ((res = eventfd_ctx_read(ctx, file->f_flags & O_NONBLOCK, &cnt)) < 0) + return res; + + return put_user(cnt, (__u64 __user *) buf) ? -EFAULT: sizeof(cnt); +} static ssize_t eventfd_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) Index: linux-2.6.mod/include/linux/eventfd.h =================================================================== --- linux-2.6.mod.orig/include/linux/eventfd.h 2010-01-06 12:37:28.000000000 -0800 +++ linux-2.6.mod/include/linux/eventfd.h 2010-01-06 14:54:36.000000000 -0800 @@ -34,6 +34,8 @@ struct file *eventfd_fget(int fd); struct eventfd_ctx *eventfd_ctx_fdget(int fd); struct eventfd_ctx *eventfd_ctx_fileget(struct file *file); int eventfd_signal(struct eventfd_ctx *ctx, int n); +ssize_t eventfd_ctx_read(struct eventfd_ctx *ctx, int no_wait, __u64 *cnt); +__u64 eventfd_ctx_peek_value(struct eventfd_ctx *ctx); #else /* CONFIG_EVENTFD */ @@ -61,6 +63,17 @@ static inline void eventfd_ctx_put(struc } +static inline ssize_t eventfd_ctx_read(struct eventfd_ctx *ctx, int no_wait, + __u64 *cnt) +{ + return -ENOSYS; +} + +static inline __u64 eventfd_ctx_peek_value(struct eventfd_ctx *ctx) +{ + return 0; +} + #endif #endif /* _LINUX_EVENTFD_H */