curl_easy_perform: avoid busy-looping

When curl_multi_wait() finds no file descriptor to wait for, it returns
instantly and this must be handled gracefully within curl_easy_perform()
or cause a busy-loop. Starting now, repeated fast returns without any
file descriptors is detected and a gradually increasing sleep will be
used (up to a max of 1000 milliseconds) before continuing the loop.

Bug: http://curl.haxx.se/bug/view.cgi?id=1238
Reported-by: Miguel Angel
This commit is contained in:
Daniel Stenberg 2013-06-13 19:27:12 +02:00
parent f24dc09d20
commit 0feeab7802

View File

@ -420,6 +420,9 @@ CURLcode curl_easy_perform(CURL *easy)
bool done = FALSE; bool done = FALSE;
int rc; int rc;
struct SessionHandle *data = easy; struct SessionHandle *data = easy;
int without_fds = 0; /* count number of consecutive returns from
curl_multi_wait() without any filedescriptors */
struct timeval before;
if(!easy) if(!easy)
return CURLE_BAD_FUNCTION_ARGUMENT; return CURLE_BAD_FUNCTION_ARGUMENT;
@ -460,6 +463,7 @@ CURLcode curl_easy_perform(CURL *easy)
int still_running; int still_running;
int ret; int ret;
before = curlx_tvnow();
mcode = curl_multi_wait(multi, NULL, 0, 1000, &ret); mcode = curl_multi_wait(multi, NULL, 0, 1000, &ret);
if(mcode == CURLM_OK) { if(mcode == CURLM_OK) {
@ -468,6 +472,27 @@ CURLcode curl_easy_perform(CURL *easy)
code = CURLE_RECV_ERROR; code = CURLE_RECV_ERROR;
break; break;
} }
else if(ret == 0) {
struct timeval after = curlx_tvnow();
/* If it returns without any filedescriptor instantly, we need to
avoid busy-looping during periods where it has nothing particular
to wait for */
if(curlx_tvdiff(after, before) <= 10) {
without_fds++;
if(without_fds > 2) {
int sleep_ms = without_fds * 50;
if(sleep_ms > 1000)
sleep_ms = 1000;
Curl_wait_ms(sleep_ms);
}
}
else
/* it wasn't "instant", restart counter */
without_fds = 0;
}
else
/* got file descriptor, restart counter */
without_fds = 0;
mcode = curl_multi_perform(multi, &still_running); mcode = curl_multi_perform(multi, &still_running);
} }