diff -ruN --exclude-from=_diff_exclude_file linux-2.4.3/arch/i386/config.in linux-2.4.3+fd_events/arch/i386/config.in
--- linux-2.4.3/arch/i386/config.in	Mon Jan  8 16:27:56 2001
+++ linux-2.4.3+fd_events/arch/i386/config.in	Fri Apr  6 15:58:28 2001
@@ -227,6 +227,13 @@
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
 tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
 
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+  bool 'File Events Interface (EXPERIMENTAL)' CONFIG_FILE_EVENTS
+
+  dep_mbool '  File Events Debugging' CONFIG_DEBUG_FILE_EVENTS $CONFIG_FILE_EVENTS
+
+fi
+
 bool 'Power Management support' CONFIG_PM
 
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
diff -ruN --exclude-from=_diff_exclude_file linux-2.4.3/arch/i386/kernel/entry.S linux-2.4.3+fd_events/arch/i386/kernel/entry.S
--- linux-2.4.3/arch/i386/kernel/entry.S	Wed Nov  8 20:09:50 2000
+++ linux-2.4.3+fd_events/arch/i386/kernel/entry.S	Fri Apr  6 15:58:28 2001
@@ -645,6 +645,8 @@
 	.long SYMBOL_NAME(sys_madvise)
 	.long SYMBOL_NAME(sys_getdents64)	/* 220 */
 	.long SYMBOL_NAME(sys_fcntl64)
+	.long SYMBOL_NAME(sys_bind_event)
+	.long SYMBOL_NAME(sys_get_events)
 	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for TUX */
 
 	/*
@@ -653,6 +655,6 @@
 	 * entries. Don't panic if you notice that this hasn't
 	 * been shrunk every time we add a new system call.
 	 */
-	.rept NR_syscalls-221
+	.rept NR_syscalls-223
 		.long SYMBOL_NAME(sys_ni_syscall)
 	.endr
diff -ruN --exclude-from=_diff_exclude_file linux-2.4.3/fs/select.c linux-2.4.3+fd_events/fs/select.c
--- linux-2.4.3/fs/select.c	Fri Feb  9 14:29:44 2001
+++ linux-2.4.3+fd_events/fs/select.c	Sun Apr 15 00:46:37 2001
@@ -12,13 +12,19 @@
  *  24 January 2000
  *     Changed sys_poll()/do_poll() to use PAGE_SIZE chunk-based allocation 
  *     of fds to overcome nfds < 16390 descriptors limit (Tigran Aivazian).
+ *
+ *  6 April 2001
+ *     Addition of sys_bind_event()/sys_get_events() to speed up event processing
+ *     for a large number of file descriptors. (Bart Trojanowski <bart@jukie.net>)
  */
 
 #include <linux/slab.h>
 #include <linux/smp_lock.h>
 #include <linux/poll.h>
 #include <linux/file.h>
+#include <linux/fdevent.h>
 
+#include <asm/softirq.h>	/* for spinlocks to work */
 #include <asm/uaccess.h>
 
 #define ROUND_UP(x,y) (((x)+(y)-1)/(y))
@@ -491,3 +497,346 @@
 	poll_freewait(&table);
 	return err;
 }
