Epoll patch (rev 7)

Mike McCormack mike at codeweavers.com
Wed Sep 22 03:34:53 CDT 2004


Updated with Marcus's suggested configure update.

Mike


ChangeLog:
* add support for using epoll instead of select to the wineserver
-------------- next part --------------
Index: server/fd.c
===================================================================
RCS file: /home/wine/wine/server/fd.c,v
retrieving revision 1.26
diff -u -r1.26 fd.c
--- server/fd.c	20 Sep 2004 19:14:35 -0000	1.26
+++ server/fd.c	22 Sep 2004 06:55:22 -0000
@@ -2,6 +2,8 @@
  * Server-side file descriptor management
  *
  * Copyright (C) 2000, 2003 Alexandre Julliard
+ * Copyright (C) 2004 Shachar Shemesh for Lingnu Open Source Consulting ltd.
+ * Copyright (C) 2004 Mike McCormack
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -33,6 +35,10 @@
 #ifdef HAVE_SYS_POLL_H
 #include <sys/poll.h>
 #endif
+#include <stdint.h>
+#ifdef HAVE_SYS_EPOLL_H
+#include <sys/epoll.h>
+#endif
 #include <sys/stat.h>
 #include <sys/time.h>
 #include <sys/types.h>
@@ -227,6 +233,103 @@
 
 
 /****************************************************************/
+/* epoll support */
+
+#if defined(HAVE_SYS_EPOLL_H) && defined(HAVE_LIBEPOLL)
+
+#define EPOLL_SIZE 1024
+#define MAX_EVENTS 10
+
+static int epoll_fd;
+
+/* this should optimize away if the poll constants are the same as the epoll ones */
+static inline int epoll_events( int events )
+{
+    int r = 0;
+
+    if ((POLLIN == EPOLLIN) && (POLLOUT == EPOLLOUT) &&
+        (POLLERR == EPOLLERR) && (POLLHUP == EPOLLHUP))
+        return events;
+    if (POLLIN&events) r |= EPOLLIN;
+    if (POLLOUT&events) r |= EPOLLOUT;
+    if (POLLERR&events) r |= EPOLLERR;
+    if (POLLHUP&events) r |= EPOLLHUP;
+    return r;
+}
+
+static inline void do_epoll_add( int fd, int events, unsigned 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_mod( int fd, int events, unsigned int user )
+{
+    struct epoll_event eev;
+    int r;
+
+    if (epoll_fd < 0)
+        return;
+    if (fd < 0)
+        return;
+    eev.events = events;
+    eev.data.u32 = user;
+    r = epoll_ctl( epoll_fd, EPOLL_CTL_MOD, fd, &eev );
+    assert( 0 == r );
+}
+
+static inline void do_epoll_remove( int fd, int old_events, unsigned int user )
+{
+    struct epoll_event eev;
+    int r;
+
+    if (epoll_fd < 0)
+        return;
+    if (fd < 0)
+        return;
+    if (!old_events)
+        return;
+    r = epoll_ctl( epoll_fd, EPOLL_CTL_DEL, fd, &eev );
+    assert( 0 == r );
+}
+
+void init_fd(void)
+{
+    epoll_fd = epoll_create(EPOLL_SIZE);
+}
+
+#else
+
+static inline void do_epoll_add( int fd, int events, unsigned int user )
+{
+}
+
+static inline void do_epoll_mod( int fd, int events, unsigned int user )
+{
+}
+
+static inline void do_epoll_remove( int fd, int old_events, unsigned int user )
+{
+}
+
+void init_fd(void)
+{
+}
+
+#endif
+
+/****************************************************************/
 /* poll support */
 
 static struct fd **poll_users;              /* users array */
@@ -280,6 +383,7 @@
 {
     assert( user >= 0 );
     assert( poll_users[user] == fd );
+    do_epoll_remove( pollfd[user].fd, pollfd[user].events, user );
     pollfd[user].fd = -1;
     pollfd[user].events = 0;
     pollfd[user].revents = 0;
@@ -335,8 +439,57 @@
     return -1;  /* no pending timeouts */
 }
 
+#if defined(HAVE_SYS_EPOLL_H) && defined(HAVE_LIBEPOLL)
+
+/* server main poll() loop using epoll */
+static int epoll_loop(void)
+{
+    struct epoll_event ev[MAX_EVENTS];
+    int ret, i, user, timeout;
+
+    if( epoll_fd < 0 )
+        return 0;
+
+    while (active_users)
+    {
+        timeout = get_next_timeout();
+
+        if (!active_users) break;  /* last user removed by a timeout */
+
+        ret = epoll_wait( epoll_fd, &ev[0], MAX_EVENTS, timeout );
+
+        /* put the events into the pollfd array first, like select does */
+        for (i = 0; i < ret; i++)
+        {
+            user = ev[i].data.u32;
+            assert( user < nb_users );
+            pollfd[user].revents = ev[i].events;
+        }
+
+        /* read events from the pollfd array, as set_fd_events may modify them */
+        for (i = 0; i < ret; i++)
+        {
+            user = ev[i].data.u32;
+            if (pollfd[user].revents)
+                fd_poll_event( poll_users[user], pollfd[user].revents );
+        }
+    }
+    close( epoll_fd );
+
+    return 1;
+}
+
+#else
+
+static int epoll_loop(void)
+{
+    return 0;
+}
+
+#endif
+
 /* server main poll() loop */
-void main_loop(void)
+void select_loop(void)
 {
     int i, ret, timeout;
 
@@ -361,6 +514,12 @@
     }
 }
 
+void main_loop(void)
+{
+    if (epoll_loop())
+        return;
+    select_loop();
+}
 
 /****************************************************************/
 /* inode functions */
