Commit f751cfc0 authored by Davide Libenzi's avatar Davide Libenzi Committed by Linus Torvalds

[PATCH] sys_epoll 0.15

Latest version of the epoll interfaces.
parent ecf2c214
......@@ -737,6 +737,10 @@ ENTRY(sys_call_table)
.long sys_free_hugepages
.long sys_exit_group
.long sys_lookup_dcookie
.long sys_epoll_create
.long sys_epoll_ctl /* 255 */
.long sys_epoll_wait
.rept NR_syscalls-(.-sys_call_table)/4
.long sys_ni_syscall
......
......@@ -7,14 +7,14 @@
#
FONTMAPFILE = cp437.uni
obj-y += mem.o tty_io.o n_tty.o tty_ioctl.o pty.o misc.o random.o
obj-y += mem.o tty_io.o n_tty.o tty_ioctl.o pty.o misc.o random.o eventpoll.o
# All of the (potential) objects that export symbols.
# This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.
export-objs := busmouse.o vt.o generic_serial.o ip2main.o \
ite_gpio.o keyboard.o misc.o nvram.o random.o rtc.o \
selection.o sonypi.o sysrq.o tty_io.o tty_ioctl.o
selection.o sonypi.o sysrq.o tty_io.o tty_ioctl.o eventpoll.o
obj-$(CONFIG_VT) += vt_ioctl.o vc_screen.o consolemap.o consolemap_deftbl.o selection.o keyboard.o
obj-$(CONFIG_HW_CONSOLE) += vt.o defkeymap.o
......
This diff is collapsed.
......@@ -6,14 +6,14 @@
#
export-objs := open.o dcache.o buffer.o bio.o inode.o dquot.o mpage.o aio.o \
fcntl.o read_write.o dcookies.o
fcntl.o read_write.o dcookies.o fcblist.o
obj-y := open.o read_write.o devices.o file_table.o buffer.o \
bio.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 \
dcache.o inode.o attr.o bad_inode.o file.o dnotify.o \
filesystems.o namespace.o seq_file.o xattr.o libfs.o \
fs-writeback.o mpage.o direct-io.o aio.o
fs-writeback.o mpage.o direct-io.o aio.o fcblist.o
ifneq ($(CONFIG_NFSD),n)
ifneq ($(CONFIG_NFSD),)
......
/*
* linux/fs/fcblist.c ( File event callbacks handling )
* Copyright (C) 2001,...,2002 Davide Libenzi
*
* 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.
*
* Davide Libenzi <davidel@xmailserver.org>
*
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/poll.h>
#include <asm/bitops.h>
#include <linux/fcblist.h>
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 */
};
/*
* Walk through the file callback list by calling each registered callback
* with the event that happened on the "filep" file. Callbacks are called
* by holding a read lock on the callback list lock, and also by keeping
* local IRQs disabled.
*/
void file_notify_event(struct file *filep, long *event)
{
unsigned long flags;
struct list_head *lnk, *lsthead;
read_lock_irqsave(&filep->f_cblock, 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);
}
read_unlock_irqrestore(&filep->f_cblock, flags);
}
/*
* Add a new callback to the list of file callbacks.
*/
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;
write_lock_irqsave(&filep->f_cblock, flags);
list_add_tail(&fcbp->llink, &filep->f_cblist);
write_unlock_irqrestore(&filep->f_cblock, flags);
return 0;
}
/*
* Removes the callback "cbproc" from the file callback list.
*/
int file_notify_delcb(struct file *filep,
void (*cbproc)(struct file *, void *, unsigned long *, long *))
{
unsigned long flags;
struct list_head *lnk, *lsthead;
write_lock_irqsave(&filep->f_cblock, 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);
write_unlock_irqrestore(&filep->f_cblock, flags);
kfree(fcbp);
return 0;
}
}
write_unlock_irqrestore(&filep->f_cblock, flags);
return -ENOENT;
}
/*
* It is called at file cleanup time and removes all the registered callbacks.
*/
void file_notify_cleanup(struct file *filep)
{
unsigned long flags;
struct list_head *lsthead;
write_lock_irqsave(&filep->f_cblock, flags);
lsthead = &filep->f_cblist;
while (!list_empty(lsthead)) {
struct fcb_struct *fcbp = list_entry(lsthead->next, struct fcb_struct, llink);
list_del(lsthead->next);
write_unlock_irqrestore(&filep->f_cblock, flags);
kfree(fcbp);
write_lock_irqsave(&filep->f_cblock, flags);
}
write_unlock_irqrestore(&filep->f_cblock, flags);
}
......@@ -8,6 +8,7 @@
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/file.h>
#include <linux/fcblist.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/smp_lock.h>
......@@ -58,6 +59,7 @@ struct file * get_empty_filp(void)
f->f_gid = current->fsgid;
f->f_owner.lock = RW_LOCK_UNLOCKED;
list_add(&f->f_list, &anon_list);
file_notify_init(f);
file_list_unlock();
return f;
}
......@@ -102,6 +104,7 @@ int init_private_file(struct file *filp, struct dentry *dentry, int mode)
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
......@@ -123,6 +126,7 @@ void __fput(struct file * file)
struct vfsmount * mnt = file->f_vfsmnt;
struct inode * inode = dentry->d_inode;
file_notify_cleanup(file);
locks_remove_flock(file);
if (file->f_op && file->f_op->release)
......
......@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/fcblist.h>
#include <asm/uaccess.h>
#include <asm/ioctls.h>
......@@ -47,7 +48,7 @@ static ssize_t
pipe_read(struct file *filp, char *buf, size_t count, loff_t *ppos)
{
struct inode *inode = filp->f_dentry->d_inode;
int do_wakeup;
int do_wakeup, pfull;
ssize_t ret;
/* pread is not allowed on pipes. */
......@@ -63,6 +64,7 @@ pipe_read(struct file *filp, char *buf, size_t count, loff_t *ppos)
down(PIPE_SEM(*inode));
for (;;) {
int size = PIPE_LEN(*inode);
pfull = PIPE_FULL(*inode);
if (size) {
char *pipebuf = PIPE_BASE(*inode) + PIPE_START(*inode);
ssize_t chars = PIPE_MAX_RCHUNK(*inode);
......@@ -108,12 +110,18 @@ pipe_read(struct file *filp, char *buf, size_t count, loff_t *ppos)
if (!ret) ret = -ERESTARTSYS;
break;
}
/* Send notification message */
if (pfull && !PIPE_FULL(*inode) && PIPE_WRITEFILE(*inode))
file_send_notify(PIPE_WRITEFILE(*inode), ION_OUT, POLLOUT | POLLWRNORM | POLLWRBAND);
if (do_wakeup) {
wake_up_interruptible(PIPE_WAIT(*inode));
kill_fasync(PIPE_FASYNC_WRITERS(*inode), SIGIO, POLL_OUT);
}
pipe_wait(inode);
}
/* Send notification message */
if (pfull && !PIPE_FULL(*inode) && PIPE_WRITEFILE(*inode))
file_send_notify(PIPE_WRITEFILE(*inode), ION_OUT, POLLOUT | POLLWRNORM | POLLWRBAND);
up(PIPE_SEM(*inode));
/* Signal writers asynchronously that there is more room. */
if (do_wakeup) {
......@@ -131,7 +139,7 @@ pipe_write(struct file *filp, const char *buf, size_t count, loff_t *ppos)
struct inode *inode = filp->f_dentry->d_inode;
ssize_t ret;
size_t min;
int do_wakeup;
int do_wakeup, pempty;
/* pwrite is not allowed on pipes. */
if (unlikely(ppos != &filp->f_pos))
......@@ -149,6 +157,7 @@ pipe_write(struct file *filp, const char *buf, size_t count, loff_t *ppos)
down(PIPE_SEM(*inode));
for (;;) {
int free;
pempty = PIPE_EMPTY(*inode);
if (!PIPE_READERS(*inode)) {
send_sig(SIGPIPE, current, 0);
if (!ret) ret = -EPIPE;
......@@ -194,6 +203,9 @@ pipe_write(struct file *filp, const char *buf, size_t count, loff_t *ppos)
if (!ret) ret = -ERESTARTSYS;
break;
}
/* Send notification message */
if (pempty && !PIPE_EMPTY(*inode) && PIPE_READFILE(*inode))
file_send_notify(PIPE_READFILE(*inode), ION_IN, POLLIN | POLLRDNORM);
if (do_wakeup) {
wake_up_interruptible_sync(PIPE_WAIT(*inode));
kill_fasync(PIPE_FASYNC_READERS(*inode), SIGIO, POLL_IN);
......@@ -203,6 +215,9 @@ pipe_write(struct file *filp, const char *buf, size_t count, loff_t *ppos)
pipe_wait(inode);
PIPE_WAITING_WRITERS(*inode)--;
}
/* Send notification message */
if (pempty && !PIPE_EMPTY(*inode) && PIPE_READFILE(*inode))
file_send_notify(PIPE_READFILE(*inode), ION_IN, POLLIN | POLLRDNORM);
up(PIPE_SEM(*inode));
if (do_wakeup) {
wake_up_interruptible(PIPE_WAIT(*inode));
......@@ -266,9 +281,22 @@ pipe_poll(struct file *filp, poll_table *wait)
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;
......@@ -488,6 +516,7 @@ struct inode* pipe_new(struct inode* inode)
PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 0;
PIPE_WAITING_WRITERS(*inode) = 0;
PIPE_RCOUNTER(*inode) = PIPE_WCOUNTER(*inode) = 1;
PIPE_READFILE(*inode) = PIPE_WRITEFILE(*inode) = NULL;
*PIPE_FASYNC_READERS(*inode) = *PIPE_FASYNC_WRITERS(*inode) = NULL;
return inode;
......@@ -596,6 +625,9 @@ int do_pipe(int *fd)
f2->f_mode = 2;
f2->f_version = 0;
PIPE_READFILE(*inode) = f1;
PIPE_WRITEFILE(*inode) = f2;
fd_install(i, f1);
fd_install(j, f2);
fd[0] = i;
......
......@@ -15,6 +15,7 @@
#define POLLWRNORM 0x0100
#define POLLWRBAND 0x0200
#define POLLMSG 0x0400
#define POLLREMOVE 0x1000
struct pollfd {
int fd;
......
......@@ -258,6 +258,9 @@
#define __NR_free_hugepages 251
#define __NR_exit_group 252
#define __NR_lookup_dcookie 253
#define __NR_sys_epoll_create 254
#define __NR_sys_epoll_ctl 255
#define __NR_sys_epoll_wait 256
/* user-visible error numbers are in the range -1 - -124: see <asm-i386/errno.h> */
......
/*
* include/linux/eventpoll.h ( Efficent event polling implementation )
* Copyright (C) 2001,...,2002 Davide Libenzi
*
* 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.
*
* Davide Libenzi <davidel@xmailserver.org>
*
*/
#ifndef _LINUX_EVENTPOLL_H
#define _LINUX_EVENTPOLL_H
#define EVENTPOLL_MINOR 124
#define POLLFD_X_PAGE (PAGE_SIZE / sizeof(struct pollfd))
#define MAX_FDS_IN_EVENTPOLL (1024 * 128)
#define MAX_EVENTPOLL_PAGES (MAX_FDS_IN_EVENTPOLL / POLLFD_X_PAGE)
#define EVENT_PAGE_INDEX(n) ((n) / POLLFD_X_PAGE)
#define EVENT_PAGE_REM(n) ((n) % POLLFD_X_PAGE)
#define EVENT_PAGE_OFFSET(n) (((n) % POLLFD_X_PAGE) * sizeof(struct pollfd))
#define EP_FDS_PAGES(n) (((n) + POLLFD_X_PAGE - 1) / POLLFD_X_PAGE)
#define EP_MAP_SIZE(n) (EP_FDS_PAGES(n) * PAGE_SIZE * 2)
struct evpoll {
int ep_timeout;
unsigned long ep_resoff;
};
#define EP_ALLOC _IOR('P', 1, int)
#define EP_POLL _IOWR('P', 2, struct evpoll)
#define EP_FREE _IO('P', 3)
#define EP_ISPOLLED _IOWR('P', 4, struct pollfd)
#define EP_CTL_ADD 1
#define EP_CTL_DEL 2
#define EP_CTL_MOD 3
asmlinkage int sys_epoll_create(int maxfds);
asmlinkage int sys_epoll_ctl(int epfd, int op, int fd, unsigned int events);
asmlinkage int sys_epoll_wait(int epfd, struct pollfd const **events, int timeout);
#endif
/*
* include/linux/fcblist.h ( File event callbacks handling )
* Copyright (C) 2001,...,2002 Davide Libenzi
*
* 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.
*
* Davide Libenzi <davidel@xmailserver.org>
*
*/
#ifndef __LINUX_FCBLIST_H
#define __LINUX_FCBLIST_H
#include <linux/config.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/fs.h>
#include <linux/file.h>
/* 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
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[];
void file_notify_event(struct file *filep, long *event);
int file_notify_addcb(struct file *filep,
void (*cbproc)(struct file *, void *, unsigned long *, long *),
void *data);
int file_notify_delcb(struct file *filep,
void (*cbproc)(struct file *, void *, unsigned long *, long *));
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
......@@ -506,6 +506,10 @@ struct file {
/* needed for tty driver, and maybe others */
void *private_data;
/* file callback list */
rwlock_t f_cblock;
struct list_head f_cblist;
};
extern spinlock_t files_lock;
#define file_list_lock() spin_lock(&files_lock);
......
......@@ -12,6 +12,8 @@ struct pipe_inode_info {
unsigned int waiting_writers;
unsigned int r_counter;
unsigned int w_counter;
struct file *rdfile;
struct file *wrfile;
struct fasync_struct *fasync_readers;
struct fasync_struct *fasync_writers;
};
......@@ -30,6 +32,8 @@ struct pipe_inode_info {
#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_FASYNC_READERS(inode) (&((inode).i_pipe->fasync_readers))
#define PIPE_FASYNC_WRITERS(inode) (&((inode).i_pipe->fasync_writers))
......
......@@ -4,7 +4,7 @@
/*
* system call entry points ... but not all are defined
*/
#define NR_syscalls 256
#define NR_syscalls 260
/*
* These are system calls that will be removed at some time
......
......@@ -52,6 +52,9 @@
#include <asm/atomic.h>
#include <net/dst.h>
#include <net/scm.h>
#include <linux/fs.h>
#include <linux/file.h>
#include <linux/fcblist.h>
/*
* This structure really needs to be cleaned up.
......@@ -766,8 +769,13 @@ static inline unsigned long sock_wspace(struct sock *sk)
static inline void sk_wake_async(struct sock *sk, int how, int band)
{
if (sk->socket && sk->socket->fasync_list)
sock_wake_async(sk->socket, how, band);
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
......
......@@ -476,8 +476,8 @@ void tcp_write_space(struct sock *sk)
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);
}
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment