time-keeping: keep timestamp in multi, always update

Always use curlx_now() when calling Curl_pgrs_now(data). Tests with the
"manual" updates to now proved differ more then 100ms in parallel testing.

Add `curlx_nowp()` to set current time into a struct curltime.
Add `curlx_ptimediff_ms() and friends, passing pointers.

Update documentation.

Closes #19998
This commit is contained in:
Stefan Eissing 2025-12-18 13:55:07 +01:00 committed by Daniel Stenberg
parent 308c347c8b
commit b4be1f271e
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
61 changed files with 471 additions and 502 deletions

View file

@ -206,7 +206,6 @@ void Curl_cpool_destroy(struct cpool *cpool)
cpool->share ? "[SHARE] " : "", cpool->num_conn);
/* Move all connections to the shutdown list */
sigpipe_init(&pipe_st);
Curl_pgrs_now_set(cpool->idata);
CPOOL_LOCK(cpool, cpool->idata);
conn = cpool_get_first(cpool);
while(conn) {
@ -275,7 +274,7 @@ static struct cpool_bundle *cpool_add_bundle(struct cpool *cpool,
static struct connectdata *
cpool_bundle_get_oldest_idle(struct cpool_bundle *bundle,
struct curltime *pnow)
const struct curltime *pnow)
{
struct Curl_llist_node *curr;
timediff_t highscore = -1;
@ -289,7 +288,7 @@ cpool_bundle_get_oldest_idle(struct cpool_bundle *bundle,
if(!CONN_INUSE(conn)) {
/* Set higher score for the age passed since the connection was used */
score = curlx_timediff_ms(*pnow, conn->lastused);
score = curlx_ptimediff_ms(pnow, &conn->lastused);
if(score > highscore) {
highscore = score;
@ -302,7 +301,7 @@ cpool_bundle_get_oldest_idle(struct cpool_bundle *bundle,
}
static struct connectdata *cpool_get_oldest_idle(struct cpool *cpool,
struct curltime *pnow)
const struct curltime *pnow)
{
struct Curl_hash_iterator iter;
struct Curl_llist_node *curr;
@ -325,7 +324,7 @@ static struct connectdata *cpool_get_oldest_idle(struct cpool *cpool,
if(CONN_INUSE(conn) || conn->bits.close || conn->connect_only)
continue;
/* Set higher score for the age passed since the connection was used */
score = curlx_timediff_ms(*pnow, conn->lastused);
score = curlx_ptimediff_ms(pnow, &conn->lastused);
if(score > highscore) {
highscore = score;
oldest_idle = conn;
@ -356,7 +355,6 @@ int Curl_cpool_check_limits(struct Curl_easy *data,
if(!dest_limit && !total_limit)
return CPOOL_LIMIT_OK;
Curl_pgrs_now_update(cpool->idata, data);
CPOOL_LOCK(cpool, cpool->idata);
if(dest_limit) {
size_t live;
@ -377,7 +375,7 @@ int Curl_cpool_check_limits(struct Curl_easy *data,
/* The bundle is full. Extract the oldest connection that may
* be removed now, if there is one. */
oldest_idle = cpool_bundle_get_oldest_idle(bundle,
&data->progress.now);
Curl_pgrs_now(data));
if(!oldest_idle)
break;
/* disconnect the old conn and continue */
@ -409,7 +407,7 @@ int Curl_cpool_check_limits(struct Curl_easy *data,
}
else {
struct connectdata *oldest_idle =
cpool_get_oldest_idle(cpool, &data->progress.now);
cpool_get_oldest_idle(cpool, Curl_pgrs_now(data));
if(!oldest_idle)
break;
/* disconnect the old conn and continue */
@ -429,7 +427,6 @@ int Curl_cpool_check_limits(struct Curl_easy *data,
out:
CPOOL_UNLOCK(cpool, cpool->idata);
Curl_pgrs_now_update(data, cpool->idata);
return result;
}
@ -539,7 +536,7 @@ bool Curl_cpool_conn_now_idle(struct Curl_easy *data,
maxconnects = data->multi->maxconnects;
}
conn->lastused = data->progress.now; /* it was used up until now */
conn->lastused = *Curl_pgrs_now(data); /* it was used up until now */
if(cpool && maxconnects) {
/* may be called form a callback already under lock */
bool do_lock = !CPOOL_IS_LOCKED(cpool);
@ -549,7 +546,7 @@ bool Curl_cpool_conn_now_idle(struct Curl_easy *data,
infof(data, "Connection pool is full, closing the oldest of %zu/%u",
cpool->num_conn, maxconnects);
oldest_idle = cpool_get_oldest_idle(cpool, &data->progress.now);
oldest_idle = cpool_get_oldest_idle(cpool, Curl_pgrs_now(data));
kept = (oldest_idle != conn);
if(oldest_idle) {
Curl_conn_terminate(data, oldest_idle, FALSE);
@ -636,7 +633,6 @@ static void cpool_discard_conn(struct cpool *cpool,
* If we do a shutdown for an aborted transfer, the server might think
* it was successful otherwise (for example an ftps: upload). This is
* not what we want. */
Curl_pgrs_now_update(cpool->idata, data);
if(aborted)
done = TRUE;
if(!done) {
@ -702,13 +698,24 @@ void Curl_conn_terminate(struct Curl_easy *data,
CPOOL_UNLOCK(cpool, data);
}
struct cpool_reaper_ctx {
size_t checked;
size_t reaped;
};
static int cpool_reap_dead_cb(struct Curl_easy *data,
struct connectdata *conn, void *param)
{
(void)param;
if((!CONN_INUSE(conn) && conn->bits.no_reuse) ||
Curl_conn_seems_dead(conn, data)) {
struct cpool_reaper_ctx *reaper = param;
bool terminate = !CONN_INUSE(conn) && conn->bits.no_reuse;
if(!terminate) {
reaper->checked++;
terminate = Curl_conn_seems_dead(conn, data);
}
if(terminate) {
/* stop the iteration here, pass back the connection that was pruned */
reaper->reaped++;
Curl_conn_terminate(data, conn, FALSE);
return 1;
}
@ -725,18 +732,20 @@ static int cpool_reap_dead_cb(struct Curl_easy *data,
void Curl_cpool_prune_dead(struct Curl_easy *data)
{
struct cpool *cpool = cpool_get_instance(data);
struct cpool_reaper_ctx reaper;
timediff_t elapsed;
if(!cpool)
return;
memset(&reaper, 0, sizeof(reaper));
CPOOL_LOCK(cpool, data);
elapsed = curlx_timediff_ms(data->progress.now, cpool->last_cleanup);
elapsed = curlx_ptimediff_ms(Curl_pgrs_now(data), &cpool->last_cleanup);
if(elapsed >= 1000L) {
while(cpool_foreach(data, cpool, NULL, cpool_reap_dead_cb))
while(cpool_foreach(data, cpool, &reaper, cpool_reap_dead_cb))
;
cpool->last_cleanup = data->progress.now;
cpool->last_cleanup = *Curl_pgrs_now(data);
}
CPOOL_UNLOCK(cpool, data);
}
@ -745,8 +754,8 @@ static int conn_upkeep(struct Curl_easy *data,
struct connectdata *conn,
void *param)
{
struct curltime *now = param;
Curl_conn_upkeep(data, conn, now);
(void)param;
Curl_conn_upkeep(data, conn);
return 0; /* continue iteration */
}
@ -758,7 +767,7 @@ CURLcode Curl_cpool_upkeep(struct Curl_easy *data)
return CURLE_OK;
CPOOL_LOCK(cpool, data);
cpool_foreach(data, cpool, &data->progress.now, conn_upkeep);
cpool_foreach(data, cpool, NULL, conn_upkeep);
CPOOL_UNLOCK(cpool, data);
return CURLE_OK;
}