Alexandre Julliard : ws2_32: Convert WS_select to use poll()
instead of select(). Also fixes an fd leak.
Alexandre Julliard
julliard at wine.codeweavers.com
Mon Nov 6 05:48:44 CST 2006
Module: wine
Branch: master
Commit: 0082973d938cffe541b24ce11218698a940de9dd
URL: http://source.winehq.org/git/wine.git/?a=commit;h=0082973d938cffe541b24ce11218698a940de9dd
Author: Alexandre Julliard <julliard at winehq.org>
Date: Mon Nov 6 12:28:53 2006 +0100
ws2_32: Convert WS_select to use poll() instead of select(). Also fixes an fd leak.
---
dlls/ws2_32/socket.c | 216 +++++++++++++++++++++++++-------------------------
1 files changed, 109 insertions(+), 107 deletions(-)
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c
index b773092..5166d93 100644
--- a/dlls/ws2_32/socket.c
+++ b/dlls/ws2_32/socket.c
@@ -589,31 +589,6 @@ static char *strdup_lower(const char *st
return ret;
}
-static fd_set* fd_set_import( fd_set* fds, const WS_fd_set* wsfds, int access, int* highfd, int lfd[] )
-{
- /* translate Winsock fd set into local fd set */
- if( wsfds )
- {
- unsigned int i;
-
- FD_ZERO(fds);
- for( i = 0; i < wsfds->fd_count; i++ )
- {
- int s = wsfds->fd_array[i];
- int fd = get_sock_fd( s, access, NULL );
- if (fd != -1)
- {
- lfd[ i ] = fd;
- if( fd > *highfd ) *highfd = fd;
- FD_SET(fd, fds);
- }
- else lfd[ i ] = -1;
- }
- return fds;
- }
- return NULL;
-}
-
inline static int sock_error_p(int s)
{
unsigned int optval, optlen;
@@ -624,50 +599,6 @@ inline static int sock_error_p(int s)
return optval != 0;
}
-static int fd_set_export( const fd_set* fds, fd_set* exceptfds, WS_fd_set* wsfds, int lfd[] )
-{
- int num_err = 0;
-
- /* translate local fd set into Winsock fd set, adding
- * errors to exceptfds (only if app requested it) */
-
- if( wsfds )
- {
- int i, j, count = wsfds->fd_count;
-
- for( i = 0, j = 0; i < count; i++ )
- {
- int fd = lfd[i];
- SOCKET s = wsfds->fd_array[i];
- if (fd == -1) continue;
- if( FD_ISSET(fd, fds) )
- {
- if ( exceptfds && sock_error_p(fd) )
- {
- FD_SET(fd, exceptfds);
- num_err++;
- }
- else wsfds->fd_array[j++] = s;
- }
- release_sock_fd( s, fd );
- }
- wsfds->fd_count = j;
- }
- return num_err;
-}
-
-static void fd_set_unimport( WS_fd_set* wsfds, int lfd[] )
-{
- if ( wsfds )
- {
- unsigned int i;
-
- for ( i = 0; i < wsfds->fd_count; i++ )
- if ( lfd[i] >= 0 ) release_sock_fd( wsfds->fd_array[i], lfd[i] );
- wsfds->fd_count = 0;
- }
-}
-
/* Utility: get the SO_RCVTIMEO or SO_SNDTIMEO socket option
* from an fd and return the value converted to milli seconds
* or -1 if there is an infinite time out */
@@ -2437,6 +2368,103 @@ int WINAPI WS_recvfrom(SOCKET s, char *b
return n;
}
+/* allocate a poll array for the corresponding fd sets */
+static struct pollfd *fd_sets_to_poll( const WS_fd_set *readfds, const WS_fd_set *writefds,
+ const WS_fd_set *exceptfds, int *count_ptr )
+{
+ int i, j = 0, count = 0;
+ struct pollfd *fds;
+
+ if (readfds) count += readfds->fd_count;
+ if (writefds) count += writefds->fd_count;
+ if (exceptfds) count += exceptfds->fd_count;
+ *count_ptr = count;
+ if (!count) return NULL;
+ if (!(fds = HeapAlloc( GetProcessHeap(), 0, count * sizeof(fds[0])))) return NULL;
+ if (readfds)
+ for (i = 0; i < readfds->fd_count; i++, j++)
+ {
+ fds[j].fd = get_sock_fd( readfds->fd_array[i], FILE_READ_DATA, NULL );
+ fds[j].events = POLLIN;
+ fds[j].revents = 0;
+ }
+ if (writefds)
+ for (i = 0; i < writefds->fd_count; i++, j++)
+ {
+ fds[j].fd = get_sock_fd( writefds->fd_array[i], FILE_WRITE_DATA, NULL );
+ fds[j].events = POLLOUT;
+ fds[j].revents = 0;
+ }
+ if (exceptfds)
+ for (i = 0; i < exceptfds->fd_count; i++, j++)
+ {
+ fds[j].fd = get_sock_fd( exceptfds->fd_array[i], 0, NULL );
+ fds[j].events = POLLHUP;
+ fds[j].revents = 0;
+ }
+ return fds;
+}
+
+/* release the file descriptor obtained in fd_sets_to_poll */
+/* must be called with the original fd_set arrays, before calling get_poll_results */
+static void release_poll_fds( const WS_fd_set *readfds, const WS_fd_set *writefds,
+ const WS_fd_set *exceptfds, struct pollfd *fds )
+{
+ int i, j = 0;
+
+ if (readfds)
+ {
+ for (i = 0; i < readfds->fd_count; i++, j++)
+ if (fds[j].fd != -1) release_sock_fd( readfds->fd_array[i], fds[j].fd );
+ }
+ if (writefds)
+ {
+ for (i = 0; i < writefds->fd_count; i++, j++)
+ if (fds[j].fd != -1) release_sock_fd( writefds->fd_array[i], fds[j].fd );
+ }
+ if (exceptfds)
+ {
+ for (i = 0; i < exceptfds->fd_count; i++, j++)
+ if (fds[j].fd != -1)
+ {
+ /* make sure we have a real error before releasing the fd */
+ if (!sock_error_p( fds[j].fd )) fds[j].revents = 0;
+ release_sock_fd( exceptfds->fd_array[i], fds[j].fd );
+ }
+ }
+}
+
+/* map the poll results back into the Windows fd sets */
+static int get_poll_results( WS_fd_set *readfds, WS_fd_set *writefds, WS_fd_set *exceptfds,
+ const struct pollfd *fds )
+{
+ int i, j = 0, k, total = 0;
+
+ if (readfds)
+ {
+ for (i = k = 0; i < readfds->fd_count; i++, j++)
+ if (fds[j].revents) readfds->fd_array[k++] = readfds->fd_array[i];
+ readfds->fd_count = k;
+ total += k;
+ }
+ if (writefds)
+ {
+ for (i = k = 0; i < writefds->fd_count; i++, j++)
+ if (fds[j].revents) writefds->fd_array[k++] = writefds->fd_array[i];
+ writefds->fd_count = k;
+ total += k;
+ }
+ if (exceptfds)
+ {
+ for (i = k = 0; i < exceptfds->fd_count; i++, j++)
+ if (fds[j].revents) exceptfds->fd_array[k++] = exceptfds->fd_array[i];
+ exceptfds->fd_count = k;
+ total += k;
+ }
+ return total;
+}
+
+
/***********************************************************************
* select (WS2_32.18)
*/
@@ -2444,53 +2472,27 @@ int WINAPI WS_select(int nfds, WS_fd_set
WS_fd_set *ws_writefds, WS_fd_set *ws_exceptfds,
const struct WS_timeval* ws_timeout)
{
- int highfd = 0;
- fd_set readfds, writefds, exceptfds;
- fd_set *p_read, *p_write, *p_except;
- int readfd[FD_SETSIZE], writefd[FD_SETSIZE], exceptfd[FD_SETSIZE];
- struct timeval timeout, *timeoutaddr = NULL;
+ struct pollfd *pollfds;
+ int count, ret, timeout = -1;
TRACE("read %p, write %p, excp %p timeout %p\n",
ws_readfds, ws_writefds, ws_exceptfds, ws_timeout);
- p_read = fd_set_import(&readfds, ws_readfds, FILE_READ_DATA, &highfd, readfd);
- p_write = fd_set_import(&writefds, ws_writefds, FILE_WRITE_DATA, &highfd, writefd);
- p_except = fd_set_import(&exceptfds, ws_exceptfds, 0, &highfd, exceptfd);
- if (ws_timeout)
+ if (!(pollfds = fd_sets_to_poll( ws_readfds, ws_writefds, ws_exceptfds, &count )) && count)
{
- timeoutaddr = &timeout;
- timeout.tv_sec=ws_timeout->tv_sec;
- timeout.tv_usec=ws_timeout->tv_usec;
+ SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+ return -1;
}
- if( (highfd = select(highfd + 1, p_read, p_write, p_except, timeoutaddr)) > 0 )
- {
- fd_set_export(&readfds, p_except, ws_readfds, readfd);
- fd_set_export(&writefds, p_except, ws_writefds, writefd);
+ if (ws_timeout) timeout = (ws_timeout->tv_sec * 1000) + (ws_timeout->tv_usec + 999) / 1000;
- if (p_except && ws_exceptfds)
- {
- unsigned int i, j;
+ ret = poll( pollfds, count, timeout );
+ release_poll_fds( ws_readfds, ws_writefds, ws_exceptfds, pollfds );
- for (i = j = 0; i < ws_exceptfds->fd_count; i++)
- {
- int fd = exceptfd[i];
- SOCKET s = ws_exceptfds->fd_array[i];
- if (fd == -1) continue;
- if (FD_ISSET(fd, &exceptfds)) ws_exceptfds->fd_array[j++] = s;
- release_sock_fd( s, fd );
- }
- ws_exceptfds->fd_count = j;
- }
- return highfd;
- }
- fd_set_unimport(ws_readfds, readfd);
- fd_set_unimport(ws_writefds, writefd);
- fd_set_unimport(ws_exceptfds, exceptfd);
-
- if( highfd == 0 ) return 0;
- SetLastError(wsaErrno());
- return SOCKET_ERROR;
+ if (ret == -1) SetLastError(wsaErrno());
+ else ret = get_poll_results( ws_readfds, ws_writefds, ws_exceptfds, pollfds );
+ HeapFree( GetProcessHeap(), 0, pollfds );
+ return ret;
}
More information about the wine-cvs
mailing list