wineserver: compact the poll array

Mike McCormack mike at codeweavers.com
Tue Nov 23 21:55:08 CST 2004


Hi,

This patch makes sure that all the fds in the poll array are always fds 
that are valid and are polling.  I found when running iTunes, the pollfd 
array was only 20% in used, which seems like a bit a waste.

Mike


ChangeLog:
* make sure the pollfd array contains only valid fd's that are being 
polled on.

-------------- next part --------------
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	24 Nov 2004 04:41:27 -0000
@@ -52,7 +52,7 @@
 extern void *get_fd_user( struct fd *fd );
 extern int get_unix_fd( struct fd *fd );
 extern int is_same_file_fd( struct fd *fd1, struct fd *fd2 );
-extern void fd_poll_event( struct fd *fd, int event );
+extern void fd_poll_event( struct fd *fd );
 extern int check_fd_events( struct fd *fd, int events );
 extern void set_fd_events( struct fd *fd, int events );
 extern obj_handle_t lock_fd( struct fd *fd, file_pos_t offset, file_pos_t count, int shared, int wait );
Index: server/fd.c
===================================================================
RCS file: /home/wine/wine/server/fd.c,v
retrieving revision 1.28
diff -u -r1.28 fd.c
--- server/fd.c	27 Oct 2004 01:03:30 -0000	1.28
+++ server/fd.c	24 Nov 2004 04:41:27 -0000
@@ -142,7 +142,8 @@
     unsigned int         sharing;     /* file sharing mode */
     int                  unix_fd;     /* unix file descriptor */
     int                  fs_locks;    /* can we use filesystem locks for this fd? */
-    int                  poll_index;  /* index of fd in poll array */
+    int                  poll_index;  /* index of fd in poll array (poll only) */
+    struct pollfd        pfd;         /* for waiting on this fd */
 };
 
 static void fd_dump( struct object *obj, int verbose );
@@ -300,7 +301,6 @@
 static int nb_users;                        /* count of array entries actually in use */
 static int active_users;                    /* current number of active users */
 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
 
@@ -308,7 +308,7 @@
 static struct epoll_event *epoll_events;
 
 /* set the events that epoll waits for on this fd; helper for set_fd_events */
