Index: Include/pytime.h =================================================================== --- Include/pytime.h (révision 84880) +++ Include/pytime.h (copie de travail) @@ -25,6 +25,17 @@ */ PyAPI_FUNC(void) _PyTime_gettimeofday(_PyTime_timeval *tp); +#define _PyTime_ADD_SECONDS(tv, interval) \ +do { \ + tv.tv_usec += (long) (((long) interval - interval) * 1000000); \ + tv.tv_sec += (time_t) interval + (time_t) (tv.tv_usec / 1000000); \ + tv.tv_usec %= 1000000; \ +} while (0) + +#define _PyTime_INTERVAL(tv_start, tv_end) \ + ((tv_end.tv_sec - tv_start.tv_sec) + \ + (tv_end.tv_usec - tv_start.tv_usec) * 0.000001) + /* Dummy to force linking. */ PyAPI_FUNC(void) _PyTime_Init(void); Index: Modules/socketmodule.c =================================================================== --- Modules/socketmodule.c (révision 84880) +++ Modules/socketmodule.c (copie de travail) @@ -474,6 +474,14 @@ return NULL; } +#ifdef MS_WINDOWS +#define CHECK_ERRNO(expected) \ + (WSAGetLastError() == WSA ## expected) +#else +#define CHECK_ERRNO(expected) \ + (errno == expected) +#endif + /* Convenience function to raise an error according to errno and return a NULL pointer from a function. */ @@ -637,7 +645,7 @@ after they've reacquired the interpreter lock. Returns 1 on timeout, -1 on error, 0 otherwise. */ static int -internal_select(PySocketSockObject *s, int writing) +internal_select_ex(PySocketSockObject *s, int writing, double interval) { int n; @@ -660,7 +668,7 @@ pollfd.events = writing ? POLLOUT : POLLIN; /* s->sock_timeout is in seconds, timeout in ms */ - timeout = (int)(s->sock_timeout * 1000 + 0.5); + timeout = (int)(interval * 1000 + 0.5); n = poll(&pollfd, 1, timeout); } #else @@ -668,8 +676,8 @@ /* Construct the arguments to select */ fd_set fds; struct timeval tv; - tv.tv_sec = (int)s->sock_timeout; - tv.tv_usec = (int)((s->sock_timeout - tv.tv_sec) * 1e6); + tv.tv_sec = (int)interval; + tv.tv_usec = (int)((interval - tv.tv_sec) * 1e6); FD_ZERO(&fds); FD_SET(s->sock_fd, &fds); @@ -690,6 +698,12 @@ return 0; } +static int +internal_select(PySocketSockObject *s, int writing) +{ + return internal_select_ex(s, writing, s->sock_timeout); +} + /* Initialize a new socket object. */ static double defaulttimeout = -1.0; /* Default timeout for new sockets */ @@ -2151,6 +2165,28 @@ * also possible that we return a number of bytes smaller than the request * bytes. */ + +#define BEGIN_SELECT_LOOP(s) \ + { \ + _PyTime_timeval now, deadline = {0, 0}; \ + double interval = s->sock_timeout; \ + int has_timeout = s->sock_timeout > 0.0; \ + if (has_timeout) { \ + _PyTime_gettimeofday(&now); \ + deadline = now; \ + _PyTime_ADD_SECONDS(deadline, s->sock_timeout); \ + } \ + while (!has_timeout || interval >= 0.0) { \ + errno = 0; \ + +#define END_SELECT_LOOP(s) \ + if (!has_timeout || !CHECK_ERRNO(EWOULDBLOCK)) \ + break; \ + _PyTime_gettimeofday(&now); \ + interval = _PyTime_INTERVAL(now, deadline); \ + } \ + } \ + static Py_ssize_t sock_recv_guts(PySocketSockObject *s, char* cbuf, Py_ssize_t len, int flags) { @@ -2171,8 +2207,9 @@ } #ifndef __VMS + BEGIN_SELECT_LOOP(s) Py_BEGIN_ALLOW_THREADS - timeout = internal_select(s, 0); + timeout = internal_select_ex(s, 0, interval); if (!timeout) outlen = recv(s->sock_fd, cbuf, len, flags); Py_END_ALLOW_THREADS @@ -2181,6 +2218,7 @@ PyErr_SetString(socket_timeout, "timed out"); return -1; } + END_SELECT_LOOP(s) if (outlen < 0) { /* Note: the call to errorhandler() ALWAYS indirectly returned NULL, so ignore its return value */