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