Commit 0feeab78 authored by Daniel Stenberg's avatar Daniel Stenberg
Browse files

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
parent f24dc09d
Loading
Loading
Loading
Loading
+25 −0
Original line number Original line Diff line number Diff line
@@ -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);
    }
    }