[Python-checkins] cpython: Issue #23618, #22117: refactor socketmodule.c

victor.stinner python-checkins at python.org
Sat Mar 28 01:29:16 CET 2015


https://hg.python.org/cpython/rev/f841d3bc30ee
changeset:   95231:f841d3bc30ee
user:        Victor Stinner <victor.stinner at gmail.com>
date:        Fri Mar 27 22:59:32 2015 +0100
summary:
  Issue #23618, #22117: refactor socketmodule.c

Move Py_BEGIN_ALLOW_THREADS/Py_END_ALLOW_THREADS inside internal_select_ex() to
prepare a switch to the _PyTime_t type and retry syscall on EINTR.

files:
  Modules/socketmodule.c |  196 ++++++++++++++++------------
  1 files changed, 113 insertions(+), 83 deletions(-)


diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c
--- a/Modules/socketmodule.c
+++ b/Modules/socketmodule.c
@@ -601,6 +601,11 @@
 {
     int n;
 
+#ifdef WITH_THREAD
+    /* must be called with the GIL held */
+    assert(PyGILState_Check());
+#endif
+
     /* Nothing to do unless we're in timeout mode (not non-blocking) */
     if (s->sock_timeout <= 0.0)
         return 0;
@@ -625,7 +630,10 @@
 
         /* s->sock_timeout is in seconds, timeout in ms */
         timeout = (int)(interval * 1000 + 0.5);
+
+        Py_BEGIN_ALLOW_THREADS;
         n = poll(&pollfd, 1, timeout);
+        Py_END_ALLOW_THREADS;
     }
 #else
     {
@@ -638,12 +646,14 @@
         FD_SET(s->sock_fd, &fds);
 
         /* See if the socket is ready */
+        Py_BEGIN_ALLOW_THREADS;
         if (writing)
             n = select(Py_SAFE_DOWNCAST(s->sock_fd+1, SOCKET_T, int),
                        NULL, &fds, NULL, &tv);
         else
             n = select(Py_SAFE_DOWNCAST(s->sock_fd+1, SOCKET_T, int),
                        &fds, NULL, NULL, &tv);
+        Py_END_ALLOW_THREADS;
     }
 #endif
 
@@ -667,11 +677,14 @@
    Here is an example of use:
 
     BEGIN_SELECT_LOOP(s)
-    Py_BEGIN_ALLOW_THREADS
+
     timeout = internal_select_ex(s, 0, interval);