+
+#ifdef CONFIG_FILE_EVENTS
+
+/* sets the file to default state by using the op->poll fn*/
+static inline unsigned long
+current_file_events(struct file *file)
+{
+	unsigned long mask = 0;
+	if ( !file->f_op) goto out;
+	if ( !file->f_op->poll) goto out;
+	mask = file->f_op->poll(file, NULL);
+ out:
+	return mask;
+}
+
+/* Marks a file for current task with the given criteria
+ * returns 1 on success, 0 on failure */
+static inline int
+do_bind_event(struct file *file, struct fdevent *ev)
+{
+	register int ret=1;/* assume success */
+
+	/* set the static fields */
+	file->f_event.event = *ev;
+	file->f_event_mask = ev->mask;
+	file->f_event.event.mask = 0;
+	
+	/* check for current events - but don't wait for them */
+	deliver_file_event(file, current_file_events(file));
+	
+	return ret;
+}
+
+/* Takes an event and registers current->files->fd[fd] to watch for 
+ *   ev->mask on ev->fd; when something happens the event structure gets
+ *   queued on current->files->file_event_head; this queue is returned
+ *   to the user when sys_get_events is called
+ * sys_bind_event returns # of files bound to, or negative on error
+ */
+asmlinkage long sys_bind_event(struct fdevent *uev)
+{
+	struct fdevent *ev;
+	long ret;
+	
+	FEDBG("sys_bind_event( %p )",uev);
+	
+	ret = -ENOMEM;
+	if( !(ev = kmalloc(sizeof(struct fdevent), GFP_KERNEL)) ) {
+		FEDBG("  kmalloc( %d, GFP_KERNEL ) failed", sizeof(struct fdevent));
+		goto out;
+	}
+	
+	ret = -EFAULT;
+	if( copy_from_user(ev, uev, sizeof(struct fdevent)) ) {
+		FEDBG("  copy_from_user( %p, %p, %d ) failed", 
+		      ev, uev, sizeof(struct fdevent));
+		goto out_ev;
+	}
+
+	FEDBG("  ev->mask = %lx", ev->mask );
+	
+	/* before we start we have to make sure that the queue list for this 
+	 * task is properly initialized; considre this a delayed initialization
+	 * as we know that not all tasks will want to use this interface */
+	spin_lock(&current->files->file_event_list.lock);
+	if( ! current->files->file_event_list.head ) {
+		/* this is a hack to catch any tasks we have not yet inited */
+		/* TODO: this should go away, just init it when the task is created */
+		FEDBG("  doing delayed initialization of files_struct!!!");
+		INIT_FILE_EVENT_LIST(&(current->files->file_event_list));
+		init_waitqueue_head(&(current->files->file_event_wait));
+	}
+	spin_unlock(&current->files->file_event_list.lock);
+	
+	/* now execute the desired command */
+	switch( ev->fd ) {
+		int i, tot;
+		struct file *file;
+		
+	case FDEVENT_FD_EXISTING:
+		FEDBG("  ev->fd = FDEVENT_FD_EXISTING" );
+		
+		/* set the ev->mask on each existing current->files->fd[*] */
+		tot = ret = 0;
+		for(i=0;i<current->files->max_fds;i++) {
+			file = fget(i);
+			if( file ) {
+				tot ++;
+				ret += do_bind_event(file,ev);
+				fput(file);
+			}
+		}
+		/* if there are no files then just return a ZERO */
+		if( !tot ) break;
+		/* if we have counted a bind in any fd's above then 
+		 * return that number */
+		if( ret ) break;
+		/* this means that there were files but they were
+		 * already bound by some other task (parent/sibling) */
+	        ret=-EBUSY;
+		break;
+		
+	case FDEVENT_FD_DEFAULT:
+		FEDBG("  ev->fd = FDEVENT_FD_DEFAULT" );
+		
+		/* set the default mask for new fd to ev->mask */
+		current->files->default_file_event = *ev;
+		ret = 0;
+		break;
+		
+	default:
+		FEDBG("  ev->fd = %d", ev->fd );
+		
+		/* set the ev->mask on the specified ev->fd */
+		file = fget(ev->fd);
+		if (!file) {
+			ret = -EBADF;
+			goto out_ev;
+		}
+		ret = do_bind_event(file,ev);
+		fput(file);
+		if( ret ) break;
+		ret = -EBUSY;
+		break;
+	}
+
+out_ev:
+	kfree(ev);
+out:
+	FEDBG("  <sys_bind_event [%ld]", ret);
+	return ret;
+}
+
+/* see sys_bind_event for specifics; in general this is just like a sys_poll call
+ * but an array of files does not have to be traversed as the files_struct
+ * of the current process already knows what events have fired */
+asmlinkage long sys_get_events(struct fdevent *uevs, unsigned int nevs, long timeout)
+{
+	int ret=0;
+	register file_event_t *ev, *nev;
+	register struct fdevent *uev = uevs;
+	file_event_list_t *list = &current->files->file_event_list;
+	unsigned long timeout_jiffies = jiffies;
+	DECLARE_WAITQUEUE(wait, current);
+
+	FEDBG("sys_get_events( %p, %u, %lu )", uevs, nevs, timeout);
+	
+	/* calculate number of jiffies needed to wait; this here part is stolen from 
+	 * sys_poll above */
+	if (timeout) {
+		/* Careful about overflow in the intermediate values */
+		if ((unsigned long) timeout < MAX_SCHEDULE_TIMEOUT / HZ) {
+			timeout = (unsigned long)(timeout*HZ+999)/1000+1;
+			timeout_jiffies += timeout;
+		} else /* Negative or overflow */
+			timeout_jiffies = 0; /* MAX_SCHEDULE_TIMEOUT; */
+	}
+	
+	
+	current->state = TASK_INTERRUPTIBLE;
+	add_wait_queue(&(current->files->file_event_wait), &wait);
+	{
+		wait_queue_head_t *queue =
+			&(current->files->file_event_wait);
+		FEDBG("  sleeping on wait queue, element %p", &wait);
+		FEDBG("    wqh       = %p", queue);
+		FEDBG("    wqh->prev = %p", queue->task_list.prev);
+		FEDBG("    wqh->next = %p", queue->task_list.next);
+	}
+	for(;;) {
+		
+		spin_lock_bh(&list->lock);
+	
+		ev = list->head;
+		while( ev != (file_event_t*)list ) {
+			int err = copy_to_user( uev, &ev->event, sizeof(*uev) );
+			struct file *file;
+			unsigned long nmask;
+			
+			if( signal_pending(current) ) {
+				if ( !ret )
+					ret = -EINTR;
+				goto out;
+			}
+			if( err ) {
+				if( !ret ) 
+					ret = -EFAULT;
+				goto out;
+			}
+		
+			FEDBG("  copied ev (fd=%d,mk=%lx,cb=%p,dt=%p) to user space",
+			      ev->event.fd, ev->event.mask,
+			      ev->event.fn, ev->event.data);
+			
+			nev = ev->next;
+			nmask = 0;
+			file = fget(ev->event.fd);
+			if( file ) {
+				nmask = current_file_events(file); 
+				fput(file);
+			}
+			if( !nmask || nmask == ev->event.mask ) {
+				nmask = 0;
+				file_event_list_del(ev);
+			} 
+			ev->event.mask = nmask;
+			ev = nev;
+		
+			uev++;
+			ret++;
+			if( ret==nevs ) 
+				goto out;
+		}
+		
+		spin_unlock_bh(&list->lock);
+		
+		/* if we got something or there was no timeout specified then bail */
+		if ( ret || !timeout ) 
+			break;
+
+		if( signal_pending(current) ) {
+			ret = -EINTR;
+			goto out;
+		}
+		
+		/* if we were unable to fill the request then wait */
+		set_current_state(TASK_INTERRUPTIBLE);
+		if ( timeout_jiffies ) {
+			long delta = timeout_jiffies - jiffies;
+			if( delta < 0 ) goto out;
+			if( delta > HZ ) delta = HZ;
+			schedule_timeout( delta );
+		} else {
+			schedule(); /* no timeout */
+			/* schedule_timeout( HZ ); */
+		}
+	}
+ out:
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&(current->files->file_event_wait), &wait);
+	current->state = TASK_RUNNING;
+	
+	FEDBG("  <sys_get_events [%d]", ret);
+	return ret;
+}
+
+/* initialize a file based on file_struct of a task 
+ *  file  - a newly created file
+ *  files - a files_struct of the task called from
+ */
+int file_event_init( struct file *file, struct files_struct *files )
+{
+	if( file ) {
+		/* init some pointers */
+		INIT_FILE_EVENT( &file->f_event );
+		
+		/* bind according to default policy */
+		do_bind_event( file, &files->default_file_event );
+		
+		/* attach list and wait to the owning task */
+		file->f_event_list = &files->file_event_list;
+		file->f_event_wait = &files->file_event_wait;
+	}
+	return 0;
+}
+
+/* releases any bindings the file has with the event list for it's task */
+int file_event_release( struct file *file )
+{
+	if( file && file->f_event_list ) {
+		int flags;
+		file_event_list_t *list = file->f_event_list;
+		
+		spin_lock_irqsave(&list->lock,flags);
+		if( file->f_event.event.mask ) {
+			FEDBG("file_event_release( %p ): removing from list", file);
+			file_event_list_del( &file->f_event );
+		}
+		file->f_event_mask = 0;
+		spin_unlock_irqrestore(&list->lock,flags);
+	}
+	return 0;
+}
+
+/* deliver an event
+ *  file - file pointer, properly locked a la get_file 
+ *  mask - what event fired (see fdevent.h)
+ */
+int deliver_file_event(struct file *file, unsigned long mask)
+{
+	if( file && (file->f_event_mask & mask) ) {
+		file_event_list_t *list = file->f_event_list;
+		file_event_t *ev = &file->f_event;
+		
+		int pr = net_ratelimit();
+		
+		if( pr )
+			FEDBG("deliver_file_event( %p, %lx ) "
+			      "passes mask (%lx) checks", 
+			      file, mask, file->f_event_mask);
+		
+		if( list ) {
+		
+			spin_lock_bh(&list->lock);
+		
+			if( ! ev->event.mask ) {
+				if( pr )
+					FEDBG("  appending event (%p) to list (%p)",
+					      ev, list );
+				file_event_list_add_tail( ev, list );
+			}
+
+			if( pr ) 
+				FEDBG("  event state moved from %lx to %lx", 
+				      ev->event.mask, ev->event.mask|mask);
+			ev->event.mask |= mask;
+
+			spin_unlock_bh(&list->lock);
+			
+			wake_up_interruptible( file->f_event_wait );
+			
+		}
+		
+		if( pr )
+			FEDBG("  <deliver_file_event [0]");
+	}
+
+	return 0;
+}
+
+#else /* CONFIG_FILE_EVENTS */
+
+asmlinkage long sys_bind_event(struct fdevent *uev)
+{
+	return sys_ni_syscall();
+}
+
+asmlinkage long sys_get_events(struct fdevent *uevs, unsigned int nevs, long timeout)
+{
+	return sys_ni_syscall();
+}
+
+#endif /* CONFIG_FILE_EVENTS */
diff -ruN --exclude-from=_diff_exclude_file linux-2.4.3/include/asm-i386/fdevent.h linux-2.4.3+fd_events/include/asm-i386/fdevent.h
--- linux-2.4.3/include/asm-i386/fdevent.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.3+fd_events/include/asm-i386/fdevent.h	Sat Apr 14 22:13:18 2001
@@ -0,0 +1,59 @@
+/* fdevent.h - user space definitions of file events interface */
+ 
+/* Written 2001 by Bart Trojanowski <bart@jukie.net>, Chrysalis-ITS */
+
+/* This interface is exported by using the bind_event()/get_events()
+ * systemcall pair; docs are on the web (jukie.net/~bart/kernel/fdevent)
+ */ 
+#ifndef __i386_FDEVENT_H
+#define __i386_FDEVENT_H
+
+#include <asm/poll.h>
+
+/* Event types are borowed from poll.h;
+ * NOTE that while the current implementation shares the flags of poll()
+ *     this cannot be taken as a rule
+ */
+#define FDEVENT_IN	POLLIN     /* 0x0001 */
+#define FDEVENT_PRI	POLLPRI    /* 0x0002 */
+#define FDEVENT_OUT	POLLOUT    /* 0x0004 */
+#define FDEVENT_ERR	POLLERR    /* 0x0008 */
+#define FDEVENT_HUP	POLLHUP    /* 0x0010 */
+#define FDEVENT_NVAL	POLLNVLA   /* 0x0020 */
+
+/* non standard, sais poll.h */
+#define FDEVENT_RDNORM	POLLRDNORM /* 0x0040 */
+#define FDEVENT_RDBAND	POLLRDBAND /* 0x0080 */
+#define FDEVENT_WRNORM	POLLWRNORM /* 0x0100 */
+#define FDEVENT_WRBAND	POLLWRBAND /* 0x0200 */
+#define FDEVENT_MSG	POLLMSG    /* 0x0400 */
+
+struct fdevent;
+
+typedef void (fdevent_fn)(struct fdevent*);
+
+struct fdevent {
+	int fd;
+	unsigned long mask;
+	void *data;
+	fdevent_fn *fn;
+};
+
+#define FDEVENT_INIT { 0, 0, NULL, NULL }
+#define INIT_FDEVENT(ptr) do { \
+	(ptr)->fd = 0; (ptr)->mask = 0; \
+	(ptr)->data = 0; (ptr)->fn = 0; \
+} while (0)
+
+
+/* wildcards for fdevent.fd */
+#define FDEVENT_FD_EXISTING -1
+#define FDEVENT_FD_DEFAULT  -2
+
+#ifndef __KERNEL__
+_syscall1( long, bind_event, struct fdevent*, uev );
+_syscall3( long, get_events, struct fdevent*, uevs, 
+	   unsigned int, nevs, long, timeout );
+#endif /* __KERNEL__ */
+
+#endif
diff -ruN --exclude-from=_diff_exclude_file linux-2.4.3/include/asm-i386/unistd.h linux-2.4.3+fd_events/include/asm-i386/unistd.h
--- linux-2.4.3/include/asm-i386/unistd.h	Fri Aug 11 17:39:23 2000
+++ linux-2.4.3+fd_events/include/asm-i386/unistd.h	Fri Apr  6 16:28:41 2001
@@ -227,6 +227,8 @@
 #define __NR_madvise1		219	/* delete when C lib stub is removed */
 #define __NR_getdents64		220
 #define __NR_fcntl64		221