@@ -843,12 +1002,24 @@
     assert( poll_users[user] == fd );
     if (events == -1)  /* stop waiting on this fd completely */
     {
+        do_epoll_remove( pollfd[user].fd, pollfd[user].events, user );
         pollfd[user].fd = -1;
         pollfd[user].events = POLLERR;
         pollfd[user].revents = 0;
     }
     else if (pollfd[user].fd != -1 || !pollfd[user].events)
     {
+        /* remove the old fd */
+        if (fd->unix_fd != pollfd[user].fd || !events)
+            do_epoll_remove( pollfd[user].fd, pollfd[user].events, user );
+        if (events)
+        {
+            /* add the new fd or update the old one */
+            if ( pollfd[user].fd == -1 || !pollfd[user].events)
+                do_epoll_add( fd->unix_fd, events, user );
+            else if (pollfd[user].events != events)
+                do_epoll_mod( fd->unix_fd, events, user );
+        }
         pollfd[user].fd = fd->unix_fd;
         pollfd[user].events = events;
     }
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	22 Sep 2004 06:55:22 -0000
@@ -122,6 +122,7 @@
     signal( SIGTERM, sigterm_handler );
     signal( SIGABRT, sigterm_handler );
 
+    init_fd();
     sock_init();
     open_master_socket();
     sync_namespace = create_namespace( 37, TRUE );
Index: server/file.h
===================================================================
RCS file: /home/wine/wine/server/file.h,v
retrieving revision 1.17
diff -u -r1.17 file.h
--- server/file.h	18 Aug 2004 00:04:58 -0000	1.17
+++ server/file.h	22 Sep 2004 06:55:22 -0000
@@ -44,6 +44,7 @@
 
 /* file descriptor functions */
 
+extern void init_fd(void);
 extern struct fd *alloc_fd( const struct fd_ops *fd_user_ops, struct object *user );
 extern struct fd *open_fd( struct fd *fd, const char *name, int flags, mode_t *mode,
                            unsigned int access, unsigned int sharing, unsigned int options );
Index: server/Makefile.in
===================================================================
RCS file: /home/wine/wine/server/Makefile.in,v
retrieving revision 1.51
diff -u -r1.51 Makefile.in
--- server/Makefile.in	23 Jun 2004 20:44:58 -0000	1.51
+++ server/Makefile.in	22 Sep 2004 06:55:22 -0000
@@ -5,6 +5,8 @@
 VPATH     = @srcdir@
 MODULE    = none
 
+LIBEPOLL  = @LIBEPOLL@
+
 C_SRCS = \
 	async.c \
 	atom.c \
@@ -52,7 +54,7 @@
 @MAKE_RULES@
 
 wineserver: $(OBJS)
-	$(CC) -o $(PROGRAMS) $(OBJS) $(LIBWINE) $(LIBUNICODE) $(LIBPORT) $(LDFLAGS) $(LIBS)
+	$(CC) -o $(PROGRAMS) $(OBJS) $(LIBWINE) $(LIBUNICODE) $(LIBPORT) $(LDFLAGS) $(LIBS) $(LIBEPOLL)
 
 install:: $(PROGRAMS)
 	$(MKINSTALLDIRS) $(bindir)
Index: configure.ac
===================================================================
RCS file: /home/wine/wine/configure.ac,v
retrieving revision 1.310
diff -u -r1.310 configure.ac
--- configure.ac	22 Sep 2004 04:08:38 -0000	1.310
+++ configure.ac	22 Sep 2004 06:55:22 -0000
@@ -132,6 +132,14 @@
 AC_CHECK_LIB(xpg4,_xpg4_setrunelocale)
 dnl Check for -lpoll for Mac OS X/Darwin
 AC_CHECK_LIB(poll,poll)
+dnl Check for -lepoll
+LIBEPOLL=
+AC_SUBST(LIBEPOLL)
+AC_CHECK_FUNC(epoll_create,
+              [AC_DEFINE(HAVE_LIBEPOLL)],
+              [AC_CHECK_LIB(epoll,epoll_create,
+                            [LIBEPOLL="-lepoll"
+                             AC_DEFINE(HAVE_LIBEPOLL)])])
 dnl Check for -lresolv for Mac OS X/Darwin
 AC_CHECK_LIB(resolv,res_9_init)
 dnl Check for -lpthread
@@ -1156,6 +1164,7 @@
 	sys/cdio.h \
 	sys/elf32.h \
 	sys/errno.h \
+	sys/epoll.h \
 	sys/exec_elf.h \
 	sys/file.h \
 	sys/filio.h \
Index: include/config.h.in
===================================================================
RCS file: /home/wine/wine/include/config.h.in,v
retrieving revision 1.198
diff -u -r1.198 config.h.in
--- include/config.h.in	22 Sep 2004 04:08:38 -0000	1.198
+++ include/config.h.in	22 Sep 2004 06:55:22 -0000
@@ -254,6 +254,9 @@
 /* Define if you have the curses library (-lcurses) */
 #undef HAVE_LIBCURSES
 
+/* Define to 1 if you have the `epoll' library (-lepoll). */
+#undef HAVE_LIBEPOLL
+
 /* Define to 1 if you have the `i386' library (-li386). */
 #undef HAVE_LIBI386
 
@@ -616,6 +619,9 @@
 
 /* Define to 1 if you have the <sys/elf32.h> header file. */
 #undef HAVE_SYS_ELF32_H
+
+/* Define to 1 if you have the <sys/epoll.h> header file. */
+#undef HAVE_SYS_EPOLL_H
 
 /* Define to 1 if you have the <sys/errno.h> header file. */
 #undef HAVE_SYS_ERRNO_H


More information about the wine-patches mailing list