Asynchronously wait for FUTEX_WAKE operation on a futex if it still contains a given value. There can be only one futex wait per file descriptor. However, it can be rearmed (possibly at a different address) anytime. The pollable futex approach is far superior (send and receive events from userspace or kernel) to eventfd and fixes (supercedes) FUTEX_FD at the same time. Building block for pollable semaphores and user-defined events. Signed-off-by: Davi E. M. Arnaut --- fs/pollfs/Makefile | 1 fs/pollfs/futex.c | 154 +++++++++++++++++++++++++++++++++++++++++++++++++++++ init/Kconfig | 7 ++ 3 files changed, 162 insertions(+) Index: linux-2.6/fs/pollfs/Makefile =================================================================== --- linux-2.6.orig/fs/pollfs/Makefile +++ linux-2.6/fs/pollfs/Makefile @@ -3,3 +3,4 @@ pollfs-y := file.o pollfs-$(CONFIG_POLLFS_SIGNAL) += signal.o pollfs-$(CONFIG_POLLFS_TIMER) += timer.o +pollfs-$(CONFIG_POLLFS_FUTEX) += futex.o Index: linux-2.6/fs/pollfs/futex.c =================================================================== --- /dev/null +++ linux-2.6/fs/pollfs/futex.c @@ -0,0 +1,154 @@ +/* + * pollable futex + * + * Copyright (C) 2007 Davi E. M. Arnaut + * + * Licensed under the GNU GPL. See the file COPYING for details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct futex_event { + union { + void __user *addr; + u64 padding; + }; + int val; +}; + +struct pfs_futex { + struct futex_q q; + struct futex_event fevt; + struct mutex mutex; + unsigned volatile queued; + struct pfs_file file; +}; + +static ssize_t read(struct pfs_futex *evs, struct futex_event __user *ufevt) +{ + int ret; + struct futex_event fevt; + + mutex_lock(&evs->mutex); + + fevt = evs->fevt; + + ret = -EAGAIN; + + if (!evs->queued) + ret = -EINVAL; + else if (list_empty(&evs->q.list)) + ret = futex_wait_unqueue(&evs->q); + + switch (ret) { + case 1: + ret = -EAGAIN; + case 0: + evs->queued = 0; + } + + mutex_unlock(&evs->mutex); + + if (ret < 0) + return ret; + + if (copy_to_user(ufevt, &fevt, sizeof(fevt))) + return -EFAULT; + + return 0; +} + +static ssize_t write(struct pfs_futex *evs, + const struct futex_event __user *ufevt) +{ + int ret; + struct futex_event fevt; + + if (copy_from_user(&fevt, ufevt, sizeof(fevt))) + return -EFAULT; + + mutex_lock(&evs->mutex); + + if (evs->queued) + futex_wait_unqueue(&evs->q); + + ret = futex_wait_queue(&evs->q, fevt.addr, fevt.val); + + if (ret) + evs->queued = 0; + else { + evs->queued = 1; + evs->fevt = fevt; + } + + mutex_unlock(&evs->mutex); + + return ret; +} + +static int poll(struct pfs_futex *evs) +{ + int ret; + + while (!mutex_trylock(&evs->mutex)) + cpu_relax(); + + ret = evs->queued && list_empty(&evs->q.list) ? POLLIN : 0; + + mutex_unlock(&evs->mutex); + + return ret; +} + +static int release(struct pfs_futex *evs) +{ + if (evs->queued) + futex_wait_unqueue(&evs->q); + + mutex_destroy(&evs->mutex); + + kfree(evs); + + return 0; +} + +static const struct pfs_operations futex_ops = { + .read = PFS_READ(read, struct pfs_futex, struct futex_event), + .write = PFS_WRITE(write, struct pfs_futex, struct futex_event), + .poll = PFS_POLL(poll, struct pfs_futex), + .release = PFS_RELEASE(release, struct pfs_futex), + .rsize = sizeof(struct futex_event), + .wsize = sizeof(struct futex_event), +}; + +asmlinkage long sys_plfutex(void) +{ + long error; + struct pfs_futex *evs; + + evs = kzalloc(sizeof(*evs), GFP_KERNEL); + if (!evs) + return -ENOMEM; + + mutex_init(&evs->mutex); + init_waitqueue_head(&evs->q.waiters); + + evs->file.data = evs; + evs->file.fops = &futex_ops; + evs->file.wait = &evs->q.waiters; + + error = pfs_open(&evs->file); + + if (error < 0) + release(evs); + + return error; +} Index: linux-2.6/init/Kconfig =================================================================== --- linux-2.6.orig/init/Kconfig +++ linux-2.6/init/Kconfig @@ -483,6 +483,13 @@ config POLLFS_TIMER help Pollable timer support +config POLLFS_FUTEX + bool "Enable pollfs futex" if EMBEDDED + default y + depends on POLLFS && FUTEX + help + Pollable futex support + config SHMEM bool "Use full shmem filesystem" if EMBEDDED default y -- - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/