+#define __NR_bind_event		222
+#define __NR_get_events		223
 
 /* user-visible error numbers are in the range -1 - -124: see <asm-i386/errno.h> */
 
diff -ruN --exclude-from=_diff_exclude_file linux-2.4.3/include/linux/fdevent.h linux-2.4.3+fd_events/include/linux/fdevent.h
--- linux-2.4.3/include/linux/fdevent.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.3+fd_events/include/linux/fdevent.h	Sat Apr 14 22:17:10 2001
@@ -0,0 +1,97 @@
+/* fdevent.h - internal definitions of file events interface */
+ 
+/* Written 2001 by Bart Trojanowski <bart@jukie.net>, Chrysalis-ITS */
+
+/* This interface is exported by using the bind_event()/get_events()
+ * systemcall pair; docs are on the web (jukie.net/~bart/kernel/fdevent)
+ */ 
+#ifndef _LINUX_FDEVENT_H
+#define _LINUX_FDEVENT_H
+
+#ifdef __KERNEL__
+
+#include <linux/config.h>
+#include <asm/fdevent.h>
+
+#ifdef CONFIG_FILE_EVENTS
+
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <asm/types.h>
+
+/* debug macros */
+#ifdef CONFIG_DEBUG_FILE_EVENTS
+#define FEDBG(format, arg...) printk(KERN_ERR __FILE__ ":%d: " \
+                                   format "\n" , __LINE__ , ## arg)
+#else
+#define FEDBG(format, arg...) do{/*nothing*/}while(0)
+#endif
+
+typedef struct file_event_s {
+	struct file_event_s *next, *prev; /* queue stored in files_struct */
+	struct fdevent event;
+	
+} file_event_t;
+
+typedef struct file_event_list_s {
+	struct file_event_s *head, *tail; /* just like next/prev above */
+	spinlock_t lock;
+} file_event_list_t;
+
+#define FILE_EVENT_INIT { NULL, NULL, FDEVENT_INIT }
+#define INIT_FILE_EVENT(ptr) do { \
+	(ptr)->next = ptr; (ptr)->prev = ptr; \
+	INIT_FDEVENT( &(ptr)->event ); \
+} while (0)
+
+#define FILE_EVENT_LIST_INIT { NULL, NULL, SPIN_LOCK_UNLOCKED }
+#define INIT_FILE_EVENT_LIST(ptr) do { \
+	(ptr)->head = (void*)ptr; (ptr)->tail = (void*)ptr; \
+	spin_lock_init( &(ptr)->lock ); \
+} while (0)
+
+
+/* 
+ * these are some wrappers for the <list.h> functions we are interested in
+ * ... no point in reinventing the wheel.
+ */
+
+static inline void 
+file_event_list_add_tail( file_event_t *ev, file_event_list_t *list )
+{
+	list_add_tail( (struct list_head*)ev, (struct list_head*)list );
+}
+
+static inline void 
+file_event_list_del( file_event_t *ev )
+{
+	list_del_init( (struct list_head*)ev );
+}
+
+/* forward declarations */
+struct file;
+struct files_struct;
+
+/* enqueue the event */
+extern int 
+deliver_file_event(struct file *file, unsigned long mask);
+
+/* initialize links between the file and the task's files_struct */
+extern int
+file_event_init( struct file *file, struct files_struct *files );
+
+/* clean up links and remove file from any link list */
+extern int
+file_event_release( struct file *file );
+
+#define DELIVER_FILE_EVENT(filp,mask) deliver_file_event(filp, mask);
+
+#else  /* CONFIG_FILE_EVENTS */
+
+#define DELIVER_FILE_EVENT(filp,mask) do{ /*nothing*/ }while(0)
+
+#endif /* CONFIG_FILE_EVENTS */
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_FDEVENT_H */
diff -ruN --exclude-from=_diff_exclude_file linux-2.4.3/include/linux/fs.h linux-2.4.3+fd_events/include/linux/fs.h
--- linux-2.4.3/include/linux/fs.h	Mon Mar 26 18:48:11 2001
+++ linux-2.4.3+fd_events/include/linux/fs.h	Sat Apr 14 22:29:39 2001
@@ -21,6 +21,7 @@
 #include <linux/cache.h>
 #include <linux/stddef.h>
 #include <linux/string.h>