-static inline void set_fd_epoll_events( struct fd *fd, int user, int events )
+static inline void set_fd_epoll_events( struct fd *fd, int events )
 {
     struct epoll_event ev;
     int ctl;
@@ -317,22 +317,22 @@
 
     if (events == -1)  /* stop waiting on this fd completely */
     {
-        if (pollfd[user].fd == -1) return;  /* already removed */
+        if (fd->pfd.events == -1) return;  /* already removed */
         ctl = EPOLL_CTL_DEL;
     }
-    else if (pollfd[user].fd == -1)
+    else if (fd->pfd.fd == -1)
     {
-        if (pollfd[user].events) return;  /* stopped waiting on it, don't restart */
+        if (fd->pfd.events) return;  /* stopped waiting on it, don't restart */
         ctl = EPOLL_CTL_ADD;
     }
     else
     {
-        if (pollfd[user].events == events) return;  /* nothing to do */
+        if (fd->pfd.events == events) return;  /* nothing to do */
         ctl = EPOLL_CTL_MOD;
     }
 
     ev.events = events;
-    ev.data.u32 = user;
+    ev.data.ptr = fd;
 
     if (epoll_ctl( epoll_fd, ctl, fd->unix_fd, &ev ) == -1)
     {
@@ -347,7 +347,7 @@
 
 #else /* USE_EPOLL */
 
-static inline void set_fd_epoll_events( struct fd *fd, int user, int events )
+static inline void set_fd_epoll_events( struct fd *fd, int events )
 {
 }
 
@@ -357,70 +357,93 @@
 /* add a user in the poll array and return its index, or -1 on failure */
 static int add_poll_user( struct fd *fd )
 {
-    int ret;
-    if (freelist)
+    if (active_users == allocated_users)
     {
-        ret = freelist - poll_users;
-        freelist = (struct fd **)poll_users[ret];
-    }
-    else
-    {
-        if (nb_users == allocated_users)
+        struct fd **newusers;
+        struct pollfd *newpoll;
+        int new_count = allocated_users ? (allocated_users + allocated_users / 2) : 16;
+        if (!(newusers = realloc( poll_users, new_count * sizeof(*poll_users) ))) return -1;
+        if (!(newpoll = realloc( pollfd, new_count * sizeof(*pollfd) )))
+        {
+            if (allocated_users)
+                poll_users = newusers;
+            else
+                free( newusers );
+            return -1;
+        }
+        poll_users = newusers;
+        pollfd = newpoll;
+#ifdef USE_EPOLL
+        if (!allocated_users) epoll_fd = epoll_create( new_count );
+        if (epoll_fd != -1)
         {
-            struct fd **newusers;
-            struct pollfd *newpoll;
-            int new_count = allocated_users ? (allocated_users + allocated_users / 2) : 16;
-            if (!(newusers = realloc( poll_users, new_count * sizeof(*poll_users) ))) return -1;
-            if (!(newpoll = realloc( pollfd, new_count * sizeof(*pollfd) )))
-            {
-                if (allocated_users)
-                    poll_users = newusers;
-                else
-                    free( newusers );
+            struct epoll_event *new_events;
+            if (!(new_events = realloc( epoll_events, new_count * sizeof(*epoll_events) )))
                 return -1;
-            }
-            poll_users = newusers;
-            pollfd = newpoll;
-#ifdef USE_EPOLL
-            if (!allocated_users) epoll_fd = epoll_create( new_count );
-            if (epoll_fd != -1)
-            {
-                struct epoll_event *new_events;
-                if (!(new_events = realloc( epoll_events, new_count * sizeof(*epoll_events) )))
-                    return -1;
-                epoll_events = new_events;
-            }
-#endif
-            allocated_users = new_count;
+            epoll_events = new_events;
         }
-        ret = nb_users++;
+#endif
+        allocated_users = new_count;
     }
-    pollfd[ret].fd = -1;
-    pollfd[ret].events = 0;
-    pollfd[ret].revents = 0;
-    poll_users[ret] = fd;
     active_users++;
-    return ret;
+
+    return 0;
 }
 
-/* remove a user from the poll list */
-static void remove_poll_user( struct fd *fd, int user )
+static void poll_add_fd( struct fd *fd )
 {
-    assert( user >= 0 );
-    assert( poll_users[user] == fd );
+    int n;
 
-#ifdef USE_EPOLL
-    if (epoll_fd != -1 && pollfd[user].fd != -1)
+    if (fd->poll_index == -1)
     {
-        struct epoll_event dummy;
-        epoll_ctl( epoll_fd, EPOLL_CTL_DEL, fd->unix_fd, &dummy );
+        n = nb_users++;
+        poll_users[n] = fd;
+        fd->poll_index = n;
     }
+    else
+        n = fd->poll_index;
+    assert(n<active_users);
+    assert(poll_users[n]==fd);
+    pollfd[n].events  = fd->pfd.events;
+    pollfd[n].revents = fd->pfd.revents;
+    pollfd[n].fd      = fd->pfd.fd;
+}
+
+static void poll_remove_fd( struct fd *fd )
+{
+    int n = fd->poll_index;
+
+    if (n == -1) return;
+    assert(nb_users<=active_users);
+    assert(nb_users);
+    nb_users--;
+    /* if we made a hole, fill it in by moving a user from the end */
+    if (n<nb_users)
+    {
+        pollfd[n] = pollfd[nb_users];
+        poll_users[n] = poll_users[nb_users];
+        poll_users[n]->poll_index = n;
+        pollfd[nb_users].events = POLLERR;
+        pollfd[nb_users].fd = -1;
+    }
+    fd->poll_index = -1;
+}
+
+/* remove a user from the poll list */
+static void remove_poll_user( struct fd *fd )
+{
+    assert(active_users);
+    if (fd->pfd.fd != -1)
+    {
+#ifdef USE_EPOLL
+        if (epoll_fd != -1)
+        {
+            struct epoll_event dummy;
+            epoll_ctl( epoll_fd, EPOLL_CTL_DEL, fd->unix_fd, &dummy );
+        }
 #endif
-    pollfd[user].fd = -1;
-    pollfd[user].events = 0;
-    pollfd[user].revents = 0;
-    poll_users[user] = (struct fd *)freelist;
-    freelist = &poll_users[user];
+        poll_remove_fd(fd);
+    }
     active_users--;
 }
 
@@ -496,15 +519,15 @@
             /* put the events into the pollfd array first, like poll does */
             for (i = 0; i < ret; i++)
             {
-                int user = epoll_events[i].data.u32;
-                pollfd[user].revents = epoll_events[i].events;
+                struct fd *fd = epoll_events[i].data.ptr;
+                fd->pfd.revents = epoll_events[i].events;
             }
 
             /* read events from the pollfd array, as set_fd_events may modify them */
             for (i = 0; i < ret; i++)
             {
-                int user = epoll_events[i].data.u32;
-                if (pollfd[user].revents) fd_poll_event( poll_users[user], pollfd[user].revents );
+                struct fd *fd = epoll_events[i].data.ptr;
+                fd_poll_event( fd );
             }
         }
     }
