From: Daniel Stenberg Date: Thu, 13 Jun 2013 17:27:12 +0000 (+0200) Subject: curl_easy_perform: avoid busy-looping X-Git-Tag: curl-7_31_0~13 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=0feeab78;p=thirdparty%2Fcurl.git 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 --- diff --git a/lib/easy.c b/lib/easy.c index 5d441f7189..94a84abb23 100644 --- a/lib/easy.c +++ b/lib/easy.c @@ -420,6 +420,9 @@ CURLcode curl_easy_perform(CURL *easy) bool done = FALSE; int rc; 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) return CURLE_BAD_FUNCTION_ARGUMENT; @@ -460,6 +463,7 @@ CURLcode curl_easy_perform(CURL *easy) int still_running; int ret; + before = curlx_tvnow(); mcode = curl_multi_wait(multi, NULL, 0, 1000, &ret); if(mcode == CURLM_OK) { @@ -468,6 +472,27 @@ CURLcode curl_easy_perform(CURL *easy) code = CURLE_RECV_ERROR; 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); }