+#include <linux/fdevent.h>
 
 #include <asm/atomic.h>
 #include <asm/bitops.h>
@@ -495,6 +496,13 @@
 
 	/* needed for tty driver, and maybe others */
 	void			*private_data;
+	
+#ifdef CONFIG_FILE_EVENTS
+	unsigned long           f_event_mask; /* event mask the user wants to watch for  */
+	file_event_t		f_event;      /* dangling link which becomes a part...   */
+	file_event_list_t       *f_event_list;/* ... of this list on files_struct of a task */
+	wait_queue_head_t       *f_event_wait;/* wake up queue after delivering an event */
+#endif
 };
 extern spinlock_t files_lock;
 #define file_list_lock() spin_lock(&files_lock);
diff -ruN --exclude-from=_diff_exclude_file linux-2.4.3/include/linux/sched.h linux-2.4.3+fd_events/include/linux/sched.h
--- linux-2.4.3/include/linux/sched.h	Mon Mar 26 18:48:11 2001
+++ linux-2.4.3+fd_events/include/linux/sched.h	Sat Apr 14 22:29:40 2001
@@ -26,6 +26,7 @@
 #include <linux/signal.h>
 #include <linux/securebits.h>
 #include <linux/fs_struct.h>
+#include <linux/fdevent.h>
 
 /*
  * cloning flags:
@@ -177,8 +178,27 @@
 	fd_set close_on_exec_init;
 	fd_set open_fds_init;
 	struct file * fd_array[NR_OPEN_DEFAULT];
+#ifdef CONFIG_FILE_EVENTS
+	struct fdevent    default_file_event; /* used to initialize files of this struct */
+	file_event_list_t file_event_list;    /* keep the queue of new events            */
+	wait_queue_head_t file_event_wait;    /* used to wake up sys_get_events caller   */
+#endif
 };
 
