[Python-Dev] [Python-checkins] cpython (2.7): Issue #9090 : Error code 10035 calling socket.recv() on a socket with a timeout
Kristján Valur Jónsson
kristjan at ccpgames.com
Tue Mar 19 20:34:21 CET 2013
Yes, it is a symbol problem on unix. Working on it.
-----Original Message-----
From: Python-checkins [mailto:python-checkins-bounces+kristjan=ccpgames.com at python.org] On Behalf Of Senthil Kumaran
Sent: 19. mars 2013 12:28
To: sweskman at gmail.com
Cc: python-checkins at python.org
Subject: Re: [Python-checkins] cpython (2.7): Issue #9090 : Error code 10035 calling socket.recv() on a socket with a timeout
Looks like RHEL 2.7 buildbots are unhappy with this change.
--
Senthil
On Tue, Mar 19, 2013 at 11:08 AM, kristjan.jonsson <python-checkins at python.org> wrote:
> http://hg.python.org/cpython/rev/8ec39bfd1f01
> changeset: 82764:8ec39bfd1f01
> branch: 2.7
> parent: 82740:b10ec5083a53
> user: Kristján Valur Jónsson <sweskman at gmail.com>
> date: Tue Mar 19 10:58:59 2013 -0700
> summary:
> Issue #9090 : Error code 10035 calling socket.recv() on a socket
> with a timeout (WSAEWOULDBLOCK - A non-blocking socket operation
> could not be completed
> immediately)
>
> files:
> Misc/NEWS | 5 +
> Modules/socketmodule.c | 104 ++++++++++++++++++++++++----
> Modules/timemodule.c | 7 +
> 3 files changed, 101 insertions(+), 15 deletions(-)
>
>
> diff --git a/Misc/NEWS b/Misc/NEWS
> --- a/Misc/NEWS
> +++ b/Misc/NEWS
> @@ -214,6 +214,11 @@
> Library
> -------
>
> +- Issue #9090: When a socket with a timeout fails with EWOULDBLOCK or
> +EAGAIN,
> + retry the select() loop instead of bailing out. This is because
> +select()
> + can incorrectly report a socket as ready for reading (for example,
> +if it
> + received some data with an invalid checksum).
> +
> - Issue #1285086: Get rid of the refcounting hack and speed up urllib.unquote().
>
> - Issue #17368: Fix an off-by-one error in the Python JSON decoder
> that caused diff --git a/Modules/socketmodule.c
> b/Modules/socketmodule.c
> --- a/Modules/socketmodule.c
> +++ b/Modules/socketmodule.c
> @@ -473,6 +473,17 @@
> return NULL;
> }
>
> +#ifdef MS_WINDOWS
> +#ifndef WSAEAGAIN
> +#define WSAEAGAIN WSAEWOULDBLOCK
> +#endif
> +#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. */
>
> @@ -661,7 +672,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;
>
> @@ -673,6 +684,10 @@
> if (s->sock_fd < 0)
> return 0;
>
> + /* Handling this condition here simplifies the select loops */
> + if (interval < 0.0)
> + return 1;
> +
> /* Prefer poll, if available, since you can poll() any fd
> * which can't be done with select(). */ #ifdef HAVE_POLL @@
> -684,7 +699,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
> @@ -692,8 +707,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);
>
> @@ -712,6 +727,49 @@
> return 0;
> }
>
> +static int
> +internal_select(PySocketSockObject *s, int writing) {
> + return internal_select_ex(s, writing, s->sock_timeout); }
> +
> +/*
> + Two macros for automatic retry of select() in case of false positives
> + (for example, select() could indicate a socket is ready for reading
> + but the data then discarded by the OS because of a wrong checksum).
> + Here is an example of use:
> +
> + BEGIN_SELECT_LOOP(s)
> + Py_BEGIN_ALLOW_THREADS
> + timeout = internal_select_ex(s, 0, interval);
> + if (!timeout)
> + outlen = recv(s->sock_fd, cbuf, len, flags);
> + Py_END_ALLOW_THREADS
> + if (timeout == 1) {
> + PyErr_SetString(socket_timeout, "timed out");
> + return -1;
> + }
> + END_SELECT_LOOP(s)
> +*/
> +PyAPI_FUNC(double) _PyTime_floattime(void); /* defined in timemodule.c */
> +#define BEGIN_SELECT_LOOP(s) \
> + { \
> + double deadline, interval = s->sock_timeout; \
> + int has_timeout = s->sock_timeout > 0.0; \
> + if (has_timeout) { \
> + deadline = _PyTime_floattime() + s->sock_timeout; \
> + } \
> + while (1) { \
> + errno = 0; \
> +
> +#define END_SELECT_LOOP(s) \
> + if (!has_timeout || \
> + (!CHECK_ERRNO(EWOULDBLOCK) && !CHECK_ERRNO(EAGAIN))) \
> + break; \
> + interval = deadline - _PyTime_floattime(); \
> + } \
> + } \
> +
> /* Initialize a new socket object. */
>
> static double defaulttimeout = -1.0; /* Default timeout for new sockets */
> @@ -1656,8 +1714,9 @@
> if (!IS_SELECTABLE(s))
> return select_error();
>
> + BEGIN_SELECT_LOOP(s)
> Py_BEGIN_ALLOW_THREADS
> - timeout = internal_select(s, 0);
> + timeout = internal_select_ex(s, 0, interval);
> if (!timeout)
> newfd = accept(s->sock_fd, SAS2SA(&addrbuf), &addrlen);
> Py_END_ALLOW_THREADS
> @@ -1666,6 +1725,7 @@
> PyErr_SetString(socket_timeout, "timed out");
> return NULL;
> }
> + END_SELECT_LOOP(s)
>
> #ifdef MS_WINDOWS
> if (newfd == INVALID_SOCKET)
> @@ -2355,8 +2415,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
> @@ -2365,6 +2426,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 */
> @@ -2386,8 +2448,9 @@
> segment = remaining;
> }
>
> + BEGIN_SELECT_LOOP(s)
> Py_BEGIN_ALLOW_THREADS
> - timeout = internal_select(s, 0);
> + timeout = internal_select_ex(s, 0, interval);
> if (!timeout)
> nread = recv(s->sock_fd, read_buf, segment, flags);
> Py_END_ALLOW_THREADS
> @@ -2396,6 +2459,8 @@
> PyErr_SetString(socket_timeout, "timed out");
> return -1;
> }
> + END_SELECT_LOOP(s)
> +
> if (nread < 0) {
> s->errorhandler();
> return -1;
> @@ -2559,9 +2624,10 @@
> return -1;
> }
>
> + BEGIN_SELECT_LOOP(s)
> Py_BEGIN_ALLOW_THREADS
> memset(&addrbuf, 0, addrlen);
> - timeout = internal_select(s, 0);
> + timeout = internal_select_ex(s, 0, interval);
> if (!timeout) {
> #ifndef MS_WINDOWS
> #if defined(PYOS_OS2) && !defined(PYCC_GCC)
> @@ -2582,6 +2648,7 @@
> PyErr_SetString(socket_timeout, "timed out");
> return -1;
> }
> + END_SELECT_LOOP(s)
> if (n < 0) {
> s->errorhandler();
> return -1;
> @@ -2719,8 +2786,9 @@
> buf = pbuf.buf;
> len = pbuf.len;
>
> + BEGIN_SELECT_LOOP(s)
> Py_BEGIN_ALLOW_THREADS
> - timeout = internal_select(s, 1);
> + timeout = internal_select_ex(s, 1, interval);
> if (!timeout)
> #ifdef __VMS
> n = sendsegmented(s->sock_fd, buf, len, flags);
> @@ -2728,13 +2796,14 @@
> n = send(s->sock_fd, buf, len, flags);
> #endif
> Py_END_ALLOW_THREADS
> -
> - PyBuffer_Release(&pbuf);
> -
> if (timeout == 1) {
> + PyBuffer_Release(&pbuf);
> PyErr_SetString(socket_timeout, "timed out");
> return NULL;
> }
> + END_SELECT_LOOP(s)
> +
> + PyBuffer_Release(&pbuf);
> if (n < 0)
> return s->errorhandler();
> return PyInt_FromLong((long)n);
> @@ -2768,8 +2837,9 @@
> }
>
> do {
> + BEGIN_SELECT_LOOP(s)
> Py_BEGIN_ALLOW_THREADS
> - timeout = internal_select(s, 1);
> + timeout = internal_select_ex(s, 1, interval);
> n = -1;
> if (!timeout) {
> #ifdef __VMS
> @@ -2784,6 +2854,7 @@
> PyErr_SetString(socket_timeout, "timed out");
> return NULL;
> }
> + END_SELECT_LOOP(s)
> /* PyErr_CheckSignals() might change errno */
> saved_errno = errno;
> /* We must run our signal handlers before looping again.
> @@ -2863,17 +2934,20 @@
> return NULL;
> }
>
> + BEGIN_SELECT_LOOP(s)
> Py_BEGIN_ALLOW_THREADS
> - timeout = internal_select(s, 1);
> + timeout = internal_select_ex(s, 1, interval);
> if (!timeout)
> n = sendto(s->sock_fd, buf, len, flags, SAS2SA(&addrbuf), addrlen);
> Py_END_ALLOW_THREADS
>
> - PyBuffer_Release(&pbuf);
> if (timeout == 1) {
> + PyBuffer_Release(&pbuf);
> PyErr_SetString(socket_timeout, "timed out");
> return NULL;
> }
> + END_SELECT_LOOP(s)
> + PyBuffer_Release(&pbuf);
> if (n < 0)
> return s->errorhandler();
> return PyInt_FromLong((long)n);
> diff --git a/Modules/timemodule.c b/Modules/timemodule.c
> --- a/Modules/timemodule.c
> +++ b/Modules/timemodule.c
> @@ -1055,3 +1055,10 @@
>
> return 0;
> }
> +
> +/* export floattime to socketmodule.c */
> +PyAPI_FUNC(double)
> +_PyTime_floattime(void)
> +{
> + return floattime();
> +}
>
> --
> Repository URL: http://hg.python.org/cpython
>
> _______________________________________________
> Python-checkins mailing list
> Python-checkins at python.org
> http://mail.python.org/mailman/listinfo/python-checkins
>
_______________________________________________
Python-checkins mailing list
Python-checkins at python.org
http://mail.python.org/mailman/listinfo/python-checkins
More information about the Python-Dev
mailing list