cpython: f841d3bc30ee (original) (raw)
--- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -601,6 +601,11 @@ internal_select_ex(PySocketSockObject *s { int n; +#ifdef WITH_THREAD
+#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 @@ internal_select_ex(PySocketSockObject *s /* s->sock_timeout is in seconds, timeout in ms */ timeout = (int)(interval * 1000 + 0.5); +
Py_BEGIN_ALLOW_THREADS;[](#l1.20) n = poll(&pollfd, 1, timeout);[](#l1.21)
}Py_END_ALLOW_THREADS;[](#l1.22)
#else { @@ -638,12 +646,14 @@ internal_select_ex(PySocketSockObject s FD_SET(s->sock_fd, &fds); / See if the socket is ready */
Py_BEGIN_ALLOW_THREADS;[](#l1.30) if (writing)[](#l1.31) n = select(Py_SAFE_DOWNCAST(s->sock_fd+1, SOCKET_T, int),[](#l1.32) NULL, &fds, NULL, &tv);[](#l1.33) else[](#l1.34) n = select(Py_SAFE_DOWNCAST(s->sock_fd+1, SOCKET_T, int),[](#l1.35) &fds, NULL, NULL, &tv);[](#l1.36)
}Py_END_ALLOW_THREADS;[](#l1.37)
#endif @@ -667,11 +677,14 @@ internal_select(PySocketSockObject *s, i Here is an example of use: BEGIN_SELECT_LOOP(s)
+ timeout = internal_select_ex(s, 0, interval);
- if (!timeout) {
Py_BEGIN_ALLOW_THREADS[](#l1.51) outlen = recv(s->sock_fd, cbuf, len, flags);[](#l1.52)
Py_END_ALLOW_THREADS[](#l1.54)
- } if (timeout == 1) { PyErr_SetString(socket_timeout, "timed out"); return -1;
@@ -2066,9 +2079,10 @@ sock_accept(PySocketSockObject *s) BEGIN_SELECT_LOOP(s) do {
Py_BEGIN_ALLOW_THREADS[](#l1.63) timeout = internal_select_ex(s, 0, interval);[](#l1.64)
Py_BEGIN_ALLOW_THREADS[](#l1.67)
#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) if (accept4_works != 0) { newfd = accept4(s->sock_fd, SAS2SA(&addrbuf), &addrlen, @@ -2083,8 +2097,8 @@ sock_accept(PySocketSockObject *s) #else newfd = accept(s->sock_fd, SAS2SA(&addrbuf), &addrlen); #endif
Py_END_ALLOW_THREADS[](#l1.75) }[](#l1.76)
} while (newfd < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); if (timeout == 1) { PyErr_SetString(socket_timeout, "timed out");Py_END_ALLOW_THREADS[](#l1.77)
@@ -2395,51 +2409,59 @@ internal_connect(PySocketSockObject *s, { int res, timeout; + timeout = 0; +
- if (s->sock_timeout > 0.0) {
if (res < 0 && WSAGetLastError() == WSAEWOULDBLOCK &&[](#l1.96)
IS_SELECTABLE(s)) {[](#l1.97)
/* This is a mess. Best solution: trust select */[](#l1.98)
fd_set fds;[](#l1.99)
fd_set fds_exc;[](#l1.100)
struct timeval tv;[](#l1.101)
tv.tv_sec = (int)s->sock_timeout;[](#l1.102)
tv.tv_usec = (int)((s->sock_timeout - tv.tv_sec) * 1e6);[](#l1.103)
FD_ZERO(&fds);[](#l1.104)
FD_SET(s->sock_fd, &fds);[](#l1.105)
FD_ZERO(&fds_exc);[](#l1.106)
FD_SET(s->sock_fd, &fds_exc);[](#l1.107)
res = select(Py_SAFE_DOWNCAST(s->sock_fd+1, SOCKET_T, int),[](#l1.108)
NULL, &fds, &fds_exc, &tv);[](#l1.109)
if (res == 0) {[](#l1.110)
res = WSAEWOULDBLOCK;[](#l1.111)
timeout = 1;[](#l1.112)
} else if (res > 0) {[](#l1.113)
if (FD_ISSET(s->sock_fd, &fds))[](#l1.114)
/* The socket is in the writable set - this[](#l1.115)
means connected */[](#l1.116)
res = 0;[](#l1.117)
else {[](#l1.118)
/* As per MS docs, we need to call getsockopt()[](#l1.119)
to get the underlying error */[](#l1.120)
int res_size = sizeof res;[](#l1.121)
/* It must be in the exception set */[](#l1.122)
assert(FD_ISSET(s->sock_fd, &fds_exc));[](#l1.123)
if (0 == getsockopt(s->sock_fd, SOL_SOCKET, SO_ERROR,[](#l1.124)
(char *)&res, &res_size))[](#l1.125)
/* getsockopt also clears WSAGetLastError,[](#l1.126)
so reset it back. */[](#l1.127)
WSASetLastError(res);[](#l1.128)
else[](#l1.129)
res = WSAGetLastError();[](#l1.130)
}[](#l1.131)
- if (s->sock_timeout > 0.0
&& res < 0 && WSAGetLastError() == WSAEWOULDBLOCK[](#l1.133)
&& IS_SELECTABLE(s)) {[](#l1.134)
/* This is a mess. Best solution: trust select */[](#l1.135)
fd_set fds;[](#l1.136)
fd_set fds_exc;[](#l1.137)
struct timeval tv;[](#l1.138)
Py_BEGIN_ALLOW_THREADS[](#l1.140)
tv.tv_sec = (int)s->sock_timeout;[](#l1.141)
tv.tv_usec = (int)((s->sock_timeout - tv.tv_sec) * 1e6);[](#l1.142)
FD_ZERO(&fds);[](#l1.143)
FD_SET(s->sock_fd, &fds);[](#l1.144)
FD_ZERO(&fds_exc);[](#l1.145)
FD_SET(s->sock_fd, &fds_exc);[](#l1.146)
res = select(Py_SAFE_DOWNCAST(s->sock_fd+1, SOCKET_T, int),[](#l1.147)
NULL, &fds, &fds_exc, &tv);[](#l1.148)
Py_END_ALLOW_THREADS[](#l1.149)
if (res == 0) {[](#l1.151)
res = WSAEWOULDBLOCK;[](#l1.152)
timeout = 1;[](#l1.153)
} else if (res > 0) {[](#l1.154)
if (FD_ISSET(s->sock_fd, &fds))[](#l1.155)
/* The socket is in the writable set - this[](#l1.156)
means connected */[](#l1.157)
res = 0;[](#l1.158)
else {[](#l1.159)
/* As per MS docs, we need to call getsockopt()[](#l1.160)
to get the underlying error */[](#l1.161)
int res_size = sizeof res;[](#l1.162)
/* It must be in the exception set */[](#l1.163)
assert(FD_ISSET(s->sock_fd, &fds_exc));[](#l1.164)
if (0 == getsockopt(s->sock_fd, SOL_SOCKET, SO_ERROR,[](#l1.165)
(char *)&res, &res_size))[](#l1.166)
/* getsockopt also clears WSAGetLastError,[](#l1.167)
so reset it back. */[](#l1.168)
WSASetLastError(res);[](#l1.169)
else[](#l1.170)
res = WSAGetLastError();[](#l1.171) }[](#l1.172)
/* else if (res < 0) an error occurred */[](#l1.173) }[](#l1.174)
} if (res < 0) @@ -2447,26 +2469,27 @@ internal_connect(PySocketSockObject *s,/* else if (res < 0) an error occurred */[](#l1.175)
- if (s->sock_timeout > 0.0) {
if (res < 0 && errno == EINPROGRESS && IS_SELECTABLE(s)) {[](#l1.184)
timeout = internal_select(s, 1);[](#l1.185)
if (timeout == 0) {[](#l1.186)
/* Bug #1019808: in case of an EINPROGRESS,[](#l1.187)
use getsockopt(SO_ERROR) to get the real[](#l1.188)
error. */[](#l1.189)
socklen_t res_size = sizeof res;[](#l1.190)
(void)getsockopt(s->sock_fd, SOL_SOCKET,[](#l1.191)
SO_ERROR, &res, &res_size);[](#l1.192)
if (res == EISCONN)[](#l1.193)
res = 0;[](#l1.194)
errno = res;[](#l1.195)
}[](#l1.196)
else if (timeout == -1) {[](#l1.197)
res = errno; /* had error */[](#l1.198)
}[](#l1.199)
else[](#l1.200)
res = EWOULDBLOCK; /* timed out */[](#l1.201)
timeout = internal_select(s, 1);[](#l1.205)
if (timeout == 0) {[](#l1.207)
/* Bug #1019808: in case of an EINPROGRESS,[](#l1.208)
use getsockopt(SO_ERROR) to get the real[](#l1.209)
error. */[](#l1.210)
socklen_t res_size = sizeof res;[](#l1.211)
(void)getsockopt(s->sock_fd, SOL_SOCKET,[](#l1.212)
SO_ERROR, &res, &res_size);[](#l1.213)
if (res == EISCONN)[](#l1.214)
res = 0;[](#l1.215)
errno = res;[](#l1.216) }[](#l1.217)
else if (timeout == -1) {[](#l1.218)
res = errno; /* had error */[](#l1.219)
}[](#l1.220)
else[](#l1.221)
} if (res < 0) @@ -2491,9 +2514,7 @@ sock_connect(PySocketSockObject *s, PyOb if (!getsockaddrarg(s, addro, SAS2SA(&addrbuf), &addrlen)) return NULL;res = EWOULDBLOCK; /* timed out */[](#l1.222)
- 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 @@ sock_connect_ex(PySocketSockObject *s, P 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 @@ sock_recv_guts(PySocketSockObject *s, ch BEGIN_SELECT_LOOP(s) do {
Py_BEGIN_ALLOW_THREADS[](#l1.250) timeout = internal_select_ex(s, 0, interval);[](#l1.251)
Py_BEGIN_ALLOW_THREADS[](#l1.254)
#ifdef MS_WINDOWS if (len > INT_MAX) len = INT_MAX; @@ -2689,8 +2709,8 @@ sock_recv_guts(PySocketSockObject *s, ch #else outlen = recv(s->sock_fd, cbuf, len, flags); #endif
Py_END_ALLOW_THREADS[](#l1.262) }[](#l1.263)
} while (outlen < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); if (timeout == 1) { @@ -2853,10 +2873,11 @@ sock_recvfrom_guts(PySocketSockObject *s BEGIN_SELECT_LOOP(s) do {Py_END_ALLOW_THREADS[](#l1.264)
Py_BEGIN_ALLOW_THREADS[](#l1.272) memset(&addrbuf, 0, addrlen);[](#l1.273) timeout = internal_select_ex(s, 0, interval);[](#l1.274)
Py_BEGIN_ALLOW_THREADS[](#l1.277)
#ifdef MS_WINDOWS if (len > INT_MAX) len = INT_MAX; @@ -2866,8 +2887,8 @@ sock_recvfrom_guts(PySocketSockObject *s n = recvfrom(s->sock_fd, cbuf, len, flags, SAS2SA(&addrbuf), &addrlen); #endif
Py_END_ALLOW_THREADS[](#l1.285) }[](#l1.286)
} while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); if (timeout == 1) { @@ -3054,7 +3075,6 @@ sock_recvmsg_guts(PySocketSockObject *s, BEGIN_SELECT_LOOP(s) do {Py_END_ALLOW_THREADS[](#l1.287)
Py_BEGIN_ALLOW_THREADS;[](#l1.295) msg.msg_name = SAS2SA(&addrbuf);[](#l1.296) msg.msg_namelen = addrbuflen;[](#l1.297) msg.msg_iov = iov;[](#l1.298)
@@ -3062,13 +3082,17 @@ sock_recvmsg_guts(PySocketSockObject *s, msg.msg_control = controlbuf; msg.msg_controllen = controllen; timeout = internal_select_ex(s, 0, interval);
if (!timeout)[](#l1.303)
bytes_received = recvmsg(s->sock_fd, &msg, flags);[](#l1.304)
Py_END_ALLOW_THREADS;[](#l1.305)
+ if (timeout == 1) { PyErr_SetString(socket_timeout, "timed out"); goto finally; } +
if (!timeout) {[](#l1.312)
Py_BEGIN_ALLOW_THREADS;[](#l1.313)
bytes_received = recvmsg(s->sock_fd, &msg, flags);[](#l1.314)
Py_END_ALLOW_THREADS;[](#l1.315)
} while (bytes_received < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); END_SELECT_LOOP(s) @@ -3350,9 +3374,10 @@ sock_send(PySocketSockObject *s, PyObjec BEGIN_SELECT_LOOP(s) do {}[](#l1.316)
Py_BEGIN_ALLOW_THREADS[](#l1.324) timeout = internal_select_ex(s, 1, interval);[](#l1.325)
Py_BEGIN_ALLOW_THREADS[](#l1.328)
#ifdef MS_WINDOWS if (len > INT_MAX) len = INT_MAX; @@ -3360,8 +3385,8 @@ sock_send(PySocketSockObject *s, PyObjec #else n = send(s->sock_fd, buf, len, flags); #endif
Py_END_ALLOW_THREADS[](#l1.336) }[](#l1.337)
} while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); if (timeout == 1) { PyBuffer_Release(&pbuf);Py_END_ALLOW_THREADS[](#l1.338)
@@ -3406,10 +3431,11 @@ sock_sendall(PySocketSockObject *s, PyOb } do {
Py_BEGIN_ALLOW_THREADS[](#l1.346) timeout = internal_select(s, 1);[](#l1.347)
Py_BEGIN_ALLOW_THREADS[](#l1.351)
#ifdef MS_WINDOWS if (len > INT_MAX) len = INT_MAX; @@ -3417,8 +3443,8 @@ sock_sendall(PySocketSockObject *s, PyOb #else n = send(s->sock_fd, buf, len, flags); #endif
Py_END_ALLOW_THREADS[](#l1.359) }[](#l1.360)
Py_END_ALLOW_THREADS[](#l1.361) if (timeout == 1) {[](#l1.362) PyBuffer_Release(&pbuf);[](#l1.363) PyErr_SetString(socket_timeout, "timed out");[](#l1.364)
@@ -3495,9 +3521,10 @@ sock_sendto(PySocketSockObject *s, PyObj BEGIN_SELECT_LOOP(s) do {
Py_BEGIN_ALLOW_THREADS[](#l1.369) timeout = internal_select_ex(s, 1, interval);[](#l1.370)
Py_BEGIN_ALLOW_THREADS[](#l1.373)
#ifdef MS_WINDOWS if (len > INT_MAX) len = INT_MAX; @@ -3507,8 +3534,8 @@ sock_sendto(PySocketSockObject *s, PyObj n = sendto(s->sock_fd, buf, len, flags, SAS2SA(&addrbuf), addrlen); #endif
Py_END_ALLOW_THREADS[](#l1.381) }[](#l1.382)
} while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); if (timeout == 1) { @@ -3710,11 +3737,14 @@ sock_sendmsg(PySocketSockObject *s, PyOb BEGIN_SELECT_LOOP(s) do {Py_END_ALLOW_THREADS[](#l1.383)
Py_BEGIN_ALLOW_THREADS;[](#l1.391) timeout = internal_select_ex(s, 1, interval);[](#l1.392)
if (!timeout)[](#l1.393)
if (!timeout) {[](#l1.395)
Py_BEGIN_ALLOW_THREADS;[](#l1.396) bytes_sent = sendmsg(s->sock_fd, &msg, flags);[](#l1.397)
Py_END_ALLOW_THREADS;[](#l1.398)
Py_END_ALLOW_THREADS;[](#l1.399)
}[](#l1.400)
+ if (timeout == 1) { PyErr_SetString(socket_timeout, "timed out"); goto finally;