llist: remove direct struct accesses, use only functions

- Turned them all into functions to also do asserts etc.

- The llist related structs got all their fields renamed in order to make
  sure no existing code remains using direct access.

- Each list node struct now points back to the list it "lives in", so
  Curl_node_remove() no longer needs the list pointer.

- Rename the node struct and some of the access functions.

- Added lots of ASSERTs to verify API being used correctly

- Fix some cases of API misuse

Add docs/LLIST.md documenting the internal linked list API.

Closes #14485
This commit is contained in:
Daniel Stenberg 2024-08-10 23:27:25 +02:00
parent 6f00a05e89
commit ba235ab269
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
27 changed files with 725 additions and 428 deletions

View file

@ -337,13 +337,13 @@ CURLcode Curl_altsvc_ctrl(struct altsvcinfo *asi, const long ctrl)
*/
void Curl_altsvc_cleanup(struct altsvcinfo **altsvcp)
{
struct Curl_llist_element *e;
struct Curl_llist_element *n;
if(*altsvcp) {
struct Curl_llist_node *e;
struct Curl_llist_node *n;
struct altsvcinfo *altsvc = *altsvcp;
for(e = altsvc->list.head; e; e = n) {
struct altsvc *as = e->ptr;
n = e->next;
for(e = Curl_llist_head(&altsvc->list); e; e = n) {
struct altsvc *as = Curl_node_elem(e);
n = Curl_node_next(e);
altsvc_free(as);
}
free(altsvc->filename);
@ -358,8 +358,6 @@ void Curl_altsvc_cleanup(struct altsvcinfo **altsvcp)
CURLcode Curl_altsvc_save(struct Curl_easy *data,
struct altsvcinfo *altsvc, const char *file)
{
struct Curl_llist_element *e;
struct Curl_llist_element *n;
CURLcode result = CURLE_OK;
FILE *out;
char *tempstore = NULL;
@ -378,12 +376,14 @@ CURLcode Curl_altsvc_save(struct Curl_easy *data,
result = Curl_fopen(data, file, &out, &tempstore);
if(!result) {
struct Curl_llist_node *e;
struct Curl_llist_node *n;
fputs("# Your alt-svc cache. https://curl.se/docs/alt-svc.html\n"
"# This file was generated by libcurl! Edit at your own risk.\n",
out);
for(e = altsvc->list.head; e; e = n) {
struct altsvc *as = e->ptr;
n = e->next;
for(e = Curl_llist_head(&altsvc->list); e; e = n) {
struct altsvc *as = Curl_node_elem(e);
n = Curl_node_next(e);
result = altsvc_out(as, out);
if(result)
break;
@ -440,15 +440,15 @@ static bool hostcompare(const char *host, const char *check)
static void altsvc_flush(struct altsvcinfo *asi, enum alpnid srcalpnid,
const char *srchost, unsigned short srcport)
{
struct Curl_llist_element *e;
struct Curl_llist_element *n;
for(e = asi->list.head; e; e = n) {
struct altsvc *as = e->ptr;
n = e->next;
struct Curl_llist_node *e;
struct Curl_llist_node *n;
for(e = Curl_llist_head(&asi->list); e; e = n) {
struct altsvc *as = Curl_node_elem(e);
n = Curl_node_next(e);
if((srcalpnid == as->src.alpnid) &&
(srcport == as->src.port) &&
hostcompare(srchost, as->src.host)) {
Curl_llist_remove(&asi->list, e, NULL);
Curl_node_remove(e);
altsvc_free(as);
}
}
@ -677,19 +677,19 @@ bool Curl_altsvc_lookup(struct altsvcinfo *asi,
struct altsvc **dstentry,
const int versions) /* one or more bits */
{
struct Curl_llist_element *e;
struct Curl_llist_element *n;
struct Curl_llist_node *e;
struct Curl_llist_node *n;
time_t now = time(NULL);
DEBUGASSERT(asi);
DEBUGASSERT(srchost);
DEBUGASSERT(dstentry);
for(e = asi->list.head; e; e = n) {
struct altsvc *as = e->ptr;
n = e->next;
for(e = Curl_llist_head(&asi->list); e; e = n) {
struct altsvc *as = Curl_node_elem(e);
n = Curl_node_next(e);
if(as->expires < now) {
/* an expired entry, remove */
Curl_llist_remove(&asi->list, e, NULL);
Curl_node_remove(e);
altsvc_free(as);
continue;
}

View file

@ -48,7 +48,7 @@ struct altsvc {
time_t expires;
bool persist;
unsigned int prio;
struct Curl_llist_element node;
struct Curl_llist_node node;
};
struct altsvcinfo {

View file

@ -99,17 +99,15 @@ static void bundle_add_conn(struct connectbundle *bundle,
static int bundle_remove_conn(struct connectbundle *bundle,
struct connectdata *conn)
{
struct Curl_llist_element *curr;
curr = bundle->conn_list.head;
struct Curl_llist_node *curr = Curl_llist_head(&bundle->conn_list);
while(curr) {
if(curr->ptr == conn) {
Curl_llist_remove(&bundle->conn_list, curr, NULL);
if(Curl_node_elem(curr) == conn) {
Curl_node_remove(curr);
bundle->num_connections--;
conn->bundle = NULL;
return 1; /* we removed a handle */
}
curr = curr->next;
curr = Curl_node_next(curr);
}
DEBUGASSERT(0);
return 0;
@ -149,7 +147,6 @@ void Curl_conncache_destroy(struct conncache *connc)
if(connc) {
Curl_hash_destroy(&connc->hash);
connc->multi = NULL;
DEBUGASSERT(!Curl_llist_count(&connc->shutdowns.conn_list));
}
}
@ -341,7 +338,6 @@ bool Curl_conncache_foreach(struct Curl_easy *data,
struct connectdata *conn, void *param))
{
struct Curl_hash_iterator iter;
struct Curl_llist_element *curr;
struct Curl_hash_element *he;
if(!connc)
@ -352,17 +348,16 @@ bool Curl_conncache_foreach(struct Curl_easy *data,
he = Curl_hash_next_element(&iter);
while(he) {
struct connectbundle *bundle;
bundle = he->ptr;
struct Curl_llist_node *curr;
struct connectbundle *bundle = he->ptr;
he = Curl_hash_next_element(&iter);
curr = bundle->conn_list.head;
curr = Curl_llist_head(&bundle->conn_list);
while(curr) {
/* Yes, we need to update curr before calling func(), because func()
might decide to remove the connection */
struct connectdata *conn = curr->ptr;
curr = curr->next;
struct connectdata *conn = Curl_node_elem(curr);
curr = Curl_node_next(curr);
if(1 == func(data, conn, param)) {
CONNCACHE_UNLOCK(data);
@ -391,12 +386,12 @@ connc_find_first_connection(struct conncache *connc)
he = Curl_hash_next_element(&iter);
while(he) {
struct Curl_llist_element *curr;
struct Curl_llist_node *curr;
bundle = he->ptr;
curr = bundle->conn_list.head;
curr = Curl_llist_head(&bundle->conn_list);
if(curr) {
return curr->ptr;
return Curl_node_elem(curr);
}
he = Curl_hash_next_element(&iter);
@ -451,7 +446,7 @@ struct connectdata *
Curl_conncache_extract_bundle(struct Curl_easy *data,
struct connectbundle *bundle)
{
struct Curl_llist_element *curr;
struct Curl_llist_node *curr;
timediff_t highscore = -1;
timediff_t score;
struct curltime now;
@ -462,9 +457,9 @@ Curl_conncache_extract_bundle(struct Curl_easy *data,
now = Curl_now();
curr = bundle->conn_list.head;
curr = Curl_llist_head(&bundle->conn_list);
while(curr) {
conn = curr->ptr;
conn = Curl_node_elem(curr);
if(!CONN_INUSE(conn)) {
/* Set higher score for the age passed since the connection was used */
@ -475,7 +470,7 @@ Curl_conncache_extract_bundle(struct Curl_easy *data,
conn_candidate = conn;
}
}
curr = curr->next;
curr = Curl_node_next(curr);
}
if(conn_candidate) {
/* remove it to prevent another thread from nicking it */
@ -499,7 +494,7 @@ Curl_conncache_extract_oldest(struct Curl_easy *data)
{
struct conncache *connc = data->state.conn_cache;
struct Curl_hash_iterator iter;
struct Curl_llist_element *curr;
struct Curl_llist_node *curr;
struct Curl_hash_element *he;
timediff_t highscore =- 1;
timediff_t score;
@ -519,9 +514,9 @@ Curl_conncache_extract_oldest(struct Curl_easy *data)
bundle = he->ptr;
curr = bundle->conn_list.head;
curr = Curl_llist_head(&bundle->conn_list);
while(curr) {
conn = curr->ptr;
conn = Curl_node_elem(curr);
if(!CONN_INUSE(conn) && !conn->bits.close &&
!conn->connect_only) {
@ -534,7 +529,7 @@ Curl_conncache_extract_oldest(struct Curl_easy *data)
bundle_candidate = bundle;
}
}
curr = curr->next;
curr = Curl_node_next(curr);
}
he = Curl_hash_next_element(&iter);
@ -553,7 +548,7 @@ Curl_conncache_extract_oldest(struct Curl_easy *data)
static void connc_shutdown_discard_all(struct conncache *connc)
{
struct Curl_llist_element *e = connc->shutdowns.conn_list.head;
struct Curl_llist_node *e = Curl_llist_head(&connc->shutdowns.conn_list);
struct connectdata *conn;
if(!e)
@ -563,12 +558,12 @@ static void connc_shutdown_discard_all(struct conncache *connc)
DEBUGASSERT(!connc->shutdowns.iter_locked);
connc->shutdowns.iter_locked = TRUE;
while(e) {
conn = e->ptr;
Curl_llist_remove(&connc->shutdowns.conn_list, e, NULL);
conn = Curl_node_elem(e);
Curl_node_remove(e);
DEBUGF(infof(connc->closure_handle, "discard connection #%"
CURL_FORMAT_CURL_OFF_T, conn->connection_id));
connc_disconnect(NULL, conn, connc, FALSE);
e = connc->shutdowns.conn_list.head;
e = Curl_llist_head(&connc->shutdowns.conn_list);
}
connc->shutdowns.iter_locked = FALSE;
}
@ -626,18 +621,18 @@ void Curl_conncache_close_all_connections(struct conncache *connc)
static void connc_shutdown_discard_oldest(struct conncache *connc)
{
struct Curl_llist_element *e;
struct Curl_llist_node *e;
struct connectdata *conn;
DEBUGASSERT(!connc->shutdowns.iter_locked);
if(connc->shutdowns.iter_locked)
return;
e = connc->shutdowns.conn_list.head;
e = Curl_llist_head(&connc->shutdowns.conn_list);
if(e) {
SIGPIPE_VARIABLE(pipe_st);
conn = e->ptr;
Curl_llist_remove(&connc->shutdowns.conn_list, e, NULL);
conn = Curl_node_elem(e);
Curl_node_remove(e);
sigpipe_init(&pipe_st);
sigpipe_apply(connc->closure_handle, &pipe_st);
connc_disconnect(NULL, conn, connc, FALSE);
@ -840,13 +835,14 @@ CURLcode Curl_conncache_add_pollfds(struct conncache *connc,
DEBUGASSERT(!connc->shutdowns.iter_locked);
connc->shutdowns.iter_locked = TRUE;
if(connc->shutdowns.conn_list.head) {
struct Curl_llist_element *e;
if(Curl_llist_head(&connc->shutdowns.conn_list)) {
struct Curl_llist_node *e;
struct easy_pollset ps;
struct connectdata *conn;
for(e = connc->shutdowns.conn_list.head; e; e = e->next) {
conn = e->ptr;
for(e = Curl_llist_head(&connc->shutdowns.conn_list); e;
e = Curl_node_next(e)) {
conn = Curl_node_elem(e);
memset(&ps, 0, sizeof(ps));
Curl_attach_connection(connc->closure_handle, conn);
Curl_conn_adjust_pollset(connc->closure_handle, &ps);
@ -871,13 +867,14 @@ CURLcode Curl_conncache_add_waitfds(struct conncache *connc,
DEBUGASSERT(!connc->shutdowns.iter_locked);
connc->shutdowns.iter_locked = TRUE;
if(connc->shutdowns.conn_list.head) {
struct Curl_llist_element *e;
if(Curl_llist_head(&connc->shutdowns.conn_list)) {
struct Curl_llist_node *e;
struct easy_pollset ps;
struct connectdata *conn;
for(e = connc->shutdowns.conn_list.head; e; e = e->next) {
conn = e->ptr;
for(e = Curl_llist_head(&connc->shutdowns.conn_list); e;
e = Curl_node_next(e)) {
conn = Curl_node_elem(e);
memset(&ps, 0, sizeof(ps));
Curl_attach_connection(connc->closure_handle, conn);
Curl_conn_adjust_pollset(connc->closure_handle, &ps);
@ -896,8 +893,8 @@ out:
static void connc_perform(struct conncache *connc)
{
struct Curl_easy *data = connc->closure_handle;
struct Curl_llist_element *e = connc->shutdowns.conn_list.head;
struct Curl_llist_element *enext;
struct Curl_llist_node *e = Curl_llist_head(&connc->shutdowns.conn_list);
struct Curl_llist_node *enext;
struct connectdata *conn;
struct curltime *nowp = NULL;
struct curltime now;
@ -913,15 +910,15 @@ static void connc_perform(struct conncache *connc)
Curl_llist_count(&connc->shutdowns.conn_list)));
connc->shutdowns.iter_locked = TRUE;
while(e) {
enext = e->next;
conn = e->ptr;
enext = Curl_node_next(e);
conn = Curl_node_elem(e);
Curl_attach_connection(data, conn);
connc_run_conn_shutdown(data, conn, &done);
DEBUGF(infof(data, "[CCACHE] shutdown #%" CURL_FORMAT_CURL_OFF_T
", done=%d", conn->connection_id, done));
Curl_detach_connection(data);
if(done) {
Curl_llist_remove(&connc->shutdowns.conn_list, e, NULL);
Curl_node_remove(e);
connc_disconnect(NULL, conn, connc, FALSE);
}
else {
@ -1039,7 +1036,7 @@ void Curl_conncache_multi_socket(struct Curl_multi *multi,
{
struct conncache *connc = &multi->conn_cache;
struct Curl_easy *data = connc->closure_handle;
struct Curl_llist_element *e = connc->shutdowns.conn_list.head;
struct Curl_llist_node *e = Curl_llist_head(&connc->shutdowns.conn_list);
struct connectdata *conn;
bool done;
@ -1050,7 +1047,7 @@ void Curl_conncache_multi_socket(struct Curl_multi *multi,
connc->shutdowns.iter_locked = TRUE;
while(e) {
conn = e->ptr;
conn = Curl_node_elem(e);
if(s == conn->sock[FIRSTSOCKET] || s == conn->sock[SECONDARYSOCKET]) {
Curl_attach_connection(data, conn);
connc_run_conn_shutdown(data, conn, &done);
@ -1058,12 +1055,12 @@ void Curl_conncache_multi_socket(struct Curl_multi *multi,
", done=%d", conn->connection_id, done));
Curl_detach_connection(data);
if(done || connc_update_shutdown_ev(multi, data, conn)) {
Curl_llist_remove(&connc->shutdowns.conn_list, e, NULL);
Curl_node_remove(e);
connc_disconnect(NULL, conn, connc, FALSE);
}
break;
}
e = e->next;
e = Curl_node_next(e);
}
connc->shutdowns.iter_locked = FALSE;
}
@ -1119,13 +1116,13 @@ static void connc_shutdown_all(struct conncache *connc, int timeout_ms)
}
DEBUGASSERT(!connc->shutdowns.iter_locked);
while(connc->shutdowns.conn_list.head) {
while(Curl_llist_head(&connc->shutdowns.conn_list)) {
timediff_t timespent;
int remain_ms;
connc_perform(connc);
if(!connc->shutdowns.conn_list.head) {
if(!Curl_llist_head(&connc->shutdowns.conn_list)) {
DEBUGF(infof(data, "conncache shutdown ok"));
break;
}
@ -1154,7 +1151,7 @@ static void connc_shutdown_all(struct conncache *connc, int timeout_ms)
void Curl_conncache_print(struct conncache *connc)
{
struct Curl_hash_iterator iter;
struct Curl_llist_element *curr;
struct Curl_llist_node *curr;
struct Curl_hash_element *he;
if(!connc)
@ -1172,12 +1169,12 @@ void Curl_conncache_print(struct conncache *connc)
bundle = he->ptr;
fprintf(stderr, "%s -", he->key);
curr = bundle->conn_list->head;
curr = Curl_llist_head(bundle->conn_list);
while(curr) {
conn = curr->ptr;
conn = Curl_node_elem(curr);
fprintf(stderr, " [%p %d]", (void *)conn, conn->refcount);
curr = curr->next;
curr = Curl_node_next(curr);
}
fprintf(stderr, "\n");

View file

@ -597,10 +597,10 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev)
}
else {
/* here pollrc is > 0 */
struct Curl_llist_element *e = multi->process.head;
struct Curl_llist_node *e = Curl_llist_head(&multi->process);
struct Curl_easy *data;
DEBUGASSERT(e);
data = e->ptr;
data = Curl_node_elem(e);
DEBUGASSERT(data);
/* loop over the monitored sockets to see which ones had activity */
@ -1018,7 +1018,9 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data)
goto fail;
}
#endif /* USE_ARES */
#ifndef CURL_DISABLE_HTTP
Curl_llist_init(&outcurl->state.httphdrs, NULL);
#endif
Curl_initinfo(outcurl);
outcurl->magic = CURLEASY_MAGIC_NUMBER;

View file

@ -30,7 +30,7 @@
struct fileinfo {
struct curl_fileinfo info;
struct Curl_llist_element list;
struct Curl_llist_node list;
struct dynbuf buf;
};

View file

@ -4037,7 +4037,7 @@ static CURLcode wc_statemach(struct Curl_easy *data)
wildcard->state = CURLWC_CLEAN;
continue;
}
if(wildcard->filelist.size == 0) {
if(Curl_llist_count(&wildcard->filelist) == 0) {
/* no corresponding file */
wildcard->state = CURLWC_CLEAN;
return CURLE_REMOTE_FILE_NOT_FOUND;
@ -4048,7 +4048,8 @@ static CURLcode wc_statemach(struct Curl_easy *data)
case CURLWC_DOWNLOADING: {
/* filelist has at least one file, lets get first one */
struct ftp_conn *ftpc = &conn->proto.ftpc;
struct curl_fileinfo *finfo = wildcard->filelist.head->ptr;
struct Curl_llist_node *head = Curl_llist_head(&wildcard->filelist);
struct curl_fileinfo *finfo = Curl_node_elem(head);
struct FTP *ftp = data->req.p.ftp;
char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename);
@ -4064,7 +4065,8 @@ static CURLcode wc_statemach(struct Curl_easy *data)
long userresponse;
Curl_set_in_callback(data, true);
userresponse = data->set.chunk_bgn(
finfo, data->set.wildcardptr, (int)wildcard->filelist.size);
finfo, data->set.wildcardptr,
(int)Curl_llist_count(&wildcard->filelist));
Curl_set_in_callback(data, false);
switch(userresponse) {
case CURL_CHUNK_BGN_FUNC_SKIP:
@ -4090,9 +4092,10 @@ static CURLcode wc_statemach(struct Curl_easy *data)
return result;
/* we do not need the Curl_fileinfo of first file anymore */
Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
Curl_node_remove(Curl_llist_head(&wildcard->filelist));
if(wildcard->filelist.size == 0) { /* remains only one file to down. */
if(Curl_llist_count(&wildcard->filelist) == 0) {
/* remains only one file to down. */
wildcard->state = CURLWC_CLEAN;
/* after that will be ftp_do called once again and no transfer
will be done because of CURLWC_CLEAN state */
@ -4107,8 +4110,8 @@ static CURLcode wc_statemach(struct Curl_easy *data)
data->set.chunk_end(data->set.wildcardptr);
Curl_set_in_callback(data, false);
}
Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
wildcard->state = (wildcard->filelist.size == 0) ?
Curl_node_remove(Curl_llist_head(&wildcard->filelist));
wildcard->state = (Curl_llist_count(&wildcard->filelist) == 0) ?
CURLWC_CLEAN : CURLWC_DOWNLOADING;
continue;
}

View file

@ -102,7 +102,7 @@ void *Curl_hash_add2(struct Curl_hash *h, void *key, size_t key_len, void *p,
Curl_hash_elem_dtor dtor)
{
struct Curl_hash_element *he;
struct Curl_llist_element *le;
struct Curl_llist_node *le;
struct Curl_llist *l;
DEBUGASSERT(h);
@ -118,10 +118,10 @@ void *Curl_hash_add2(struct Curl_hash *h, void *key, size_t key_len, void *p,
l = FETCH_LIST(h, key, key_len);
for(le = l->head; le; le = le->next) {
he = (struct Curl_hash_element *) le->ptr;
for(le = Curl_llist_head(l); le; le = Curl_node_next(le)) {
he = (struct Curl_hash_element *) Curl_node_elem(le);
if(h->comp_func(he->key, he->key_len, key, key_len)) {
Curl_llist_remove(l, le, (void *)h);
Curl_node_uremove(le, (void *)h);
--h->size;
break;
}
@ -158,18 +158,16 @@ Curl_hash_add(struct Curl_hash *h, void *key, size_t key_len, void *p)
*/
int Curl_hash_delete(struct Curl_hash *h, void *key, size_t key_len)
{
struct Curl_llist_element *le;
struct Curl_llist *l;
DEBUGASSERT(h);
DEBUGASSERT(h->slots);
if(h->table) {
l = FETCH_LIST(h, key, key_len);
struct Curl_llist_node *le;
struct Curl_llist *l = FETCH_LIST(h, key, key_len);
for(le = l->head; le; le = le->next) {
struct Curl_hash_element *he = le->ptr;
for(le = Curl_llist_head(l); le; le = Curl_node_next(le)) {
struct Curl_hash_element *he = Curl_node_elem(le);
if(h->comp_func(he->key, he->key_len, key, key_len)) {
Curl_llist_remove(l, le, (void *) h);
Curl_node_uremove(le, (void *) h);
--h->size;
return 0;
}
@ -185,15 +183,14 @@ int Curl_hash_delete(struct Curl_hash *h, void *key, size_t key_len)
void *
Curl_hash_pick(struct Curl_hash *h, void *key, size_t key_len)
{
struct Curl_llist_element *le;
struct Curl_llist *l;
DEBUGASSERT(h);
if(h->table) {
struct Curl_llist_node *le;
struct Curl_llist *l;
DEBUGASSERT(h->slots);
l = FETCH_LIST(h, key, key_len);
for(le = l->head; le; le = le->next) {
struct Curl_hash_element *he = le->ptr;
for(le = Curl_llist_head(l); le; le = Curl_node_next(le)) {
struct Curl_hash_element *he = Curl_node_elem(le);
if(h->comp_func(he->key, he->key_len, key, key_len)) {
return he->ptr;
}
@ -239,23 +236,21 @@ void
Curl_hash_clean_with_criterium(struct Curl_hash *h, void *user,
int (*comp)(void *, void *))
{
struct Curl_llist_element *le;
struct Curl_llist_element *lnext;
struct Curl_llist *list;
size_t i;
if(!h || !h->table)
return;
for(i = 0; i < h->slots; ++i) {
list = &h->table[i];
le = list->head; /* get first list entry */
struct Curl_llist *list = &h->table[i];
struct Curl_llist_node *le =
Curl_llist_head(list); /* get first list entry */
while(le) {
struct Curl_hash_element *he = le->ptr;
lnext = le->next;
struct Curl_hash_element *he = Curl_node_elem(le);
struct Curl_llist_node *lnext = Curl_node_next(le);
/* ask the callback function if we shall remove this entry or not */
if(!comp || comp(user, he->ptr)) {
Curl_llist_remove(list, le, (void *) h);
Curl_node_uremove(le, (void *) h);
--h->size; /* one less entry in the hash now */
}
le = lnext;
@ -305,14 +300,14 @@ Curl_hash_next_element(struct Curl_hash_iterator *iter)
/* Get the next element in the current list, if any */
if(iter->current_element)
iter->current_element = iter->current_element->next;
iter->current_element = Curl_node_next(iter->current_element);
/* If we have reached the end of the list, find the next one */
if(!iter->current_element) {
size_t i;
for(i = iter->slot_index; i < h->slots; i++) {
if(h->table[i].head) {
iter->current_element = h->table[i].head;
if(Curl_llist_head(&h->table[i])) {
iter->current_element = Curl_llist_head(&h->table[i]);
iter->slot_index = i + 1;
break;
}
@ -320,7 +315,7 @@ Curl_hash_next_element(struct Curl_hash_iterator *iter)
}
if(iter->current_element) {
struct Curl_hash_element *he = iter->current_element->ptr;
struct Curl_hash_element *he = Curl_node_elem(iter->current_element);
return he;
}
return NULL;

View file

@ -61,7 +61,7 @@ struct Curl_hash {
typedef void (*Curl_hash_elem_dtor)(void *key, size_t key_len, void *p);
struct Curl_hash_element {
struct Curl_llist_element list;
struct Curl_llist_node list;
void *ptr;
Curl_hash_elem_dtor dtor;
size_t key_len;
@ -71,7 +71,7 @@ struct Curl_hash_element {
struct Curl_hash_iterator {
struct Curl_hash *hash;
size_t slot_index;
struct Curl_llist_element *current_element;
struct Curl_llist_node *current_element;
};
void Curl_hash_init(struct Curl_hash *h,

View file

@ -42,7 +42,7 @@
static void copy_header_external(struct Curl_header_store *hs,
size_t index,
size_t amount,
struct Curl_llist_element *e,
struct Curl_llist_node *e,
struct curl_header *hout)
{
struct curl_header *h = hout;
@ -66,8 +66,8 @@ CURLHcode curl_easy_header(CURL *easy,
int request,
struct curl_header **hout)
{
struct Curl_llist_element *e;
struct Curl_llist_element *e_pick = NULL;
struct Curl_llist_node *e;
struct Curl_llist_node *e_pick = NULL;
struct Curl_easy *data = easy;
size_t match = 0;
size_t amount = 0;
@ -85,8 +85,8 @@ CURLHcode curl_easy_header(CURL *easy,
request = data->state.requests;
/* we need a first round to count amount of this header */
for(e = data->state.httphdrs.head; e; e = e->next) {
hs = e->ptr;
for(e = Curl_llist_head(&data->state.httphdrs); e; e = Curl_node_next(e)) {
hs = Curl_node_elem(e);
if(strcasecompare(hs->name, name) &&
(hs->type & type) &&
(hs->request == request)) {
@ -104,8 +104,8 @@ CURLHcode curl_easy_header(CURL *easy,
/* if the last or only occurrence is what's asked for, then we know it */
hs = pick;
else {
for(e = data->state.httphdrs.head; e; e = e->next) {
hs = e->ptr;
for(e = Curl_llist_head(&data->state.httphdrs); e; e = Curl_node_next(e)) {
hs = Curl_node_elem(e);
if(strcasecompare(hs->name, name) &&
(hs->type & type) &&
(hs->request == request) &&
@ -131,8 +131,8 @@ struct curl_header *curl_easy_nextheader(CURL *easy,
struct curl_header *prev)
{
struct Curl_easy *data = easy;
struct Curl_llist_element *pick;
struct Curl_llist_element *e;
struct Curl_llist_node *pick;
struct Curl_llist_node *e;
struct Curl_header_store *hs;
size_t amount = 0;
size_t index = 0;
@ -147,18 +147,18 @@ struct curl_header *curl_easy_nextheader(CURL *easy,
if(!pick)
/* something is wrong */
return NULL;
pick = pick->next;
pick = Curl_node_next(pick);
}
else
pick = data->state.httphdrs.head;
pick = Curl_llist_head(&data->state.httphdrs);
if(pick) {
/* make sure it is the next header of the desired type */
do {
hs = pick->ptr;
hs = Curl_node_elem(pick);
if((hs->type & type) && (hs->request == request))
break;
pick = pick->next;
pick = Curl_node_next(pick);
} while(pick);
}
@ -166,12 +166,12 @@ struct curl_header *curl_easy_nextheader(CURL *easy,
/* no more headers available */
return NULL;
hs = pick->ptr;
hs = Curl_node_elem(pick);
/* count number of occurrences of this name within the mask and figure out
the index for the currently selected entry */
for(e = data->state.httphdrs.head; e; e = e->next) {
struct Curl_header_store *check = e->ptr;
for(e = Curl_llist_head(&data->state.httphdrs); e; e = Curl_node_next(e)) {
struct Curl_header_store *check = Curl_node_elem(e);
if(strcasecompare(hs->name, check->name) &&
(check->request == request) &&
(check->type & type))
@ -247,7 +247,7 @@ static CURLcode unfold_value(struct Curl_easy *data, const char *value,
/* since this header block might move in the realloc below, it needs to
first be unlinked from the list and then re-added again after the
realloc */
Curl_llist_remove(&data->state.httphdrs, &hs->node, NULL);
Curl_node_remove(&hs->node);
/* new size = struct + new value length + old name+value length */
newhs = Curl_saferealloc(hs, sizeof(*hs) + vlen + oalloc + 1);
@ -405,12 +405,12 @@ CURLcode Curl_headers_init(struct Curl_easy *data)
*/
CURLcode Curl_headers_cleanup(struct Curl_easy *data)
{
struct Curl_llist_element *e;
struct Curl_llist_element *n;
struct Curl_llist_node *e;
struct Curl_llist_node *n;
for(e = data->state.httphdrs.head; e; e = n) {
struct Curl_header_store *hs = e->ptr;
n = e->next;
for(e = Curl_llist_head(&data->state.httphdrs); e; e = n) {
struct Curl_header_store *hs = Curl_node_elem(e);
n = Curl_node_next(e);
free(hs);
}
headers_reset(data);

View file

@ -28,7 +28,7 @@
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_HEADERS_API)
struct Curl_header_store {
struct Curl_llist_element node;
struct Curl_llist_node node;
char *name; /* points into 'buffer' */
char *value; /* points into 'buffer */
int request; /* 0 is the first request, then 1.. 2.. */

View file

@ -94,11 +94,11 @@ void Curl_hsts_cleanup(struct hsts **hp)
{
struct hsts *h = *hp;
if(h) {
struct Curl_llist_element *e;
struct Curl_llist_element *n;
for(e = h->list.head; e; e = n) {
struct stsentry *sts = e->ptr;
n = e->next;
struct Curl_llist_node *e;
struct Curl_llist_node *n;
for(e = Curl_llist_head(&h->list); e; e = n) {
struct stsentry *sts = Curl_node_elem(e);
n = Curl_node_next(e);
hsts_free(sts);
}
free(h->filename);
@ -215,7 +215,7 @@ CURLcode Curl_hsts_parse(struct hsts *h, const char *hostname,
/* remove the entry if present verbatim (without subdomain match) */
sts = Curl_hsts(h, hostname, FALSE);
if(sts) {
Curl_llist_remove(&h->list, &sts->node, NULL);
Curl_node_remove(&sts->node);
hsts_free(sts);
}
return CURLE_OK;
@ -253,8 +253,8 @@ struct stsentry *Curl_hsts(struct hsts *h, const char *hostname,
char buffer[MAX_HSTS_HOSTLEN + 1];
time_t now = time(NULL);
size_t hlen = strlen(hostname);
struct Curl_llist_element *e;
struct Curl_llist_element *n;
struct Curl_llist_node *e;
struct Curl_llist_node *n;
if((hlen > MAX_HSTS_HOSTLEN) || !hlen)
return NULL;
@ -265,12 +265,12 @@ struct stsentry *Curl_hsts(struct hsts *h, const char *hostname,
buffer[hlen] = 0;
hostname = buffer;
for(e = h->list.head; e; e = n) {
struct stsentry *sts = e->ptr;
n = e->next;
for(e = Curl_llist_head(&h->list); e; e = n) {
struct stsentry *sts = Curl_node_elem(e);
n = Curl_node_next(e);
if(sts->expires <= now) {
/* remove expired entries */
Curl_llist_remove(&h->list, &sts->node, NULL);
Curl_node_remove(&sts->node);
hsts_free(sts);
continue;
}
@ -353,8 +353,8 @@ static CURLcode hsts_out(struct stsentry *sts, FILE *fp)
CURLcode Curl_hsts_save(struct Curl_easy *data, struct hsts *h,
const char *file)
{
struct Curl_llist_element *e;
struct Curl_llist_element *n;
struct Curl_llist_node *e;
struct Curl_llist_node *n;
CURLcode result = CURLE_OK;
FILE *out;
char *tempstore = NULL;
@ -376,9 +376,9 @@ CURLcode Curl_hsts_save(struct Curl_easy *data, struct hsts *h,
fputs("# Your HSTS cache. https://curl.se/docs/hsts.html\n"
"# This file was generated by libcurl! Edit at your own risk.\n",
out);
for(e = h->list.head; e; e = n) {
struct stsentry *sts = e->ptr;
n = e->next;
for(e = Curl_llist_head(&h->list); e; e = n) {
struct stsentry *sts = Curl_node_elem(e);
n = Curl_node_next(e);
result = hsts_out(sts, out);
if(result)
break;
@ -395,12 +395,12 @@ skipsave:
if(data->set.hsts_write) {
/* if there is a write callback */
struct curl_index i; /* count */
i.total = h->list.size;
i.total = Curl_llist_count(&h->list);
i.index = 0;
for(e = h->list.head; e; e = n) {
struct stsentry *sts = e->ptr;
for(e = Curl_llist_head(&h->list); e; e = n) {
struct stsentry *sts = Curl_node_elem(e);
bool stop;
n = e->next;
n = Curl_node_next(e);
result = hsts_push(data, &i, sts, &stop);
if(result || stop)
break;

View file

@ -34,7 +34,7 @@ extern time_t deltatime;
#endif
struct stsentry {
struct Curl_llist_element node;
struct Curl_llist_node node;
const char *host;
bool includeSubDomains;
curl_off_t expires; /* the timestamp of this entry's expiry */

View file

@ -3118,7 +3118,7 @@ CURLcode Curl_http_header(struct Curl_easy *data,
#ifdef DEBUGBUILD
else
infof(data, "Parsed STS header fine (%zu entries)",
data->hsts->list.size);
Curl_llist_count(&data->hsts->list));
#endif
}
#endif

View file

@ -32,16 +32,34 @@
/* this must be the last include file */
#include "memdebug.h"
#define LLISTINIT 0x100cc001 /* random pattern */
#define NODEINIT 0x12344321 /* random pattern */
#define NODEREM 0x54321012 /* random pattern */
#ifdef DEBUGBUILD
#define VERIFYNODE(x) verifynode(x)
static struct Curl_llist_node *verifynode(struct Curl_llist_node *n)
{
DEBUGASSERT(!n || (n->_init == NODEINIT));
return n;
}
#else
#define VERIFYNODE(x) x
#endif
/*
* @unittest: 1300
*/
void
Curl_llist_init(struct Curl_llist *l, Curl_llist_dtor dtor)
{
l->size = 0;
l->dtor = dtor;
l->head = NULL;
l->tail = NULL;
l->_size = 0;
l->_dtor = dtor;
l->_head = NULL;
l->_tail = NULL;
#ifdef DEBUGBUILD
l->_init = LLISTINIT;
#endif
}
/*
@ -56,36 +74,45 @@ Curl_llist_init(struct Curl_llist *l, Curl_llist_dtor dtor)
* @unittest: 1300
*/
void
Curl_llist_insert_next(struct Curl_llist *list, struct Curl_llist_element *e,
Curl_llist_insert_next(struct Curl_llist *list,
struct Curl_llist_node *e, /* may be NULL */
const void *p,
struct Curl_llist_element *ne)
struct Curl_llist_node *ne)
{
ne->ptr = (void *) p;
if(list->size == 0) {
list->head = ne;
list->head->prev = NULL;
list->head->next = NULL;
list->tail = ne;
DEBUGASSERT(list);
DEBUGASSERT(list->_init == LLISTINIT);
DEBUGASSERT(ne);
#ifdef DEBUGBUILD
ne->_init = NODEINIT;
#endif
ne->_ptr = (void *) p;
ne->_list = list;
if(list->_size == 0) {
list->_head = ne;
list->_head->_prev = NULL;
list->_head->_next = NULL;
list->_tail = ne;
}
else {
/* if 'e' is NULL here, we insert the new element first in the list */
ne->next = e?e->next:list->head;
ne->prev = e;
ne->_next = e?e->_next:list->_head;
ne->_prev = e;
if(!e) {
list->head->prev = ne;
list->head = ne;
list->_head->_prev = ne;
list->_head = ne;
}
else if(e->next) {
e->next->prev = ne;
else if(e->_next) {
e->_next->_prev = ne;
}
else {
list->tail = ne;
list->_tail = ne;
}
if(e)
e->next = ne;
e->_next = ne;
}
++list->size;
++list->_size;
}
/*
@ -99,64 +126,131 @@ Curl_llist_insert_next(struct Curl_llist *list, struct Curl_llist_element *e,
*/
void
Curl_llist_append(struct Curl_llist *list, const void *p,
struct Curl_llist_element *ne)
struct Curl_llist_node *ne)
{
Curl_llist_insert_next(list, list->tail, p, ne);
DEBUGASSERT(list);
DEBUGASSERT(list->_init == LLISTINIT);
DEBUGASSERT(ne);
Curl_llist_insert_next(list, list->_tail, p, ne);
}
/*
* @unittest: 1300
*/
void
Curl_llist_remove(struct Curl_llist *list, struct Curl_llist_element *e,
void *user)
Curl_node_uremove(struct Curl_llist_node *e, void *user)
{
void *ptr;
if(!e || list->size == 0)
struct Curl_llist *list;
if(!e)
return;
if(e == list->head) {
list->head = e->next;
list = e->_list;
DEBUGASSERT(list);
DEBUGASSERT(list->_init == LLISTINIT);
DEBUGASSERT(list->_size);
DEBUGASSERT(e->_init == NODEINIT);
if(e == list->_head) {
list->_head = e->_next;
if(!list->head)
list->tail = NULL;
if(!list->_head)
list->_tail = NULL;
else
e->next->prev = NULL;
e->_next->_prev = NULL;
}
else {
if(e->prev)
e->prev->next = e->next;
if(e->_prev)
e->_prev->_next = e->_next;
if(!e->next)
list->tail = e->prev;
if(!e->_next)
list->_tail = e->_prev;
else
e->next->prev = e->prev;
e->_next->_prev = e->_prev;
}
ptr = e->ptr;
ptr = e->_ptr;
e->ptr = NULL;
e->prev = NULL;
e->next = NULL;
e->_ptr = NULL;
e->_prev = NULL;
e->_next = NULL;
#ifdef DEBUGBUILD
e->_init = NODEREM; /* specific pattern on remove - not zero */
#endif
--list->size;
--list->_size;
/* call the dtor() last for when it actually frees the 'e' memory itself */
if(list->dtor)
list->dtor(user, ptr);
if(list->_dtor)
list->_dtor(user, ptr);
}
void Curl_node_remove(struct Curl_llist_node *e)
{
Curl_node_uremove(e, NULL);
}
void
Curl_llist_destroy(struct Curl_llist *list, void *user)
{
if(list) {
while(list->size > 0)
Curl_llist_remove(list, list->tail, user);
DEBUGASSERT(list->_init == LLISTINIT);
while(list->_size > 0)
Curl_node_uremove(list->_tail, user);
}
}
size_t
Curl_llist_count(struct Curl_llist *list)
/* Curl_llist_head() returns the first 'struct Curl_llist_node *', which
might be NULL */
struct Curl_llist_node *Curl_llist_head(struct Curl_llist *list)
{
return list->size;
DEBUGASSERT(list);
DEBUGASSERT(list->_init == LLISTINIT);
return VERIFYNODE(list->_head);
}
/* Curl_llist_tail() returns the last 'struct Curl_llist_node *', which
might be NULL */
struct Curl_llist_node *Curl_llist_tail(struct Curl_llist *list)
{
DEBUGASSERT(list);
DEBUGASSERT(list->_init == LLISTINIT);
return VERIFYNODE(list->_tail);
}
/* Curl_llist_count() returns a size_t the number of nodes in the list */
size_t Curl_llist_count(struct Curl_llist *list)
{
DEBUGASSERT(list);
DEBUGASSERT(list->_init == LLISTINIT);
return list->_size;
}
/* Curl_node_elem() returns the custom data from a Curl_llist_node */
void *Curl_node_elem(struct Curl_llist_node *n)
{
DEBUGASSERT(n);
DEBUGASSERT(n->_init == NODEINIT);
return n->_ptr;
}
/* Curl_node_next() returns the next element in a list from a given
Curl_llist_node */
struct Curl_llist_node *Curl_node_next(struct Curl_llist_node *n)
{
DEBUGASSERT(n);
DEBUGASSERT(n->_init == NODEINIT);
return VERIFYNODE(n->_next);
}
#ifdef UNITTEST
/* Curl_node_prev() returns the previous element in a list from a given
Curl_llist_node */
struct Curl_llist_node *Curl_node_prev(struct Curl_llist_node *n)
{
DEBUGASSERT(n);
DEBUGASSERT(n->_init == NODEINIT);
return VERIFYNODE(n->_prev);
}
#endif

View file

@ -27,28 +27,60 @@
#include "curl_setup.h"
#include <stddef.h>
typedef void (*Curl_llist_dtor)(void *, void *);
typedef void (*Curl_llist_dtor)(void *user, void *elem);
struct Curl_llist_element {
void *ptr;
struct Curl_llist_element *prev;
struct Curl_llist_element *next;
};
/* none of these struct members should be referenced directly, use the
dedicated functions */
struct Curl_llist {
struct Curl_llist_element *head;
struct Curl_llist_element *tail;
Curl_llist_dtor dtor;
size_t size;
struct Curl_llist_node *_head;
struct Curl_llist_node *_tail;
Curl_llist_dtor _dtor;
size_t _size;
#ifdef DEBUGBUILD
int _init; /* detect API usage mistakes */
#endif
};
struct Curl_llist_node {
struct Curl_llist *_list; /* the list where this belongs */
void *_ptr;
struct Curl_llist_node *_prev;
struct Curl_llist_node *_next;
#ifdef DEBUGBUILD
int _init; /* detect API usage mistakes */
#endif
};
void Curl_llist_init(struct Curl_llist *, Curl_llist_dtor);
void Curl_llist_insert_next(struct Curl_llist *, struct Curl_llist_element *,
const void *, struct Curl_llist_element *node);
void Curl_llist_insert_next(struct Curl_llist *, struct Curl_llist_node *,
const void *, struct Curl_llist_node *node);
void Curl_llist_append(struct Curl_llist *,
const void *, struct Curl_llist_element *node);
void Curl_llist_remove(struct Curl_llist *, struct Curl_llist_element *,
void *);
size_t Curl_llist_count(struct Curl_llist *);
const void *, struct Curl_llist_node *node);
void Curl_node_uremove(struct Curl_llist_node *, void *);
void Curl_node_remove(struct Curl_llist_node *);
void Curl_llist_destroy(struct Curl_llist *, void *);
/* Curl_llist_head() returns the first 'struct Curl_llist_node *', which
might be NULL */
struct Curl_llist_node *Curl_llist_head(struct Curl_llist *list);
/* Curl_llist_tail() returns the last 'struct Curl_llist_node *', which
might be NULL */
struct Curl_llist_node *Curl_llist_tail(struct Curl_llist *list);
/* Curl_llist_count() returns a size_t the number of nodes in the list */
size_t Curl_llist_count(struct Curl_llist *list);
/* Curl_node_elem() returns the custom data from a Curl_llist_node */
void *Curl_node_elem(struct Curl_llist_node *n);
/* Curl_node_next() returns the next element in a list from a given
Curl_llist_node */
struct Curl_llist_node *Curl_node_next(struct Curl_llist_node *n);
/* Curl_node_prev() returns the previous element in a list from a given
Curl_llist_node */
struct Curl_llist_node *Curl_node_prev(struct Curl_llist_node *n);
#endif /* HEADER_CURL_LLIST_H */

View file

@ -467,21 +467,6 @@ static void multi_warn_debug(struct Curl_multi *multi, struct Curl_easy *data)
#define multi_warn_debug(x,y) Curl_nop_stmt
#endif
static void link_easy(struct Curl_multi *multi,
struct Curl_easy *data)
{
/* add the easy handle to the process list */
Curl_llist_append(&multi->process, data, &data->multi_queue);
}
/* unlink the given easy handle from the process list */
static void unlink_easy(struct Curl_multi *multi,
struct Curl_easy *data)
{
Curl_llist_remove(&multi->process, &data->multi_queue, NULL);
}
CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
struct Curl_easy *data)
{
@ -557,8 +542,10 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
memset(&multi->timer_lastcall, 0, sizeof(multi->timer_lastcall));
rc = Curl_update_timer(multi);
if(rc)
if(rc) {
data->multi = NULL; /* not anymore */
return rc;
}
/* set the easy handle */
multistate(data, MSTATE_INIT);
@ -586,7 +573,8 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
data->psl = &multi->psl;
#endif
link_easy(multi, data);
/* add the easy handle to the process list */
Curl_llist_append(&multi->process, data, &data->multi_queue);
/* increase the node-counter */
multi->num_easy++;
@ -706,7 +694,7 @@ static CURLcode multi_done(struct Curl_easy *data,
CONNCACHE_UNLOCK(data);
DEBUGF(infof(data, "Connection still in use %zu, "
"no more multi_done now!",
conn->easyq.size));
Curl_llist_count(&conn->easyq)));
return CURLE_OK;
}
@ -804,7 +792,7 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
{
struct Curl_easy *easy = data;
bool premature;
struct Curl_llist_element *e;
struct Curl_llist_node *e;
CURLMcode rc;
/* First, make some basic checks that the CURLM handle is a good handle */
@ -812,7 +800,7 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
return CURLM_BAD_HANDLE;
/* Verify that we got a somewhat good easy handle too */
if(!GOOD_EASY_HANDLE(data))
if(!GOOD_EASY_HANDLE(data) || !multi->num_easy)
return CURLM_BAD_EASY_HANDLE;
/* Prevent users from trying to remove same easy handle more than once */
@ -858,15 +846,8 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
called. Do it after multi_done() in case that sets another time! */
Curl_expire_clear(data);
if(data->multi_queue.ptr) {
/* the handle is in a list, remove it from the right one */
if(data->mstate == MSTATE_PENDING)
Curl_llist_remove(&multi->pending, &data->multi_queue, NULL);
else if(data->mstate == MSTATE_MSGSENT)
Curl_llist_remove(&multi->msgsent, &data->multi_queue, NULL);
else
Curl_llist_remove(&multi->process, &data->multi_queue, NULL);
}
/* the handle is in a list, remove it from whichever it is */
Curl_node_remove(&data->multi_queue);
if(data->dns.hostcachetype == HCACHE_MULTI) {
/* stop using the multi handle's DNS cache, *after* the possible
@ -927,11 +908,11 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
/* make sure there is no pending message in the queue sent from this easy
handle */
for(e = multi->msglist.head; e; e = e->next) {
struct Curl_message *msg = e->ptr;
for(e = Curl_llist_head(&multi->msglist); e; e = Curl_node_next(e)) {
struct Curl_message *msg = Curl_node_elem(e);
if(msg->extmsg.easy_handle == easy) {
Curl_llist_remove(&multi->msglist, e, NULL);
Curl_node_remove(e);
/* there can only be one from this specific handle */
break;
}
@ -966,7 +947,7 @@ void Curl_detach_connection(struct Curl_easy *data)
struct connectdata *conn = data->conn;
if(conn) {
Curl_conn_ev_data_detach(conn, data);
Curl_llist_remove(&conn->easyq, &data->conn_queue, NULL);
Curl_node_remove(&data->conn_queue);
}
data->conn = NULL;
}
@ -1181,7 +1162,7 @@ CURLMcode curl_multi_fdset(struct Curl_multi *multi,
and then we must make sure that is done. */
int this_max_fd = -1;
struct easy_pollset ps;
struct Curl_llist_element *e;
struct Curl_llist_node *e;
(void)exc_fd_set; /* not used */
if(!GOOD_MULTI_HANDLE(multi))
@ -1191,8 +1172,8 @@ CURLMcode curl_multi_fdset(struct Curl_multi *multi,
return CURLM_RECURSIVE_API_CALL;
memset(&ps, 0, sizeof(ps));
for(e = multi->process.head; e; e = e->next) {
struct Curl_easy *data = e->ptr;
for(e = Curl_llist_head(&multi->process); e; e = Curl_node_next(e)) {
struct Curl_easy *data = Curl_node_elem(e);
unsigned int i;
multi_getsock(data, &ps);
@ -1223,7 +1204,7 @@ CURLMcode curl_multi_waitfds(struct Curl_multi *multi,
struct curl_waitfds cwfds;
struct easy_pollset ps;
CURLMcode result = CURLM_OK;
struct Curl_llist_element *e;
struct Curl_llist_node *e;
if(!ufds)
return CURLM_BAD_FUNCTION_ARGUMENT;
@ -1236,8 +1217,8 @@ CURLMcode curl_multi_waitfds(struct Curl_multi *multi,
Curl_waitfds_init(&cwfds, ufds, size);
memset(&ps, 0, sizeof(ps));
for(e = multi->process.head; e; e = e->next) {
struct Curl_easy *data = e->ptr;
for(e = Curl_llist_head(&multi->process); e; e = Curl_node_next(e)) {
struct Curl_easy *data = Curl_node_elem(e);
multi_getsock(data, &ps);
if(Curl_waitfds_add_ps(&cwfds, &ps)) {
result = CURLM_OUT_OF_MEMORY;
@ -1290,7 +1271,7 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
struct curl_pollfds cpfds;
unsigned int curl_nfds = 0; /* how many pfds are for curl transfers */
CURLMcode result = CURLM_OK;
struct Curl_llist_element *e;
struct Curl_llist_node *e;
#ifdef USE_WINSOCK
WSANETWORKEVENTS wsa_events;
@ -1313,8 +1294,8 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
memset(&ps, 0, sizeof(ps));
/* Add the curl handles to our pollfds first */
for(e = multi->process.head; e; e = e->next) {
struct Curl_easy *data = e->ptr;
for(e = Curl_llist_head(&multi->process); e; e = Curl_node_next(e)) {
struct Curl_easy *data = Curl_node_elem(e);
multi_getsock(data, &ps);
if(Curl_pollfds_add_ps(&cpfds, &ps)) {
@ -1453,8 +1434,9 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
/* Count up all our own sockets that had activity,
and remove them from the event. */
if(curl_nfds) {
for(e = multi->process.head; e && !result; e = e->next) {
struct Curl_easy *data = e->ptr;
for(e = Curl_llist_head(&multi->process); e && !result;
e = Curl_node_next(e)) {
struct Curl_easy *data = Curl_node_elem(e);
multi_getsock(data, &ps);
for(i = 0; i < ps.num; i++) {
@ -1948,7 +1930,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
state and wait for an available connection. */
multistate(data, MSTATE_PENDING);
/* unlink from process list */
unlink_easy(multi, data);
Curl_node_remove(&data->multi_queue);
/* add handle to pending list */
Curl_llist_append(&multi->pending, data, &data->multi_queue);
result = CURLE_OK;
@ -2661,9 +2643,9 @@ statemachine_end:
}
multistate(data, MSTATE_MSGSENT);
/* unlink from the main list */
unlink_easy(multi, data);
/* add this handle to the list of msgsent handles */
/* unlink from the process list */
Curl_node_remove(&data->multi_queue);
/* add this handle msgsent list */
Curl_llist_append(&multi->msgsent, data, &data->multi_queue);
return CURLM_OK;
}
@ -2679,8 +2661,8 @@ CURLMcode curl_multi_perform(struct Curl_multi *multi, int *running_handles)
CURLMcode returncode = CURLM_OK;
struct Curl_tree *t;
struct curltime now = Curl_now();
struct Curl_llist_element *e;
struct Curl_llist_element *n = NULL;
struct Curl_llist_node *e;
struct Curl_llist_node *n = NULL;
SIGPIPE_VARIABLE(pipe_st);
if(!GOOD_MULTI_HANDLE(multi))
@ -2690,15 +2672,15 @@ CURLMcode curl_multi_perform(struct Curl_multi *multi, int *running_handles)
return CURLM_RECURSIVE_API_CALL;
sigpipe_init(&pipe_st);
for(e = multi->process.head; e; e = n) {
struct Curl_easy *data = e->ptr;
for(e = Curl_llist_head(&multi->process); e; e = n) {
struct Curl_easy *data = Curl_node_elem(e);
CURLMcode result;
/* Do the loop and only alter the signal ignore state if the next handle
has a different NO_SIGNAL state than the previous */
/* the current node might be unlinked in multi_runsingle(), get the next
pointer now */
n = e->next;
n = Curl_node_next(e);
if(data != multi->conn_cache.closure_handle) {
/* connection cache handle is processed below */
@ -2755,14 +2737,14 @@ CURLMcode curl_multi_perform(struct Curl_multi *multi, int *running_handles)
the process list */
static void unlink_all_msgsent_handles(struct Curl_multi *multi)
{
struct Curl_llist_element *e;
for(e = multi->msgsent.head; e; e = e->next) {
struct Curl_easy *data = e->ptr;
struct Curl_llist_node *e;
for(e = Curl_llist_head(&multi->msgsent); e; e = Curl_node_next(e)) {
struct Curl_easy *data = Curl_node_elem(e);
if(data) {
DEBUGASSERT(data->mstate == MSTATE_MSGSENT);
Curl_llist_remove(&multi->msgsent, &data->multi_queue, NULL);
Curl_node_remove(&data->multi_queue);
/* put it into the process list */
link_easy(multi, data);
Curl_llist_append(&multi->process, data, &data->multi_queue);
}
}
}
@ -2770,8 +2752,8 @@ static void unlink_all_msgsent_handles(struct Curl_multi *multi)
CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
{
if(GOOD_MULTI_HANDLE(multi)) {
struct Curl_llist_element *e;
struct Curl_llist_element *n;
struct Curl_llist_node *e;
struct Curl_llist_node *n;
if(multi->in_callback)
return CURLM_RECURSIVE_API_CALL;
@ -2783,13 +2765,13 @@ CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
process_pending_handles(multi);
/* First remove all remaining easy handles */
for(e = multi->process.head; e; e = n) {
struct Curl_easy *data = e->ptr;
for(e = Curl_llist_head(&multi->process); e; e = n) {
struct Curl_easy *data = Curl_node_elem(e);
if(!GOOD_EASY_HANDLE(data))
return CURLM_BAD_HANDLE;
n = e->next;
n = Curl_node_next(e);
if(!data->state.done && data->conn)
/* if DONE was never called for this handle */
(void)multi_done(data, CURLE_OK, TRUE);
@ -2858,15 +2840,15 @@ CURLMsg *curl_multi_info_read(struct Curl_multi *multi, int *msgs_in_queue)
!multi->in_callback &&
Curl_llist_count(&multi->msglist)) {
/* there is one or more messages in the list */
struct Curl_llist_element *e;
struct Curl_llist_node *e;
/* extract the head of the list to return */
e = multi->msglist.head;
e = Curl_llist_head(&multi->msglist);
msg = e->ptr;
msg = Curl_node_elem(e);
/* remove the extracted entry */
Curl_llist_remove(&multi->msglist, e, NULL);
Curl_node_remove(e);
*msgs_in_queue = curlx_uztosi(Curl_llist_count(&multi->msglist));
@ -3110,26 +3092,24 @@ static CURLMcode add_next_timeout(struct curltime now,
{
struct curltime *tv = &d->state.expiretime;
struct Curl_llist *list = &d->state.timeoutlist;
struct Curl_llist_element *e;
struct time_node *node = NULL;
struct Curl_llist_node *e;
/* move over the timeout list for this specific handle and remove all
timeouts that are now passed tense and store the next pending
timeout in *tv */
for(e = list->head; e;) {
struct Curl_llist_element *n = e->next;
timediff_t diff;
node = (struct time_node *)e->ptr;
diff = Curl_timediff_us(node->time, 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 = Curl_timediff_us(node->time, now);
if(diff <= 0)
/* remove outdated entry */
Curl_llist_remove(list, e, NULL);
Curl_node_remove(e);
else
/* the list is sorted so get out on the first mismatch */
break;
e = n;
}
e = list->head;
e = Curl_llist_head(list);
if(!e) {
/* clear the expire times within the handles that we remove from the
splay tree */
@ -3137,6 +3117,7 @@ static CURLMcode add_next_timeout(struct curltime now,
tv->tv_usec = 0;
}
else {
struct time_node *node = Curl_node_elem(e);
/* copy the first entry to 'tv' */
memcpy(tv, &node->time, sizeof(*tv));
@ -3162,15 +3143,16 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
SIGPIPE_VARIABLE(pipe_st);
if(checkall) {
struct Curl_llist_element *e;
struct Curl_llist_node *e;
/* *perform() deals with running_handles on its own */
result = curl_multi_perform(multi, running_handles);
/* walk through each easy handle and do the socket state change magic
and callbacks */
if(result != CURLM_BAD_HANDLE) {
for(e = multi->process.head; e && !result; e = e->next) {
result = singlesocket(multi, e->ptr);
for(e = Curl_llist_head(&multi->process); e && !result;
e = Curl_node_next(e)) {
result = singlesocket(multi, Curl_node_elem(e));
}
}
@ -3499,13 +3481,13 @@ CURLMcode Curl_update_timer(struct Curl_multi *multi)
static void
multi_deltimeout(struct Curl_easy *data, expire_id eid)
{
struct Curl_llist_element *e;
struct Curl_llist_node *e;
struct Curl_llist *timeoutlist = &data->state.timeoutlist;
/* find and remove the specific node from the list */
for(e = timeoutlist->head; e; e = e->next) {
struct time_node *n = (struct time_node *)e->ptr;
for(e = Curl_llist_head(timeoutlist); e; e = Curl_node_next(e)) {
struct time_node *n = Curl_node_elem(e);
if(n->eid == eid) {
Curl_llist_remove(timeoutlist, e, NULL);
Curl_node_remove(e);
return;
}
}
@ -3523,9 +3505,9 @@ multi_addtimeout(struct Curl_easy *data,
struct curltime *stamp,
expire_id eid)
{
struct Curl_llist_element *e;
struct Curl_llist_node *e;
struct time_node *node;
struct Curl_llist_element *prev = NULL;
struct Curl_llist_node *prev = NULL;
size_t n;
struct Curl_llist *timeoutlist = &data->state.timeoutlist;
@ -3538,8 +3520,8 @@ multi_addtimeout(struct Curl_easy *data,
n = Curl_llist_count(timeoutlist);
if(n) {
/* find the correct spot in the list */
for(e = timeoutlist->head; e; e = e->next) {
struct time_node *check = (struct time_node *)e->ptr;
for(e = Curl_llist_head(timeoutlist); e; e = Curl_node_next(e)) {
struct time_node *check = Curl_node_elem(e);
timediff_t diff = Curl_timediff(check->time, node->time);
if(diff > 0)
break;
@ -3661,10 +3643,8 @@ void Curl_expire_clear(struct Curl_easy *data)
if(rc)
infof(data, "Internal error clearing splay node = %d", rc);
/* flush the timeout list too */
while(list->size > 0) {
Curl_llist_remove(list, list->tail, NULL);
}
/* clear the timeout list too */
Curl_llist_destroy(list, NULL);
#ifdef DEBUGBUILD
infof(data, "Expire cleared");
@ -3726,10 +3706,10 @@ static void move_pending_to_connect(struct Curl_multi *multi,
DEBUGASSERT(data->mstate == MSTATE_PENDING);
/* Remove this node from the pending list */
Curl_llist_remove(&multi->pending, &data->multi_queue, NULL);
Curl_node_remove(&data->multi_queue);
/* put it into the process list */
link_easy(multi, data);
Curl_llist_append(&multi->process, data, &data->multi_queue);
multistate(data, MSTATE_CONNECT);
@ -3737,7 +3717,7 @@ static void move_pending_to_connect(struct Curl_multi *multi,
Curl_expire(data, 0, EXPIRE_RUN_NOW);
}
/* process_pending_handles() moves a handle from PENDING back into the main
/* process_pending_handles() moves a handle from PENDING back into the process
list and change state to CONNECT.
We do not move all transfers because that can be a significant amount.
@ -3753,9 +3733,9 @@ static void move_pending_to_connect(struct Curl_multi *multi,
*/
static void process_pending_handles(struct Curl_multi *multi)
{
struct Curl_llist_element *e = multi->pending.head;
struct Curl_llist_node *e = Curl_llist_head(&multi->pending);
if(e) {
struct Curl_easy *data = e->ptr;
struct Curl_easy *data = Curl_node_elem(e);
move_pending_to_connect(multi, data);
}
}
@ -3783,9 +3763,9 @@ struct Curl_easy **curl_multi_get_handles(struct Curl_multi *multi)
(multi->num_easy + 1));
if(a) {
unsigned int i = 0;
struct Curl_llist_element *e;
for(e = multi->process.head; e; e = e->next) {
struct Curl_easy *data = e->ptr;
struct Curl_llist_node *e;
for(e = Curl_llist_head(&multi->process); e; e = Curl_node_next(e)) {
struct Curl_easy *data = Curl_node_elem(e);
DEBUGASSERT(i < multi->num_easy);
if(!data->state.internal)
a[i++] = data;

View file

@ -33,7 +33,7 @@
struct connectdata;
struct Curl_message {
struct Curl_llist_element list;
struct Curl_llist_node list;
/* the 'CURLMsg' is the part that is visible to the external user */
struct CURLMsg extmsg;
};
@ -92,7 +92,7 @@ struct Curl_multi {
struct Curl_llist msglist; /* a list of messages from completed transfers */
/* Each added easy handle is in ONE of these three lists */
/* Each added easy handle is added to ONE of these three lists */
struct Curl_llist process; /* not in PENDING or MSGSENT */
struct Curl_llist pending; /* in PENDING */
struct Curl_llist msgsent; /* in MSGSENT */

View file

@ -539,6 +539,9 @@ CURLcode Curl_open(struct Curl_easy **curl)
data->progress.flags |= PGRS_HIDE;
data->state.current_speed = -1; /* init to negative == impossible */
#ifndef CURL_DISABLE_HTTP
Curl_llist_init(&data->state.httphdrs, NULL);
#endif
}
if(result) {
@ -551,7 +554,6 @@ CURLcode Curl_open(struct Curl_easy **curl)
}
else
*curl = data;
return result;
}
@ -895,7 +897,7 @@ ConnectionExists(struct Curl_easy *data,
bool foundPendingCandidate = FALSE;
bool canmultiplex = FALSE;
struct connectbundle *bundle;
struct Curl_llist_element *curr;
struct Curl_llist_node *curr;
#ifdef USE_NTLM
bool wantNTLMhttp = ((data->state.authhost.want & CURLAUTH_NTLM) &&
@ -952,12 +954,12 @@ ConnectionExists(struct Curl_easy *data,
}
}
curr = bundle->conn_list.head;
curr = Curl_llist_head(&bundle->conn_list);
while(curr) {
struct connectdata *check = curr->ptr;
struct connectdata *check = Curl_node_elem(curr);
/* Get next node now. We might remove a dead `check` connection which
* would invalidate `curr` as well. */
curr = curr->next;
curr = Curl_node_next(curr);
/* Note that if we use an HTTP proxy in normal mode (no tunneling), we
* check connections to that proxy and not to the actual remote server.
@ -987,8 +989,8 @@ ConnectionExists(struct Curl_easy *data,
}
else {
/* Could multiplex, but not when check belongs to another multi */
struct Curl_llist_element *e = check->easyq.head;
struct Curl_easy *entry = e->ptr;
struct Curl_llist_node *e = Curl_llist_head(&check->easyq);
struct Curl_easy *entry = Curl_node_elem(e);
if(entry->multi != data->multi)
continue;
}

View file

@ -797,7 +797,7 @@ struct ldapconninfo;
* unique for an entire connection.
*/
struct connectdata {
struct Curl_llist_element bundle_node; /* conncache */
struct Curl_llist_node bundle_node; /* conncache */
curl_closesocket_callback fclosesocket; /* function closing the socket(s) */
void *closesocket_client;
@ -806,7 +806,7 @@ struct connectdata {
handle is still used by one or more easy handles and can only used by any
other easy handle without careful consideration (== only for
multiplexing) and it cannot be used by another multi handle! */
#define CONN_INUSE(c) ((c)->easyq.size)
#define CONN_INUSE(c) Curl_llist_count(&(c)->easyq)
/**** Fields set when inited and not modified again */
curl_off_t connection_id; /* Contains a unique number to make it easier to
@ -1194,7 +1194,7 @@ typedef enum {
* One instance for each timeout an easy handle can set.
*/
struct time_node {
struct Curl_llist_element list;
struct Curl_llist_node list;
struct curltime time;
expire_id eid;
};
@ -1910,8 +1910,8 @@ struct Curl_easy {
curl_off_t id;
struct connectdata *conn;
struct Curl_llist_element multi_queue; /* for multihandle list management */
struct Curl_llist_element conn_queue; /* list per connectdata */
struct Curl_llist_node multi_queue; /* for multihandle list management */
struct Curl_llist_node conn_queue; /* list per connectdata */
CURLMstate mstate; /* the handle's state */
CURLcode result; /* previous result */

View file

@ -274,10 +274,10 @@ static struct Curl_easy *get_stream_easy(struct Curl_cfilter *cf,
return data;
}
else {
struct Curl_llist_element *e;
struct Curl_llist_node *e;
DEBUGASSERT(data->multi);
for(e = data->multi->process.head; e; e = e->next) {
struct Curl_easy *sdata = e->ptr;
for(e = Curl_llist_head(&data->multi->process); e; e = Curl_node_next(e)) {
struct Curl_easy *sdata = Curl_node_elem(e);
if(sdata->conn != data->conn)
continue;
stream = H3_STREAM_CTX(ctx, sdata);

View file

@ -669,10 +669,10 @@ static struct cf_osslq_stream *cf_osslq_get_qstream(struct Curl_cfilter *cf,
return &ctx->h3.s_qpack_dec;
}
else {
struct Curl_llist_element *e;
struct Curl_llist_node *e;
DEBUGASSERT(data->multi);
for(e = data->multi->process.head; e; e = e->next) {
struct Curl_easy *sdata = e->ptr;
for(e = Curl_llist_head(&data->multi->process); e; e = Curl_node_next(e)) {
struct Curl_easy *sdata = Curl_node_elem(e);
if(sdata->conn != data->conn)
continue;
stream = H3_STREAM_CTX(ctx, sdata);
@ -1423,12 +1423,12 @@ static CURLcode cf_progress_ingress(struct Curl_cfilter *cf,
}
if(ctx->h3.conn) {
struct Curl_llist_element *e;
struct Curl_llist_node *e;
struct h3_stream_ctx *stream;
/* PULL all open streams */
DEBUGASSERT(data->multi);
for(e = data->multi->process.head; e; e = e->next) {
struct Curl_easy *sdata = e->ptr;
for(e = Curl_llist_head(&data->multi->process); e; e = Curl_node_next(e)) {
struct Curl_easy *sdata = Curl_node_elem(e);
if(sdata->conn == data->conn && CURL_WANT_RECV(sdata)) {
stream = H3_STREAM_CTX(ctx, sdata);
if(stream && !stream->closed &&
@ -1454,9 +1454,9 @@ static CURLcode cf_osslq_check_and_unblock(struct Curl_cfilter *cf,
struct h3_stream_ctx *stream;
if(ctx->h3.conn) {
struct Curl_llist_element *e;
for(e = data->multi->process.head; e; e = e->next) {
struct Curl_easy *sdata = e->ptr;
struct Curl_llist_node *e;
for(e = Curl_llist_head(&data->multi->process); e; e = Curl_node_next(e)) {
struct Curl_easy *sdata = Curl_node_elem(e);
if(sdata->conn == data->conn) {
stream = H3_STREAM_CTX(ctx, sdata);
if(stream && stream->s.ssl && stream->s.send_blocked &&

View file

@ -177,11 +177,11 @@ static void check_resumes(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
struct cf_quiche_ctx *ctx = cf->ctx;
struct Curl_llist_element *e;
struct Curl_llist_node *e;
DEBUGASSERT(data->multi);
for(e = data->multi->process.head; e; e = e->next) {
struct Curl_easy *sdata = e->ptr;
for(e = Curl_llist_head(&data->multi->process); e; e = Curl_node_next(e)) {
struct Curl_easy *sdata = Curl_node_elem(e);
if(sdata->conn == data->conn) {
struct stream_ctx *stream = H3_STREAM_CTX(ctx, sdata);
if(stream && stream->quic_flow_blocked) {
@ -277,10 +277,10 @@ static struct Curl_easy *get_stream_easy(struct Curl_cfilter *cf,
return data;
}
else {
struct Curl_llist_element *e;
struct Curl_llist_node *e;
DEBUGASSERT(data->multi);
for(e = data->multi->process.head; e; e = e->next) {
struct Curl_easy *sdata = e->ptr;
for(e = Curl_llist_head(&data->multi->process); e; e = Curl_node_next(e)) {
struct Curl_easy *sdata = Curl_node_elem(e);
if(sdata->conn != data->conn)
continue;
stream = H3_STREAM_CTX(ctx, sdata);
@ -297,12 +297,12 @@ static struct Curl_easy *get_stream_easy(struct Curl_cfilter *cf,
static void cf_quiche_expire_conn_closed(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
struct Curl_llist_element *e;
struct Curl_llist_node *e;
DEBUGASSERT(data->multi);
CURL_TRC_CF(data, cf, "conn closed, expire all transfers");
for(e = data->multi->process.head; e; e = e->next) {
struct Curl_easy *sdata = e->ptr;
for(e = Curl_llist_head(&data->multi->process); e; e = Curl_node_next(e)) {
struct Curl_easy *sdata = Curl_node_elem(e);
if(sdata == data || sdata->conn != data->conn)
continue;
CURL_TRC_CF(sdata, cf, "conn closed, expire transfer");