+/* if compiled in then need to initialize the file events part of the files_struct */
+#ifdef CONFIG_FILE_EVENTS
+#define INIT_FILES_STRUCT_EVENTS ,                      \
+		default_file_event: FDEVENT_INIT,       \
+		file_event_list:   FILE_EVENT_LIST_INIT,\
+		file_event_wait:   { 			\
+			lock: WAITQUEUE_RW_LOCK_UNLOCKED,\
+			task_list: { NULL, NULL }	\
+		} 					\
+
+#else
+#define INIT_FILES_STRUCT_EVENTS /* nothing */
+#endif
+
 #define INIT_FILES \
 { 							\
 	count:		ATOMIC_INIT(1), 		\
@@ -192,6 +212,7 @@
 	close_on_exec_init: { { 0, } }, 		\
 	open_fds_init:	{ { 0, } }, 			\
 	fd_array:	{ NULL, } 			\
+	INIT_FILES_STRUCT_EVENTS			\
 }
 
 /* Maximum number of active map areas.. This is a random (large) number */
diff -ruN --exclude-from=_diff_exclude_file linux-2.4.3/kernel/fork.c linux-2.4.3+fd_events/kernel/fork.c
--- linux-2.4.3/kernel/fork.c	Mon Mar 19 15:35:08 2001
+++ linux-2.4.3+fd_events/kernel/fork.c	Fri Apr  6 21:27:03 2001
@@ -18,6 +18,7 @@
 #include <linux/smp_lock.h>
 #include <linux/module.h>
 #include <linux/vmalloc.h>
