epoll patch - status?

Mike McCormack mike at codeweavers.com
Wed Sep 8 12:51:35 CDT 2004


Shachar Shemesh wrote:

> After a discussion with Alexandre on IRC I came to the conclusion that 
> nothing I will do will make this patch go in. Mike, please add it to 
> your list of "uncommitted patches".

Hi Shachar,

I'm not sure which Mike the above is addressed at... :)

I agree epoll is something worth persuing, so I had a go at refining 
your patch in accordance with what Alexandre recommended (quoted below). 
  Here's what I came up with... it's not complete as yet, but hopefully 
it's more conformant with Alexandre's wishes ...

Notes:
* used direct syscalls as my libc doesn't have epoll_* functions
* fixed array of epoll_event structures for starters
* do_epoll_remove assert commented as it occasionally triggers
* cheated by not declaring init_fd() in a header

It works for a quick test, but I'm sure everybody can find problems with 
it...

Mike

> It needs some cleaning up, you need to find a way to make fewer
> changes to the poll() side of things, also the epoll stuff should be
> separated enough that you can put it inside #ifdef instead of having
> dummy declarations of the epoll functions. Also try to better follow
> the coding conventions of the rest of the file, for instance use
> underscores in variable names, get rid of some useless asserts, etc.

-------------- next part --------------
? server/mailslot.c
Index: server/fd.c
===================================================================
RCS file: /home/wine/wine/server/fd.c,v
retrieving revision 1.24
diff -u -r1.24 fd.c
--- server/fd.c	8 Sep 2004 04:17:31 -0000	1.24
+++ server/fd.c	8 Sep 2004 16:09:18 -0000
@@ -18,6 +18,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#define USE_EPOLL
 
 #include "config.h"
 
@@ -236,6 +237,122 @@
 static int allocated_users;                 /* count of allocated entries in the array */
 static struct fd **freelist;                /* list of free entries in the array */
 
