[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

AltStyle によって変換されたページ (->オリジナル) /