-    if (!timeout)
+
+    if (!timeout) {
+        Py_BEGIN_ALLOW_THREADS
         outlen = recv(s->sock_fd, cbuf, len, flags);
-    Py_END_ALLOW_THREADS
+        Py_END_ALLOW_THREADS
+    }
     if (timeout == 1) {
         PyErr_SetString(socket_timeout, "timed out");
         return -1;
@@ -2066,9 +2079,10 @@
 
     BEGIN_SELECT_LOOP(s)
     do {
-        Py_BEGIN_ALLOW_THREADS
         timeout = internal_select_ex(s, 0, interval);
+
         if (!timeout) {
+            Py_BEGIN_ALLOW_THREADS
 #if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC)
             if (accept4_works != 0) {
                 newfd = accept4(s->sock_fd, SAS2SA(&addrbuf), &addrlen,
@@ -2083,8 +2097,8 @@
 #else
             newfd = accept(s->sock_fd, SAS2SA(&addrbuf), &addrlen);
 #endif
+            Py_END_ALLOW_THREADS
         }
-        Py_END_ALLOW_THREADS
     } while (newfd < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
     if (timeout == 1) {
         PyErr_SetString(socket_timeout, "timed out");
@@ -2395,51 +2409,59 @@
 {
     int res, timeout;
 
+
     timeout = 0;
+
+    Py_BEGIN_ALLOW_THREADS
     res = connect(s->sock_fd, addr, addrlen);
+    Py_END_ALLOW_THREADS
+
 
 #ifdef MS_WINDOWS
 
-    if (s->sock_timeout > 0.0) {
-        if (res < 0 && WSAGetLastError() == WSAEWOULDBLOCK &&
-            IS_SELECTABLE(s)) {
-            /* This is a mess.  Best solution: trust select */
-            fd_set fds;
-            fd_set fds_exc;
-            struct timeval tv;
-            tv.tv_sec = (int)s->sock_timeout;
-            tv.tv_usec = (int)((s->sock_timeout - tv.tv_sec) * 1e6);
-            FD_ZERO(&fds);
-            FD_SET(s->sock_fd, &fds);
-            FD_ZERO(&fds_exc);
-            FD_SET(s->sock_fd, &fds_exc);
-            res = select(Py_SAFE_DOWNCAST(s->sock_fd+1, SOCKET_T, int),
-                         NULL, &fds, &fds_exc, &tv);
-            if (res == 0) {
-                res = WSAEWOULDBLOCK;
-                timeout = 1;
-            } else if (res > 0) {
-                if (FD_ISSET(s->sock_fd, &fds))
-                    /* The socket is in the writable set - this
-                       means connected */
-                    res = 0;
-                else {
-                    /* As per MS docs, we need to call getsockopt()
-                       to get the underlying error */
-                    int res_size = sizeof res;
-                    /* It must be in the exception set */
-                    assert(FD_ISSET(s->sock_fd, &fds_exc));
-                    if (0 == getsockopt(s->sock_fd, SOL_SOCKET, SO_ERROR,
-                                        (char *)&res, &res_size))
-                        /* getsockopt also clears WSAGetLastError,
-                           so reset it back. */
-                        WSASetLastError(res);
-                    else
-                        res = WSAGetLastError();
-                }
+    if (s->sock_timeout > 0.0
+        && res < 0 && WSAGetLastError() == WSAEWOULDBLOCK
+        && IS_SELECTABLE(s)) {
+        /* This is a mess.  Best solution: trust select */
+        fd_set fds;
+        fd_set fds_exc;
+        struct timeval tv;
+
+        Py_BEGIN_ALLOW_THREADS
+        tv.tv_sec = (int)s->sock_timeout;
+        tv.tv_usec = (int)((s->sock_timeout - tv.tv_sec) * 1e6);
+        FD_ZERO(&fds);
+        FD_SET(s->sock_fd, &fds);
+        FD_ZERO(&fds_exc);
+        FD_SET(s->sock_fd, &fds_exc);
+        res = select(Py_SAFE_DOWNCAST(s->sock_fd+1, SOCKET_T, int),
+                     NULL, &fds, &fds_exc, &tv);
+        Py_END_ALLOW_THREADS
+
+        if (res == 0) {
+            res = WSAEWOULDBLOCK;
+            timeout = 1;
+        } else if (res > 0) {
+            if (FD_ISSET(s->sock_fd, &fds))
+                /* The socket is in the writable set - this
+                   means connected */
+                res = 0;
+            else {
+                /* As per MS docs, we need to call getsockopt()
+                   to get the underlying error */
+                int res_size = sizeof res;
+                /* It must be in the exception set */
+                assert(FD_ISSET(s->sock_fd, &fds_exc));
+                if (0 == getsockopt(s->sock_fd, SOL_SOCKET, SO_ERROR,
+                                    (char *)&res, &res_size))
+                    /* getsockopt also clears WSAGetLastError,
+                       so reset it back. */
+                    WSASetLastError(res);
+                else
+                    res = WSAGetLastError();
             }
-            /* else if (res < 0) an error occurred */
         }
+        /* else if (res < 0) an error occurred */
     }
 
     if (res < 0)
@@ -2447,26 +2469,27 @@
 
 #else
 
-    if (s->sock_timeout > 0.0) {
-        if (res < 0 && errno == EINPROGRESS && IS_SELECTABLE(s)) {
-            timeout = internal_select(s, 1);
-            if (timeout == 0) {
-                /* Bug #1019808: in case of an EINPROGRESS,
-                   use getsockopt(SO_ERROR) to get the real
-                   error. */
-                socklen_t res_size = sizeof res;
-                (void)getsockopt(s->sock_fd, SOL_SOCKET,
-                                 SO_ERROR, &res, &res_size);
-                if (res == EISCONN)
-                    res = 0;
-                errno = res;
-            }
-            else if (timeout == -1) {
-                res = errno;            /* had error */
-            }
-            else
-                res = EWOULDBLOCK;                      /* timed out */
+    if (s->sock_timeout > 0.0
+        && res < 0 && errno == EINPROGRESS && IS_SELECTABLE(s)) {
+
+        timeout = internal_select(s, 1);
+
+        if (timeout == 0) {
+            /* Bug #1019808: in case of an EINPROGRESS,
+               use getsockopt(SO_ERROR) to get the real
+               error. */
+            socklen_t res_size = sizeof res;
+            (void)getsockopt(s->sock_fd, SOL_SOCKET,
+                             SO_ERROR, &res, &res_size);
+            if (res == EISCONN)
+                res = 0;
+            errno = res;
         }
+        else if (timeout == -1) {
+            res = errno;            /* had error */
+        }
+        else
+            res = EWOULDBLOCK;                      /* timed out */
     }
 
     if (res < 0)
@@ -2491,9 +2514,7 @@
     if (!getsockaddrarg(s, addro, SAS2SA(&addrbuf), &addrlen))
         return NULL;
 
-    Py_BEGIN_ALLOW_THREADS
     res = internal_connect(s, SAS2SA(&addrbuf), addrlen, &timeout);
-    Py_END_ALLOW_THREADS
 
     if (timeout == 1) {
         PyErr_SetString(socket_timeout, "timed out");
@@ -2525,9 +2546,7 @@
     if (!getsockaddrarg(s, addro, SAS2SA(&addrbuf), &addrlen))
         return NULL;
 
-    Py_BEGIN_ALLOW_THREADS
     res = internal_connect(s, SAS2SA(&addrbuf), addrlen, &timeout);
-    Py_END_ALLOW_THREADS
 
     /* Signals are not errors (though they may raise exceptions).  Adapted
        from PyErr_SetFromErrnoWithFilenameObject(). */
@@ -2679,9 +2698,10 @@
 
     BEGIN_SELECT_LOOP(s)
     do {
-        Py_BEGIN_ALLOW_THREADS
         timeout = internal_select_ex(s, 0, interval);
+
         if (!timeout) {
+            Py_BEGIN_ALLOW_THREADS
 #ifdef MS_WINDOWS
             if (len > INT_MAX)
                 len = INT_MAX;
@@ -2689,8 +2709,8 @@
 #else
             outlen = recv(s->sock_fd, cbuf, len, flags);
 #endif
+            Py_END_ALLOW_THREADS
         }
-        Py_END_ALLOW_THREADS
     } while (outlen < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
 
     if (timeout == 1) {
@@ -2853,10 +2873,11 @@
 
     BEGIN_SELECT_LOOP(s)
     do {
-        Py_BEGIN_ALLOW_THREADS
         memset(&addrbuf, 0, addrlen);
         timeout = internal_select_ex(s, 0, interval);
+
         if (!timeout) {
+            Py_BEGIN_ALLOW_THREADS
 #ifdef MS_WINDOWS
             if (len > INT_MAX)
                 len = INT_MAX;
@@ -2866,8 +2887,8 @@
             n = recvfrom(s->sock_fd, cbuf, len, flags,
                          SAS2SA(&addrbuf), &addrlen);
 #endif
+            Py_END_ALLOW_THREADS
         }
-        Py_END_ALLOW_THREADS
     } while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
 
     if (timeout == 1) {
@@ -3054,7 +3075,6 @@
 
     BEGIN_SELECT_LOOP(s)
     do {
-        Py_BEGIN_ALLOW_THREADS;
         msg.msg_name = SAS2SA(&addrbuf);
         msg.msg_namelen = addrbuflen;
         msg.msg_iov = iov;
@@ -3062,13 +3082,17 @@
         msg.msg_control = controlbuf;
         msg.msg_controllen = controllen;
         timeout = internal_select_ex(s, 0, interval);
-        if (!timeout)
-            bytes_received = recvmsg(s->sock_fd, &msg, flags);
-        Py_END_ALLOW_THREADS;
+
         if (timeout == 1) {
             PyErr_SetString(socket_timeout, "timed out");
             goto finally;
         }
+
+        if (!timeout) {
+            Py_BEGIN_ALLOW_THREADS;
+            bytes_received = recvmsg(s->sock_fd, &msg, flags);
+            Py_END_ALLOW_THREADS;
+        }
     } while (bytes_received < 0 && errno == EINTR &&
              !(async_err = PyErr_CheckSignals()));
     END_SELECT_LOOP(s)
@@ -3350,9 +3374,10 @@
 
     BEGIN_SELECT_LOOP(s)
     do {
-        Py_BEGIN_ALLOW_THREADS
         timeout = internal_select_ex(s, 1, interval);
+
         if (!timeout) {
+            Py_BEGIN_ALLOW_THREADS
 #ifdef MS_WINDOWS
             if (len > INT_MAX)
                 len = INT_MAX;
@@ -3360,8 +3385,8 @@
 #else
             n = send(s->sock_fd, buf, len, flags);
 #endif
+            Py_END_ALLOW_THREADS
         }
-        Py_END_ALLOW_THREADS
     } while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
     if (timeout == 1) {
         PyBuffer_Release(&pbuf);
@@ -3406,10 +3431,11 @@
     }
 
     do {
-        Py_BEGIN_ALLOW_THREADS
         timeout = internal_select(s, 1);
+
         n = -1;
         if (!timeout) {
+            Py_BEGIN_ALLOW_THREADS
 #ifdef MS_WINDOWS
             if (len > INT_MAX)
                 len = INT_MAX;
@@ -3417,8 +3443,8 @@
 #else
             n = send(s->sock_fd, buf, len, flags);
 #endif
+            Py_END_ALLOW_THREADS
         }
-        Py_END_ALLOW_THREADS
         if (timeout == 1) {
             PyBuffer_Release(&pbuf);
             PyErr_SetString(socket_timeout, "timed out");
@@ -3495,9 +3521,10 @@
 
     BEGIN_SELECT_LOOP(s)
     do {
-        Py_BEGIN_ALLOW_THREADS
         timeout = internal_select_ex(s, 1, interval);
+
         if (!timeout) {
+            Py_BEGIN_ALLOW_THREADS
 #ifdef MS_WINDOWS
             if (len > INT_MAX)
                 len = INT_MAX;
@@ -3507,8 +3534,8 @@
             n = sendto(s->sock_fd, buf, len, flags,
                        SAS2SA(&addrbuf), addrlen);
 #endif
+            Py_END_ALLOW_THREADS
         }
-        Py_END_ALLOW_THREADS
     } while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
 
     if (timeout == 1) {
@@ -3710,11 +3737,14 @@
 
     BEGIN_SELECT_LOOP(s)
     do {
-        Py_BEGIN_ALLOW_THREADS;
         timeout = internal_select_ex(s, 1, interval);
-        if (!timeout)
+
+        if (!timeout) {
+            Py_BEGIN_ALLOW_THREADS;
             bytes_sent = sendmsg(s->sock_fd, &msg, flags);
-        Py_END_ALLOW_THREADS;
+            Py_END_ALLOW_THREADS;
+        }
+
         if (timeout == 1) {
             PyErr_SetString(socket_timeout, "timed out");
             goto finally;

-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list