2.0 KiB
Keeping Time
Transfers need the current time to handle timeouts and keep a record of
events. The current time function is curlx_now() and it uses a monotonic
clock on most platforms. This ensures that time only ever increases (the
timestamps it gives are however not the "real" world clock).
Initial Approach (now historic)
The loop processing functions called curlx_now() at the beginning and then
passed a pointer to the struct curltime now to functions to save them the
calls. Passing this pointer down to all functions possibly involved was not
done as this pollutes the internal APIs.
Some functions continued to call curlx_now() on their own while others used
the passed pointer to a timestamp in the past. This led to a transfer
experiencing jumps in time, reversing cause and effect. On fast systems,
this was mostly not noticeable. On slow machines or in CI, this led to rare
and annoying test failures.
(Especially when we added assertions that the reported "timeline" of a transfer was in the correct order: queue -> nameloopup -> connect -> appconnect ->....)
Revised Approach
The strategy of handling transfer's time is now:
- Keep a "now" timestamp in the multi handle. Keep a fallback "now" timestamp in the easy handle.
- Always use
Curl_pgrs_now(data)to get the current time of a transfer. - Do not use
curlx_now()directly for transfer handling (exceptions apply for loops).
This has the following advantages:
- No need to pass a
struct curltimearound or pass a pointer to an outdated timestamp to other functions. - No need to calculate the exact
nowuntil it is really used. - Passing a
constpointer is better than struct passing. Updating and passing a pointer to the same memory location for all transfers is even better.
Caveats:
- do not store the pointer returned by
Curl_pgrs_now(data)anywhere that outlives the current code invocation.