+#include <linux/fdevent.h>	/* file events interface */
 
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
@@ -440,6 +441,14 @@
 	newf->close_on_exec = &newf->close_on_exec_init;
 	newf->open_fds	    = &newf->open_fds_init;
 	newf->fd	    = &newf->fd_array[0];
+	
+#ifdef CONFIG_FILE_EVENTS
+	/* support for file_events on this task */
+	INIT_FDEVENT( &newf->default_file_event );
+	INIT_FILE_EVENT_LIST( &newf->file_event_list );
+	init_waitqueue_head( &newf->file_event_wait );
+	/* TODO: I should inherit the events of the parent process */
+#endif
 
 	/* We don't yet have the oldf readlock, but even if the old
            fdset gets grown now, we'll only copy up to "size" fds */
@@ -485,6 +494,9 @@
 		if (f)
 			get_file(f);
 		*new_fds++ = f;
+#ifdef CONFIG_FILE_EVENTS
+		/* TODO: I should inherit the links list of events from the parent process */
+#endif
 	}
 	read_unlock(&oldf->file_lock);
 
diff -ruN --exclude-from=_diff_exclude_file linux-2.4.3/net/core/sock.c linux-2.4.3+fd_events/net/core/sock.c
--- linux-2.4.3/net/core/sock.c	Sat Feb  3 14:26:44 2001
+++ linux-2.4.3+fd_events/net/core/sock.c	Fri Apr  6 22:38:39 2001
@@ -79,6 +79,7 @@
  *		Jay Schulist	:	Added SO_ATTACH_FILTER and SO_DETACH_FILTER.
  *		Andi Kleen	:	Add sock_kmalloc()/sock_kfree_s()
  *		Andi Kleen	:	Fix write_space callback
