curl-library
Re: mutli interface weird callstack
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