1
0
mirror of https://github.com/moparisthebest/curl synced 2025-01-11 05:58:01 -05:00

multi: expand pre-check for socket readiness

Check readiness of all sockets before waiting on them
to avoid locking in case the one-time event FD_WRITE
was already consumed by a previous wait operation.

More information about WinSock network events:
https://docs.microsoft.com/en-us/windows/win32/api/
   winsock2/nf-winsock2-wsaeventselect#return-value

Closes #5634
This commit is contained in:
Marc Hoersken 2020-07-26 21:26:46 +02:00
parent d2a7d7c185
commit 3334ee6bcb
No known key found for this signature in database
GPG Key ID: 61E03CBED7BC859E

View File

@ -1094,7 +1094,7 @@ static CURLMcode Curl_multi_wait(struct Curl_multi *multi,
struct pollfd *ufds = &a_few_on_stack[0]; struct pollfd *ufds = &a_few_on_stack[0];
bool ufds_malloc = FALSE; bool ufds_malloc = FALSE;
#else #else
int already_writable = 0; struct pollfd pre_poll;
DEBUGASSERT(multi->wsa_event != WSA_INVALID_EVENT); DEBUGASSERT(multi->wsa_event != WSA_INVALID_EVENT);
#endif #endif
@ -1175,13 +1175,15 @@ static CURLMcode Curl_multi_wait(struct Curl_multi *multi,
while(data) { while(data) {
bitmap = multi_getsock(data, sockbunch); bitmap = multi_getsock(data, sockbunch);
for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++) { for(i = 0; i < MAX_SOCKSPEREASYHANDLE; i++) {
curl_socket_t s = CURL_SOCKET_BAD; curl_socket_t s = CURL_SOCKET_BAD;
#ifdef USE_WINSOCK #ifdef USE_WINSOCK
long mask = 0; long mask = 0;
#endif #endif
if(bitmap & GETSOCK_READSOCK(i)) { if(bitmap & GETSOCK_READSOCK(i)) {
#ifdef USE_WINSOCK #ifdef USE_WINSOCK
if(SOCKET_READABLE(sockbunch[i], 0) > 0)
timeout_ms = 0;
mask |= FD_READ; mask |= FD_READ;
#else #else
ufds[nfds].fd = sockbunch[i]; ufds[nfds].fd = sockbunch[i];
@ -1192,15 +1194,8 @@ static CURLMcode Curl_multi_wait(struct Curl_multi *multi,
} }
if(bitmap & GETSOCK_WRITESOCK(i)) { if(bitmap & GETSOCK_WRITESOCK(i)) {
#ifdef USE_WINSOCK #ifdef USE_WINSOCK
struct timeval timeout; if(SOCKET_WRITABLE(sockbunch[i], 0) > 0)
fd_set writefds; timeout_ms = 0;
timeout.tv_sec = 0;
timeout.tv_usec = 0;
FD_ZERO(&writefds);
FD_SET(sockbunch[i], &writefds);
if(select((int)sockbunch[i] + 1, NULL, &writefds, NULL,
&timeout) == 1)
already_writable++;
mask |= FD_WRITE; mask |= FD_WRITE;
#else #else
ufds[nfds].fd = sockbunch[i]; ufds[nfds].fd = sockbunch[i];
@ -1227,23 +1222,30 @@ static CURLMcode Curl_multi_wait(struct Curl_multi *multi,
#ifdef USE_WINSOCK #ifdef USE_WINSOCK
long events = 0; long events = 0;
extra_fds[i].revents = 0; extra_fds[i].revents = 0;
if(extra_fds[i].events & CURL_WAIT_POLLIN) pre_poll.fd = extra_fds[i].fd;
pre_poll.events = 0;
pre_poll.revents = 0;
if(extra_fds[i].events & CURL_WAIT_POLLIN) {
events |= FD_READ; events |= FD_READ;
if(extra_fds[i].events & CURL_WAIT_POLLPRI) pre_poll.events |= POLLIN;
events |= FD_OOB;
if(extra_fds[i].events & CURL_WAIT_POLLOUT) {
struct timeval timeout;
fd_set writefds;
timeout.tv_sec = 0;
timeout.tv_usec = 0;
FD_ZERO(&writefds);
FD_SET(extra_fds[i].fd, &writefds);
if(select((int)extra_fds[i].fd + 1, NULL, &writefds, NULL,
&timeout) == 1) {
extra_fds[i].revents = CURL_WAIT_POLLOUT;
already_writable++;
} }
if(extra_fds[i].events & CURL_WAIT_POLLPRI) {
events |= FD_OOB;
pre_poll.events |= POLLPRI;
}
if(extra_fds[i].events & CURL_WAIT_POLLOUT) {
events |= FD_WRITE; events |= FD_WRITE;
pre_poll.events |= POLLOUT;
}
if(Curl_poll(&pre_poll, 1, 0) > 0) {
if(pre_poll.revents & POLLIN)
extra_fds[i].revents |= CURL_WAIT_POLLIN;
if(pre_poll.revents & POLLOUT)
extra_fds[i].revents |= CURL_WAIT_POLLOUT;
if(pre_poll.revents & POLLPRI)
extra_fds[i].revents |= CURL_WAIT_POLLPRI;
if(extra_fds[i].revents)
timeout_ms = 0;
} }
if(WSAEventSelect(extra_fds[i].fd, multi->wsa_event, events) != 0) if(WSAEventSelect(extra_fds[i].fd, multi->wsa_event, events) != 0)
return CURLM_INTERNAL_ERROR; return CURLM_INTERNAL_ERROR;
@ -1273,8 +1275,6 @@ static CURLMcode Curl_multi_wait(struct Curl_multi *multi,
if(nfds) { if(nfds) {
/* wait... */ /* wait... */
#ifdef USE_WINSOCK #ifdef USE_WINSOCK
if(already_writable > 0)
timeout_ms = 0;
WSAWaitForMultipleEvents(1, &multi->wsa_event, FALSE, timeout_ms, FALSE); WSAWaitForMultipleEvents(1, &multi->wsa_event, FALSE, timeout_ms, FALSE);
#else #else
int pollrc = Curl_poll(ufds, nfds, timeout_ms); int pollrc = Curl_poll(ufds, nfds, timeout_ms);
@ -1306,7 +1306,7 @@ static CURLMcode Curl_multi_wait(struct Curl_multi *multi,
if(events.lNetworkEvents & FD_OOB) if(events.lNetworkEvents & FD_OOB)
mask |= CURL_WAIT_POLLPRI; mask |= CURL_WAIT_POLLPRI;
if(events.lNetworkEvents != 0) if(ret && events.lNetworkEvents != 0)
retcode++; retcode++;
} }
WSAEventSelect(extra_fds[i].fd, multi->wsa_event, 0); WSAEventSelect(extra_fds[i].fd, multi->wsa_event, 0);
@ -1337,19 +1337,15 @@ static CURLMcode Curl_multi_wait(struct Curl_multi *multi,
WSANETWORKEVENTS events = {0}; WSANETWORKEVENTS events = {0};
if(WSAEnumNetworkEvents(sockbunch[i], multi->wsa_event, if(WSAEnumNetworkEvents(sockbunch[i], multi->wsa_event,
&events) == 0) { &events) == 0) {
if(events.lNetworkEvents != 0) if(ret && events.lNetworkEvents != 0)
retcode++; retcode++;
} }
if(ret && !events.lNetworkEvents && if(ret && !timeout_ms && !events.lNetworkEvents) {
(bitmap & GETSOCK_WRITESOCK(i))) { if((bitmap & GETSOCK_READSOCK(i)) &&
struct timeval timeout; SOCKET_READABLE(sockbunch[i], 0) > 0)
fd_set writefds; retcode++;
timeout.tv_sec = 0; else if((bitmap & GETSOCK_WRITESOCK(i)) &&
timeout.tv_usec = 0; SOCKET_WRITABLE(sockbunch[i], 0) > 0)
FD_ZERO(&writefds);
FD_SET(sockbunch[i], &writefds);
if(select((int)sockbunch[i] + 1, NULL, &writefds, NULL,
&timeout) == 1)
retcode++; retcode++;
} }
WSAEventSelect(sockbunch[i], multi->wsa_event, 0); WSAEventSelect(sockbunch[i], multi->wsa_event, 0);