llist: no longer uses malloc

The 'list element' struct now has to be within the data that is being
added to the list. Removes 16.6% (tiny) mallocs from a simple HTTP
transfer. (96 => 80)

Also removed return codes since the llist functions can't fail now.

Test 1300 updated accordingly.

Closes #1435
This commit is contained in:
Daniel Stenberg 2017-04-20 15:10:04 +02:00
parent cbb59ed9ce
commit cbae73e1dd
13 changed files with 165 additions and 203 deletions

View File

@ -72,13 +72,11 @@ static void bundle_destroy(struct connectbundle *cb_ptr)
/* Add a connection to a bundle */ /* Add a connection to a bundle */
static CURLcode bundle_add_conn(struct connectbundle *cb_ptr, static CURLcode bundle_add_conn(struct connectbundle *cb_ptr,
struct connectdata *conn) struct connectdata *conn)
{ {
if(!Curl_llist_insert_next(&cb_ptr->conn_list, cb_ptr->conn_list.tail, conn)) Curl_llist_insert_next(&cb_ptr->conn_list, cb_ptr->conn_list.tail, conn,
return CURLE_OUT_OF_MEMORY; &conn->bundle_node);
conn->bundle = cb_ptr; conn->bundle = cb_ptr;
cb_ptr->num_connections++; cb_ptr->num_connections++;
return CURLE_OK; return CURLE_OK;
} }

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____| * \___|\___/|_| \_\_____|
* *
* Copyright (C) 2010 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * Copyright (C) 2010 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
* *
* This software is licensed as described in the file COPYING, which * This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms * you should have received as part of this distribution. The terms
@ -28,23 +28,19 @@
/* The last #include file should be: */ /* The last #include file should be: */
#include "memdebug.h" #include "memdebug.h"
struct curl_fileinfo *Curl_fileinfo_alloc(void) struct fileinfo *Curl_fileinfo_alloc(void)
{ {
struct curl_fileinfo *tmp = malloc(sizeof(struct curl_fileinfo)); return calloc(1, sizeof(struct fileinfo));
if(!tmp)
return NULL;
memset(tmp, 0, sizeof(struct curl_fileinfo));
return tmp;
} }
void Curl_fileinfo_dtor(void *user, void *element) void Curl_fileinfo_dtor(void *user, void *element)
{ {
struct curl_fileinfo *finfo = element; struct fileinfo *finfo = element;
(void) user; (void) user;
if(!finfo) if(!finfo)
return; return;
Curl_safefree(finfo->b_data); Curl_safefree(finfo->info.b_data);
free(finfo); free(finfo);
} }

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____| * \___|\___/|_| \_\_____|
* *
* Copyright (C) 2010, Daniel Stenberg, <daniel@haxx.se>, et al. * Copyright (C) 2010, 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
* *
* This software is licensed as described in the file COPYING, which * This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms * you should have received as part of this distribution. The terms
@ -23,11 +23,15 @@
***************************************************************************/ ***************************************************************************/
#include <curl/curl.h> #include <curl/curl.h>
#include "llist.h"
struct curl_fileinfo *Curl_fileinfo_alloc(void); struct fileinfo {
struct curl_fileinfo info;
struct curl_llist_element list;
};
struct fileinfo *Curl_fileinfo_alloc(void);
void Curl_fileinfo_dtor(void *, void *); void Curl_fileinfo_dtor(void *, void *);
struct curl_fileinfo *Curl_fileinfo_dup(const struct curl_fileinfo *src);
#endif /* HEADER_CURL_FILEINFO_H */ #endif /* HEADER_CURL_FILEINFO_H */

View File