+ *              Bart Trojanowski:       Added file_event support
  *
  * To Fix:
  *
@@ -107,6 +108,7 @@
 #include <linux/interrupt.h>
 #include <linux/poll.h>
 #include <linux/init.h>
+#include <linux/fdevent.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -1084,6 +1086,8 @@
 	if (sk->sleep && waitqueue_active(sk->sleep))
 		wake_up_interruptible(sk->sleep);
 	sk_wake_async(sk,0,POLL_ERR); 
+	if( sk->socket )
+		DELIVER_FILE_EVENT(sk->socket->file, FDEVENT_ERR);
 	read_unlock(&sk->callback_lock);
 }
 
@@ -1093,6 +1097,8 @@
 	if (sk->sleep && waitqueue_active(sk->sleep))
 		wake_up_interruptible(sk->sleep);
 	sk_wake_async(sk,1,POLL_IN);
+	if( sk->socket )
+		DELIVER_FILE_EVENT(sk->socket->file, FDEVENT_IN);
 	read_unlock(&sk->callback_lock);
 }
 
@@ -1108,8 +1114,11 @@
 			wake_up_interruptible(sk->sleep);
 
 		/* Should agree with poll, otherwise some programs break */
-		if (sock_writeable(sk))
+		if (sock_writeable(sk)) {
 			sk_wake_async(sk, 2, POLL_OUT);
+			if( sk->socket )
+				DELIVER_FILE_EVENT(sk->socket->file, FDEVENT_OUT);
+		}
 	}
 
 	read_unlock(&sk->callback_lock);
diff -ruN --exclude-from=_diff_exclude_file linux-2.4.3/net/ipv4/tcp_input.c linux-2.4.3+fd_events/net/ipv4/tcp_input.c
--- linux-2.4.3/net/ipv4/tcp_input.c	Fri Feb  9 14:34:13 2001
+++ linux-2.4.3+fd_events/net/ipv4/tcp_input.c	Fri Apr  6 22:40:04 2001
@@ -60,6 +60,7 @@
  *		Pasi Sarolahti,
  *		Panu Kuhlberg:		Experimental audit of TCP (re)transmission
  *					engine. Lots of bugs are found.
+ *              Bart Trojanowski:       Added file_event support
  */
 
 #include <linux/config.h>
@@ -68,7 +69,7 @@
 #include <net/tcp.h>
 #include <net/inet_common.h>
 #include <linux/ipsec.h>
-
+#include <linux/fdevent.h>
 
 /* These are on by default so the code paths get tested.
  * For the final 2.2 this may be undone at our discretion. -DaveM
@@ -2281,10 +2282,15 @@
 		sk->state_change(sk);
 
 		/* Do not send POLL_HUP for half duplex close. */
