diff --git a/include/libwebsockets/lws-lwsac.h b/include/libwebsockets/lws-lwsac.h index 89d5834db..1c0d69b8a 100644 --- a/include/libwebsockets/lws-lwsac.h +++ b/include/libwebsockets/lws-lwsac.h @@ -95,11 +95,36 @@ lws_list_ptr_insert(lws_list_ptr *phead, lws_list_ptr *add, * whatever is necessary to return you a pointer to ensure bytes of memory * reserved for the caller. * + * This always allocates in the current chunk or a new chunk... see the + * lwsac_use_backfill() variant to try first to find space in earlier chunks. + * * Returns NULL if OOM. */ LWS_VISIBLE LWS_EXTERN void * lwsac_use(struct lwsac **head, size_t ensure, size_t chunk_size); +/** + * lwsac_use_backfill - allocate / use some memory from a lwsac + * + * \param head: pointer to the lwsac list object + * \param ensure: the number of bytes we want to use + * \param chunk_size: 0, or the size of the chunk to (over)allocate if + * what we want won't fit in the current tail chunk. If + * 0, the default value of 4000 is used. If ensure is + * larger, it is used instead. + * + * This also serves to init the lwsac if *head is NULL. Basically it does + * whatever is necessary to return you a pointer to ensure bytes of memory + * reserved for the caller. + * + * Also checks if earlier blocks have enough remaining space to take the + * allocation before making a new allocation. + * + * Returns NULL if OOM. + */ +LWS_VISIBLE LWS_EXTERN void * +lwsac_use_backfill(struct lwsac **head, size_t ensure, size_t chunk_size); + /** * lwsac_use - allocate / use some memory from a lwsac * @@ -191,8 +216,9 @@ lwsac_cached_file(const char *filepath, lwsac_cached_file_t *cache, /* more advanced helpers */ +/* offset from lac to start of payload, first = 1 = first lac in chain */ LWS_VISIBLE LWS_EXTERN size_t -lwsac_sizeof(void); +lwsac_sizeof(int first); LWS_VISIBLE LWS_EXTERN size_t lwsac_get_tail_pos(struct lwsac *lac); diff --git a/lib/misc/lwsac/cached-file.c b/lib/misc/lwsac/cached-file.c index a58903779..d5573ee65 100644 --- a/lib/misc/lwsac/cached-file.c +++ b/lib/misc/lwsac/cached-file.c @@ -71,6 +71,7 @@ #define cache_file_to_lac(c) ((struct lwsac *)((char *)c - \ sizeof(struct cached_file_info) - \ + sizeof(struct lwsac_head) - \ sizeof(struct lwsac))) void @@ -176,7 +177,7 @@ lwsac_cached_file(const char *filepath, lwsac_cached_file_t *cache, size_t *len) * it... reload in a new lac and then detach the old lac. */ - all = sizeof(*info) + s.st_size + 1; + all = sizeof(*info) + s.st_size + 2; info = lwsac_use(&lac, all, all); if (!info) diff --git a/lib/misc/lwsac/lwsac.c b/lib/misc/lwsac/lwsac.c index 59ca36cf8..5830ef6ca 100644 --- a/lib/misc/lwsac/lwsac.c +++ b/lib/misc/lwsac/lwsac.c @@ -52,9 +52,9 @@ lwsac_align(size_t length) } size_t -lwsac_sizeof(void) +lwsac_sizeof(int first) { - return sizeof(struct lwsac); + return sizeof(struct lwsac) + (first ? sizeof(struct lwsac_head) : 0); } size_t @@ -69,39 +69,59 @@ lwsac_get_next(struct lwsac *lac) return lac->next; } -void * -lwsac_use(struct lwsac **head, size_t ensure, size_t chunk_size) +static void * +_lwsac_use(struct lwsac **head, size_t ensure, size_t chunk_size, char backfill) { - size_t ofs, alloc, al; - struct lwsac *bf = *head; struct lwsac_head *lachead = NULL; + size_t ofs, alloc, al, hp; + struct lwsac *bf = *head; if (bf) lachead = (struct lwsac_head *)&bf[1]; - /* check for something that can take it first */ + al = lwsac_align(ensure); - while (bf) { - if (bf->alloc_size - bf->ofs >= ensure) - goto do_use; + /* backfill into earlier chunks if that is allowed */ - bf = bf->next; + if (backfill) + /* + * check if anything can take it, from the start + */ + while (bf) { + if (bf->alloc_size - bf->ofs >= ensure) + goto do_use; + + bf = bf->next; + } + else { + /* + * If there's a current chunk, just check if he can take it + */ + if (lachead && lachead->curr) { + bf = lachead->curr; + if (bf->alloc_size - bf->ofs >= ensure) + goto do_use; + } } /* nothing can currently take it... so we must allocate */ + hp = sizeof(*bf); /* always need the normal header part... */ + if (!*head) + hp += sizeof(struct lwsac_head); + if (!chunk_size) - alloc = LWSAC_CHUNK_SIZE + sizeof(*bf); + alloc = LWSAC_CHUNK_SIZE + hp; else - alloc = chunk_size + sizeof(*bf); + alloc = chunk_size + hp; /* * If we get asked for something outside our expectation, * increase the allocation to meet it */ - if (ensure >= alloc - sizeof(*bf)) - alloc = ensure + sizeof(*bf); + if (al >= alloc - hp) + alloc = al + hp; bf = malloc(alloc); if (!bf) { @@ -142,7 +162,6 @@ do_use: ofs = bf->ofs; - al = lwsac_align(ensure); if (al > ensure) /* zero down the alignment padding part */ memset((char *)bf + ofs + ensure, 0, al - ensure); @@ -154,6 +173,18 @@ do_use: return (char *)bf + ofs; } +void * +lwsac_use(struct lwsac **head, size_t ensure, size_t chunk_size) +{ + return _lwsac_use(head, ensure, chunk_size, 0); +} + +void * +lwsac_use_backfill(struct lwsac **head, size_t ensure, size_t chunk_size) +{ + return _lwsac_use(head, ensure, chunk_size, 1); +} + uint8_t * lwsac_scan_extant(struct lwsac *head, uint8_t *find, size_t len, int nul) {