@@ -521,10 +544,12 @@
         if (ret > 0)
         {
             for (i = 0; i < nb_users; i++)
+                poll_users[i]->pfd.revents = pollfd[i].revents;
+            for (i = 0; i < nb_users; i++)
             {
                 if (pollfd[i].revents)
                 {
-                    fd_poll_event( poll_users[i], pollfd[i].revents );
+                    fd_poll_event( poll_users[i] );
                     if (!--ret) break;
                 }
             }
@@ -995,7 +1020,7 @@
 
     remove_fd_locks( fd );
     list_remove( &fd->inode_entry );
-    if (fd->poll_index != -1) remove_poll_user( fd, fd->poll_index );
+    remove_poll_user( fd );
     if (fd->inode)
     {
         inode_add_closed_fd( fd->inode, fd->closed );
@@ -1010,21 +1035,20 @@
 /* set the events that select waits for on this fd */
 void set_fd_events( struct fd *fd, int events )
 {
-    int user = fd->poll_index;
-    assert( poll_users[user] == fd );
-
-    set_fd_epoll_events( fd, user, events );
+    set_fd_epoll_events( fd, events );
 
     if (events == -1)  /* stop waiting on this fd completely */
     {
-        pollfd[user].fd = -1;
-        pollfd[user].events = POLLERR;
-        pollfd[user].revents = 0;
-    }
-    else if (pollfd[user].fd != -1 || !pollfd[user].events)
-    {
-        pollfd[user].fd = fd->unix_fd;
-        pollfd[user].events = events;
+        poll_remove_fd(fd);
+        fd->pfd.events = POLLERR;
+        fd->pfd.revents = 0;
+        fd->pfd.fd = -1;
+    }
+    else if (fd->pfd.fd != -1 || !fd->pfd.events)
+    {
+        fd->pfd.events = events;
+        fd->pfd.fd = fd->unix_fd;
+        poll_add_fd(fd);
     }
 }
 
@@ -1044,10 +1068,13 @@
     fd->unix_fd    = -1;
     fd->fs_locks   = 1;
     fd->poll_index = -1;
+    fd->pfd.fd     = -1;
+    fd->pfd.events = 0;
+    fd->pfd.revents = 0;
     list_init( &fd->inode_entry );
     list_init( &fd->locks );
 
-    if ((fd->poll_index = add_poll_user( fd )) == -1)
+    if (add_poll_user( fd ) == -1)
     {
         release_object( fd );
         return NULL;
@@ -1228,9 +1255,10 @@
 }
 
 /* callback for event happening in the main poll() loop */
-void fd_poll_event( struct fd *fd, int event )
+void fd_poll_event( struct fd *fd )
 {
-    return fd->fd_ops->poll_event( fd, event );
+    if (!fd->pfd.revents) return;
+    return fd->fd_ops->poll_event( fd, fd->pfd.revents );
 }
 
 /* check if events are pending and if yes return which one(s) */


More information about the wine-patches mailing list