@ -165,7 +165,7 @@ struct ftp_parselist_data {
} state; } state;
CURLcode error; CURLcode error;
struct curl_fileinfo *file_data; struct fileinfo *file_data;
unsigned int item_length; unsigned int item_length;
size_t item_offset; size_t item_offset;
struct { struct {
@ -275,7 +275,7 @@ static void PL_ERROR(struct connectdata *conn, CURLcode err)
} }
static CURLcode ftp_pl_insert_finfo(struct connectdata *conn, static CURLcode ftp_pl_insert_finfo(struct connectdata *conn,
struct curl_fileinfo *finfo) struct fileinfo *infop)
{ {
curl_fnmatch_callback compare; curl_fnmatch_callback compare;
struct WildcardData *wc = &conn->data->wildcard; struct WildcardData *wc = &conn->data->wildcard;
@ -283,6 +283,7 @@ static CURLcode ftp_pl_insert_finfo(struct connectdata *conn,
struct curl_llist *llist = &wc->filelist; struct curl_llist *llist = &wc->filelist;
struct ftp_parselist_data *parser = tmpdata->parser; struct ftp_parselist_data *parser = tmpdata->parser;
bool add = TRUE; bool add = TRUE;
struct curl_fileinfo *finfo = &infop->info;
/* move finfo pointers to b_data */ /* move finfo pointers to b_data */
char *str = finfo->b_data; char *str = finfo->b_data;
@ -316,11 +317,7 @@ static CURLcode ftp_pl_insert_finfo(struct connectdata *conn,
} }
if(add) { if(add) {
if(!Curl_llist_insert_next(llist, llist->tail, finfo)) { Curl_llist_insert_next(llist, llist->tail, finfo, &infop->list);
Curl_fileinfo_dtor(NULL, finfo);
tmpdata->parser->file_data = NULL;
return CURLE_OUT_OF_MEMORY;
}
} }
else { else {
Curl_fileinfo_dtor(NULL, finfo); Curl_fileinfo_dtor(NULL, finfo);
@ -337,6 +334,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
struct connectdata *conn = (struct connectdata *)connptr; struct connectdata *conn = (struct connectdata *)connptr;
struct ftp_wc_tmpdata *tmpdata = conn->data->wildcard.tmp; struct ftp_wc_tmpdata *tmpdata = conn->data->wildcard.tmp;
struct ftp_parselist_data *parser = tmpdata->parser; struct ftp_parselist_data *parser = tmpdata->parser;
struct fileinfo *infop;
struct curl_fileinfo *finfo; struct curl_fileinfo *finfo;
unsigned long i = 0; unsigned long i = 0;
CURLcode result; CURLcode result;
@ -366,17 +364,18 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
parser->error = CURLE_OUT_OF_MEMORY; parser->error = CURLE_OUT_OF_MEMORY;
return bufflen; return bufflen;
} }
parser->file_data->b_data = malloc(FTP_BUFFER_ALLOCSIZE); parser->file_data->info.b_data = malloc(FTP_BUFFER_ALLOCSIZE);
if(!parser->file_data->b_data) { if(!parser->file_data->info.b_data) {
PL_ERROR(conn, CURLE_OUT_OF_MEMORY); PL_ERROR(conn, CURLE_OUT_OF_MEMORY);
return bufflen; return bufflen;
} }
parser->file_data->b_size = FTP_BUFFER_ALLOCSIZE; parser->file_data->info.b_size = FTP_BUFFER_ALLOCSIZE;
parser->item_offset = 0; parser->item_offset = 0;
parser->item_length = 0; parser->item_length = 0;
} }
finfo = parser->file_data; infop = parser->file_data;
finfo = &infop->info;
finfo->b_data[finfo->b_used++] = c; finfo->b_data[finfo->b_used++] = c;
if(finfo->b_used >= finfo->b_size - 1) { if(finfo->b_used >= finfo->b_size - 1) {
@ -498,8 +497,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
return bufflen; return bufflen;
} }
parser->file_data->flags |= CURLFINFOFLAG_KNOWN_PERM; parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_PERM;
parser->file_data->perm = perm; parser->file_data->info.perm = perm;
parser->offsets.perm = parser->item_offset; parser->offsets.perm = parser->item_offset;
parser->item_length = 0; parser->item_length = 0;
@ -530,8 +529,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
finfo->b_data[parser->item_offset + parser->item_length - 1] = 0; finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
hlinks = strtol(finfo->b_data + parser->item_offset, &p, 10); hlinks = strtol(finfo->b_data + parser->item_offset, &p, 10);
if(p[0] == '\0' && hlinks != LONG_MAX && hlinks != LONG_MIN) { if(p[0] == '\0' && hlinks != LONG_MAX && hlinks != LONG_MIN) {
parser->file_data->flags |= CURLFINFOFLAG_KNOWN_HLINKCOUNT; parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_HLINKCOUNT;
parser->file_data->hardlinks = hlinks; parser->file_data->info.hardlinks = hlinks;
} }
parser->item_length = 0; parser->item_length = 0;
parser->item_offset = 0; parser->item_offset = 0;
@ -613,8 +612,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
fsize = curlx_strtoofft(finfo->b_data+parser->item_offset, &p, 10); fsize = curlx_strtoofft(finfo->b_data+parser->item_offset, &p, 10);
if(p[0] == '\0' && fsize != CURL_OFF_T_MAX && if(p[0] == '\0' && fsize != CURL_OFF_T_MAX &&
fsize != CURL_OFF_T_MIN) { fsize != CURL_OFF_T_MIN) {
parser->file_data->flags |= CURLFINFOFLAG_KNOWN_SIZE; parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_SIZE;
parser->file_data->size = fsize; parser->file_data->info.size = fsize;
} }
parser->item_length = 0; parser->item_length = 0;
parser->item_offset = 0; parser->item_offset = 0;
@ -731,7 +730,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
finfo->b_data[parser->item_offset + parser->item_length - 1] = 0; finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
parser->offsets.filename = parser->item_offset; parser->offsets.filename = parser->item_offset;
parser->state.UNIX.main = PL_UNIX_FILETYPE; parser->state.UNIX.main = PL_UNIX_FILETYPE;
result = ftp_pl_insert_finfo(conn, finfo); result = ftp_pl_insert_finfo(conn, infop);
if(result) { if(result) {
PL_ERROR(conn, result); PL_ERROR(conn, result);
return bufflen; return bufflen;
@ -743,7 +742,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
finfo->b_data[parser->item_offset + parser->item_length - 1] = 0; finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
parser->offsets.filename = parser->item_offset; parser->offsets.filename = parser->item_offset;
parser->state.UNIX.main = PL_UNIX_FILETYPE; parser->state.UNIX.main = PL_UNIX_FILETYPE;
result = ftp_pl_insert_finfo(conn, finfo); result = ftp_pl_insert_finfo(conn, infop);
if(result) { if(result) {
PL_ERROR(conn, result); PL_ERROR(conn, result);
return bufflen; return bufflen;
@ -838,7 +837,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
else if(c == '\n') { else if(c == '\n') {
finfo->b_data[parser->item_offset + parser->item_length - 1] = 0; finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
parser->offsets.symlink_target = parser->item_offset; parser->offsets.symlink_target = parser->item_offset;
result = ftp_pl_insert_finfo(conn, finfo); result = ftp_pl_insert_finfo(conn, infop);
if(result) { if(result) {
PL_ERROR(conn, result); PL_ERROR(conn, result);
return bufflen; return bufflen;
@ -850,7 +849,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
if(c == '\n') { if(c == '\n') {
finfo->b_data[parser->item_offset + parser->item_length - 1] = 0; finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
parser->offsets.symlink_target = parser->item_offset; parser->offsets.symlink_target = parser->item_offset;
result = ftp_pl_insert_finfo(conn, finfo); result = ftp_pl_insert_finfo(conn, infop);
if(result) { if(result) {
PL_ERROR(conn, result); PL_ERROR(conn, result);
return bufflen; return bufflen;
@ -953,10 +952,10 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
return bufflen; return bufflen;
} }
/* correct file type */ /* correct file type */
parser->file_data->filetype = CURLFILETYPE_FILE; parser->file_data->info.filetype = CURLFILETYPE_FILE;
} }
parser->file_data->flags |= CURLFINFOFLAG_KNOWN_SIZE; parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_SIZE;
parser->item_length = 0; parser->item_length = 0;
parser->state.NT.main = PL_WINNT_FILENAME; parser->state.NT.main = PL_WINNT_FILENAME;
parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE; parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE;
@ -983,7 +982,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
parser->offsets.filename = parser->item_offset; parser->offsets.filename = parser->item_offset;
finfo->b_data[finfo->b_used - 1] = 0; finfo->b_data[finfo->b_used - 1] = 0;
parser->offsets.filename = parser->item_offset; parser->offsets.filename = parser->item_offset;
result = ftp_pl_insert_finfo(conn, finfo); result = ftp_pl_insert_finfo(conn, infop);
if(result) { if(result) {
PL_ERROR(conn, result); PL_ERROR(conn, result);
return bufflen; return bufflen;
@ -995,7 +994,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
case PL_WINNT_FILENAME_WINEOL: case PL_WINNT_FILENAME_WINEOL:
if(c == '\n') { if(c == '\n') {
parser->offsets.filename = parser->item_offset; parser->offsets.filename = parser->item_offset;
result = ftp_pl_insert_finfo(conn, finfo); result = ftp_pl_insert_finfo(conn, infop);
if(result) { if(result) {
PL_ERROR(conn, result); PL_ERROR(conn, result);
return bufflen; return bufflen;

View File

@ -124,17 +124,9 @@ Curl_hash_add(struct curl_hash *h, void *key, size_t key_len, void *p)
he = mk_hash_element(key, key_len, p); he = mk_hash_element(key, key_len, p);
if(he) { if(he) {
if(Curl_llist_insert_next(l, l->tail, he)) { Curl_llist_insert_next(l, l->tail, he, &he->list);
++h->size; ++h->size;
return p; /* return the new entry */ return p; /* return the new entry */
}
/*
* Couldn't insert it, destroy the 'he' element and the key again. We
* don't call hash_element_dtor() since that would also call the
* "destructor" for the actual data 'p'. When we fail, we shall not touch
* that data.
*/
free(he);
} }
return NULL; /* failure */ return NULL; /* failure */

View File

@ -57,6 +57,7 @@ struct curl_hash {
}; };
struct curl_hash_element { struct curl_hash_element {
struct curl_llist_element list;
void *ptr; void *ptr;
size_t key_len; size_t key_len;
char key[1]; /* allocated memory following the struct */ char key[1]; /* allocated memory following the struct */

View File

@ -49,18 +49,17 @@ Curl_llist_init(struct curl_llist *l, curl_llist_dtor dtor)
* entry is NULL and the list already has elements, the new one will be * entry is NULL and the list already has elements, the new one will be
* inserted first in the list. * inserted first in the list.
* *
* The 'ne' argument should be a pointer into the object to store.
*
* Returns: 1 on success and 0 on failure. * Returns: 1 on success and 0 on failure.
* *
* @unittest: 1300 * @unittest: 1300
*/ */
int 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_element *e,
const void *p) const void *p,
struct curl_llist_element *ne)
{ {
struct curl_llist_element *ne = malloc(sizeof(struct curl_llist_element));
if(!ne)
return 0;
ne->ptr = (void *) p; ne->ptr = (void *) p;
if(list->size == 0) { if(list->size == 0) {
list->head = ne; list->head = ne;
@ -87,19 +86,18 @@ Curl_llist_insert_next(struct curl_llist *list, struct curl_llist_element *e,
} }
++list->size; ++list->size;
return 1;
} }
/* /*
* @unittest: 1300 * @unittest: 1300
*/ */
int void
Curl_llist_remove(struct curl_llist *list, struct curl_llist_element *e, Curl_llist_remove(struct curl_llist *list, struct curl_llist_element *e,
void *user) void *user)
{ {
void *ptr;
if(e == NULL || list->size == 0) if(e == NULL || list->size == 0)
return 1; return;
if(e == list->head) { if(e == list->head) {
list->head = e->next; list->head = e->next;
@ -117,16 +115,16 @@ Curl_llist_remove(struct curl_llist *list, struct curl_llist_element *e,
e->next->prev = e->prev; e->next->prev = e->prev;
} }
list->dtor(user, e->ptr); ptr = e->ptr;
e->ptr = NULL; e->ptr = NULL;
e->prev = NULL; e->prev = NULL;
e->next = NULL; e->next = NULL;
free(e);
--list->size; --list->size;
return 1; /* call the dtor() last for when it actually frees the 'e' memory itself */
list->dtor(user, ptr);
} }
void void
@ -147,13 +145,13 @@ Curl_llist_count(struct curl_llist *list)
/* /*
* @unittest: 1300 * @unittest: 1300
*/ */
int Curl_llist_move(struct curl_llist *list, struct curl_llist_element *e, void Curl_llist_move(struct curl_llist *list, struct curl_llist_element *e,
struct curl_llist *to_list, struct curl_llist *to_list,
struct curl_llist_element *to_e) struct curl_llist_element *to_e)
{ {
/* Remove element from list */ /* Remove element from list */
if(e == NULL || list->size == 0) if(e == NULL || list->size == 0)
return 0; return;
if(e == list->head) { if(e == list->head) {
list->head = e->next; list->head = e->next;
@ -193,6 +191,4 @@ int Curl_llist_move(struct curl_llist *list, struct curl_llist_element *e,
} }
++to_list->size; ++to_list->size;
return 1;
} }

View File

@ -29,7 +29,6 @@ typedef void (*curl_llist_dtor)(void *, void *);
struct curl_llist_element { struct curl_llist_element {
void *ptr; void *ptr;
struct curl_llist_element *prev; struct curl_llist_element *prev;
struct curl_llist_element *next; struct curl_llist_element *next;
}; };
@ -37,21 +36,19 @@ struct curl_llist_element {
struct curl_llist { struct curl_llist {
struct curl_llist_element *head; struct curl_llist_element *head;
struct curl_llist_element *tail; struct curl_llist_element *tail;
curl_llist_dtor dtor; curl_llist_dtor dtor;
size_t size; size_t size;
}; };
void Curl_llist_init(struct curl_llist *, curl_llist_dtor); void Curl_llist_init(struct curl_llist *, curl_llist_dtor);
int Curl_llist_insert_next(struct curl_llist *, struct curl_llist_element *, void Curl_llist_insert_next(struct curl_llist *, struct curl_llist_element *,
const void *); const void *, struct curl_llist_element *node);
int Curl_llist_remove(struct curl_llist *, struct curl_llist_element *, void Curl_llist_remove(struct curl_llist *, struct curl_llist_element *,
void *); void *);
size_t Curl_llist_count(struct curl_llist *); size_t Curl_llist_count(struct curl_llist *);
void Curl_llist_destroy(struct curl_llist *, void *); void Curl_llist_destroy(struct curl_llist *, void *);
int Curl_llist_move(struct curl_llist *, struct curl_llist_element *, void Curl_llist_move(struct curl_llist *, struct curl_llist_element *,
struct curl_llist *, struct curl_llist_element *); struct curl_llist *, struct curl_llist_element *);
#endif /* HEADER_CURL_LLIST_H */ #endif /* HEADER_CURL_LLIST_H */

View File

@ -280,9 +280,8 @@ static int sh_init(struct curl_hash *hash, int hashsize)
static CURLMcode multi_addmsg(struct Curl_multi *multi, static CURLMcode multi_addmsg(struct Curl_multi *multi,
struct Curl_message *msg) struct Curl_message *msg)
{ {
if(!Curl_llist_insert_next(&multi->msglist, multi->msglist.tail, msg)) Curl_llist_insert_next(&multi->msglist, multi->msglist.tail, msg,
return CURLM_OUT_OF_MEMORY; &msg->list);
return CURLM_OK; return CURLM_OK;
} }
@ -1432,10 +1431,9 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
multistate(data, CURLM_STATE_CONNECT_PEND); multistate(data, CURLM_STATE_CONNECT_PEND);
/* add this handle to the list of connect-pending handles */ /* add this handle to the list of connect-pending handles */
if(!Curl_llist_insert_next(&multi->pending, multi->pending.tail, data)) Curl_llist_insert_next(&multi->pending, multi->pending.tail, data,
result = CURLE_OUT_OF_MEMORY; &data->connect_queue);
else result = CURLE_OK;
result = CURLE_OK;
break; break;
} }
@ -2483,7 +2481,10 @@ void Curl_multi_closed(struct connectdata *conn, curl_socket_t s)
} }
} }
struct time_node {
struct curl_llist_element list;
struct timeval time;
};
/* /*
* add_next_timeout() * add_next_timeout()
@ -2504,13 +2505,16 @@ static CURLMcode add_next_timeout(struct timeval now,
struct timeval *tv = &d->state.expiretime; struct timeval *tv = &d->state.expiretime;
struct curl_llist *list = &d->state.timeoutlist; struct curl_llist *list = &d->state.timeoutlist;
struct curl_llist_element *e; struct curl_llist_element *e;
struct time_node *node = NULL;
/* move over the timeout list for this specific handle and remove all /* move over the timeout list for this specific handle and remove all
timeouts that are now passed tense and store the next pending timeouts that are now passed tense and store the next pending
timeout in *tv */ timeout in *tv */
for(e = list->head; e;) { for(e = list->head; e;) {
struct curl_llist_element *n = e->next; struct curl_llist_element *n = e->next;
time_t diff = curlx_tvdiff(*(struct timeval *)e->ptr, now); time_t diff;
node = (struct time_node *)e->ptr;
diff = curlx_tvdiff(node->time, now);
if(diff <= 0) if(diff <= 0)
/* remove outdated entry */ /* remove outdated entry */
Curl_llist_remove(list, e, NULL); Curl_llist_remove(list, e, NULL);
@ -2528,7 +2532,7 @@ static CURLMcode add_next_timeout(struct timeval now,
} }
else { else {
/* copy the first entry to 'tv' */ /* copy the first entry to 'tv' */
memcpy(tv, e->ptr, sizeof(*tv)); memcpy(tv, &node->time, sizeof(*tv));
/* remove first entry from list */ /* remove first entry from list */
Curl_llist_remove(list, e, NULL); Curl_llist_remove(list, e, NULL);
@ -2879,21 +2883,21 @@ multi_addtimeout(struct curl_llist *timeoutlist,
struct timeval *stamp) struct timeval *stamp)
{ {
struct curl_llist_element *e; struct curl_llist_element *e;
struct timeval *timedup; struct time_node *node;
struct curl_llist_element *prev = NULL; struct curl_llist_element *prev = NULL;
timedup = malloc(sizeof(*timedup)); node = malloc(sizeof(struct time_node));
if(!timedup) if(!node)
return CURLM_OUT_OF_MEMORY; return CURLM_OUT_OF_MEMORY;
/* copy the timestamp */ /* copy the timestamp */
memcpy(timedup, stamp, sizeof(*timedup)); memcpy(&node->time, stamp, sizeof(*stamp));
if(Curl_llist_count(timeoutlist)) { if(Curl_llist_count(timeoutlist)) {
/* find the correct spot in the list */ /* find the correct spot in the list */
for(e = timeoutlist->head; e; e = e->next) { for(e = timeoutlist->head; e; e = e->next) {
struct timeval *checktime = e->ptr; struct time_node *check = (struct time_node *)e->ptr;
time_t diff = curlx_tvdiff(*checktime, *timedup); time_t diff = curlx_tvdiff(check->time, node->time);
if(diff > 0) if(diff > 0)
break; break;
prev = e; prev = e;
@ -2903,11 +2907,7 @@ multi_addtimeout(struct curl_llist *timeoutlist,
/* else /* else
this is the first timeout on the list */ this is the first timeout on the list */
if(!Curl_llist_insert_next(timeoutlist, prev, timedup)) { Curl_llist_insert_next(timeoutlist, prev, node, &node->list);
free(timedup);
return CURLM_OUT_OF_MEMORY;
}
return CURLM_OK; return CURLM_OK;
} }
@ -3044,8 +3044,9 @@ void Curl_expire_clear(struct Curl_easy *data)
infof(data, "Internal error clearing splay node = %d\n", rc); infof(data, "Internal error clearing splay node = %d\n", rc);
/* flush the timeout list too */ /* flush the timeout list too */
while(list->size > 0) while(list->size > 0) {
Curl_llist_remove(list, list->tail, NULL); Curl_llist_remove(list, list->tail, NULL);
}
#ifdef DEBUGBUILD #ifdef DEBUGBUILD
infof(data, "Expire cleared\n"); infof(data, "Expire cleared\n");

View File

@ -25,6 +25,7 @@
#include "conncache.h" #include "conncache.h"
struct Curl_message { struct Curl_message {
struct curl_llist_element list;
/* the 'CURLMsg' is the part that is visible to the external user */ /* the 'CURLMsg' is the part that is visible to the external user */
struct CURLMsg extmsg; struct CURLMsg extmsg;
}; };

View File

@ -38,16 +38,15 @@
#include "memdebug.h" #include "memdebug.h"
struct site_blacklist_entry { struct site_blacklist_entry {
char *hostname; struct curl_llist_element list;
unsigned short port; unsigned short port;
char hostname[1];
}; };
static void site_blacklist_llist_dtor(void *user, void *element) static void site_blacklist_llist_dtor(void *user, void *element)
{ {
struct site_blacklist_entry *entry = element; struct site_blacklist_entry *entry = element;
(void)user; (void)user;
Curl_safefree(entry->hostname);
free(entry); free(entry);
} }
@ -94,8 +93,8 @@ bool Curl_pipeline_penalized(struct Curl_easy *data,
static CURLcode addHandleToPipeline(struct Curl_easy *data, static CURLcode addHandleToPipeline(struct Curl_easy *data,
struct curl_llist *pipeline) struct curl_llist *pipeline)
{ {
if(!Curl_llist_insert_next(pipeline, pipeline->tail, data)) Curl_llist_insert_next(pipeline, pipeline->tail, data,
return CURLE_OUT_OF_MEMORY; &data->pipeline_queue);
return CURLE_OK; return CURLE_OK;
} }
@ -202,24 +201,17 @@ CURLMcode Curl_pipeline_set_site_blacklist(char **sites,
/* Parse the URLs and populate the list */ /* Parse the URLs and populate the list */
while(*sites) { while(*sites) {
char *hostname;
char *port; char *port;
struct site_blacklist_entry *entry; struct site_blacklist_entry *entry;
hostname = strdup(*sites); entry = malloc(sizeof(struct site_blacklist_entry) + strlen(*sites));
if(!hostname) {
Curl_llist_destroy(list, NULL);
return CURLM_OUT_OF_MEMORY;
}
entry = malloc(sizeof(struct site_blacklist_entry));
if(!entry) { if(!entry) {
free(hostname);
Curl_llist_destroy(list, NULL); Curl_llist_destroy(list, NULL);
return CURLM_OUT_OF_MEMORY; return CURLM_OUT_OF_MEMORY;
} }
strcpy(entry->hostname, *sites);
port = strchr(hostname, ':'); port = strchr(entry->hostname, ':');
if(port) { if(port) {
*port = '\0'; *port = '\0';
port++; port++;
@ -230,14 +222,7 @@ CURLMcode Curl_pipeline_set_site_blacklist(char **sites,
entry->port = 80; entry->port = 80;
} }
entry->hostname = hostname; Curl_llist_insert_next(list, list->tail, entry, &entry->list);
if(!Curl_llist_insert_next(list, list->tail, entry)) {
site_blacklist_llist_dtor(NULL, entry);
Curl_llist_destroy(list, NULL);
return CURLM_OUT_OF_MEMORY;
}
sites++; sites++;
} }
} }
@ -274,6 +259,11 @@ bool Curl_pipeline_server_blacklisted(struct Curl_easy *handle,
return FALSE; return FALSE;
} }
struct blacklist_node {
struct curl_llist_element list;
char server_name[1];
};
CURLMcode Curl_pipeline_set_server_blacklist(char **servers, CURLMcode Curl_pipeline_set_server_blacklist(char **servers,
struct curl_llist *list) struct curl_llist *list)
{ {
@ -286,20 +276,18 @@ CURLMcode Curl_pipeline_set_server_blacklist(char **servers,
/* Parse the URLs and populate the list */ /* Parse the URLs and populate the list */
while(*servers) { while(*servers) {
char *server_name; struct blacklist_node *n;
size_t len = strlen(*servers);
server_name = strdup(*servers); n = malloc(sizeof(struct blacklist_node) + len);
if(!server_name) { if(!n) {
Curl_llist_destroy(list, NULL); Curl_llist_destroy(list, NULL);
return CURLM_OUT_OF_MEMORY; return CURLM_OUT_OF_MEMORY;
} }
strcpy(n->server_name, *servers);
if(!Curl_llist_insert_next(list, list->tail, server_name)) { Curl_llist_insert_next(list, list->tail, n->server_name,
Curl_llist_destroy(list, NULL); &n->list);
Curl_safefree(server_name);
return CURLM_OUT_OF_MEMORY;
}
servers++; servers++;
} }
} }

View File

@ -898,6 +898,8 @@ struct connectdata {
connection is used! */ connection is used! */
struct Curl_easy *data; struct Curl_easy *data;
struct curl_llist_element bundle_node; /* conncache */
/* chunk is for HTTP chunked encoding, but is in the general connectdata /* chunk is for HTTP chunked encoding, but is in the general connectdata
struct only because we can do just about any protocol through a HTTP proxy struct only because we can do just about any protocol through a HTTP proxy
and a HTTP proxy may in fact respond using chunked encoding */ and a HTTP proxy may in fact respond using chunked encoding */
@ -1804,6 +1806,8 @@ struct Curl_easy {
struct Curl_easy *prev; struct Curl_easy *prev;
struct connectdata *easy_conn; /* the "unit's" connection */ struct connectdata *easy_conn; /* the "unit's" connection */
struct curl_llist_element connect_queue;
struct curl_llist_element pipeline_queue;
CURLMstate mstate; /* the handle's state */ CURLMstate mstate; /* the handle's state */
CURLcode result; /* previous result */ CURLcode result; /* previous result */

View File

@ -48,15 +48,20 @@ static void unit_stop(void)
} }
UNITTEST_START UNITTEST_START
{
int unusedData_case1 = 1; int unusedData_case1 = 1;
int unusedData_case2 = 2; int unusedData_case2 = 2;
int unusedData_case3 = 3; int unusedData_case3 = 3;
struct curl_llist_element case1_list;
struct curl_llist_element case2_list;
struct curl_llist_element case3_list;
struct curl_llist_element case4_list;
struct curl_llist_element case5_list;
struct curl_llist_element *head; struct curl_llist_element *head;
struct curl_llist_element *element_next; struct curl_llist_element *element_next;
struct curl_llist_element *element_prev; struct curl_llist_element *element_prev;
struct curl_llist_element *to_remove; struct curl_llist_element *to_remove;
size_t llist_size = Curl_llist_count(&llist); size_t llist_size = Curl_llist_count(&llist);
int curlErrCode = 0;
/** /**
* testing llist_init * testing llist_init
@ -85,67 +90,49 @@ UNITTEST_START
* 3: list tail will be the same as list head * 3: list tail will be the same as list head
*/ */
curlErrCode = Curl_llist_insert_next(&llist, llist.head, &unusedData_case1); Curl_llist_insert_next(&llist, llist.head, &unusedData_case1, &case1_list);
if(curlErrCode == 1) {
fail_unless(Curl_llist_count(&llist) == 1,
"List size should be 1 after adding a new element");
/*test that the list head data holds my unusedData */
fail_unless(llist.head->ptr == &unusedData_case1,
"List size should be 1 after adding a new element");
/*same goes for the list tail */
fail_unless(llist.tail == llist.head,
"List size should be 1 after adding a new element");
/** fail_unless(Curl_llist_count(&llist) == 1,
* testing Curl_llist_insert_next "List size should be 1 after adding a new element");
* case 2: /*test that the list head data holds my unusedData */
* list has 1 element, adding one element after the head fail_unless(llist.head->ptr == &unusedData_case1,
* @assumptions: "head ptr should be first entry");
* 1: the element next to head should be our newly created element /*same goes for the list tail */
* 2: the list tail should be our newly created element fail_unless(llist.tail == llist.head,
*/ "tail and head should be the same");
curlErrCode = Curl_llist_insert_next(&llist, llist.head, /**
&unusedData_case3); * testing Curl_llist_insert_next
if(curlErrCode == 1) { * case 2:
fail_unless(llist.head->next->ptr == &unusedData_case3, * list has 1 element, adding one element after the head
"the node next to head is not getting set correctly"); * @assumptions:
fail_unless(llist.tail->ptr == &unusedData_case3, * 1: the element next to head should be our newly created element
"the list tail is not getting set correctly"); * 2: the list tail should be our newly created element
} */
else {
printf("skipping Curl_llist_insert_next as a non "
"success error code was returned\n");
}
/** Curl_llist_insert_next(&llist, llist.head,
* testing Curl_llist_insert_next &unusedData_case3, &case3_list);
* case 3: fail_unless(llist.head->next->ptr == &unusedData_case3,
* list has >1 element, adding one element after "NULL" "the node next to head is not getting set correctly");
* @assumptions: fail_unless(llist.tail->ptr == &unusedData_case3,
* 1: the element next to head should be our newly created element "the list tail is not getting set correctly");
* 2: the list tail should different from newly created element
*/
curlErrCode = Curl_llist_insert_next(&llist, llist.head, /**
&unusedData_case2); * testing Curl_llist_insert_next
if(curlErrCode == 1) { * case 3:
fail_unless(llist.head->next->ptr == &unusedData_case2, * list has >1 element, adding one element after "NULL"
"the node next to head is not getting set correctly"); * @assumptions:
/* better safe than sorry, check that the tail isn't corrupted */ * 1: the element next to head should be our newly created element
fail_unless(llist.tail->ptr != &unusedData_case2, * 2: the list tail should different from newly created element
"the list tail is not getting set correctly"); */
}
else {
printf("skipping Curl_llist_insert_next as a non "
"success error code was returned\n");
}
} Curl_llist_insert_next(&llist, llist.head,
else { &unusedData_case2, &case2_list);
printf("skipping Curl_llist_insert_next as a non " fail_unless(llist.head->next->ptr == &unusedData_case2,
"success error code was returned\n"); "the node next to head is not getting set correctly");
} /* better safe than sorry, check that the tail isn't corrupted */
fail_unless(llist.tail->ptr != &unusedData_case2,
"the list tail is not getting set correctly");
/* unit tests for Curl_llist_remove */ /* unit tests for Curl_llist_remove */
@ -183,8 +170,11 @@ UNITTEST_START
* 2: element->previous->next will be element->next * 2: element->previous->next will be element->next
* 3: element->next->previous will be element->previous * 3: element->next->previous will be element->previous
*/ */
Curl_llist_insert_next(&llist, llist.head, &unusedData_case3); Curl_llist_insert_next(&llist, llist.head, &unusedData_case3,
&case4_list);
llist_size = Curl_llist_count(&llist); llist_size = Curl_llist_count(&llist);
fail_unless(llist_size == 3, "should be 3 list members");
to_remove = llist.head->next; to_remove = llist.head->next;
abort_unless(to_remove, "to_remove is NULL"); abort_unless(to_remove, "to_remove is NULL");
element_next = to_remove->next; element_next = to_remove->next;
@ -248,20 +238,17 @@ UNITTEST_START
* add one element to the list * add one element to the list
*/ */
curlErrCode = Curl_llist_insert_next(&llist, llist.head, &unusedData_case1); Curl_llist_insert_next(&llist, llist.head, &unusedData_case1,
&case5_list);
/* necessary assertions */ /* necessary assertions */
abort_unless(curlErrCode == 1,
"Curl_llist_insert_next returned an error, Can't move on with test");
abort_unless(Curl_llist_count(&llist) == 1, abort_unless(Curl_llist_count(&llist) == 1,
"Number of list elements is not as expected, Aborting"); "Number of list elements is not as expected, Aborting");
abort_unless(Curl_llist_count(&llist_destination) == 0, abort_unless(Curl_llist_count(&llist_destination) == 0,
"Number of list elements is not as expected, Aborting"); "Number of list elements is not as expected, Aborting");
/*actual testing code*/ /*actual testing code*/
curlErrCode = Curl_llist_move(&llist, llist.head, &llist_destination, NULL); Curl_llist_move(&llist, llist.head, &llist_destination, NULL);
abort_unless(curlErrCode == 1,
"Curl_llist_move returned an error, Can't move on with test");
fail_unless(Curl_llist_count(&llist) == 0, fail_unless(Curl_llist_count(&llist) == 0,
"moving element from llist didn't decrement the size"); "moving element from llist didn't decrement the size");
@ -279,7 +266,5 @@ UNITTEST_START
fail_unless(llist_destination.tail == llist_destination.tail, fail_unless(llist_destination.tail == llist_destination.tail,
"llist_destination tail doesn't equal llist_destination head"); "llist_destination tail doesn't equal llist_destination head");
}
UNITTEST_STOP UNITTEST_STOP