curl_multi_setopt
curl_multi_assign
curl_multi_get_handles
+curl_multi_get_offt
curl_pushheader_bynum
curl_pushheader_byname
curl_multi_waitfds
curl_multi_cleanup.3 \
curl_multi_fdset.3 \
curl_multi_get_handles.3 \
+ curl_multi_get_offt.3 \
curl_multi_info_read.3 \
curl_multi_init.3 \
curl_multi_perform.3 \
--- /dev/null
+---
+c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+SPDX-License-Identifier: curl
+Title: curl_multi_get_offt
+Section: 3
+Source: libcurl
+See-also:
+ - curl_multi_add_handle (3)
+ - curl_multi_remove_handle (3)
+Protocol:
+ - All
+Added-in: 8.16.0
+---
+
+# NAME
+
+curl_multi_get_offt - extract information from a multi handle
+
+# SYNOPSIS
+
+~~~c
+#include <curl/curl.h>
+
+CURLMcode curl_multi_get_offt(CURLM *multi_handle,
+ CURLMinfo_offt info,
+ curl_off_t *pvalue);
+~~~
+
+# DESCRIPTION
+
+Get the *info* kept in the *multi* handle for `CURLMI_OFFT_*`.
+If the *info* is not applicable, this function returns CURLM_UNKNOWN_OPTION.
+
+# OPTIONS
+
+The following information can be extracted:
+
+## CURLMINFO_XFERS_CURRENT
+
+The number of easy handles currently added to the multi. This does not
+count handles removed. It does count internal handles that get
+added for tasks (like resolving via DoH, for example).
+
+For the total number of easy handles ever added to the multi, see
+*CURLMINFO_XFERS_ADDED*.
+
+## CURLMINFO_XFERS_RUNNING
+
+The number of easy handles currently running, e.g. where the transfer
+has started but not finished yet.
+
+## CURLMINFO_XFERS_PENDING
+
+The number of current easy handles waiting to start. An added transfer
+might become pending for various reasons: a connection limit forces it
+to wait, resolving DNS is not finished or it is not clear if an existing,
+matching connection may allow multiplexing (HTTP/2 or HTTP/3).
+
+## CURLMINFO_XFERS_DONE
+
+The number of easy handles currently finished, but not yet processed
+via curl_multi_info_read(3).
+
+## CURLMINFO_XFERS_ADDED
+
+The cumulative number of all easy handles added to the multi, ever.
+This includes internal handles added for tasks (like resolving
+via DoH, for example).
+
+For the current number of easy handles managed by the multi, use
+*CURLMINFO_XFERS_CURRENT*.
+
+# %PROTOCOLS%
+
+# EXAMPLE
+
+~~~c
+int main(void)
+{
+ /* init a multi stack */
+ CURLM *multi = curl_multi_init();
+ CURL *curl = curl_easy_init();
+ curl_off_t n;
+
+ if(curl) {
+ /* add the transfer */
+ curl_multi_add_handle(multi, curl);
+
+ curl_multi_get_offt(multi, CURLMINFO_XFERS_ADDED, &n);
+ /* on successful add, n is 1 */
+ }
+}
+~~~
+
+# %AVAILABILITY%
+
+# RETURN VALUE
+
+This function returns a CURLMcode indicating success or error.
+
+CURLM_OK (0) means everything was OK, non-zero means an error occurred,
+see libcurl-errors(3).
CURLM_UNKNOWN_OPTION 7.15.4
CURLM_UNRECOVERABLE_POLL 7.84.0
CURLM_WAKEUP_FAILURE 7.68.0
+CURLMINFO_NONE 8.16.0
+CURLMINFO_XFERS_CURRENT 8.16.0
+CURLMINFO_XFERS_RUNNING 8.16.0
+CURLMINFO_XFERS_PENDING 8.16.0
+CURLMINFO_XFERS_DONE 8.16.0
+CURLMINFO_XFERS_ADDED 8.16.0
CURLMIMEOPT_FORMESCAPE 7.81.0
CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE 7.30.0
CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE 7.30.0
*/
CURL_EXTERN CURL **curl_multi_get_handles(CURLM *multi_handle);
+
+typedef enum {
+ CURLMINFO_NONE, /* first, never use this */
+ /* The number of easy handles currently managed by the multi handle,
+ * e.g. have been added but not yet removed. */
+ CURLMINFO_XFERS_CURRENT = 1,
+ /* The number of easy handles running, e.g. not done and not queueing. */
+ CURLMINFO_XFERS_RUNNING = 2,
+ /* The number of easy handles waiting to start, e.g. for a connection
+ * to become available due to limits on parallelism, max connections
+ * or other factors. */
+ CURLMINFO_XFERS_PENDING = 3,
+ /* The number of easy handles finished, waiting for their results to
+ * be read via `curl_multi_info_read()`. */
+ CURLMINFO_XFERS_DONE = 4,
+ /* The total number of easy handles added to the multi handle, ever. */
+ CURLMINFO_XFERS_ADDED = 5
+} CURLMinfo_offt;
+
+/*
+ * Name: curl_multi_get_offt()
+ *
+ * Desc: Retrieves a numeric value for the `CURLMINFO_*` enums.
+ *
+ * Returns: CULRM_OK or error when value could not be obtained.
+ */
+CURL_EXTERN CURLMcode curl_multi_get_offt(CURLM *multi_handle,
+ CURLMinfo_offt info,
+ curl_off_t *pvalue);
+
/*
* Name: curl_push_callback
*
curl_multi_cleanup
curl_multi_fdset
curl_multi_get_handles
+curl_multi_get_offt
curl_multi_info_read
curl_multi_init
curl_multi_perform
/* add the easy handle to the process set */
Curl_uint_bset_add(&multi->process, data->mid);
++multi->xfers_alive;
+ ++multi->xfers_total_ever;
Curl_cpool_xfer_init(data);
multi_warn_debug(multi, data);
return a;
}
+CURLMcode curl_multi_get_offt(CURLM *m,
+ CURLMinfo_offt info,
+ curl_off_t *pvalue)
+{
+ struct Curl_multi *multi = m;
+
+ if(!GOOD_MULTI_HANDLE(multi))
+ return CURLM_BAD_HANDLE;
+ if(!pvalue)
+ return CURLM_BAD_FUNCTION_ARGUMENT;
+
+ switch(info) {
+ case CURLMINFO_XFERS_CURRENT: {
+ unsigned int n = Curl_uint_tbl_count(&multi->xfers);
+ if(n && multi->admin)
+ --n;
+ *pvalue = (curl_off_t)n;
+ return CURLM_OK;
+ }
+ case CURLMINFO_XFERS_RUNNING:
+ *pvalue = (curl_off_t)Curl_uint_bset_count(&multi->process);
+ return CURLM_OK;
+ case CURLMINFO_XFERS_PENDING:
+ *pvalue = (curl_off_t)Curl_uint_bset_count(&multi->pending);
+ return CURLM_OK;
+ case CURLMINFO_XFERS_DONE:
+ *pvalue = (curl_off_t)Curl_uint_bset_count(&multi->msgsent);
+ return CURLM_OK;
+ case CURLMINFO_XFERS_ADDED:
+ *pvalue = multi->xfers_total_ever;
+ return CURLM_OK;
+ default:
+ *pvalue = -1;
+ return CURLM_UNKNOWN_OPTION;
+ }
+}
+
CURLcode Curl_multi_xfer_buf_borrow(struct Curl_easy *data,
char **pbuf, size_t *pbuflen)
{
unsigned int xfers_alive; /* amount of added transfers that have
not yet reached COMPLETE state */
+ curl_off_t xfers_total_ever; /* total of added transfers, ever. */
struct uint_tbl xfers; /* transfers added to this multi */
/* Each transfer's mid may be present in at most one of these */
struct uint_bset process; /* transfer being processed */
{
return bset->nslots * 64;
}
+#endif
-UNITTEST unsigned int Curl_uint_bset_count(struct uint_bset *bset)
+unsigned int Curl_uint_bset_count(struct uint_bset *bset)
{
unsigned int i;
unsigned int n = 0;
}
return n;
}
-#endif
bool Curl_uint_bset_empty(struct uint_bset *bset)
{
'curl_multi_cleanup' => 'API',
'curl_multi_fdset' => 'API',
'curl_multi_get_handles' => 'API',
+ 'curl_multi_get_offt' => 'API',
'curl_multi_info_read' => 'API',
'curl_multi_init' => 'API',
'curl_multi_perform' => 'API',
struct per_transfer *transfers; /* first node */
static struct per_transfer *transfersl; /* last node */
-static curl_off_t all_pers;
/* add_per_transfer creates a new 'per_transfer' node in the linked
list of transfers */
transfersl = p;
}
*per = p;
- all_xfers++; /* count total number of transfers added */
- all_pers++;
return CURLE_OK;
}
transfersl = p;
free(per);
- all_pers--;
return n;
}
CURLMcode mcode;
bool sleeping = FALSE;
char *errorbuf;
+ curl_off_t nxfers;
+
*addedp = FALSE;
*morep = FALSE;
- if(all_pers < (global->parallel_max*2)) {
+ mcode = curl_multi_get_offt(multi, CURLMINFO_XFERS_CURRENT, &nxfers);
+ if(mcode) {
+ DEBUGASSERT(0);
+ return CURLE_UNKNOWN_OPTION;
+ }
+
+ if(nxfers < (curl_off_t)(global->parallel_max*2)) {
bool skipped = FALSE;
do {
result = create_transfer(global, share, addedp, &skipped);
CURLMsg *msg;
bool checkmore = FALSE;
struct GlobalConfig *global = s->global;
- progress_meter(global, &s->start, FALSE);
+ progress_meter(global, s->multi, &s->start, FALSE);
do {
msg = curl_multi_info_read(s->multi, &rc);
if(msg) {
result = check_finished(s);
}
- (void)progress_meter(global, &s->start, TRUE);
+ (void)progress_meter(global, s->multi, &s->start, TRUE);
}
/* Make sure to return some kind of error if there was a multi problem */
static curl_off_t all_dlalready = 0;
static curl_off_t all_ulalready = 0;
-curl_off_t all_xfers = 0; /* current total */
-
struct speedcount {
curl_off_t dl;
curl_off_t ul;
| 6 -- 9.9G 0 2 2 0:00:40 0:00:02 0:00:37 4087M
*/
bool progress_meter(struct GlobalConfig *global,
+ CURLM *multi,
struct curltime *start,
bool final)
{
struct per_transfer *per;
curl_off_t all_dlnow = 0;
curl_off_t all_ulnow = 0;
+ curl_off_t xfers_added = 0;
+ curl_off_t xfers_running = 0;
bool dlknown = TRUE;
bool ulknown = TRUE;
- curl_off_t all_running = 0; /* in progress */
curl_off_t speed = 0;
unsigned int i;
stamp = now;
all_ultotal += per->ultotal;
per->ultotal_added = TRUE;
}
- if(per->added)
- all_running++;
}
if(dlknown && all_dltotal)
msnprintf(dlpercen, sizeof(dlpercen), "%3" CURL_FORMAT_CURL_OFF_T,
}
time2str(time_spent, spent);
+ (void)curl_multi_get_offt(multi, CURLMINFO_XFERS_ADDED, &xfers_added);
+ (void)curl_multi_get_offt(multi, CURLMINFO_XFERS_RUNNING, &xfers_running);
fprintf(tool_stderr,
"\r"
"%-3s " /* percent downloaded */
ulpercen, /* 3 letters */
max5data(all_dlnow, buffer[0]),
max5data(all_ulnow, buffer[1]),
- all_xfers,
- all_running,
+ xfers_added,
+ xfers_running,
time_total,
time_spent,
time_left,
curl_off_t ulnow);
bool progress_meter(struct GlobalConfig *global,
+ CURLM *multi,
struct curltime *start,
bool final);
void progress_finalize(struct per_transfer *per);
-extern curl_off_t all_xfers; /* total number */
-
#endif /* HEADER_CURL_TOOL_PROGRESS_H */
curl_multi_setopt
curl_multi_assign
curl_multi_get_handles
+curl_multi_get_offt
curl_pushheader_bynum
curl_pushheader_byname
curl_multi_waitfds