cURL / Mailing Lists / curl-library / Single Mail


Re: Is it normal to the progress callback be called once again after returning non-zero value?

From: Ray Satiro <>
Date: Sat, 07 Jun 2014 03:34:31 -0400

On 6/6/2014 3:15 PM, Jonathan C. wrote:
>> It should, yes. If it behaves differently at any point I would consider that
>> room for improvement!
> I'm sending as attachment a code that is acting odd, at least here.
> The progress callback is called two times, I'm using libcurl 7.36.
> E:\curl-issue\build>test.exe
> Progress Called!
> Progress Called!
> Tested under Windows 7 x64 and Debian 7 x64.

I am not familiar with libuv but I took a look at your example. It looks
similar to the example here:
Two things about the curl example:

First in start_timeout() it calls uv_timer_start() which expects a
uv_timer_cb callback:
UV_EXTERN int uv_timer_start(uv_timer_t* handle,
                              uv_timer_cb cb,
                              uint64_t timeout,
                              uint64_t repeat);
typedef void (*uv_timer_cb)(uv_timer_t* handle);
Notice the callback doesn't receive a status so the definition should
probably be changed from:
void on_timeout(uv_timer_t *req, int status)
void on_timeout(uv_timer_t *req)

Second start_timeout() should return int, 0 in this case if I'm getting
libuv and reading this right:
So from:
void start_timeout(CURLM *multi, long timeout_ms, void *userp)
int start_timeout(CURLM *multi, long timeout_ms, void *userp)
and return 0

I ran that (modified) example instead of your example just to rule out
any problem in your example and the results are the same. It looks as
though there's always a final call made, here is the stack. I am on
Windows 7 x64 using master for both curl and libuv in VS2010.
      multi-uv.exe!progress(void * clientp, __int64 dltotal, __int64
dlnow, __int64 ultotal, __int64 ulnow) Line 81 C++
      multi-uv.exe!Curl_pgrsUpdate(connectdata * conn) Line 373 + 0x6d
bytes C
> multi-uv.exe!Curl_pgrsDone(connectdata * conn) Line 140 + 0x9
bytes C
      multi-uv.exe!Curl_done(connectdata * * connp, CURLcode status,
bool premature) Line 5813 + 0x9 bytes C
      multi-uv.exe!multi_runsingle(Curl_multi * multi, timeval now,
SessionHandle * data) Line 1613 + 0x10 bytes C
      multi-uv.exe!multi_socket(Curl_multi * multi, bool checkall,
unsigned int s, int ev_bitmask, int * running_handles) Line 2285 + 0x15
bytes C
      multi-uv.exe!curl_multi_socket_action(void * multi_handle,
unsigned int s, int ev_bitmask, int * running_handles) Line 2390 + 0x17
bytes C
      multi-uv.exe!on_timeout(uv_timer_s * req) Line 161 + 0x14
bytes C++
      multi-uv.exe!uv_process_timers(uv_loop_s * loop) Line 252 + 0xe
bytes C
      multi-uv.exe!uv_run(uv_loop_s * loop, uv_run_mode mode) Line 343
+ 0x9 bytes C
      multi-uv.exe!main(int argc, char * * argv) Line 271 + 0xd
bytes C++
      multi-uv.exe!__tmainCRTStartup() Line 278 + 0x19 bytes C
      multi-uv.exe!mainCRTStartup() Line 189 C
      kernel32.dll!@BaseThreadInitThunk_at_12() + 0x12 bytes
      ntdll.dll!___RtlUserThreadStart_at_8() + 0x27 bytes
      ntdll.dll!__RtlUserThreadStart_at_8() + 0x1b bytes

140 in progress.c:
   rc = Curl_pgrsUpdate(conn); /* the final (forced) update */

Doesn't seem like a bug to me to have a final update although the manual
Returning a non-zero value from this callback will cause libcurl to
abort the transfer and return CURLE_ABORTED_BY_CALLBACK.
That implies to me at least that a progress function would not be called
again if it aborts. If it's going to be called again the documentation
should be clarified and maybe there is a workaround like something you
can pass in for userp, int already_aborted or something. On the other
hand if the curl behavior is going to be changed I can't imagine most
devs would be depending on a final forced update after their progress
function aborts since the manual doesn't imply or specify it. Really I
don't know though that's a question best left for others to answer.

List admin:
Received on 2014-06-07