Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 10550cd

Browse files
committed
Issue #23834: Simplify timeout handling
* Use the new _PyTime_FromSeconds() function to set the timeout to -1 second for socket.settimeout(None). It avoids a special case in internal_select() because of a rounding issue: -1 nanosecond is rounded to 0 millisecond which means non-blocking, instead of blocking. * Check if the interval the negative in sock_call_ex() instead of doing the check in internal_select(). sock_call_ex() remembers if the socket has a timeout or not, which avoids a race condition if the timeout is modified in a different thread.
1 parent 13019fd commit 10550cd

1 file changed

Lines changed: 13 additions & 27 deletions

File tree

Modules/socketmodule.c

Lines changed: 13 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -629,17 +629,6 @@ internal_select(PySocketSockObject *s, int writing, _PyTime_t interval,
629629
if (s->sock_fd < 0)
630630
return 0;
631631

632-
/* for connect(), we want to poll even if the socket is blocking */
633-
if (!connect) {
634-
/* Nothing to do unless we're in timeout mode (not non-blocking) */
635-
if (s->sock_timeout <= 0)
636-
return 0;
637-
638-
/* Handling this condition here simplifies the select loops */
639-
if (interval < 0)
640-
return 1;
641-
}
642-
643632
/* Prefer poll, if available, since you can poll() any fd
644633
* which can't be done with select(). */
645634
#ifdef HAVE_POLL
@@ -654,22 +643,14 @@ internal_select(PySocketSockObject *s, int writing, _PyTime_t interval,
654643
}
655644

656645
/* s->sock_timeout is in seconds, timeout in ms */
657-
if (interval >= 0)
658-
ms = _PyTime_AsMilliseconds(interval, _PyTime_ROUND_CEILING);
659-
else
660-
ms = -1;
646+
ms = _PyTime_AsMilliseconds(interval, _PyTime_ROUND_CEILING);
661647
assert(ms <= INT_MAX);
662648

663649
Py_BEGIN_ALLOW_THREADS;
664650
n = poll(&pollfd, 1, (int)ms);
665651
Py_END_ALLOW_THREADS;
666652
#else
667-
if (interval >= 0)
668-
_PyTime_AsTimeval_noraise(interval, &tv, _PyTime_ROUND_CEILING);
669-
else {
670-
tv.tv_sec = -1;
671-
tv.tv_sec = 0;
672-
}
653+
_PyTime_AsTimeval_noraise(interval, &tv, _PyTime_ROUND_CEILING);
673654

674655
FD_ZERO(&fds);
675656
FD_SET(s->sock_fd, &fds);
@@ -741,9 +722,9 @@ sock_call_ex(PySocketSockObject *s,
741722
/* For connect(), poll even for blocking socket. The connection
742723
runs asynchronously. */
743724
if (has_timeout || connect) {
744-
_PyTime_t interval;
745-
746725
if (has_timeout) {
726+
_PyTime_t interval;
727+
747728
if (deadline_initialized) {
748729
/* recompute the timeout */
749730
interval = deadline - _PyTime_GetMonotonicClock();
@@ -753,11 +734,16 @@ sock_call_ex(PySocketSockObject *s,
753734
deadline = _PyTime_GetMonotonicClock() + s->sock_timeout;
754735
interval = s->sock_timeout;
755736
}
737+
738+
if (interval >= 0)
739+
res = internal_select(s, writing, interval, connect);
740+
else
741+
res = 1;
742+
}
743+
else {
744+
res = internal_select(s, writing, -1, connect);
756745
}
757-
else
758-
interval = -1;
759746

760-
res = internal_select(s, writing, interval, connect);
761747
if (res == -1) {
762748
if (err)
763749
*err = GET_SOCK_ERROR;
@@ -2332,7 +2318,7 @@ socket_parse_timeout(_PyTime_t *timeout, PyObject *timeout_obj)
23322318
int overflow = 0;
23332319

23342320
if (timeout_obj == Py_None) {
2335-
*timeout = -1;
2321+
*timeout = _PyTime_FromSeconds(-1);
23362322
return 0;
23372323
}
23382324

0 commit comments

Comments
 (0)