curl-library
curl_multi_perform will never return CURLM_CALL_MULTI_PERFORM (and suggested fix)
Date: Fri, 3 Aug 2012 11:08:46 -0500
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
Received on 2012-08-03