From d3036f34cce421990e8268ee4bbfc0d9f5ceb054 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 13 Jun 2013 19:27:12 +0200 Subject: [PATCH] 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 [upstream commit 0feeab7802dd2a6465d22d153d8d36b2cca99b96] Signed-off-by: Kamil Dudka --- lib/easy.c | 25 +++++++++++++++++++++++++ 1 files changed, 25 insertions(+), 0 deletions(-) diff --git a/lib/easy.c b/lib/easy.c index 2739598..a7051dd 100644 --- a/lib/easy.c +++ b/lib/easy.c @@ -410,6 +410,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; @@ -445,6 +448,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) { @@ -453,6 +457,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); } -- 1.7.1