summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2020-06-17 09:16:57 +0200
committerDaniel Stenberg <daniel@haxx.se>2020-06-17 16:41:56 +0200
commit57166cf898fb46830448778f47c825c876a263f1 (patch)
treeed2043de6b522e0206394c70c24993b113017dd7
parent8bc25c590e530de87595d1bb3577f699eb1309b9 (diff)
downloadcurl-57166cf898fb46830448778f47c825c876a263f1.tar.gz
time: reduce calls to Curl_now()
Curl_now() returns the current time with microsecond accuracy - but should not be used superfluously. Instead use Curl_mnow(), which is a cached "reasonably updated" current time. To force a time refresh, use Curl_now_update(). Each API entry point should force a time refresh, as well as after any potential waits or delays. As an extra debug-helper: debug builds will get a check in Curl_mnow() that compares the "cached" time with the Curl_now() time and warns on stderr if the delta is 5000 microseconds or more. It also keeps the source name + line number of the most recent update to aid. Fixes #5574
-rw-r--r--lib/asyn-ares.c11
-rw-r--r--lib/asyn-thread.c8
-rw-r--r--lib/conncache.c6
-rw-r--r--lib/connect.c24
-rw-r--r--lib/connect.h4
-rw-r--r--lib/doh.c2
-rw-r--r--lib/easy.c6
-rw-r--r--lib/file.c4
-rw-r--r--lib/ftp.c13
-rw-r--r--lib/gopher.c2
-rw-r--r--lib/hostip.c2
-rw-r--r--lib/http.c1
-rw-r--r--lib/http2.c2
-rw-r--r--lib/http_proxy.c2
-rw-r--r--lib/multi.c117
-rw-r--r--lib/multihandle.h9
-rw-r--r--lib/multiif.h18
-rw-r--r--lib/pingpong.c16
-rw-r--r--lib/pingpong.h3
-rw-r--r--lib/progress.c11
-rw-r--r--lib/progress.h4
-rw-r--r--lib/psl.c32
-rw-r--r--lib/rand.c5
-rw-r--r--lib/smtp.c2
-rw-r--r--lib/socks.c2
-rw-r--r--lib/speedcheck.c6
-rw-r--r--lib/speedcheck.h6
-rw-r--r--lib/telnet.c7
-rw-r--r--lib/tftp.c4
-rw-r--r--lib/timeval.c6
-rw-r--r--lib/timeval.h2
-rw-r--r--lib/transfer.c19
-rw-r--r--lib/url.c21
-rw-r--r--lib/urldata.h2
-rw-r--r--lib/vssh/libssh.c6
-rw-r--r--lib/vssh/libssh2.c5
-rw-r--r--lib/vssh/wolfssh.c6
-rw-r--r--lib/vtls/openssl.c4
-rw-r--r--tests/unit/unit1303.c8
-rw-r--r--tests/unit/unit1606.c11
40 files changed, 249 insertions, 170 deletions
diff --git a/lib/asyn-ares.c b/lib/asyn-ares.c
index ba5160b25..dc9f3b249 100644
--- a/lib/asyn-ares.c
+++ b/lib/asyn-ares.c
@@ -366,7 +366,7 @@ CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
/* This is only set to non-zero if the timer was started. */
&& (res->happy_eyeballs_dns_time.tv_sec
|| res->happy_eyeballs_dns_time.tv_usec)
- && (Curl_timediff(Curl_now(), res->happy_eyeballs_dns_time)
+ && (Curl_timediff(Curl_mnow(data->multi), res->happy_eyeballs_dns_time)
>= HAPPY_EYEBALLS_DNS_TIMEOUT)) {
/* Remember that the EXPIRE_HAPPY_EYEBALLS_DNS timer is no longer
running. */
@@ -419,12 +419,12 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
CURLcode result = CURLE_OK;
struct Curl_easy *data = conn->data;
timediff_t timeout;
- struct curltime now = Curl_now();
+ struct curltime now = Curl_mnow(data->multi);
DEBUGASSERT(entry);
*entry = NULL; /* clear on entry */
- timeout = Curl_timeleft(data, &now, TRUE);
+ timeout = Curl_timeleft(data, TRUE);
if(timeout < 0) {
/* already expired! */
connclose(conn, "Timed out before name resolve started");
@@ -467,7 +467,7 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
if(Curl_pgrsUpdate(conn))
result = CURLE_ABORTED_BY_CALLBACK;
else {
- struct curltime now2 = Curl_now();
+ struct curltime now2 = Curl_mnow(data->multi);
timediff_t timediff = Curl_timediff(now2, now); /* spent time */
if(timediff <= 0)
timeout -= 1; /* always deduct at least 1 */
@@ -527,6 +527,7 @@ static void query_completed_cb(void *arg, /* (struct connectdata *) */
struct hostent *hostent)
{
struct connectdata *conn = (struct connectdata *)arg;
+ struct Curl_easy *data = conn->data;
struct ResolverResults *res;
#ifdef HAVE_CARES_CALLBACK_TIMEOUTS
@@ -607,7 +608,7 @@ static void query_completed_cb(void *arg, /* (struct connectdata *) */
timeout to prevent it. After all, we don't even know where in the
c-ares retry cycle each request is.
*/
- res->happy_eyeballs_dns_time = Curl_now();
+ res->happy_eyeballs_dns_time = Curl_mnow(data->multi);
Curl_expire(
conn->data, HAPPY_EYEBALLS_DNS_TIMEOUT, EXPIRE_HAPPY_EYEBALLS_DNS);
}
diff --git a/lib/asyn-thread.c b/lib/asyn-thread.c
index a60f4f066..f0edcaf8f 100644
--- a/lib/asyn-thread.c
+++ b/lib/asyn-thread.c
@@ -625,7 +625,7 @@ CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
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 = Curl_timediff(Curl_now(),
+ timediff_t elapsed = Curl_timediff(data->multi->mnow,
data->progress.t_startsingle);
if(elapsed < 0)
elapsed = 0;
@@ -671,7 +671,7 @@ int Curl_resolver_getsock(struct connectdata *conn,
}
else {
#endif
- ms = Curl_timediff(Curl_now(), reslv->start);
+ ms = Curl_timediff(data->multi->mnow, reslv->start);
if(ms < 3)
milli = 0;
else if(ms <= 50)
@@ -703,7 +703,7 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
*waitp = 0; /* default to synchronous response */
- reslv->start = Curl_now();
+ reslv->start = data->multi->mnow;
/* fire up a new resolver thread! */
if(init_resolve_thread(conn, hostname, port, NULL)) {
@@ -759,7 +759,7 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
hints.ai_socktype = (conn->transport == TRNSPRT_TCP)?
SOCK_STREAM : SOCK_DGRAM;
- reslv->start = Curl_now();
+ reslv->start = data->multi->mnow;
/* fire up a new resolver thread! */
if(init_resolve_thread(conn, hostname, port, &hints)) {
*waitp = 1; /* expect asynchronous response */
diff --git a/lib/conncache.c b/lib/conncache.c
index d21a00cfd..43b67fb54 100644
--- a/lib/conncache.c
+++ b/lib/conncache.c
@@ -400,7 +400,7 @@ bool Curl_conncache_return_conn(struct Curl_easy *data,
data->multi->maxconnects;
struct connectdata *conn_candidate = NULL;
- conn->lastused = Curl_now(); /* it was used up until now */
+ conn->lastused = Curl_mnow(data->multi); /* it was used up until now */
if(maxconnects > 0 &&
Curl_conncache_size(data) > maxconnects) {
infof(data, "Connection cache is full, closing the oldest one.\n");
@@ -438,7 +438,7 @@ Curl_conncache_extract_bundle(struct Curl_easy *data,
(void)data;
- now = Curl_now();
+ now = Curl_mnow(data->multi);
curr = bundle->conn_list.head;
while(curr) {
@@ -487,7 +487,7 @@ Curl_conncache_extract_oldest(struct Curl_easy *data)
struct connectbundle *bundle;
struct connectbundle *bundle_candidate = NULL;
- now = Curl_now();
+ now = Curl_mnow(data->multi);
CONNCACHE_LOCK(data);
Curl_hash_start_iterate(&connc->hash, &iter);
diff --git a/lib/connect.c b/lib/connect.c
index 46c285537..77a6e49d9 100644
--- a/lib/connect.c
+++ b/lib/connect.c
@@ -184,13 +184,11 @@ singleipconnect(struct connectdata *conn,
*
* @unittest: 1303
*/
-timediff_t Curl_timeleft(struct Curl_easy *data,
- struct curltime *nowp,
- bool duringconnect)
+timediff_t Curl_timeleft(struct Curl_easy *data, bool duringconnect)
{
int timeout_set = 0;
timediff_t timeout_ms = duringconnect?DEFAULT_CONNECT_TIMEOUT:0;
- struct curltime now;
+ struct curltime now = Curl_mnow(data->multi);
/* if a timeout is set, use the most restrictive one */
@@ -222,18 +220,13 @@ timediff_t Curl_timeleft(struct Curl_easy *data,
break;
}
- if(!nowp) {
- now = Curl_now();
- nowp = &now;
- }
-
/* subtract elapsed time */
if(duringconnect)
/* since this most recent connect started */
- timeout_ms -= Curl_timediff(*nowp, data->progress.t_startsingle);
+ timeout_ms -= Curl_timediff(now, data->progress.t_startsingle);
else
/* since the entire operation started */
- timeout_ms -= Curl_timediff(*nowp, data->progress.t_startop);
+ timeout_ms -= Curl_timediff(now, data->progress.t_startop);
if(!timeout_ms)
/* avoid returning 0 as that means no timeout! */
return -1;
@@ -836,10 +829,10 @@ CURLcode Curl_is_connected(struct connectdata *conn,
return CURLE_OK;
}
- now = Curl_now();
+ now = Curl_mnow(data->multi);
/* figure out how long time we have left to connect */
- allow = Curl_timeleft(data, &now, TRUE);
+ allow = Curl_timeleft(data, TRUE);
if(allow < 0) {
/* time-out, bail out, go home */
@@ -1205,7 +1198,7 @@ static CURLcode singleipconnect(struct connectdata *conn,
/* set socket non-blocking */
(void)curlx_nonblock(sockfd, TRUE);
- conn->connecttime = Curl_now();
+ conn->connecttime = Curl_mnow(data->multi);
if(conn->num_addr > 1)
Curl_expire(data, conn->timeoutms_per_addr, EXPIRE_DNS_PER_NAME);
@@ -1314,10 +1307,9 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
const struct Curl_dns_entry *remotehost)
{
struct Curl_easy *data = conn->data;
- struct curltime before = Curl_now();
CURLcode result = CURLE_COULDNT_CONNECT;
int i;
- timediff_t timeout_ms = Curl_timeleft(data, &before, TRUE);
+ timediff_t timeout_ms = Curl_timeleft(data, TRUE);
if(timeout_ms < 0) {
/* a precaution, no need to continue if time already is up */
diff --git a/lib/connect.h b/lib/connect.h
index 6fd9ea878..b4367cca5 100644
--- a/lib/connect.h
+++ b/lib/connect.h
@@ -36,9 +36,7 @@ CURLcode Curl_connecthost(struct connectdata *conn,
/* generic function that returns how much time there's left to run, according
to the timeouts set */
-timediff_t Curl_timeleft(struct Curl_easy *data,
- struct curltime *nowp,
- bool duringconnect);
+timediff_t Curl_timeleft(struct Curl_easy *data, bool duringconnect);
#define DEFAULT_CONNECT_TIMEOUT 300000 /* milliseconds == five minutes */
diff --git a/lib/doh.c b/lib/doh.c
index ebb2c243b..21cdce0b5 100644
--- a/lib/doh.c
+++ b/lib/doh.c
@@ -250,7 +250,7 @@ static CURLcode dohprobe(struct Curl_easy *data,
url = nurl;
}
- timeout_ms = Curl_timeleft(data, NULL, TRUE);
+ timeout_ms = Curl_timeleft(data, TRUE);
if(timeout_ms <= 0) {
result = CURLE_OPERATION_TIMEDOUT;
goto error;
diff --git a/lib/easy.c b/lib/easy.c
index 292cca7f6..4e30cc719 100644
--- a/lib/easy.c
+++ b/lib/easy.c
@@ -507,12 +507,10 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev)
}
/* get the time stamp to use to figure out how long poll takes */
- before = Curl_now();
-
+ before = Curl_mnow(multi);
/* wait for activity or timeout */
pollrc = Curl_poll(fds, numfds, ev->ms);
-
- after = Curl_now();
+ after = Curl_now_update(multi);
ev->msbump = FALSE; /* reset here */
diff --git a/lib/file.c b/lib/file.c
index 576a79463..8de9e50c2 100644
--- a/lib/file.c
+++ b/lib/file.c
@@ -346,7 +346,7 @@ static CURLcode file_upload(struct connectdata *conn)
if(Curl_pgrsUpdate(conn))
result = CURLE_ABORTED_BY_CALLBACK;
else
- result = Curl_speedcheck(data, Curl_now());
+ result = Curl_speedcheck(data);
}
if(!result && Curl_pgrsUpdate(conn))
result = CURLE_ABORTED_BY_CALLBACK;
@@ -533,7 +533,7 @@ static CURLcode file_do(struct connectdata *conn, bool *done)
if(Curl_pgrsUpdate(conn))
result = CURLE_ABORTED_BY_CALLBACK;
else
- result = Curl_speedcheck(data, Curl_now());
+ result = Curl_speedcheck(data);
}
if(Curl_pgrsUpdate(conn))
result = CURLE_ABORTED_BY_CALLBACK;
diff --git a/lib/ftp.c b/lib/ftp.c
index 175d2eea7..1eb424ac8 100644
--- a/lib/ftp.c
+++ b/lib/ftp.c
@@ -329,15 +329,13 @@ static timediff_t ftp_timeleft_accept(struct Curl_easy *data)
{
timediff_t timeout_ms = DEFAULT_ACCEPT_TIMEOUT;
timediff_t other;
- struct curltime now;
+ struct curltime now = Curl_mnow(data->multi);
if(data->set.accepttimeout > 0)
timeout_ms = data->set.accepttimeout;
- now = Curl_now();
-
/* check if the generic timeout possibly is set shorter */
- other = Curl_timeleft(data, &now, FALSE);
+ other = Curl_timeleft(data, FALSE);
if(other && (other < timeout_ms))
/* note that this also works fine for when other happens to be negative
due to it already having elapsed */
@@ -677,11 +675,13 @@ CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
return CURLE_RECV_ERROR;
case 0: /* timeout */
+ Curl_now_update(data->multi);
if(Curl_pgrsUpdate(conn))
return CURLE_ABORTED_BY_CALLBACK;
continue; /* just continue in our loop for the timeout duration */
default: /* for clarity */
+ Curl_now_update(data->multi);
break;
}
}
@@ -3268,7 +3268,7 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
timediff_t old_time = pp->response_time;
pp->response_time = 60*1000; /* give it only a minute for now */
- pp->response = Curl_now(); /* timeout relative now */
+ pp->response = Curl_mnow(data->multi); /* timeout relative now */
result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
@@ -3387,8 +3387,7 @@ CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote)
}
PPSENDF(&conn->proto.ftpc.pp, "%s", cmd);
-
- pp->response = Curl_now(); /* timeout relative now */
+ pp->response = Curl_mnow(conn->data->multi); /* timeout relative now */
result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
if(result)
diff --git a/lib/gopher.c b/lib/gopher.c
index c48098f75..1c9d548ce 100644
--- a/lib/gopher.c
+++ b/lib/gopher.c
@@ -142,7 +142,7 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done)
else
break;
- timeout_ms = Curl_timeleft(conn->data, NULL, FALSE);
+ timeout_ms = Curl_timeleft(conn->data, FALSE);
if(timeout_ms < 0) {
result = CURLE_OPERATION_TIMEDOUT;
break;
diff --git a/lib/hostip.c b/lib/hostip.c
index dd5916e33..6020cba3e 100644
--- a/lib/hostip.c
+++ b/lib/hostip.c
@@ -783,7 +783,7 @@ 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 = Curl_timediff(Curl_now(),
+ timediff_t elapsed_secs = Curl_timediff(data->multi->mnow,
conn->created) / 1000;
/* the alarm period is counted in even number of seconds */
diff --git a/lib/http.c b/lib/http.c
index 482f9ad0a..7a3f93238 100644
--- a/lib/http.c
+++ b/lib/http.c
@@ -2973,6 +2973,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
if(data->req.writebytecount) {
/* if a request-body has been sent off, we make sure this progress is noted
properly */
+ Curl_now_update(data->multi); /* sending that data could be slow */
Curl_pgrsSetUploadCounter(data, data->req.writebytecount);
if(Curl_pgrsUpdate(conn))
result = CURLE_ABORTED_BY_CALLBACK;
diff --git a/lib/http2.c b/lib/http2.c
index 61990019e..e7fc271db 100644
--- a/lib/http2.c
+++ b/lib/http2.c
@@ -224,7 +224,7 @@ static unsigned int http2_conncheck(struct connectdata *check,
}
if(checks_to_perform & CONNCHECK_KEEPALIVE) {
- struct curltime now = Curl_now();
+ struct curltime now = Curl_mnow(check->data->multi);
timediff_t elapsed = Curl_timediff(now, check->keepalive);
if(elapsed > check->upkeep_interval_ms) {
diff --git a/lib/http_proxy.c b/lib/http_proxy.c
index f188cbfc6..d19d36bb9 100644
--- a/lib/http_proxy.c
+++ b/lib/http_proxy.c
@@ -309,7 +309,7 @@ static CURLcode CONNECT(struct connectdata *conn,
s->tunnel_state = TUNNEL_CONNECT;
} /* END CONNECT PHASE */
- check = Curl_timeleft(data, NULL, TRUE);
+ check = Curl_timeleft(data, TRUE);
if(check <= 0) {
failf(data, "Proxy CONNECT aborted due to timeout");
return CURLE_OPERATION_TIMEDOUT;
diff --git a/lib/multi.c b/lib/multi.c
index 121a44593..f3158c02c 100644
--- a/lib/multi.c
+++ b/lib/multi.c
@@ -487,6 +487,10 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
/* make the Curl_easy refer back to this multi handle */
data->multi = multi;
+ /* refresh the time before we call expire or anything else that need the
+ time */
+ Curl_now_update(multi);
+
/* Set the timeout for this handle to expire really soon so that it will
be taken care of even when this handle is added in the midst of operation
when only the curl_multi_socket() API is used. During that flow, only
@@ -1116,6 +1120,8 @@ static CURLMcode Curl_multi_wait(struct Curl_multi *multi,
data = data->next; /* check next handle */
}
+ Curl_now_update(multi);
+
/* If the internally desired timeout is actually shorter than requested from
the outside, then use the shorter time! But only if the internal timer
is actually larger than -1! */
@@ -1355,7 +1361,7 @@ static CURLMcode Curl_multi_wait(struct Curl_multi *multi,
long sleep_ms = 0;
/* Avoid busy-looping when there's nothing particular to wait for */
- if(!curl_multi_timeout(multi, &sleep_ms) && sleep_ms) {
+ if(!multi_timeout(multi, &sleep_ms) && sleep_ms) {
if(sleep_ms > timeout_ms)
sleep_ms = timeout_ms;
/* when there are no easy handles in the multi, this holds a -1
@@ -1466,6 +1472,8 @@ CURLMcode Curl_multi_add_perform(struct Curl_multi *multi,
if(multi->in_callback)
return CURLM_RECURSIVE_API_CALL;
+ Curl_now_update(multi);
+
rc = curl_multi_add_handle(multi, data);
if(!rc) {
struct SingleRequest *k = &data->req;
@@ -1655,31 +1663,88 @@ static CURLcode preconnect(struct Curl_easy *data)
return CURLE_OK;
}
+/*
+ * Curl_now_update() updates the "now" time stamp in the multi handle and
+ * returns it. Call this only after a "time gap" risk of more than a few
+ * milliseconds.
+ *
+ * Sometimes used without a multi handle!
+ */
+struct curltime Curl_now_update_func(struct Curl_multi *multi)
+{
+ struct curltime now = Curl_now();
+ if(multi)
+ multi->mulnow = now;
+ return now;
+}
+
+#ifdef CURLDEBUG
+struct curltime Curl_now_update_debug(struct Curl_multi *multi,
+ const char *file,
+ int lineno)
+{
+ multi->now_file = file;
+ multi->now_lineno = lineno;
+ return Curl_now_update_func(multi);
+}
+
+/*
+ * Curl_mnow_debug() is a debug-only helper function to help us identify
+ * places in the code where we risk a time lag: when Curl_mnow() returns a
+ * time what differs 5000 microseconds or more from what Curl_now() returns.
+ */
+struct curltime Curl_mnow_debug(struct Curl_multi *multi,
+ const char *file, int fileno)
+{
+ if(multi) {
+ struct curltime now = Curl_now();
+ timediff_t delta = Curl_timediff_us(now, multi->mulnow);
+ if(delta >= 5000) {
+ fprintf(stderr, "time lag %ldus at %s:%d (updated at %s:%d)\n",
+ (long)delta, file, fileno,
+ multi->now_file, multi->now_lineno);
+ }
+ DEBUGASSERT(delta < 5000);
+ }
+ return Curl_mnow_func(multi);
+}
+#endif
+
+/*
+ * Sometimes used without a multi handle!
+ */
+struct curltime Curl_mnow_func(const struct Curl_multi *multi)
+{
+ if(multi)
+ return multi->mulnow;
+ return Curl_now();
+}
+
static CURLMcode multi_runsingle(struct Curl_multi *multi,
- struct curltime now,
struct Curl_easy *data)
{
- struct Curl_message *msg = NULL;
- bool connected;
- bool async;
- bool protocol_connected = FALSE;
- bool dophase_done = FALSE;
- bool done = FALSE;
CURLMcode rc;
CURLcode result = CURLE_OK;
- timediff_t timeout_ms;
- timediff_t recv_timeout_ms;
- timediff_t send_timeout_ms;
- int control;
-
if(!GOOD_EASY_HANDLE(data))
return CURLM_BAD_EASY_HANDLE;
do {
+ struct Curl_message *msg = NULL;
+ bool connected;
+ bool async;
+ bool protocol_connected = FALSE;
+ bool dophase_done = FALSE;
+ bool done = FALSE;
+ timediff_t timeout_ms;
+ timediff_t recv_timeout_ms;
+ timediff_t send_timeout_ms;
+ int control;
+
/* A "stream" here is a logical stream if the protocol can handle that
(HTTP/2), or the full connection for older protocols */
bool stream_error = FALSE;
+ struct curltime now = Curl_now_update(multi); /* refresh in the loop */
rc = CURLM_OK;
if(multi_ischanged(multi, TRUE)) {
@@ -1698,8 +1763,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
(data->mstate < CURLM_STATE_COMPLETED)) {
/* we need to wait for the connect state as only then is the start time
stored, but we must not check already completed handles */
- timeout_ms = Curl_timeleft(data, &now,
- (data->mstate <= CURLM_STATE_DO)?
+ timeout_ms = Curl_timeleft(data, (data->mstate <= CURLM_STATE_DO)?
TRUE:FALSE);
if(timeout_ms < 0) {
@@ -2175,7 +2239,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
if(Curl_pgrsUpdate(data->conn))
result = CURLE_ABORTED_BY_CALLBACK;
else
- result = Curl_speedcheck(data, now);
+ result = Curl_speedcheck(data);
if(!result) {
send_timeout_ms = 0;
@@ -2198,7 +2262,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
if(!send_timeout_ms && !recv_timeout_ms) {
multistate(data, CURLM_STATE_PERFORM);
- Curl_ratelimit(data, now);
+ Curl_ratelimit(data);
}
else if(send_timeout_ms >= recv_timeout_ms)
Curl_expire(data, send_timeout_ms, EXPIRE_TOOFAST);
@@ -2232,7 +2296,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
now);
if(send_timeout_ms || recv_timeout_ms) {
- Curl_ratelimit(data, now);
+ Curl_ratelimit(data);
multistate(data, CURLM_STATE_TOOFAST);
if(send_timeout_ms >= recv_timeout_ms)
Curl_expire(data, send_timeout_ms, EXPIRE_TOOFAST);
@@ -2498,7 +2562,7 @@ CURLMcode curl_multi_perform(struct Curl_multi *multi, int *running_handles)
struct Curl_easy *data;
CURLMcode returncode = CURLM_OK;
struct Curl_tree *t;
- struct curltime now = Curl_now();
+ struct curltime now = Curl_now_update(multi);
if(!GOOD_MULTI_HANDLE(multi))
return CURLM_BAD_HANDLE;
@@ -2512,7 +2576,7 @@ CURLMcode curl_multi_perform(struct Curl_multi *multi, int *running_handles)
SIGPIPE_VARIABLE(pipe_st);
sigpipe_ignore(data, &pipe_st);
- result = multi_runsingle(multi, now, data);
+ result = multi_runsingle(multi, data);
sigpipe_restore(&pipe_st);
if(result)
@@ -2908,7 +2972,7 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
CURLMcode result = CURLM_OK;
struct Curl_easy *data = NULL;
struct Curl_tree *t;
- struct curltime now = Curl_now();
+ struct curltime now;
if(checkall) {
/* *perform() deals with running_handles on its own */
@@ -2927,6 +2991,7 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
/* or should we fall-through and do the timer-based stuff? */
return result;
}
+ now = Curl_now_update(multi);
if(s != CURL_SOCKET_TIMEOUT) {
struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s);
@@ -2962,8 +3027,6 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
data = NULL; /* set data to NULL again to avoid calling
multi_runsingle() in case there's no need to */
- now = Curl_now(); /* get a newer time since the multi_runsingle() loop
- may have taken some time */
}
}
else {
@@ -2986,7 +3049,7 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
SIGPIPE_VARIABLE(pipe_st);
sigpipe_ignore(data, &pipe_st);
- result = multi_runsingle(multi, now, data);
+ result = multi_runsingle(multi, data);
sigpipe_restore(&pipe_st);
if(CURLM_OK >= result) {
@@ -3134,7 +3197,7 @@ static CURLMcode multi_timeout(struct Curl_multi *multi,
if(multi->timetree) {
/* we have a tree of expire times */
- struct curltime now = Curl_now();
+ struct curltime now = Curl_mnow(multi);
/* splay the lowest to the bottom */
multi->timetree = Curl_splay(tv_zero, multi->timetree);
@@ -3176,6 +3239,8 @@ CURLMcode curl_multi_timeout(struct Curl_multi *multi,
if(multi->in_callback)
return CURLM_RECURSIVE_API_CALL;
+ Curl_now_update(multi);
+
return multi_timeout(multi, timeout_ms);
}
@@ -3303,7 +3368,7 @@ void Curl_expire(struct Curl_easy *data, timediff_t milli, expire_id id)
DEBUGASSERT(id < EXPIRE_LAST);
- set = Curl_now();
+ set = Curl_mnow(data->multi);
set.tv_sec += (time_t)(milli/1000); /* might be a 64 to 32 bit conversion */
set.tv_usec += (unsigned int)(milli%1000)*1000;
diff --git a/lib/multihandle.h b/lib/multihandle.h
index 94bbad77a..0100f437b 100644
--- a/lib/multihandle.h
+++ b/lib/multihandle.h
@@ -85,6 +85,15 @@ struct Curl_multi {
struct Curl_easy *easyp;
struct Curl_easy *easylp; /* last node */
+ /* Update time with Curl_now_update(), read time with Curl_mnow(). Never
+ access this variable directly. */
+ struct curltime mulnow;
+#ifdef CURLDEBUG
+ /* for debug-logging where the now time was updated last */
+ const char *now_file;
+ int now_lineno;
+#endif
+
int num_easy; /* amount of entries in the linked list above. */
int num_alive; /* amount of easy handles that are added but have not yet
reached COMPLETE state */
diff --git a/lib/multiif.h b/lib/multiif.h
index c07587baf..adf9a3d8c 100644
--- a/lib/multiif.h
+++ b/lib/multiif.h
@@ -38,6 +38,24 @@ bool Curl_multiplex_wanted(const struct Curl_multi *multi);
void Curl_set_in_callback(struct Curl_easy *data, bool value);
bool Curl_is_in_callback(struct Curl_easy *easy);
+struct curltime Curl_now_update_func(struct Curl_multi *m);
+#ifdef CURLDEBUG
+struct curltime Curl_now_update_debug(struct Curl_multi *multi,
+ const char *file, int fileno);
+#define Curl_now_update(x) Curl_now_update_debug(x, __FILE__, __LINE__)
+#else
+#define Curl_now_update(x) Curl_now_update_func(x)
+#endif
+
+struct curltime Curl_mnow_func(const struct Curl_multi *multi);
+#ifdef CURLDEBUG
+struct curltime Curl_mnow_debug(struct Curl_multi *multi,
+ const char *file, int fileno);
+#define Curl_mnow(x) Curl_mnow_debug(x, __FILE__, __LINE__)
+#else
+#define Curl_mnow(x) Curl_mnow_func(x)
+#endif
+
/* Internal version of curl_multi_init() accepts size parameters for the
socket and connection hashes */
struct Curl_multi *Curl_multi_handle(int hashsize, int chashsize);
diff --git a/lib/pingpong.c b/lib/pingpong.c
index ced832ecf..4270130e3 100644
--- a/lib/pingpong.c
+++ b/lib/pingpong.c
@@ -51,6 +51,7 @@ timediff_t Curl_pp_state_timeout(struct pingpong *pp, bool disconnecting)
timediff_t timeout_ms; /* in milliseconds */
timediff_t response_time = (data->set.server_response_timeout)?
data->set.server_response_timeout: pp->response_time;
+ struct curltime now = Curl_mnow(data->multi);
/* if CURLOPT_SERVER_RESPONSE_TIMEOUT is set, use that to determine
remaining time, or use pp->response because SERVER_RESPONSE_TIMEOUT is
@@ -60,12 +61,12 @@ timediff_t Curl_pp_state_timeout(struct pingpong *pp, bool disconnecting)
/* Without a requested timeout, we only wait 'response_time' seconds for the
full response to arrive before we bail out */
timeout_ms = response_time -
- Curl_timediff(Curl_now(), pp->response); /* spent time */
+ Curl_timediff(now, pp->response); /* spent time */
if(data->set.timeout && !disconnecting) {
/* if timeout is requested, find out how much remaining time we have */
timediff_t timeout2_ms = data->set.timeout - /* timeout time */
- Curl_timediff(Curl_now(), conn->now); /* spent time */
+ Curl_timediff(now, data->req.start); /* spent time */
/* pick the lowest number */
timeout_ms = CURLMIN(timeout_ms, timeout2_ms);
@@ -84,8 +85,8 @@ CURLcode Curl_pp_statemach(struct pingpong *pp, bool block,
curl_socket_t sock = conn->sock[FIRSTSOCKET];
int rc;
timediff_t interval_ms;
- timediff_t timeout_ms = Curl_pp_state_timeout(pp, disconnecting);
struct Curl_easy *data = conn->data;
+ timediff_t timeout_ms = Curl_pp_state_timeout(pp, disconnecting);
CURLcode result = CURLE_OK;
if(timeout_ms <= 0) {
@@ -117,10 +118,11 @@ CURLcode Curl_pp_statemach(struct pingpong *pp, bool block,
if(block) {
/* if we didn't wait, we don't have to spend time on this now */
+ Curl_now_update(data->multi);
if(Curl_pgrsUpdate(conn))
result = CURLE_ABORTED_BY_CALLBACK;
else
- result = Curl_speedcheck(data, Curl_now());
+ result = Curl_speedcheck(data);
if(result)
return result;
@@ -143,7 +145,7 @@ void Curl_pp_init(struct pingpong *pp)
pp->nread_resp = 0;
pp->linestart_resp = conn->data->state.buffer;
pp->pending_resp = TRUE;
- pp->response = Curl_now(); /* start response time-out now! */
+ pp->response = Curl_mnow(conn->data->multi);
}
@@ -234,7 +236,7 @@ CURLcode Curl_pp_vsendf(struct pingpong *pp,
free(s);
pp->sendthis = NULL;
pp->sendleft = pp->sendsize = 0;
- pp->response = Curl_now();
+ pp->response = Curl_mnow(data->multi);
}
return CURLE_OK;
@@ -496,7 +498,7 @@ CURLcode Curl_pp_flushsend(struct pingpong *pp)
free(pp->sendthis);
pp->sendthis = NULL;
pp->sendleft = pp->sendsize = 0;
- pp->response = Curl_now();
+ pp->response = Curl_mnow(conn->data->multi);
}
return CURLE_OK;
}
diff --git a/lib/pingpong.h b/lib/pingpong.h
index e874799d4..03a09701b 100644
--- a/lib/pingpong.h
+++ b/lib/pingpong.h
@@ -58,7 +58,7 @@ struct pingpong {
server */
size_t sendleft; /* number of bytes left to send from the sendthis buffer */
size_t sendsize; /* total size of the sendthis buffer */
- struct curltime response; /* set to Curl_now() when a command has been sent
+ struct curltime response; /* set to curren time when a command has been sent
off, used to time-out response reading */
timediff_t response_time; /* When no timeout is given, this is the amount of
milliseconds we await for a server response. */
@@ -90,7 +90,6 @@ void Curl_pp_init(struct pingpong *pp);
triggered */
timediff_t Curl_pp_state_timeout(struct pingpong *pp, bool disconnecting);
-
/***********************************************************************
*
* Curl_pp_sendf()
diff --git a/lib/progress.c b/lib/progress.c
index 895138448..fb84b41bd 100644
--- a/lib/progress.c
+++ b/lib/progress.c
@@ -168,7 +168,7 @@ void Curl_pgrsResetTransferSizes(struct Curl_easy *data)
*/
void Curl_pgrsTime(struct Curl_easy *data, timerid timer)
{
- struct curltime now = Curl_now();
+ struct curltime now = Curl_mnow(data->multi);
timediff_t *delta = NULL;
switch(timer) {
@@ -233,7 +233,7 @@ void Curl_pgrsTime(struct Curl_easy *data, timerid timer)
void Curl_pgrsStartNow(struct Curl_easy *data)
{
data->progress.speeder_c = 0; /* reset the progress meter display */
- data->progress.start = Curl_now();
+ data->progress.start = Curl_mnow(data->multi);
data->progress.is_t_startransfer_set = false;
data->progress.ul_limit_start.tv_sec = 0;
data->progress.ul_limit_start.tv_usec = 0;
@@ -243,7 +243,7 @@ void Curl_pgrsStartNow(struct Curl_easy *data)
data->progress.uploaded = 0;
/* clear all bits except HIDE and HEADERS_OUT */
data->progress.flags &= PGRS_HIDE|PGRS_HEADERS_OUT;
- Curl_ratelimit(data, data->progress.start);
+ Curl_ratelimit(data);
}
/*
@@ -316,8 +316,9 @@ void Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size)
/*
* Update the timestamp and sizestamp to use for rate limit calculations.
*/
-void Curl_ratelimit(struct Curl_easy *data, struct curltime now)
+void Curl_ratelimit(struct Curl_easy *data)
{
+ struct curltime now = Curl_mnow(data->multi);
/* don't set a new stamp unless the time since last update is long enough */
if(data->set.max_recv_speed > 0) {
if(Curl_timediff(now, data->progress.dl_limit_start) >=
@@ -581,7 +582,7 @@ static void progress_meter(struct connectdata *conn)
int Curl_pgrsUpdate(struct connectdata *conn)
{
struct Curl_easy *data = conn->data;
- struct curltime now = Curl_now(); /* what time is it */
+ struct curltime now = Curl_mnow(data->multi); /* what time is it */
bool showprogress = progress_calc(conn, now);
if(!(data->progress.flags & PGRS_HIDE)) {
if(data->set.fxferinfo) {
diff --git a/lib/progress.h b/lib/progress.h
index 3515ac6d5..80dfa9bda 100644
--- a/lib/progress.h
+++ b/lib/progress.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -46,7 +46,7 @@ void Curl_pgrsSetDownloadSize(struct Curl_easy *data, curl_off_t size);
void Curl_pgrsSetUploadSize(struct Curl_easy *data, curl_off_t size);
void Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size);
void Curl_pgrsSetUploadCounter(struct Curl_easy *data, curl_off_t size);
-void Curl_ratelimit(struct Curl_easy *data, struct curltime now);
+void Curl_ratelimit(struct Curl_easy *data);
int Curl_pgrsUpdate(struct connectdata *);
void Curl_pgrsResetTransferSizes(struct Curl_easy *data);
void Curl_pgrsTime(struct Curl_easy *data, timerid timer);
diff --git a/lib/psl.c b/lib/psl.c
index 568baff03..f3333528b 100644
--- a/lib/psl.c
+++ b/lib/psl.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -28,6 +28,7 @@
#include "psl.h"
#include "share.h"
+#include "multiif.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -44,33 +45,32 @@ void Curl_psl_destroy(struct PslCache *pslcache)
}
}
-static time_t now_seconds(void)
+static time_t now_seconds(struct Curl_easy *data)
{
- struct curltime now = Curl_now();
-
+ struct curltime now = Curl_mnow(data->multi);
return now.tv_sec;
}
-const psl_ctx_t *Curl_psl_use(struct Curl_easy *easy)
+const psl_ctx_t *Curl_psl_use(struct Curl_easy *data)
{
- struct PslCache *pslcache = easy->psl;
+ struct PslCache *pslcache = data->psl;
const psl_ctx_t *psl;
time_t now;
if(!pslcache)
return NULL;
- Curl_share_lock(easy, CURL_LOCK_DATA_PSL, CURL_LOCK_ACCESS_SHARED);
- now = now_seconds();
+ Curl_share_lock(data, CURL_LOCK_DATA_PSL, CURL_LOCK_ACCESS_SHARED);
+ now = now_seconds(data);
if(!pslcache->psl || pslcache->expires <= now) {
/* Let a chance to other threads to do the job: avoids deadlock. */
- Curl_share_unlock(easy, CURL_LOCK_DATA_PSL);
+ Curl_share_unlock(data, CURL_LOCK_DATA_PSL);
/* Update cache: this needs an exclusive lock. */
- Curl_share_lock(easy, CURL_LOCK_DATA_PSL, CURL_LOCK_ACCESS_SINGLE);
+ Curl_share_lock(data, CURL_LOCK_DATA_PSL, CURL_LOCK_ACCESS_SINGLE);
/* Recheck in case another thread did the job. */
- now = now_seconds();
+ now = now_seconds(data);
if(!pslcache->psl || pslcache->expires <= now) {
bool dynamic = FALSE;
time_t expires = TIME_T_MAX;
@@ -94,18 +94,18 @@ const psl_ctx_t *Curl_psl_use(struct Curl_easy *easy)
pslcache->expires = expires;
}
}
- Curl_share_unlock(easy, CURL_LOCK_DATA_PSL); /* Release exclusive lock. */
- Curl_share_lock(easy, CURL_LOCK_DATA_PSL, CURL_LOCK_ACCESS_SHARED);
+ Curl_share_unlock(data, CURL_LOCK_DATA_PSL); /* Release exclusive lock. */
+ Curl_share_lock(data, CURL_LOCK_DATA_PSL, CURL_LOCK_ACCESS_SHARED);
}
psl = pslcache->psl;
if(!psl)
- Curl_share_unlock(easy, CURL_LOCK_DATA_PSL);
+ Curl_share_unlock(data, CURL_LOCK_DATA_PSL);
return psl;
}
-void Curl_psl_release(struct Curl_easy *easy)
+void Curl_psl_release(struct Curl_easy *data)
{
- Curl_share_unlock(easy, CURL_LOCK_DATA_PSL);
+ Curl_share_unlock(data, CURL_LOCK_DATA_PSL);
}
#endif /* USE_LIBPSL */
diff --git a/lib/rand.c b/lib/rand.c
index c415048ec..b9ad7a74f 100644
--- a/lib/rand.c
+++ b/lib/rand.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -30,6 +30,7 @@
#include "vtls/vtls.h"
#include "sendf.h"
#include "rand.h"
+#include "multiif.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -86,7 +87,7 @@ static CURLcode randit(struct Curl_easy *data, unsigned int *rnd)
#endif
if(!seeded) {
- struct curltime now = Curl_now();
+ struct curltime now = Curl_mnow(data->multi);
infof(data, "WARNING: Using weak random seed\n");
randseed += (unsigned int)now.tv_usec + (unsigned int)now.tv_sec;
randseed = randseed * 1103515245 + 12345;
diff --git a/lib/smtp.c b/lib/smtp.c
index ec936480e..3f68c9d19 100644
--- a/lib/smtp.c
+++ b/lib/smtp.c
@@ -1412,7 +1412,7 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
}
else {
/* Successfully sent so adjust the response timeout relative to now */
- pp->response = Curl_now();
+ pp->response = Curl_mnow(data->multi);
free(eob);
}
diff --git a/lib/socks.c b/lib/socks.c
index b2215fef3..57dfcb372 100644
--- a/lib/socks.c
+++ b/lib/socks.c
@@ -62,7 +62,7 @@ int Curl_blockread_all(struct connectdata *conn, /* connection data */
int result;
*n = 0;
for(;;) {
- timediff_t timeout_ms = Curl_timeleft(conn->data, NULL, TRUE);
+ timediff_t timeout_ms = Curl_timeleft(conn->data, TRUE);
if(timeout_ms < 0) {
/* we already got the timeout */
result = CURLE_OPERATION_TIMEDOUT;
diff --git a/lib/speedcheck.c b/lib/speedcheck.c
index 3aeea9111..b756987ee 100644
--- a/lib/speedcheck.c
+++ b/lib/speedcheck.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2017, 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -36,9 +36,9 @@ void Curl_speedinit(struct Curl_easy *data)
/*
* @unittest: 1606
*/
-CURLcode Curl_speedcheck(struct Curl_easy *data,
- struct curltime now)
+CURLcode Curl_speedcheck(struct Curl_easy *data)
{
+ struct curltime now = Curl_mnow(data->multi);
if((data->progress.current_speed >= 0) && data->set.low_speed_time) {
if(data->progress.current_speed < data->set.low_speed_limit) {
if(!data->state.keeps_speed.tv_sec)
diff --git a/lib/speedcheck.h b/lib/speedcheck.h
index 5c2dc9a22..4d05fbfdf 100644
--- a/lib/speedcheck.h
+++ b/lib/speedcheck.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -27,7 +27,5 @@
#include "timeval.h"
void Curl_speedinit(struct Curl_easy *data);
-CURLcode Curl_speedcheck(struct Curl_easy *data,
- struct curltime now);
-
+CURLcode Curl_speedcheck(struct Curl_easy *data);
#endif /* HEADER_CURL_SPEEDCHECK_H */
diff --git a/lib/telnet.c b/lib/telnet.c
index 01394e1e3..752a23866 100644
--- a/lib/telnet.c
+++ b/lib/telnet.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -56,6 +56,7 @@
#include "select.h"
#include "strcase.h"
#include "warnless.h"
+#include "multiif.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -1559,7 +1560,7 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done)
}
if(data->set.timeout) {
- now = Curl_now();
+ now = data->multi->mnow;
if(Curl_timediff(now, conn->created) >= data->set.timeout) {
failf(data, "Time-out");
result = CURLE_OPERATION_TIMEDOUT;
@@ -1677,7 +1678,7 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done)
} /* poll switch statement */
if(data->set.timeout) {
- now = Curl_now();
+ now = Curl_mnow(data->multi);
if(Curl_timediff(now, conn->created) >= data->set.timeout) {
failf(data, "Time-out");
result = CURLE_OPERATION_TIMEDOUT;
diff --git a/lib/tftp.c b/lib/tftp.c
index 4f2f973a8..b9f269c9e 100644
--- a/lib/tftp.c
+++ b/lib/tftp.c
@@ -205,7 +205,7 @@ static CURLcode tftp_set_timeouts(struct tftp_state_data *state)
time(&state->start_time);
/* Compute drop-dead time */
- timeout_ms = Curl_timeleft(state->conn->data, NULL, start);
+ timeout_ms = Curl_timeleft(state->conn->data, start);
if(timeout_ms < 0) {
/* time-out, bail out, go home */
@@ -1315,7 +1315,7 @@ static CURLcode tftp_doing(struct connectdata *conn, bool *dophase_done)
if(Curl_pgrsUpdate(conn))
result = CURLE_ABORTED_BY_CALLBACK;
else
- result = Curl_speedcheck(conn->data, Curl_now());
+ result = Curl_speedcheck(conn->data);
}
return result;
}
diff --git a/lib/timeval.c b/lib/timeval.c
index e761966a1..0abbe46e1 100644
--- a/lib/timeval.c
+++ b/lib/timeval.c
@@ -24,6 +24,12 @@
#if defined(WIN32) && !defined(MSDOS)
+/*
+ * Curl_now() returns the current time with microsecond accuracy - but it
+ * SHOULD BE AVOIDED. Instead use Curl_mnow(). To force a time refresh, use
+ * Curl_now_update().
+ */
+
/* set in win32_init() */
extern LARGE_INTEGER Curl_freq;
extern bool Curl_isVistaOrGreater;
diff --git a/lib/timeval.h b/lib/timeval.h
index 53e063607..b0b9b72ea 100644
--- a/lib/timeval.h
+++ b/lib/timeval.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
diff --git a/lib/transfer.c b/lib/transfer.c
index 133a4783c..57182e2be 100644
--- a/lib/transfer.c
+++ b/lib/transfer.c
@@ -614,7 +614,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
Curl_pgrsTime(data, TIMER_STARTTRANSFER);
if(k->exp100 > EXP100_SEND_DATA)
/* set time stamp to compare with when waiting for the 100 */
- k->start100 = Curl_now();
+ k->start100 = Curl_mnow(data->multi);
}
*didwhat |= KEEP_RECV;
@@ -1033,7 +1033,7 @@ static CURLcode readwrite_upload(struct Curl_easy *data,
go into the Expect: 100 state and await such a header */
k->exp100 = EXP100_AWAITING_CONTINUE; /* wait for the header */
k->keepon &= ~KEEP_SEND; /* disable writing */
- k->start100 = Curl_now(); /* timeout count starts now */
+ k->start100 = Curl_mnow(data->multi); /* timeout count starts now */
*didwhat &= ~KEEP_SEND; /* we didn't write anything actually */
/* set a timeout for the multi interface */
Curl_expire(data, data->set.expect_100_timeout, EXPIRE_100_TIMEOUT);
@@ -1209,7 +1209,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
struct SingleRequest *k = &data->req;
CURLcode result;
int didwhat = 0;
-
+ struct curltime now = Curl_mnow(data->multi);
curl_socket_t fd_read;
curl_socket_t fd_write;
int select_res = conn->cselect_bits;
@@ -1261,7 +1261,6 @@ CURLcode Curl_readwrite(struct connectdata *conn,
return result;
}
- k->now = Curl_now();
if(didwhat) {
;
}
@@ -1281,7 +1280,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
*/
- timediff_t ms = Curl_timediff(k->now, k->start100);
+ timediff_t ms = Curl_timediff(now, k->start100);
if(ms >= data->set.expect_100_timeout) {
/* we've waited long enough, continue anyway */
k->exp100 = EXP100_SEND_DATA;
@@ -1295,23 +1294,23 @@ CURLcode Curl_readwrite(struct connectdata *conn,
if(Curl_pgrsUpdate(conn))
result = CURLE_ABORTED_BY_CALLBACK;
else
- result = Curl_speedcheck(data, k->now);
+ result = Curl_speedcheck(data);
if(result)
return result;
if(k->keepon) {
- if(0 > Curl_timeleft(data, &k->now, FALSE)) {
+ if(0 > Curl_timeleft(data, FALSE)) {
if(k->size != -1) {
failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T
" milliseconds with %" CURL_FORMAT_CURL_OFF_T " out of %"
CURL_FORMAT_CURL_OFF_T " bytes received",
- Curl_timediff(k->now, data->progress.t_startsingle),
+ Curl_timediff(now, data->progress.t_startsingle),
k->bytecount, k->size);
}
else {
failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T
" milliseconds with %" CURL_FORMAT_CURL_OFF_T " bytes received",
- Curl_timediff(k->now, data->progress.t_startsingle),
+ Curl_timediff(now, data->progress.t_startsingle),
k->bytecount);
}
return CURLE_OPERATION_TIMEDOUT;
@@ -1902,7 +1901,7 @@ Curl_setup_transfer(
(http->sending == HTTPSEND_BODY)) {
/* wait with write until we either got 100-continue or a timeout */
k->exp100 = EXP100_AWAITING_CONTINUE;
- k->start100 = Curl_now();
+ k->start100 = Curl_mnow(data->multi);
/* Set a timeout for the multi interface. Add the inaccuracy margin so
that we don't fire slightly too early and get denied to run. */
diff --git a/lib/url.c b/lib/url.c
index 4021c5d78..5b3218f40 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -944,7 +944,7 @@ static bool extract_if_dead(struct connectdata *conn,
/* The check for a dead socket makes sense only if the connection isn't in
use */
bool dead;
- struct curltime now = Curl_now();
+ struct curltime now = Curl_mnow(data->multi);
if(conn_maxage(data, conn, now)) {
dead = TRUE;
}
@@ -999,7 +999,7 @@ static int call_extract_if_dead(struct connectdata *conn, void *param)
*/
static void prune_dead_connections(struct Curl_easy *data)
{
- struct curltime now = Curl_now();
+ struct curltime now = Curl_mnow(data->multi);
timediff_t elapsed;
CONNCACHE_LOCK(data);
@@ -1624,10 +1624,10 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
connclose(conn, "Default to force-close");
/* Store creation time to help future close decision making */
- conn->created = Curl_now();
+ conn->created = Curl_mnow(data->multi);
/* Store current time to give a baseline to keepalive connection times. */
- conn->keepalive = Curl_now();
+ conn->keepalive = Curl_mnow(data->multi);
/* Store off the configured connection upkeep time. */
conn->upkeep_interval_ms = data->set.upkeep_interval_ms;
@@ -1705,7 +1705,7 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
it may live on without (this specific) Curl_easy */
conn->fclosesocket = data->set.fclosesocket;
conn->closesocket_client = data->set.closesocket_client;
- conn->lastused = Curl_now(); /* used now */
+ conn->lastused = Curl_mnow(data->multi); /* used now */
return conn;
error:
@@ -3145,7 +3145,7 @@ static CURLcode resolve_server(struct Curl_easy *data,
bool *async)
{
CURLcode result = CURLE_OK;
- timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
+ timediff_t timeout_ms = Curl_timeleft(data, TRUE);
DEBUGASSERT(conn);
DEBUGASSERT(data);
@@ -3898,10 +3898,6 @@ CURLcode Curl_setup_conn(struct connectdata *conn,
data->state.crlf_conversions = 0; /* reset CRLF conversion counter */
#endif /* CURL_DO_LINEEND_CONV */
- /* set start time here for timeout purposes in the connect procedure, it
- is later set again for the progress meter purpose */
- conn->now = Curl_now();
-
if(CURL_SOCKET_BAD == conn->sock[FIRSTSOCKET]) {
conn->bits.tcpconnect[FIRSTSOCKET] = FALSE;
result = Curl_connecthost(conn, conn->dns_entry);
@@ -3919,8 +3915,6 @@ CURLcode Curl_setup_conn(struct connectdata *conn,
Curl_verboseconnect(conn);
}
- conn->now = Curl_now(); /* time this *after* the connect is done, we set
- this here perhaps a second time */
return result;
}
@@ -3997,8 +3991,7 @@ CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn)
/* in HTTP lingo, no body means using the HEAD request... */
data->state.httpreq = HTTPREQ_HEAD;
- k->start = Curl_now(); /* start time */
- k->now = k->start; /* current time is now */
+ k->start = Curl_mnow(data->multi); /* start time */
k->header = TRUE; /* assume header */
k->bytecount = 0;
k->ignorebody = FALSE;
diff --git a/lib/urldata.h b/lib/urldata.h
index 33ec160ac..82644a0f5 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -606,7 +606,6 @@ struct SingleRequest {
CURLE_GOT_NOTHING error code */
struct curltime start; /* transfer started at this time */
- struct curltime now; /* current time */
enum {
HEADER_NORMAL, /* no bad header at all */
HEADER_PARTHEADER, /* part of the chunk is a bad header, the rest
@@ -949,7 +948,6 @@ struct connectdata {
int httpversion; /* the HTTP version*10 reported by the server */
int rtspversion; /* the RTSP version*10 reported by the server */
- struct curltime now; /* "current" time */
struct curltime created; /* creation time */
struct curltime lastused; /* when returned to the connection cache */
curl_socket_t sock[2]; /* two sockets, the second is used for the data
diff --git a/lib/vssh/libssh.c b/lib/vssh/libssh.c
index 8988e2392..457d1d3aa 100644
--- a/lib/vssh/libssh.c
+++ b/lib/vssh/libssh.c
@@ -2089,7 +2089,7 @@ static CURLcode myssh_block_statemach(struct connectdata *conn,
while((sshc->state != SSH_STOP) && !result) {
bool block;
timediff_t left = 1000;
- struct curltime now = Curl_now();
+ struct curltime now = data->multi->mnow;
result = myssh_statemach_act(conn, &block);
if(result)
@@ -2099,11 +2099,11 @@ static CURLcode myssh_block_statemach(struct connectdata *conn,
if(Curl_pgrsUpdate(conn))
return CURLE_ABORTED_BY_CALLBACK;
- result = Curl_speedcheck(data, now);
+ result = Curl_speedcheck(data);
if(result)
break;
- left = Curl_timeleft(data, NULL, FALSE);
+ left = Curl_timeleft(data, FALSE);
if(left < 0) {
failf(data, "Operation timed out");
return CURLE_OPERATION_TIMEDOUT;
diff --git a/lib/vssh/libssh2.c b/lib/vssh/libssh2.c
index 555afc9ef..f6258bfaf 100644
--- a/lib/vssh/libssh2.c
+++ b/lib/vssh/libssh2.c
@@ -2942,7 +2942,6 @@ static CURLcode ssh_block_statemach(struct connectdata *conn,
while((sshc->state != SSH_STOP) && !result) {
bool block;
timediff_t left = 1000;
- struct curltime now = Curl_now();
result = ssh_statemach_act(conn, &block);
if(result)
@@ -2951,11 +2950,11 @@ static CURLcode ssh_block_statemach(struct connectdata *conn,
if(Curl_pgrsUpdate(conn))
return CURLE_ABORTED_BY_CALLBACK;
- result = Curl_speedcheck(data, now);
+ result = Curl_speedcheck(data);
if(result)
break;
- left = Curl_timeleft(data, NULL, duringconnect);
+ left = Curl_timeleft(data, duringconnect);
if(left < 0) {
failf(data, "Operation timed out");
return CURLE_OPERATION_TIMEDOUT;
diff --git a/lib/vssh/wolfssh.c b/lib/vssh/wolfssh.c
index dcbbab6c3..ae4314bd8 100644
--- a/lib/vssh/wolfssh.c
+++ b/lib/vssh/wolfssh.c
@@ -982,7 +982,7 @@ static CURLcode wssh_block_statemach(struct connectdata *conn,
while((sshc->state != SSH_STOP) && !result) {
bool block;
timediff_t left = 1000;
- struct curltime now = Curl_now();
+ struct curltime now = data->multi->mnow;
result = wssh_statemach_act(conn, &block);
if(result)
@@ -992,11 +992,11 @@ static CURLcode wssh_block_statemach(struct connectdata *conn,
if(Curl_pgrsUpdate(conn))
return CURLE_ABORTED_BY_CALLBACK;
- result = Curl_speedcheck(data, now);
+ result = Curl_speedcheck(data);
if(result)
break;
- left = Curl_timeleft(data, NULL, FALSE);
+ left = Curl_timeleft(data, FALSE);
if(left < 0) {
failf(data, "Operation timed out");
return CURLE_OPERATION_TIMEDOUT;
diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c
index 41d948b3a..c819fca66 100644
--- a/lib/vtls/openssl.c
+++ b/lib/vtls/openssl.c
@@ -3974,7 +3974,7 @@ static CURLcode ossl_connect_common(struct connectdata *conn,
if(ssl_connect_1 == connssl->connecting_state) {
/* Find out how much more time we're allowed */
- const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
+ const timediff_t timeout_ms = Curl_timeleft(data, TRUE);
if(timeout_ms < 0) {
/* no need to continue if time already is up */
@@ -3992,7 +3992,7 @@ static CURLcode ossl_connect_common(struct connectdata *conn,
ssl_connect_2_writing == connssl->connecting_state) {
/* check allowed time left */
- const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
+ const timediff_t timeout_ms = Curl_timeleft(data, TRUE);
if(timeout_ms < 0) {
/* no need to continue if time already is up */
diff --git a/tests/unit/unit1303.c b/tests/unit/unit1303.c
index 945b82ba7..9e7bd0585 100644
--- a/tests/unit/unit1303.c
+++ b/tests/unit/unit1303.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -49,7 +49,7 @@ static void unit_stop(void)
#define BASE 1000000
/* macro to set the pretended current time */
-#define NOW(x,y) now.tv_sec = x; now.tv_usec = y
+#define NOW(x,y) nowp->tv_sec = x; nowp->tv_usec = y
/* macro to set the millisecond based timeouts to use */
#define TIMEOUTS(x,y) data->set.timeout = x; data->set.connecttimeout = y
@@ -74,7 +74,7 @@ struct timetest {
UNITTEST_START
{
- struct curltime now;
+ struct curltime *nowp = &data->multi->mulnow;
unsigned int i;
const struct timetest run[] = {
@@ -141,7 +141,7 @@ UNITTEST_START
timediff_t timeout;
NOW(run[i].now_s, run[i].now_us);
TIMEOUTS(run[i].timeout_ms, run[i].connecttimeout_ms);
- timeout = Curl_timeleft(data, &now, run[i].connecting);
+ timeout = Curl_timeleft(data, run[i].connecting);
if(timeout != run[i].result)
fail(run[i].comment);
}
diff --git a/tests/unit/unit1606.c b/tests/unit/unit1606.c
index 9da0b70b6..d68e0562a 100644
--- a/tests/unit/unit1606.c
+++ b/tests/unit/unit1606.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -49,7 +49,6 @@ static int runawhile(long time_limit,
int dec)
{
int counter = 1;
- struct curltime now = {1, 0};
CURLcode result;
int finaltime;
@@ -57,18 +56,20 @@ static int runawhile(long time_limit,
curl_easy_setopt(easy, CURLOPT_LOW_SPEED_TIME, time_limit);
Curl_speedinit(easy);
+ easy->multi->mulnow.tv_sec = 1;
+ easy->multi->mulnow.tv_usec = 0;
do {
/* fake the current transfer speed */
easy->progress.current_speed = speed;
- result = Curl_speedcheck(easy, now);
+ result = Curl_speedcheck(easy);
if(result)
break;
/* step the time */
- now.tv_sec = ++counter;
+ easy->multi->mulnow.tv_sec = ++counter;
speed -= dec;
} while(counter < 100);
- finaltime = (int)(now.tv_sec - 1);
+ finaltime = (int)(easy->multi->mulnow.tv_sec - 1);
return finaltime;
}