From: Stefan Eissing Date: Thu, 18 Dec 2025 12:55:07 +0000 (+0100) Subject: time-keeping: keep timestamp in multi, always update X-Git-Tag: rc-8_18_0-3~72 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b4be1f271e8e2010be89b1cc243fc516cc00ac80;p=thirdparty%2Fcurl.git 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 --- diff --git a/docs/internals/TIME-KEEPING.md b/docs/internals/TIME-KEEPING.md index fc0020d6a4..769c195d1c 100644 --- a/docs/internals/TIME-KEEPING.md +++ b/docs/internals/TIME-KEEPING.md @@ -11,10 +11,6 @@ time function is `curlx_now()` and it uses a **monotonic** clock on most platfor ensures that time only ever increases (the timestamps it gives are however not the "real" world clock). -The simplest handling of transfer time would be to just always call `curlx_now()`. However -there is a performance penalty to that - varying by platform - so this is not a desirable -strategy. Processing thousands of transfers in a loop needs a smarter approach. - ## Initial Approach (now historic) The loop processing functions called `curlx_now()` at the beginning and then passed @@ -34,49 +30,16 @@ in the correct order: *queue -> nameloopup -> connect -> appconnect ->...*.) The strategy of handling transfer's time is now: -* Keep a "now" timestamp in `data->progress.now`. -* Perform time checks and event recording using `data->progress.now`. -* Set `data->progress.now` at the start of API calls (e.g. `curl_multi_perform()`, etc.). -* Set `data->progress.now` when recorded events happen (for precision). -* Set `data->progress.now` on multi state changes. -* Set `data->progress.now` in `pingpong` timeout handling, since `pingpong` is old and not always non-blocking. - -In addition to *setting* `data->progress.now` this timestamp can be *advanced* using 2 new methods: - -* `Curl_pgrs_now_at_least(data, &now)`: code that has a "now" timestamp can progress the `data`'s own "now" to be at least as new. If `data->progress.now` is already newer, no change is done. A transfer never goes **back**. -* `Curl_pgrs_now_update(data1, data2)`: update the "now" in `data1` to be at least as new as the one in `data2`. If it already is newer, nothing changes. - -### Time Advancing Loops - -This advancing is used in the following way in loop like `curl_multi_perform()`: - -```C -struct curltime now = curlx_now(); /* start of API call */ -forall data in transfers { - Curl_pgrs_set_at_least(data, now); - progress(data); /* may update "now" */ - now = data->progress.now; -} -``` - -Transfers that update their "now" pass that timestamp to the next transfer processed. - -### Transfers triggering other transfers - -In HTTP/2 and HTTP/3 processing, incoming data causes actions on transfers other than -the calling one. The protocols may receive data for any transfer on the connection and need -to dispatch it: - -* a Close/Reset comes in for another transfer. That transfer is marked as "dirty", making sure it is processed in a timely manner. -* Response Data arrives: this data is written out to the client. Before this is done, the "now" timestamp is updated via `Curl_pgrs_now_update(data, calling)` from the "calling" transfer. - -## Blocking Operations +* 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). -We still have places in `libcurl` where we do blocking operations. We should always use `Curl_pgrs_now_set(data)` afterwards since we cannot be sure how much time has passed. Since loop processing passed an updated "now" to the next transfer, a delay due to blocking is passed on. +This has the following advantages: -There are other places where we may lose track of time: +* No need to pass a `struct curltime` around or pass a pointer to an outdated timestamp to other functions. +* No need to calculate the exact `now` until it is really used. +* Passing a `const` pointer is better than struct passing. Updating and passing a pointer to the same memory location for all transfers is even better. -* Cache/Pool Locks: no "now" updates happen after a lock has been acquired. These locks should not be kept for a longer time. -* User Callbacks: no "now" updates happen after callbacks have been invoked. The expectation is that those do not take long. +Caveats: -Should these assumptions prove wrong, we need to add updates. +* do not store the pointer returned by `Curl_pgrs_now(data)` anywhere that outlives the current code invocation. diff --git a/lib/asyn-ares.c b/lib/asyn-ares.c index 81b7090f22..a7704d1ca6 100644 --- a/lib/asyn-ares.c +++ b/lib/asyn-ares.c @@ -311,7 +311,8 @@ CURLcode Curl_async_is_resolved(struct Curl_easy *data, /* This is only set to non-zero if the timer was started. */ (ares->happy_eyeballs_dns_time.tv_sec || ares->happy_eyeballs_dns_time.tv_usec) && - (curlx_timediff_ms(data->progress.now, ares->happy_eyeballs_dns_time) >= + (curlx_ptimediff_ms(Curl_pgrs_now(data), + &ares->happy_eyeballs_dns_time) >= HAPPY_EYEBALLS_DNS_TIMEOUT)) { /* Remember that the EXPIRE_HAPPY_EYEBALLS_DNS timer is no longer running. */ @@ -439,14 +440,13 @@ CURLcode Curl_async_await(struct Curl_easy *data, result = CURLE_ABORTED_BY_CALLBACK; else { struct curltime now = curlx_now(); /* update in loop */ - timediff_t elapsed_ms = curlx_timediff_ms(now, data->progress.now); + timediff_t elapsed_ms = curlx_ptimediff_ms(&now, Curl_pgrs_now(data)); if(elapsed_ms <= 0) timeout_ms -= 1; /* always deduct at least 1 */ else if(elapsed_ms > timeout_ms) timeout_ms = -1; else timeout_ms -= elapsed_ms; - Curl_pgrs_now_at_least(data, &now); } if(timeout_ms < 0) result = CURLE_OPERATION_TIMEDOUT; @@ -582,7 +582,7 @@ static void async_ares_hostbyname_cb(void *user_data, timeout to prevent it. After all, we do not even know where in the c-ares retry cycle each request is. */ - ares->happy_eyeballs_dns_time = data->progress.now; + ares->happy_eyeballs_dns_time = *Curl_pgrs_now(data); Curl_expire(data, HAPPY_EYEBALLS_DNS_TIMEOUT, EXPIRE_HAPPY_EYEBALLS_DNS); } } diff --git a/lib/asyn-thrdd.c b/lib/asyn-thrdd.c index 408f05844d..a2656f64cb 100644 --- a/lib/asyn-thrdd.c +++ b/lib/asyn-thrdd.c @@ -63,6 +63,7 @@ #include "url.h" #include "multiif.h" #include "curl_threads.h" +#include "progress.h" #include "select.h" #ifdef USE_ARES @@ -442,7 +443,7 @@ static bool async_thrdd_init(struct Curl_easy *data, /* passing addr_ctx to the thread adds a reference */ addr_ctx->ref_count = 2; - addr_ctx->start = data->progress.now; + addr_ctx->start = *Curl_pgrs_now(data); #ifdef HAVE_GETADDRINFO addr_ctx->thread_hnd = Curl_thread_create(getaddrinfo_thread, addr_ctx); @@ -655,8 +656,8 @@ CURLcode Curl_async_is_resolved(struct Curl_easy *data, else { /* poll for name lookup done with exponential backoff up to 250ms */ /* should be fine even if this converts to 32-bit */ - timediff_t elapsed = curlx_timediff_ms(data->progress.now, - data->progress.t_startsingle); + timediff_t elapsed = curlx_ptimediff_ms(Curl_pgrs_now(data), + &data->progress.t_startsingle); if(elapsed < 0) elapsed = 0; @@ -706,7 +707,8 @@ CURLcode Curl_async_pollset(struct Curl_easy *data, struct easy_pollset *ps) result = Curl_pollset_add_in(data, ps, thrdd->addr->sock_pair[0]); #else timediff_t milli; - timediff_t ms = curlx_timediff_ms(data->progress.now, thrdd->addr->start); + timediff_t ms = + curlx_ptimediff_ms(Curl_pgrs_now(data), &thrdd->addr->start); if(ms < 3) milli = 0; else if(ms <= 50) diff --git a/lib/cf-https-connect.c b/lib/cf-https-connect.c index 104df248eb..849b45c773 100644 --- a/lib/cf-https-connect.c +++ b/lib/cf-https-connect.c @@ -35,6 +35,7 @@ #include "multiif.h" #include "cf-https-connect.h" #include "http2.h" +#include "progress.h" #include "select.h" #include "vquic/vquic.h" @@ -149,7 +150,7 @@ static void cf_hc_baller_init(struct cf_hc_baller *b, struct Curl_cfilter *save = cf->next; cf->next = NULL; - b->started = data->progress.now; + b->started = *Curl_pgrs_now(data); switch(b->alpn_id) { case ALPN_h3: transport = TRNSPRT_QUIC; @@ -212,12 +213,12 @@ static CURLcode baller_connected(struct Curl_cfilter *cf, if(reply_ms >= 0) CURL_TRC_CF(data, cf, "connect+handshake %s: %dms, 1st data: %dms", winner->name, - (int)curlx_timediff_ms(data->progress.now, - winner->started), reply_ms); + (int)curlx_ptimediff_ms(Curl_pgrs_now(data), + &winner->started), reply_ms); else CURL_TRC_CF(data, cf, "deferred handshake %s: %dms", - winner->name, (int)curlx_timediff_ms(data->progress.now, - winner->started)); + winner->name, (int)curlx_ptimediff_ms(Curl_pgrs_now(data), + &winner->started)); /* install the winning filter below this one. */ cf->next = winner->cf; @@ -265,7 +266,7 @@ static bool time_to_start_next(struct Curl_cfilter *cf, ctx->ballers[idx].name); return TRUE; } - elapsed_ms = curlx_timediff_ms(now, ctx->started); + elapsed_ms = curlx_ptimediff_ms(&now, &ctx->started); if(elapsed_ms >= ctx->hard_eyeballs_timeout_ms) { CURL_TRC_CF(data, cf, "hard timeout of %" FMT_TIMEDIFF_T "ms reached, " "starting %s", @@ -308,7 +309,7 @@ static CURLcode cf_hc_connect(struct Curl_cfilter *cf, for(i = 0; i < ctx->baller_count; i++) DEBUGASSERT(!ctx->ballers[i].cf); CURL_TRC_CF(data, cf, "connect, init"); - ctx->started = data->progress.now; + ctx->started = *Curl_pgrs_now(data); cf_hc_baller_init(&ctx->ballers[0], cf, data, ctx->ballers[0].transport); if(ctx->baller_count > 1) { Curl_expire(data, ctx->soft_eyeballs_timeout_ms, EXPIRE_ALPN_EYEBALLS); @@ -327,7 +328,7 @@ static CURLcode cf_hc_connect(struct Curl_cfilter *cf, } } - if(time_to_start_next(cf, data, 1, data->progress.now)) { + if(time_to_start_next(cf, data, 1, *Curl_pgrs_now(data))) { cf_hc_baller_init(&ctx->ballers[1], cf, data, ctx->ballers[1].transport); } @@ -468,7 +469,7 @@ static struct curltime cf_get_max_baller_time(struct Curl_cfilter *cf, struct Curl_cfilter *cfb = ctx->ballers[i].cf; memset(&t, 0, sizeof(t)); if(cfb && !cfb->cft->query(cfb, data, query, NULL, &t)) { - if((t.tv_sec || t.tv_usec) && curlx_timediff_us(t, tmax) > 0) + if((t.tv_sec || t.tv_usec) && curlx_ptimediff_us(&t, &tmax) > 0) tmax = t; } } diff --git a/lib/cf-ip-happy.c b/lib/cf-ip-happy.c index d6501d0079..36d53ed9c2 100644 --- a/lib/cf-ip-happy.c +++ b/lib/cf-ip-happy.c @@ -393,7 +393,7 @@ evaluate: /* no attempt connected yet, start another one? */ if(!ongoing) { if(!bs->started.tv_sec && !bs->started.tv_usec) - bs->started = data->progress.now; + bs->started = *Curl_pgrs_now(data); do_more = TRUE; } else { @@ -403,7 +403,7 @@ evaluate: more_possible = cf_ai_iter_has_more(&bs->ipv6_iter); #endif do_more = more_possible && - (curlx_timediff_ms(data->progress.now, bs->last_attempt_started) >= + (curlx_ptimediff_ms(Curl_pgrs_now(data), &bs->last_attempt_started) >= bs->attempt_delay_ms); if(do_more) CURL_TRC_CF(data, cf, "happy eyeballs timeout expired, " @@ -442,7 +442,7 @@ evaluate: while(*panchor) panchor = &((*panchor)->next); *panchor = a; - bs->last_attempt_started = data->progress.now; + bs->last_attempt_started = *Curl_pgrs_now(data); bs->last_attempt_ai_family = ai_family; /* and run everything again */ goto evaluate; @@ -451,7 +451,7 @@ evaluate: /* tried all addresses, no success but some where inconclusive. * Let's restart the inconclusive ones. */ timediff_t since_ms = - curlx_timediff_ms(data->progress.now, bs->last_attempt_started); + curlx_ptimediff_ms(Curl_pgrs_now(data), &bs->last_attempt_started); timediff_t delay_ms = bs->attempt_delay_ms - since_ms; if(delay_ms <= 0) { CURL_TRC_CF(data, cf, "all attempts inconclusive, restarting one"); @@ -464,7 +464,7 @@ evaluate: CURL_TRC_CF(data, cf, "restarted baller %d -> %d", i, result); if(result) /* serious failure */ goto out; - bs->last_attempt_started = data->progress.now; + bs->last_attempt_started = *Curl_pgrs_now(data); goto evaluate; } DEBUGASSERT(0); /* should not come here */ @@ -499,7 +499,8 @@ out: next_expire_ms = Curl_timeleft_ms(data, TRUE); if(next_expire_ms <= 0) { failf(data, "Connection timeout after %" FMT_OFF_T " ms", - curlx_timediff_ms(data->progress.now, data->progress.t_startsingle)); + curlx_ptimediff_ms(Curl_pgrs_now(data), + &data->progress.t_startsingle)); return CURLE_OPERATION_TIMEDOUT; } @@ -511,7 +512,7 @@ out: if(more_possible) { timediff_t expire_ms, elapsed_ms; elapsed_ms = - curlx_timediff_ms(data->progress.now, bs->last_attempt_started); + curlx_ptimediff_ms(Curl_pgrs_now(data), &bs->last_attempt_started); expire_ms = CURLMAX(bs->attempt_delay_ms - elapsed_ms, 0); next_expire_ms = CURLMIN(next_expire_ms, expire_ms); if(next_expire_ms <= 0) { @@ -587,7 +588,7 @@ static struct curltime cf_ip_ballers_max_time(struct cf_ip_ballers *bs, for(a = bs->running; a; a = a->next) { memset(&t, 0, sizeof(t)); if(!a->cf->cft->query(a->cf, data, query, NULL, &t)) { - if((t.tv_sec || t.tv_usec) && curlx_timediff_us(t, tmax) > 0) + if((t.tv_sec || t.tv_usec) && curlx_ptimediff_us(&t, &tmax) > 0) tmax = t; } } @@ -672,7 +673,8 @@ static CURLcode is_connected(struct Curl_cfilter *cf, proxy_name ? "via " : "", proxy_name ? proxy_name : "", proxy_name ? " " : "", - curlx_timediff_ms(data->progress.now, data->progress.t_startsingle), + curlx_ptimediff_ms(Curl_pgrs_now(data), + &data->progress.t_startsingle), curl_easy_strerror(result)); } @@ -704,7 +706,7 @@ static CURLcode start_connect(struct Curl_cfilter *cf, } CURL_TRC_CF(data, cf, "init ip ballers for transport %u", ctx->transport); - ctx->started = data->progress.now; + ctx->started = *Curl_pgrs_now(data); return cf_ip_ballers_init(&ctx->ballers, cf->conn->ip_version, dns->addr, ctx->cf_create, ctx->transport, data->set.happy_eyeballs_timeout); diff --git a/lib/cf-socket.c b/lib/cf-socket.c index 4e122093cd..121dcd4ec2 100644 --- a/lib/cf-socket.c +++ b/lib/cf-socket.c @@ -1081,7 +1081,7 @@ static CURLcode cf_socket_open(struct Curl_cfilter *cf, (void)data; DEBUGASSERT(ctx->sock == CURL_SOCKET_BAD); - ctx->started_at = data->progress.now; + ctx->started_at = *Curl_pgrs_now(data); #ifdef SOCK_NONBLOCK /* Do not tuck SOCK_NONBLOCK into socktype when opensocket callback is set * because we would not know how socketype is about to be used in the @@ -1208,7 +1208,7 @@ out: } else if(isconnected) { set_local_ip(cf, data); - ctx->connected_at = data->progress.now; + ctx->connected_at = *Curl_pgrs_now(data); cf->connected = TRUE; } CURL_TRC_CF(data, cf, "cf_socket_open() -> %d, fd=%" FMT_SOCKET_T, @@ -1327,7 +1327,7 @@ static CURLcode cf_tcp_connect(struct Curl_cfilter *cf, else if(rc == CURL_CSELECT_OUT || cf->conn->bits.tcp_fastopen) { if(verifyconnect(ctx->sock, &ctx->error)) { /* we are connected with TCP, awesome! */ - ctx->connected_at = data->progress.now; + ctx->connected_at = *Curl_pgrs_now(data); set_local_ip(cf, data); *done = TRUE; cf->connected = TRUE; @@ -1409,7 +1409,8 @@ static void win_update_sndbuf_size(struct Curl_easy *data, ULONG ideal; DWORD ideallen; - if(curlx_timediff_ms(data->progress.now, ctx->last_sndbuf_query_at) > 1000) { + if(curlx_ptimediff_ms(Curl_pgrs_now(data), + &ctx->last_sndbuf_query_at) > 1000) { if(!WSAIoctl(ctx->sock, SIO_IDEAL_SEND_BACKLOG_QUERY, 0, 0, &ideal, sizeof(ideal), &ideallen, 0, 0) && ideal != ctx->sndbuf_size && @@ -1417,7 +1418,7 @@ static void win_update_sndbuf_size(struct Curl_easy *data, (const char *)&ideal, sizeof(ideal))) { ctx->sndbuf_size = ideal; } - ctx->last_sndbuf_query_at = data->progress.now; + ctx->last_sndbuf_query_at = *Curl_pgrs_now(data); } } @@ -1564,7 +1565,7 @@ static CURLcode cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data, CURL_TRC_CF(data, cf, "recv(len=%zu) -> %d, %zu", len, result, *pnread); if(!result && !ctx->got_first_byte) { - ctx->first_byte_at = data->progress.now; + ctx->first_byte_at = *Curl_pgrs_now(data); ctx->got_first_byte = TRUE; } return result; @@ -1678,7 +1679,8 @@ static CURLcode cf_socket_query(struct Curl_cfilter *cf, return CURLE_OK; case CF_QUERY_CONNECT_REPLY_MS: if(ctx->got_first_byte) { - timediff_t ms = curlx_timediff_ms(ctx->first_byte_at, ctx->started_at); + timediff_t ms = curlx_ptimediff_ms(&ctx->first_byte_at, + &ctx->started_at); *pres1 = (ms < INT_MAX) ? (int)ms : INT_MAX; } else @@ -2011,7 +2013,7 @@ static timediff_t cf_tcp_accept_timeleft(struct Curl_cfilter *cf, timeout_ms = other_ms; else { /* subtract elapsed time */ - timeout_ms -= curlx_timediff_ms(data->progress.now, ctx->started_at); + timeout_ms -= curlx_ptimediff_ms(Curl_pgrs_now(data), &ctx->started_at); if(!timeout_ms) /* avoid returning 0 as that means no timeout! */ timeout_ms = -1; @@ -2147,7 +2149,7 @@ static CURLcode cf_tcp_accept_connect(struct Curl_cfilter *cf, cf_tcp_set_accepted_remote_ip(cf, data); set_local_ip(cf, data); ctx->active = TRUE; - ctx->connected_at = data->progress.now; + ctx->connected_at = *Curl_pgrs_now(data); cf->connected = TRUE; CURL_TRC_CF(data, cf, "accepted_set(sock=%" FMT_SOCKET_T ", remote=%s port=%d)", @@ -2213,7 +2215,7 @@ CURLcode Curl_conn_tcp_listen_set(struct Curl_easy *data, goto out; Curl_conn_cf_add(data, conn, sockindex, cf); - ctx->started_at = data->progress.now; + ctx->started_at = *Curl_pgrs_now(data); conn->sock[sockindex] = ctx->sock; set_local_ip(cf, data); CURL_TRC_CF(data, cf, "set filter for listen socket fd=%" FMT_SOCKET_T diff --git a/lib/cfilters.c b/lib/cfilters.c index 0c259e4439..2ac99a4288 100644 --- a/lib/cfilters.c +++ b/lib/cfilters.c @@ -502,7 +502,7 @@ CURLcode Curl_conn_connect(struct Curl_easy *data, * socket and ip related information. */ cf_cntrl_update_info(data, data->conn); conn_report_connect_stats(cf, data); - data->conn->keepalive = data->progress.now; + data->conn->keepalive = *Curl_pgrs_now(data); #ifndef CURL_DISABLE_VERBOSE_STRINGS result = cf_verboseconnect(data, cf); #endif diff --git a/lib/conncache.c b/lib/conncache.c index d9efb61a07..7e0e2c9084 100644 --- a/lib/conncache.c +++ b/lib/conncache.c @@ -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; } diff --git a/lib/connect.c b/lib/connect.c index 42d5cd7a3f..d9926d8697 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -112,8 +112,9 @@ enum alpnid Curl_str2alpnid(const struct Curl_str *cstr) * @param duringconnect TRUE iff connect timeout is also taken into account. * @unittest: 1303 */ -timediff_t Curl_timeleft_ms(struct Curl_easy *data, - bool duringconnect) +timediff_t Curl_timeleft_now_ms(struct Curl_easy *data, + const struct curltime *pnow, + bool duringconnect) { timediff_t timeleft_ms = 0; timediff_t ctimeleft_ms = 0; @@ -129,7 +130,7 @@ timediff_t Curl_timeleft_ms(struct Curl_easy *data, if(data->set.timeout) { timeleft_ms = data->set.timeout - - curlx_timediff_ms(data->progress.now, data->progress.t_startop); + curlx_ptimediff_ms(pnow, &data->progress.t_startop); if(!timeleft_ms) timeleft_ms = -1; /* 0 is "no limit", fake 1 ms expiry */ } @@ -139,7 +140,7 @@ timediff_t Curl_timeleft_ms(struct Curl_easy *data, ctimeout_ms = (data->set.connecttimeout > 0) ? data->set.connecttimeout : DEFAULT_CONNECT_TIMEOUT; ctimeleft_ms = ctimeout_ms - - curlx_timediff_ms(data->progress.now, data->progress.t_startsingle); + curlx_ptimediff_ms(pnow, &data->progress.t_startsingle); if(!ctimeleft_ms) ctimeleft_ms = -1; /* 0 is "no limit", fake 1 ms expiry */ if(!timeleft_ms) @@ -149,13 +150,19 @@ timediff_t Curl_timeleft_ms(struct Curl_easy *data, return (ctimeleft_ms < timeleft_ms) ? ctimeleft_ms : timeleft_ms; } +timediff_t Curl_timeleft_ms(struct Curl_easy *data, + bool duringconnect) +{ + return Curl_timeleft_now_ms(data, Curl_pgrs_now(data), duringconnect); +} + void Curl_shutdown_start(struct Curl_easy *data, int sockindex, int timeout_ms) { struct connectdata *conn = data->conn; DEBUGASSERT(conn); - conn->shutdown.start[sockindex] = data->progress.now; + conn->shutdown.start[sockindex] = *Curl_pgrs_now(data); conn->shutdown.timeout_ms = (timeout_ms > 0) ? (timediff_t)timeout_ms : ((data->set.shutdowntimeout > 0) ? @@ -176,8 +183,8 @@ timediff_t Curl_shutdown_timeleft(struct Curl_easy *data, return 0; /* not started or no limits */ left_ms = conn->shutdown.timeout_ms - - curlx_timediff_ms(data->progress.now, - conn->shutdown.start[sockindex]); + curlx_ptimediff_ms(Curl_pgrs_now(data), + &conn->shutdown.start[sockindex]); return left_ms ? left_ms : -1; } diff --git a/lib/connect.h b/lib/connect.h index 09776e636f..5b59c6cf25 100644 --- a/lib/connect.h +++ b/lib/connect.h @@ -40,6 +40,9 @@ enum alpnid Curl_str2alpnid(const struct Curl_str *str); to the timeouts set */ timediff_t Curl_timeleft_ms(struct Curl_easy *data, bool duringconnect); +timediff_t Curl_timeleft_now_ms(struct Curl_easy *data, + const struct curltime *pnow, + bool duringconnect); #define DEFAULT_CONNECT_TIMEOUT 300000 /* milliseconds == five minutes */ diff --git a/lib/cshutdn.c b/lib/cshutdn.c index 21ab1209eb..4a403b261e 100644 --- a/lib/cshutdn.c +++ b/lib/cshutdn.c @@ -266,7 +266,7 @@ static void cshutdn_terminate_all(struct cshutdn *cshutdn, struct Curl_easy *data, int timeout_ms) { - struct curltime started = data->progress.now; + struct curltime started = *Curl_pgrs_now(data); struct Curl_llist_node *e; SIGPIPE_VARIABLE(pipe_st); @@ -289,8 +289,7 @@ static void cshutdn_terminate_all(struct cshutdn *cshutdn, } /* wait for activity, timeout or "nothing" */ - Curl_pgrs_now_set(data); /* update in loop */ - spent_ms = curlx_timediff_ms(data->progress.now, started); + spent_ms = curlx_ptimediff_ms(Curl_pgrs_now(data), &started); if(spent_ms >= (timediff_t)timeout_ms) { CURL_TRC_M(data, "[SHUTDOWN] shutdown finished, %s", (timeout_ms > 0) ? "timeout" : "best effort done"); diff --git a/lib/curl_trc.c b/lib/curl_trc.c index 8308f49c5d..d9932ae7f0 100644 --- a/lib/curl_trc.c +++ b/lib/curl_trc.c @@ -42,6 +42,7 @@ #include "cf-haproxy.h" #include "cf-https-connect.h" #include "cf-ip-happy.h" +#include "progress.h" #include "socks.h" #include "curlx/strparse.h" #include "vtls/vtls.h" @@ -314,11 +315,12 @@ void Curl_trc_easy_timers(struct Curl_easy *data) if(CURL_TRC_TIMER_is_verbose(data)) { struct Curl_llist_node *e = Curl_llist_head(&data->state.timeoutlist); if(e) { + const struct curltime *pnow = Curl_pgrs_now(data); while(e) { struct time_node *n = Curl_node_elem(e); e = Curl_node_next(e); CURL_TRC_TIMER(data, n->eid, "expires in %" FMT_TIMEDIFF_T "ns", - curlx_timediff_us(n->time, data->progress.now)); + curlx_ptimediff_us(&n->time, pnow)); } } } diff --git a/lib/curlx/timeval.c b/lib/curlx/timeval.c index 490dcf0838..d1521ad418 100644 --- a/lib/curlx/timeval.c +++ b/lib/curlx/timeval.c @@ -47,9 +47,8 @@ void curlx_now_init(void) } /* In case of bug fix this function has a counterpart in tool_util.c */ -struct curltime curlx_now(void) +void curlx_pnow(struct curltime *pnow) { - struct curltime now; bool isVistaOrGreater; isVistaOrGreater = Curl_isVistaOrGreater; if(isVistaOrGreater) { /* QPC timer might have issues pre-Vista */ @@ -58,8 +57,8 @@ struct curltime curlx_now(void) freq = Curl_freq; DEBUGASSERT(freq.QuadPart); QueryPerformanceCounter(&count); - now.tv_sec = (time_t)(count.QuadPart / freq.QuadPart); - now.tv_usec = (int)((count.QuadPart % freq.QuadPart) * 1000000 / + pnow->tv_sec = (time_t)(count.QuadPart / freq.QuadPart); + pnow->tv_usec = (int)((count.QuadPart % freq.QuadPart) * 1000000 / freq.QuadPart); } else { @@ -73,16 +72,15 @@ struct curltime curlx_now(void) #pragma warning(pop) #endif - now.tv_sec = (time_t)(milliseconds / 1000); - now.tv_usec = (int)((milliseconds % 1000) * 1000); + pnow->tv_sec = (time_t)(milliseconds / 1000); + pnow->tv_usec = (int)((milliseconds % 1000) * 1000); } - return now; } #elif defined(HAVE_CLOCK_GETTIME_MONOTONIC) || \ defined(HAVE_CLOCK_GETTIME_MONOTONIC_RAW) -struct curltime curlx_now(void) +void curlx_pnow(struct curltime *pnow) { /* ** clock_gettime() is granted to be increased monotonically when the @@ -94,7 +92,6 @@ struct curltime curlx_now(void) #ifdef HAVE_GETTIMEOFDAY struct timeval now; #endif - struct curltime cnow; struct timespec tsnow; /* @@ -116,8 +113,8 @@ struct curltime curlx_now(void) have_clock_gettime && #endif (clock_gettime(CLOCK_MONOTONIC_RAW, &tsnow) == 0)) { - cnow.tv_sec = tsnow.tv_sec; - cnow.tv_usec = (int)(tsnow.tv_nsec / 1000); + pnow->tv_sec = tsnow.tv_sec; + pnow->tv_usec = (int)(tsnow.tv_nsec / 1000); } else #endif @@ -128,8 +125,8 @@ struct curltime curlx_now(void) have_clock_gettime && #endif (clock_gettime(CLOCK_MONOTONIC, &tsnow) == 0)) { - cnow.tv_sec = tsnow.tv_sec; - cnow.tv_usec = (int)(tsnow.tv_nsec / 1000); + pnow->tv_sec = tsnow.tv_sec; + pnow->tv_usec = (int)(tsnow.tv_nsec / 1000); } /* ** Even when the configure process has truly detected monotonic clock @@ -139,16 +136,15 @@ struct curltime curlx_now(void) #ifdef HAVE_GETTIMEOFDAY else { (void)gettimeofday(&now, NULL); - cnow.tv_sec = now.tv_sec; - cnow.tv_usec = (int)now.tv_usec; + pnow->tv_sec = now.tv_sec; + pnow->tv_usec = (int)now.tv_usec; } #else else { - cnow.tv_sec = time(NULL); - cnow.tv_usec = 0; + pnow->tv_sec = time(NULL); + pnow->tv_usec = 0; } #endif - return cnow; } #elif defined(HAVE_MACH_ABSOLUTE_TIME) @@ -156,7 +152,7 @@ struct curltime curlx_now(void) #include #include -struct curltime curlx_now(void) +void curlx_pnow(struct curltime *pnow) { /* ** Monotonic timer on macOS is provided by mach_absolute_time(), which @@ -165,7 +161,6 @@ struct curltime curlx_now(void) ** mach_timebase_info(). */ static mach_timebase_info_data_t timebase; - struct curltime cnow; uint64_t usecs; if(timebase.denom == 0) @@ -176,15 +171,13 @@ struct curltime curlx_now(void) usecs /= timebase.denom; usecs /= 1000; - cnow.tv_sec = usecs / 1000000; - cnow.tv_usec = (int)(usecs % 1000000); - - return cnow; + pnow->tv_sec = usecs / 1000000; + pnow->tv_usec = (int)(usecs % 1000000); } #elif defined(HAVE_GETTIMEOFDAY) -struct curltime curlx_now(void) +void curlx_pnow(struct curltime *pnow) { /* ** gettimeofday() is not granted to be increased monotonically, due to @@ -192,42 +185,52 @@ struct curltime curlx_now(void) ** forward or backward in time. */ struct timeval now; - struct curltime ret; (void)gettimeofday(&now, NULL); - ret.tv_sec = now.tv_sec; - ret.tv_usec = (int)now.tv_usec; - return ret; + pnow->tv_sec = now.tv_sec; + pnow->tv_usec = (int)now.tv_usec; } #else -struct curltime curlx_now(void) +void curlx_pnow(struct curltime *pnow) { /* ** time() returns the value of time in seconds since the Epoch. */ - struct curltime now; - now.tv_sec = time(NULL); - now.tv_usec = 0; - return now; + pnow->tv_sec = time(NULL); + pnow->tv_usec = 0; } #endif +struct curltime curlx_now(void) +{ + struct curltime now; + curlx_pnow(&now); + return now; +} + /* * Returns: time difference in number of milliseconds. For too large diffs it * returns max value. * * @unittest: 1323 */ -timediff_t curlx_timediff_ms(struct curltime newer, struct curltime older) +timediff_t curlx_ptimediff_ms(const struct curltime *newer, + const struct curltime *older) { - timediff_t diff = (timediff_t)newer.tv_sec - older.tv_sec; + timediff_t diff = (timediff_t)newer->tv_sec - older->tv_sec; if(diff >= (TIMEDIFF_T_MAX / 1000)) return TIMEDIFF_T_MAX; else if(diff <= (TIMEDIFF_T_MIN / 1000)) return TIMEDIFF_T_MIN; - return diff * 1000 + (newer.tv_usec - older.tv_usec) / 1000; + return diff * 1000 + (newer->tv_usec - older->tv_usec) / 1000; +} + + +timediff_t curlx_timediff_ms(struct curltime newer, struct curltime older) +{ + return curlx_ptimediff_ms(&newer, &older); } /* @@ -249,14 +252,20 @@ timediff_t curlx_timediff_ceil_ms(struct curltime newer, * Returns: time difference in number of microseconds. For too large diffs it * returns max value. */ -timediff_t curlx_timediff_us(struct curltime newer, struct curltime older) +timediff_t curlx_ptimediff_us(const struct curltime *newer, + const struct curltime *older) { - timediff_t diff = (timediff_t)newer.tv_sec - older.tv_sec; + timediff_t diff = (timediff_t)newer->tv_sec - older->tv_sec; if(diff >= (TIMEDIFF_T_MAX / 1000000)) return TIMEDIFF_T_MAX; else if(diff <= (TIMEDIFF_T_MIN / 1000000)) return TIMEDIFF_T_MIN; - return diff * 1000000 + newer.tv_usec - older.tv_usec; + return diff * 1000000 + newer->tv_usec - older->tv_usec; +} + +timediff_t curlx_timediff_us(struct curltime newer, struct curltime older) +{ + return curlx_ptimediff_us(&newer, &older); } #if defined(__MINGW32__) && (__MINGW64_VERSION_MAJOR <= 3) diff --git a/lib/curlx/timeval.h b/lib/curlx/timeval.h index 9cb57af2b7..533e80e5e3 100644 --- a/lib/curlx/timeval.h +++ b/lib/curlx/timeval.h @@ -39,6 +39,7 @@ void curlx_now_init(void); #endif struct curltime curlx_now(void); +void curlx_pnow(struct curltime *pnow); /* * Make sure that the first argument (newer) is the more recent time and older @@ -47,6 +48,8 @@ struct curltime curlx_now(void); * Returns: the time difference in number of milliseconds. */ timediff_t curlx_timediff_ms(struct curltime newer, struct curltime older); +timediff_t curlx_ptimediff_ms(const struct curltime *newer, + const struct curltime *older); /* * Make sure that the first argument (newer) is the more recent time and older @@ -64,6 +67,8 @@ timediff_t curlx_timediff_ceil_ms(struct curltime newer, * Returns: the time difference in number of microseconds. */ timediff_t curlx_timediff_us(struct curltime newer, struct curltime older); +timediff_t curlx_ptimediff_us(const struct curltime *newer, + const struct curltime *older); CURLcode curlx_gmtime(time_t intime, struct tm *store); diff --git a/lib/easy.c b/lib/easy.c index d7d766a4f8..e86f7f7404 100644 --- a/lib/easy.c +++ b/lib/easy.c @@ -607,11 +607,11 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev) CURLMsg *msg; struct pollfd fds[4]; int pollrc; - struct curltime before; + struct curltime start; const unsigned int numfds = populate_fds(fds, ev); /* get the time stamp to use to figure out how long poll takes */ - before = curlx_now(); + curlx_pnow(&start); result = poll_fds(ev, fds, numfds, &pollrc); if(result) @@ -647,7 +647,7 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev) /* If nothing updated the timeout, we decrease it by the spent time. * If it was updated, it has the new timeout time stored already. */ - timediff_t spent_ms = curlx_timediff_ms(curlx_now(), before); + timediff_t spent_ms = curlx_timediff_ms(curlx_now(), start); if(spent_ms > 0) { #if DEBUG_EV_POLL curl_mfprintf(stderr, "poll timeout %ldms not updated, decrease by " @@ -995,7 +995,6 @@ CURL *curl_easy_duphandle(CURL *d) if(dupset(outcurl, data)) goto fail; - Curl_pgrs_now_set(outcurl); /* start of API call */ outcurl->progress.hide = data->progress.hide; outcurl->progress.callback = data->progress.callback; @@ -1155,7 +1154,6 @@ CURLcode curl_easy_pause(CURL *d, int action) if(Curl_is_in_callback(data)) recursive = TRUE; - Curl_pgrs_now_set(data); /* start of API call */ recv_paused = Curl_xfer_recv_is_paused(data); recv_paused_new = (action & CURLPAUSE_RECV); send_paused = Curl_xfer_send_is_paused(data); @@ -1180,7 +1178,7 @@ CURLcode curl_easy_pause(CURL *d, int action) Curl_multi_mark_dirty(data); /* make it run */ /* On changes, tell application to update its timers. */ if(changed) { - if(Curl_update_timer(data->multi, &data->progress.now) && !result) + if(Curl_update_timer(data->multi) && !result) result = CURLE_ABORTED_BY_CALLBACK; } } diff --git a/lib/ftp.c b/lib/ftp.c index 00f3385440..f84ac839f7 100644 --- a/lib/ftp.c +++ b/lib/ftp.c @@ -3179,7 +3179,7 @@ static CURLcode ftp_connect(struct Curl_easy *data, conn->bits.ftp_use_control_ssl = TRUE; } - Curl_pp_init(pp, &data->progress.now); /* once per transfer */ + Curl_pp_init(pp, Curl_pgrs_now(data)); /* once per transfer */ /* When we connect, we start in the state where we await the 220 response */ @@ -3315,7 +3315,7 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status, * data has been transferred. This happens when doing through NATs etc that * abandon old silent connections. */ - pp->response = data->progress.now; /* timeout relative now */ + pp->response = *Curl_pgrs_now(data); /* timeout relative now */ result = getftpresponse(data, &nread, &ftpcode); if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) { @@ -3435,7 +3435,7 @@ static CURLcode ftp_sendquote(struct Curl_easy *data, result = Curl_pp_sendf(data, &ftpc->pp, "%s", cmd); if(!result) { - pp->response = data->progress.now; /* timeout relative now */ + pp->response = *Curl_pgrs_now(data); /* timeout relative now */ result = getftpresponse(data, &nread, &ftpcode); } if(result) diff --git a/lib/hostip.c b/lib/hostip.c index eb59193d2c..b18e5e0bd4 100644 --- a/lib/hostip.c +++ b/lib/hostip.c @@ -57,6 +57,7 @@ #include "multiif.h" #include "doh.h" #include "curlx/warnless.h" +#include "progress.h" #include "select.h" #include "strcase.h" #include "easy_lock.h" @@ -191,7 +192,7 @@ static int dnscache_entry_is_stale(void *datap, void *hc) if(dns->timestamp.tv_sec || dns->timestamp.tv_usec) { /* get age in milliseconds */ - timediff_t age = curlx_timediff_ms(prune->now, dns->timestamp); + timediff_t age = curlx_ptimediff_ms(&prune->now, &dns->timestamp); if(!dns->addr) age *= 2; /* negative entries age twice as fast */ if(age >= prune->max_age_ms) @@ -265,7 +266,7 @@ void Curl_dnscache_prune(struct Curl_easy *data) do { /* Remove outdated and unused entries from the hostcache */ timediff_t oldest_ms = - dnscache_prune(&dnscache->entries, timeout_ms, data->progress.now); + dnscache_prune(&dnscache->entries, timeout_ms, *Curl_pgrs_now(data)); if(Curl_hash_count(&dnscache->entries) > MAX_DNS_CACHE_SIZE) /* prune the ones over half this age */ @@ -331,7 +332,7 @@ static struct Curl_dns_entry *fetch_addr(struct Curl_easy *data, /* See whether the returned entry is stale. Done before we release lock */ struct dnscache_prune_data user; - user.now = data->progress.now; + user.now = *Curl_pgrs_now(data); user.max_age_ms = data->set.dns_cache_timeout_ms; user.oldest_ms = 0; @@ -520,7 +521,7 @@ Curl_dnscache_mk_entry(struct Curl_easy *data, dns->timestamp.tv_usec = 0; /* an entry that never goes stale */ } else { - dns->timestamp = data->progress.now; + dns->timestamp = *Curl_pgrs_now(data); } dns->hostport = port; if(hostlen) @@ -1136,8 +1137,8 @@ clean_up: the time we spent until now! */ if(prev_alarm) { /* there was an alarm() set before us, now put it back */ - timediff_t elapsed_secs = curlx_timediff_ms(data->progress.now, - data->conn->created) / 1000; + timediff_t elapsed_secs = curlx_ptimediff_ms(Curl_pgrs_now(data), + &data->conn->created) / 1000; /* the alarm period is counted in even number of seconds */ unsigned long alarm_set = (unsigned long)(prev_alarm - elapsed_secs); diff --git a/lib/http.c b/lib/http.c index ea62219542..fce6c7ccb8 100644 --- a/lib/http.c +++ b/lib/http.c @@ -4980,7 +4980,7 @@ static CURLcode cr_exp100_read(struct Curl_easy *data, DEBUGF(infof(data, "cr_exp100_read, start AWAITING_CONTINUE, " "timeout %dms", data->set.expect_100_timeout)); ctx->state = EXP100_AWAITING_CONTINUE; - ctx->start = data->progress.now; + ctx->start = *Curl_pgrs_now(data); Curl_expire(data, data->set.expect_100_timeout, EXPIRE_100_TIMEOUT); *nread = 0; *eos = FALSE; @@ -4991,7 +4991,7 @@ static CURLcode cr_exp100_read(struct Curl_easy *data, *eos = FALSE; return CURLE_READ_ERROR; case EXP100_AWAITING_CONTINUE: - ms = curlx_timediff_ms(data->progress.now, ctx->start); + ms = curlx_ptimediff_ms(Curl_pgrs_now(data), &ctx->start); if(ms < data->set.expect_100_timeout) { DEBUGF(infof(data, "cr_exp100_read, AWAITING_CONTINUE, not expired")); *nread = 0; diff --git a/lib/http2.c b/lib/http2.c index dc71f20690..d547cf4894 100644 --- a/lib/http2.c +++ b/lib/http2.c @@ -306,8 +306,8 @@ static void h2_stream_hash_free(unsigned int id, void *stream) static int32_t cf_h2_get_desired_local_win(struct Curl_cfilter *cf, struct Curl_easy *data) { - curl_off_t avail = - Curl_rlimit_avail(&data->progress.dl.rlimit, &data->progress.now); + curl_off_t avail = Curl_rlimit_avail(&data->progress.dl.rlimit, + Curl_pgrs_now(data)); (void)cf; if(avail < CURL_OFF_T_MAX) { /* limit in place */ @@ -1424,7 +1424,7 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags, struct Curl_cfilter *cf = userp; struct cf_h2_ctx *ctx = cf->ctx; struct h2_stream_ctx *stream; - struct Curl_easy *data_s, *calling = CF_DATA_CURRENT(cf); + struct Curl_easy *data_s; (void)flags; DEBUGASSERT(stream_id); /* should never be a zero stream ID here */ @@ -1445,8 +1445,6 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags, stream = H2_STREAM_CTX(ctx, data_s); if(!stream) return NGHTTP2_ERR_CALLBACK_FAILURE; - if(calling) - Curl_pgrs_now_update(data_s, calling); h2_xfer_write_resp(cf, data_s, stream, (const char *)mem, len, FALSE); diff --git a/lib/imap.c b/lib/imap.c index 8b8bd9ca03..1547d9f7e9 100644 --- a/lib/imap.c +++ b/lib/imap.c @@ -1994,7 +1994,7 @@ static CURLcode imap_setup_connection(struct Curl_easy *data, Curl_sasl_init(&imapc->sasl, data, &saslimap); curlx_dyn_init(&imapc->dyn, DYN_IMAP_CMD); - Curl_pp_init(pp, &data->progress.now); + Curl_pp_init(pp, Curl_pgrs_now(data)); if(Curl_conn_meta_set(conn, CURL_META_IMAP_CONN, imapc, imap_conn_dtor)) return CURLE_OUT_OF_MEMORY; diff --git a/lib/mqtt.c b/lib/mqtt.c index bd6d25331d..7587d373b6 100644 --- a/lib/mqtt.c +++ b/lib/mqtt.c @@ -186,7 +186,7 @@ static CURLcode mqtt_send(struct Curl_easy *data, result = Curl_xfer_send(data, buf, len, FALSE, &n); if(result) return result; - mq->lastTime = data->progress.now; + mq->lastTime = *Curl_pgrs_now(data); Curl_debug(data, CURLINFO_HEADER_OUT, buf, n); if(len != n) { size_t nsend = len - n; @@ -770,7 +770,7 @@ MQTT_SUBACK_COMING: } /* we received something */ - mq->lastTime = data->progress.now; + mq->lastTime = *Curl_pgrs_now(data); /* if QoS is set, message contains packet id */ result = Curl_client_write(data, CLIENTWRITE_BODY, buffer, nread); @@ -800,7 +800,7 @@ static CURLcode mqtt_do(struct Curl_easy *data, bool *done) if(!mq) return CURLE_FAILED_INIT; - mq->lastTime = data->progress.now; + mq->lastTime = *Curl_pgrs_now(data); mq->pingsent = FALSE; result = mqtt_connect(data); @@ -839,8 +839,8 @@ static CURLcode mqtt_ping(struct Curl_easy *data) if(mqtt->state == MQTT_FIRST && !mq->pingsent && data->set.upkeep_interval_ms > 0) { - struct curltime t = data->progress.now; - timediff_t diff = curlx_timediff_ms(t, mq->lastTime); + struct curltime t = *Curl_pgrs_now(data); + timediff_t diff = curlx_ptimediff_ms(&t, &mq->lastTime); if(diff > data->set.upkeep_interval_ms) { /* 0xC0 is PINGREQ, and 0x00 is remaining length */ @@ -898,7 +898,7 @@ static CURLcode mqtt_doing(struct Curl_easy *data, bool *done) Curl_debug(data, CURLINFO_HEADER_IN, (const char *)&mq->firstbyte, 1); /* we received something */ - mq->lastTime = data->progress.now; + mq->lastTime = *Curl_pgrs_now(data); /* remember the first byte */ mq->npacket = 0; diff --git a/lib/multi.c b/lib/multi.c index 8d4c6c3da7..289ab0714b 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -81,6 +81,7 @@ #define CURL_MULTI_HANDLE 0x000bab1e + #ifdef DEBUGBUILD /* On a debug build, we want to fail hard on multi handles that * are not NULL, but no longer have the MAGIC touch. This gives @@ -95,11 +96,10 @@ static void move_pending_to_connect(struct Curl_multi *multi, struct Curl_easy *data); -static CURLMcode add_next_timeout(struct curltime now, +static CURLMcode add_next_timeout(const struct curltime *pnow, struct Curl_multi *multi, struct Curl_easy *d); static void multi_timeout(struct Curl_multi *multi, - struct curltime *pnow, struct curltime *expire_time, long *timeout_ms); static void process_pending_handles(struct Curl_multi *multi); @@ -108,6 +108,12 @@ static void multi_xfer_bufs_free(struct Curl_multi *multi); static void multi_xfer_tbl_dump(struct Curl_multi *multi); #endif +static const struct curltime *multi_now(struct Curl_multi *multi) +{ + curlx_pnow(&multi->now); + return &multi->now; +} + /* function pointer called once when switching TO a state */ typedef void (*init_multistate_func)(struct Curl_easy *data); @@ -167,7 +173,6 @@ static void mstate(struct Curl_easy *data, CURLMstate state #endif /* really switching state */ - Curl_pgrs_now_set(data); data->mstate = state; switch(state) { case MSTATE_DONE: @@ -449,7 +454,6 @@ CURLMcode curl_multi_add_handle(CURLM *m, CURL *d) Curl_uint32_bset_clear(&multi->msgsent); } - Curl_pgrs_now_set(data); /* start of API call */ if(data->multi_easy) { /* if this easy handle was previously used for curl_easy_perform(), there is a private multi handle here that we can kill */ @@ -503,7 +507,7 @@ CURLMcode curl_multi_add_handle(CURLM *m, CURL *d) /* Necessary in event based processing, where dirty handles trigger * a timeout callback invocation. */ - mresult = Curl_update_timer(multi, &data->progress.now); + mresult = Curl_update_timer(multi); if(mresult) { data->multi = NULL; /* not anymore */ Curl_uint32_tbl_remove(&multi->xfers, data->mid); @@ -784,7 +788,6 @@ CURLMcode curl_multi_remove_handle(CURLM *m, CURL *d) if(multi->in_callback) return CURLM_RECURSIVE_API_CALL; - Curl_pgrs_now_set(data); /* start of API call */ premature = (data->mstate < MSTATE_COMPLETED); /* If the 'state' is not INIT or COMPLETED, we might need to do something @@ -883,7 +886,7 @@ CURLMcode curl_multi_remove_handle(CURLM *m, CURL *d) process_pending_handles(multi); if(removed_timer) { - mresult = Curl_update_timer(multi, &data->progress.now); + mresult = Curl_update_timer(multi); if(mresult) return mresult; } @@ -951,11 +954,11 @@ static CURLcode multi_adjust_pollset(struct Curl_easy *data, CURLcode result = CURLE_OK; if(ps->n) { - bool send_blocked = - (Curl_rlimit_avail(&data->progress.dl.rlimit, &data->progress.now) <= 0); - bool recv_blocked = - (Curl_rlimit_avail(&data->progress.ul.rlimit, &data->progress.now) <= 0); + const struct curltime *pnow = Curl_pgrs_now(data); + bool send_blocked, recv_blocked; + recv_blocked = (Curl_rlimit_avail(&data->progress.dl.rlimit, pnow) <= 0); + send_blocked = (Curl_rlimit_avail(&data->progress.ul.rlimit, pnow) <= 0); if(send_blocked || recv_blocked) { int i; for(i = 0; i <= SECONDARYSOCKET; ++i) { @@ -1226,7 +1229,6 @@ CURLMcode curl_multi_fdset(CURLM *m, struct Curl_multi *multi = m; struct easy_pollset ps; unsigned int i, mid; - struct curltime now = curlx_now(); /* start of API call */ (void)exc_fd_set; if(!GOOD_MULTI_HANDLE(multi)) @@ -1245,7 +1247,6 @@ CURLMcode curl_multi_fdset(CURLM *m, continue; } - Curl_pgrs_now_at_least(data, &now); Curl_multi_pollset(data, &ps); for(i = 0; i < ps.n; i++) { if(!FDSET_SOCK(ps.sockets[i])) @@ -1287,7 +1288,6 @@ CURLMcode curl_multi_waitfds(CURLM *m, struct Curl_multi *multi = m; struct easy_pollset ps; unsigned int need = 0, mid; - struct curltime now = curlx_now(); /* start of API call */ if(!ufds && (size || !fd_count)) return CURLM_BAD_FUNCTION_ARGUMENT; @@ -1309,7 +1309,6 @@ CURLMcode curl_multi_waitfds(CURLM *m, Curl_uint32_bset_remove(&multi->dirty, mid); continue; } - Curl_pgrs_now_at_least(data, &now); Curl_multi_pollset(data, &ps); need += Curl_waitfds_add_ps(&cwfds, &ps); } while(Curl_uint32_bset_next(&multi->process, mid, &mid)); @@ -1362,7 +1361,6 @@ static CURLMcode multi_wait(struct Curl_multi *multi, unsigned int curl_nfds = 0; /* how many pfds are for curl transfers */ struct Curl_easy *data = NULL; CURLMcode mresult = CURLM_OK; - struct curltime now = curlx_now(); /* start of API call */ uint32_t mid; #ifdef USE_WINSOCK @@ -1395,13 +1393,11 @@ static CURLMcode multi_wait(struct Curl_multi *multi, Curl_uint32_bset_remove(&multi->dirty, mid); continue; } - Curl_pgrs_now_at_least(data, &now); Curl_multi_pollset(data, &ps); if(Curl_pollfds_add_ps(&cpfds, &ps)) { mresult = CURLM_OUT_OF_MEMORY; goto out; } - now = data->progress.now; } while(Curl_uint32_bset_next(&multi->process, mid, &mid)); } @@ -1462,7 +1458,7 @@ static CURLMcode multi_wait(struct Curl_multi *multi, * poll. Collecting the sockets may install new timers by protocols * and connection filters. * Use the shorter one of the internal and the caller requested timeout. */ - multi_timeout(multi, &now, &expire_time, &timeout_internal); + multi_timeout(multi, &expire_time, &timeout_internal); if((timeout_internal >= 0) && (timeout_internal < (long)timeout_ms)) timeout_ms = (int)timeout_internal; @@ -1583,7 +1579,7 @@ static CURLMcode multi_wait(struct Curl_multi *multi, long sleep_ms = 0; /* Avoid busy-looping when there is nothing particular to wait for */ - multi_timeout(multi, &now, &expire_time, &sleep_ms); + multi_timeout(multi, &expire_time, &sleep_ms); if(sleep_ms) { if(sleep_ms > timeout_ms) sleep_ms = timeout_ms; @@ -1780,8 +1776,9 @@ static bool multi_handle_timeout(struct Curl_easy *data, CURLcode *result) { bool connect_timeout = data->mstate < MSTATE_DO; - timediff_t timeout_ms = - Curl_timeleft_ms(data, connect_timeout); + timediff_t timeout_ms; + + timeout_ms = Curl_timeleft_ms(data, connect_timeout); if(timeout_ms < 0) { /* Handle timed out */ struct curltime since; @@ -1791,23 +1788,26 @@ static bool multi_handle_timeout(struct Curl_easy *data, since = data->progress.t_startop; if(data->mstate == MSTATE_RESOLVING) failf(data, "Resolving timed out after %" FMT_TIMEDIFF_T - " milliseconds", curlx_timediff_ms(data->progress.now, since)); + " milliseconds", + curlx_ptimediff_ms(Curl_pgrs_now(data), &since)); else if(data->mstate == MSTATE_CONNECTING) failf(data, "Connection timed out after %" FMT_TIMEDIFF_T - " milliseconds", curlx_timediff_ms(data->progress.now, since)); + " milliseconds", + curlx_ptimediff_ms(Curl_pgrs_now(data), &since)); else { struct SingleRequest *k = &data->req; if(k->size != -1) { failf(data, "Operation timed out after %" FMT_TIMEDIFF_T " milliseconds with %" FMT_OFF_T " out of %" FMT_OFF_T " bytes received", - curlx_timediff_ms(data->progress.now, since), + curlx_ptimediff_ms(Curl_pgrs_now(data), &since), k->bytecount, k->size); } else { failf(data, "Operation timed out after %" FMT_TIMEDIFF_T " milliseconds with %" FMT_OFF_T " bytes received", - curlx_timediff_ms(data->progress.now, since), k->bytecount); + curlx_ptimediff_ms(Curl_pgrs_now(data), &since), + k->bytecount); } } *result = CURLE_OPERATION_TIMEDOUT; @@ -1935,14 +1935,13 @@ static CURLcode multi_follow(struct Curl_easy *data, static CURLcode mspeed_check(struct Curl_easy *data) { + const struct curltime *pnow = Curl_pgrs_now(data); timediff_t recv_wait_ms = 0; timediff_t send_wait_ms = 0; /* check if our send/recv limits require idle waits */ - send_wait_ms = - Curl_rlimit_wait_ms(&data->progress.ul.rlimit, &data->progress.now); - recv_wait_ms = - Curl_rlimit_wait_ms(&data->progress.dl.rlimit, &data->progress.now); + send_wait_ms = Curl_rlimit_wait_ms(&data->progress.ul.rlimit, pnow); + recv_wait_ms = Curl_rlimit_wait_ms(&data->progress.dl.rlimit, pnow); if(send_wait_ms || recv_wait_ms) { if(data->mstate != MSTATE_RATELIMITING) { @@ -2765,11 +2764,10 @@ statemachine_end: } static CURLMcode multi_perform(struct Curl_multi *multi, - struct curltime *pnow, int *running_handles) { CURLMcode returncode = CURLM_OK; - struct Curl_tree *t = NULL; + struct curltime start = *multi_now(multi); uint32_t mid; SIGPIPE_VARIABLE(pipe_st); @@ -2793,9 +2791,7 @@ static CURLMcode multi_perform(struct Curl_multi *multi, continue; } sigpipe_apply(data, &pipe_st); - Curl_pgrs_now_at_least(data, pnow); mresult = multi_runsingle(multi, data); - *pnow = data->progress.now; /* in case transfer updated */ if(mresult) returncode = mresult; } while(Curl_uint32_bset_next(&multi->process, mid, &mid)); @@ -2818,22 +2814,25 @@ static CURLMcode multi_perform(struct Curl_multi *multi, * then and then we risk this loop to remove timers that actually have not * been handled! */ - do { - multi->timetree = Curl_splaygetbest(*pnow, multi->timetree, &t); - if(t) { - /* the removed may have another timeout in queue */ - struct Curl_easy *data = Curl_splayget(t); - (void)add_next_timeout(*pnow, multi, data); - if(data->mstate == MSTATE_PENDING) { - bool stream_unused; - CURLcode result_unused; - if(multi_handle_timeout(data, &stream_unused, &result_unused)) { - infof(data, "PENDING handle timeout"); - move_pending_to_connect(multi, data); + if(multi->timetree) { + struct Curl_tree *t = NULL; + do { + multi->timetree = Curl_splaygetbest(&start, multi->timetree, &t); + if(t) { + /* the removed may have another timeout in queue */ + struct Curl_easy *data = Curl_splayget(t); + (void)add_next_timeout(&start, multi, data); + if(data->mstate == MSTATE_PENDING) { + bool stream_unused; + CURLcode result_unused; + if(multi_handle_timeout(data, &stream_unused, &result_unused)) { + infof(data, "PENDING handle timeout"); + move_pending_to_connect(multi, data); + } } } - } - } while(t); + } while(t); + } if(running_handles) { unsigned int running = Curl_multi_xfers_running(multi); @@ -2841,20 +2840,19 @@ static CURLMcode multi_perform(struct Curl_multi *multi, } if(CURLM_OK >= returncode) - returncode = Curl_update_timer(multi, pnow); + returncode = Curl_update_timer(multi); return returncode; } CURLMcode curl_multi_perform(CURLM *m, int *running_handles) { - struct curltime now = curlx_now(); /* start of API call */ struct Curl_multi *multi = m; if(!GOOD_MULTI_HANDLE(multi)) return CURLM_BAD_HANDLE; - return multi_perform(multi, &now, running_handles); + return multi_perform(multi, running_handles); } CURLMcode curl_multi_cleanup(CURLM *m) @@ -3015,7 +3013,7 @@ void Curl_multi_will_close(struct Curl_easy *data, curl_socket_t s) * The splay tree only has each sessionhandle as a single node and the nearest * timeout is used to sort it on. */ -static CURLMcode add_next_timeout(struct curltime now, +static CURLMcode add_next_timeout(const struct curltime *pnow, struct Curl_multi *multi, struct Curl_easy *d) { @@ -3029,7 +3027,7 @@ static CURLMcode add_next_timeout(struct curltime now, for(e = Curl_llist_head(list); e;) { struct Curl_llist_node *n = Curl_node_next(e); struct time_node *node = Curl_node_elem(e); - timediff_t diff = curlx_timediff_us(node->time, now); + timediff_t diff = curlx_ptimediff_us(&node->time, pnow); if(diff <= 0) /* remove outdated entry */ Curl_node_remove(e); @@ -3052,7 +3050,7 @@ static CURLMcode add_next_timeout(struct curltime now, /* Insert this node again into the splay. Keep the timer in the list in case we need to recompute future timers. */ - multi->timetree = Curl_splayinsert(*tv, multi->timetree, + multi->timetree = Curl_splayinsert(tv, multi->timetree, &d->state.timenode); } return CURLM_OK; @@ -3060,12 +3058,12 @@ static CURLMcode add_next_timeout(struct curltime now, struct multi_run_ctx { struct Curl_multi *multi; - struct curltime now; size_t run_xfers; SIGPIPE_MEMBER(pipe_st); }; -static void multi_mark_expired_as_dirty(struct multi_run_ctx *mrc) +static void multi_mark_expired_as_dirty(struct multi_run_ctx *mrc, + const struct curltime *ts) { struct Curl_multi *multi = mrc->multi; struct Curl_easy *data = NULL; @@ -3079,7 +3077,7 @@ static void multi_mark_expired_as_dirty(struct multi_run_ctx *mrc) while(1) { /* Check if there is one (more) expired timer to deal with! This function extracts a matching node if there is one */ - multi->timetree = Curl_splaygetbest(mrc->now, multi->timetree, &t); + multi->timetree = Curl_splaygetbest(ts, multi->timetree, &t); if(!t) return; @@ -3095,7 +3093,7 @@ static void multi_mark_expired_as_dirty(struct multi_run_ctx *mrc) } } #endif - (void)add_next_timeout(mrc->now, multi, data); + (void)add_next_timeout(ts, multi, data); Curl_multi_mark_dirty(data); } } @@ -3121,9 +3119,7 @@ static CURLMcode multi_run_dirty(struct multi_run_ctx *mrc) mrc->run_xfers++; sigpipe_apply(data, &mrc->pipe_st); /* runsingle() clears the dirty mid */ - Curl_pgrs_now_at_least(data, &mrc->now); mresult = multi_runsingle(multi, data); - mrc->now = data->progress.now; /* in case transfer updated */ if(CURLM_OK >= mresult) { /* reassess event handling of data */ @@ -3155,17 +3151,15 @@ static CURLMcode multi_socket(struct Curl_multi *multi, (void)ev_bitmask; memset(&mrc, 0, sizeof(mrc)); mrc.multi = multi; - mrc.now = curlx_now(); /* start of API call */ sigpipe_init(&mrc.pipe_st); if(checkall) { /* *perform() deals with running_handles on its own */ - mresult = multi_perform(multi, &mrc.now, running_handles); + mresult = multi_perform(multi, running_handles); if(mresult != CURLM_BAD_HANDLE) { /* Reassess event status of all active transfers */ - mresult = Curl_multi_ev_assess_xfer_bset(multi, &multi->process, - &mrc.now); + mresult = Curl_multi_ev_assess_xfer_bset(multi, &multi->process); } goto out; } @@ -3183,7 +3177,7 @@ static CURLMcode multi_socket(struct Curl_multi *multi, memset(&multi->last_expire_ts, 0, sizeof(multi->last_expire_ts)); } - multi_mark_expired_as_dirty(&mrc); + multi_mark_expired_as_dirty(&mrc, multi_now(multi)); mresult = multi_run_dirty(&mrc); if(mresult) goto out; @@ -3194,7 +3188,7 @@ static CURLMcode multi_socket(struct Curl_multi *multi, * to set a 0 timeout and call us again, we run them here. * Do that only once or it might be unfair to transfers on other * sockets. */ - multi_mark_expired_as_dirty(&mrc); + multi_mark_expired_as_dirty(&mrc, &multi->now); mresult = multi_run_dirty(&mrc); } @@ -3213,7 +3207,7 @@ out: } if(CURLM_OK >= mresult) - mresult = Curl_update_timer(multi, &mrc.now); + mresult = Curl_update_timer(multi); return mresult; } @@ -3366,7 +3360,6 @@ static bool multi_has_dirties(struct Curl_multi *multi) } static void multi_timeout(struct Curl_multi *multi, - struct curltime *pnow, struct curltime *expire_time, long *timeout_ms) { @@ -3381,13 +3374,14 @@ static void multi_timeout(struct Curl_multi *multi, } if(multi_has_dirties(multi)) { - *expire_time = *pnow; + *expire_time = *multi_now(multi); *timeout_ms = 0; return; } else if(multi->timetree) { + const struct curltime *pnow = multi_now(multi); /* splay the lowest to the bottom */ - multi->timetree = Curl_splay(tv_zero, multi->timetree); + multi->timetree = Curl_splay(&tv_zero, multi->timetree); /* this will not return NULL from a non-empty tree, but some compilers * are not convinced of that. Analyzers are hard. */ *expire_time = multi->timetree ? multi->timetree->key : tv_zero; @@ -3395,9 +3389,10 @@ static void multi_timeout(struct Curl_multi *multi, /* 'multi->timetree' will be non-NULL here but the compilers sometimes yell at us if we assume so */ if(multi->timetree && - curlx_timediff_us(multi->timetree->key, *pnow) > 0) { + curlx_ptimediff_us(&multi->timetree->key, pnow) > 0) { /* some time left before expiration */ - timediff_t diff_ms = curlx_timediff_ceil_ms(multi->timetree->key, *pnow); + timediff_t diff_ms = + curlx_timediff_ceil_ms(multi->timetree->key, *pnow); #ifndef CURL_DISABLE_VERBOSE_STRINGS data = Curl_splayget(multi->timetree); #endif @@ -3437,7 +3432,6 @@ CURLMcode curl_multi_timeout(CURLM *m, { struct curltime expire_time; struct Curl_multi *multi = m; - struct curltime now = curlx_now(); /* start of API call */ /* First, make some basic checks that the CURLM handle is a good handle */ if(!GOOD_MULTI_HANDLE(multi)) @@ -3446,7 +3440,7 @@ CURLMcode curl_multi_timeout(CURLM *m, if(multi->in_callback) return CURLM_RECURSIVE_API_CALL; - multi_timeout(multi, &now, &expire_time, timeout_ms); + multi_timeout(multi, &expire_time, timeout_ms); return CURLM_OK; } @@ -3454,8 +3448,7 @@ CURLMcode curl_multi_timeout(CURLM *m, * Tell the application it should update its timers, if it subscribes to the * update timer callback. */ -CURLMcode Curl_update_timer(struct Curl_multi *multi, - struct curltime *pnow) +CURLMcode Curl_update_timer(struct Curl_multi *multi) { struct curltime expire_ts; long timeout_ms; @@ -3464,7 +3457,7 @@ CURLMcode Curl_update_timer(struct Curl_multi *multi, if(!multi->timer_cb || multi->dead) return CURLM_OK; - multi_timeout(multi, pnow, &expire_ts, &timeout_ms); + multi_timeout(multi, &expire_ts, &timeout_ms); if(timeout_ms < 0 && multi->last_timeout_ms < 0) { /* nothing to do */ @@ -3479,7 +3472,7 @@ CURLMcode Curl_update_timer(struct Curl_multi *multi, CURL_TRC_M(multi->admin, "[TIMER] set %ldms, none before", timeout_ms); set_value = TRUE; } - else if(curlx_timediff_us(multi->last_expire_ts, expire_ts)) { + else if(curlx_ptimediff_us(&multi->last_expire_ts, &expire_ts)) { /* We had a timeout before and have one now, the absolute timestamp * differs. The relative timeout_ms may be the same, but the starting * point differs. Let the application restart its timer. */ @@ -3535,8 +3528,7 @@ static void multi_deltimeout(struct Curl_easy *data, expire_id eid) */ static CURLMcode multi_addtimeout(struct Curl_easy *data, struct curltime *stamp, - expire_id eid, - const struct curltime *nowp) + expire_id eid) { struct Curl_llist_node *e; struct time_node *node; @@ -3544,7 +3536,6 @@ static CURLMcode multi_addtimeout(struct Curl_easy *data, size_t n; struct Curl_llist *timeoutlist = &data->state.timeoutlist; - (void)nowp; node = &data->state.expires[eid]; /* copy the timestamp and id */ @@ -3556,7 +3547,7 @@ static CURLMcode multi_addtimeout(struct Curl_easy *data, /* find the correct spot in the list */ for(e = Curl_llist_head(timeoutlist); e; e = Curl_node_next(e)) { struct time_node *check = Curl_node_elem(e); - timediff_t diff = curlx_timediff_ms(check->time, node->time); + timediff_t diff = curlx_ptimediff_ms(&check->time, &node->time); if(diff > 0) break; prev = e; @@ -3567,7 +3558,7 @@ static CURLMcode multi_addtimeout(struct Curl_easy *data, Curl_llist_insert_next(timeoutlist, prev, node, &node->list); CURL_TRC_TIMER(data, eid, "set for %" FMT_TIMEDIFF_T "ns", - curlx_timediff_us(node->time, *nowp)); + curlx_ptimediff_us(&node->time, Curl_pgrs_now(data))); return CURLM_OK; } @@ -3585,7 +3576,7 @@ void Curl_expire_ex(struct Curl_easy *data, DEBUGASSERT(id < EXPIRE_LAST); - set = data->progress.now; + set = *Curl_pgrs_now(data); set.tv_sec += (time_t)(milli / 1000); /* may be a 64 to 32-bit conversion */ set.tv_usec += (int)(milli % 1000) * 1000; @@ -3599,13 +3590,13 @@ void Curl_expire_ex(struct Curl_easy *data, /* Add it to the timer list. It must stay in the list until it has expired in case we need to recompute the minimum timer later. */ - multi_addtimeout(data, &set, id, &data->progress.now); + multi_addtimeout(data, &set, id); if(curr_expire->tv_sec || curr_expire->tv_usec) { /* This means that the struct is added as a node in the splay tree. Compare if the new time is earlier, and only remove-old/add-new if it is. */ - timediff_t diff = curlx_timediff_ms(set, *curr_expire); + timediff_t diff = curlx_ptimediff_ms(&set, curr_expire); int rc; if(diff > 0) { @@ -3626,7 +3617,7 @@ void Curl_expire_ex(struct Curl_easy *data, value since it is our local minimum. */ *curr_expire = set; Curl_splayset(&data->state.timenode, data); - multi->timetree = Curl_splayinsert(*curr_expire, multi->timetree, + multi->timetree = Curl_splayinsert(curr_expire, multi->timetree, &data->state.timenode); } diff --git a/lib/multi_ev.c b/lib/multi_ev.c index 85e2bd6c60..906b1c7183 100644 --- a/lib/multi_ev.c +++ b/lib/multi_ev.c @@ -538,8 +538,7 @@ CURLMcode Curl_multi_ev_assess_conn(struct Curl_multi *multi, } CURLMcode Curl_multi_ev_assess_xfer_bset(struct Curl_multi *multi, - struct uint32_bset *set, - struct curltime *pnow) + struct uint32_bset *set) { uint32_t mid; CURLMcode mresult = CURLM_OK; @@ -548,7 +547,6 @@ CURLMcode Curl_multi_ev_assess_xfer_bset(struct Curl_multi *multi, do { struct Curl_easy *data = Curl_multi_get_easy(multi, mid); if(data) { - Curl_pgrs_now_at_least(data, pnow); mresult = Curl_multi_ev_assess_xfer(multi, data); } } while(!mresult && Curl_uint32_bset_next(set, mid, &mid)); diff --git a/lib/multi_ev.h b/lib/multi_ev.h index d9794ed865..4e5b2a454d 100644 --- a/lib/multi_ev.h +++ b/lib/multi_ev.h @@ -55,8 +55,7 @@ CURLMcode Curl_multi_ev_assess_xfer(struct Curl_multi *multi, struct Curl_easy *data); /* Assess all easy handles on the list */ CURLMcode Curl_multi_ev_assess_xfer_bset(struct Curl_multi *multi, - struct uint32_bset *set, - struct curltime *pnow); + struct uint32_bset *set); /* Assess the connection by getting its current pollset */ CURLMcode Curl_multi_ev_assess_conn(struct Curl_multi *multi, struct Curl_easy *data, diff --git a/lib/multihandle.h b/lib/multihandle.h index d71958c414..2bf06322a8 100644 --- a/lib/multihandle.h +++ b/lib/multihandle.h @@ -116,6 +116,8 @@ struct Curl_multi { struct PslCache psl; #endif + /* current time for transfers running in this multi handle */ + struct curltime now; /* timetree points to the splay-tree of time nodes to figure out expire times of all currently set timers */ struct Curl_tree *timetree; @@ -170,6 +172,9 @@ struct Curl_multi { unsigned int maxconnects; /* if >0, a fixed limit of the maximum number of entries we are allowed to grow the connection cache to */ +#ifdef DEBUGBUILD + unsigned int now_access_count; +#endif #define IPV6_UNKNOWN 0 #define IPV6_DEAD 1 #define IPV6_WORKS 2 diff --git a/lib/multiif.h b/lib/multiif.h index 42651c5150..f4dc24a3e9 100644 --- a/lib/multiif.h +++ b/lib/multiif.h @@ -33,8 +33,7 @@ void Curl_expire_ex(struct Curl_easy *data, timediff_t milli, expire_id id); bool Curl_expire_clear(struct Curl_easy *data); void Curl_expire_done(struct Curl_easy *data, expire_id id); -CURLMcode Curl_update_timer(struct Curl_multi *multi, - struct curltime *pnow) WARN_UNUSED_RESULT; +CURLMcode Curl_update_timer(struct Curl_multi *multi) WARN_UNUSED_RESULT; void Curl_attach_connection(struct Curl_easy *data, struct connectdata *conn); void Curl_detach_connection(struct Curl_easy *data); @@ -163,4 +162,6 @@ void Curl_multi_mark_dirty(struct Curl_easy *data); /* Clear transfer from the dirty set. */ void Curl_multi_clear_dirty(struct Curl_easy *data); +void Curl_multi_set_now(struct Curl_multi *multi); + #endif /* HEADER_CURL_MULTIIF_H */ diff --git a/lib/pingpong.c b/lib/pingpong.c index fcfd991d81..6c64164e48 100644 --- a/lib/pingpong.c +++ b/lib/pingpong.c @@ -53,14 +53,10 @@ timediff_t Curl_pp_state_timeout(struct Curl_easy *data, supposed to govern the response for any given server response, not for the time from connect to the given server response. */ - /* pingpong can spend some time processing, always update - * the transfer timestamp before checking timeouts. */ - Curl_pgrs_now_set(data); - /* Without a requested timeout, we only wait 'response_time' seconds for the full response to arrive before we bail out */ timeout_ms = response_time - - curlx_timediff_ms(data->progress.now, pp->response); + curlx_ptimediff_ms(Curl_pgrs_now(data), &pp->response); if(data->set.timeout && !disconnecting) { /* if timeout is requested, find out how much overall remains */ @@ -139,7 +135,7 @@ CURLcode Curl_pp_statemach(struct Curl_easy *data, } /* initialize stuff to prepare for reading a fresh new response */ -void Curl_pp_init(struct pingpong *pp, struct curltime *pnow) +void Curl_pp_init(struct pingpong *pp, const struct curltime *pnow) { DEBUGASSERT(!pp->initialised); pp->nread_resp = 0; @@ -212,7 +208,7 @@ CURLcode Curl_pp_vsendf(struct Curl_easy *data, else { pp->sendthis = NULL; pp->sendleft = pp->sendsize = 0; - pp->response = data->progress.now; + pp->response = *Curl_pgrs_now(data); } return CURLE_OK; @@ -403,7 +399,7 @@ CURLcode Curl_pp_flushsend(struct Curl_easy *data, else { pp->sendthis = NULL; pp->sendleft = pp->sendsize = 0; - pp->response = data->progress.now; + pp->response = *Curl_pgrs_now(data); } return CURLE_OK; } diff --git a/lib/pingpong.h b/lib/pingpong.h index a41d76308c..b3780571c4 100644 --- a/lib/pingpong.h +++ b/lib/pingpong.h @@ -87,7 +87,7 @@ CURLcode Curl_pp_statemach(struct Curl_easy *data, struct pingpong *pp, bool block, bool disconnecting); /* initialize stuff to prepare for reading a fresh new response */ -void Curl_pp_init(struct pingpong *pp, struct curltime *pnow); +void Curl_pp_init(struct pingpong *pp, const struct curltime *pnow); /* Returns timeout in ms. 0 or negative number means the timeout has already triggered */ diff --git a/lib/pop3.c b/lib/pop3.c index 1fd22116c5..478dd7bc19 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -1297,7 +1297,7 @@ static CURLcode pop3_connect(struct Curl_easy *data, bool *done) Curl_sasl_init(&pop3c->sasl, data, &saslpop3); /* Initialise the pingpong layer */ - Curl_pp_init(pp, &data->progress.now); + Curl_pp_init(pp, Curl_pgrs_now(data)); /* Parse the URL options */ result = pop3_parse_url_options(conn); diff --git a/lib/progress.c b/lib/progress.c index e11a1ff82f..ed842cefcd 100644 --- a/lib/progress.c +++ b/lib/progress.c @@ -102,7 +102,7 @@ static void pgrs_speedinit(struct Curl_easy *data) * @unittest: 1606 */ UNITTEST CURLcode pgrs_speedcheck(struct Curl_easy *data, - struct curltime *pnow) + const struct curltime *pnow) { if(!data->set.low_speed_time || !data->set.low_speed_limit || Curl_xfer_recv_is_paused(data) || Curl_xfer_send_is_paused(data)) @@ -116,7 +116,8 @@ UNITTEST CURLcode pgrs_speedcheck(struct Curl_easy *data, data->state.keeps_speed = *pnow; else { /* how long has it been under the limit */ - timediff_t howlong = curlx_timediff_ms(*pnow, data->state.keeps_speed); + timediff_t howlong = + curlx_ptimediff_ms(pnow, &data->state.keeps_speed); if(howlong >= data->set.low_speed_time * 1000) { /* too long */ @@ -141,23 +142,12 @@ UNITTEST CURLcode pgrs_speedcheck(struct Curl_easy *data, return CURLE_OK; } -void Curl_pgrs_now_set(struct Curl_easy *data) +const struct curltime *Curl_pgrs_now(struct Curl_easy *data) { - data->progress.now = curlx_now(); -} - -void Curl_pgrs_now_at_least(struct Curl_easy *data, struct curltime *pts) -{ - if((pts->tv_sec > data->progress.now.tv_sec) || - ((pts->tv_sec == data->progress.now.tv_sec) && - (pts->tv_usec > data->progress.now.tv_usec))) { - data->progress.now = *pts; - } -} - -void Curl_pgrs_now_update(struct Curl_easy *data, struct Curl_easy *other) -{ - Curl_pgrs_now_at_least(data, &other->progress.now); + struct curltime *pnow = data->multi ? + &data->multi->now : &data->progress.now; + curlx_pnow(pnow); + return pnow; } /* @@ -251,7 +241,7 @@ void Curl_pgrsTimeWas(struct Curl_easy *data, timerid timer, case TIMER_POSTQUEUE: /* Queue time is accumulative from all involved redirects */ data->progress.t_postqueue += - curlx_timediff_us(timestamp, data->progress.t_startqueue); + curlx_ptimediff_us(×tamp, &data->progress.t_startqueue); break; case TIMER_STARTACCEPT: data->progress.t_acceptdata = timestamp; @@ -287,13 +277,14 @@ void Curl_pgrsTimeWas(struct Curl_easy *data, timerid timer, delta = &data->progress.t_posttransfer; break; case TIMER_REDIRECT: - data->progress.t_redirect = curlx_timediff_us(timestamp, - data->progress.start); + data->progress.t_redirect = curlx_ptimediff_us(×tamp, + &data->progress.start); data->progress.t_startqueue = timestamp; break; } if(delta) { - timediff_t us = curlx_timediff_us(timestamp, data->progress.t_startsingle); + timediff_t us = curlx_ptimediff_us(×tamp, + &data->progress.t_startsingle); if(us < 1) us = 1; /* make sure at least one microsecond passed */ *delta += us; @@ -309,15 +300,15 @@ void Curl_pgrsTimeWas(struct Curl_easy *data, timerid timer, */ void Curl_pgrsTime(struct Curl_easy *data, timerid timer) { - Curl_pgrs_now_set(data); /* update on real progress */ - Curl_pgrsTimeWas(data, timer, data->progress.now); + Curl_pgrsTimeWas(data, timer, *Curl_pgrs_now(data)); } void Curl_pgrsStartNow(struct Curl_easy *data) { struct Progress *p = &data->progress; + p->speeder_c = 0; /* reset the progress meter display */ - p->start = data->progress.now; + p->start = *Curl_pgrs_now(data); p->is_t_startransfer_set = FALSE; p->dl.cur_size = 0; p->ul.cur_size = 0; @@ -330,7 +321,7 @@ void Curl_pgrs_download_inc(struct Curl_easy *data, size_t delta) { if(delta) { data->progress.dl.cur_size += delta; - Curl_rlimit_drain(&data->progress.dl.rlimit, delta, &data->progress.now); + Curl_rlimit_drain(&data->progress.dl.rlimit, delta, Curl_pgrs_now(data)); } } @@ -338,7 +329,7 @@ void Curl_pgrs_upload_inc(struct Curl_easy *data, size_t delta) { if(delta) { data->progress.ul.cur_size += delta; - Curl_rlimit_drain(&data->progress.ul.rlimit, delta, &data->progress.now); + Curl_rlimit_drain(&data->progress.ul.rlimit, delta, Curl_pgrs_now(data)); } } @@ -394,7 +385,8 @@ static curl_off_t trspeed(curl_off_t size, /* number of bytes */ } /* returns TRUE if it is time to show the progress meter */ -static bool progress_calc(struct Curl_easy *data, struct curltime *pnow) +static bool progress_calc(struct Curl_easy *data, + const struct curltime *pnow) { struct Progress * const p = &data->progress; int i_next, i_oldest, i_latest; @@ -402,7 +394,7 @@ static bool progress_calc(struct Curl_easy *data, struct curltime *pnow) curl_off_t amount; /* The time spent so far (from the start) in microseconds */ - p->timespent = curlx_timediff_us(*pnow, p->start); + p->timespent = curlx_ptimediff_us(pnow, &p->start); p->dl.speed = trspeed(p->dl.cur_size, p->timespent); p->ul.speed = trspeed(p->ul.cur_size, p->timespent); @@ -422,7 +414,7 @@ static bool progress_calc(struct Curl_easy *data, struct curltime *pnow) /* Make a new record only when some time has passed. * Too frequent calls otherwise ruin the history. */ - if(curlx_timediff_ms(*pnow, p->speed_time[i_latest]) >= 1000) { + if(curlx_ptimediff_ms(pnow, &p->speed_time[i_latest]) >= 1000) { p->speeder_c++; i_latest = i_next; p->speed_amount[i_latest] = p->dl.cur_size + p->ul.cur_size; @@ -449,8 +441,8 @@ static bool progress_calc(struct Curl_easy *data, struct curltime *pnow) /* How much we transferred between oldest and current records */ amount = p->speed_amount[i_latest] - p->speed_amount[i_oldest]; /* How long this took */ - duration_ms = curlx_timediff_ms(p->speed_time[i_latest], - p->speed_time[i_oldest]); + duration_ms = curlx_ptimediff_ms(&p->speed_time[i_latest], + &p->speed_time[i_oldest]); if(duration_ms <= 0) duration_ms = 1; @@ -635,7 +627,8 @@ static CURLcode pgrsupdate(struct Curl_easy *data, bool showprogress) return CURLE_OK; } -static CURLcode pgrs_update(struct Curl_easy *data, struct curltime *pnow) +static CURLcode pgrs_update(struct Curl_easy *data, + const struct curltime *pnow) { bool showprogress = progress_calc(data, pnow); return pgrsupdate(data, showprogress); @@ -643,16 +636,16 @@ static CURLcode pgrs_update(struct Curl_easy *data, struct curltime *pnow) CURLcode Curl_pgrsUpdate(struct Curl_easy *data) { - return pgrs_update(data, &data->progress.now); + return pgrs_update(data, Curl_pgrs_now(data)); } CURLcode Curl_pgrsCheck(struct Curl_easy *data) { CURLcode result; - result = pgrs_update(data, &data->progress.now); + result = pgrs_update(data, Curl_pgrs_now(data)); if(!result && !data->req.done) - result = pgrs_speedcheck(data, &data->progress.now); + result = pgrs_speedcheck(data, Curl_pgrs_now(data)); return result; } @@ -661,5 +654,5 @@ CURLcode Curl_pgrsCheck(struct Curl_easy *data) */ void Curl_pgrsUpdate_nometer(struct Curl_easy *data) { - (void)progress_calc(data, &data->progress.now); + (void)progress_calc(data, Curl_pgrs_now(data)); } diff --git a/lib/progress.h b/lib/progress.h index 2154ff60bd..f368c2475e 100644 --- a/lib/progress.h +++ b/lib/progress.h @@ -44,16 +44,8 @@ typedef enum { TIMER_LAST /* must be last */ } timerid; -#define CURL_PGRS_NOW_MONOTONIC - -/* Set current time in data->progress.now */ -void Curl_pgrs_now_set(struct Curl_easy *data); -/* Advance `now` timestamp at least to given timestamp. - * No effect it data's `now` is already later than `pts`. */ -void Curl_pgrs_now_at_least(struct Curl_easy *data, struct curltime *pts); -/* `data` progressing continues after `other` processing. Advance `data`s - * now timestamp to at least `other's` timestamp. */ -void Curl_pgrs_now_update(struct Curl_easy *data, struct Curl_easy *other); +/* Get the current timestamp of the transfer */ +const struct curltime *Curl_pgrs_now(struct Curl_easy *data); int Curl_pgrsDone(struct Curl_easy *data); void Curl_pgrsStartNow(struct Curl_easy *data); @@ -93,7 +85,7 @@ void Curl_pgrsEarlyData(struct Curl_easy *data, curl_off_t sent); #ifdef UNITTESTS UNITTEST CURLcode pgrs_speedcheck(struct Curl_easy *data, - struct curltime *pnow); + const struct curltime *pnow); #endif #endif /* HEADER_CURL_PROGRESS_H */ diff --git a/lib/psl.c b/lib/psl.c index 0be51e4402..a089402ece 100644 --- a/lib/psl.c +++ b/lib/psl.c @@ -29,6 +29,7 @@ #ifdef USE_LIBPSL #include "psl.h" +#include "progress.h" #include "curl_share.h" void Curl_psl_destroy(struct PslCache *pslcache) @@ -41,25 +42,18 @@ void Curl_psl_destroy(struct PslCache *pslcache) } } -static time_t now_seconds(void) -{ - struct curltime now = curlx_now(); - - return now.tv_sec; -} - const psl_ctx_t *Curl_psl_use(struct Curl_easy *easy) { struct PslCache *pslcache = easy->psl; const psl_ctx_t *psl; - time_t now; + time_t now_sec; if(!pslcache) return NULL; Curl_share_lock(easy, CURL_LOCK_DATA_PSL, CURL_LOCK_ACCESS_SHARED); - now = now_seconds(); - if(!pslcache->psl || pslcache->expires <= now) { + now_sec = Curl_pgrs_now(easy)->tv_sec; + if(!pslcache->psl || pslcache->expires <= now_sec) { /* Let a chance to other threads to do the job: avoids deadlock. */ Curl_share_unlock(easy, CURL_LOCK_DATA_PSL); @@ -67,8 +61,10 @@ const psl_ctx_t *Curl_psl_use(struct Curl_easy *easy) Curl_share_lock(easy, CURL_LOCK_DATA_PSL, CURL_LOCK_ACCESS_SINGLE); /* Recheck in case another thread did the job. */ - now = now_seconds(); - if(!pslcache->psl || pslcache->expires <= now) { + if(pslcache->expires <= now_sec) { + now_sec = Curl_pgrs_now(easy)->tv_sec; + } + if(!pslcache->psl || pslcache->expires <= now_sec) { bool dynamic = FALSE; time_t expires = TIME_T_MAX; @@ -76,7 +72,8 @@ const psl_ctx_t *Curl_psl_use(struct Curl_easy *easy) psl = psl_latest(NULL); dynamic = psl != NULL; /* Take care of possible time computation overflow. */ - expires = now < TIME_T_MAX - PSL_TTL ? now + PSL_TTL : TIME_T_MAX; + expires = (now_sec < TIME_T_MAX - PSL_TTL) ? + (now_sec + PSL_TTL) : TIME_T_MAX; /* Only get the built-in PSL if we do not already have the "latest". */ if(!psl && !pslcache->dynamic) diff --git a/lib/rand.c b/lib/rand.c index 88324e918a..a5694233fc 100644 --- a/lib/rand.c +++ b/lib/rand.c @@ -119,7 +119,8 @@ static CURLcode weak_random(struct Curl_easy *data, static bool seeded = FALSE; unsigned int rnd; if(!seeded) { - struct curltime now = curlx_now(); + struct curltime now; + curlx_pnow(&now); randseed += (unsigned int)now.tv_usec + (unsigned int)now.tv_sec; randseed = randseed * 1103515245 + 12345; randseed = randseed * 1103515245 + 12345; diff --git a/lib/ratelimit.c b/lib/ratelimit.c index 5c2e005133..dc1a545201 100644 --- a/lib/ratelimit.c +++ b/lib/ratelimit.c @@ -25,6 +25,7 @@ #include "curl_setup.h" #include "curlx/timeval.h" +#include "progress.h" #include "ratelimit.h" @@ -35,7 +36,7 @@ void Curl_rlimit_init(struct Curl_rlimit *r, curl_off_t rate_per_s, curl_off_t burst_per_s, - struct curltime *pts) + const struct curltime *pts) { curl_off_t rate_steps; @@ -62,7 +63,7 @@ void Curl_rlimit_init(struct Curl_rlimit *r, r->blocked = FALSE; } -void Curl_rlimit_start(struct Curl_rlimit *r, struct curltime *pts) +void Curl_rlimit_start(struct Curl_rlimit *r, const struct curltime *pts) { r->tokens = r->rate_per_step; r->spare_us = 0; @@ -80,7 +81,7 @@ bool Curl_rlimit_is_blocked(struct Curl_rlimit *r) } static void ratelimit_update(struct Curl_rlimit *r, - struct curltime *pts) + const struct curltime *pts) { timediff_t elapsed_us, elapsed_steps; curl_off_t token_gain; @@ -89,7 +90,7 @@ static void ratelimit_update(struct Curl_rlimit *r, if((r->ts.tv_sec == pts->tv_sec) && (r->ts.tv_usec == pts->tv_usec)) return; - elapsed_us = curlx_timediff_us(*pts, r->ts); + elapsed_us = curlx_ptimediff_us(pts, &r->ts); if(elapsed_us < 0) { /* not going back in time */ DEBUGASSERT(0); return; @@ -120,7 +121,7 @@ static void ratelimit_update(struct Curl_rlimit *r, } curl_off_t Curl_rlimit_avail(struct Curl_rlimit *r, - struct curltime *pts) + const struct curltime *pts) { if(r->blocked) return 0; @@ -134,7 +135,7 @@ curl_off_t Curl_rlimit_avail(struct Curl_rlimit *r, void Curl_rlimit_drain(struct Curl_rlimit *r, size_t tokens, - struct curltime *pts) + const struct curltime *pts) { if(r->blocked || !r->rate_per_step) return; @@ -157,7 +158,7 @@ void Curl_rlimit_drain(struct Curl_rlimit *r, } timediff_t Curl_rlimit_wait_ms(struct Curl_rlimit *r, - struct curltime *pts) + const struct curltime *pts) { timediff_t wait_us, elapsed_us; @@ -172,7 +173,7 @@ timediff_t Curl_rlimit_wait_ms(struct Curl_rlimit *r, wait_us = (1 + (-r->tokens / r->rate_per_step)) * r->step_us; wait_us -= r->spare_us; - elapsed_us = curlx_timediff_us(*pts, r->ts); + elapsed_us = curlx_ptimediff_us(pts, &r->ts); if(elapsed_us >= wait_us) return 0; wait_us -= elapsed_us; @@ -181,7 +182,7 @@ timediff_t Curl_rlimit_wait_ms(struct Curl_rlimit *r, void Curl_rlimit_block(struct Curl_rlimit *r, bool activate, - struct curltime *pts) + const struct curltime *pts) { if(!activate == !r->blocked) return; diff --git a/lib/ratelimit.h b/lib/ratelimit.h index b5a7c56fce..aa57645126 100644 --- a/lib/ratelimit.h +++ b/lib/ratelimit.h @@ -26,6 +26,8 @@ #include "curlx/timeval.h" +struct Curl_easy; + /* This is a rate limiter that provides "tokens" to be consumed * per second with a "burst" rate limitation. Example: * A rate limit of 1 megabyte per second with a burst rate of 1.5MB. @@ -62,14 +64,14 @@ struct Curl_rlimit { void Curl_rlimit_init(struct Curl_rlimit *r, curl_off_t rate_per_s, curl_off_t burst_per_s, - struct curltime *pts); + const struct curltime *pts); /* Start ratelimiting with the given timestamp. Resets available tokens. */ -void Curl_rlimit_start(struct Curl_rlimit *r, struct curltime *pts); +void Curl_rlimit_start(struct Curl_rlimit *r, const struct curltime *pts); /* How many milliseconds to wait until token are available again. */ timediff_t Curl_rlimit_wait_ms(struct Curl_rlimit *r, - struct curltime *pts); + const struct curltime *pts); /* Return if rate limiting of tokens is active */ bool Curl_rlimit_active(struct Curl_rlimit *r); @@ -77,16 +79,16 @@ bool Curl_rlimit_is_blocked(struct Curl_rlimit *r); /* Return how many tokens are available to spend, may be negative */ curl_off_t Curl_rlimit_avail(struct Curl_rlimit *r, - struct curltime *pts); + const struct curltime *pts); /* Drain tokens from the ratelimit, return how many are now available. */ void Curl_rlimit_drain(struct Curl_rlimit *r, size_t tokens, - struct curltime *pts); + const struct curltime *pts); /* Block/unblock ratelimiting. A blocked ratelimit has 0 tokens available. */ void Curl_rlimit_block(struct Curl_rlimit *r, bool activate, - struct curltime *pts); + const struct curltime *pts); #endif /* HEADER_Curl_rlimit_H */ diff --git a/lib/request.c b/lib/request.c index 03dde6ab6d..8d5144f610 100644 --- a/lib/request.c +++ b/lib/request.c @@ -90,7 +90,7 @@ CURLcode Curl_req_soft_reset(struct SingleRequest *req, CURLcode Curl_req_start(struct SingleRequest *req, struct Curl_easy *data) { - req->start = data->progress.now; + req->start = *Curl_pgrs_now(data); return Curl_req_soft_reset(req, data); } diff --git a/lib/sendf.c b/lib/sendf.c index c236d558e6..7ab6af8b69 100644 --- a/lib/sendf.c +++ b/lib/sendf.c @@ -230,7 +230,7 @@ static CURLcode cw_download_write(struct Curl_easy *data, if(!ctx->started_response && !(type & (CLIENTWRITE_INFO | CLIENTWRITE_CONNECT))) { Curl_pgrsTime(data, TIMER_STARTTRANSFER); - Curl_rlimit_start(&data->progress.dl.rlimit, &data->progress.now); + Curl_rlimit_start(&data->progress.dl.rlimit, Curl_pgrs_now(data)); ctx->started_response = TRUE; } @@ -1202,13 +1202,13 @@ CURLcode Curl_client_read(struct Curl_easy *data, char *buf, size_t blen, DEBUGASSERT(data->req.reader_stack); } if(!data->req.reader_started) { - Curl_rlimit_start(&data->progress.ul.rlimit, &data->progress.now); + Curl_rlimit_start(&data->progress.ul.rlimit, Curl_pgrs_now(data)); data->req.reader_started = TRUE; } if(Curl_rlimit_active(&data->progress.ul.rlimit)) { - curl_off_t ul_avail = - Curl_rlimit_avail(&data->progress.ul.rlimit, &data->progress.now); + curl_off_t ul_avail = Curl_rlimit_avail(&data->progress.ul.rlimit, + Curl_pgrs_now(data)); if(ul_avail <= 0) { result = CURLE_OK; *eos = FALSE; diff --git a/lib/setopt.c b/lib/setopt.c index 627865dc31..3c4350e539 100644 --- a/lib/setopt.c +++ b/lib/setopt.c @@ -2814,7 +2814,7 @@ static CURLcode setopt_offt(struct Curl_easy *data, CURLoption option, return CURLE_BAD_FUNCTION_ARGUMENT; s->max_send_speed = offt; Curl_rlimit_init(&data->progress.ul.rlimit, offt, offt, - &data->progress.now); + Curl_pgrs_now(data)); break; case CURLOPT_MAX_RECV_SPEED_LARGE: /* @@ -2825,7 +2825,7 @@ static CURLcode setopt_offt(struct Curl_easy *data, CURLoption option, return CURLE_BAD_FUNCTION_ARGUMENT; s->max_recv_speed = offt; Curl_rlimit_init(&data->progress.dl.rlimit, offt, offt, - &data->progress.now); + Curl_pgrs_now(data)); break; case CURLOPT_RESUME_FROM_LARGE: /* diff --git a/lib/smtp.c b/lib/smtp.c index 8ae7bc169d..026e3efc0f 100644 --- a/lib/smtp.c +++ b/lib/smtp.c @@ -1441,7 +1441,7 @@ static CURLcode smtp_connect(struct Curl_easy *data, bool *done) Curl_sasl_init(&smtpc->sasl, data, &saslsmtp); /* Initialise the pingpong layer */ - Curl_pp_init(&smtpc->pp, &data->progress.now); + Curl_pp_init(&smtpc->pp, Curl_pgrs_now(data)); /* Parse the URL options */ result = smtp_parse_url_options(data->conn, smtpc); diff --git a/lib/splay.c b/lib/splay.c index d036d27f54..a95eb10d85 100644 --- a/lib/splay.c +++ b/lib/splay.c @@ -34,13 +34,13 @@ * zero : when i is equal to j * positive when : when i is larger than j */ -#define compare(i, j) curlx_timediff_us(i, j) +#define splay_compare(i, j) curlx_ptimediff_us(i, j) /* * Splay using the key i (which may or may not be in the tree.) The starting * root is t. */ -struct Curl_tree *Curl_splay(struct curltime i, +struct Curl_tree *Curl_splay(const struct curltime *pkey, struct Curl_tree *t) { struct Curl_tree N, *l, *r, *y; @@ -51,11 +51,11 @@ struct Curl_tree *Curl_splay(struct curltime i, l = r = &N; for(;;) { - timediff_t comp = compare(i, t->key); + timediff_t comp = splay_compare(pkey, &t->key); if(comp < 0) { if(!t->smaller) break; - if(compare(i, t->smaller->key) < 0) { + if(splay_compare(pkey, &t->smaller->key) < 0) { y = t->smaller; /* rotate smaller */ t->smaller = y->larger; y->larger = t; @@ -70,7 +70,7 @@ struct Curl_tree *Curl_splay(struct curltime i, else if(comp > 0) { if(!t->larger) break; - if(compare(i, t->larger->key) > 0) { + if(splay_compare(pkey, &t->larger->key) > 0) { y = t->larger; /* rotate larger */ t->larger = y->smaller; y->smaller = t; @@ -103,16 +103,16 @@ static const struct curltime SPLAY_SUBNODE = { * * @unittest: 1309 */ -struct Curl_tree *Curl_splayinsert(struct curltime i, +struct Curl_tree *Curl_splayinsert(const struct curltime *pkey, struct Curl_tree *t, struct Curl_tree *node) { DEBUGASSERT(node); if(t) { - t = Curl_splay(i, t); + t = Curl_splay(pkey, t); DEBUGASSERT(t); - if(compare(i, t->key) == 0) { + if(splay_compare(pkey, &t->key) == 0) { /* There already exists a node in the tree with the same key. Build a doubly-linked circular list of nodes. We add the new 'node' struct to the end of this list. */ @@ -130,7 +130,7 @@ struct Curl_tree *Curl_splayinsert(struct curltime i, if(!t) { node->smaller = node->larger = NULL; } - else if(compare(i, t->key) < 0) { + else if(splay_compare(pkey, &t->key) < 0) { node->smaller = t->smaller; node->larger = t; t->smaller = NULL; @@ -140,7 +140,7 @@ struct Curl_tree *Curl_splayinsert(struct curltime i, node->smaller = t; t->larger = NULL; } - node->key = i; + node->key = *pkey; /* no identical nodes (yet), we are the only one in the list of nodes */ node->samen = node; @@ -151,7 +151,7 @@ struct Curl_tree *Curl_splayinsert(struct curltime i, /* Finds and deletes the best-fit node from the tree. Return a pointer to the resulting tree. best-fit means the smallest node if it is not larger than the key */ -struct Curl_tree *Curl_splaygetbest(struct curltime i, +struct Curl_tree *Curl_splaygetbest(const struct curltime *pkey, struct Curl_tree *t, struct Curl_tree **removed) { @@ -164,9 +164,9 @@ struct Curl_tree *Curl_splaygetbest(struct curltime i, } /* find smallest */ - t = Curl_splay(tv_zero, t); + t = Curl_splay(&tv_zero, t); DEBUGASSERT(t); - if(compare(i, t->key) < 0) { + if(splay_compare(pkey, &t->key) < 0) { /* even the smallest is too big */ *removed = NULL; return t; @@ -218,7 +218,7 @@ int Curl_splayremove(struct Curl_tree *t, DEBUGASSERT(removenode); - if(compare(SPLAY_SUBNODE, removenode->key) == 0) { + if(splay_compare(&SPLAY_SUBNODE, &removenode->key) == 0) { /* It is a subnode within a 'same' linked list and thus we can unlink it easily. */ DEBUGASSERT(removenode->samen != removenode); @@ -236,7 +236,7 @@ int Curl_splayremove(struct Curl_tree *t, return 0; } - t = Curl_splay(removenode->key, t); + t = Curl_splay(&removenode->key, t); DEBUGASSERT(t); /* First make sure that we got the same root node as the one we want @@ -268,7 +268,7 @@ int Curl_splayremove(struct Curl_tree *t, if(!t->smaller) x = t->larger; else { - x = Curl_splay(removenode->key, t->smaller); + x = Curl_splay(&removenode->key, t->smaller); DEBUGASSERT(x); x->larger = t->larger; } diff --git a/lib/splay.h b/lib/splay.h index ccc3781ec1..3a256b5713 100644 --- a/lib/splay.h +++ b/lib/splay.h @@ -36,14 +36,14 @@ struct Curl_tree { void *ptr; /* data the splay code does not care about */ }; -struct Curl_tree *Curl_splay(struct curltime i, +struct Curl_tree *Curl_splay(const struct curltime *pkey, struct Curl_tree *t); -struct Curl_tree *Curl_splayinsert(struct curltime key, +struct Curl_tree *Curl_splayinsert(const struct curltime *pkey, struct Curl_tree *t, struct Curl_tree *newnode); -struct Curl_tree *Curl_splaygetbest(struct curltime key, +struct Curl_tree *Curl_splaygetbest(const struct curltime *pkey, struct Curl_tree *t, struct Curl_tree **removed); diff --git a/lib/telnet.c b/lib/telnet.c index 4a25527388..e517b0c138 100644 --- a/lib/telnet.c +++ b/lib/telnet.c @@ -1507,8 +1507,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done) } /* switch */ if(data->set.timeout) { - Curl_pgrs_now_set(data); - if(curlx_timediff_ms(data->progress.now, conn->created) >= + if(curlx_ptimediff_ms(Curl_pgrs_now(data), &conn->created) >= data->set.timeout) { failf(data, "Time-out"); result = CURLE_OPERATION_TIMEDOUT; @@ -1627,8 +1626,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done) } /* poll switch statement */ if(data->set.timeout) { - Curl_pgrs_now_set(data); - if(curlx_timediff_ms(data->progress.now, conn->created) >= + if(curlx_ptimediff_ms(Curl_pgrs_now(data), &conn->created) >= data->set.timeout) { failf(data, "Time-out"); result = CURLE_OPERATION_TIMEDOUT; diff --git a/lib/transfer.c b/lib/transfer.c index 5407ba4477..6e190f46c0 100644 --- a/lib/transfer.c +++ b/lib/transfer.c @@ -261,7 +261,7 @@ static CURLcode sendrecv_dl(struct Curl_easy *data, if(bytestoread && Curl_rlimit_active(&data->progress.dl.rlimit)) { curl_off_t dl_avail = Curl_rlimit_avail(&data->progress.dl.rlimit, - &data->progress.now); + Curl_pgrs_now(data)); /* DEBUGF(infof(data, "dl_rlimit, available=%" FMT_OFF_T, dl_avail)); */ /* In case of rate limited downloads: if this loop already got @@ -399,15 +399,15 @@ CURLcode Curl_sendrecv(struct Curl_easy *data) failf(data, "Operation timed out after %" FMT_TIMEDIFF_T " milliseconds with %" FMT_OFF_T " out of %" FMT_OFF_T " bytes received", - curlx_timediff_ms(data->progress.now, - data->progress.t_startsingle), + curlx_ptimediff_ms(Curl_pgrs_now(data), + &data->progress.t_startsingle), k->bytecount, k->size); } else { failf(data, "Operation timed out after %" FMT_TIMEDIFF_T " milliseconds with %" FMT_OFF_T " bytes received", - curlx_timediff_ms(data->progress.now, - data->progress.t_startsingle), + curlx_ptimediff_ms(Curl_pgrs_now(data), + &data->progress.t_startsingle), k->bytecount); } result = CURLE_OPERATION_TIMEDOUT; @@ -903,7 +903,7 @@ bool Curl_xfer_recv_is_paused(struct Curl_easy *data) CURLcode Curl_xfer_pause_send(struct Curl_easy *data, bool enable) { CURLcode result = CURLE_OK; - Curl_rlimit_block(&data->progress.ul.rlimit, enable, &data->progress.now); + Curl_rlimit_block(&data->progress.ul.rlimit, enable, Curl_pgrs_now(data)); if(!enable && Curl_creader_is_paused(data)) result = Curl_creader_unpause(data); Curl_pgrsSendPause(data, enable); @@ -913,7 +913,7 @@ CURLcode Curl_xfer_pause_send(struct Curl_easy *data, bool enable) CURLcode Curl_xfer_pause_recv(struct Curl_easy *data, bool enable) { CURLcode result = CURLE_OK; - Curl_rlimit_block(&data->progress.dl.rlimit, enable, &data->progress.now); + Curl_rlimit_block(&data->progress.dl.rlimit, enable, Curl_pgrs_now(data)); if(!enable && Curl_cwriter_is_paused(data)) result = Curl_cwriter_unpause(data); Curl_conn_ev_data_pause(data, enable); diff --git a/lib/url.c b/lib/url.c index fe5c3f38da..29d6b34422 100644 --- a/lib/url.c +++ b/lib/url.c @@ -514,7 +514,6 @@ CURLcode Curl_open(struct Curl_easy **curl) #endif Curl_netrc_init(&data->state.netrc); Curl_init_userdefined(data); - Curl_pgrs_now_set(data); /* on easy handle create */ *curl = data; return CURLE_OK; @@ -638,7 +637,7 @@ static bool conn_maxage(struct Curl_easy *data, timediff_t age_ms; if(data->set.conn_max_idle_ms) { - age_ms = curlx_timediff_ms(now, conn->lastused); + age_ms = curlx_ptimediff_ms(&now, &conn->lastused); if(age_ms > data->set.conn_max_idle_ms) { infof(data, "Too old connection (%" FMT_TIMEDIFF_T " ms idle, max idle is %" FMT_TIMEDIFF_T " ms), disconnect it", @@ -648,7 +647,7 @@ static bool conn_maxage(struct Curl_easy *data, } if(data->set.conn_max_age_ms) { - age_ms = curlx_timediff_ms(now, conn->created); + age_ms = curlx_ptimediff_ms(&now, &conn->created); if(age_ms > data->set.conn_max_age_ms) { infof(data, "Too old connection (created %" FMT_TIMEDIFF_T @@ -673,7 +672,7 @@ bool Curl_conn_seems_dead(struct connectdata *conn, use */ bool dead; - if(conn_maxage(data, conn, data->progress.now)) { + if(conn_maxage(data, conn, *Curl_pgrs_now(data))) { /* avoid check if already too old */ dead = TRUE; } @@ -722,11 +721,11 @@ bool Curl_conn_seems_dead(struct connectdata *conn, } CURLcode Curl_conn_upkeep(struct Curl_easy *data, - struct connectdata *conn, - struct curltime *now) + struct connectdata *conn) { CURLcode result = CURLE_OK; - if(curlx_timediff_ms(*now, conn->keepalive) <= data->set.upkeep_interval_ms) + if(curlx_ptimediff_ms(Curl_pgrs_now(data), &conn->keepalive) <= + data->set.upkeep_interval_ms) return result; /* briefly attach for action */ @@ -744,7 +743,7 @@ CURLcode Curl_conn_upkeep(struct Curl_easy *data, } Curl_detach_connection(data); - conn->keepalive = *now; + conn->keepalive = *Curl_pgrs_now(data); return result; } @@ -1341,7 +1340,7 @@ static struct connectdata *allocate_conn(struct Curl_easy *data) conn->remote_port = -1; /* unknown at this point */ /* Store creation time to help future close decision making */ - conn->created = data->progress.now; + conn->created = *Curl_pgrs_now(data); /* Store current time to give a baseline to keepalive connection times. */ conn->keepalive = conn->created; @@ -3261,7 +3260,8 @@ static CURLcode resolve_server(struct Curl_easy *data, else if(result == CURLE_OPERATION_TIMEDOUT) { failf(data, "Failed to resolve %s '%s' with timeout after %" FMT_TIMEDIFF_T " ms", peertype, ehost->dispname, - curlx_timediff_ms(data->progress.now, data->progress.t_startsingle)); + curlx_ptimediff_ms(Curl_pgrs_now(data), + &data->progress.t_startsingle)); return CURLE_OPERATION_TIMEDOUT; } else if(result) { diff --git a/lib/url.h b/lib/url.h index 6c2f1e144c..3a8d57c377 100644 --- a/lib/url.h +++ b/lib/url.h @@ -90,8 +90,7 @@ bool Curl_conn_seems_dead(struct connectdata *conn, * Perform upkeep operations on the connection. */ CURLcode Curl_conn_upkeep(struct Curl_easy *data, - struct connectdata *conn, - struct curltime *now); + struct connectdata *conn); /** * Always eval all arguments, return the first result != CURLE_OK. diff --git a/lib/vquic/curl_ngtcp2.c b/lib/vquic/curl_ngtcp2.c index 881f06760d..6087481f59 100644 --- a/lib/vquic/curl_ngtcp2.c +++ b/lib/vquic/curl_ngtcp2.c @@ -389,10 +389,11 @@ static void pktx_update_time(struct Curl_easy *data, struct Curl_cfilter *cf) { struct cf_ngtcp2_ctx *ctx = cf->ctx; + const struct curltime *pnow = Curl_pgrs_now(data); - vquic_ctx_update_time(data, &ctx->q); - pktx->ts = (ngtcp2_tstamp)ctx->q.last_op.tv_sec * NGTCP2_SECONDS + - (ngtcp2_tstamp)ctx->q.last_op.tv_usec * NGTCP2_MICROSECONDS; + vquic_ctx_update_time(&ctx->q, pnow); + pktx->ts = (ngtcp2_tstamp)pnow->tv_sec * NGTCP2_SECONDS + + (ngtcp2_tstamp)pnow->tv_usec * NGTCP2_MICROSECONDS; } static void pktx_init(struct pkt_io_ctx *pktx, @@ -400,13 +401,14 @@ static void pktx_init(struct pkt_io_ctx *pktx, struct Curl_easy *data) { struct cf_ngtcp2_ctx *ctx = cf->ctx; + const struct curltime *pnow = Curl_pgrs_now(data); pktx->cf = cf; pktx->data = data; ngtcp2_path_storage_zero(&pktx->ps); - vquic_ctx_set_time(data, &ctx->q); - pktx->ts = (ngtcp2_tstamp)ctx->q.last_op.tv_sec * NGTCP2_SECONDS + - (ngtcp2_tstamp)ctx->q.last_op.tv_usec * NGTCP2_MICROSECONDS; + vquic_ctx_set_time(&ctx->q, pnow); + pktx->ts = (ngtcp2_tstamp)pnow->tv_sec * NGTCP2_SECONDS + + (ngtcp2_tstamp)pnow->tv_usec * NGTCP2_MICROSECONDS; } static int cb_h3_acked_req_body(nghttp3_conn *conn, int64_t stream_id, @@ -505,8 +507,7 @@ static int cf_ngtcp2_handshake_completed(ngtcp2_conn *tconn, void *user_data) if(!ctx || !data) return NGHTTP3_ERR_CALLBACK_FAILURE; - Curl_pgrs_now_set(data); /* real change */ - ctx->handshake_at = data->progress.now; + ctx->handshake_at = *Curl_pgrs_now(data); ctx->tls_handshake_complete = TRUE; Curl_vquic_report_handshake(&ctx->tls, cf, data); @@ -520,7 +521,7 @@ static int cf_ngtcp2_handshake_completed(ngtcp2_conn *tconn, void *user_data) "ms, remote transport[max_udp_payload=%" PRIu64 ", initial_max_data=%" PRIu64 "]", - curlx_timediff_ms(ctx->handshake_at, ctx->started_at), + curlx_ptimediff_ms(&ctx->handshake_at, &ctx->started_at), rp->max_udp_payload_size, rp->initial_max_data); } #endif @@ -1058,7 +1059,8 @@ static void cf_ngtcp2_ack_stream(struct Curl_cfilter *cf, /* How many byte to ack on the stream? */ /* how much does rate limiting allow us to acknowledge? */ - avail = Curl_rlimit_avail(&data->progress.dl.rlimit, &data->progress.now); + avail = Curl_rlimit_avail(&data->progress.dl.rlimit, + Curl_pgrs_now(data)); if(avail == CURL_OFF_T_MAX) { /* no rate limit, ack all */ ack_len = stream->download_unacked; } @@ -1082,7 +1084,6 @@ static int cb_h3_recv_data(nghttp3_conn *conn, int64_t stream3_id, struct Curl_cfilter *cf = user_data; struct cf_ngtcp2_ctx *ctx = cf->ctx; struct Curl_easy *data = stream_user_data; - struct Curl_easy *calling = CF_DATA_CURRENT(cf); struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); (void)conn; @@ -1090,8 +1091,6 @@ static int cb_h3_recv_data(nghttp3_conn *conn, int64_t stream3_id, if(!stream) return NGHTTP3_ERR_CALLBACK_FAILURE; - if(calling) - Curl_pgrs_now_update(data, calling); h3_xfer_write_resp(cf, data, stream, (const char *)buf, blen, FALSE); CURL_TRC_CF(data, cf, "[%" PRId64 "] DATA len=%zu", stream->id, blen); @@ -2637,7 +2636,7 @@ static CURLcode cf_ngtcp2_connect(struct Curl_cfilter *cf, CF_DATA_SAVE(save, cf, data); if(!ctx->qconn) { - ctx->started_at = data->progress.now; + ctx->started_at = *Curl_pgrs_now(data); result = cf_connect_start(cf, data, &pktx); if(result) goto out; @@ -2750,7 +2749,8 @@ static CURLcode cf_ngtcp2_query(struct Curl_cfilter *cf, } case CF_QUERY_CONNECT_REPLY_MS: if(ctx->q.got_first_byte) { - timediff_t ms = curlx_timediff_ms(ctx->q.first_byte_at, ctx->started_at); + timediff_t ms = curlx_ptimediff_ms(&ctx->q.first_byte_at, + &ctx->started_at); *pres1 = (ms < INT_MAX) ? (int)ms : INT_MAX; } else @@ -2812,7 +2812,7 @@ static bool cf_ngtcp2_conn_is_alive(struct Curl_cfilter *cf, rp = ngtcp2_conn_get_remote_transport_params(ctx->qconn); if(rp && rp->max_idle_timeout) { timediff_t idletime_ms = - curlx_timediff_ms(data->progress.now, ctx->q.last_io); + curlx_ptimediff_ms(Curl_pgrs_now(data), &ctx->q.last_io); if(idletime_ms > 0) { uint64_t max_idle_ms = (uint64_t)(rp->max_idle_timeout / NGTCP2_MILLISECONDS); diff --git a/lib/vquic/curl_osslq.c b/lib/vquic/curl_osslq.c index 44a12526f0..dc79fe399c 100644 --- a/lib/vquic/curl_osslq.c +++ b/lib/vquic/curl_osslq.c @@ -1650,7 +1650,7 @@ static CURLcode h3_send_streams(struct Curl_cfilter *cf, if(acked_len > 0 || (eos && !s->send_blocked)) { /* Since QUIC buffers the data written internally, we can tell * nghttp3 that it can move forward on it */ - ctx->q.last_io = curlx_now(); + ctx->q.last_io = *Curl_pgrs_now(data); rv = nghttp3_conn_add_write_offset(ctx->h3.conn, s->id, acked_len); if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) { failf(data, "nghttp3_conn_add_write_offset returned error: %s", @@ -1766,7 +1766,7 @@ static CURLcode cf_osslq_connect(struct Curl_cfilter *cf, CF_DATA_SAVE(save, cf, data); if(!ctx->tls.ossl.ssl) { - ctx->started_at = data->progress.now; + ctx->started_at = *Curl_pgrs_now(data); result = cf_osslq_ctx_start(cf, data); if(result) goto out; @@ -1776,7 +1776,7 @@ static CURLcode cf_osslq_connect(struct Curl_cfilter *cf, int readable = SOCKET_READABLE(ctx->q.sockfd, 0); if(readable > 0 && (readable & CURL_CSELECT_IN)) { ctx->got_first_byte = TRUE; - ctx->first_byte_at = data->progress.now; + ctx->first_byte_at = *Curl_pgrs_now(data); } } @@ -1797,14 +1797,13 @@ static CURLcode cf_osslq_connect(struct Curl_cfilter *cf, /* if not recorded yet, take the timestamp before we called * SSL_do_handshake() as the time we received the first packet. */ ctx->got_first_byte = TRUE; - ctx->first_byte_at = data->progress.now; + ctx->first_byte_at = *Curl_pgrs_now(data); } /* Record the handshake complete with a new time stamp. */ - Curl_pgrs_now_set(data); - ctx->handshake_at = data->progress.now; - ctx->q.last_io = data->progress.now; + ctx->handshake_at = *Curl_pgrs_now(data); + ctx->q.last_io = *Curl_pgrs_now(data); CURL_TRC_CF(data, cf, "handshake complete after %" FMT_TIMEDIFF_T "ms", - curlx_timediff_ms(data->progress.now, ctx->started_at)); + curlx_ptimediff_ms(Curl_pgrs_now(data), &ctx->started_at)); result = cf_osslq_verify_peer(cf, data); if(!result) { CURL_TRC_CF(data, cf, "peer verified"); @@ -1816,17 +1815,17 @@ static CURLcode cf_osslq_connect(struct Curl_cfilter *cf, int detail = SSL_get_error(ctx->tls.ossl.ssl, err); switch(detail) { case SSL_ERROR_WANT_READ: - ctx->q.last_io = data->progress.now; + ctx->q.last_io = *Curl_pgrs_now(data); CURL_TRC_CF(data, cf, "QUIC SSL_connect() -> WANT_RECV"); goto out; case SSL_ERROR_WANT_WRITE: - ctx->q.last_io = data->progress.now; + ctx->q.last_io = *Curl_pgrs_now(data); CURL_TRC_CF(data, cf, "QUIC SSL_connect() -> WANT_SEND"); result = CURLE_OK; goto out; #ifdef SSL_ERROR_WANT_ASYNC case SSL_ERROR_WANT_ASYNC: - ctx->q.last_io = data->progress.now; + ctx->q.last_io = *Curl_pgrs_now(data); CURL_TRC_CF(data, cf, "QUIC SSL_connect() -> WANT_ASYNC"); result = CURLE_OK; goto out; @@ -2240,7 +2239,7 @@ static bool cf_osslq_conn_is_alive(struct Curl_cfilter *cf, goto out; } CURL_TRC_CF(data, cf, "negotiated idle timeout: %" PRIu64 "ms", idle_ms); - idletime = curlx_timediff_ms(data->progress.now, ctx->q.last_io); + idletime = curlx_ptimediff_ms(Curl_pgrs_now(data), &ctx->q.last_io); if(idle_ms && idletime > 0 && (uint64_t)idletime > idle_ms) goto out; } @@ -2330,7 +2329,8 @@ static CURLcode cf_osslq_query(struct Curl_cfilter *cf, } case CF_QUERY_CONNECT_REPLY_MS: if(ctx->got_first_byte) { - timediff_t ms = curlx_timediff_ms(ctx->first_byte_at, ctx->started_at); + timediff_t ms = curlx_ptimediff_ms(&ctx->first_byte_at, + &ctx->started_at); *pres1 = (ms < INT_MAX) ? (int)ms : INT_MAX; } else diff --git a/lib/vquic/curl_quiche.c b/lib/vquic/curl_quiche.c index 4ee12dc005..abf1a23c20 100644 --- a/lib/vquic/curl_quiche.c +++ b/lib/vquic/curl_quiche.c @@ -499,7 +499,6 @@ static void cf_quiche_recv_body(struct Curl_cfilter *cf, } static void cf_quiche_process_ev(struct Curl_cfilter *cf, - struct Curl_easy *calling, struct Curl_easy *data, struct h3_stream_ctx *stream, quiche_h3_event *ev) @@ -507,7 +506,6 @@ static void cf_quiche_process_ev(struct Curl_cfilter *cf, if(!stream) return; - Curl_pgrs_now_update(data, calling); switch(quiche_h3_event_type(ev)) { case QUICHE_H3_EVENT_HEADERS: { struct cb_ctx cb_ctx; @@ -563,7 +561,6 @@ struct cf_quich_disp_ctx { uint64_t stream_id; struct Curl_cfilter *cf; struct Curl_multi *multi; - struct Curl_easy *calling; quiche_h3_event *ev; }; @@ -575,7 +572,7 @@ static bool cf_quiche_disp_event(uint32_t mid, void *val, void *user_data) if(stream->id == dctx->stream_id) { struct Curl_easy *sdata = Curl_multi_get_easy(dctx->multi, mid); if(sdata) - cf_quiche_process_ev(dctx->cf, dctx->calling, sdata, stream, dctx->ev); + cf_quiche_process_ev(dctx->cf, sdata, stream, dctx->ev); return FALSE; /* stop iterating */ } return TRUE; @@ -602,7 +599,7 @@ static CURLcode cf_poll_events(struct Curl_cfilter *cf, stream = H3_STREAM_CTX(ctx, data); if(stream && stream->id == (uint64_t)rv) { /* event for calling transfer */ - cf_quiche_process_ev(cf, data, data, stream, ev); + cf_quiche_process_ev(cf, data, stream, ev); quiche_h3_event_free(ev); if(stream->xfer_result) return stream->xfer_result; @@ -613,7 +610,6 @@ static CURLcode cf_poll_events(struct Curl_cfilter *cf, struct cf_quich_disp_ctx dctx; dctx.stream_id = (uint64_t)rv; dctx.cf = cf; - dctx.calling = data; dctx.multi = data->multi; dctx.ev = ev; Curl_uint32_hash_visit(&ctx->streams, cf_quiche_disp_event, &dctx); @@ -869,7 +865,7 @@ static CURLcode cf_quiche_recv(struct Curl_cfilter *cf, struct Curl_easy *data, *pnread = 0; (void)buf; (void)blen; - vquic_ctx_update_time(data, &ctx->q); + vquic_ctx_update_time(&ctx->q, Curl_pgrs_now(data)); if(!stream) return CURLE_RECV_ERROR; @@ -1079,7 +1075,7 @@ static CURLcode cf_quiche_send(struct Curl_cfilter *cf, struct Curl_easy *data, CURLcode result; *pnwritten = 0; - vquic_ctx_update_time(data, &ctx->q); + vquic_ctx_update_time(&ctx->q, Curl_pgrs_now(data)); result = cf_process_ingress(cf, data); if(result) @@ -1356,7 +1352,7 @@ static CURLcode cf_quiche_connect(struct Curl_cfilter *cf, } *done = FALSE; - vquic_ctx_update_time(data, &ctx->q); + vquic_ctx_update_time(&ctx->q, Curl_pgrs_now(data)); if(!ctx->qconn) { result = cf_quiche_ctx_open(cf, data); @@ -1379,7 +1375,7 @@ static CURLcode cf_quiche_connect(struct Curl_cfilter *cf, if(quiche_conn_is_established(ctx->qconn)) { ctx->handshake_at = ctx->q.last_op; CURL_TRC_CF(data, cf, "handshake complete after %" FMT_TIMEDIFF_T "ms", - curlx_timediff_ms(ctx->handshake_at, ctx->started_at)); + curlx_ptimediff_ms(&ctx->handshake_at, &ctx->started_at)); result = cf_quiche_verify_peer(cf, data); if(!result) { CURL_TRC_CF(data, cf, "peer verified"); @@ -1438,7 +1434,7 @@ static CURLcode cf_quiche_shutdown(struct Curl_cfilter *cf, int err; ctx->shutdown_started = TRUE; - vquic_ctx_update_time(data, &ctx->q); + vquic_ctx_update_time(&ctx->q, Curl_pgrs_now(data)); err = quiche_conn_close(ctx->qconn, TRUE, 0, NULL, 0); if(err) { CURL_TRC_CF(data, cf, "error %d adding shutdown packet, " @@ -1509,7 +1505,8 @@ static CURLcode cf_quiche_query(struct Curl_cfilter *cf, } case CF_QUERY_CONNECT_REPLY_MS: if(ctx->q.got_first_byte) { - timediff_t ms = curlx_timediff_ms(ctx->q.first_byte_at, ctx->started_at); + timediff_t ms = curlx_ptimediff_ms(&ctx->q.first_byte_at, + &ctx->started_at); *pres1 = (ms < INT_MAX) ? (int)ms : INT_MAX; } else diff --git a/lib/vquic/vquic.c b/lib/vquic/vquic.c index 03da05dcce..3bc6835184 100644 --- a/lib/vquic/vquic.c +++ b/lib/vquic/vquic.c @@ -95,7 +95,7 @@ CURLcode vquic_ctx_init(struct Curl_easy *data, } } #endif - vquic_ctx_set_time(data, qctx); + vquic_ctx_set_time(qctx, Curl_pgrs_now(data)); return CURLE_OK; } @@ -105,17 +105,16 @@ void vquic_ctx_free(struct cf_quic_ctx *qctx) Curl_bufq_free(&qctx->sendbuf); } -void vquic_ctx_set_time(struct Curl_easy *data, - struct cf_quic_ctx *qctx) +void vquic_ctx_set_time(struct cf_quic_ctx *qctx, + const struct curltime *pnow) { - qctx->last_op = data->progress.now; + qctx->last_op = *pnow; } -void vquic_ctx_update_time(struct Curl_easy *data, - struct cf_quic_ctx *qctx) +void vquic_ctx_update_time(struct cf_quic_ctx *qctx, + const struct curltime *pnow) { - Curl_pgrs_now_set(data); - qctx->last_op = data->progress.now; + qctx->last_op = *pnow; } static CURLcode send_packet_no_gso(struct Curl_cfilter *cf, diff --git a/lib/vquic/vquic_int.h b/lib/vquic/vquic_int.h index efe4e2c816..82f22b45a8 100644 --- a/lib/vquic/vquic_int.h +++ b/lib/vquic/vquic_int.h @@ -58,11 +58,11 @@ CURLcode vquic_ctx_init(struct Curl_easy *data, struct cf_quic_ctx *qctx); void vquic_ctx_free(struct cf_quic_ctx *qctx); -void vquic_ctx_set_time(struct Curl_easy *data, - struct cf_quic_ctx *qctx); +void vquic_ctx_set_time(struct cf_quic_ctx *qctx, + const struct curltime *pnow); -void vquic_ctx_update_time(struct Curl_easy *data, - struct cf_quic_ctx *qctx); +void vquic_ctx_update_time(struct cf_quic_ctx *qctx, + const struct curltime *pnow); void vquic_push_blocked_pkt(struct Curl_cfilter *cf, struct cf_quic_ctx *qctx, diff --git a/lib/vssh/libssh2.c b/lib/vssh/libssh2.c index 0f023078eb..0cabe28dbb 100644 --- a/lib/vssh/libssh2.c +++ b/lib/vssh/libssh2.c @@ -3119,13 +3119,12 @@ static CURLcode ssh_block_statemach(struct Curl_easy *data, bool disconnect) { CURLcode result = CURLE_OK; - struct curltime start = data->progress.now; + struct curltime start = *Curl_pgrs_now(data); while((sshc->state != SSH_STOP) && !result) { bool block; timediff_t left_ms = 1000; - Curl_pgrs_now_set(data); /* timeout disconnect */ result = ssh_statemachine(data, sshc, sshp, &block); if(result) break; @@ -3141,7 +3140,7 @@ static CURLcode ssh_block_statemach(struct Curl_easy *data, return CURLE_OPERATION_TIMEDOUT; } } - else if(curlx_timediff_ms(data->progress.now, start) > 1000) { + else if(curlx_ptimediff_ms(Curl_pgrs_now(data), &start) > 1000) { /* disconnect timeout */ failf(data, "Disconnect timed out"); result = CURLE_OK; diff --git a/lib/vtls/gtls.c b/lib/vtls/gtls.c index 9e88367737..543173ae58 100644 --- a/lib/vtls/gtls.c +++ b/lib/vtls/gtls.c @@ -412,7 +412,7 @@ CURLcode Curl_gtls_shared_creds_create(struct Curl_easy *data, } shared->refcount = 1; - shared->time = data->progress.now; + shared->time = *Curl_pgrs_now(data); *pcreds = shared; return CURLE_OK; } @@ -559,11 +559,11 @@ static CURLcode gtls_populate_creds(struct Curl_cfilter *cf, /* key to use at `multi->proto_hash` */ #define MPROTO_GTLS_X509_KEY "tls:gtls:x509:share" -static bool gtls_shared_creds_expired(const struct Curl_easy *data, +static bool gtls_shared_creds_expired(struct Curl_easy *data, const struct gtls_shared_creds *sc) { const struct ssl_general_config *cfg = &data->set.general_ssl; - timediff_t elapsed_ms = curlx_timediff_ms(data->progress.now, sc->time); + timediff_t elapsed_ms = curlx_ptimediff_ms(Curl_pgrs_now(data), &sc->time); timediff_t timeout_ms = cfg->ca_cache_timeout * (timediff_t)1000; if(timeout_ms < 0) diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index d09e2d1a71..619fb2e2d0 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -53,6 +53,7 @@ #include "openssl.h" #include "../connect.h" #include "../slist.h" +#include "../progress.h" #include "../select.h" #include "../curlx/wait.h" #include "vtls.h" @@ -3212,14 +3213,14 @@ static void oss_x509_share_free(void *key, size_t key_len, void *p) curlx_free(share); } -static bool ossl_cached_x509_store_expired(const struct Curl_easy *data, +static bool ossl_cached_x509_store_expired(struct Curl_easy *data, const struct ossl_x509_share *mb) { const struct ssl_general_config *cfg = &data->set.general_ssl; if(cfg->ca_cache_timeout < 0) return FALSE; else { - timediff_t elapsed_ms = curlx_timediff_ms(data->progress.now, mb->time); + timediff_t elapsed_ms = curlx_ptimediff_ms(Curl_pgrs_now(data), &mb->time); timediff_t timeout_ms = cfg->ca_cache_timeout * (timediff_t)1000; return elapsed_ms >= timeout_ms; @@ -3241,7 +3242,7 @@ static bool ossl_cached_x509_store_different(struct Curl_cfilter *cf, } static X509_STORE *ossl_get_cached_x509_store(struct Curl_cfilter *cf, - const struct Curl_easy *data, + struct Curl_easy *data, bool *pempty) { struct Curl_multi *multi = data->multi; @@ -3264,7 +3265,7 @@ static X509_STORE *ossl_get_cached_x509_store(struct Curl_cfilter *cf, } static void ossl_set_cached_x509_store(struct Curl_cfilter *cf, - const struct Curl_easy *data, + struct Curl_easy *data, X509_STORE *store, bool is_empty) { @@ -3310,7 +3311,7 @@ static void ossl_set_cached_x509_store(struct Curl_cfilter *cf, curlx_free(share->CAfile); } - share->time = data->progress.now; + share->time = *Curl_pgrs_now(data); share->store = store; share->store_is_empty = is_empty; share->CAfile = CAfile; diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c index 2aa889bde2..986b65ec03 100644 --- a/lib/vtls/schannel.c +++ b/lib/vtls/schannel.c @@ -1722,7 +1722,7 @@ schannel_recv_renegotiate(struct Curl_cfilter *cf, struct Curl_easy *data, connssl->connecting_state = ssl_connect_2; memset(rs, 0, sizeof(*rs)); rs->io_need = CURL_SSL_IO_NEED_SEND; - rs->start_time = curlx_now(); + rs->start_time = *Curl_pgrs_now(data); rs->started = TRUE; } @@ -1731,7 +1731,7 @@ schannel_recv_renegotiate(struct Curl_cfilter *cf, struct Curl_easy *data, curl_socket_t readfd, writefd; timediff_t elapsed; - elapsed = curlx_timediff_ms(curlx_now(), rs->start_time); + elapsed = curlx_ptimediff_ms(Curl_pgrs_now(data), &rs->start_time); if(elapsed >= MAX_RENEG_BLOCK_TIME) { failf(data, "schannel: renegotiation timeout"); result = CURLE_SSL_CONNECT_ERROR; @@ -1797,7 +1797,7 @@ schannel_recv_renegotiate(struct Curl_cfilter *cf, struct Curl_easy *data, if(result) break; - elapsed = curlx_timediff_ms(curlx_now(), rs->start_time); + elapsed = curlx_ptimediff_ms(Curl_pgrs_now(data), &rs->start_time); if(elapsed >= MAX_RENEG_BLOCK_TIME) { failf(data, "schannel: renegotiation timeout"); result = CURLE_SSL_CONNECT_ERROR; @@ -2723,7 +2723,7 @@ static void *schannel_get_internals(struct ssl_connect_data *connssl, } HCERTSTORE Curl_schannel_get_cached_cert_store(struct Curl_cfilter *cf, - const struct Curl_easy *data) + struct Curl_easy *data) { struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); struct Curl_multi *multi = data->multi; @@ -2732,7 +2732,6 @@ HCERTSTORE Curl_schannel_get_cached_cert_store(struct Curl_cfilter *cf, const struct ssl_general_config *cfg = &data->set.general_ssl; timediff_t timeout_ms; timediff_t elapsed_ms; - struct curltime now; unsigned char info_blob_digest[CURL_SHA256_DIGEST_LENGTH]; DEBUGASSERT(multi); @@ -2758,8 +2757,7 @@ HCERTSTORE Curl_schannel_get_cached_cert_store(struct Curl_cfilter *cf, negative timeout means retain forever. */ timeout_ms = cfg->ca_cache_timeout * (timediff_t)1000; if(timeout_ms >= 0) { - now = curlx_now(); - elapsed_ms = curlx_timediff_ms(now, share->time); + elapsed_ms = curlx_ptimediff_ms(Curl_pgrs_now(data), &share->time); if(elapsed_ms >= timeout_ms) { return NULL; } @@ -2803,7 +2801,7 @@ static void schannel_cert_share_free(void *key, size_t key_len, void *p) } bool Curl_schannel_set_cached_cert_store(struct Curl_cfilter *cf, - const struct Curl_easy *data, + struct Curl_easy *data, HCERTSTORE cert_store) { struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); diff --git a/lib/vtls/schannel_int.h b/lib/vtls/schannel_int.h index 88f03aaf68..0146bf8619 100644 --- a/lib/vtls/schannel_int.h +++ b/lib/vtls/schannel_int.h @@ -158,10 +158,10 @@ struct num_ip_data { }; HCERTSTORE Curl_schannel_get_cached_cert_store(struct Curl_cfilter *cf, - const struct Curl_easy *data); + struct Curl_easy *data); bool Curl_schannel_set_cached_cert_store(struct Curl_cfilter *cf, - const struct Curl_easy *data, + struct Curl_easy *data, HCERTSTORE cert_store); #endif /* USE_SCHANNEL */ diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c index 171e3731e8..643009a229 100644 --- a/lib/vtls/vtls.c +++ b/lib/vtls/vtls.c @@ -1371,8 +1371,7 @@ static CURLcode ssl_cf_connect(struct Curl_cfilter *cf, if(!result && *done) { cf->connected = TRUE; if(connssl->state == ssl_connection_complete) { - Curl_pgrs_now_set(data); - connssl->handshake_done = data->progress.now; + connssl->handshake_done = *Curl_pgrs_now(data); } /* Connection can be deferred when sending early data */ DEBUGASSERT(connssl->state == ssl_connection_complete || diff --git a/lib/vtls/wolfssl.c b/lib/vtls/wolfssl.c index 3632d962ef..c2c66715c2 100644 --- a/lib/vtls/wolfssl.c +++ b/lib/vtls/wolfssl.c @@ -723,11 +723,11 @@ static void wssl_x509_share_free(void *key, size_t key_len, void *p) curlx_free(share); } -static bool wssl_cached_x509_store_expired(const struct Curl_easy *data, +static bool wssl_cached_x509_store_expired(struct Curl_easy *data, const struct wssl_x509_share *mb) { const struct ssl_general_config *cfg = &data->set.general_ssl; - timediff_t elapsed_ms = curlx_timediff_ms(data->progress.now, mb->time); + timediff_t elapsed_ms = curlx_ptimediff_ms(Curl_pgrs_now(data), &mb->time); timediff_t timeout_ms = cfg->ca_cache_timeout * (timediff_t)1000; if(timeout_ms < 0) @@ -747,7 +747,7 @@ static bool wssl_cached_x509_store_different(struct Curl_cfilter *cf, } static WOLFSSL_X509_STORE *wssl_get_cached_x509_store(struct Curl_cfilter *cf, - const struct Curl_easy *data) + struct Curl_easy *data) { struct Curl_multi *multi = data->multi; struct wssl_x509_share *share; @@ -767,7 +767,7 @@ static WOLFSSL_X509_STORE *wssl_get_cached_x509_store(struct Curl_cfilter *cf, } static void wssl_set_cached_x509_store(struct Curl_cfilter *cf, - const struct Curl_easy *data, + struct Curl_easy *data, WOLFSSL_X509_STORE *store) { struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); @@ -810,7 +810,7 @@ static void wssl_set_cached_x509_store(struct Curl_cfilter *cf, curlx_free(share->CAfile); } - share->time = data->progress.now; + share->time = *Curl_pgrs_now(data); share->store = store; share->CAfile = CAfile; } diff --git a/tests/unit/unit1303.c b/tests/unit/unit1303.c index 5bdb3f7003..ca2d349bc4 100644 --- a/tests/unit/unit1303.c +++ b/tests/unit/unit1303.c @@ -148,7 +148,7 @@ static CURLcode test_unit1303(const char *arg) NOW(run[i].now_s, run[i].now_us); TIMEOUTS(run[i].timeout_ms, run[i].connecttimeout_ms); easy->progress.now = now; - timeout = Curl_timeleft_ms(easy, run[i].connecting); + timeout = Curl_timeleft_now_ms(easy, &now, run[i].connecting); if(timeout != run[i].result) fail(run[i].comment); } diff --git a/tests/unit/unit1309.c b/tests/unit/unit1309.c index 46596544c6..b5620dcdbb 100644 --- a/tests/unit/unit1309.c +++ b/tests/unit/unit1309.c @@ -78,7 +78,7 @@ static CURLcode test_unit1309(const char *arg) key.tv_usec = (541 * i) % 1023; storage[i] = key.tv_usec; Curl_splayset(&nodes[i], &storage[i]); - root = Curl_splayinsert(key, root, &nodes[i]); + root = Curl_splayinsert(&key, root, &nodes[i]); } puts("Result:"); @@ -111,7 +111,7 @@ static CURLcode test_unit1309(const char *arg) for(j = 0; j <= i % 3; j++) { storage[i * 3 + j] = key.tv_usec * 10 + j; Curl_splayset(&nodes[i * 3 + j], &storage[i * 3 + j]); - root = Curl_splayinsert(key, root, &nodes[i * 3 + j]); + root = Curl_splayinsert(&key, root, &nodes[i * 3 + j]); } } @@ -119,12 +119,12 @@ static CURLcode test_unit1309(const char *arg) for(i = 0; i <= 1100; i += 100) { curl_mprintf("Removing nodes not larger than %d\n", i); tv_now.tv_usec = i; - root = Curl_splaygetbest(tv_now, root, &removed); + root = Curl_splaygetbest(&tv_now, root, &removed); while(removed) { curl_mprintf("removed payload %zu[%zu]\n", *(size_t *)Curl_splayget(removed) / 10, *(size_t *)Curl_splayget(removed) % 10); - root = Curl_splaygetbest(tv_now, root, &removed); + root = Curl_splaygetbest(&tv_now, root, &removed); } } diff --git a/tests/unit/unit1399.c b/tests/unit/unit1399.c index e02bf08bd9..9ce182c154 100644 --- a/tests/unit/unit1399.c +++ b/tests/unit/unit1399.c @@ -78,6 +78,7 @@ static CURLcode test_unit1399(const char *arg) struct Curl_easy data; struct curltime now = curlx_now(); + data.multi = NULL; data.progress.now = now; data.progress.t_nslookup = 0; data.progress.t_connect = 0; diff --git a/tests/unit/unit1607.c b/tests/unit/unit1607.c index 202cc3b9c6..111a5d2f4e 100644 --- a/tests/unit/unit1607.c +++ b/tests/unit/unit1607.c @@ -25,6 +25,7 @@ #include "urldata.h" #include "connect.h" +#include "progress.h" #include "curl_share.h" static CURLcode t1607_setup(void)