diff -aur --exclude=CVS linux/Documentation/Configure.help 2.4.18-kpoll/Documentation/Configure.help --- linux/Documentation/Configure.help Mon Feb 25 20:37:51 2002 +++ 2.4.18-kpoll/Documentation/Configure.help Tue Mar 26 16:54:11 2002 @@ -24382,6 +24382,13 @@ information: http://www.candelatech.com/~greear/vlan.html If unsure, you can safely say 'N'. +/dev/kpoll support +CONFIG_KPOLL + '/dev/kpoll' is drived from '/dev/epoll' but is also handling pending + events like a regular poll or select. It does so in an efficent way + making /dev/kpoll a real alternative to poll or select. Create the + /dev/kpoll with "mknod /dev/kpoll c 10 152". + # # A couple of things I keep forgetting: # capitalize: AppleTalk, Ethernet, DOS, DMA, FAT, FTP, Internet, diff -aur --exclude=CVS linux/Makefile 2.4.18-kpoll/Makefile --- linux/Makefile Mon Feb 25 20:37:52 2002 +++ 2.4.18-kpoll/Makefile Tue Mar 26 16:54:10 2002 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 18 -EXTRAVERSION = +EXTRAVERSION = kpoll KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) diff -aur --exclude=CVS linux/drivers/char/Config.in 2.4.18-kpoll/drivers/char/Config.in --- linux/drivers/char/Config.in Mon Feb 25 20:37:57 2002 +++ 2.4.18-kpoll/drivers/char/Config.in Tue Mar 26 16:54:11 2002 @@ -185,6 +185,7 @@ dep_tristate 'Intel i8x0 Random Number Generator support' CONFIG_INTEL_RNG $CONFIG_PCI tristate '/dev/nvram support' CONFIG_NVRAM +tristate '/dev/kpoll - Efficient replacement to poll' CONFIG_KPOLL tristate 'Enhanced Real Time Clock Support' CONFIG_RTC if [ "$CONFIG_IA64" = "y" ]; then bool 'EFI Real Time Clock Services' CONFIG_EFI_RTC diff -aur --exclude=CVS linux/drivers/char/Makefile 2.4.18-kpoll/drivers/char/Makefile --- linux/drivers/char/Makefile Mon Feb 25 20:37:57 2002 +++ 2.4.18-kpoll/drivers/char/Makefile Tue Mar 26 16:54:11 2002 @@ -192,6 +192,7 @@ ifeq ($(CONFIG_PPC),) obj-$(CONFIG_NVRAM) += nvram.o endif +obj-$(CONFIG_KPOLL) += kpoll.o obj-$(CONFIG_TOSHIBA) += toshiba.o obj-$(CONFIG_I8K) += i8k.o obj-$(CONFIG_DS1620) += ds1620.o diff -aur --exclude=CVS linux/drivers/char/kpoll.c 2.4.18-kpoll/drivers/char/kpoll.c --- linux/drivers/char/kpoll.c Sat Jul 13 13:00:11 2002 +++ 2.4.18-kpoll/drivers/char/kpoll.c Sat Mar 30 07:54:23 2002 @@ -0,0 +1,1064 @@ +/* + * kpoll.c - driver for /dev/kpoll + * + * --- Notices from eventpoll.c, upon which this driver is based --- + * + * Copyright (C) 2001, Davide Libenzi + * + * Efficent event polling implementation + * + * --- End of notice from eventpoll.c --- + * + * eventpoll was changed to handle pending events, making kpoll + * simpler to use when replacing poll() + * + * also added the possiblity to update new file descriptors from + * other threads and waking the poll when the updated file descriptor + * had pending events. + * + * Tony Rogvall + * Per Bergqvist + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +#define DEBUG 0 +#ifdef DEBUG +#define DPRINTK(x) printk x +#define DNPRINTK(n,x) if (n <= DEBUG) printk x +#else +#define DPRINTK(x) +#define DNPRINTK(n,x) +#endif + +#define DEBUG_DPI 0 + +#if DEBUG_DPI +#define DPI_SLAB_DEBUG (SLAB_DEBUG_FREE | SLAB_RED_ZONE /* | SLAB_POISON */) +#else +#define DPI_SLAB_DEBUG 0 +#endif + +#define INITIAL_HASH_BITS 7 +#define MAX_HASH_BITS 18 +#define RESIZE_LENGTH 2 + +#define dpi_mem_alloc() (struct kpitem *) kmem_cache_alloc(dpi_cache, SLAB_KERNEL) +#define dpi_mem_free(p) kmem_cache_free(dpi_cache, p) + +#define EVENT_PAGE_INDEX(n) ((n) / KPOLLFD_X_PAGE) +#define EVENT_PAGE_REM(n) ((n) % KPOLLFD_X_PAGE) +#define EVENT_PAGE_OFFSET(n) (((n) % KPOLLFD_X_PAGE) * sizeof(struct pollfd)) + +#define PAGE_FD(pages, ix) \ +(struct pollfd *) ((pages)[EVENT_PAGE_INDEX((ix))]+EVENT_PAGE_OFFSET((ix))) + +#define MAX_EVT(kp) ((kp)->numpages * KPOLLFD_X_PAGE) + +typedef unsigned long long event_version_t; + +struct kpoll { + rwlock_t lock; + wait_queue_head_t wq; + wait_queue_head_t poll_wait; + struct list_head *hash; + unsigned int hbits; + unsigned int hmask; + atomic_t hents; + atomic_t resize; + int numpages; + char **pages; + char *pages0[MAX_KPOLL_PAGES]; + char *pages1[MAX_KPOLL_PAGES]; + atomic_t mmapped; + int eventcnt0; + int eventcnt; + int eventpoll; + event_version_t ver; + atomic_t shutdown; +}; + +struct kpitem { + struct list_head llink; + struct kpoll *kp; + struct pollfd pfd; + int index; + event_version_t ver; +}; + + +static int kp_alloc_pages(char **pages, int numpages); +static int kp_free_pages(char **pages, int numpages); +static int kp_init(struct kpoll *kp); +static void kp_free(struct kpoll *kp); +static inline struct kpitem *kp_find_nl(struct kpoll *kp, int fd); +static struct kpitem *kp_find(struct kpoll *kp, int fd); +static int kp_hashresize(struct kpoll *kp, unsigned long *kflags); +static int kp_insert(struct kpoll *kp, struct pollfd *pfd, struct file* file); +static int kp_remove(struct kpoll *kp, struct kpitem *dpi, struct file* file); +static int kp_update(struct kpoll *kp, struct kpitem *dpi, + struct pollfd *pfd, struct file* file); +static void notify_proc(struct file *file, void *data, unsigned long *local, long *event); +static int open_kpoll(struct inode *inode, struct file *file); +static int close_kpoll(struct inode *inode, struct file *file); +static unsigned int poll_kpoll(struct file *file, poll_table *wait); +static int write_kpoll(struct file *file, const char *buffer, size_t count, + loff_t *ppos); +static int kp_poll(struct kpoll *kp, void *arg); +static int ioctl_kpoll(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg); +static void kpoll_mm_open(struct vm_area_struct * vma); +static void kpoll_mm_close(struct vm_area_struct * vma); +static int mmap_kpoll(struct file *file, struct vm_area_struct *vma); + + + + +static kmem_cache_t *dpi_cache; + +static struct file_operations kpoll_fops = { + write: write_kpoll, + ioctl: ioctl_kpoll, + mmap: mmap_kpoll, + open: open_kpoll, + release: close_kpoll, + poll: poll_kpoll +}; + +static struct vm_operations_struct kpoll_mmap_ops = { + open: kpoll_mm_open, + close: kpoll_mm_close, +}; + +static struct miscdevice kpoll = { + KPOLL_MINOR, "kpoll", &kpoll_fops +}; + + + + +static int kp_alloc_pages(char **pages, int numpages) +{ + int ii; + + for (ii = 0; ii < numpages; ii++) { + pages[ii] = (char *) __get_free_pages(GFP_KERNEL, 0); + if (!pages[ii]) { + for (--ii; ii >= 0; ii--) { + clear_bit(PG_reserved, &virt_to_page(pages[ii])->flags); + free_pages((unsigned long) pages[ii], 0); + } + return -ENOMEM; + } + set_bit(PG_reserved, &virt_to_page(pages[ii])->flags); + } + return 0; +} + + +static int kp_free_pages(char **pages, int numpages) +{ + int ii; + + for (ii = 0; ii < numpages; ii++) { + clear_bit(PG_reserved, &virt_to_page(pages[ii])->flags); + free_pages((unsigned long) pages[ii], 0); + } + return 0; +} + + +static int kp_init(struct kpoll *kp) +{ + int ii, hentries; + + rwlock_init(&kp->lock); + init_waitqueue_head(&kp->wq); + init_waitqueue_head(&kp->poll_wait); + kp->hbits = INITIAL_HASH_BITS; + kp->hmask = (1 << kp->hbits) - 1; + atomic_set(&kp->hents, 0); + atomic_set(&kp->resize, 0); + atomic_set(&kp->mmapped, 0); + kp->numpages = 0; + kp->pages = kp->pages0; + kp->eventcnt = 0; + kp->eventcnt0 = 0; + kp->ver = 1; + kp->eventpoll = 0; + atomic_set(&kp->shutdown, 0); + + hentries = kp->hmask + 1; + if (!(kp->hash = (struct list_head *) vmalloc(hentries * sizeof(struct list_head)))) + return -ENOMEM; + + for (ii = 0; ii < hentries; ii++) + INIT_LIST_HEAD(&kp->hash[ii]); + + return 0; +} + + +static void kp_free(struct kpoll *kp) +{ + int ii; + struct list_head *lnk; + struct file *file; + + lock_kernel(); + for (ii = 0; ii <= kp->hmask; ii++) { + while ((lnk = list_first(&kp->hash[ii]))) { + struct kpitem *dpi = list_entry(lnk, struct kpitem, llink); + + if (current->files && (file = fcheck(dpi->pfd.fd))) + file_notify_delcb(file, notify_proc); + list_del(lnk); + dpi_mem_free(dpi); + } + } + vfree(kp->hash); + if (kp->numpages > 0) { + kp_free_pages(kp->pages0, kp->numpages); + kp_free_pages(kp->pages1, kp->numpages); + } + unlock_kernel(); +} + + +static inline struct kpitem *kp_find_nl(struct kpoll *kp, int fd) +{ + struct kpitem *dpi = NULL; + struct list_head *lsthead, *lnk; + + lsthead = &kp->hash[fd & kp->hmask]; + list_for_each(lnk, lsthead) { + dpi = list_entry(lnk, struct kpitem, llink); + + if (dpi->pfd.fd == fd) break; + dpi = NULL; + } + + DNPRINTK(3, (KERN_INFO "[%p] /dev/kpoll: kp_find(%d) -> %p\n", current, fd, dpi)); + + return dpi; +} + + +static struct kpitem *kp_find(struct kpoll *kp, int fd) +{ + struct kpitem *dpi; + unsigned long flags; + + read_lock_irqsave(&kp->lock, flags); + + dpi = kp_find_nl(kp, fd); + + read_unlock_irqrestore(&kp->lock, flags); + + return dpi; +} + +/* remove and item from current set (FIXME: inline) */ +static void kp_remove_nl(struct kpoll *kp, struct kpitem *dpi) +{ + if ((dpi->ver == kp->ver) && + (dpi->index >= 0) && (dpi->index < kp->eventcnt)) { + struct pollfd *pfd = PAGE_FD(kp->pages, dpi->index); + if (dpi->index < --kp->eventcnt) { + struct kpitem *ldpi; + *pfd = *PAGE_FD(kp->pages, kp->eventcnt); + if ((ldpi = kp_find_nl(kp, pfd->fd))) + ldpi->index = dpi->index; + } + dpi->index = -1; + dpi->ver = kp->ver - 1; + } +} + +static int kp_hashresize(struct kpoll *kp, unsigned long *kflags) +{ + struct list_head *hash, *oldhash; + unsigned int hbits = kp->hbits + 1; + unsigned int hmask = (1 << hbits) - 1; + int ii, res, hentries = hmask + 1; + unsigned long flags = *kflags; + + DNPRINTK(3, (KERN_INFO "[%p] /dev/kpoll: kp_hashresize(%p) bits=%u\n", current, kp, hbits)); + + write_unlock_irqrestore(&kp->lock, flags); + + res = -ENOMEM; + if (!(hash = (struct list_head *) vmalloc(hentries * sizeof(struct list_head)))) { + write_lock_irqsave(&kp->lock, flags); + goto out; + } + + for (ii = 0; ii < hentries; ii++) + INIT_LIST_HEAD(&hash[ii]); + + write_lock_irqsave(&kp->lock, flags); + + oldhash = kp->hash; + for (ii = 0; ii <= kp->hmask; ii++) { + struct list_head *oldhead = &oldhash[ii], *lnk; + + while ((lnk = list_first(oldhead))) { + struct kpitem *dpi = list_entry(lnk, struct kpitem, llink); + + list_del(lnk); + list_add(lnk, &hash[dpi->pfd.fd & hmask]); + } + } + + kp->hash = hash; + kp->hbits = hbits; + kp->hmask = hmask; + + write_unlock_irqrestore(&kp->lock, flags); + vfree(oldhash); + write_lock_irqsave(&kp->lock, flags); + + res = 0; + out: + *kflags = flags; + atomic_dec(&kp->resize); + return res; +} + +/* + * When updating an existing poll item, we need to check current status + * 1. status may have changed + * a) trigged event was OUT new event is IN and IN was ready + * then just update the revents to reflect that + * b) trigged event was OUT and new event is IN and there is no IN + * condtion, then the slot is removed and eventcount is updated + * + * 2. status is new + * a) no revents but poll return IN/OUT then insert a slot + * and update revents + * + * returns: + * 0 ok but nothing where added + * 1 ok and we added the fd, had and event by polling + * <0 error + * + */ + +static int kp_update(struct kpoll *kp, struct kpitem *dpi, + struct pollfd *pfd, struct file* file) +{ + unsigned long flags; + int res = 0; + + write_lock_irqsave(&kp->lock, flags); + + dpi->pfd.events = pfd->events; + dpi->pfd.revents = 0; + + if (!kp->eventpoll && file->f_op && file->f_op->poll) { + unsigned int mask; + struct pollfd *dpfd; + + mask = file->f_op->poll(file,NULL); + mask &= (dpi->pfd.events | POLLERR | POLLHUP); + dpi->pfd.revents = mask; + + if (mask) { /* update or insert event */ + if (dpi->ver == kp->ver) { + if ((dpi->index >= 0) && (dpi->index < kp->eventcnt)) { + dpfd = PAGE_FD(kp->pages, dpi->index); + *dpfd = dpi->pfd; + } + } else if (kp->eventcnt < MAX_EVT(kp)) { + dpi->index = kp->eventcnt++; + dpi->ver = kp->ver; + dpfd = PAGE_FD(kp->pages, dpi->index); + *dpfd = dpi->pfd; + res = 1; + } + } else { + kp_remove_nl(kp, dpi); + } + } + + write_unlock_irqrestore(&kp->lock, flags); + + return res; +} + +/* + * Insert a new file descriptor. + * + * returns: + * 0 ok inserted but no pending events + * 1 ok inserted and had pending events + * <0 error + */ + +static int kp_insert(struct kpoll *kp, struct pollfd *pfd, struct file* file) +{ + struct kpitem *dpi; + unsigned long flags; + int res = 0; + + if (atomic_read(&kp->hents) >= MAX_EVT(kp)) + return -E2BIG; + + if (!(dpi = dpi_mem_alloc())) + return -ENOMEM; + + INIT_LIST_HEAD(&dpi->llink); + dpi->kp = kp; + dpi->pfd = *pfd; + dpi->index = -1; + dpi->ver = kp->ver - 1; + + write_lock_irqsave(&kp->lock, flags); + + list_add(&dpi->llink, &kp->hash[pfd->fd & kp->hmask]); + atomic_inc(&kp->hents); + + if (!atomic_read(&kp->resize) && + (atomic_read(&kp->hents) >> kp->hbits) > RESIZE_LENGTH && + kp->hbits < MAX_HASH_BITS) { + atomic_inc(&kp->resize); + kp_hashresize(kp, &flags); + } + + write_unlock_irqrestore(&kp->lock, flags); + + file_notify_addcb(file, notify_proc, dpi); + + if (!kp->eventpoll) { + write_lock_irqsave(&kp->lock, flags); + + /* check for pending events */ + if ( file->f_op && file->f_op->poll ) { + unsigned int mask; + mask = file->f_op->poll(file,NULL); + mask &= (dpi->pfd.events | POLLERR | POLLHUP ); + if ( mask ) { + dpi->pfd.revents = mask; + if (kp->eventcnt < MAX_EVT(kp)) { + dpi->index = kp->eventcnt++; + dpi->ver = kp->ver; + pfd = PAGE_FD(kp->pages, dpi->index); + *pfd = dpi->pfd; + res = 1; + } + } + } + write_unlock_irqrestore(&kp->lock, flags); + } + + DNPRINTK(3, (KERN_INFO "[%p] /dev/kpoll: kp_insert(%p, %d)\n", current, kp, pfd->fd)); + return res; +} + +/* + * Remove a file descriptor. + * + * returns: + * 0 ok + * <0 error + */ + +static int kp_remove(struct kpoll *kp, struct kpitem *dpi, struct file* file) +{ + int fd = dpi->pfd.fd; + unsigned long flags; + + if (file != NULL) + file_notify_delcb(file, notify_proc); + + write_lock_irqsave(&kp->lock, flags); + + list_del(&dpi->llink); + atomic_dec(&kp->hents); + + kp_remove_nl(kp, dpi); + + write_unlock_irqrestore(&kp->lock, flags); + + dpi_mem_free(dpi); + + DNPRINTK(3, (KERN_INFO "[%p] /dev/kpoll: kp_remove(%p, %d)\n", + current, kp, fd)); + return 0; +} + +static void notify_proc(struct file *file, void *data, unsigned long *local, long *event) +{ + struct kpitem *dpi = (struct kpitem *) data; + struct kpoll *kp = dpi->kp; + struct pollfd *pfd; + + DNPRINTK(3, (KERN_INFO "[%p] /dev/kpoll: notify(%p, %p, %08lx, %08lx) kp=%p\n", + current, file, data, event[0], event[1], kp)); + + if (atomic_read(&kp->shutdown)) return; + + write_lock(&kp->lock); + + if (event[1] & POLLREMOVE) { + /* file is about to get closed */ + if ( current->files ) + file_notify_delcb(file, notify_proc); + list_del(&dpi->llink); + atomic_dec(&kp->hents); + + kp_remove_nl(kp, dpi); + + write_unlock(&kp->lock); + dpi_mem_free(dpi); + return; + } + else if ((dpi->pfd.events | POLLERR | POLLHUP) & event[1]) { + if ((dpi->index < 0) || (dpi->ver != kp->ver)) { + if (kp->eventcnt >= MAX_EVT(kp)) + goto out; + dpi->index = kp->eventcnt++; + dpi->ver = kp->ver; + pfd = PAGE_FD(kp->pages, dpi->index); + *pfd = dpi->pfd; + } else { + /* FIXME: when do we need this? */ + pfd = PAGE_FD(kp->pages, dpi->index); + if (pfd->fd != dpi->pfd.fd) { + if (kp->eventcnt >= MAX_EVT(kp)) + goto out; + dpi->index = kp->eventcnt++; + pfd = PAGE_FD(kp->pages, dpi->index); + *pfd = dpi->pfd; + } + dpi->ver = kp->ver; + } + pfd->revents |= ((pfd->events | POLLERR | POLLHUP) & event[1]); + + if (waitqueue_active(&kp->wq)) + wake_up(&kp->wq); + if (waitqueue_active(&kp->poll_wait)) + wake_up(&kp->poll_wait); + } + + out: + write_unlock(&kp->lock); +} + + +static int open_kpoll(struct inode *inode, struct file *file) +{ + int res; + struct kpoll *kp; + + if (!(kp = kmalloc(sizeof(struct kpoll), GFP_KERNEL))) + return -ENOMEM; + + memset(kp, 0, sizeof(*kp)); + if ((res = kp_init(kp))) { + kfree(kp); + return res; + } + + file->private_data = kp; + + MOD_INC_USE_COUNT; + + DNPRINTK(3, (KERN_INFO "[%p] /dev/kpoll: open() kp=%p\n", current, kp)); + return 0; +} + + +static int close_kpoll(struct inode *inode, struct file *file) +{ + struct kpoll *kp = file->private_data; + + atomic_set(&kp->shutdown, 1); + + kp_free(kp); + + kfree(kp); + + MOD_DEC_USE_COUNT; + + DNPRINTK(3, (KERN_INFO "[%p] /dev/kpoll: close() kp=%p\n", current, kp)); + return 0; +} + + +static int write_kpoll(struct file *file, const char *buffer, size_t count, + loff_t *ppos) +{ + int res, rcount, ready; + struct kpoll *kp = file->private_data; + + DNPRINTK(3, (KERN_INFO "[%p] /dev/kpoll: write(%p, %d)\n", current, kp, count)); + + if (count % sizeof(struct pollfd)) + return -EINVAL; + + if ((res = verify_area(VERIFY_READ, buffer, count))) + return res; + + rcount = 0; + ready = 0; + + lock_kernel(); /* Is this needed when we use fget (I do not think so) */ + + while (count > 0) { + struct pollfd pfd; + + __copy_from_user(&pfd, buffer, sizeof(pfd)); + + if (pfd.fd >= 0) { + struct kpitem *dpi = kp_find(kp, pfd.fd); + struct file *file = fget(pfd.fd); + + if (file == NULL) + pfd.events = POLLREMOVE; + if (pfd.events & POLLREMOVE) { + if (dpi) { + kp_remove(kp, dpi, file); + rcount += sizeof(pfd); + } + } else if (dpi) { + if ((res = kp_update(kp, dpi, &pfd, file)) >= 0) { + rcount += sizeof(pfd); + if (res > 0) + ready = 1; + } + } else { + pfd.revents = 0; + if ((res = kp_insert(kp, &pfd, file)) >= 0) { + rcount += sizeof(pfd); + if (res > 0) + ready = 1; + } + } + if (file != NULL) + fput(file); + } + buffer += sizeof(pfd); + count -= sizeof(pfd); + } + + unlock_kernel(); + + if (ready) { + unsigned long flags; + + write_lock_irqsave(&kp->lock, flags); + if (kp->eventcnt) { + if (waitqueue_active(&kp->wq)) + wake_up(&kp->wq); + if (waitqueue_active(&kp->poll_wait)) + wake_up(&kp->poll_wait); + } + write_unlock_irqrestore(&kp->lock, flags); + } + return rcount; +} + +/* + * check the slots that had events in previous KP_POLL, need to + * re-poll them if they have not trigged already. + * Since there may be an input ready, but nothing to trigg that!! + * scan_only = 0 moves trigged fd to current version + * scan_only = 1 returns realy ready fd count + * scan_only = 2 return 0|1 if there are ready fds + */ +static int kp_scan_previous(struct kpoll *kp, int scan_only) +{ + int i; + int readycnt = 0; + char** pages = (kp->pages == kp->pages0) ? kp->pages1 : kp->pages0; + + for (i = 0; i < kp->eventcnt0; i++) { + struct pollfd* pfd = PAGE_FD(pages, i); + struct kpitem *dpi = kp_find_nl(kp, pfd->fd); + if ((dpi != NULL) && + (dpi->ver != kp->ver) && + (dpi->pfd.events & ~(POLLHUP|POLLERR))) { + struct file *file = fget(pfd->fd); + + if (file != NULL) { + struct pollfd *dpfd; + unsigned int mask = 0; + + if (file->f_op && file->f_op->poll) + mask = file->f_op->poll(file,NULL); + fput(file); + mask &= (dpi->pfd.events | POLLERR | POLLHUP); + + if (!scan_only) + dpi->pfd.revents = mask; + if (mask) { + readycnt++; + if (scan_only == 2) break; + if ((!scan_only) && (kp->eventcnt < MAX_EVT(kp))) { + dpi->index = kp->eventcnt++; + dpi->ver = kp->ver; + dpfd = PAGE_FD(kp->pages, dpi->index); + *dpfd = dpi->pfd; + } + } + } + } + } + if ( (!scan_only) || (!readycnt) ) + kp->eventcnt0 = 0; + return readycnt; +} + +static void kp_scan_current(struct kpoll *kp, int max_index) +{ + int i; + + /* poll the fds we haven't scan in this run */ + for(i = 0; i < max_index; i++) { + struct pollfd* pfd = PAGE_FD(kp->pages, i); + struct kpitem *dpi = kp_find_nl(kp, pfd->fd); + if ((dpi != NULL) && + (dpi->pfd.events & ~(POLLHUP|POLLERR))) { + struct file *file = fget(pfd->fd); + + if (file != NULL) { + unsigned int mask = 0; + + if (file->f_op && file->f_op->poll) + mask = file->f_op->poll(file,NULL); + fput(file); + mask &= (dpi->pfd.events|POLLERR|POLLHUP); + + dpi->pfd.revents = mask; + if (mask) { + *pfd = dpi->pfd; + } else { + kp_remove_nl(kp, dpi); + } + } + } + } +} + + +static unsigned int poll_kpoll(struct file *file, poll_table *wait) +{ + unsigned long flags; + struct kpoll *kp = file->private_data; + + write_lock_irqsave(&kp->lock, flags); + + if (kp_scan_previous(kp,2)) { + write_unlock_irqrestore(&kp->lock, flags); + return POLLIN | POLLRDNORM; + } + write_unlock_irqrestore(&kp->lock, flags); + + poll_wait(file, &kp->poll_wait, wait); + if (kp->eventcnt) + return POLLIN | POLLRDNORM; + + return 0; +} + + +static int kp_poll(struct kpoll *kp, void *arg) +{ + int res = 0; + long timeout; + unsigned long flags; + struct k_poll dvp; + wait_queue_t wait; + + if (copy_from_user(&dvp, arg, sizeof(struct k_poll))) + return -EFAULT; + + if (!atomic_read(&kp->mmapped)) + return -EINVAL; + + DNPRINTK(3, (KERN_INFO "[%p] /dev/kpoll: ioctl(%p, KP_POLL, %d)\n", current, kp, dvp.kp_timeout)); + + write_lock_irqsave(&kp->lock, flags); + + if (!kp->eventpoll) { + kp_scan_current(kp,kp->eventcnt); + kp_scan_previous(kp,0); + } + + res = 0; + if (!kp->eventcnt) { + init_waitqueue_entry(&wait, current); + add_wait_queue(&kp->wq, &wait); + if ((timeout = dvp.kp_timeout) != 0) { + /* from sys_poll */ + if ((unsigned long) timeout < MAX_SCHEDULE_TIMEOUT / HZ) + timeout = (unsigned long)(timeout*HZ+999)/1000+1; + else /* Negative or overflow */ + timeout = MAX_SCHEDULE_TIMEOUT; + } + + for (;;) { + if (kp->eventcnt || !timeout) + break; + if (signal_pending(current)) { + res = -EINTR; + break; + } + + set_current_state(TASK_INTERRUPTIBLE); + + write_unlock_irqrestore(&kp->lock, flags); + timeout = schedule_timeout(timeout); + write_lock_irqsave(&kp->lock, flags); + } + remove_wait_queue(&kp->wq, &wait); + + set_current_state(TASK_RUNNING); + } + + if (!res && kp->eventcnt) { + kp->eventcnt0 = kp->eventcnt; + res = kp->eventcnt; + kp->eventcnt = 0; + ++kp->ver; + if (kp->pages == kp->pages0) { + kp->pages = kp->pages1; + dvp.kp_resoff = 0; + } else { + kp->pages = kp->pages0; + dvp.kp_resoff = kp->numpages * PAGE_SIZE; + } + } + + write_unlock_irqrestore(&kp->lock, flags); + + if (res > 0) + copy_to_user(arg, &dvp, sizeof(struct k_poll)); + + DNPRINTK(3, (KERN_INFO "[%p] /dev/kpoll: ioctl(%p, KP_POLL, %d) == %d\n", current, kp, dvp.kp_timeout, res)); + return res; +} + + +static int ioctl_kpoll(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int res, numpages; + struct kpoll *kp = file->private_data; + struct kpitem *dpi; + unsigned long flags; + struct pollfd pfd; + + switch (cmd) { + case KP_ALLOC: + if (atomic_read(&kp->mmapped)) + return -EBUSY; + + numpages = KP_FDS_PAGES(arg); + if (numpages > MAX_KPOLL_PAGES) + return -EINVAL; + + res = 0; + write_lock_irqsave(&kp->lock, flags); + if (numpages > kp->numpages) { + if (!(res = kp_alloc_pages(&kp->pages0[kp->numpages], numpages - kp->numpages))) { + if (!(res = kp_alloc_pages(&kp->pages1[kp->numpages], numpages - kp->numpages))) { + kp->numpages = numpages; + } else { + kp_free_pages(&kp->pages0[kp->numpages], numpages - kp->numpages); + } + } + } + write_unlock_irqrestore(&kp->lock, flags); + + DNPRINTK(3, (KERN_INFO "[%p] /dev/kpoll: ioctl(%p, KP_ALLOC, %lu) == %d\n", + current, kp, arg, res)); + return res; + + case KP_FREE: + if (atomic_read(&kp->mmapped)) + return -EBUSY; + + res = -EINVAL; + write_lock_irqsave(&kp->lock, flags); + if (kp->numpages > 0) { + kp_free_pages(kp->pages0, kp->numpages); + kp_free_pages(kp->pages1, kp->numpages); + kp->numpages = 0; + kp->pages = kp->pages0; + res = 0; + } + write_unlock_irqrestore(&kp->lock, flags); + + DNPRINTK(3, (KERN_INFO "[%p] /dev/kpoll: ioctl(%p, KP_FREE) == %d\n", + current, kp, res)); + return res; + + case KP_POLL: + return kp_poll(kp, (void *) arg); + + case KP_EVENTPOLL: + kp->eventpoll = (int) arg; + return 0; + + + case KP_ISPOLLED: + if (copy_from_user(&pfd, (void *) arg, sizeof(struct pollfd))) + return 0; + + read_lock_irqsave(&kp->lock, flags); + + res = 0; + if (!(dpi = kp_find_nl(kp, pfd.fd))) + goto out_ispolled; + + pfd = dpi->pfd; + res = 1; + + out_ispolled: + read_unlock_irqrestore(&kp->lock, flags); + + if (res) + copy_to_user((void *) arg, &pfd, sizeof(struct pollfd)); + + DNPRINTK(3, (KERN_INFO "[%p] /dev/kpoll: ioctl(%p, KP_ISPOLLED, %d) == %d\n", + current, kp, pfd.fd, res)); + return res; + } + + return -EINVAL; +} + + +static void kpoll_mm_open(struct vm_area_struct * vma) +{ + struct file *file = vma->vm_file; + struct kpoll *kp = file->private_data; + + if (kp) atomic_inc(&kp->mmapped); + + DNPRINTK(3, (KERN_INFO "[%p] /dev/kpoll: mm_open(%p)\n", current, kp)); +} + + +static void kpoll_mm_close(struct vm_area_struct * vma) +{ + struct file *file = vma->vm_file; + struct kpoll *kp = file->private_data; + + if (kp) atomic_dec(&kp->mmapped); + + DNPRINTK(3, (KERN_INFO "[%p] /dev/kpoll: mm_close(%p)\n", current, kp)); +} + + +static int mmap_kpoll(struct file *file, struct vm_area_struct *vma) +{ + struct kpoll *kp = file->private_data; + unsigned long start, flags; + int ii, res; + int numpages; + size_t mapsize; + + DNPRINTK(3, (KERN_INFO "[%p] /dev/kpoll: mmap(%p, %lx, %lx)\n", + current, kp, vma->vm_start, vma->vm_pgoff << PAGE_SHIFT)); + + if ((vma->vm_pgoff << PAGE_SHIFT) != 0) + return -EINVAL; + + mapsize = PAGE_ALIGN(vma->vm_end - vma->vm_start); + numpages = mapsize >> PAGE_SHIFT; + + write_lock_irqsave(&kp->lock, flags); + + res = -EINVAL; + if (numpages != (2 * kp->numpages)) + goto out; + + start = vma->vm_start; + for (ii = 0; ii < kp->numpages; ii++) { + if (remap_page_range(start, __pa(kp->pages0[ii]), + PAGE_SIZE, vma->vm_page_prot)) + goto out; + start += PAGE_SIZE; + } + for (ii = 0; ii < kp->numpages; ii++) { + if (remap_page_range(start, __pa(kp->pages1[ii]), + PAGE_SIZE, vma->vm_page_prot)) + goto out; + start += PAGE_SIZE; + } + vma->vm_ops = &kpoll_mmap_ops; + atomic_set(&kp->mmapped, 1); + res = 0; + out: + write_unlock_irqrestore(&kp->lock, flags); + + DNPRINTK(3, (KERN_INFO "[%p] /dev/kpoll: mmap(%p, %lx, %lx) == %d\n", + current, kp, vma->vm_start, vma->vm_pgoff << PAGE_SHIFT, res)); + return res; +} + + +int __init kpoll_init(void) +{ + dpi_cache = kmem_cache_create("kpoll", + sizeof(struct kpitem), + __alignof__(struct kpitem), + DPI_SLAB_DEBUG, NULL, NULL); + if (!dpi_cache) { + printk(KERN_INFO "[%p] /dev/kpoll: driver install failed.\n", current); + return -ENOMEM; + } + + printk(KERN_INFO "[%p] /dev/kpoll: driver installed.\n", current); + + misc_register(&kpoll); + + return 0; +} + + +module_init(kpoll_init); + +#ifdef MODULE + +void cleanup_module(void) +{ + misc_deregister(&kpoll); + kmem_cache_destroy(dpi_cache); + printk(KERN_INFO "[%p] /dev/kpoll: driver cleaned up.\n", current); + +} + +#endif diff -aur --exclude=CVS linux/fs/Makefile 2.4.18-kpoll/fs/Makefile --- linux/fs/Makefile Mon Feb 25 20:38:07 2002 +++ 2.4.18-kpoll/fs/Makefile Tue Mar 26 16:54:11 2002 @@ -7,12 +7,12 @@ O_TARGET := fs.o -export-objs := filesystems.o open.o dcache.o buffer.o +export-objs := filesystems.o open.o dcache.o buffer.o fcblist.o mod-subdirs := nls obj-y := open.o read_write.o devices.o file_table.o buffer.o \ super.o block_dev.o char_dev.o stat.o exec.o pipe.o namei.o \ - fcntl.o ioctl.o readdir.o select.o fifo.o locks.o \ + fcntl.o ioctl.o readdir.o select.o fifo.o locks.o fcblist.o \ dcache.o inode.o attr.o bad_inode.o file.o iobuf.o dnotify.o \ filesystems.o namespace.o seq_file.o diff -aur --exclude=CVS linux/fs/fcblist.c 2.4.18-kpoll/fs/fcblist.c --- linux/fs/fcblist.c Sat Jul 13 13:00:22 2002 +++ 2.4.18-kpoll/fs/fcblist.c Sat Jul 13 07:34:41 2002 @@ -0,0 +1,126 @@ +/* + * linux/fs/fcblist.c + * + * Copyright (C) 2001, Davide Libenzi + * + * Handle file callbacks + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +long ion_band_table[NSIGPOLL] = { + ION_IN, /* POLL_IN */ + ION_OUT, /* POLL_OUT */ + ION_IN, /* POLL_MSG */ + ION_ERR, /* POLL_ERR */ + 0, /* POLL_PRI */ + ION_HUP /* POLL_HUP */ +}; + +long poll_band_table[NSIGPOLL] = { + POLLIN | POLLRDNORM, /* POLL_IN */ + POLLOUT | POLLWRNORM | POLLWRBAND, /* POLL_OUT */ + POLLIN | POLLRDNORM | POLLMSG, /* POLL_MSG */ + POLLERR, /* POLL_ERR */ + POLLPRI | POLLRDBAND, /* POLL_PRI */ + POLLHUP | POLLERR /* POLL_HUP */ +}; + +#define list_first(head) (((head)->next != (head)) ? (head)->next: (struct list_head *) 0) + + +void file_notify_event(struct file *filep, long *event) +{ + unsigned long flags; + struct list_head *lnk, *lsthead; + + fcblist_read_lock(filep, flags); + + lsthead = &filep->f_cblist; + list_for_each(lnk, lsthead) { + struct fcb_struct *fcbp = list_entry(lnk, struct fcb_struct, llink); + + fcbp->cbproc(filep, fcbp->data, fcbp->local, event); + } + + fcblist_read_unlock(filep, flags); +} + +int file_notify_addcb(struct file *filep, + void (*cbproc)(struct file *, void *, unsigned long *, long *), void *data) +{ + unsigned long flags; + struct fcb_struct *fcbp; + + if (!(fcbp = (struct fcb_struct *) kmalloc(sizeof(struct fcb_struct), GFP_KERNEL))) + return -ENOMEM; + + memset(fcbp, 0, sizeof(struct fcb_struct)); + fcbp->cbproc = cbproc; + fcbp->data = data; + + fcblist_write_lock(filep, flags); + list_add_tail(&fcbp->llink, &filep->f_cblist); + fcblist_write_unlock(filep, flags); + + return 0; +} + +int file_notify_delcb(struct file *filep, + void (*cbproc)(struct file *, void *, unsigned long *, long *)) +{ + unsigned long flags; + struct list_head *lnk, *lsthead; + + fcblist_write_lock(filep, flags); + + lsthead = &filep->f_cblist; + list_for_each(lnk, lsthead) { + struct fcb_struct *fcbp = list_entry(lnk, struct fcb_struct, llink); + + if (fcbp->cbproc == cbproc) { + list_del(lnk); + fcblist_write_unlock(filep, flags); + kfree(fcbp); + return 0; + } + } + + fcblist_write_unlock(filep, flags); + + return -ENOENT; +} + +void file_notify_cleanup(struct file *filep) +{ + unsigned long flags; + struct list_head *lnk, *lsthead; + + file_send_notify(filep, 0, POLLREMOVE); + + fcblist_write_lock(filep, flags); + + lsthead = &filep->f_cblist; + while ((lnk = list_first(lsthead))) { + struct fcb_struct *fcbp = list_entry(lnk, struct fcb_struct, llink); + + list_del(lnk); + fcblist_write_unlock(filep, flags); + kfree(fcbp); + fcblist_write_lock(filep, flags); + } + + fcblist_write_unlock(filep, flags); +} + +EXPORT_SYMBOL(file_notify_addcb); +EXPORT_SYMBOL(file_notify_delcb); diff -aur --exclude=CVS linux/fs/file_table.c 2.4.18-kpoll/fs/file_table.c --- linux/fs/file_table.c Mon Sep 17 22:16:30 2001 +++ 2.4.18-kpoll/fs/file_table.c Tue Mar 26 17:07:26 2002 @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -47,6 +48,7 @@ f->f_uid = current->fsuid; f->f_gid = current->fsgid; list_add(&f->f_list, &anon_list); + file_notify_init(f); file_list_unlock(); return f; } @@ -91,6 +93,7 @@ filp->f_uid = current->fsuid; filp->f_gid = current->fsgid; filp->f_op = dentry->d_inode->i_fop; + file_notify_init(filp); if (filp->f_op->open) return filp->f_op->open(dentry->d_inode, filp); else @@ -104,6 +107,7 @@ struct inode * inode = dentry->d_inode; if (atomic_dec_and_test(&file->f_count)) { + file_notify_cleanup(file); locks_remove_flock(file); if (file->f_iobuf) diff -aur --exclude=CVS linux/fs/pipe.c 2.4.18-kpoll/fs/pipe.c --- linux/fs/pipe.c Sat Sep 29 03:03:48 2001 +++ 2.4.18-kpoll/fs/pipe.c Tue Mar 26 17:07:26 2002 @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -40,6 +41,7 @@ pipe_read(struct file *filp, char *buf, size_t count, loff_t *ppos) { struct inode *inode = filp->f_dentry->d_inode; + int pfull; ssize_t size, read, ret; /* Seeks are not allowed on pipes. */ @@ -72,6 +74,7 @@ PIPE_WAITING_READERS(*inode)++; pipe_wait(inode); PIPE_WAITING_READERS(*inode)--; + pfull = PIPE_FULL(*inode); ret = -ERESTARTSYS; if (signal_pending(current)) goto out; @@ -82,6 +85,8 @@ goto out; } } + else + pfull = PIPE_FULL(*inode); /* Read what data is available. */ ret = -EFAULT; @@ -104,6 +109,9 @@ count -= chars; buf += chars; } + /* Send notification message */ + if (pfull && !PIPE_FULL(*inode) && PIPE_WRITEFILE(*inode)) + file_send_notify(PIPE_WRITEFILE(*inode), ION_OUT, POLLOUT | POLLWRNORM | POLLWRBAND); /* Cache behaviour optimization */ if (!PIPE_LEN(*inode)) @@ -136,6 +144,7 @@ pipe_write(struct file *filp, const char *buf, size_t count, loff_t *ppos) { struct inode *inode = filp->f_dentry->d_inode; + int pempty; ssize_t free, written, ret; /* Seeks are not allowed on pipes. */ @@ -180,6 +189,7 @@ } /* Copy into available space. */ + pempty = PIPE_EMPTY(*inode); ret = -EFAULT; while (count > 0) { int space; @@ -208,6 +218,9 @@ break; do { + /* Send notification message */ + if (pempty && !PIPE_EMPTY(*inode) && PIPE_READFILE(*inode)) + file_send_notify(PIPE_READFILE(*inode), ION_IN, POLLIN | POLLRDNORM); /* * Synchronous wake-up: it knows that this process * is going to give up this CPU, so it doesnt have @@ -217,6 +230,7 @@ PIPE_WAITING_WRITERS(*inode)++; pipe_wait(inode); PIPE_WAITING_WRITERS(*inode)--; + pempty = PIPE_EMPTY(*inode); if (signal_pending(current)) goto out; if (!PIPE_READERS(*inode)) @@ -225,6 +239,9 @@ ret = -EFAULT; } + /* Send notification message */ + if (pempty && !PIPE_EMPTY(*inode) && PIPE_READFILE(*inode)) + file_send_notify(PIPE_READFILE(*inode), ION_IN, POLLIN | POLLRDNORM); /* Signal readers asynchronously that there is more data. */ wake_up_interruptible(PIPE_WAIT(*inode)); @@ -303,9 +320,22 @@ static int pipe_release(struct inode *inode, int decr, int decw) { + struct file *rdfile, *wrfile; down(PIPE_SEM(*inode)); PIPE_READERS(*inode) -= decr; PIPE_WRITERS(*inode) -= decw; + rdfile = PIPE_READFILE(*inode); + wrfile = PIPE_WRITEFILE(*inode); + if (decr && !PIPE_READERS(*inode)) { + PIPE_READFILE(*inode) = NULL; + if (wrfile) + file_send_notify(wrfile, ION_HUP, POLLHUP); + } + if (decw && !PIPE_WRITERS(*inode)) { + PIPE_WRITEFILE(*inode) = NULL; + if (rdfile) + file_send_notify(rdfile, ION_HUP, POLLHUP); + } if (!PIPE_READERS(*inode) && !PIPE_WRITERS(*inode)) { struct pipe_inode_info *info = inode->i_pipe; inode->i_pipe = NULL; @@ -458,6 +488,7 @@ PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 0; PIPE_WAITING_READERS(*inode) = PIPE_WAITING_WRITERS(*inode) = 0; PIPE_RCOUNTER(*inode) = PIPE_WCOUNTER(*inode) = 1; + PIPE_READFILE(*inode) = PIPE_WRITEFILE(*inode) = NULL; return inode; fail_page: @@ -564,6 +595,9 @@ f2->f_op = &write_pipe_fops; f2->f_mode = 2; f2->f_version = 0; + + PIPE_READFILE(*inode) = f1; + PIPE_WRITEFILE(*inode) = f2; fd_install(i, f1); fd_install(j, f2); diff -aur --exclude=CVS linux/include/asm-i386/poll.h 2.4.18-kpoll/include/asm-i386/poll.h --- linux/include/asm-i386/poll.h Thu Jan 23 20:01:28 1997 +++ 2.4.18-kpoll/include/asm-i386/poll.h Tue Mar 26 16:54:11 2002 @@ -15,6 +15,7 @@ #define POLLWRNORM 0x0100 #define POLLWRBAND 0x0200 #define POLLMSG 0x0400 +#define POLLREMOVE 0x1000 struct pollfd { int fd; diff -aur --exclude=CVS linux/include/linux/fcblist.h 2.4.18-kpoll/include/linux/fcblist.h --- linux/include/linux/fcblist.h Sat Jul 13 13:00:32 2002 +++ 2.4.18-kpoll/include/linux/fcblist.h Sat Jul 13 07:35:11 2002 @@ -0,0 +1,67 @@ +/* + * include/linux/fcblist.h + * + * Copyright (C) 2001, Davide Libenzi + * + * Handle file callbacks + */ + +#ifndef __LINUX_FCBLIST_H +#define __LINUX_FCBLIST_H + +#include +#include +#include +#include + + + +/* file callback notification events */ +#define ION_IN 1 +#define ION_OUT 2 +#define ION_HUP 3 +#define ION_ERR 4 + +#define FCB_LOCAL_SIZE 4 + +#define fcblist_read_lock(fp, fl) read_lock_irqsave(&(fp)->f_cblock, fl) +#define fcblist_read_unlock(fp, fl) read_unlock_irqrestore(&(fp)->f_cblock, fl) +#define fcblist_write_lock(fp, fl) write_lock_irqsave(&(fp)->f_cblock, fl) +#define fcblist_write_unlock(fp, fl) write_unlock_irqrestore(&(fp)->f_cblock, fl) + +struct fcb_struct { + struct list_head llink; + void (*cbproc)(struct file *, void *, unsigned long *, long *); + void *data; + unsigned long local[FCB_LOCAL_SIZE]; +}; + + +extern long ion_band_table[]; +extern long poll_band_table[]; + + +extern void file_notify_event(struct file *filep, long *event); + +extern int file_notify_addcb(struct file *filep, + void (*cbproc)(struct file *, void *, unsigned long *, long *), void *data); + +extern int file_notify_delcb(struct file *filep, + void (*cbproc)(struct file *, void *, unsigned long *, long *)); + +extern void file_notify_cleanup(struct file *filep); + + +static inline void file_notify_init(struct file *filep) +{ + rwlock_init(&filep->f_cblock); + INIT_LIST_HEAD(&filep->f_cblist); +} + +static inline void file_send_notify(struct file *filep, long ioevt, long plevt) { + long event[] = { ioevt, plevt, -1 }; + + file_notify_event(filep, event); +} + +#endif diff -aur --exclude=CVS linux/include/linux/fs.h 2.4.18-kpoll/include/linux/fs.h --- linux/include/linux/fs.h Mon Feb 25 20:38:13 2002 +++ 2.4.18-kpoll/include/linux/fs.h Sat Jul 13 07:36:26 2002 @@ -535,6 +535,10 @@ /* needed for tty driver, and maybe others */ void *private_data; + /* file callback list */ + rwlock_t f_cblock; + struct list_head f_cblist; + /* preallocated helper kiobuf to speedup O_DIRECT */ struct kiobuf *f_iobuf; long f_iobuf_lock; diff -aur --exclude=CVS linux/include/linux/kpoll.h 2.4.18-kpoll/include/linux/kpoll.h --- linux/include/linux/kpoll.h Sat Jul 13 13:00:40 2002 +++ 2.4.18-kpoll/include/linux/kpoll.h Tue Mar 26 16:54:11 2002 @@ -0,0 +1,40 @@ +/* + * --- Notices from eventpoll.h, upon which this driver is based --- + * + * Copyright (C) 2001, Davide Libenzi + * + * Efficent event polling implementation + * + * --- End of notice from eventpoll.h --- + * + * + */ + +#ifndef _LINUX_KPOLL_H +#define _LINUX_KPOLL_H + + +#define KPOLL_MINOR 152 +#define KPOLLFD_X_PAGE (PAGE_SIZE / sizeof(struct pollfd)) +#define MAX_FDS_IN_KPOLL (1024 * 128) +#define MAX_KPOLL_PAGES (MAX_FDS_IN_KPOLL / KPOLLFD_X_PAGE) + + +#define KP_FDS_PAGES(n) (((n) + KPOLLFD_X_PAGE - 1) / KPOLLFD_X_PAGE) +#define KP_MAP_SIZE(n) (KP_FDS_PAGES(n) * PAGE_SIZE * 2) + + +struct k_poll { + int kp_timeout; + unsigned long kp_resoff; +}; + +#define KP_ALLOC _IOR('P', 1, int) +#define KP_POLL _IOWR('P', 2, struct k_poll) +#define KP_FREE _IO('P', 3) +#define KP_ISPOLLED _IOWR('P', 4, struct pollfd) +#define KP_EVENTPOLL _IOWR('P', 5, int) + + +#endif + diff -aur --exclude=CVS linux/include/linux/list.h 2.4.18-kpoll/include/linux/list.h --- linux/include/linux/list.h Fri Dec 21 18:42:03 2001 +++ 2.4.18-kpoll/include/linux/list.h Sat Jul 13 07:36:30 2002 @@ -172,6 +172,11 @@ pos = pos->prev, prefetch(pos->prev)) +#define list_first(head) (((head)->next != (head)) ? (head)->next: (struct list_head *) 0) +#define list_last(head) (((head)->prev != (head)) ? (head)->prev: (struct list_head *) 0) +#define list_next(pos, head) (((pos)->next != (head)) ? (pos)->next: (struct list_head *) 0) +#define list_prev(pos, head) (((pos)->prev != (head)) ? (pos)->prev: (struct list_head *) 0) + #endif /* __KERNEL__ || _LVM_H_INCLUDE */ #endif diff -aur --exclude=CVS linux/include/linux/pipe_fs_i.h 2.4.18-kpoll/include/linux/pipe_fs_i.h --- linux/include/linux/pipe_fs_i.h Wed Apr 25 23:18:23 2001 +++ 2.4.18-kpoll/include/linux/pipe_fs_i.h Tue Mar 26 16:54:11 2002 @@ -13,6 +13,8 @@ unsigned int waiting_writers; unsigned int r_counter; unsigned int w_counter; + struct file *rdfile; + struct file *wrfile; }; /* Differs from PIPE_BUF in that PIPE_SIZE is the length of the actual @@ -30,6 +32,8 @@ #define PIPE_WAITING_WRITERS(inode) ((inode).i_pipe->waiting_writers) #define PIPE_RCOUNTER(inode) ((inode).i_pipe->r_counter) #define PIPE_WCOUNTER(inode) ((inode).i_pipe->w_counter) +#define PIPE_READFILE(inode) ((inode).i_pipe->rdfile) +#define PIPE_WRITEFILE(inode) ((inode).i_pipe->wrfile) #define PIPE_EMPTY(inode) (PIPE_LEN(inode) == 0) #define PIPE_FULL(inode) (PIPE_LEN(inode) == PIPE_SIZE) diff -aur --exclude=CVS linux/include/net/sock.h 2.4.18-kpoll/include/net/sock.h --- linux/include/net/sock.h Fri Dec 21 18:42:04 2001 +++ 2.4.18-kpoll/include/net/sock.h Tue Mar 26 16:54:11 2002 @@ -105,7 +105,9 @@ #include #include - +#include +#include +#include /* The AF_UNIX specific socket options */ struct unix_opt { @@ -1215,8 +1217,13 @@ static inline void sk_wake_async(struct sock *sk, int how, int band) { - if (sk->socket && sk->socket->fasync_list) + if (sk->socket) { + if (sk->socket->file) + file_send_notify(sk->socket->file, ion_band_table[band - POLL_IN], + poll_band_table[band - POLL_IN]); + if (sk->socket->fasync_list) sock_wake_async(sk->socket, how, band); + } } #define SOCK_MIN_SNDBUF 2048 diff -aur --exclude=CVS linux/net/ipv4/tcp.c 2.4.18-kpoll/net/ipv4/tcp.c --- linux/net/ipv4/tcp.c Fri Dec 21 18:42:05 2001 +++ 2.4.18-kpoll/net/ipv4/tcp.c Fri Jul 12 14:02:49 2002 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp.c,v 1.215 2001/10/31 08:17:58 davem Exp $ + * Version: $Id: tcp.c,v 1.3 2002/04/24 09:22:17 tonyrog Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -470,8 +470,8 @@ if (sk->sleep && waitqueue_active(sk->sleep)) wake_up_interruptible(sk->sleep); - if (sock->fasync_list && !(sk->shutdown&SEND_SHUTDOWN)) - sock_wake_async(sock, 2, POLL_OUT); + if (!(sk->shutdown&SEND_SHUTDOWN)) + sk_wake_async(sk, 2, POLL_OUT); } }