curl / Mailing Lists / curl-library / Single Mail


Re: curl_multi_add_handle and subsequent timer

From: Daniel Stenberg <>
Date: Mon, 13 Nov 2017 11:09:52 +0100 (CET)

On Mon, 13 Nov 2017, Maksim Dmitrichenko via curl-library wrote:

>> The timeout is actually at 0ms these days.
> Maybe I'm running a bit outdated version 7.38 - it is on Debian Jessie. It
> request 1 ms.

*A bit*, yes:

>> You can always - at your choice - decide to call
>> libcurl earlier or later than the timeout suggests.
> Well, it is not that simple. Timer callback is called for various purposes -
> sometimes it is called to setup connection timeout, sometimes (like the
> above) to start execution of new handle. I never know for sure when I could
> skip waiting for it.

Then why even bother trying to do something special for this case? libcurl
tells you the timeout so why not simply adhere to it?

> For example: let's have a working HTTP request that waits for response from
> server. We have a socket that polls for incoming data and a request timeout
> of e.g. 5000 ms. Ignoring that timeout and calling libcurl instead will lead
> to another timeout being requested by libcurl (e.g. for 4999 ms) and so on.

If you're talking about libcurl's event-based multi_socket API, then libcurl
will not update the timeout until the absolute timeout time changes. So you
can keep calling libcurl all those 5000 milliseconds and unless there's a new
timeout getting set, it won't (or at least shouldn't) update the callback with
a new timeout.

But unless there's socket activity there's no point in calling libcurl until
the timer expires because it will have nothing to do.

> So ignoring timeouts generally will lead to high CPU consumption without
> doing any useful work. So, generally choosing to ignore timeouts is a bad
> idea.

I don't encourage anyone to generally ignore timeouts. I'm just saying that
nothing breaks in libcurl if you do. libcurl keeps track of the timed actions
to do no matter when you call it and won't run the timed actions until after
the timout time has expired.

You asked if you could call perform right away after add handle, and the
answer is yes. With your oldish libcurl however, chances are that you'd ask
libcurl to perform something *before* the 1ms has expired and then it still
won't do anything ... :-O

> 3) Thread 1: upon return from curl_multi_add_handle() my code signals to
> eventfd to interrupt epoll() running in thread 2.
> 4) Thread 2: epoll() exists with signal in eventfd().
> 5) Thread 2: my code makes a call curl_multi_socket_action(handle_multi,
> CURL_SOCKET_TIMEOUT, 0, &running_handles);
> 6) Thread 2: timer callback is called from within libcurl and asks for
> timer for 1 ms. Timer reloaded. (AGAIN!!!)

... because the 1ms timeout hasn't expired and libcurl still wants to get
called when it expires. You better set a timeout and wait until it expires!

> There is no sleeps between steps 1 to 7!!! Only one context switch to thread
> 2.

That's your choice. libcurl doesn't make you act like that.

> So, I tried to hack this timeout but this doesn't work. Something inside
> libcurl actually waits for 1 ms to pass.

Yes, since it sets a timeout to expire in 1ms it will perform those actions
after 1ms and not before.

It used 1ms back then simply because we used the magic number of 0 to mean
something else internally. In commit bde2f09d5e4c4a3 that internal quirk was
fixed so since 7.50.2 (released over a year ago) it doesn't wait 1ms to start.
Since then it sets the initial timeout to 0ms into the future.

Received on 2017-11-13