cURL / Mailing Lists / curl-library / Single Mail

curl-library

Re: mutli interface weird callstack

From: Dan Fandrich <dan_at_coneharvesters.com>
Date: Sat, 13 Jun 2015 23:31:39 +0200

On Thu, Jun 11, 2015 at 10:02:32AM +0800, Vincent Chen wrote:
> I have developed a HTTP client with multi interface with boost ASIO library
> and uses "CURLMOPT_SOCKETFUNCTION", "CURLMOPT_TIMERFUNCTION" to achieve
> asynchronous request.
>
> My timer callback is implemented like this:
>
> /* a static function */
> int AsyncCURLMgr::curlTimerCB(CURLM*, long timeout_ms, AsyncCURLMgr* mgr)
> {
>     // call it immediately
>     if(timeout_ms == 0 )
>     {
>         boost::system::error_code e;
>         mgr->whenTimerTimeout(e, timeout_ms);

This path calls curl_multi_socket_action() immediately, which isn't allowed.
The docs say that this callback should install a timer, and that timer callback
should call curl_multi_socket_action.

>     }
>     else if(timeout_ms > 0)
>     {
>         /* update timer */
>         boost::system::error_code e;
>         mgr->timer_.expires_from_now(boost::posix_time::millisec(timeout_ms),
> e);
>         mgr->timer_.async_wait(boost::bind(&AsyncCURLMgr::whenTimerTimeout,
> mgr, boost::asio::placeholders::error, timeout_ms));
>     }
>
>     return 0;
> }
>
> void AsyncCURLMgr::whenTimerTimeout(const boost::system::error_code& e, long)
> {
>     if(!e)
>     {
>         int still_running = 0;
>         CURLMcode rc = curl_multi_socket_action(curl_multi_,
> CURL_SOCKET_TIMEOUT, 0, &still_running);
>         if(rc!= CURLM_OK)
>            LOG_ERR("[whenTimerTimeout] curl_multi_socket_action return %d %s\
> n", rc, curl_multi_strerror(rc));
>        
>         checkMultiInfo();  // using curl_multi_info_read() to check complete
> requests
>     }
> }
>
>
> Recently, I am debugging my program and found a weird call stack.
> In the call stack you can see curlTimerCB( ) is called again and again with
> timeout value 0.
> -------------------------------------------------------------------------------------
> #0  LIBPROXY::AsyncCURLMgr::curlSocketCB (easy_handle=0x19c8c240, s=44, action=
> 2, mgr=0x19c23f50) at ../AsyncCURLMgr.cpp:153
> #1  0x00002ba9cf986ee6 in singlesocket () from /usr/tmcss/lib/libcurl.so.4
> #2  0x00002ba9cf988974 in multi_socket () from /usr/tmcss/lib/libcurl.so.4
> #3  0x00002ba9cf988a2f in curl_multi_socket_action () from /usr/tmcss/lib/
> libcurl.so.4
> #4  0x00002ba9cf71eb27 in LIBPROXY::AsyncCURLMgr::whenTimerTimeout (this=
> 0x19c23f50, e=@0x2ba9d243f5b0) at ../AsyncCURLMgr.cpp:478
> #5  0x00002ba9cf7200c1 in LIBPROXY::AsyncCURLMgr::curlTimerCB (timeout_ms=0,
> mgr=0x19c23f50) at ../AsyncCURLMgr.cpp:177
> #6  0x00002ba9cf9869c4 in update_timer () from /usr/tmcss/lib/libcurl.so.4
> #7  0x00002ba9cf988a4e in curl_multi_socket_action () from /usr/tmcss/lib/
> libcurl.so.4
> #8  0x00002ba9cf71eb27 in LIBPROXY::AsyncCURLMgr::whenTimerTimeout (this=
> 0x19c23f50, e=@0x2ba9d243f710) at ../AsyncCURLMgr.cpp:478
> #9  0x00002ba9cf7200c1 in LIBPROXY::AsyncCURLMgr::curlTimerCB (timeout_ms=0,
> mgr=0x19c23f50) at ../AsyncCURLMgr.cpp:177
> #10 0x00002ba9cf9869c4 in update_timer () from /usr/tmcss/lib/libcurl.so.4
> #11 0x00002ba9cf988a4e in curl_multi_socket_action () from /usr/tmcss/lib/
> libcurl.so.4
> #12 0x00002ba9cf71eb27 in LIBPROXY::AsyncCURLMgr::whenTimerTimeout (this=
> 0x19c23f50, e=@0x2ba9d243f870) at ../AsyncCURLMgr.cpp:478
> #13 0x00002ba9cf7200c1 in LIBPROXY::AsyncCURLMgr::curlTimerCB (timeout_ms=0,
> mgr=0x19c23f50) at ../AsyncCURLMgr.cpp:177
> #14 0x00002ba9cf9869c4 in update_timer () from /usr/tmcss/lib/libcurl.so.4
> #15 0x00002ba9cf988a4e in curl_multi_socket_action () from /usr/tmcss/lib/
> libcurl.so.4
> #16 0x00002ba9cf71eb27 in LIBPROXY::AsyncCURLMgr::whenTimerTimeout (this=
> 0x19c23f50, e=@0x2ba9d243f9d0) at ../AsyncCURLMgr.cpp:478
> #17 0x00002ba9cf7200c1 in LIBPROXY::AsyncCURLMgr::curlTimerCB (timeout_ms=0,
> mgr=0x19c23f50) at ../AsyncCURLMgr.cpp:177
> #18 0x00002ba9cf9869c4 in update_timer () from /usr/tmcss/lib/libcurl.so.4
> #19 0x00002ba9cf989083 in curl_multi_add_handle () from /usr/tmcss/lib/
> libcurl.so.4
> -------------------------------------------------------------------------------------
>
> According to the API document, when timeout is 0, I should call
> curl_multi_socket_action() immediately.

Immediately *after* the callback returns. What's happening is to be expected
if it's implemented as it is.

> so in my example code above, I call whenTimerTimeout( ) immediately when
> timeout is 0.
> so that it can call curl_multi_socket_action() quickly without timer.
>
> I am just curious if this behavior correct?
>
> In addition, I checked the example http://curl.haxx.se/libcurl/c/multi-uv.html
>
> --------------
> void start_timeout(CURLM *multi, long timeout_ms, void *userp)
> {
>   if(timeout_ms <= 0)
> timeout_ms = 1; /* 0 means directly call socket_action, but we'll do it in a bit */
>
> uv_timer_start(&timeout, on_timeout, timeout_ms, 0);
> }
> --------------
>
>
> I found it doesn't call  on_timeout() when timeout value is 0.
>
> Could you advice the correct calling sequence when timeout value is 0?

The most straightforward way is probably to set a flag and call
curl_multi_socket_action when it's set from within the main curl event loop.

>>> Dan
-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette: http://curl.haxx.se/mail/etiquette.html
Received on 2015-06-13