kevent: generic poll and timer notifications.
Subsystems (2)
RFC 4/4 kevent: generic poll and timer notifications.
This patch includes generic poll/select and timer notifications.
Signed-off-by Evgeniy Polyakov <[email protected]>
kernel/kevent/kevent_poll.c new file +223 -0
@@ -0,0 +1,223 @@ +/* +* kevent_poll.c +* +* 2006 Copyright (c) Evgeniy Polyakov <[email protected]> +* All rights reserved. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +*/ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/list.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/timer.h> +#include <linux/file.h> +#include <linux/kevent.h> +#include <linux/poll.h> +#include <linux/fs.h> + +static kmem_cache_t *kevent_poll_container_cache; +static kmem_cache_t *kevent_poll_priv_cache; + +struct kevent_poll_ctl +{ +struct poll_table_struct pt; +struct kevent *k; +}; + +struct kevent_poll_wait_container +{ +struct list_head container_entry; +wait_queue_head_t *whead; +wait_queue_t wait; +struct kevent *k; +}; + +struct kevent_poll_private +{ +struct list_head container_list; +spinlock_t container_lock; +}; + +static int kevent_poll_enqueue (struct kevent *k); +static int kevent_poll_dequeue (struct kevent *k); +static int kevent_poll_callback (struct kevent *k); + +static int kevent_poll_wait_callback (wait_queue_t *wait, +unsigned mode,int sync,void *key) +{ +struct kevent_poll_wait_container *cont = + container_of(wait, struct kevent_poll_wait_container, wait); +struct kevent *k = cont->k; +struct file *file = k->st->origin; +unsigned long flags; +u32 revents, event; + + revents = file->f_op->poll (file,NULL ); +spin_lock_irqsave (&k->lock, flags); + event = k->event.event; +spin_unlock_irqrestore (&k->lock, flags); + +kevent_storage_ready (k->st,NULL , revents); + +return 0 ; +} + +static void kevent_poll_qproc (struct file *file,wait_queue_head_t *whead, +struct poll_table_struct *poll_table) +{ +struct kevent *k = + container_of(poll_table, struct kevent_poll_ctl, pt)->k; +struct kevent_poll_private *priv = k->priv; +struct kevent_poll_wait_container *cont; +unsigned long flags; + + cont =kmem_cache_alloc (kevent_poll_container_cache,SLAB_KERNEL ); +if (!cont) { +kevent_break (k); +return ; + } + + cont->k = k; +init_waitqueue_func_entry (&cont->wait, kevent_poll_wait_callback); + cont->whead = whead; + +spin_lock_irqsave (&priv->container_lock, flags); +list_add_tail (&cont->container_entry, &priv->container_list); +spin_unlock_irqrestore (&priv->container_lock, flags); + +add_wait_queue (whead, &cont->wait); +} + +static int kevent_poll_enqueue (struct kevent *k) +{ +struct file *file; +int err, ready =0 ; +unsigned int revents; +struct kevent_poll_ctl ctl; +struct kevent_poll_private *priv; + + file =fget (k->event.id.raw[0 ]); +if (!file) +return -ENODEV ; + + err = -EINVAL ; +if (!file->f_op || !file->f_op->poll) + goto err_out_fput; + + err = -ENOMEM ; + priv =kmem_cache_alloc (kevent_poll_priv_cache,SLAB_KERNEL ); +if (!priv) + goto err_out_fput; + +spin_lock_init (&priv->container_lock); +INIT_LIST_HEAD (&priv->container_list); + + k->priv = priv; + + ctl.k = k; +init_poll_funcptr (&ctl.pt, &kevent_poll_qproc); + + err =kevent_storage_enqueue (&file->st, k); +if (err) + goto err_out_free; + + revents = file->f_op->poll (file, &ctl.pt); +if (revents & k->event.event) { + ready =1 ; +kevent_poll_dequeue (k); + } + +return ready; + +err_out_free: +kmem_cache_free (kevent_poll_priv_cache, priv); +err_out_fput: +fput (file); +return err; +} + +static int kevent_poll_dequeue (struct kevent *k) +{ +struct file *file = k->st->origin; +struct kevent_poll_private *priv = k->priv; +struct kevent_poll_wait_container *w, *n; +unsigned long flags; + +kevent_storage_dequeue (k->st, k); + +spin_lock_irqsave (&priv->container_lock, flags); +list_for_each_entry_safe (w, n, &priv->container_list, container_entry) { +list_del (&w->container_entry); +remove_wait_queue (w->whead, &w->wait); +kmem_cache_free (kevent_poll_container_cache, w); + } +spin_unlock_irqrestore (&priv->container_lock, flags); + +kmem_cache_free (kevent_poll_priv_cache, priv); + k->priv =NULL ; + +fput (file); + +return 0 ; +} + +static int kevent_poll_callback (struct kevent *k) +{ +struct file *file = k->st->origin; +unsigned int revents = file->f_op->poll (file,NULL ); +return (revents & k->event.event); +} + +int kevent_init_poll (struct kevent *k) +{ +if (!kevent_poll_container_cache || !kevent_poll_priv_cache) +return -ENOMEM ; + + k->enqueue = &kevent_poll_enqueue; + k->dequeue = &kevent_poll_dequeue; + k->callback = &kevent_poll_callback; +return 0 ; +} + + +static int __init kevent_poll_sys_init (void ) +{ + kevent_poll_container_cache =kmem_cache_create ("kevent_poll_container_cache" , +sizeof (struct kevent_poll_wait_container ),0 ,0 ,NULL ,NULL ); +if (!kevent_poll_container_cache) { +printk (KERN_ERR "Failed to create kevent poll container cache.\n" ); +return -ENOMEM ; + } + + kevent_poll_priv_cache =kmem_cache_create ("kevent_poll_priv_cache" , +sizeof (struct kevent_poll_private ),0 ,0 ,NULL ,NULL ); +if (!kevent_poll_priv_cache) { +printk (KERN_ERR "Failed to create kevent poll private data cache.\n" ); +kmem_cache_destroy (kevent_poll_container_cache); + kevent_poll_container_cache =NULL ; +return -ENOMEM ; + } + +printk (KERN_INFO "Kevent poll()/select() subsystem has been initialized.\n" ); +return 0 ; +} + +static void __exit kevent_poll_sys_fini(void) +{ +kmem_cache_destroy (kevent_poll_priv_cache); +kmem_cache_destroy (kevent_poll_container_cache); +} + +module_init (kevent_poll_sys_init); +module_exit (kevent_poll_sys_fini);
kernel/kevent/kevent_timer.c new file +112 -0
112 lines not on this page · raw message
Signature · 1 line
Evgeniy Polyakov