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