-		if (sk->shutdown == SHUTDOWN_MASK || sk->state == TCP_CLOSE)
+		if (sk->shutdown == SHUTDOWN_MASK || sk->state == TCP_CLOSE) {
 			sk_wake_async(sk, 1, POLL_HUP);
-		else
+			if( sk->socket )
+				DELIVER_FILE_EVENT(sk->socket->file, FDEVENT_HUP);
+		} else {
 			sk_wake_async(sk, 1, POLL_IN);
+			if( sk->socket )
+				DELIVER_FILE_EVENT(sk->socket->file, FDEVENT_IN);
+		}
 	}
 }
 
@@ -2911,8 +2917,10 @@
 		if (sk->sleep && waitqueue_active(sk->sleep))
 			wake_up_interruptible(sk->sleep);
 
-		if (sock->fasync_list && !(sk->shutdown&SEND_SHUTDOWN))
+		if (sock->fasync_list && !(sk->shutdown&SEND_SHUTDOWN)) {
 			sock_wake_async(sock, 2, POLL_OUT);
+			DELIVER_FILE_EVENT(sock->file, FDEVENT_OUT);
+		}
 
 		/* Satisfy those who hook write_space() callback. */
 		if (sk->write_space != tcp_write_space)
@@ -3020,6 +3028,8 @@
 		else
 			kill_pg(-sk->proc, SIGURG, 1);
 		sk_wake_async(sk, 3, POLL_PRI);
+		if( sk->socket )
+			DELIVER_FILE_EVENT(sk->socket->file, FDEVENT_PRI);
 	}
 
 	/* We may be adding urgent data when the last byte read was
@@ -3496,6 +3506,8 @@
 		if(!sk->dead) {
 			sk->state_change(sk);
 			sk_wake_async(sk, 0, POLL_OUT);
+			if( sk->socket )
+				DELIVER_FILE_EVENT(sk->socket->file, FDEVENT_OUT);
 		}
 
 		if (tp->write_pending || tp->defer_accept) {
@@ -3722,6 +3734,7 @@
 				if (sk->socket) {
 					sk->state_change(sk);
 					sk_wake_async(sk,0,POLL_OUT);
+					DELIVER_FILE_EVENT(sk->socket->file, FDEVENT_OUT);
 				}
 
 				tp->snd_una = TCP_SKB_CB(skb)->ack_seq;
diff -ruN --exclude-from=_diff_exclude_file linux-2.4.3/net/socket.c linux-2.4.3+fd_events/net/socket.c
--- linux-2.4.3/net/socket.c	Fri Nov 17 14:36:27 2000
+++ linux-2.4.3+fd_events/net/socket.c	Fri Apr  6 16:46:55 2001
@@ -44,6 +44,7 @@
  *		Tigran Aivazian	:	sys_send(args) calls sys_sendto(args, NULL, 0)
  *		Tigran Aivazian	:	Made listen(2) backlog sanity checks 
  *					protocol-independent
+ *              Bart Trojanowsi :       Added support for file_event on sockets
  *
  *
  *		This program is free software; you can redistribute it and/or
@@ -484,6 +485,10 @@
  
 void sock_release(struct socket *sock)
 {
+#ifdef CONFIG_FILE_EVENTS
+	(void)file_event_release( sock->file );
+#endif
+
 	if (sock->ops) 
 		sock->ops->release(sock);
 
@@ -898,7 +903,11 @@
 	retval = sock_map_fd(sock);
 	if (retval < 0)
 		goto out_release;
-
+	
+#ifdef CONFIG_FILE_EVENTS
+	(void)file_event_init( sock->file, current->files );
+#endif
+	
 out:
 	/* It may be already another descriptor 8) Not kernel problem. */
 	return retval;
@@ -953,8 +962,13 @@
 	err = put_user(fd1, &usockvec[0]); 
 	if (!err)
 		err = put_user(fd2, &usockvec[1]);
-	if (!err)
+	if (!err) {
+#ifdef CONFIG_FILE_EVENTS
+		(void)file_event_init( sock1->file, current->files );
+		(void)file_event_init( sock2->file, current->files );
+#endif
 		return 0;
+	}
 
 	sys_close(fd2);
 	sys_close(fd1);
@@ -1066,6 +1080,10 @@
 
 	if ((err = sock_map_fd(newsock)) < 0)
 		goto out_release;
+
+#ifdef CONFIG_FILE_EVENTS
+	(void)file_event_init( newsock->file, current->files );
+#endif
 
 out_put:
 	sockfd_put(sock);

