mirror of
https://github.com/curl/curl.git
synced 2025-01-18 14:04:30 +08:00
multi: reduce Win32 API calls to improve performance
1. Consolidate pre-checks into a single Curl_poll call: This is an attempt to restructure the code in Curl_multi_wait in such a way that less syscalls are made by removing individual calls to Curl_socket_check via SOCKET_READABLE/SOCKET_WRITABLE. 2. Avoid resetting the WinSock event multiple times: We finally call WSAResetEvent anyway, so specifying it as an optional parameter to WSAEnumNetworkEvents is redundant. 3. Wakeup directly in case no sockets are being monitoring: Fix the WinSock based implementation to skip extra waiting by not sleeping in case no sockets are to be waited on and just the WinSock event is being monitored for wakeup functionality. Assisted-by: Tommy Odom Reviewed-by: Jay Satiro Reviewed-by: Marcel Raad Bug: #6146 Closes #6245
This commit is contained in:
parent
bcca174cfa
commit
e92998a312
124
lib/multi.c
124
lib/multi.c
@ -1086,12 +1086,10 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
|
||||
unsigned int curlfds;
|
||||
long timeout_internal;
|
||||
int retcode = 0;
|
||||
#ifndef USE_WINSOCK
|
||||
struct pollfd a_few_on_stack[NUM_POLLS_ON_STACK];
|
||||
struct pollfd *ufds = &a_few_on_stack[0];
|
||||
bool ufds_malloc = FALSE;
|
||||
#else
|
||||
struct pollfd pre_poll;
|
||||
#ifdef USE_WINSOCK
|
||||
WSANETWORKEVENTS wsa_events;
|
||||
DEBUGASSERT(multi->wsa_event != WSA_INVALID_EVENT);
|
||||
#endif
|
||||
@ -1149,7 +1147,6 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef USE_WINSOCK
|
||||
if(nfds > NUM_POLLS_ON_STACK) {
|
||||
/* 'nfds' is a 32 bit value and 'struct pollfd' is typically 8 bytes
|
||||
big, so at 2^29 sockets this value might wrap. When a process gets
|
||||
@ -1160,9 +1157,7 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
|
||||
return CURLM_OUT_OF_MEMORY;
|
||||
ufds_malloc = TRUE;
|
||||
}
|
||||
|
||||
nfds = 0;
|
||||
#endif
|
||||
|
||||
/* only do the second loop if we found descriptors in the first stage run
|
||||
above */
|
||||
@ -1180,34 +1175,31 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
|
||||
#endif
|
||||
if(bitmap & GETSOCK_READSOCK(i)) {
|
||||
#ifdef USE_WINSOCK
|
||||
if(timeout_ms && SOCKET_READABLE(sockbunch[i], 0) > 0)
|
||||
timeout_ms = 0;
|
||||
mask |= FD_READ|FD_ACCEPT|FD_CLOSE;
|
||||
#else
|
||||
#endif
|
||||
ufds[nfds].fd = sockbunch[i];
|
||||
ufds[nfds].events = POLLIN;
|
||||
++nfds;
|
||||
#endif
|
||||
s = sockbunch[i];
|
||||
}
|
||||
if(bitmap & GETSOCK_WRITESOCK(i)) {
|
||||
#ifdef USE_WINSOCK
|
||||
if(timeout_ms && SOCKET_WRITABLE(sockbunch[i], 0) > 0)
|
||||
timeout_ms = 0;
|
||||
mask |= FD_WRITE|FD_CONNECT|FD_CLOSE;
|
||||
#else
|
||||
#endif
|
||||
ufds[nfds].fd = sockbunch[i];
|
||||
ufds[nfds].events = POLLOUT;
|
||||
++nfds;
|
||||
#endif
|
||||
s = sockbunch[i];
|
||||
}
|
||||
if(s == CURL_SOCKET_BAD) {
|
||||
break;
|
||||
}
|
||||
#ifdef USE_WINSOCK
|
||||
if(WSAEventSelect(s, multi->wsa_event, mask) != 0)
|
||||
if(WSAEventSelect(s, multi->wsa_event, mask) != 0) {
|
||||
if(ufds_malloc)
|
||||
free(ufds);
|
||||
return CURLM_INTERNAL_ERROR;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -1219,35 +1211,18 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
|
||||
for(i = 0; i < extra_nfds; i++) {
|
||||
#ifdef USE_WINSOCK
|
||||
long mask = 0;
|
||||
extra_fds[i].revents = 0;
|
||||
pre_poll.fd = extra_fds[i].fd;
|
||||
pre_poll.events = 0;
|
||||
pre_poll.revents = 0;
|
||||
if(extra_fds[i].events & CURL_WAIT_POLLIN) {
|
||||
if(extra_fds[i].events & CURL_WAIT_POLLIN)
|
||||
mask |= FD_READ|FD_ACCEPT|FD_CLOSE;
|
||||
pre_poll.events |= POLLIN;
|
||||
}
|
||||
if(extra_fds[i].events & CURL_WAIT_POLLPRI) {
|
||||
if(extra_fds[i].events & CURL_WAIT_POLLPRI)
|
||||
mask |= FD_OOB;
|
||||
pre_poll.events |= POLLPRI;
|
||||
}
|
||||
if(extra_fds[i].events & CURL_WAIT_POLLOUT) {
|
||||
if(extra_fds[i].events & CURL_WAIT_POLLOUT)
|
||||
mask |= FD_WRITE|FD_CONNECT|FD_CLOSE;
|
||||
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 & POLLPRI)
|
||||
extra_fds[i].revents |= CURL_WAIT_POLLPRI;
|
||||
if(pre_poll.revents & POLLOUT)
|
||||
extra_fds[i].revents |= CURL_WAIT_POLLOUT;
|
||||
if(extra_fds[i].revents)
|
||||
timeout_ms = 0;
|
||||
}
|
||||
if(WSAEventSelect(extra_fds[i].fd, multi->wsa_event, mask) != 0)
|
||||
if(WSAEventSelect(extra_fds[i].fd, multi->wsa_event, mask) != 0) {
|
||||
if(ufds_malloc)
|
||||
free(ufds);
|
||||
return CURLM_INTERNAL_ERROR;
|
||||
#else
|
||||
}
|
||||
#endif
|
||||
ufds[nfds].fd = extra_fds[i].fd;
|
||||
ufds[nfds].events = 0;
|
||||
if(extra_fds[i].events & CURL_WAIT_POLLIN)
|
||||
@ -1257,7 +1232,6 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
|
||||
if(extra_fds[i].events & CURL_WAIT_POLLOUT)
|
||||
ufds[nfds].events |= POLLOUT;
|
||||
++nfds;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef ENABLE_WAKEUP
|
||||
@ -1270,53 +1244,59 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if(nfds) {
|
||||
/* wait... */
|
||||
#ifdef USE_WINSOCK
|
||||
WSAWaitForMultipleEvents(1, &multi->wsa_event, FALSE, timeout_ms, FALSE);
|
||||
#if defined(ENABLE_WAKEUP) && defined(USE_WINSOCK)
|
||||
if(nfds || use_wakeup) {
|
||||
#else
|
||||
int pollrc = Curl_poll(ufds, nfds, timeout_ms);
|
||||
if(nfds) {
|
||||
#endif
|
||||
int pollrc;
|
||||
#ifdef USE_WINSOCK
|
||||
if(nfds)
|
||||
pollrc = Curl_poll(ufds, nfds, 0); /* just pre-check with WinSock */
|
||||
else
|
||||
pollrc = 0;
|
||||
if(pollrc <= 0) /* now wait... if not ready during the pre-check above */
|
||||
WSAWaitForMultipleEvents(1, &multi->wsa_event, FALSE, timeout_ms, FALSE);
|
||||
#else
|
||||
pollrc = Curl_poll(ufds, nfds, timeout_ms); /* wait... */
|
||||
#endif
|
||||
|
||||
#ifdef USE_WINSOCK
|
||||
/* With Winsock, we have to run this unconditionally to call
|
||||
WSAEventSelect(fd, event, 0) on all the sockets */
|
||||
{
|
||||
retcode = 0;
|
||||
#else
|
||||
if(pollrc > 0) {
|
||||
retcode = pollrc;
|
||||
#ifdef USE_WINSOCK
|
||||
}
|
||||
/* With WinSock, we have to run the following section unconditionally
|
||||
to call WSAEventSelect(fd, event, 0) on all the sockets */
|
||||
{
|
||||
#endif
|
||||
/* copy revents results from the poll to the curl_multi_wait poll
|
||||
struct, the bit values of the actual underlying poll() implementation
|
||||
may not be the same as the ones in the public libcurl API! */
|
||||
for(i = 0; i < extra_nfds; i++) {
|
||||
unsigned r = ufds[curlfds + i].revents;
|
||||
unsigned short mask = 0;
|
||||
#ifdef USE_WINSOCK
|
||||
wsa_events.lNetworkEvents = 0;
|
||||
mask = extra_fds[i].revents;
|
||||
if(WSAEnumNetworkEvents(extra_fds[i].fd, multi->wsa_event,
|
||||
&wsa_events) == 0) {
|
||||
if(WSAEnumNetworkEvents(extra_fds[i].fd, NULL, &wsa_events) == 0) {
|
||||
if(wsa_events.lNetworkEvents & (FD_READ|FD_ACCEPT|FD_CLOSE))
|
||||
mask |= CURL_WAIT_POLLIN;
|
||||
if(wsa_events.lNetworkEvents & (FD_WRITE|FD_CONNECT|FD_CLOSE))
|
||||
mask |= CURL_WAIT_POLLOUT;
|
||||
if(wsa_events.lNetworkEvents & FD_OOB)
|
||||
mask |= CURL_WAIT_POLLPRI;
|
||||
if(ret && wsa_events.lNetworkEvents != 0)
|
||||
if(ret && pollrc <= 0 && wsa_events.lNetworkEvents != 0)
|
||||
retcode++;
|
||||
}
|
||||
WSAEventSelect(extra_fds[i].fd, multi->wsa_event, 0);
|
||||
#else
|
||||
unsigned r = ufds[curlfds + i].revents;
|
||||
|
||||
if(pollrc <= 0)
|
||||
continue;
|
||||
#endif
|
||||
if(r & POLLIN)
|
||||
mask |= CURL_WAIT_POLLIN;
|
||||
if(r & POLLOUT)
|
||||
mask |= CURL_WAIT_POLLOUT;
|
||||
if(r & POLLPRI)
|
||||
mask |= CURL_WAIT_POLLPRI;
|
||||
#endif
|
||||
extra_fds[i].revents = mask;
|
||||
}
|
||||
|
||||
@ -1331,17 +1311,8 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
|
||||
for(i = 0; i < MAX_SOCKSPEREASYHANDLE; i++) {
|
||||
if(bitmap & (GETSOCK_READSOCK(i) | GETSOCK_WRITESOCK(i))) {
|
||||
wsa_events.lNetworkEvents = 0;
|
||||
if(WSAEnumNetworkEvents(sockbunch[i], multi->wsa_event,
|
||||
&wsa_events) == 0) {
|
||||
if(ret && wsa_events.lNetworkEvents != 0)
|
||||
retcode++;
|
||||
}
|
||||
if(ret && !timeout_ms && wsa_events.lNetworkEvents == 0) {
|
||||
if((bitmap & GETSOCK_READSOCK(i)) &&
|
||||
SOCKET_READABLE(sockbunch[i], 0) > 0)
|
||||
retcode++;
|
||||
else if((bitmap & GETSOCK_WRITESOCK(i)) &&
|
||||
SOCKET_WRITABLE(sockbunch[i], 0) > 0)
|
||||
if(WSAEnumNetworkEvents(sockbunch[i], NULL, &wsa_events) == 0) {
|
||||
if(ret && pollrc <= 0 && wsa_events.lNetworkEvents != 0)
|
||||
retcode++;
|
||||
}
|
||||
WSAEventSelect(sockbunch[i], multi->wsa_event, 0);
|
||||
@ -1382,16 +1353,15 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef USE_WINSOCK
|
||||
if(ufds_malloc)
|
||||
free(ufds);
|
||||
#endif
|
||||
if(ret)
|
||||
*ret = retcode;
|
||||
if(!extrawait || nfds)
|
||||
/* if any socket was checked */
|
||||
;
|
||||
else {
|
||||
#if defined(ENABLE_WAKEUP) && defined(USE_WINSOCK)
|
||||
if(extrawait && !nfds && !use_wakeup) {
|
||||
#else
|
||||
if(extrawait && !nfds) {
|
||||
#endif
|
||||
long sleep_ms = 0;
|
||||
|
||||
/* Avoid busy-looping when there's nothing particular to wait for */
|
||||
|
Loading…
Reference in New Issue
Block a user