[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