Update Files
This commit is contained in:
148
Kinc/Sources/kinc/libs/misc/lwsac/README.md
Normal file
148
Kinc/Sources/kinc/libs/misc/lwsac/README.md
Normal file
@ -0,0 +1,148 @@
|
||||
## LWS Allocated Chunks
|
||||
|
||||

|
||||
|
||||
These apis provide a way to manage a linked-list of allocated chunks...
|
||||
|
||||
[ HEAD alloc ] -> [ next alloc ] -> [ next alloc ] -> [ curr alloc ]
|
||||
|
||||
... and sub-allocate trivially inside the chunks. These sub-allocations are
|
||||
not tracked by lwsac at all, there is a "used" high-water mark for each chunk
|
||||
that's simply advanced by the amount sub-allocated. If the allocation size
|
||||
matches the platform pointer alignment, there is zero overhead to sub-allocate
|
||||
(otherwise the allocation is padded to the next platform pointer alignment
|
||||
automatically).
|
||||
|
||||
If you have an unknown amount of relatively little things to allocate, including
|
||||
strings or other unstructured data, lwsac is significantly more efficient than
|
||||
individual allocations using malloc or so.
|
||||
|
||||
[lwsac full public api](https://libwebsockets.org/git/libwebsockets/tree/include/libwebsockets/lws-lwsac.h)
|
||||
|
||||
## lwsac_use() api
|
||||
|
||||
```
|
||||
/**
|
||||
* lwsac_use - 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.
|
||||
*
|
||||
* Returns NULL if OOM.
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN void *
|
||||
lwsac_use(struct lwsac **head, size_t ensure, size_t chunk_size);
|
||||
```
|
||||
|
||||
When you make an sub-allocation using `lwsac_use()`, you can either
|
||||
set the `chunk_size` arg to zero, defaulting to 4000, or a specific chunk size.
|
||||
In the event the requested sub-allocation exceeds the chunk size, the chunk
|
||||
size is increated to match it automatically for this allocation only.
|
||||
|
||||
Subsequent `lwsac_use()` calls will advance internal pointers to use up the
|
||||
remaining space inside the current chunk if possible; if not enough remaining
|
||||
space it is skipped, a new allocation is chained on and the request pointed to
|
||||
there.
|
||||
|
||||
Lwsac does not store information about sub-allocations. There is really zero
|
||||
overhead for individual sub-allocations (unless their size is not
|
||||
pointer-aligned, in which case the actual amount sub-allocated is rounded up to
|
||||
the next pointer alignment automatically). For structs, which are pointer-
|
||||
aligned naturally, and a chunk size relatively large for the sub-allocation
|
||||
size, lwsac is extremely efficient even for huge numbers of small allocations.
|
||||
|
||||
This makes lwsac very effective when the total amount of allocation needed is
|
||||
not known at the start and may be large... it will simply add on chunks to cope
|
||||
with whatever happens.
|
||||
|
||||
## lwsac_free() api
|
||||
|
||||
```
|
||||
/**
|
||||
* lwsac_free - deallocate all chunks in the lwsac and set head NULL
|
||||
*
|
||||
* \param head: pointer to the lwsac list object
|
||||
*
|
||||
* This deallocates all chunks in the lwsac, then sets *head to NULL. All
|
||||
* lwsac_use() pointers are invalidated in one hit without individual frees.
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lwsac_free(struct lwsac **head);
|
||||
```
|
||||
|
||||
When you are finished with the lwsac, you simply free the chain of allocated
|
||||
chunks using lwsac_free() on the lwsac head. There's no tracking or individual
|
||||
destruction of suballocations - the whole chain of chunks the suballocations
|
||||
live in are freed and invalidated all together.
|
||||
|
||||
If the structs stored in the lwsac allocated things **outside** the lwsac, then the
|
||||
user must unwind through them and perform the frees. But the idea of lwsac is
|
||||
things stored in the lwsac also suballocate into the lwsac, and point into the
|
||||
lwsac if they need to, avoiding any need to visit them during destroy. It's
|
||||
like clearing up after a kids' party by gathering up a disposable tablecloth:
|
||||
no matter what was left on the table, it's all gone in one step.
|
||||
|
||||
## `lws_list_ptr` helpers
|
||||
|
||||
```
|
||||
/* sort may be NULL if you don't care about order */
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_list_ptr_insert(lws_list_ptr *phead, lws_list_ptr *add,
|
||||
lws_list_ptr_sort_func_t sort);
|
||||
```
|
||||
|
||||
A common pattern needed with sub-allocated structs is they are on one or more
|
||||
linked-list. To make that simple to do cleanly, `lws_list...` apis are provided
|
||||
along with a generic insertion function that can take a sort callback. These
|
||||
allow a struct to participate on multiple linked-lists simultaneously.
|
||||
|
||||
## common const string and blob folding
|
||||
|
||||
In some cases the input to be stored in the lwsac may repeat the same tokens
|
||||
multiple times... if the pattern is to store the string or blob in the lwsac
|
||||
and then point to it, you can make use of a helper api
|
||||
|
||||
```
|
||||
uint8_t *
|
||||
lwsac_scan_extant(struct lwsac *head, uint8_t *find, size_t len, int nul);
|
||||
```
|
||||
|
||||
This lets you check in all previous used parts of the lwsac for the same
|
||||
string or blob, plus optionally a terminal NUL afterwards. If not found,
|
||||
it returns `NULL` and you can copy it into the lwsac as usual. If it is
|
||||
found, a pointer is returned, and you can use this directly without copying
|
||||
the string or blob in again.
|
||||
|
||||
## optimizations to minimize overhead
|
||||
|
||||
If the lwsac will persist in the system for some time, it's desirable to reduce
|
||||
the memory needed as overhead. Overhead is created
|
||||
|
||||
- once per chunk... in addition to the malloc overhead, there's an lwsac
|
||||
chunk header of 2 x pointers and 2 x size_t
|
||||
|
||||
- at the unused part at the end that was allocated but not used
|
||||
|
||||
A good strategy is to make the initial allocation reflect the minimum expected
|
||||
size of the overall lwsac in one hit. Then use a chunk size that is a tradeoff
|
||||
between the number of chunks that might be needed and the fact that on average,
|
||||
you can expect to waste half a chunk. For example if the storage is typically
|
||||
between 4K - 6K, you could allocate 4K or 4.5K for the first chunk and then fill
|
||||
in using 256 or 512 byte chunks.
|
||||
|
||||
You can measure the overhead in an lwsac using `lwsac_total_overhead()`.
|
||||
|
||||
The lwsac apis look first in the unused part of previous chunks, if any, and
|
||||
will place new allocations there preferentially if they fit. This helps for the
|
||||
case lwsac was forced to allocate a new chunk because you asked for something
|
||||
large, while there was actually significant free space left in the old chunk,
|
||||
just not enough for that particular allocation. Subsequent lwsac use can then
|
||||
"backfill" smaller things there to make best use of allocated space.
|
218
Kinc/Sources/kinc/libs/misc/lwsac/cached-file.c
Normal file
218
Kinc/Sources/kinc/libs/misc/lwsac/cached-file.c
Normal file
@ -0,0 +1,218 @@
|
||||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#if !defined(LWS_PLAT_OPTEE) && !defined(OPTEE_DEV_KIT)
|
||||
|
||||
#include "private-lib-core.h"
|
||||
#include "private-lib-misc-lwsac.h"
|
||||
|
||||
/*
|
||||
* Helper for caching a file in memory in a lac, but also to check at intervals
|
||||
* no less than 5s if the file is still fresh.
|
||||
*
|
||||
* Set *cache to NULL the first time before calling.
|
||||
*
|
||||
* You should call this each time before using the cache... if it's
|
||||
*
|
||||
* - less than 5s since the last freshness check, and
|
||||
* - the file is already in memory
|
||||
*
|
||||
* it just returns with *cache left alone; this costs very little. You should
|
||||
* call `lwsac_use_cached_file_start()` and `lwsac_use_cached_file_end()`
|
||||
* to lock the cache against deletion while you are using it.
|
||||
*
|
||||
* If it's
|
||||
*
|
||||
* - at least 5s since the last freshness check, and
|
||||
* - the file timestamp has changed
|
||||
*
|
||||
* then
|
||||
*
|
||||
* - the file is reloaded into a new lac and *cache set to that
|
||||
*
|
||||
* - the old cache lac, if any, is detached (so it will be freed when its
|
||||
* reference count reaches zero, or immediately if nobody has it)
|
||||
*
|
||||
* Note the call can fail due to OOM or filesystem issue at any time.
|
||||
*
|
||||
*
|
||||
* After the LAC header there is stored a `struct cached_file_info` and then
|
||||
* the raw file contents. *
|
||||
*
|
||||
* [LAC header]
|
||||
* [struct cached_file_info]
|
||||
* [file contents] <--- *cache is set to here
|
||||
*
|
||||
* The api returns a lwsac_cached_file_t type offset to point to the file
|
||||
* contents. Helpers for reference counting and freeing are also provided
|
||||
* that take that type and know how to correct it back to operate on the LAC.
|
||||
*/
|
||||
|
||||
#define cache_file_to_lac(c) ((struct lwsac *)((char *)c - \
|
||||
sizeof(struct cached_file_info) - \
|
||||
sizeof(struct lwsac_head) - \
|
||||
sizeof(struct lwsac)))
|
||||
|
||||
void
|
||||
lwsac_use_cached_file_start(lwsac_cached_file_t cache)
|
||||
{
|
||||
struct lwsac *lac = cache_file_to_lac(cache);
|
||||
struct lwsac_head *lachead = (struct lwsac_head *)&lac->head[1];
|
||||
|
||||
lachead->refcount++;
|
||||
// lwsl_debug("%s: html refcount: %d\n", __func__, lachead->refcount);
|
||||
}
|
||||
|
||||
void
|
||||
lwsac_use_cached_file_end(lwsac_cached_file_t *cache)
|
||||
{
|
||||
struct lwsac *lac;
|
||||
struct lwsac_head *lachead;
|
||||
|
||||
if (!cache || !*cache)
|
||||
return;
|
||||
|
||||
lac = cache_file_to_lac(*cache);
|
||||
lachead = (struct lwsac_head *)&lac->head[1];
|
||||
|
||||
if (!lachead->refcount)
|
||||
lwsl_err("%s: html refcount zero on entry\n", __func__);
|
||||
|
||||
if (lachead->refcount && !--lachead->refcount && lachead->detached) {
|
||||
*cache = NULL; /* not usable any more */
|
||||
lwsac_free(&lac);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
lwsac_use_cached_file_detach(lwsac_cached_file_t *cache)
|
||||
{
|
||||
struct lwsac *lac = cache_file_to_lac(*cache);
|
||||
struct lwsac_head *lachead = NULL;
|
||||
|
||||
if (lac) {
|
||||
lachead = (struct lwsac_head *)&lac->head[1];
|
||||
|
||||
lachead->detached = 1;
|
||||
if (lachead->refcount)
|
||||
return;
|
||||
}
|
||||
|
||||
*cache = NULL;
|
||||
lwsac_free(&lac);
|
||||
}
|
||||
|
||||
int
|
||||
lwsac_cached_file(const char *filepath, lwsac_cached_file_t *cache, size_t *len)
|
||||
{
|
||||
struct cached_file_info *info = NULL;
|
||||
lwsac_cached_file_t old = *cache;
|
||||
struct lwsac *lac = NULL;
|
||||
time_t t = time(NULL);
|
||||
unsigned char *a;
|
||||
struct stat s;
|
||||
size_t all;
|
||||
ssize_t rd;
|
||||
int fd;
|
||||
|
||||
if (old) { /* we already have a cached copy of it */
|
||||
|
||||
info = (struct cached_file_info *)((*cache) - sizeof(*info));
|
||||
|
||||
if (t - info->last_confirm < 5)
|
||||
/* we checked it as fresh less than 5s ago, use old */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ...it's been 5s, we should check again on the filesystem
|
||||
* that the file hasn't changed
|
||||
*/
|
||||
|
||||
fd = open(filepath, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
lwsl_err("%s: cannot open %s\n", __func__, filepath);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (fstat(fd, &s)) {
|
||||
lwsl_err("%s: cannot stat %s\n", __func__, filepath);
|
||||
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (old && s.st_mtime == info->s.st_mtime) {
|
||||
/* it still seems to be the same as our cached one */
|
||||
info->last_confirm = t;
|
||||
|
||||
close(fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* we either didn't cache it yet, or it has changed since we cached
|
||||
* it... reload in a new lac and then detach the old lac.
|
||||
*/
|
||||
|
||||
all = sizeof(*info) + (unsigned long)s.st_size + 2;
|
||||
|
||||
info = lwsac_use(&lac, all, all);
|
||||
if (!info)
|
||||
goto bail;
|
||||
|
||||
info->s = s;
|
||||
info->last_confirm = t;
|
||||
|
||||
a = (unsigned char *)(info + 1);
|
||||
|
||||
*len = (unsigned long)s.st_size;
|
||||
a[s.st_size] = '\0';
|
||||
|
||||
rd = read(fd, a, (unsigned long)s.st_size);
|
||||
if (rd != s.st_size) {
|
||||
lwsl_err("%s: cannot read %s (%d)\n", __func__, filepath,
|
||||
(int)rd);
|
||||
goto bail1;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
*cache = (lwsac_cached_file_t)a;
|
||||
if (old)
|
||||
lwsac_use_cached_file_detach(&old);
|
||||
|
||||
return 0;
|
||||
|
||||
bail1:
|
||||
lwsac_free(&lac);
|
||||
|
||||
bail:
|
||||
close(fd);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
358
Kinc/Sources/kinc/libs/misc/lwsac/lwsac.c
Normal file
358
Kinc/Sources/kinc/libs/misc/lwsac/lwsac.c
Normal file
@ -0,0 +1,358 @@
|
||||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "private-lib-core.h"
|
||||
#include "private-lib-misc-lwsac.h"
|
||||
|
||||
void
|
||||
lws_list_ptr_insert(lws_list_ptr *head, lws_list_ptr *add,
|
||||
lws_list_ptr_sort_func_t sort_func)
|
||||
{
|
||||
while (sort_func && *head) {
|
||||
if (sort_func(add, *head) <= 0)
|
||||
break;
|
||||
|
||||
head = *head;
|
||||
}
|
||||
|
||||
*add = *head;
|
||||
*head = add;
|
||||
}
|
||||
|
||||
size_t
|
||||
lwsac_align(size_t length)
|
||||
{
|
||||
size_t align = sizeof(int *);
|
||||
|
||||
if (length & (align - 1))
|
||||
length += align - (length & (align - 1));
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
size_t
|
||||
lwsac_sizeof(int first)
|
||||
{
|
||||
return sizeof(struct lwsac) + (first ? sizeof(struct lwsac_head) : 0);
|
||||
}
|
||||
|
||||
size_t
|
||||
lwsac_get_tail_pos(struct lwsac *lac)
|
||||
{
|
||||
return lac->ofs;
|
||||
}
|
||||
|
||||
struct lwsac *
|
||||
lwsac_get_next(struct lwsac *lac)
|
||||
{
|
||||
return lac->next;
|
||||
}
|
||||
|
||||
int
|
||||
lwsac_extend(struct lwsac *head, size_t amount)
|
||||
{
|
||||
struct lwsac_head *lachead;
|
||||
struct lwsac *bf;
|
||||
|
||||
assert(head);
|
||||
lachead = (struct lwsac_head *)&head[1];
|
||||
|
||||
bf = lachead->curr;
|
||||
assert(bf);
|
||||
|
||||
if (bf->alloc_size - bf->ofs < lwsac_align(amount))
|
||||
return 1;
|
||||
|
||||
/* memset so constant folding never sees uninitialized data */
|
||||
|
||||
memset(((uint8_t *)bf) + bf->ofs, 0, lwsac_align(amount));
|
||||
bf->ofs += lwsac_align(amount);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *
|
||||
_lwsac_use(struct lwsac **head, size_t ensure, size_t chunk_size, char backfill)
|
||||
{
|
||||
struct lwsac_head *lachead = NULL;
|
||||
size_t ofs, alloc, al, hp;
|
||||
struct lwsac *bf = *head;
|
||||
|
||||
if (bf)
|
||||
lachead = (struct lwsac_head *)&bf[1];
|
||||
|
||||
al = lwsac_align(ensure);
|
||||
|
||||
/* backfill into earlier chunks if that is allowed */
|
||||
|
||||
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 + hp;
|
||||
else
|
||||
alloc = chunk_size + hp;
|
||||
|
||||
/*
|
||||
* If we get asked for something outside our expectation,
|
||||
* increase the allocation to meet it
|
||||
*/
|
||||
|
||||
if (al >= alloc - hp)
|
||||
alloc = al + hp;
|
||||
|
||||
// lwsl_debug("%s: alloc %d for %d\n", __func__, (int)alloc, (int)ensure);
|
||||
bf = malloc(alloc);
|
||||
if (!bf) {
|
||||
lwsl_err("%s: OOM trying to alloc %llud\n", __func__,
|
||||
(unsigned long long)alloc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* belabouring the point... ofs is aligned to the platform's
|
||||
* generic struct alignment at the start then
|
||||
*/
|
||||
bf->ofs = sizeof(*bf);
|
||||
|
||||
if (!*head) {
|
||||
/*
|
||||
* We are the first, head, entry...
|
||||
*/
|
||||
*head = bf;
|
||||
/*
|
||||
* ... allocate for the special head block
|
||||
*/
|
||||
bf->ofs += sizeof(*lachead);
|
||||
lachead = (struct lwsac_head *)&bf[1];
|
||||
memset(lachead, 0, sizeof(*lachead));
|
||||
} else
|
||||
if (lachead->curr)
|
||||
lachead->curr->next = bf;
|
||||
|
||||
lachead->curr = bf;
|
||||
bf->head = *head;
|
||||
bf->next = NULL;
|
||||
bf->alloc_size = alloc;
|
||||
|
||||
lachead->total_alloc_size += alloc;
|
||||
lachead->total_blocks++;
|
||||
|
||||
do_use:
|
||||
|
||||
ofs = bf->ofs;
|
||||
|
||||
if (al > ensure)
|
||||
/* zero down the alignment padding part */
|
||||
memset((char *)bf + ofs + ensure, 0, al - ensure);
|
||||
|
||||
bf->ofs += al;
|
||||
if (bf->ofs >= bf->alloc_size)
|
||||
bf->ofs = bf->alloc_size;
|
||||
|
||||
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)
|
||||
{
|
||||
while (head) {
|
||||
uint8_t *pos = (uint8_t *)&head[1],
|
||||
*end = ((uint8_t *)head) + head->ofs - len;
|
||||
|
||||
if (head->ofs - sizeof(*head) >= len)
|
||||
while (pos < end) {
|
||||
if (*pos == *find && (!nul || !pos[len]) &&
|
||||
pos[len - 1] == find[len - 1] &&
|
||||
!memcmp(pos, find, len))
|
||||
/* found the blob */
|
||||
return pos;
|
||||
pos++;
|
||||
}
|
||||
|
||||
head = head->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
lwsac_total_overhead(struct lwsac *head)
|
||||
{
|
||||
uint64_t overhead = 0;
|
||||
|
||||
while (head) {
|
||||
overhead += (head->alloc_size - head->ofs) + sizeof(*head);
|
||||
|
||||
head = head->next;
|
||||
}
|
||||
|
||||
return overhead;
|
||||
}
|
||||
|
||||
void *
|
||||
lwsac_use_zero(struct lwsac **head, size_t ensure, size_t chunk_size)
|
||||
{
|
||||
void *p = lwsac_use(head, ensure, chunk_size);
|
||||
|
||||
if (p)
|
||||
memset(p, 0, ensure);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
lwsac_free(struct lwsac **head)
|
||||
{
|
||||
struct lwsac *it = *head;
|
||||
|
||||
*head = NULL;
|
||||
// lwsl_debug("%s: head %p\n", __func__, *head);
|
||||
|
||||
while (it) {
|
||||
struct lwsac *tmp = it->next;
|
||||
|
||||
free(it);
|
||||
it = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
lwsac_info(struct lwsac *head)
|
||||
{
|
||||
#if _LWS_ENABLED_LOGS & LLL_DEBUG
|
||||
struct lwsac_head *lachead;
|
||||
|
||||
if (!head) {
|
||||
lwsl_debug("%s: empty\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
lachead = (struct lwsac_head *)&head[1];
|
||||
|
||||
lwsl_debug("%s: lac %p: %dKiB in %d blocks\n", __func__, head,
|
||||
(int)(lachead->total_alloc_size >> 10), lachead->total_blocks);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint64_t
|
||||
lwsac_total_alloc(struct lwsac *head)
|
||||
{
|
||||
struct lwsac_head *lachead;
|
||||
|
||||
if (!head)
|
||||
return 0;
|
||||
|
||||
lachead = (struct lwsac_head *)&head[1];
|
||||
return lachead->total_alloc_size;
|
||||
}
|
||||
|
||||
void
|
||||
lwsac_reference(struct lwsac *head)
|
||||
{
|
||||
struct lwsac_head *lachead = (struct lwsac_head *)&head[1];
|
||||
|
||||
lachead->refcount++;
|
||||
lwsl_debug("%s: head %p: (det %d) refcount -> %d\n",
|
||||
__func__, head, lachead->detached, lachead->refcount);
|
||||
}
|
||||
|
||||
void
|
||||
lwsac_unreference(struct lwsac **head)
|
||||
{
|
||||
struct lwsac_head *lachead;
|
||||
|
||||
if (!(*head))
|
||||
return;
|
||||
|
||||
lachead = (struct lwsac_head *)&(*head)[1];
|
||||
|
||||
if (!lachead->refcount)
|
||||
lwsl_warn("%s: refcount going below zero\n", __func__);
|
||||
|
||||
lachead->refcount--;
|
||||
|
||||
lwsl_debug("%s: head %p: (det %d) refcount -> %d\n",
|
||||
__func__, *head, lachead->detached, lachead->refcount);
|
||||
|
||||
if (lachead->detached && !lachead->refcount) {
|
||||
lwsl_debug("%s: head %p: FREED\n", __func__, *head);
|
||||
lwsac_free(head);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
lwsac_detach(struct lwsac **head)
|
||||
{
|
||||
struct lwsac_head *lachead;
|
||||
|
||||
if (!(*head))
|
||||
return;
|
||||
|
||||
lachead = (struct lwsac_head *)&(*head)[1];
|
||||
|
||||
lachead->detached = 1;
|
||||
if (!lachead->refcount) {
|
||||
lwsl_debug("%s: head %p: FREED\n", __func__, *head);
|
||||
lwsac_free(head);
|
||||
} else
|
||||
lwsl_debug("%s: head %p: refcount %d: Marked as detached\n",
|
||||
__func__, *head, lachead->refcount);
|
||||
}
|
80
Kinc/Sources/kinc/libs/misc/lwsac/lwsac.cxx
Normal file
80
Kinc/Sources/kinc/libs/misc/lwsac/lwsac.cxx
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2020 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*
|
||||
* C++ classes for Secure Streams - atomic heap messages
|
||||
*/
|
||||
|
||||
#include <libwebsockets.hxx>
|
||||
#include "private-lib-misc-lwsac.h"
|
||||
|
||||
void
|
||||
lssAc::start(bool atomic)
|
||||
{
|
||||
if (atomic && ac->next) {
|
||||
struct lwsac *ac2 = NULL, *i;
|
||||
size_t total = (size_t)lwsac_total_alloc(ac);
|
||||
uint8_t *p = (uint8_t *)lwsac_use(&ac2, total, total);
|
||||
|
||||
/*
|
||||
* He wants a single linear buffer, and we have more than one
|
||||
* piece... let's make a new, single one, copy the fragments
|
||||
* in and replace the fragmented one with the unified copy.
|
||||
*/
|
||||
|
||||
i = ac;
|
||||
while (i) {
|
||||
size_t bl = lwsac_get_tail_pos(i) -
|
||||
lwsac_sizeof(i == ac);
|
||||
memcpy(p, (uint8_t *)i + lwsac_sizeof(i == ac), bl);
|
||||
p += bl;
|
||||
}
|
||||
|
||||
lwsac_free(&ac);
|
||||
ac = ac2;
|
||||
}
|
||||
|
||||
iter = ac;
|
||||
}
|
||||
|
||||
int
|
||||
lssAc::get(lssbuf_t *lb)
|
||||
{
|
||||
if (!ac)
|
||||
return 1;
|
||||
|
||||
lb->buf = (uint8_t *)iter + lwsac_sizeof(iter == ac);
|
||||
lb->len = lwsac_get_tail_pos(iter) - lwsac_sizeof(iter == ac);
|
||||
iter = iter->next;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
lssAc::append(lssbuf_t *lb)
|
||||
{
|
||||
uint8_t *p = (uint8_t *)lwsac_use(&ac, lb->len, lb->len);
|
||||
|
||||
if (!p)
|
||||
throw lssException("oom");
|
||||
memcpy(p, lb->buf, lb->len);
|
||||
}
|
70
Kinc/Sources/kinc/libs/misc/lwsac/private-lib-misc-lwsac.h
Normal file
70
Kinc/Sources/kinc/libs/misc/lwsac/private-lib-misc-lwsac.h
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#if !defined(__LWS_PRIVATE_LIB_MISC_LWSAC_H__)
|
||||
#define __LWS_PRIVATE_LIB_MISC_LWSAC_H__
|
||||
|
||||
#if !defined(LWS_PLAT_OPTEE)
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
/* under page size of 4096 to allow overhead */
|
||||
#define LWSAC_CHUNK_SIZE 4000
|
||||
|
||||
/*
|
||||
* the chunk list members all point back to the head themselves so the list
|
||||
* can be detached from the formal head and free itself when its reference
|
||||
* count reaches zero.
|
||||
*/
|
||||
|
||||
/*
|
||||
* One of these per chunk
|
||||
*/
|
||||
|
||||
struct lwsac {
|
||||
struct lwsac *next;
|
||||
struct lwsac *head; /* pointer back to the first chunk */
|
||||
size_t alloc_size; /* alloc size of the whole chunk */
|
||||
size_t ofs; /* next writeable position inside chunk */
|
||||
};
|
||||
|
||||
/*
|
||||
* One of these per lwsac, at start of first chunk
|
||||
*/
|
||||
|
||||
struct lwsac_head {
|
||||
struct lwsac *curr;
|
||||
size_t total_alloc_size;
|
||||
int refcount;
|
||||
int total_blocks;
|
||||
char detached; /* if our refcount gets to zero, free the chunk list */
|
||||
};
|
||||
|
||||
#if !defined(LWS_PLAT_OPTEE)
|
||||
struct cached_file_info {
|
||||
struct stat s;
|
||||
time_t last_confirm;
|
||||
};
|
||||
#endif
|
||||
#endif
|
Reference in New Issue
Block a user