lkml.org 
[lkml]   [2007]   [Apr]   [1]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[patch 08/12] pollfs: pollable futex
    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.

    Building block for pollable semaphores and user-defined events.

    Signed-off-by: Davi E. M. Arnaut <davi@haxent.com.br>
    ---

    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,155 @@
    +/*
    + * pollable futex
    + *
    + * Copyright (C) 2007 Davi E. M. Arnaut
    + *
    + * Licensed under the GNU GPL. See the file COPYING for details.
    + */
    +
    +#include <linux/kernel.h>
    +#include <linux/sched.h>
    +#include <linux/module.h>
    +#include <linux/slab.h>
    +#include <linux/err.h>
    +#include <linux/wait.h>
    +#include <linux/poll.h>
    +#include <linux/pollfs_fs.h>
    +#include <linux/futex.h>
    +
    +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 = 1;
    + evs->fevt = fevt;
    + } else {
    + evs->queued = 0;
    + evs->fevt.addr = NULL;
    + }
    +
    + 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/

    \
     
     \ /
      Last update: 2007-04-01 18:09    [W:4.624 / U:0.028 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site