+#ifdef USE_EPOLL
+
+#define EPOLL_SIZE 1024
+#define MAX_EVENTS 10
+
+static int epoll_fd;
+
+enum EPOLL_EVENTS
+{
+    EPOLLIN  = 0x001,
+    EPOLLPRI = 0x002,
+    EPOLLOUT = 0x004,
+    EPOLLERR = 0x008,
+    EPOLLHUP = 0x010
+};
+
+#define EPOLL_CTL_ADD 1
+#define EPOLL_CTL_DEL 2
+#define EPOLL_CTL_MOD 3
+
+#ifndef __NR_epoll_create
+#define __NR_epoll_create	254
+#endif
+
+#ifndef __NR_epoll_ctl
+#define __NR_epoll_ctl		255
+#endif
+
+#ifndef __NR_epoll_wait
+#define __NR_epoll_wait		256
+#endif
+
+typedef union epoll_data {
+     void *ptr;
+     int fd;
+     __uint32_t u32;
+     __uint64_t u64;
+} epoll_data_t;
+
+struct epoll_event {
+     __uint32_t events;
+     epoll_data_t data;
+};
+
+static inline int sys_epoll_create( int size )
+{
+    return syscall(__NR_epoll_create, size);
+}
+
+static inline int sys_epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
+{
+    return syscall(__NR_epoll_ctl, epfd, op, fd, event);
+}
+
+static inline int sys_epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout)
+{
+    return syscall(__NR_epoll_wait, epfd, events, maxevents, timeout);
+}
+
+#define epoll_create sys_epoll_create
+#define epoll_ctl    sys_epoll_ctl
+#define epoll_wait   sys_epoll_wait
+
+static inline void do_epoll_add( int fd, int events, int user )
+{
+    struct epoll_event eev;
+    int r;
+
+    if( epoll_fd < 0 )
+        return;
+    if( fd < 0 )
+        return;
+    if( !events )
+        return;
+    eev.events = events;
+    eev.data.u32 = user;
+    r = epoll_ctl( epoll_fd, EPOLL_CTL_ADD, fd, &eev );
+    assert( 0 == r );
+}
+
+static inline void do_epoll_remove( int fd )
+{
+    struct epoll_event eev;
+    int r;
+
+    if( epoll_fd < 0 )
+        return;
+    if( fd < 0 )
+        return;
+    r = epoll_ctl( epoll_fd, EPOLL_CTL_DEL, fd, &eev );
+
+    /* get an assert here sometimes removing an fd we never added */
+    /* assert( 0 == r ); */
+}
+
+void init_fd()
+{
+    epoll_fd = epoll_create(EPOLL_SIZE);
+}
+
+#else
+
+static inline void do_epoll_add( int fd, int events, int user )
+{
+}
+
+static inline void do_epoll_remove( int fd )
+{
+}
+
+void init_fd()
+{
+}
+
+#endif
+
 /* add a user in the poll array and return its index, or -1 on failure */
 static int add_poll_user( struct fd *fd )
 {
@@ -280,6 +397,7 @@
 {
     assert( user >= 0 );
     assert( poll_users[user] == fd );
+    do_epoll_remove( pollfd[user].fd );
     pollfd[user].fd = -1;
     pollfd[user].events = 0;
     pollfd[user].revents = 0;
@@ -288,56 +406,92 @@
     active_users--;
 }
 
-
-/* server main poll() loop */
-void main_loop(void)
+static inline int next_delta()
 {
-    int ret;
+    long diff = -1;
+    struct list expired_list, *ptr;
+    struct timeval now;
 
-    while (active_users)
+    if (list_empty(&timeout_list))
+        return diff;
+
+    gettimeofday( &now, NULL );
+
+    /* first remove all expired timers from the list */
+
+    list_init( &expired_list );
+    while ((ptr = list_head( &timeout_list )) != NULL)
     {
-        long diff = -1;
-        if (!list_empty( &timeout_list ))
+        struct timeout_user *timeout = LIST_ENTRY( ptr, struct timeout_user, entry );
+
+        if (!time_before( &now, &timeout->when ))
         {
-            struct list expired_list, *ptr;
-            struct timeval now;
-            gettimeofday( &now, NULL );
+            list_remove( &timeout->entry );
+            list_add_tail( &expired_list, &timeout->entry );
+        }
+        else break;
+    }
 
-            /* first remove all expired timers from the list */
+    /* now call the callback for all the removed timers */
 
-            list_init( &expired_list );
-            while ((ptr = list_head( &timeout_list )) != NULL)
-            {
-                struct timeout_user *timeout = LIST_ENTRY( ptr, struct timeout_user, entry );
+    while ((ptr = list_head( &expired_list )) != NULL)
+    {
+        struct timeout_user *timeout = LIST_ENTRY( ptr, struct timeout_user, entry );
+        list_remove( &timeout->entry );
+        timeout->callback( timeout->private );
+        free( timeout );
+    }
 
-                if (!time_before( &now, &timeout->when ))
-                {
-                    list_remove( &timeout->entry );
-                    list_add_tail( &expired_list, &timeout->entry );
-                }
-                else break;
-            }
+    if (!active_users) return diff;  /* last user removed by a timeout */
 
-            /* now call the callback for all the removed timers */
+    if ((ptr = list_head( &timeout_list )) != NULL)
+    {
+        struct timeout_user *timeout = LIST_ENTRY( ptr, struct timeout_user, entry );
+        diff = (timeout->when.tv_sec - now.tv_sec) * 1000
+             + (timeout->when.tv_usec - now.tv_usec) / 1000;
+        if (diff < 0) diff = 0;
+    }
 
-            while ((ptr = list_head( &expired_list )) != NULL)
-            {
-                struct timeout_user *timeout = LIST_ENTRY( ptr, struct timeout_user, entry );
-                list_remove( &timeout->entry );
-                timeout->callback( timeout->private );
-                free( timeout );
-            }
+    return diff;
+}
 
-            if (!active_users) break;  /* last user removed by a timeout */
+#ifdef USE_EPOLL
 
-            if ((ptr = list_head( &timeout_list )) != NULL)
-            {
-                struct timeout_user *timeout = LIST_ENTRY( ptr, struct timeout_user, entry );
-                diff = (timeout->when.tv_sec - now.tv_sec) * 1000
-                     + (timeout->when.tv_usec - now.tv_usec) / 1000;
-                if (diff < 0) diff = 0;
-            }
+/* server main poll() loop using epoll */
+static void epoll_loop(void)
+{
+    int ret, i;
+    struct epoll_event ev[MAX_EVENTS];
+
+    assert(POLLIN == EPOLLIN);
+    assert(POLLOUT == EPOLLOUT);
+    assert(POLLERR == EPOLLERR);
+    assert(POLLHUP == EPOLLHUP);
+
+    while (active_users)
+    {
+        int diff = next_delta();
+        if (!active_users) break;  /* last user removed by a timeout */
+
+        ret = epoll_wait( epoll_fd, &ev[0], MAX_EVENTS, diff );
+        for( i=0; i<ret; i++ )
+        {
+            assert( ev[i].data.u32 < nb_users );
+            fd_poll_event( poll_users[ev[i].data.u32], ev[i].events );
         }
+    }
+}
+#endif
+
+/* server main poll() loop using select */
+static void select_loop(void)
+{
+    int ret;
+
+    while (active_users)
+    {
+        int diff = next_delta();
+        if (!active_users) break;  /* last user removed by a timeout */
 
         ret = poll( pollfd, nb_users, diff );
         if (ret > 0)
@@ -355,6 +509,19 @@
     }
 }
 
+void main_loop(void)
+{
+#ifdef USE_EPOLL
+    if( epoll_fd >= 0 )
+    {
+        fprintf(stderr,"epoll enabled\n");
+        epoll_loop();
+        close( epoll_fd );
+        return;
+    }
+#endif
+    select_loop();
+}
 
 /****************************************************************/
 /* inode functions */
@@ -837,14 +1004,19 @@
     assert( poll_users[user] == fd );
     if (events == -1)  /* stop waiting on this fd completely */
     {
+        if( pollfd[user].events )
+            do_epoll_remove( pollfd[user].fd );
         pollfd[user].fd = -1;
         pollfd[user].events = POLLERR;
         pollfd[user].revents = 0;
     }
     else if (pollfd[user].fd != -1 || !pollfd[user].events)
     {
+        if( pollfd[user].events )
+            do_epoll_remove( pollfd[user].fd );
         pollfd[user].fd = fd->unix_fd;
         pollfd[user].events = events;
+        do_epoll_add( pollfd[user].fd, pollfd[user].events, user );
     }
 }
 
Index: server/main.c
===================================================================
RCS file: /home/wine/wine/server/main.c,v
retrieving revision 1.31
diff -u -r1.31 main.c
--- server/main.c	26 Mar 2003 01:32:18 -0000	1.31
+++ server/main.c	8 Sep 2004 16:09:18 -0000
@@ -110,6 +110,7 @@
     exit(1);  /* make sure atexit functions get called */
 }
 
+void init_fd();
 int main( int argc, char *argv[] )
 {
     parse_args( argc, argv );
@@ -122,6 +123,7 @@
     signal( SIGTERM, sigterm_handler );
     signal( SIGABRT, sigterm_handler );
 
+    init_fd();
     sock_init();
     open_master_socket();
     sync_namespace = create_namespace( 37, TRUE );


More information about the wine-devel mailing list