Since 7.20 a do-while loop has been added when processing each easy handle held by the multi handle.

For real time applications it's important to be able to just do a single multi_runsingle per easy handle and allow the calling application to decide if to call curl_multi_perform again if it has cycles left for that frame.

I did check on 7.27 and the problem is still in there but this code snippet is from 7.21.7

If you look at the inner do-while loop as it is now, you can see curl_multi_performwill never return CURLM_CALL_MULTI_PERFORM, since each easy handle that returns that will cause the inner do_while loop to execute again.

    CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
    {
      struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
      struct Curl_one_easy *easy;
      CURLMcode returncode=CURLM_OK;
    ...
      struct timeval now = Curl_tvnow();
    ...
      easy=multi->easy.next;
      while(easy != &multi->easy) {
    ...
        do
          result = multi_runsingle(multi, now, easy);
        while(CURLM_CALL_MULTI_PERFORM == result);
    ...
        if(result)
          returncode = result;

        easy = easy->next; /* operate on next handle */
      }
    ...
      return returncode;
    }

Pre 7.20, the do_while loop was not present, but there was a bug since the returned value would have been the last non CURLM_OK on the multi handle list of easy handles.

My suggestion will be to change the code so it does a single multi_runsingle call per easy_handle and returning CURLM_CALL_MULTI_PERFORM if any of the easy handles needs to be called back.

I also added code to store the last non CURLM_OK nor CURLM_CALL_MULTI_PERFORM, so if you want to prioritize returning errors over CURLM_OK or CURLM_CALL_MULTI_PERFORM the code will look like this:

    CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
    {
      struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
      struct Curl_one_easy *easy;
      CURLMcode returncode=CURLM_OK;
      CURLMcode lasterrorcode = CURLM_OK;
    ...
      struct timeval now = Curl_tvnow();
    ...
      easy=multi->easy.next;
      while(easy != &multi->easy) {
    ...
result = multi_runsingle(multi, now, easy); /* removed the do_while loop */
    ...
        if(CURLM_CALL_MULTI_PERFORM == result)
          returncode = result;
        else if(CURLM_OK != result)
          lasterrorcode = result;

        easy = easy->next; /* operate on next handle */
      }
    ...
      return (CURLM_OK!=lasterrorcode)?lasterrorcode:returncode;
    }


if you want to allow other easy handles to complete first before reporting the error thenchange the return to:

return (CURLM_OK != lasterrorcode && CURLM_CALL_MULTI_PERFORM != returncode)?lasterrorcode:returncode;

I think these changes will make the original intent of CURLM_CALL_MULTI_PERFORM be of relevance once more, specially for real-time applications that want a tighter resource control.

BTW I have another code change suggestion regarding CURLOPT_MAX_RECV_SPEED_LARGE unintended behavior but i'll send a separate report.

Thanks,

Miguel


-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette:  http://curl.haxx.se/mail/etiquette.html

Reply via email to