You've already forked pgbackrest
mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2025-07-07 00:35:37 +02:00
Improve memory usage of mem contexts.
Each mem context can track child contexts, allocations, and a callback. Before this change memory was allocated for tracking all three even if they were not used for a particular context. This made mem contexts unsuitable for String and Variant objects since they are plentiful and need to be as small as possible. This change allows mem contexts to be configured to track any combination of child contexts, allocations, and a callback. In addition, the mem context can be configured to track a single child context and/or allocation, which saves memory and is a common use case. Another benefit is that Variants can own objects (e.g. KeyValue) that they encapsulate. All of this makes memory accounting simpler because mem contexts have names while allocations do not. No more memory is used than before since Variants and Strings still had to store the memory context they were originally allocated in so they could be easily freed. Update the String and Variant objects to use this new functionality. The custom strFree() and varFree() functions are no longer required and can now be a wrapper around objFree(). Lastly, this will allow strMove() and varMove() to be implemented and used in cases where strDup() and varDup() are being used to move a String or Variant to a new context. Since this will be a bit noisy it is saved for a future commit.
This commit is contained in:
@ -15,6 +15,20 @@
|
|||||||
|
|
||||||
<release-list>
|
<release-list>
|
||||||
<release date="XXXX-XX-XX" version="2.40dev" title="UNDER DEVELOPMENT">
|
<release date="XXXX-XX-XX" version="2.40dev" title="UNDER DEVELOPMENT">
|
||||||
|
<release-core-list>
|
||||||
|
<release-development-list>
|
||||||
|
<release-item>
|
||||||
|
<github-pull-request id="1749"/>
|
||||||
|
|
||||||
|
<release-item-contributor-list>
|
||||||
|
<release-item-contributor id="david.steele"/>
|
||||||
|
<release-item-reviewer id="reid.thompson"/>
|
||||||
|
</release-item-contributor-list>
|
||||||
|
|
||||||
|
<p>Improve memory usage of mem contexts.</p>
|
||||||
|
</release-item>
|
||||||
|
</release-development-list>
|
||||||
|
</release-core-list>
|
||||||
</release>
|
</release>
|
||||||
|
|
||||||
<release date="2022-05-16" version="2.39" title="Verify and File Bundling">
|
<release date="2022-05-16" version="2.39" title="Verify and File Bundling">
|
||||||
|
@ -47,7 +47,7 @@ yamlNew(const Buffer *const buffer)
|
|||||||
|
|
||||||
Yaml *this = NULL;
|
Yaml *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(Yaml)
|
OBJ_NEW_BEGIN(Yaml, .childQty = MEM_CONTEXT_QTY_MAX, .callbackQty = 1)
|
||||||
{
|
{
|
||||||
// Create object
|
// Create object
|
||||||
this = OBJ_NEW_ALLOC();
|
this = OBJ_NEW_ALLOC();
|
||||||
|
@ -235,7 +235,7 @@ pageChecksumNew(const unsigned int segmentNo, const unsigned int segmentPageTota
|
|||||||
|
|
||||||
IoFilter *this = NULL;
|
IoFilter *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(PageChecksum)
|
OBJ_NEW_BEGIN(PageChecksum, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
PageChecksum *driver = OBJ_NEW_ALLOC();
|
PageChecksum *driver = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ cmdServerInit(void)
|
|||||||
{
|
{
|
||||||
MEM_CONTEXT_BEGIN(memContextTop())
|
MEM_CONTEXT_BEGIN(memContextTop())
|
||||||
{
|
{
|
||||||
MEM_CONTEXT_NEW_BEGIN("Server")
|
MEM_CONTEXT_NEW_BEGIN(Server, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
serverLocal.memContext = MEM_CONTEXT_NEW();
|
serverLocal.memContext = MEM_CONTEXT_NEW();
|
||||||
serverLocal.processList = lstNewP(sizeof(pid_t));
|
serverLocal.processList = lstNewP(sizeof(pid_t));
|
||||||
|
@ -167,7 +167,7 @@ bz2CompressNew(int level)
|
|||||||
|
|
||||||
IoFilter *this = NULL;
|
IoFilter *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(Bz2Compress)
|
OBJ_NEW_BEGIN(Bz2Compress, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX, .callbackQty = 1)
|
||||||
{
|
{
|
||||||
Bz2Compress *driver = OBJ_NEW_ALLOC();
|
Bz2Compress *driver = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -150,7 +150,7 @@ bz2DecompressNew(void)
|
|||||||
|
|
||||||
IoFilter *this = NULL;
|
IoFilter *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(Bz2Decompress)
|
OBJ_NEW_BEGIN(Bz2Decompress, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX, .callbackQty = 1)
|
||||||
{
|
{
|
||||||
// Allocate state and set context
|
// Allocate state and set context
|
||||||
Bz2Decompress *driver = OBJ_NEW_ALLOC();
|
Bz2Decompress *driver = OBJ_NEW_ALLOC();
|
||||||
|
@ -172,7 +172,7 @@ gzCompressNew(int level)
|
|||||||
|
|
||||||
IoFilter *this = NULL;
|
IoFilter *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(GzCompress)
|
OBJ_NEW_BEGIN(GzCompress, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX, .callbackQty = 1)
|
||||||
{
|
{
|
||||||
GzCompress *driver = OBJ_NEW_ALLOC();
|
GzCompress *driver = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -150,7 +150,7 @@ gzDecompressNew(void)
|
|||||||
|
|
||||||
IoFilter *this = NULL;
|
IoFilter *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(GzDecompress)
|
OBJ_NEW_BEGIN(GzDecompress, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX, .callbackQty = 1)
|
||||||
{
|
{
|
||||||
// Allocate state and set context
|
// Allocate state and set context
|
||||||
GzDecompress *driver = OBJ_NEW_ALLOC();
|
GzDecompress *driver = OBJ_NEW_ALLOC();
|
||||||
|
@ -253,7 +253,7 @@ lz4CompressNew(int level)
|
|||||||
|
|
||||||
IoFilter *this = NULL;
|
IoFilter *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(Lz4Compress)
|
OBJ_NEW_BEGIN(Lz4Compress, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX, .callbackQty = 1)
|
||||||
{
|
{
|
||||||
Lz4Compress *driver = OBJ_NEW_ALLOC();
|
Lz4Compress *driver = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -163,7 +163,7 @@ lz4DecompressNew(void)
|
|||||||
|
|
||||||
IoFilter *this = NULL;
|
IoFilter *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(Lz4Decompress)
|
OBJ_NEW_BEGIN(Lz4Decompress, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX, .callbackQty = 1)
|
||||||
{
|
{
|
||||||
Lz4Decompress *driver = OBJ_NEW_ALLOC();
|
Lz4Decompress *driver = OBJ_NEW_ALLOC();
|
||||||
*driver = (Lz4Decompress){0};
|
*driver = (Lz4Decompress){0};
|
||||||
|
@ -174,7 +174,7 @@ zstCompressNew(int level)
|
|||||||
|
|
||||||
IoFilter *this = NULL;
|
IoFilter *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(ZstCompress)
|
OBJ_NEW_BEGIN(ZstCompress, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX, .callbackQty = 1)
|
||||||
{
|
{
|
||||||
ZstCompress *driver = OBJ_NEW_ALLOC();
|
ZstCompress *driver = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -162,7 +162,7 @@ zstDecompressNew(void)
|
|||||||
|
|
||||||
IoFilter *this = NULL;
|
IoFilter *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(ZstDecompress)
|
OBJ_NEW_BEGIN(ZstDecompress, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX, .callbackQty = 1)
|
||||||
{
|
{
|
||||||
ZstDecompress *driver = OBJ_NEW_ALLOC();
|
ZstDecompress *driver = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -421,7 +421,7 @@ cipherBlockNew(CipherMode mode, CipherType cipherType, const Buffer *pass, const
|
|||||||
// Allocate memory to hold process state
|
// Allocate memory to hold process state
|
||||||
IoFilter *this = NULL;
|
IoFilter *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(CipherBlock)
|
OBJ_NEW_BEGIN(CipherBlock, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX, .callbackQty = 1)
|
||||||
{
|
{
|
||||||
CipherBlock *driver = OBJ_NEW_ALLOC();
|
CipherBlock *driver = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -185,7 +185,7 @@ cryptoHashNew(const String *type)
|
|||||||
// Allocate memory to hold process state
|
// Allocate memory to hold process state
|
||||||
IoFilter *this = NULL;
|
IoFilter *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(CryptoHash)
|
OBJ_NEW_BEGIN(CryptoHash, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX, .callbackQty = 1)
|
||||||
{
|
{
|
||||||
CryptoHash *driver = OBJ_NEW_ALLOC();
|
CryptoHash *driver = OBJ_NEW_ALLOC();
|
||||||
*driver = (CryptoHash){0};
|
*driver = (CryptoHash){0};
|
||||||
|
@ -127,7 +127,7 @@ execNew(const String *command, const StringList *param, const String *name, Time
|
|||||||
|
|
||||||
Exec *this = NULL;
|
Exec *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(Exec)
|
OBJ_NEW_BEGIN(Exec, .childQty = MEM_CONTEXT_QTY_MAX, .callbackQty = 1)
|
||||||
{
|
{
|
||||||
this = OBJ_NEW_ALLOC();
|
this = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ iniNew(void)
|
|||||||
|
|
||||||
Ini *this = NULL;
|
Ini *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(Ini)
|
OBJ_NEW_BEGIN(Ini, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
this = OBJ_NEW_ALLOC();
|
this = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -94,7 +94,7 @@ ioBufferReadNew(const Buffer *buffer)
|
|||||||
|
|
||||||
IoRead *this = NULL;
|
IoRead *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(IoBufferRead)
|
OBJ_NEW_BEGIN(IoBufferRead, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
IoBufferRead *driver = OBJ_NEW_ALLOC();
|
IoBufferRead *driver = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ ioBufferWriteNew(Buffer *buffer)
|
|||||||
|
|
||||||
IoWrite *this = NULL;
|
IoWrite *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(IoBufferWrite)
|
OBJ_NEW_BEGIN(IoBufferWrite, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
IoBufferWrite *driver = OBJ_NEW_ALLOC();
|
IoBufferWrite *driver = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -156,7 +156,7 @@ ioFdReadNew(const String *name, int fd, TimeMSec timeout)
|
|||||||
|
|
||||||
IoRead *this = NULL;
|
IoRead *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(IoFdRead)
|
OBJ_NEW_BEGIN(IoFdRead, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
IoFdRead *driver = OBJ_NEW_ALLOC();
|
IoFdRead *driver = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -112,7 +112,7 @@ ioFdWriteNew(const String *name, int fd, TimeMSec timeout)
|
|||||||
|
|
||||||
IoWrite *this = NULL;
|
IoWrite *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(IoFdWrite)
|
OBJ_NEW_BEGIN(IoFdWrite, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
IoFdWrite *driver = OBJ_NEW_ALLOC();
|
IoFdWrite *driver = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -110,7 +110,7 @@ ioBufferNew(void)
|
|||||||
|
|
||||||
IoFilter *this = NULL;
|
IoFilter *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(IoBuffer)
|
OBJ_NEW_BEGIN(IoBuffer, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
IoBuffer *driver = OBJ_NEW_ALLOC();
|
IoBuffer *driver = OBJ_NEW_ALLOC();
|
||||||
*driver = (IoBuffer){0};
|
*driver = (IoBuffer){0};
|
||||||
|
@ -63,7 +63,7 @@ ioFilterGroupNew(void)
|
|||||||
|
|
||||||
IoFilterGroup *this = NULL;
|
IoFilterGroup *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(IoFilterGroup)
|
OBJ_NEW_BEGIN(IoFilterGroup, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
this = OBJ_NEW_ALLOC();
|
this = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ ioSinkNew(void)
|
|||||||
|
|
||||||
IoFilter *this = NULL;
|
IoFilter *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(IoSink)
|
OBJ_NEW_BEGIN(IoSink, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
IoSink *driver = OBJ_NEW_ALLOC();
|
IoSink *driver = OBJ_NEW_ALLOC();
|
||||||
this = ioFilterNewP(SINK_FILTER_TYPE, driver, NULL, .inOut = ioSinkProcess);
|
this = ioFilterNewP(SINK_FILTER_TYPE, driver, NULL, .inOut = ioSinkProcess);
|
||||||
|
@ -93,7 +93,7 @@ ioSizeNew(void)
|
|||||||
|
|
||||||
IoFilter *this = NULL;
|
IoFilter *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(IoSize)
|
OBJ_NEW_BEGIN(IoSize, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
IoSize *driver = OBJ_NEW_ALLOC();
|
IoSize *driver = OBJ_NEW_ALLOC();
|
||||||
*driver = (IoSize){0};
|
*driver = (IoSize){0};
|
||||||
|
@ -43,7 +43,7 @@ httpClientNew(IoClient *ioClient, TimeMSec timeout)
|
|||||||
|
|
||||||
HttpClient *this = NULL;
|
HttpClient *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(HttpClient)
|
OBJ_NEW_BEGIN(HttpClient, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
this = OBJ_NEW_ALLOC();
|
this = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ httpHeaderNew(const StringList *redactList)
|
|||||||
|
|
||||||
HttpHeader *this = NULL;
|
HttpHeader *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(HttpHeader)
|
OBJ_NEW_BEGIN(HttpHeader, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
// Allocate state and set context
|
// Allocate state and set context
|
||||||
this = OBJ_NEW_ALLOC();
|
this = OBJ_NEW_ALLOC();
|
||||||
@ -54,7 +54,7 @@ httpHeaderDup(const HttpHeader *header, const StringList *redactList)
|
|||||||
|
|
||||||
if (header != NULL)
|
if (header != NULL)
|
||||||
{
|
{
|
||||||
OBJ_NEW_BEGIN(HttpHeader)
|
OBJ_NEW_BEGIN(HttpHeader, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
// Allocate state and set context
|
// Allocate state and set context
|
||||||
this = OBJ_NEW_ALLOC();
|
this = OBJ_NEW_ALLOC();
|
||||||
|
@ -27,7 +27,7 @@ httpQueryNew(HttpQueryNewParam param)
|
|||||||
|
|
||||||
HttpQuery *this = NULL;
|
HttpQuery *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(HttpQuery)
|
OBJ_NEW_BEGIN(HttpQuery, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
// Allocate state and set context
|
// Allocate state and set context
|
||||||
this = OBJ_NEW_ALLOC();
|
this = OBJ_NEW_ALLOC();
|
||||||
@ -55,7 +55,7 @@ httpQueryNewStr(const String *query)
|
|||||||
|
|
||||||
HttpQuery *this = NULL;
|
HttpQuery *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(HttpQuery)
|
OBJ_NEW_BEGIN(HttpQuery, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
this = OBJ_NEW_ALLOC();
|
this = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
@ -108,7 +108,7 @@ httpQueryDup(const HttpQuery *query, HttpQueryDupParam param)
|
|||||||
|
|
||||||
if (query != NULL)
|
if (query != NULL)
|
||||||
{
|
{
|
||||||
OBJ_NEW_BEGIN(HttpQuery)
|
OBJ_NEW_BEGIN(HttpQuery, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
// Allocate state and set context
|
// Allocate state and set context
|
||||||
this = OBJ_NEW_ALLOC();
|
this = OBJ_NEW_ALLOC();
|
||||||
|
@ -192,7 +192,7 @@ httpRequestNew(HttpClient *client, const String *verb, const String *path, HttpR
|
|||||||
|
|
||||||
HttpRequest *this = NULL;
|
HttpRequest *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(HttpRequest)
|
OBJ_NEW_BEGIN(HttpRequest, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
this = OBJ_NEW_ALLOC();
|
this = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -220,7 +220,7 @@ httpResponseNew(HttpSession *session, const String *verb, bool contentCache)
|
|||||||
|
|
||||||
HttpResponse *this = NULL;
|
HttpResponse *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(HttpResponse)
|
OBJ_NEW_BEGIN(HttpResponse, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
this = OBJ_NEW_ALLOC();
|
this = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ httpSessionNew(HttpClient *httpClient, IoSession *ioSession)
|
|||||||
|
|
||||||
HttpSession *this = NULL;
|
HttpSession *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(HttpSession)
|
OBJ_NEW_BEGIN(HttpSession, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
this = OBJ_NEW_ALLOC();
|
this = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ httpUrlNewParse(const String *const url, HttpUrlNewParseParam param)
|
|||||||
|
|
||||||
HttpUrl *this = NULL;
|
HttpUrl *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(HttpUrl)
|
OBJ_NEW_BEGIN(HttpUrl, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
// Allocate state and set context
|
// Allocate state and set context
|
||||||
this = OBJ_NEW_ALLOC();
|
this = OBJ_NEW_ALLOC();
|
||||||
|
@ -35,7 +35,7 @@ ioReadNew(void *driver, IoReadInterface interface)
|
|||||||
|
|
||||||
IoRead *this = NULL;
|
IoRead *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(IoRead)
|
OBJ_NEW_BEGIN(IoRead, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
this = OBJ_NEW_ALLOC();
|
this = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -172,7 +172,7 @@ sckClientNew(const String *const host, const unsigned int port, const TimeMSec t
|
|||||||
|
|
||||||
IoClient *this = NULL;
|
IoClient *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(SocketClient)
|
OBJ_NEW_BEGIN(SocketClient, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
SocketClient *driver = OBJ_NEW_ALLOC();
|
SocketClient *driver = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -155,7 +155,7 @@ sckServerNew(const String *const address, const unsigned int port, const TimeMSe
|
|||||||
|
|
||||||
IoServer *this = NULL;
|
IoServer *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(SocketServer)
|
OBJ_NEW_BEGIN(SocketServer, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX, .callbackQty = 1)
|
||||||
{
|
{
|
||||||
SocketServer *const driver = OBJ_NEW_ALLOC();
|
SocketServer *const driver = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -178,7 +178,7 @@ sckSessionNew(IoSessionRole role, int fd, const String *host, unsigned int port,
|
|||||||
|
|
||||||
IoSession *this = NULL;
|
IoSession *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(SocketSession)
|
OBJ_NEW_BEGIN(SocketSession, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX, .callbackQty = 1)
|
||||||
{
|
{
|
||||||
SocketSession *driver = OBJ_NEW_ALLOC();
|
SocketSession *driver = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -365,7 +365,7 @@ tlsClientNew(
|
|||||||
|
|
||||||
IoClient *this = NULL;
|
IoClient *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(TlsClient)
|
OBJ_NEW_BEGIN(TlsClient, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX, .callbackQty = 1)
|
||||||
{
|
{
|
||||||
TlsClient *driver = OBJ_NEW_ALLOC();
|
TlsClient *driver = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -282,7 +282,7 @@ tlsServerNew(
|
|||||||
|
|
||||||
IoServer *this = NULL;
|
IoServer *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(TlsServer)
|
OBJ_NEW_BEGIN(TlsServer, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX, .callbackQty = 1)
|
||||||
{
|
{
|
||||||
TlsServer *const driver = OBJ_NEW_ALLOC();
|
TlsServer *const driver = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -371,7 +371,7 @@ tlsSessionNew(SSL *session, IoSession *ioSession, TimeMSec timeout)
|
|||||||
|
|
||||||
IoSession *this = NULL;
|
IoSession *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(TlsSession)
|
OBJ_NEW_BEGIN(TlsSession, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX, .callbackQty = 1)
|
||||||
{
|
{
|
||||||
TlsSession *driver = OBJ_NEW_ALLOC();
|
TlsSession *driver = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ ioWriteNew(void *driver, IoWriteInterface interface)
|
|||||||
|
|
||||||
IoWrite *this = NULL;
|
IoWrite *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(IoWrite)
|
OBJ_NEW_BEGIN(IoWrite, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
this = OBJ_NEW_ALLOC();
|
this = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -415,7 +415,7 @@ lockAcquire(
|
|||||||
{
|
{
|
||||||
MEM_CONTEXT_BEGIN(memContextTop())
|
MEM_CONTEXT_BEGIN(memContextTop())
|
||||||
{
|
{
|
||||||
MEM_CONTEXT_NEW_BEGIN("Lock")
|
MEM_CONTEXT_NEW_BEGIN(Lock, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
lockLocal.memContext = MEM_CONTEXT_NEW();
|
lockLocal.memContext = MEM_CONTEXT_NEW();
|
||||||
lockLocal.execId = strDup(execId);
|
lockLocal.execId = strDup(execId);
|
||||||
|
@ -8,6 +8,7 @@ Memory Context Manager
|
|||||||
|
|
||||||
#include "common/debug.h"
|
#include "common/debug.h"
|
||||||
#include "common/error.h"
|
#include "common/error.h"
|
||||||
|
#include "common/macro.h"
|
||||||
#include "common/memContext.h"
|
#include "common/memContext.h"
|
||||||
|
|
||||||
/***********************************************************************************************************************************
|
/***********************************************************************************************************************************
|
||||||
@ -27,52 +28,180 @@ typedef struct MemContextAlloc
|
|||||||
// Get the allocation header pointer given the allocation buffer pointer
|
// Get the allocation header pointer given the allocation buffer pointer
|
||||||
#define MEM_CONTEXT_ALLOC_HEADER(buffer) ((MemContextAlloc *)buffer - 1)
|
#define MEM_CONTEXT_ALLOC_HEADER(buffer) ((MemContextAlloc *)buffer - 1)
|
||||||
|
|
||||||
// Make sure the allocation is valid for the current memory context. This check only works correctly if the allocation is valid but
|
// Make sure the allocation is valid for the current memory context. This check only works correctly if the allocation is valid and
|
||||||
// belongs to another context. Otherwise, there is likely to be a segfault.
|
// allocated as one of many but belongs to another context. Otherwise, there is likely to be a segfault.
|
||||||
#define ASSERT_ALLOC_VALID(alloc) \
|
#define ASSERT_ALLOC_MANY_VALID(alloc) \
|
||||||
ASSERT( \
|
ASSERT( \
|
||||||
alloc != NULL && (uintptr_t)alloc != (uintptr_t)-sizeof(MemContextAlloc) && \
|
alloc != NULL && (uintptr_t)alloc != (uintptr_t)-sizeof(MemContextAlloc) && \
|
||||||
alloc->allocIdx < memContextStack[memContextCurrentStackIdx].memContext->allocListSize && \
|
alloc->allocIdx < memContextAllocMany(memContextStack[memContextCurrentStackIdx].memContext)->listSize && \
|
||||||
memContextStack[memContextCurrentStackIdx].memContext->allocList[alloc->allocIdx]);
|
memContextAllocMany(memContextStack[memContextCurrentStackIdx].memContext)->list[alloc->allocIdx]);
|
||||||
|
|
||||||
/***********************************************************************************************************************************
|
/***********************************************************************************************************************************
|
||||||
Contains information about the memory context
|
Contains information about the memory context
|
||||||
***********************************************************************************************************************************/
|
***********************************************************************************************************************************/
|
||||||
|
// Quantity of child contexts, allocations, or callbacks
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
memQtyNone = 0, // None for this type
|
||||||
|
memQtyOne = 1, // One for this type
|
||||||
|
memQtyMany = 2, // Many for this type
|
||||||
|
} MemQty;
|
||||||
|
|
||||||
|
// Main structure required by every mem context
|
||||||
struct MemContext
|
struct MemContext
|
||||||
{
|
{
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
const char *name; // Indicates what the context is being used for
|
const char *name; // Indicates what the context is being used for
|
||||||
bool active:1; // Is the context currently active?
|
bool active:1; // Is the context currently active?
|
||||||
#endif
|
#endif
|
||||||
|
MemQty childQty:2; // How many child contexts can this context have?
|
||||||
|
bool childInitialized:1; // Has the child context list been initialized?
|
||||||
|
MemQty allocQty:2; // How many allocations can this context have?
|
||||||
|
bool allocInitialized:1; // Has the allocation list been initialized?
|
||||||
|
MemQty callbackQty:2; // How many callbacks can this context have?
|
||||||
|
bool callbackInitialized:1; // Has the callback been initialized?
|
||||||
size_t allocExtra:16; // Size of extra allocation (1kB max)
|
size_t allocExtra:16; // Size of extra allocation (1kB max)
|
||||||
|
|
||||||
unsigned int contextParentIdx; // Index in the parent context list
|
unsigned int contextParentIdx; // Index in the parent context list
|
||||||
MemContext *contextParent; // All contexts have a parent except top
|
MemContext *contextParent; // All contexts have a parent except top
|
||||||
|
|
||||||
MemContext **contextChildList; // List of contexts created in this context
|
|
||||||
unsigned int contextChildListSize; // Size of child context list (not the actual count of contexts)
|
|
||||||
unsigned int contextChildFreeIdx; // Index of first free space in the context list
|
|
||||||
|
|
||||||
MemContextAlloc **allocList; // List of memory allocations created in this context
|
|
||||||
unsigned int allocListSize; // Size of alloc list (not the actual count of allocations)
|
|
||||||
unsigned int allocFreeIdx; // Index of first free space in the alloc list
|
|
||||||
|
|
||||||
void (*callbackFunction)(void *); // Function to call before the context is freed
|
|
||||||
void *callbackArgument; // Argument to pass to callback function
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Mem context with one allocation
|
||||||
|
typedef struct MemContextAllocOne
|
||||||
|
{
|
||||||
|
MemContextAlloc *alloc; // Memory allocation created in this context
|
||||||
|
} MemContextAllocOne;
|
||||||
|
|
||||||
|
// Mem context with many allocations
|
||||||
|
typedef struct MemContextAllocMany
|
||||||
|
{
|
||||||
|
MemContextAlloc **list; // List of memory allocations created in this context
|
||||||
|
unsigned int listSize; // Size of alloc list (not the actual count of allocations)
|
||||||
|
unsigned int freeIdx; // Index of first free space in the alloc list
|
||||||
|
} MemContextAllocMany;
|
||||||
|
|
||||||
|
// Mem context with one child context
|
||||||
|
typedef struct MemContextChildOne
|
||||||
|
{
|
||||||
|
MemContext *context; // Context created in this context
|
||||||
|
} MemContextChildOne;
|
||||||
|
|
||||||
|
// Mem context with many child contexts
|
||||||
|
typedef struct MemContextChildMany
|
||||||
|
{
|
||||||
|
MemContext **list; // List of contexts created in this context
|
||||||
|
unsigned int listSize; // Size of child context list (not the actual count of contexts)
|
||||||
|
unsigned int freeIdx; // Index of first free space in the context list
|
||||||
|
} MemContextChildMany;
|
||||||
|
|
||||||
|
// Mem context with one callback
|
||||||
|
typedef struct MemContextCallbackOne
|
||||||
|
{
|
||||||
|
void (*function)(void *); // Function to call before the context is freed
|
||||||
|
void *argument; // Argument to pass to callback function
|
||||||
|
} MemContextCallbackOne;
|
||||||
|
|
||||||
|
/***********************************************************************************************************************************
|
||||||
|
Possible sizes for the manifest based on options. Formatting has been compressed to save space.
|
||||||
|
***********************************************************************************************************************************/
|
||||||
|
static const uint8_t memContextSizePossible[memQtyMany + 1][memQtyMany + 1][memQtyOne + 1] =
|
||||||
|
{
|
||||||
|
// child none
|
||||||
|
{// alloc none
|
||||||
|
{/* callback none */ 0, /* callback one */ sizeof(MemContextCallbackOne)},
|
||||||
|
// alloc one
|
||||||
|
{/* callback none */ sizeof(MemContextAllocOne),
|
||||||
|
/* callback one */ sizeof(MemContextAllocOne) + sizeof(MemContextCallbackOne)},
|
||||||
|
// alloc many
|
||||||
|
{/* callback none */ sizeof(MemContextAllocMany),
|
||||||
|
/* callback one */ sizeof(MemContextAllocMany) + sizeof(MemContextCallbackOne)}},
|
||||||
|
// child one
|
||||||
|
{// alloc none
|
||||||
|
{/* callback none */ sizeof(MemContextChildOne),
|
||||||
|
/* callback one */ sizeof(MemContextChildOne) + sizeof(MemContextCallbackOne)},
|
||||||
|
// alloc one
|
||||||
|
{/* callback none */ sizeof(MemContextChildOne) + sizeof(MemContextAllocOne),
|
||||||
|
/* callback one */ sizeof(MemContextChildOne) + sizeof(MemContextAllocOne) + sizeof(MemContextCallbackOne)},
|
||||||
|
// alloc many
|
||||||
|
{/* callback none */ sizeof(MemContextChildOne) + sizeof(MemContextAllocMany),
|
||||||
|
/* callback one */ sizeof(MemContextChildOne) + sizeof(MemContextAllocMany) + sizeof(MemContextCallbackOne)}},
|
||||||
|
// child many
|
||||||
|
{// alloc none
|
||||||
|
{/* callback none */ sizeof(MemContextChildMany),
|
||||||
|
/* callback one */ sizeof(MemContextChildMany) + sizeof(MemContextCallbackOne)},
|
||||||
|
// alloc one
|
||||||
|
{/* callback none */ sizeof(MemContextChildMany) + sizeof(MemContextAllocOne),
|
||||||
|
/* callback one */ sizeof(MemContextChildMany) + sizeof(MemContextAllocOne) + sizeof(MemContextCallbackOne)},
|
||||||
|
// alloc many
|
||||||
|
{/* callback none */ sizeof(MemContextChildMany) + sizeof(MemContextAllocMany),
|
||||||
|
/* callback one */ sizeof(MemContextChildMany) + sizeof(MemContextAllocMany) + sizeof(MemContextCallbackOne)}},
|
||||||
|
};
|
||||||
|
|
||||||
|
/***********************************************************************************************************************************
|
||||||
|
Get pointers to optional parts of the manifest
|
||||||
|
***********************************************************************************************************************************/
|
||||||
|
// Get pointer to child part
|
||||||
|
#define MEM_CONTEXT_CHILD_OFFSET(memContext) ((unsigned char *)(memContext + 1) + memContext->allocExtra)
|
||||||
|
|
||||||
|
static MemContextChildOne *
|
||||||
|
memContextChildOne(MemContext *const memContext)
|
||||||
|
{
|
||||||
|
return (MemContextChildOne *)MEM_CONTEXT_CHILD_OFFSET(memContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
static MemContextChildMany *
|
||||||
|
memContextChildMany(MemContext *const memContext)
|
||||||
|
{
|
||||||
|
return (MemContextChildMany *)MEM_CONTEXT_CHILD_OFFSET(memContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get pointer to allocation part
|
||||||
|
#define MEM_CONTEXT_ALLOC_OFFSET(memContext) \
|
||||||
|
((unsigned char *)(memContext + 1) + memContextSizePossible[memContext->childQty][0][0] + memContext->allocExtra)
|
||||||
|
|
||||||
|
static MemContextAllocOne *
|
||||||
|
memContextAllocOne(MemContext *const memContext)
|
||||||
|
{
|
||||||
|
return (MemContextAllocOne *)MEM_CONTEXT_ALLOC_OFFSET(memContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
static MemContextAllocMany *
|
||||||
|
memContextAllocMany(MemContext *const memContext)
|
||||||
|
{
|
||||||
|
return (MemContextAllocMany *)MEM_CONTEXT_ALLOC_OFFSET(memContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get pointer to callback part
|
||||||
|
static MemContextCallbackOne *
|
||||||
|
memContextCallbackOne(MemContext *const memContext)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
(MemContextCallbackOne *)((unsigned char *)(memContext + 1) +
|
||||||
|
memContextSizePossible[memContext->childQty][memContext->allocQty][0] + memContext->allocExtra);
|
||||||
|
}
|
||||||
|
|
||||||
/***********************************************************************************************************************************
|
/***********************************************************************************************************************************
|
||||||
Top context
|
Top context
|
||||||
|
|
||||||
The top context always exists and can never be freed. All other contexts are children of the top context. The top context is
|
The top context always exists and can never be freed. All other contexts are children of the top context. The top context is
|
||||||
generally used to allocate memory that exists for the life of the program.
|
generally used to allocate memory that exists for the life of the program.
|
||||||
***********************************************************************************************************************************/
|
***********************************************************************************************************************************/
|
||||||
static MemContext contextTop =
|
static struct MemContextTop
|
||||||
{
|
{
|
||||||
|
MemContext memContext;
|
||||||
|
MemContextChildMany memContextChildMany;
|
||||||
|
MemContextAllocMany memContextAllocMany;
|
||||||
|
} contextTop =
|
||||||
|
{
|
||||||
|
.memContext =
|
||||||
|
{
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
.name = "TOP",
|
.name = "TOP",
|
||||||
.active = true,
|
.active = true,
|
||||||
#endif
|
#endif
|
||||||
|
.childQty = memQtyMany,
|
||||||
|
.allocQty = memQtyMany,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
/***********************************************************************************************************************************
|
/***********************************************************************************************************************************
|
||||||
@ -94,7 +223,7 @@ static struct MemContextStack
|
|||||||
MemContext *memContext;
|
MemContext *memContext;
|
||||||
MemContextStackType type;
|
MemContextStackType type;
|
||||||
unsigned int tryDepth;
|
unsigned int tryDepth;
|
||||||
} memContextStack[MEM_CONTEXT_STACK_MAX] = {{.memContext = &contextTop}};
|
} memContextStack[MEM_CONTEXT_STACK_MAX] = {{.memContext = (MemContext *)&contextTop}};
|
||||||
|
|
||||||
static unsigned int memContextCurrentStackIdx = 0;
|
static unsigned int memContextCurrentStackIdx = 0;
|
||||||
static unsigned int memContextMaxStackIdx = 0;
|
static unsigned int memContextMaxStackIdx = 0;
|
||||||
@ -209,49 +338,51 @@ memFreeInternal(void *buffer)
|
|||||||
Find space for a new mem context
|
Find space for a new mem context
|
||||||
***********************************************************************************************************************************/
|
***********************************************************************************************************************************/
|
||||||
static unsigned int
|
static unsigned int
|
||||||
memContextNewIndex(MemContext *memContext)
|
memContextNewIndex(MemContext *const memContext, MemContextChildMany *const memContextChild)
|
||||||
{
|
{
|
||||||
FUNCTION_TEST_BEGIN();
|
FUNCTION_TEST_BEGIN();
|
||||||
FUNCTION_TEST_PARAM(MEM_CONTEXT, memContext);
|
FUNCTION_TEST_PARAM(MEM_CONTEXT, memContext);
|
||||||
|
FUNCTION_TEST_PARAM_P(VOID, memContextChild);
|
||||||
FUNCTION_TEST_END();
|
FUNCTION_TEST_END();
|
||||||
|
|
||||||
ASSERT(memContext != NULL);
|
ASSERT(memContext != NULL);
|
||||||
|
ASSERT(memContextChild != NULL);
|
||||||
|
|
||||||
// Try to find space for the new context
|
// Initialize (free space will always be index 0)
|
||||||
for (; memContext->contextChildFreeIdx < memContext->contextChildListSize; memContext->contextChildFreeIdx++)
|
if (!memContext->childInitialized)
|
||||||
{
|
{
|
||||||
if (memContext->contextChildList[memContext->contextChildFreeIdx] == NULL)
|
*memContextChild = (MemContextChildMany)
|
||||||
|
{
|
||||||
|
.list = memAllocPtrArrayInternal(MEM_CONTEXT_INITIAL_SIZE),
|
||||||
|
.listSize = MEM_CONTEXT_INITIAL_SIZE,
|
||||||
|
};
|
||||||
|
|
||||||
|
memContext->childInitialized = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Try to find space for the new context
|
||||||
|
for (; memContextChild->freeIdx < memContextChild->listSize; memContextChild->freeIdx++)
|
||||||
|
{
|
||||||
|
if (memContextChild->list[memContextChild->freeIdx] == NULL)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If no space was found then allocate more
|
// If no space was found then allocate more
|
||||||
if (memContext->contextChildFreeIdx == memContext->contextChildListSize)
|
if (memContextChild->freeIdx == memContextChild->listSize)
|
||||||
{
|
|
||||||
// If no space has been allocated to the list
|
|
||||||
if (memContext->contextChildListSize == 0)
|
|
||||||
{
|
|
||||||
// Allocate memory before modifying anything else in case there is an error
|
|
||||||
memContext->contextChildList = memAllocPtrArrayInternal(MEM_CONTEXT_INITIAL_SIZE);
|
|
||||||
|
|
||||||
// Set new list size
|
|
||||||
memContext->contextChildListSize = MEM_CONTEXT_INITIAL_SIZE;
|
|
||||||
}
|
|
||||||
// Else grow the list
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
// Calculate new list size
|
// Calculate new list size
|
||||||
unsigned int contextChildListSizeNew = memContext->contextChildListSize * 2;
|
const unsigned int listSizeNew = memContextChild->listSize * 2;
|
||||||
|
|
||||||
// ReAllocate memory before modifying anything else in case there is an error
|
// ReAllocate memory before modifying anything else in case there is an error
|
||||||
memContext->contextChildList = memReAllocPtrArrayInternal(
|
memContextChild->list = memReAllocPtrArrayInternal(memContextChild->list, memContextChild->listSize, listSizeNew);
|
||||||
memContext->contextChildList, memContext->contextChildListSize, contextChildListSizeNew);
|
|
||||||
|
|
||||||
// Set new list size
|
// Set new list size
|
||||||
memContext->contextChildListSize = contextChildListSizeNew;
|
memContextChild->listSize = listSizeNew;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FUNCTION_TEST_RETURN(UINT, memContext->contextChildFreeIdx);
|
FUNCTION_TEST_RETURN(UINT, memContextChild->freeIdx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**********************************************************************************************************************************/
|
/**********************************************************************************************************************************/
|
||||||
@ -264,22 +395,36 @@ memContextNew(
|
|||||||
{
|
{
|
||||||
FUNCTION_TEST_BEGIN();
|
FUNCTION_TEST_BEGIN();
|
||||||
FUNCTION_TEST_PARAM(STRINGZ, name);
|
FUNCTION_TEST_PARAM(STRINGZ, name);
|
||||||
|
FUNCTION_TEST_PARAM(UINT, param.childQty);
|
||||||
|
FUNCTION_TEST_PARAM(UINT, param.allocQty);
|
||||||
|
FUNCTION_TEST_PARAM(UINT, param.callbackQty);
|
||||||
FUNCTION_TEST_PARAM(SIZE, param.allocExtra);
|
FUNCTION_TEST_PARAM(SIZE, param.allocExtra);
|
||||||
FUNCTION_TEST_END();
|
FUNCTION_TEST_END();
|
||||||
|
|
||||||
ASSERT(name != NULL);
|
ASSERT(name != NULL);
|
||||||
|
ASSERT(param.childQty <= 1 || param.childQty == UINT8_MAX);
|
||||||
|
ASSERT(param.allocQty <= 1 || param.allocQty == UINT8_MAX);
|
||||||
|
ASSERT(param.callbackQty <= 1);
|
||||||
// Check context name length
|
// Check context name length
|
||||||
ASSERT(name[0] != '\0');
|
ASSERT(name[0] != '\0');
|
||||||
|
|
||||||
// Find space for the new context
|
// Pad allocExtra so that optional structures will be aligned. There may not be any optional structures but it doesn't seem
|
||||||
MemContext *contextCurrent = memContextStack[memContextCurrentStackIdx].memContext;
|
// worth the cost of checking since memory allocations are aligned so the extra bytes would be wasted anyway.
|
||||||
unsigned int contextIdx = memContextNewIndex(contextCurrent);
|
size_t allocExtra = param.allocExtra;
|
||||||
|
|
||||||
// Allocate memory for the context
|
if (allocExtra % ALIGN_OF(void *) != 0)
|
||||||
contextCurrent->contextChildList[contextIdx] = memAllocInternal(sizeof(MemContext) + param.allocExtra);
|
allocExtra += ALIGN_OFFSET(void *, allocExtra);
|
||||||
|
|
||||||
// Get the context
|
// Create the new context
|
||||||
MemContext *this = contextCurrent->contextChildList[contextIdx];
|
MemContext *const contextCurrent = memContextStack[memContextCurrentStackIdx].memContext;
|
||||||
|
ASSERT(contextCurrent->childQty != memQtyNone);
|
||||||
|
|
||||||
|
const MemQty childQty = param.childQty > 1 ? memQtyMany : (MemQty)param.childQty;
|
||||||
|
const MemQty allocQty = param.allocQty > 1 ? memQtyMany : (MemQty)param.allocQty;
|
||||||
|
const MemQty callbackQty = (MemQty)param.callbackQty;
|
||||||
|
|
||||||
|
MemContext *const this = memAllocInternal(
|
||||||
|
sizeof(MemContext) + allocExtra + memContextSizePossible[childQty][allocQty][callbackQty]);
|
||||||
|
|
||||||
*this = (MemContext)
|
*this = (MemContext)
|
||||||
{
|
{
|
||||||
@ -290,16 +435,37 @@ memContextNew(
|
|||||||
// Set new context active
|
// Set new context active
|
||||||
.active = true,
|
.active = true,
|
||||||
#endif
|
#endif
|
||||||
|
// Set flags
|
||||||
|
.childQty = childQty,
|
||||||
|
.allocQty = allocQty,
|
||||||
|
.callbackQty = callbackQty,
|
||||||
|
|
||||||
// Set extra allocation
|
// Set extra allocation
|
||||||
.allocExtra = param.allocExtra,
|
.allocExtra = (uint16_t)allocExtra,
|
||||||
|
|
||||||
// Set current context as the parent
|
// Set current context as the parent
|
||||||
.contextParent = contextCurrent,
|
.contextParent = contextCurrent,
|
||||||
.contextParentIdx = contextIdx,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Find space for the new context
|
||||||
|
if (contextCurrent->childQty == memQtyOne)
|
||||||
|
{
|
||||||
|
ASSERT(!contextCurrent->childInitialized || memContextChildOne(contextCurrent)->context == NULL);
|
||||||
|
|
||||||
|
memContextChildOne(contextCurrent)->context = this;
|
||||||
|
contextCurrent->childInitialized = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ASSERT(contextCurrent->childQty == memQtyMany);
|
||||||
|
MemContextChildMany *const memContextChild = memContextChildMany(contextCurrent);
|
||||||
|
|
||||||
|
this->contextParentIdx = memContextNewIndex(contextCurrent, memContextChild);
|
||||||
|
memContextChild->list[this->contextParentIdx] = this;
|
||||||
|
|
||||||
// Possible free context must be in the next position
|
// Possible free context must be in the next position
|
||||||
contextCurrent->contextChildFreeIdx++;
|
memContextChild->freeIdx++;
|
||||||
|
}
|
||||||
|
|
||||||
// Add to the mem context stack so it will be automatically freed on error if memContextKeep() has not been called
|
// Add to the mem context stack so it will be automatically freed on error if memContextKeep() has not been called
|
||||||
memContextMaxStackIdx++;
|
memContextMaxStackIdx++;
|
||||||
@ -369,20 +535,18 @@ memContextCallbackSet(MemContext *this, void (*callbackFunction)(void *), void *
|
|||||||
ASSERT(this != NULL);
|
ASSERT(this != NULL);
|
||||||
ASSERT(this->active);
|
ASSERT(this->active);
|
||||||
ASSERT(callbackFunction != NULL);
|
ASSERT(callbackFunction != NULL);
|
||||||
|
ASSERT(this->active);
|
||||||
// Top context cannot have a callback
|
ASSERT(this->callbackQty != memQtyNone);
|
||||||
if (this == &contextTop)
|
|
||||||
THROW(AssertError, "top context may not have a callback");
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
// Error if callback has already been set - there may be valid use cases for this but error until one is found
|
// Error if callback has already been set - there may be valid use cases for this in the future but error until one is found
|
||||||
if (this->callbackFunction)
|
if (this->callbackInitialized)
|
||||||
THROW_FMT(AssertError, "callback is already set for context '%s'", this->name);
|
THROW_FMT(AssertError, "callback is already set for context '%s'", this->name);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Set callback function and argument
|
// Set callback function and argument
|
||||||
this->callbackFunction = callbackFunction;
|
*(memContextCallbackOne(this)) = (MemContextCallbackOne){.function = callbackFunction, .argument = callbackArgument};
|
||||||
this->callbackArgument = callbackArgument;
|
this->callbackInitialized = true;
|
||||||
|
|
||||||
FUNCTION_TEST_RETURN_VOID();
|
FUNCTION_TEST_RETURN_VOID();
|
||||||
}
|
}
|
||||||
@ -396,13 +560,12 @@ memContextCallbackClear(MemContext *this)
|
|||||||
FUNCTION_TEST_END();
|
FUNCTION_TEST_END();
|
||||||
|
|
||||||
ASSERT(this != NULL);
|
ASSERT(this != NULL);
|
||||||
|
ASSERT(this->callbackQty != memQtyNone);
|
||||||
// Top context cannot have a callback
|
ASSERT(this->active);
|
||||||
ASSERT(this != &contextTop);
|
|
||||||
|
|
||||||
// Clear callback function and argument
|
// Clear callback function and argument
|
||||||
this->callbackFunction = NULL;
|
*(memContextCallbackOne(this)) = (MemContextCallbackOne){0};
|
||||||
this->callbackArgument = NULL;
|
this->callbackInitialized = false;
|
||||||
|
|
||||||
FUNCTION_TEST_RETURN_VOID();
|
FUNCTION_TEST_RETURN_VOID();
|
||||||
}
|
}
|
||||||
@ -411,60 +574,77 @@ memContextCallbackClear(MemContext *this)
|
|||||||
Find an available slot in the memory context's allocation list and allocate memory
|
Find an available slot in the memory context's allocation list and allocate memory
|
||||||
***********************************************************************************************************************************/
|
***********************************************************************************************************************************/
|
||||||
static MemContextAlloc *
|
static MemContextAlloc *
|
||||||
memContextAllocNew(size_t size)
|
memContextAllocNew(const size_t size)
|
||||||
{
|
{
|
||||||
FUNCTION_TEST_BEGIN();
|
FUNCTION_TEST_BEGIN();
|
||||||
FUNCTION_TEST_PARAM(SIZE, size);
|
FUNCTION_TEST_PARAM(SIZE, size);
|
||||||
FUNCTION_TEST_END();
|
FUNCTION_TEST_END();
|
||||||
|
|
||||||
// Find space for the new allocation
|
// Allocate memory
|
||||||
MemContext *contextCurrent = memContextStack[memContextCurrentStackIdx].memContext;
|
MemContextAlloc *const result = memAllocInternal(sizeof(MemContextAlloc) + size);
|
||||||
|
|
||||||
for (; contextCurrent->allocFreeIdx < contextCurrent->allocListSize; contextCurrent->allocFreeIdx++)
|
// Find space for the new allocation
|
||||||
if (contextCurrent->allocList[contextCurrent->allocFreeIdx] == NULL)
|
MemContext *const contextCurrent = memContextStack[memContextCurrentStackIdx].memContext;
|
||||||
|
ASSERT(contextCurrent->allocQty != memQtyNone);
|
||||||
|
|
||||||
|
if (contextCurrent->allocQty == memQtyOne)
|
||||||
|
{
|
||||||
|
MemContextAllocOne *const contextAlloc = memContextAllocOne(contextCurrent);
|
||||||
|
ASSERT(!contextCurrent->allocInitialized || contextAlloc->alloc == NULL);
|
||||||
|
|
||||||
|
// Initialize allocation header
|
||||||
|
*result = (MemContextAlloc){.size = (unsigned int)(sizeof(MemContextAlloc) + size)};
|
||||||
|
|
||||||
|
// Set pointer in allocation
|
||||||
|
contextAlloc->alloc = result;
|
||||||
|
contextCurrent->allocInitialized = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ASSERT(contextCurrent->allocQty == memQtyMany);
|
||||||
|
|
||||||
|
MemContextAllocMany *const contextAlloc = memContextAllocMany(contextCurrent);
|
||||||
|
|
||||||
|
// Initialize (free space will always be index 0)
|
||||||
|
if (!contextCurrent->allocInitialized)
|
||||||
|
{
|
||||||
|
*contextAlloc = (MemContextAllocMany)
|
||||||
|
{
|
||||||
|
.list = memAllocPtrArrayInternal(MEM_CONTEXT_ALLOC_INITIAL_SIZE),
|
||||||
|
.listSize = contextAlloc->listSize = MEM_CONTEXT_ALLOC_INITIAL_SIZE,
|
||||||
|
};
|
||||||
|
|
||||||
|
contextCurrent->allocInitialized = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (; contextAlloc->freeIdx < contextAlloc->listSize; contextAlloc->freeIdx++)
|
||||||
|
if (contextAlloc->list[contextAlloc->freeIdx] == NULL)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// If no space was found then allocate more
|
// If no space was found then allocate more
|
||||||
if (contextCurrent->allocFreeIdx == contextCurrent->allocListSize)
|
if (contextAlloc->freeIdx == contextAlloc->listSize)
|
||||||
{
|
|
||||||
// Only the top context will not have initial space for allocations
|
|
||||||
if (contextCurrent->allocListSize == 0)
|
|
||||||
{
|
|
||||||
// Allocate memory before modifying anything else in case there is an error
|
|
||||||
contextCurrent->allocList = memAllocPtrArrayInternal(MEM_CONTEXT_ALLOC_INITIAL_SIZE);
|
|
||||||
|
|
||||||
// Set new size
|
|
||||||
contextCurrent->allocListSize = MEM_CONTEXT_ALLOC_INITIAL_SIZE;
|
|
||||||
}
|
|
||||||
// Else grow the list
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
// Calculate new list size
|
// Calculate new list size
|
||||||
unsigned int allocListSizeNew = contextCurrent->allocListSize * 2;
|
unsigned int listSizeNew = contextAlloc->listSize * 2;
|
||||||
|
|
||||||
// Reallocate memory before modifying anything else in case there is an error
|
// Reallocate memory before modifying anything else in case there is an error
|
||||||
contextCurrent->allocList = memReAllocPtrArrayInternal(
|
contextAlloc->list = memReAllocPtrArrayInternal(contextAlloc->list, contextAlloc->listSize, listSizeNew);
|
||||||
contextCurrent->allocList, contextCurrent->allocListSize, allocListSizeNew);
|
|
||||||
|
|
||||||
// Set new size
|
// Set new size
|
||||||
contextCurrent->allocListSize = allocListSizeNew;
|
contextAlloc->listSize = listSizeNew;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create new allocation
|
// Initialize allocation header
|
||||||
MemContextAlloc *result = memAllocInternal(sizeof(MemContextAlloc) + size);
|
*result = (MemContextAlloc){.allocIdx = contextAlloc->freeIdx, .size = (unsigned int)(sizeof(MemContextAlloc) + size)};
|
||||||
|
|
||||||
*result = (MemContextAlloc)
|
|
||||||
{
|
|
||||||
.allocIdx = contextCurrent->allocFreeIdx,
|
|
||||||
.size = (unsigned int)(sizeof(MemContextAlloc) + size),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Set pointer in allocation list
|
// Set pointer in allocation list
|
||||||
contextCurrent->allocList[contextCurrent->allocFreeIdx] = result;
|
contextAlloc->list[contextAlloc->freeIdx] = result;
|
||||||
|
|
||||||
// Update free index to next location. This location may not actually be free but it is where the search should start next time.
|
// Update free index to next location. This location may not be free but it is where the search should start next time.
|
||||||
contextCurrent->allocFreeIdx++;
|
contextAlloc->freeIdx++;
|
||||||
|
}
|
||||||
|
|
||||||
FUNCTION_TEST_RETURN_TYPE_P(MemContextAlloc, result);
|
FUNCTION_TEST_RETURN_TYPE_P(MemContextAlloc, result);
|
||||||
}
|
}
|
||||||
@ -480,14 +660,27 @@ memContextAllocResize(MemContextAlloc *alloc, size_t size)
|
|||||||
FUNCTION_TEST_PARAM(SIZE, size);
|
FUNCTION_TEST_PARAM(SIZE, size);
|
||||||
FUNCTION_TEST_END();
|
FUNCTION_TEST_END();
|
||||||
|
|
||||||
ASSERT_ALLOC_VALID(alloc);
|
|
||||||
|
|
||||||
// Resize the allocation
|
// Resize the allocation
|
||||||
alloc = memReAllocInternal(alloc, sizeof(MemContextAlloc) + size);
|
alloc = memReAllocInternal(alloc, sizeof(MemContextAlloc) + size);
|
||||||
alloc->size = (unsigned int)(sizeof(MemContextAlloc) + size);
|
alloc->size = (unsigned int)(sizeof(MemContextAlloc) + size);
|
||||||
|
|
||||||
// Update pointer in allocation list in case the realloc moved the allocation
|
// Update pointer in allocation list in case the realloc moved the allocation
|
||||||
memContextStack[memContextCurrentStackIdx].memContext->allocList[alloc->allocIdx] = alloc;
|
MemContext *const currentContext = memContextStack[memContextCurrentStackIdx].memContext;
|
||||||
|
ASSERT(currentContext->allocQty != memQtyNone);
|
||||||
|
ASSERT(currentContext->allocInitialized);
|
||||||
|
|
||||||
|
if (currentContext->allocQty == memQtyOne)
|
||||||
|
{
|
||||||
|
ASSERT(memContextAllocOne(currentContext)->alloc != NULL);
|
||||||
|
memContextAllocOne(currentContext)->alloc = alloc;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ASSERT(currentContext->allocQty == memQtyMany);
|
||||||
|
ASSERT_ALLOC_MANY_VALID(alloc);
|
||||||
|
|
||||||
|
memContextAllocMany(currentContext)->list[alloc->allocIdx] = alloc;
|
||||||
|
}
|
||||||
|
|
||||||
FUNCTION_TEST_RETURN_TYPE_P(MemContextAlloc, alloc);
|
FUNCTION_TEST_RETURN_TYPE_P(MemContextAlloc, alloc);
|
||||||
}
|
}
|
||||||
@ -500,7 +693,9 @@ memNew(size_t size)
|
|||||||
FUNCTION_TEST_PARAM(SIZE, size);
|
FUNCTION_TEST_PARAM(SIZE, size);
|
||||||
FUNCTION_TEST_END();
|
FUNCTION_TEST_END();
|
||||||
|
|
||||||
FUNCTION_TEST_RETURN_P(VOID, MEM_CONTEXT_ALLOC_BUFFER(memContextAllocNew(size)));
|
void *result = MEM_CONTEXT_ALLOC_BUFFER(memContextAllocNew(size));
|
||||||
|
|
||||||
|
FUNCTION_TEST_RETURN_P(VOID, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**********************************************************************************************************************************/
|
/**********************************************************************************************************************************/
|
||||||
@ -535,24 +730,40 @@ memResize(const void *buffer, size_t size)
|
|||||||
|
|
||||||
/**********************************************************************************************************************************/
|
/**********************************************************************************************************************************/
|
||||||
void
|
void
|
||||||
memFree(void *buffer)
|
memFree(void *const buffer)
|
||||||
{
|
{
|
||||||
FUNCTION_TEST_BEGIN();
|
FUNCTION_TEST_BEGIN();
|
||||||
FUNCTION_TEST_PARAM_P(VOID, buffer);
|
FUNCTION_TEST_PARAM_P(VOID, buffer);
|
||||||
FUNCTION_TEST_END();
|
FUNCTION_TEST_END();
|
||||||
|
|
||||||
ASSERT_ALLOC_VALID(MEM_CONTEXT_ALLOC_HEADER(buffer));
|
|
||||||
|
|
||||||
// Get the allocation
|
// Get the allocation
|
||||||
MemContext *contextCurrent = memContextStack[memContextCurrentStackIdx].memContext;
|
MemContext *const contextCurrent = memContextStack[memContextCurrentStackIdx].memContext;
|
||||||
MemContextAlloc *alloc = MEM_CONTEXT_ALLOC_HEADER(buffer);
|
ASSERT(contextCurrent->allocQty != memQtyNone);
|
||||||
|
ASSERT(contextCurrent->allocInitialized);
|
||||||
|
MemContextAlloc *const alloc = MEM_CONTEXT_ALLOC_HEADER(buffer);
|
||||||
|
|
||||||
|
// Remove allocation from the context
|
||||||
|
if (contextCurrent->allocQty == memQtyOne)
|
||||||
|
{
|
||||||
|
ASSERT(memContextAllocOne(contextCurrent)->alloc == alloc);
|
||||||
|
memContextAllocOne(contextCurrent)->alloc = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ASSERT(contextCurrent->allocQty == memQtyMany);
|
||||||
|
ASSERT_ALLOC_MANY_VALID(alloc);
|
||||||
|
|
||||||
// If this allocation is before the current free allocation then make it the current free allocation
|
// If this allocation is before the current free allocation then make it the current free allocation
|
||||||
if (alloc->allocIdx < contextCurrent->allocFreeIdx)
|
MemContextAllocMany *const contextAlloc = memContextAllocMany(contextCurrent);
|
||||||
contextCurrent->allocFreeIdx = alloc->allocIdx;
|
|
||||||
|
if (alloc->allocIdx < contextAlloc->freeIdx)
|
||||||
|
contextAlloc->freeIdx = alloc->allocIdx;
|
||||||
|
|
||||||
|
// Null the allocation
|
||||||
|
contextAlloc->list[alloc->allocIdx] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
// Free the allocation
|
// Free the allocation
|
||||||
contextCurrent->allocList[alloc->allocIdx] = NULL;
|
|
||||||
memFreeInternal(alloc);
|
memFreeInternal(alloc);
|
||||||
|
|
||||||
FUNCTION_TEST_RETURN_VOID();
|
FUNCTION_TEST_RETURN_VOID();
|
||||||
@ -572,15 +783,48 @@ memContextMove(MemContext *this, MemContext *parentNew)
|
|||||||
// Only move if a valid mem context is provided and the old and new parents are not the same
|
// Only move if a valid mem context is provided and the old and new parents are not the same
|
||||||
if (this != NULL && this->contextParent != parentNew)
|
if (this != NULL && this->contextParent != parentNew)
|
||||||
{
|
{
|
||||||
// Null out the context in the old parent
|
ASSERT(this->active);
|
||||||
ASSERT(this->contextParent->contextChildList[this->contextParentIdx] == this);
|
ASSERT(this->contextParent->active);
|
||||||
this->contextParent->contextChildList[this->contextParentIdx] = NULL;
|
ASSERT(this->contextParent->childQty != memQtyNone);
|
||||||
|
ASSERT(this->contextParent->childInitialized);
|
||||||
|
|
||||||
// Find a place in the new parent context and assign it. The child list may be moved while finding a new index so store the
|
// Null out the context in the old parent
|
||||||
// index and use it with (what might be) the new pointer.
|
if (this->contextParent->childQty == memQtyOne)
|
||||||
|
{
|
||||||
|
ASSERT(memContextChildOne(this->contextParent)->context != NULL);
|
||||||
|
memContextChildOne(this->contextParent)->context = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ASSERT(this->contextParent->childQty == memQtyMany);
|
||||||
|
ASSERT(memContextChildMany(this->contextParent)->list[this->contextParentIdx] == this);
|
||||||
|
|
||||||
|
memContextChildMany(this->contextParent)->list[this->contextParentIdx] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find a place in the new parent context and assign it
|
||||||
|
ASSERT(parentNew->active);
|
||||||
|
ASSERT(parentNew->childQty != memQtyNone);
|
||||||
|
|
||||||
|
if (parentNew->childQty == memQtyOne)
|
||||||
|
{
|
||||||
|
ASSERT(!parentNew->childInitialized || memContextChildOne(parentNew)->context == NULL);
|
||||||
|
|
||||||
|
memContextChildOne(parentNew)->context = this;
|
||||||
|
parentNew->childInitialized = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ASSERT(parentNew->childQty == memQtyMany);
|
||||||
|
MemContextChildMany *const memContextChild = memContextChildMany(parentNew);
|
||||||
|
|
||||||
|
// The child list may move while finding a new index so store the index and use it with (what might be) the new pointer
|
||||||
|
this->contextParentIdx = memContextNewIndex(parentNew, memContextChild);
|
||||||
|
memContextChild->list[this->contextParentIdx] = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set new parent
|
||||||
this->contextParent = parentNew;
|
this->contextParent = parentNew;
|
||||||
this->contextParentIdx = memContextNewIndex(parentNew);
|
|
||||||
parentNew->contextChildList[this->contextParentIdx] = this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FUNCTION_TEST_RETURN_VOID();
|
FUNCTION_TEST_RETURN_VOID();
|
||||||
@ -691,7 +935,7 @@ MemContext *
|
|||||||
memContextTop(void)
|
memContextTop(void)
|
||||||
{
|
{
|
||||||
FUNCTION_TEST_VOID();
|
FUNCTION_TEST_VOID();
|
||||||
FUNCTION_TEST_RETURN(MEM_CONTEXT, &contextTop);
|
FUNCTION_TEST_RETURN(MEM_CONTEXT, (MemContext *)&contextTop);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**********************************************************************************************************************************/
|
/**********************************************************************************************************************************/
|
||||||
@ -720,32 +964,86 @@ memContextPrior(void)
|
|||||||
|
|
||||||
/**********************************************************************************************************************************/
|
/**********************************************************************************************************************************/
|
||||||
size_t
|
size_t
|
||||||
memContextSize(const MemContext *this)
|
memContextSize(const MemContext *const this)
|
||||||
{
|
{
|
||||||
FUNCTION_TEST_BEGIN();
|
FUNCTION_TEST_BEGIN();
|
||||||
FUNCTION_TEST_PARAM(MEM_CONTEXT, this);
|
FUNCTION_TEST_PARAM(MEM_CONTEXT, this);
|
||||||
FUNCTION_TEST_END();
|
FUNCTION_TEST_END();
|
||||||
|
|
||||||
// Size of struct and child context/alloc arrays
|
ASSERT(this != NULL);
|
||||||
size_t result =
|
ASSERT(this->active);
|
||||||
sizeof(MemContext) + this->allocExtra + (this->contextChildListSize * sizeof(MemContext *)) +
|
|
||||||
(this->allocListSize * sizeof(MemContextAlloc *));
|
|
||||||
|
|
||||||
// Add child contexts
|
// Size of struct and extra
|
||||||
for (unsigned int contextIdx = 0; contextIdx < this->contextChildListSize; contextIdx++)
|
size_t total = 0;
|
||||||
|
const unsigned char *offset = (unsigned char *)(this + 1) + this->allocExtra;
|
||||||
|
|
||||||
|
// Size of child contexts
|
||||||
|
if (this->childQty == memQtyOne)
|
||||||
{
|
{
|
||||||
if (this->contextChildList[contextIdx])
|
if (this->childInitialized)
|
||||||
result += memContextSize(this->contextChildList[contextIdx]);
|
{
|
||||||
|
const MemContextChildOne *const contextChild = (const MemContextChildOne *const)offset;
|
||||||
|
|
||||||
|
if (contextChild->context != NULL)
|
||||||
|
total += memContextSize(contextChild->context);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add allocations
|
offset += sizeof(MemContextChildOne);
|
||||||
for (unsigned int allocIdx = 0; allocIdx < this->allocListSize; allocIdx++)
|
}
|
||||||
|
else if (this->childQty == memQtyMany)
|
||||||
{
|
{
|
||||||
if (this->allocList[allocIdx] != NULL)
|
if (this->childInitialized)
|
||||||
result += this->allocList[allocIdx]->size;
|
{
|
||||||
|
const MemContextChildMany *const contextChild = (const MemContextChildMany *const)offset;
|
||||||
|
|
||||||
|
for (unsigned int contextIdx = 0; contextIdx < contextChild->listSize; contextIdx++)
|
||||||
|
{
|
||||||
|
if (contextChild->list[contextIdx] != NULL)
|
||||||
|
total += memContextSize(contextChild->list[contextIdx]);
|
||||||
}
|
}
|
||||||
|
|
||||||
FUNCTION_TEST_RETURN(SIZE, result);
|
total += contextChild->listSize * sizeof(MemContextChildMany *);
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += sizeof(MemContextChildMany);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Size of allocations
|
||||||
|
if (this->allocQty == memQtyOne)
|
||||||
|
{
|
||||||
|
if (this->allocInitialized)
|
||||||
|
{
|
||||||
|
const MemContextAllocOne *const contextAlloc = (const MemContextAllocOne *const)offset;
|
||||||
|
|
||||||
|
if (contextAlloc->alloc != NULL)
|
||||||
|
total += contextAlloc->alloc->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += sizeof(MemContextAllocOne);
|
||||||
|
}
|
||||||
|
else if (this->allocQty == memQtyMany)
|
||||||
|
{
|
||||||
|
if (this->allocInitialized)
|
||||||
|
{
|
||||||
|
const MemContextAllocMany *const contextAlloc = (const MemContextAllocMany *const)offset;
|
||||||
|
|
||||||
|
for (unsigned int allocIdx = 0; allocIdx < contextAlloc->listSize; allocIdx++)
|
||||||
|
{
|
||||||
|
if (contextAlloc->list[allocIdx] != NULL)
|
||||||
|
total += contextAlloc->list[allocIdx]->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
total += contextAlloc->listSize * sizeof(MemContextAllocMany *);
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += sizeof(MemContextAllocMany);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Size of callback
|
||||||
|
if (this->callbackQty != memQtyNone)
|
||||||
|
offset += sizeof(MemContextCallbackOne);
|
||||||
|
|
||||||
|
FUNCTION_TEST_RETURN(SIZE, (size_t)(offset - (unsigned char *)this) + total);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**********************************************************************************************************************************/
|
/**********************************************************************************************************************************/
|
||||||
@ -798,23 +1096,40 @@ memContextCallbackRecurse(MemContext *const this)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Callback
|
// Callback
|
||||||
if (this->callbackFunction)
|
if (this->callbackInitialized)
|
||||||
{
|
{
|
||||||
this->callbackFunction(this->callbackArgument);
|
MemContextCallbackOne *const callback = memContextCallbackOne(this);
|
||||||
this->callbackFunction = NULL;
|
callback->function(callback->argument);
|
||||||
|
this->callbackInitialized = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Child callbacks
|
// Child callbacks
|
||||||
for (unsigned int contextIdx = 0; contextIdx < this->contextChildListSize; contextIdx++)
|
if (this->childInitialized)
|
||||||
{
|
{
|
||||||
if (this->contextChildList[contextIdx] != NULL)
|
if (this->childQty == memQtyOne)
|
||||||
memContextCallbackRecurse(this->contextChildList[contextIdx]);
|
{
|
||||||
|
MemContextChildOne *const memContextChild = memContextChildOne(this);
|
||||||
|
|
||||||
|
if (memContextChild->context != NULL)
|
||||||
|
memContextCallbackRecurse(memContextChild->context);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ASSERT(this->childQty == memQtyMany);
|
||||||
|
MemContextChildMany *const memContextChild = memContextChildMany(this);
|
||||||
|
|
||||||
|
for (unsigned int contextIdx = 0; contextIdx < memContextChild->listSize; contextIdx++)
|
||||||
|
{
|
||||||
|
if (memContextChild->list[contextIdx] != NULL)
|
||||||
|
memContextCallbackRecurse(memContextChild->list[contextIdx]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FUNCTION_TEST_RETURN_VOID();
|
FUNCTION_TEST_RETURN_VOID();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper to free the context and all its children
|
/**********************************************************************************************************************************/
|
||||||
static void
|
static void
|
||||||
memContextFreeRecurse(MemContext *const this)
|
memContextFreeRecurse(MemContext *const this)
|
||||||
{
|
{
|
||||||
@ -826,55 +1141,95 @@ memContextFreeRecurse(MemContext *const this)
|
|||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
// Current context cannot be freed unless it is top (top is never really freed, just the stuff under it)
|
// Current context cannot be freed unless it is top (top is never really freed, just the stuff under it)
|
||||||
if (this == memContextStack[memContextCurrentStackIdx].memContext && this != &contextTop)
|
if (this == memContextStack[memContextCurrentStackIdx].memContext && this != memContextTop())
|
||||||
THROW_FMT(AssertError, "cannot free current context '%s'", this->name);
|
THROW_FMT(AssertError, "cannot free current context '%s'", this->name);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Free child contexts and list
|
|
||||||
if (this->contextChildListSize > 0)
|
|
||||||
{
|
|
||||||
// Free child contexts
|
// Free child contexts
|
||||||
for (unsigned int contextIdx = 0; contextIdx < this->contextChildListSize; contextIdx++)
|
if (this->childInitialized)
|
||||||
{
|
{
|
||||||
if (this->contextChildList[contextIdx] != NULL)
|
if (this->childQty == memQtyOne)
|
||||||
memContextFreeRecurse(this->contextChildList[contextIdx]);
|
{
|
||||||
|
MemContextChildOne *const memContextChild = memContextChildOne(this);
|
||||||
|
|
||||||
|
if (memContextChild->context != NULL)
|
||||||
|
memContextFreeRecurse(memContextChild->context);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ASSERT(this->childQty == memQtyMany);
|
||||||
|
MemContextChildMany *const memContextChild = memContextChildMany(this);
|
||||||
|
|
||||||
|
for (unsigned int contextIdx = 0; contextIdx < memContextChild->listSize; contextIdx++)
|
||||||
|
{
|
||||||
|
if (memContextChild->list[contextIdx] != NULL)
|
||||||
|
memContextFreeRecurse(memContextChild->list[contextIdx]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Free child context allocation list
|
// Free child context allocation list
|
||||||
memFreeInternal(this->contextChildList);
|
memFreeInternal(memContextChildMany(this)->list);
|
||||||
this->contextChildListSize = 0;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Free memory allocations and list
|
// Free memory allocations and list
|
||||||
if (this->allocListSize > 0)
|
if (this->allocInitialized)
|
||||||
{
|
{
|
||||||
for (unsigned int allocIdx = 0; allocIdx < this->allocListSize; allocIdx++)
|
ASSERT(this->allocQty != memQtyNone);
|
||||||
if (this->allocList[allocIdx] != NULL)
|
|
||||||
memFreeInternal(this->allocList[allocIdx]);
|
|
||||||
|
|
||||||
memFreeInternal(this->allocList);
|
if (this->allocQty == memQtyOne)
|
||||||
this->allocListSize = 0;
|
{
|
||||||
|
MemContextAllocOne *const contextAlloc = memContextAllocOne(this);
|
||||||
|
|
||||||
|
if (contextAlloc->alloc != NULL)
|
||||||
|
memFreeInternal(contextAlloc->alloc);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ASSERT(this->allocQty == memQtyMany);
|
||||||
|
|
||||||
|
MemContextAllocMany *const contextAlloc = memContextAllocMany(this);
|
||||||
|
|
||||||
|
for (unsigned int allocIdx = 0; allocIdx < contextAlloc->listSize; allocIdx++)
|
||||||
|
if (contextAlloc->list[allocIdx] != NULL)
|
||||||
|
memFreeInternal(contextAlloc->list[allocIdx]);
|
||||||
|
|
||||||
|
memFreeInternal(contextAlloc->list);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the context index is lower than the current free index in the parent then replace it
|
|
||||||
if (this->contextParent != NULL && this->contextParentIdx < this->contextParent->contextChildFreeIdx)
|
|
||||||
this->contextParent->contextChildFreeIdx = this->contextParentIdx;
|
|
||||||
|
|
||||||
// Free the memory context so the slot can be reused (if not the top mem context)
|
// Free the memory context so the slot can be reused (if not the top mem context)
|
||||||
if (this != &contextTop)
|
if (this != memContextTop())
|
||||||
{
|
{
|
||||||
ASSERT(this->contextParent != NULL);
|
ASSERT(this->contextParent != NULL);
|
||||||
|
|
||||||
this->contextParent->contextChildList[this->contextParentIdx] = NULL;
|
if (this->contextParent->childQty == memQtyOne)
|
||||||
memFreeInternal(this);
|
memContextChildOne(this->contextParent)->context = NULL;
|
||||||
}
|
|
||||||
#ifdef DEBUG
|
|
||||||
// Else make the top mem context active again
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
this->active = true;
|
ASSERT(this->contextParent->childQty == memQtyMany);
|
||||||
|
|
||||||
|
MemContextChildMany *const memContextChild = memContextChildMany(this->contextParent);
|
||||||
|
|
||||||
|
// If the context index is lower than the current free index in the parent then replace it
|
||||||
|
if (this->contextParentIdx < memContextChild->freeIdx)
|
||||||
|
memContextChild->freeIdx = this->contextParentIdx;
|
||||||
|
|
||||||
|
memContextChildMany(this->contextParent)->list[this->contextParentIdx] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memFreeInternal(this);
|
||||||
|
}
|
||||||
|
// Else reset top context. In practice it is uncommon for the top mem context to be freed and then used again.
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this->childInitialized = false;
|
||||||
|
this->allocInitialized = false;
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
// Make the top mem context active again
|
||||||
|
this->active = true;
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
FUNCTION_TEST_RETURN_VOID();
|
FUNCTION_TEST_RETURN_VOID();
|
||||||
}
|
}
|
||||||
|
@ -118,7 +118,7 @@ Note that memory context names are expected to live for the lifetime of the cont
|
|||||||
#define MEM_CONTEXT_NEW_BEGIN(memContextName, ...) \
|
#define MEM_CONTEXT_NEW_BEGIN(memContextName, ...) \
|
||||||
do \
|
do \
|
||||||
{ \
|
{ \
|
||||||
MemContext *MEM_CONTEXT_NEW() = memContextNewP(memContextName, __VA_ARGS__); \
|
MemContext *MEM_CONTEXT_NEW() = memContextNewP(STRINGIFY(memContextName), __VA_ARGS__); \
|
||||||
memContextSwitch(MEM_CONTEXT_NEW());
|
memContextSwitch(MEM_CONTEXT_NEW());
|
||||||
|
|
||||||
#define MEM_CONTEXT_NEW_ALLOC() \
|
#define MEM_CONTEXT_NEW_ALLOC() \
|
||||||
@ -150,7 +150,8 @@ MEM_CONTEXT_TEMP_END();
|
|||||||
#define MEM_CONTEXT_TEMP_BEGIN() \
|
#define MEM_CONTEXT_TEMP_BEGIN() \
|
||||||
do \
|
do \
|
||||||
{ \
|
{ \
|
||||||
MemContext *MEM_CONTEXT_TEMP() = memContextNewP("temporary"); \
|
MemContext *MEM_CONTEXT_TEMP() = memContextNewP( \
|
||||||
|
"temporary", .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX); \
|
||||||
memContextSwitch(MEM_CONTEXT_TEMP());
|
memContextSwitch(MEM_CONTEXT_TEMP());
|
||||||
|
|
||||||
#define MEM_CONTEXT_TEMP_RESET_BEGIN() \
|
#define MEM_CONTEXT_TEMP_RESET_BEGIN() \
|
||||||
@ -166,7 +167,7 @@ MEM_CONTEXT_TEMP_END();
|
|||||||
{ \
|
{ \
|
||||||
memContextSwitchBack(); \
|
memContextSwitchBack(); \
|
||||||
memContextDiscard(); \
|
memContextDiscard(); \
|
||||||
MEM_CONTEXT_TEMP() = memContextNewP("temporary"); \
|
MEM_CONTEXT_TEMP() = memContextNewP("temporary", .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX); \
|
||||||
memContextSwitch(MEM_CONTEXT_TEMP()); \
|
memContextSwitch(MEM_CONTEXT_TEMP()); \
|
||||||
MEM_CONTEXT_TEMP_loopTotal = 0; \
|
MEM_CONTEXT_TEMP_loopTotal = 0; \
|
||||||
} \
|
} \
|
||||||
@ -204,9 +205,18 @@ Use the MEM_CONTEXT*() macros when possible rather than reimplement the boilerpl
|
|||||||
typedef struct MemContextNewParam
|
typedef struct MemContextNewParam
|
||||||
{
|
{
|
||||||
VAR_PARAM_HEADER;
|
VAR_PARAM_HEADER;
|
||||||
|
uint8_t childQty; // How many child contexts can this context have?
|
||||||
|
uint8_t allocQty; // How many allocations can this context have?
|
||||||
|
uint8_t callbackQty; // How many callbacks can this context have?
|
||||||
uint16_t allocExtra; // Extra memory to allocate with the context
|
uint16_t allocExtra; // Extra memory to allocate with the context
|
||||||
} MemContextNewParam;
|
} MemContextNewParam;
|
||||||
|
|
||||||
|
// Maximum amount of extra memory that can be allocated with the context using allocExtra
|
||||||
|
#define MEM_CONTEXT_ALLOC_EXTRA_MAX UINT16_MAX
|
||||||
|
|
||||||
|
// Specify maximum quantity of child contexts or allocations using childQty or allocQty
|
||||||
|
#define MEM_CONTEXT_QTY_MAX UINT8_MAX
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
#define memContextNewP(name, ...) \
|
#define memContextNewP(name, ...) \
|
||||||
memContextNew(name, (MemContextNewParam){VAR_PARAM_INIT, __VA_ARGS__})
|
memContextNew(name, (MemContextNewParam){VAR_PARAM_INIT, __VA_ARGS__})
|
||||||
|
@ -74,7 +74,7 @@ regExpNew(const String *expression)
|
|||||||
|
|
||||||
RegExp *this = NULL;
|
RegExp *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(RegExp)
|
OBJ_NEW_BEGIN(RegExp, .childQty = MEM_CONTEXT_QTY_MAX, .callbackQty = 1)
|
||||||
{
|
{
|
||||||
this = OBJ_NEW_ALLOC();
|
this = OBJ_NEW_ALLOC();
|
||||||
*this = (RegExp){{0}}; // Extra braces are required for older gcc versions
|
*this = (RegExp){{0}}; // Extra braces are required for older gcc versions
|
||||||
|
@ -37,7 +37,7 @@ statInit(void)
|
|||||||
|
|
||||||
MEM_CONTEXT_BEGIN(memContextTop())
|
MEM_CONTEXT_BEGIN(memContextTop())
|
||||||
{
|
{
|
||||||
MEM_CONTEXT_NEW_BEGIN("StatLocalData")
|
MEM_CONTEXT_NEW_BEGIN(StatLocalData, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
statLocalData.memContext = MEM_CONTEXT_NEW();
|
statLocalData.memContext = MEM_CONTEXT_NEW();
|
||||||
statLocalData.stat = lstNewP(sizeof(Stat), .sortOrder = sortOrderAsc, .comparator = lstComparatorStr);
|
statLocalData.stat = lstNewP(sizeof(Stat), .sortOrder = sortOrderAsc, .comparator = lstComparatorStr);
|
||||||
|
@ -39,7 +39,7 @@ bufNew(size_t size)
|
|||||||
|
|
||||||
Buffer *this = NULL;
|
Buffer *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(Buffer)
|
OBJ_NEW_BEGIN(Buffer, .allocQty = 1)
|
||||||
{
|
{
|
||||||
// Create object
|
// Create object
|
||||||
this = OBJ_NEW_ALLOC();
|
this = OBJ_NEW_ALLOC();
|
||||||
|
@ -92,7 +92,7 @@ jsonReadNew(const String *const json)
|
|||||||
|
|
||||||
JsonRead *this = NULL;
|
JsonRead *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(JsonRead)
|
OBJ_NEW_BEGIN(JsonRead, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
this = OBJ_NEW_ALLOC();
|
this = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
@ -1309,7 +1309,7 @@ jsonWriteNew(JsonWriteNewParam param)
|
|||||||
|
|
||||||
JsonWrite *this = NULL;
|
JsonWrite *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(JsonWrite)
|
OBJ_NEW_BEGIN(JsonWrite, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
this = OBJ_NEW_ALLOC();
|
this = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ kvNew(void)
|
|||||||
|
|
||||||
KeyValue *this = NULL;
|
KeyValue *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(KeyValue)
|
OBJ_NEW_BEGIN(KeyValue, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
// Allocate state and set context
|
// Allocate state and set context
|
||||||
this = OBJ_NEW_ALLOC();
|
this = OBJ_NEW_ALLOC();
|
||||||
|
@ -35,7 +35,7 @@ lstNew(size_t itemSize, ListParam param)
|
|||||||
|
|
||||||
List *this = NULL;
|
List *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(List)
|
OBJ_NEW_BEGIN(List, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
// Create object
|
// Create object
|
||||||
this = OBJ_NEW_ALLOC();
|
this = OBJ_NEW_ALLOC();
|
||||||
|
@ -29,8 +29,11 @@ OBJ_NEW_BEGIN(MyObj)
|
|||||||
}
|
}
|
||||||
OBJ_NEW_END();
|
OBJ_NEW_END();
|
||||||
***********************************************************************************************************************************/
|
***********************************************************************************************************************************/
|
||||||
#define OBJ_NEW_BEGIN(type) \
|
#define OBJ_NEW_EXTRA_BEGIN(type, extra, ...) \
|
||||||
MEM_CONTEXT_NEW_BEGIN(STRINGIFY(type), .allocExtra = sizeof(type))
|
MEM_CONTEXT_NEW_BEGIN(type, .allocExtra = extra, __VA_ARGS__)
|
||||||
|
|
||||||
|
#define OBJ_NEW_BEGIN(type, ...) \
|
||||||
|
OBJ_NEW_EXTRA_BEGIN(type, sizeof(type), __VA_ARGS__)
|
||||||
|
|
||||||
#define OBJ_NEW_ALLOC() \
|
#define OBJ_NEW_ALLOC() \
|
||||||
memContextAllocExtra(memContextCurrent())
|
memContextAllocExtra(memContextCurrent())
|
||||||
|
@ -336,7 +336,7 @@ pckReadNewInternal(void)
|
|||||||
|
|
||||||
PackRead *this = NULL;
|
PackRead *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(PackRead)
|
OBJ_NEW_BEGIN(PackRead, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
this = OBJ_NEW_ALLOC();
|
this = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
@ -1295,7 +1295,7 @@ pckWriteNewInternal(void)
|
|||||||
|
|
||||||
PackWrite *this = NULL;
|
PackWrite *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(PackWrite)
|
OBJ_NEW_BEGIN(PackWrite, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
this = OBJ_NEW_ALLOC();
|
this = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -66,7 +66,6 @@ Object type
|
|||||||
struct String
|
struct String
|
||||||
{
|
{
|
||||||
StringPub pub; // Publicly accessible variables
|
StringPub pub; // Publicly accessible variables
|
||||||
MemContext *memContext; // Required for dynamically allocated strings
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**********************************************************************************************************************************/
|
/**********************************************************************************************************************************/
|
||||||
@ -75,8 +74,11 @@ strNew(void)
|
|||||||
{
|
{
|
||||||
FUNCTION_TEST_VOID();
|
FUNCTION_TEST_VOID();
|
||||||
|
|
||||||
// Create object
|
String *this = NULL;
|
||||||
String *this = memNew(sizeof(String));
|
|
||||||
|
OBJ_NEW_BEGIN(String, .allocQty = 1)
|
||||||
|
{
|
||||||
|
this = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
*this = (String)
|
*this = (String)
|
||||||
{
|
{
|
||||||
@ -85,8 +87,9 @@ strNew(void)
|
|||||||
// Set empty so nothing is allocated until needed
|
// Set empty so nothing is allocated until needed
|
||||||
.buffer = STR_EMPTY_BUFFER,
|
.buffer = STR_EMPTY_BUFFER,
|
||||||
},
|
},
|
||||||
.memContext = memContextCurrent(),
|
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
OBJ_NEW_END();
|
||||||
|
|
||||||
FUNCTION_TEST_RETURN(STRING, this);
|
FUNCTION_TEST_RETURN(STRING, this);
|
||||||
}
|
}
|
||||||
@ -103,7 +106,34 @@ strNewFixed(const size_t size)
|
|||||||
|
|
||||||
CHECK_SIZE(size);
|
CHECK_SIZE(size);
|
||||||
|
|
||||||
String *this = memNew(sizeof(String) + size + 1);
|
String *this = NULL;
|
||||||
|
|
||||||
|
// If the string is larger than the extra allowed with a mem context then allocate the buffer separately
|
||||||
|
size_t allocExtra = sizeof(String) + size + 1;
|
||||||
|
|
||||||
|
if (allocExtra > MEM_CONTEXT_ALLOC_EXTRA_MAX)
|
||||||
|
{
|
||||||
|
OBJ_NEW_BEGIN(String, .allocQty = 1)
|
||||||
|
{
|
||||||
|
this = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
*this = (String)
|
||||||
|
{
|
||||||
|
.pub =
|
||||||
|
{
|
||||||
|
.size = (unsigned int)size,
|
||||||
|
.buffer = memNew(size + 1),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
OBJ_NEW_END();
|
||||||
|
|
||||||
|
FUNCTION_TEST_RETURN(STRING, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
OBJ_NEW_EXTRA_BEGIN(String, (uint16_t)(allocExtra))
|
||||||
|
{
|
||||||
|
this = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
*this = (String)
|
*this = (String)
|
||||||
{
|
{
|
||||||
@ -112,8 +142,9 @@ strNewFixed(const size_t size)
|
|||||||
.size = (unsigned int)size,
|
.size = (unsigned int)size,
|
||||||
.buffer = STR_FIXED_BUFFER,
|
.buffer = STR_FIXED_BUFFER,
|
||||||
},
|
},
|
||||||
.memContext = memContextCurrent(),
|
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
OBJ_NEW_END();
|
||||||
|
|
||||||
FUNCTION_TEST_RETURN(STRING, this);
|
FUNCTION_TEST_RETURN(STRING, this);
|
||||||
}
|
}
|
||||||
@ -330,14 +361,14 @@ strResize(String *this, size_t requested)
|
|||||||
if (this->pub.extra < STRING_EXTRA_MIN)
|
if (this->pub.extra < STRING_EXTRA_MIN)
|
||||||
this->pub.extra = STRING_EXTRA_MIN;
|
this->pub.extra = STRING_EXTRA_MIN;
|
||||||
|
|
||||||
MEM_CONTEXT_BEGIN(this->memContext)
|
MEM_CONTEXT_OBJ_BEGIN(this)
|
||||||
{
|
{
|
||||||
if (STR_IS_EMPTY_BUFFER())
|
if (STR_IS_EMPTY_BUFFER())
|
||||||
this->pub.buffer = memNew(strSize(this) + this->pub.extra + 1);
|
this->pub.buffer = memNew(strSize(this) + this->pub.extra + 1);
|
||||||
else
|
else
|
||||||
this->pub.buffer = memResize(this->pub.buffer, strSize(this) + this->pub.extra + 1);
|
this->pub.buffer = memResize(this->pub.buffer, strSize(this) + this->pub.extra + 1);
|
||||||
}
|
}
|
||||||
MEM_CONTEXT_END();
|
MEM_CONTEXT_OBJ_END();
|
||||||
}
|
}
|
||||||
|
|
||||||
FUNCTION_TEST_RETURN_VOID();
|
FUNCTION_TEST_RETURN_VOID();
|
||||||
@ -1065,28 +1096,3 @@ strSizeFormat(const uint64_t size)
|
|||||||
|
|
||||||
FUNCTION_TEST_RETURN(STRING, result);
|
FUNCTION_TEST_RETURN(STRING, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************************************************************************************************************************
|
|
||||||
Free the string
|
|
||||||
***********************************************************************************************************************************/
|
|
||||||
void
|
|
||||||
strFree(String *this)
|
|
||||||
{
|
|
||||||
FUNCTION_TEST_BEGIN();
|
|
||||||
FUNCTION_TEST_PARAM(STRING, this);
|
|
||||||
FUNCTION_TEST_END();
|
|
||||||
|
|
||||||
if (this != NULL)
|
|
||||||
{
|
|
||||||
MEM_CONTEXT_BEGIN(this->memContext)
|
|
||||||
{
|
|
||||||
if (!STR_IS_EMPTY_BUFFER() && !STR_IS_FIXED_BUFFER())
|
|
||||||
memFree(this->pub.buffer);
|
|
||||||
|
|
||||||
memFree(this);
|
|
||||||
}
|
|
||||||
MEM_CONTEXT_END();
|
|
||||||
}
|
|
||||||
|
|
||||||
FUNCTION_TEST_RETURN_VOID();
|
|
||||||
}
|
|
||||||
|
@ -202,7 +202,11 @@ String *strTrunc(String *this, int idx);
|
|||||||
/***********************************************************************************************************************************
|
/***********************************************************************************************************************************
|
||||||
Destructor
|
Destructor
|
||||||
***********************************************************************************************************************************/
|
***********************************************************************************************************************************/
|
||||||
void strFree(String *this);
|
__attribute__((always_inline)) static inline void
|
||||||
|
strFree(String *const this)
|
||||||
|
{
|
||||||
|
objFree(this);
|
||||||
|
}
|
||||||
|
|
||||||
/***********************************************************************************************************************************
|
/***********************************************************************************************************************************
|
||||||
Macros for constant strings
|
Macros for constant strings
|
||||||
|
@ -37,51 +37,43 @@ struct Variant
|
|||||||
typedef struct VariantBool
|
typedef struct VariantBool
|
||||||
{
|
{
|
||||||
VariantBoolPub pub; // Publicly accessible variables
|
VariantBoolPub pub; // Publicly accessible variables
|
||||||
MemContext *memContext;
|
|
||||||
} VariantBool;
|
} VariantBool;
|
||||||
|
|
||||||
typedef struct VariantInt
|
typedef struct VariantInt
|
||||||
{
|
{
|
||||||
VariantIntPub pub; // Publicly accessible variables
|
VariantIntPub pub; // Publicly accessible variables
|
||||||
MemContext *memContext;
|
|
||||||
} VariantInt;
|
} VariantInt;
|
||||||
|
|
||||||
typedef struct VariantInt64
|
typedef struct VariantInt64
|
||||||
{
|
{
|
||||||
VariantInt64Pub pub; // Publicly accessible variables
|
VariantInt64Pub pub; // Publicly accessible variables
|
||||||
MemContext *memContext;
|
|
||||||
} VariantInt64;
|
} VariantInt64;
|
||||||
|
|
||||||
typedef struct VariantKeyValue
|
typedef struct VariantKeyValue
|
||||||
{
|
{
|
||||||
VARIANT_COMMON
|
VARIANT_COMMON
|
||||||
KeyValue *data; // KeyValue data
|
KeyValue *data; // KeyValue data
|
||||||
MemContext *memContext;
|
|
||||||
} VariantKeyValue;
|
} VariantKeyValue;
|
||||||
|
|
||||||
typedef struct VariantString
|
typedef struct VariantString
|
||||||
{
|
{
|
||||||
VariantStringPub pub; // Publicly accessible variables
|
VariantStringPub pub; // Publicly accessible variables
|
||||||
MemContext *memContext;
|
|
||||||
} VariantString;
|
} VariantString;
|
||||||
|
|
||||||
typedef struct VariantUInt
|
typedef struct VariantUInt
|
||||||
{
|
{
|
||||||
VariantUIntPub pub; // Publicly accessible variables
|
VariantUIntPub pub; // Publicly accessible variables
|
||||||
MemContext *memContext;
|
|
||||||
} VariantUInt;
|
} VariantUInt;
|
||||||
|
|
||||||
typedef struct VariantUInt64
|
typedef struct VariantUInt64
|
||||||
{
|
{
|
||||||
VariantUInt64Pub pub; // Publicly accessible variables
|
VariantUInt64Pub pub; // Publicly accessible variables
|
||||||
MemContext *memContext;
|
|
||||||
} VariantUInt64;
|
} VariantUInt64;
|
||||||
|
|
||||||
typedef struct VariantVariantList
|
typedef struct VariantVariantList
|
||||||
{
|
{
|
||||||
VARIANT_COMMON
|
VARIANT_COMMON
|
||||||
VariantList *data; // VariantList data
|
VariantList *data; // VariantList data
|
||||||
MemContext *memContext;
|
|
||||||
} VariantVariantList;
|
} VariantVariantList;
|
||||||
|
|
||||||
/***********************************************************************************************************************************
|
/***********************************************************************************************************************************
|
||||||
@ -127,16 +119,7 @@ varDup(const Variant *this)
|
|||||||
|
|
||||||
case varTypeKeyValue:
|
case varTypeKeyValue:
|
||||||
{
|
{
|
||||||
VariantKeyValue *keyValue = memNew(sizeof(VariantKeyValue));
|
result = varNewKv(kvDup(varKv(this)));
|
||||||
|
|
||||||
*keyValue = (VariantKeyValue)
|
|
||||||
{
|
|
||||||
.memContext = memContextCurrent(),
|
|
||||||
.type = varTypeKeyValue,
|
|
||||||
.data = kvDup(varKv(this)),
|
|
||||||
};
|
|
||||||
|
|
||||||
result = (Variant *)keyValue;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -224,8 +207,11 @@ varNewBool(bool data)
|
|||||||
FUNCTION_TEST_PARAM(BOOL, data);
|
FUNCTION_TEST_PARAM(BOOL, data);
|
||||||
FUNCTION_TEST_END();
|
FUNCTION_TEST_END();
|
||||||
|
|
||||||
// Allocate memory for the variant and set the type and data
|
VariantBool *this = NULL;
|
||||||
VariantBool *this = memNew(sizeof(VariantBool));
|
|
||||||
|
OBJ_NEW_BEGIN(VariantBool)
|
||||||
|
{
|
||||||
|
this = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
*this = (VariantBool)
|
*this = (VariantBool)
|
||||||
{
|
{
|
||||||
@ -234,8 +220,9 @@ varNewBool(bool data)
|
|||||||
.type = varTypeBool,
|
.type = varTypeBool,
|
||||||
.data = data,
|
.data = data,
|
||||||
},
|
},
|
||||||
.memContext = memContextCurrent(),
|
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
OBJ_NEW_END();
|
||||||
|
|
||||||
FUNCTION_TEST_RETURN(VARIANT, (Variant *)this);
|
FUNCTION_TEST_RETURN(VARIANT, (Variant *)this);
|
||||||
}
|
}
|
||||||
@ -329,8 +316,11 @@ varNewInt(int data)
|
|||||||
FUNCTION_TEST_PARAM(INT, data);
|
FUNCTION_TEST_PARAM(INT, data);
|
||||||
FUNCTION_TEST_END();
|
FUNCTION_TEST_END();
|
||||||
|
|
||||||
// Allocate memory for the variant and set the type and data
|
VariantInt *this = NULL;
|
||||||
VariantInt *this = memNew(sizeof(VariantInt));
|
|
||||||
|
OBJ_NEW_BEGIN(VariantInt)
|
||||||
|
{
|
||||||
|
this = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
*this = (VariantInt)
|
*this = (VariantInt)
|
||||||
{
|
{
|
||||||
@ -339,8 +329,9 @@ varNewInt(int data)
|
|||||||
.type = varTypeInt,
|
.type = varTypeInt,
|
||||||
.data = data,
|
.data = data,
|
||||||
},
|
},
|
||||||
.memContext = memContextCurrent(),
|
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
OBJ_NEW_END();
|
||||||
|
|
||||||
FUNCTION_TEST_RETURN(VARIANT, (Variant *)this);
|
FUNCTION_TEST_RETURN(VARIANT, (Variant *)this);
|
||||||
}
|
}
|
||||||
@ -441,8 +432,11 @@ varNewInt64(int64_t data)
|
|||||||
FUNCTION_TEST_PARAM(INT64, data);
|
FUNCTION_TEST_PARAM(INT64, data);
|
||||||
FUNCTION_TEST_END();
|
FUNCTION_TEST_END();
|
||||||
|
|
||||||
// Allocate memory for the variant and set the type and data
|
VariantInt64 *this = NULL;
|
||||||
VariantInt64 *this = memNew(sizeof(VariantInt64));
|
|
||||||
|
OBJ_NEW_BEGIN(VariantInt64)
|
||||||
|
{
|
||||||
|
this = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
*this = (VariantInt64)
|
*this = (VariantInt64)
|
||||||
{
|
{
|
||||||
@ -451,8 +445,9 @@ varNewInt64(int64_t data)
|
|||||||
.type = varTypeInt64,
|
.type = varTypeInt64,
|
||||||
.data = data,
|
.data = data,
|
||||||
},
|
},
|
||||||
.memContext = memContextCurrent(),
|
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
OBJ_NEW_END();
|
||||||
|
|
||||||
FUNCTION_TEST_RETURN(VARIANT, (Variant *)this);
|
FUNCTION_TEST_RETURN(VARIANT, (Variant *)this);
|
||||||
}
|
}
|
||||||
@ -537,8 +532,11 @@ varNewUInt(unsigned int data)
|
|||||||
FUNCTION_TEST_PARAM(UINT, data);
|
FUNCTION_TEST_PARAM(UINT, data);
|
||||||
FUNCTION_TEST_END();
|
FUNCTION_TEST_END();
|
||||||
|
|
||||||
// Allocate memory for the variant and set the type and data
|
VariantUInt *this = NULL;
|
||||||
VariantUInt *this = memNew(sizeof(VariantUInt));
|
|
||||||
|
OBJ_NEW_BEGIN(VariantUInt)
|
||||||
|
{
|
||||||
|
this = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
*this = (VariantUInt)
|
*this = (VariantUInt)
|
||||||
{
|
{
|
||||||
@ -547,8 +545,9 @@ varNewUInt(unsigned int data)
|
|||||||
.type = varTypeUInt,
|
.type = varTypeUInt,
|
||||||
.data = data,
|
.data = data,
|
||||||
},
|
},
|
||||||
.memContext = memContextCurrent(),
|
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
OBJ_NEW_END();
|
||||||
|
|
||||||
FUNCTION_TEST_RETURN(VARIANT, (Variant *)this);
|
FUNCTION_TEST_RETURN(VARIANT, (Variant *)this);
|
||||||
}
|
}
|
||||||
@ -658,8 +657,11 @@ varNewUInt64(uint64_t data)
|
|||||||
FUNCTION_TEST_PARAM(UINT64, data);
|
FUNCTION_TEST_PARAM(UINT64, data);
|
||||||
FUNCTION_TEST_END();
|
FUNCTION_TEST_END();
|
||||||
|
|
||||||
// Allocate memory for the variant and set the type and data
|
VariantUInt64 *this = NULL;
|
||||||
VariantUInt64 *this = memNew(sizeof(VariantUInt64));
|
|
||||||
|
OBJ_NEW_BEGIN(VariantUInt64)
|
||||||
|
{
|
||||||
|
this = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
*this = (VariantUInt64)
|
*this = (VariantUInt64)
|
||||||
{
|
{
|
||||||
@ -668,8 +670,9 @@ varNewUInt64(uint64_t data)
|
|||||||
.type = varTypeUInt64,
|
.type = varTypeUInt64,
|
||||||
.data = data,
|
.data = data,
|
||||||
},
|
},
|
||||||
.memContext = memContextCurrent(),
|
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
OBJ_NEW_END();
|
||||||
|
|
||||||
FUNCTION_TEST_RETURN(VARIANT, (Variant *)this);
|
FUNCTION_TEST_RETURN(VARIANT, (Variant *)this);
|
||||||
}
|
}
|
||||||
@ -766,17 +769,21 @@ varNewKv(KeyValue *data)
|
|||||||
FUNCTION_TEST_PARAM(KEY_VALUE, data);
|
FUNCTION_TEST_PARAM(KEY_VALUE, data);
|
||||||
FUNCTION_TEST_END();
|
FUNCTION_TEST_END();
|
||||||
|
|
||||||
// Allocate memory for the variant and set the type and data
|
VariantKeyValue *this = NULL;
|
||||||
VariantKeyValue *this = memNew(sizeof(VariantKeyValue));
|
|
||||||
|
OBJ_NEW_BEGIN(VariantKeyValue, .childQty = 1)
|
||||||
|
{
|
||||||
|
this = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
*this = (VariantKeyValue)
|
*this = (VariantKeyValue)
|
||||||
{
|
{
|
||||||
.memContext = memContextCurrent(),
|
|
||||||
.type = varTypeKeyValue,
|
.type = varTypeKeyValue,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (data != NULL)
|
if (data != NULL)
|
||||||
this->data = kvMove(data, memContextCurrent());
|
this->data = kvMove(data, memContextCurrent());
|
||||||
|
}
|
||||||
|
OBJ_NEW_END();
|
||||||
|
|
||||||
FUNCTION_TEST_RETURN(VARIANT, (Variant *)this);
|
FUNCTION_TEST_RETURN(VARIANT, (Variant *)this);
|
||||||
}
|
}
|
||||||
@ -808,8 +815,36 @@ varNewStr(const String *data)
|
|||||||
FUNCTION_TEST_PARAM(STRING, data);
|
FUNCTION_TEST_PARAM(STRING, data);
|
||||||
FUNCTION_TEST_END();
|
FUNCTION_TEST_END();
|
||||||
|
|
||||||
// Allocate memory for the variant
|
VariantString *this = NULL;
|
||||||
VariantString *this = memNew(sizeof(VariantString) + (data != NULL ? sizeof(StringPub) + strSize(data) + 1 : 0));
|
|
||||||
|
// If the variant is larger than the extra allowed with a mem context then allocate the buffer separately
|
||||||
|
size_t allocExtra = sizeof(VariantString) + (data != NULL ? sizeof(StringPub) + strSize(data) + 1 : 0);
|
||||||
|
|
||||||
|
if (allocExtra > MEM_CONTEXT_ALLOC_EXTRA_MAX)
|
||||||
|
{
|
||||||
|
ASSERT(data != NULL);
|
||||||
|
|
||||||
|
OBJ_NEW_BEGIN(VariantString, .childQty = 1)
|
||||||
|
{
|
||||||
|
this = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
*this = (VariantString)
|
||||||
|
{
|
||||||
|
.pub =
|
||||||
|
{
|
||||||
|
.type = varTypeString,
|
||||||
|
.data = strDup(data),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
OBJ_NEW_END();
|
||||||
|
|
||||||
|
FUNCTION_TEST_RETURN(VARIANT, (Variant *)this);
|
||||||
|
}
|
||||||
|
|
||||||
|
OBJ_NEW_EXTRA_BEGIN(VariantString, (uint16_t)(allocExtra))
|
||||||
|
{
|
||||||
|
this = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
*this = (VariantString)
|
*this = (VariantString)
|
||||||
{
|
{
|
||||||
@ -817,7 +852,6 @@ varNewStr(const String *data)
|
|||||||
{
|
{
|
||||||
.type = varTypeString,
|
.type = varTypeString,
|
||||||
},
|
},
|
||||||
.memContext = memContextCurrent(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (data != NULL)
|
if (data != NULL)
|
||||||
@ -837,6 +871,8 @@ varNewStr(const String *data)
|
|||||||
strncpy(pubData->buffer, strZ(data), strSize(data));
|
strncpy(pubData->buffer, strZ(data), strSize(data));
|
||||||
pubData->buffer[strSize(data)] = '\0';
|
pubData->buffer[strSize(data)] = '\0';
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
OBJ_NEW_END();
|
||||||
|
|
||||||
FUNCTION_TEST_RETURN(VARIANT, (Variant *)this);
|
FUNCTION_TEST_RETURN(VARIANT, (Variant *)this);
|
||||||
}
|
}
|
||||||
@ -942,17 +978,21 @@ varNewVarLst(const VariantList *data)
|
|||||||
FUNCTION_TEST_PARAM(VARIANT_LIST, data);
|
FUNCTION_TEST_PARAM(VARIANT_LIST, data);
|
||||||
FUNCTION_TEST_END();
|
FUNCTION_TEST_END();
|
||||||
|
|
||||||
// Allocate memory for the variant and set the type and data
|
VariantVariantList *this = NULL;
|
||||||
VariantVariantList *this = memNew(sizeof(VariantVariantList));
|
|
||||||
|
OBJ_NEW_BEGIN(VariantVariantList, .childQty = 1)
|
||||||
|
{
|
||||||
|
this = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
*this = (VariantVariantList)
|
*this = (VariantVariantList)
|
||||||
{
|
{
|
||||||
.memContext = memContextCurrent(),
|
|
||||||
.type = varTypeVariantList,
|
.type = varTypeVariantList,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (data != NULL)
|
if (data != NULL)
|
||||||
this->data = varLstDup(data);
|
this->data = varLstDup(data);
|
||||||
|
}
|
||||||
|
OBJ_NEW_END();
|
||||||
|
|
||||||
FUNCTION_TEST_RETURN(VARIANT, (Variant *)this);
|
FUNCTION_TEST_RETURN(VARIANT, (Variant *)this);
|
||||||
}
|
}
|
||||||
@ -1014,62 +1054,3 @@ varToLog(const Variant *this)
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**********************************************************************************************************************************/
|
|
||||||
void
|
|
||||||
varFree(Variant *this)
|
|
||||||
{
|
|
||||||
FUNCTION_TEST_BEGIN();
|
|
||||||
FUNCTION_TEST_PARAM(VARIANT, this);
|
|
||||||
FUNCTION_TEST_END();
|
|
||||||
|
|
||||||
if (this != NULL)
|
|
||||||
{
|
|
||||||
MemContext *memContext = NULL;
|
|
||||||
|
|
||||||
switch (varType(this))
|
|
||||||
{
|
|
||||||
case varTypeBool:
|
|
||||||
memContext = ((VariantBool *)this)->memContext;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case varTypeInt:
|
|
||||||
memContext = ((VariantInt *)this)->memContext;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case varTypeInt64:
|
|
||||||
memContext = ((VariantInt64 *)this)->memContext;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case varTypeKeyValue:
|
|
||||||
memContext = ((VariantKeyValue *)this)->memContext;
|
|
||||||
kvFree(((VariantKeyValue *)this)->data);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case varTypeString:
|
|
||||||
memContext = ((VariantString *)this)->memContext;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case varTypeUInt:
|
|
||||||
memContext = ((VariantUInt *)this)->memContext;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case varTypeUInt64:
|
|
||||||
memContext = ((VariantUInt64 *)this)->memContext;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case varTypeVariantList:
|
|
||||||
memContext = ((VariantVariantList *)this)->memContext;
|
|
||||||
varLstFree(((VariantVariantList *)this)->data);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
MEM_CONTEXT_BEGIN(memContext)
|
|
||||||
{
|
|
||||||
memFree(this);
|
|
||||||
}
|
|
||||||
MEM_CONTEXT_END();
|
|
||||||
}
|
|
||||||
|
|
||||||
FUNCTION_TEST_RETURN_VOID();
|
|
||||||
}
|
|
||||||
|
@ -151,7 +151,11 @@ bool varEq(const Variant *this1, const Variant *this2);
|
|||||||
/***********************************************************************************************************************************
|
/***********************************************************************************************************************************
|
||||||
Destructor
|
Destructor
|
||||||
***********************************************************************************************************************************/
|
***********************************************************************************************************************************/
|
||||||
void varFree(Variant *this);
|
__attribute__((always_inline)) static inline void
|
||||||
|
varFree(Variant *const this)
|
||||||
|
{
|
||||||
|
objFree(this);
|
||||||
|
}
|
||||||
|
|
||||||
/***********************************************************************************************************************************
|
/***********************************************************************************************************************************
|
||||||
Macros for constant variants
|
Macros for constant variants
|
||||||
|
@ -332,7 +332,7 @@ xmlDocumentNew(const String *rootName)
|
|||||||
// Create object
|
// Create object
|
||||||
XmlDocument *this = NULL;
|
XmlDocument *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(XmlDocument)
|
OBJ_NEW_BEGIN(XmlDocument, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX, .callbackQty = 1)
|
||||||
{
|
{
|
||||||
this = OBJ_NEW_ALLOC();
|
this = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
@ -368,7 +368,7 @@ xmlDocumentNewBuf(const Buffer *buffer)
|
|||||||
// Create object
|
// Create object
|
||||||
XmlDocument *this = NULL;
|
XmlDocument *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(XmlDocument)
|
OBJ_NEW_BEGIN(XmlDocument, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX, .callbackQty = 1)
|
||||||
{
|
{
|
||||||
this = OBJ_NEW_ALLOC();
|
this = OBJ_NEW_ALLOC();
|
||||||
*this = (XmlDocument){{0}}; // Extra braces are required for older gcc versions
|
*this = (XmlDocument){{0}}; // Extra braces are required for older gcc versions
|
||||||
|
@ -34,7 +34,7 @@ userInitInternal(void)
|
|||||||
|
|
||||||
MEM_CONTEXT_BEGIN(memContextTop())
|
MEM_CONTEXT_BEGIN(memContextTop())
|
||||||
{
|
{
|
||||||
MEM_CONTEXT_NEW_BEGIN("UserLocalData")
|
MEM_CONTEXT_NEW_BEGIN(UserLocalData, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
userLocalData.memContext = MEM_CONTEXT_NEW();
|
userLocalData.memContext = MEM_CONTEXT_NEW();
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ waitNew(TimeMSec waitTime)
|
|||||||
// Allocate wait object
|
// Allocate wait object
|
||||||
Wait *this = NULL;
|
Wait *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(Wait)
|
OBJ_NEW_BEGIN(Wait, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
// Create object
|
// Create object
|
||||||
this = OBJ_NEW_ALLOC();
|
this = OBJ_NEW_ALLOC();
|
||||||
|
@ -1380,7 +1380,7 @@ configParse(const Storage *storage, unsigned int argListSize, const char *argLis
|
|||||||
// Create the config struct
|
// Create the config struct
|
||||||
Config *config;
|
Config *config;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(Config)
|
OBJ_NEW_BEGIN(Config, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
config = OBJ_NEW_ALLOC();
|
config = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ dbNew(PgClient *client, ProtocolClient *remoteClient, const Storage *const stora
|
|||||||
|
|
||||||
Db *this = NULL;
|
Db *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(Db)
|
OBJ_NEW_BEGIN(Db, .childQty = MEM_CONTEXT_QTY_MAX, .callbackQty = 1)
|
||||||
{
|
{
|
||||||
this = OBJ_NEW_ALLOC();
|
this = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -121,7 +121,7 @@ infoNew(const String *cipherPass)
|
|||||||
|
|
||||||
Info *this = NULL;
|
Info *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(Info)
|
OBJ_NEW_BEGIN(Info, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
this = infoNewInternal();
|
this = infoNewInternal();
|
||||||
|
|
||||||
@ -256,7 +256,7 @@ infoNewLoad(IoRead *read, InfoLoadNewCallback *callbackFunction, void *callbackD
|
|||||||
|
|
||||||
Info *this = NULL;
|
Info *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(Info)
|
OBJ_NEW_BEGIN(Info, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
this = infoNewInternal();
|
this = infoNewInternal();
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ infoArchiveNew(unsigned int pgVersion, uint64_t pgSystemId, const String *cipher
|
|||||||
|
|
||||||
InfoArchive *this = NULL;
|
InfoArchive *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(InfoArchive)
|
OBJ_NEW_BEGIN(InfoArchive, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
this = infoArchiveNewInternal();
|
this = infoArchiveNewInternal();
|
||||||
|
|
||||||
@ -94,7 +94,7 @@ infoArchiveNewLoad(IoRead *read)
|
|||||||
|
|
||||||
InfoArchive *this = NULL;
|
InfoArchive *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(InfoArchive)
|
OBJ_NEW_BEGIN(InfoArchive, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
this = infoArchiveNewInternal();
|
this = infoArchiveNewInternal();
|
||||||
this->pub.infoPg = infoPgNewLoad(read, infoPgArchive, NULL, NULL);
|
this->pub.infoPg = infoPgNewLoad(read, infoPgArchive, NULL, NULL);
|
||||||
|
@ -76,7 +76,7 @@ infoBackupNew(unsigned int pgVersion, uint64_t pgSystemId, unsigned int pgCatalo
|
|||||||
|
|
||||||
InfoBackup *this = NULL;
|
InfoBackup *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(InfoBackup)
|
OBJ_NEW_BEGIN(InfoBackup, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
this = infoBackupNewInternal();
|
this = infoBackupNewInternal();
|
||||||
|
|
||||||
@ -225,7 +225,7 @@ infoBackupNewLoad(IoRead *read)
|
|||||||
|
|
||||||
InfoBackup *this = NULL;
|
InfoBackup *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(InfoBackup)
|
OBJ_NEW_BEGIN(InfoBackup, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
this = infoBackupNewInternal();
|
this = infoBackupNewInternal();
|
||||||
this->pub.infoPg = infoPgNewLoad(read, infoPgBackup, infoBackupLoadCallback, this);
|
this->pub.infoPg = infoPgNewLoad(read, infoPgBackup, infoBackupLoadCallback, this);
|
||||||
|
@ -69,7 +69,7 @@ infoPgNew(InfoPgType type, const String *cipherPassSub)
|
|||||||
|
|
||||||
InfoPg *this = NULL;
|
InfoPg *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(InfoPg)
|
OBJ_NEW_BEGIN(InfoPg, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
this = infoPgNewInternal(type);
|
this = infoPgNewInternal(type);
|
||||||
this->pub.info = infoNew(cipherPassSub);
|
this->pub.info = infoNew(cipherPassSub);
|
||||||
@ -164,7 +164,7 @@ infoPgNewLoad(IoRead *read, InfoPgType type, InfoLoadNewCallback *callbackFuncti
|
|||||||
|
|
||||||
InfoPg *this = NULL;
|
InfoPg *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(InfoPg)
|
OBJ_NEW_BEGIN(InfoPg, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
this = infoPgNewInternal(type);
|
this = infoPgNewInternal(type);
|
||||||
|
|
||||||
|
@ -1112,7 +1112,7 @@ manifestNewBuild(
|
|||||||
|
|
||||||
Manifest *this = NULL;
|
Manifest *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(Manifest)
|
OBJ_NEW_BEGIN(Manifest, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
this = manifestNewInternal();
|
this = manifestNewInternal();
|
||||||
this->pub.info = infoNew(NULL);
|
this->pub.info = infoNew(NULL);
|
||||||
@ -2050,14 +2050,14 @@ manifestNewLoad(IoRead *read)
|
|||||||
|
|
||||||
Manifest *this = NULL;
|
Manifest *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(Manifest)
|
OBJ_NEW_BEGIN(Manifest, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
this = manifestNewInternal();
|
this = manifestNewInternal();
|
||||||
|
|
||||||
// Load the manifest
|
// Load the manifest
|
||||||
ManifestLoadData loadData =
|
ManifestLoadData loadData =
|
||||||
{
|
{
|
||||||
.memContext = memContextNewP("load"),
|
.memContext = memContextNewP("load", .childQty = MEM_CONTEXT_QTY_MAX),
|
||||||
.manifest = this,
|
.manifest = this,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ pgClientNew(const String *host, const unsigned int port, const String *database,
|
|||||||
|
|
||||||
PgClient *this = NULL;
|
PgClient *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(PgClient)
|
OBJ_NEW_BEGIN(PgClient, .childQty = MEM_CONTEXT_QTY_MAX, .callbackQty = 1)
|
||||||
{
|
{
|
||||||
this = OBJ_NEW_ALLOC();
|
this = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -90,7 +90,7 @@ protocolClientNew(const String *name, const String *service, IoRead *read, IoWri
|
|||||||
|
|
||||||
ProtocolClient *this = NULL;
|
ProtocolClient *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(ProtocolClient)
|
OBJ_NEW_BEGIN(ProtocolClient, .childQty = MEM_CONTEXT_QTY_MAX, .callbackQty = 1)
|
||||||
{
|
{
|
||||||
this = OBJ_NEW_ALLOC();
|
this = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ protocolCommandNew(const StringId command)
|
|||||||
|
|
||||||
ProtocolCommand *this = NULL;
|
ProtocolCommand *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(ProtocolCommand)
|
OBJ_NEW_BEGIN(ProtocolCommand, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
this = OBJ_NEW_ALLOC();
|
this = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ protocolHelperInit(void)
|
|||||||
// Create a mem context to store protocol objects
|
// Create a mem context to store protocol objects
|
||||||
MEM_CONTEXT_BEGIN(memContextTop())
|
MEM_CONTEXT_BEGIN(memContextTop())
|
||||||
{
|
{
|
||||||
MEM_CONTEXT_NEW_BEGIN("ProtocolHelper")
|
MEM_CONTEXT_NEW_BEGIN("ProtocolHelper", .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
protocolHelper.memContext = MEM_CONTEXT_NEW();
|
protocolHelper.memContext = MEM_CONTEXT_NEW();
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ protocolParallelNew(TimeMSec timeout, ParallelJobCallback *callbackFunction, voi
|
|||||||
|
|
||||||
ProtocolParallel *this = NULL;
|
ProtocolParallel *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(ProtocolParallel)
|
OBJ_NEW_BEGIN(ProtocolParallel, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
this = OBJ_NEW_ALLOC();
|
this = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ protocolParallelJobNew(const Variant *key, ProtocolCommand *command)
|
|||||||
|
|
||||||
ProtocolParallelJob *this = NULL;
|
ProtocolParallelJob *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(ProtocolParallelJob)
|
OBJ_NEW_BEGIN(ProtocolParallelJob, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
this = OBJ_NEW_ALLOC();
|
this = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ protocolServerNew(const String *name, const String *service, IoRead *read, IoWri
|
|||||||
|
|
||||||
ProtocolServer *this = NULL;
|
ProtocolServer *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(ProtocolServer)
|
OBJ_NEW_BEGIN(ProtocolServer, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
this = OBJ_NEW_ALLOC();
|
this = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -125,7 +125,7 @@ storageReadAzureNew(
|
|||||||
|
|
||||||
StorageRead *this = NULL;
|
StorageRead *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(StorageReadAzure)
|
OBJ_NEW_BEGIN(StorageReadAzure, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
StorageReadAzure *driver = OBJ_NEW_ALLOC();
|
StorageReadAzure *driver = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -719,7 +719,7 @@ storageAzureNew(
|
|||||||
|
|
||||||
Storage *this = NULL;
|
Storage *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(StorageAzure)
|
OBJ_NEW_BEGIN(StorageAzure, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
StorageAzure *driver = OBJ_NEW_ALLOC();
|
StorageAzure *driver = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -274,7 +274,7 @@ storageWriteAzureNew(StorageAzure *storage, const String *name, uint64_t fileId,
|
|||||||
|
|
||||||
StorageWrite *this = NULL;
|
StorageWrite *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(StorageWriteAzure)
|
OBJ_NEW_BEGIN(StorageWriteAzure, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
StorageWriteAzure *driver = OBJ_NEW_ALLOC();
|
StorageWriteAzure *driver = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -132,7 +132,7 @@ storageReadGcsNew(
|
|||||||
|
|
||||||
StorageRead *this = NULL;
|
StorageRead *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(StorageReadGcs)
|
OBJ_NEW_BEGIN(StorageReadGcs, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
StorageReadGcs *driver = OBJ_NEW_ALLOC();
|
StorageReadGcs *driver = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -954,7 +954,7 @@ storageGcsNew(
|
|||||||
|
|
||||||
Storage *this = NULL;
|
Storage *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(StorageGcs)
|
OBJ_NEW_BEGIN(StorageGcs, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
StorageGcs *driver = OBJ_NEW_ALLOC();
|
StorageGcs *driver = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -333,7 +333,7 @@ storageWriteGcsNew(StorageGcs *storage, const String *name, size_t chunkSize)
|
|||||||
|
|
||||||
StorageWrite *this = NULL;
|
StorageWrite *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(StorageWriteGcs)
|
OBJ_NEW_BEGIN(StorageWriteGcs, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
StorageWriteGcs *driver = OBJ_NEW_ALLOC();
|
StorageWriteGcs *driver = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ storageHelperContextInit(void)
|
|||||||
{
|
{
|
||||||
MEM_CONTEXT_BEGIN(memContextTop())
|
MEM_CONTEXT_BEGIN(memContextTop())
|
||||||
{
|
{
|
||||||
MEM_CONTEXT_NEW_BEGIN("StorageHelper")
|
MEM_CONTEXT_NEW_BEGIN(StorageHelper, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
storageHelper.memContext = MEM_CONTEXT_NEW();
|
storageHelper.memContext = MEM_CONTEXT_NEW();
|
||||||
}
|
}
|
||||||
|
@ -223,7 +223,7 @@ storageReadPosixNew(
|
|||||||
|
|
||||||
StorageRead *this = NULL;
|
StorageRead *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(StorageReadPosix)
|
OBJ_NEW_BEGIN(StorageReadPosix, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX, .callbackQty = 1)
|
||||||
{
|
{
|
||||||
StorageReadPosix *driver = OBJ_NEW_ALLOC();
|
StorageReadPosix *driver = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -592,7 +592,7 @@ storagePosixNewInternal(
|
|||||||
// Create the object
|
// Create the object
|
||||||
Storage *this = NULL;
|
Storage *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(StoragePosix)
|
OBJ_NEW_BEGIN(StoragePosix, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
StoragePosix *driver = OBJ_NEW_ALLOC();
|
StoragePosix *driver = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -245,7 +245,7 @@ storageWritePosixNew(
|
|||||||
|
|
||||||
StorageWrite *this = NULL;
|
StorageWrite *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(StorageWritePosix)
|
OBJ_NEW_BEGIN(StorageWritePosix, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX, .callbackQty = 1)
|
||||||
{
|
{
|
||||||
StorageWritePosix *driver = OBJ_NEW_ALLOC();
|
StorageWritePosix *driver = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -114,7 +114,7 @@ storageRemoteFeatureProtocol(PackRead *const param, ProtocolServer *const server
|
|||||||
{
|
{
|
||||||
MEM_CONTEXT_PRIOR_BEGIN()
|
MEM_CONTEXT_PRIOR_BEGIN()
|
||||||
{
|
{
|
||||||
MEM_CONTEXT_NEW_BEGIN("StorageRemoteProtocol")
|
MEM_CONTEXT_NEW_BEGIN(StorageRemoteProtocol, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
storageRemoteProtocolLocal.memContext = memContextCurrent();
|
storageRemoteProtocolLocal.memContext = memContextCurrent();
|
||||||
storageRemoteProtocolLocal.driver = storageDriver(storage);
|
storageRemoteProtocolLocal.driver = storageDriver(storage);
|
||||||
|
@ -232,7 +232,7 @@ storageReadRemoteNew(
|
|||||||
|
|
||||||
StorageReadRemote *this = NULL;
|
StorageReadRemote *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(StorageReadRemote)
|
OBJ_NEW_BEGIN(StorageReadRemote, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
this = OBJ_NEW_ALLOC();
|
this = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -451,7 +451,7 @@ storageRemoteNew(
|
|||||||
|
|
||||||
Storage *this = NULL;
|
Storage *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(StorageRemote)
|
OBJ_NEW_BEGIN(StorageRemote, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
StorageRemote *driver = OBJ_NEW_ALLOC();
|
StorageRemote *driver = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -211,7 +211,7 @@ storageWriteRemoteNew(
|
|||||||
|
|
||||||
StorageWriteRemote *this = NULL;
|
StorageWriteRemote *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(StorageWriteRemote)
|
OBJ_NEW_BEGIN(StorageWriteRemote, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX, .callbackQty = 1)
|
||||||
{
|
{
|
||||||
this = OBJ_NEW_ALLOC();
|
this = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -128,7 +128,7 @@ storageReadS3New(
|
|||||||
|
|
||||||
StorageRead *this = NULL;
|
StorageRead *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(StorageReadS3)
|
OBJ_NEW_BEGIN(StorageReadS3, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
StorageReadS3 *driver = OBJ_NEW_ALLOC();
|
StorageReadS3 *driver = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -1111,7 +1111,7 @@ storageS3New(
|
|||||||
|
|
||||||
Storage *this = NULL;
|
Storage *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(StorageS3)
|
OBJ_NEW_BEGIN(StorageS3, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
StorageS3 *driver = OBJ_NEW_ALLOC();
|
StorageS3 *driver = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -278,7 +278,7 @@ storageWriteS3New(StorageS3 *storage, const String *name, size_t partSize)
|
|||||||
|
|
||||||
StorageWrite *this = NULL;
|
StorageWrite *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(StorageWriteS3)
|
OBJ_NEW_BEGIN(StorageWriteS3, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
StorageWriteS3 *driver = OBJ_NEW_ALLOC();
|
StorageWriteS3 *driver = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -253,7 +253,7 @@ hrnLogReplaceAdd(const char *expression, const char *expressionSub, const char *
|
|||||||
{
|
{
|
||||||
MEM_CONTEXT_BEGIN(memContextTop())
|
MEM_CONTEXT_BEGIN(memContextTop())
|
||||||
{
|
{
|
||||||
MEM_CONTEXT_NEW_BEGIN("HarnessLog")
|
MEM_CONTEXT_NEW_BEGIN(HarnessLog, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
harnessLog.memContext = MEM_CONTEXT_NEW();
|
harnessLog.memContext = MEM_CONTEXT_NEW();
|
||||||
}
|
}
|
||||||
|
@ -1757,7 +1757,7 @@ testRun(void)
|
|||||||
|
|
||||||
Manifest *manifest = NULL;
|
Manifest *manifest = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(Manifest)
|
OBJ_NEW_BEGIN(Manifest, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
manifest = manifestNewInternal();
|
manifest = manifestNewInternal();
|
||||||
manifest->pub.data.backupType = backupTypeFull;
|
manifest->pub.data.backupType = backupTypeFull;
|
||||||
@ -1778,7 +1778,7 @@ testRun(void)
|
|||||||
|
|
||||||
Manifest *manifestResume = NULL;
|
Manifest *manifestResume = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(Manifest)
|
OBJ_NEW_BEGIN(Manifest, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
manifestResume = manifestNewInternal();
|
manifestResume = manifestNewInternal();
|
||||||
manifestResume->pub.info = infoNew(NULL);
|
manifestResume->pub.info = infoNew(NULL);
|
||||||
@ -1912,7 +1912,7 @@ testRun(void)
|
|||||||
// Create manifest with file
|
// Create manifest with file
|
||||||
Manifest *manifest = NULL;
|
Manifest *manifest = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(Manifest)
|
OBJ_NEW_BEGIN(Manifest, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
manifest = manifestNewInternal();
|
manifest = manifestNewInternal();
|
||||||
manifestFileAdd(manifest, &(ManifestFile){.name = STRDEF("pg_data/test")});
|
manifestFileAdd(manifest, &(ManifestFile){.name = STRDEF("pg_data/test")});
|
||||||
|
@ -138,7 +138,7 @@ testManifestMinimal(const String *label, unsigned int pgVersion, const String *p
|
|||||||
|
|
||||||
Manifest *result = NULL;
|
Manifest *result = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(Manifest)
|
OBJ_NEW_BEGIN(Manifest, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
result = manifestNewInternal();
|
result = manifestNewInternal();
|
||||||
result->pub.info = infoNew(NULL);
|
result->pub.info = infoNew(NULL);
|
||||||
@ -1294,7 +1294,7 @@ testRun(void)
|
|||||||
|
|
||||||
Manifest *manifest = NULL;
|
Manifest *manifest = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(Manifest)
|
OBJ_NEW_BEGIN(Manifest, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
manifest = manifestNewInternal();
|
manifest = manifestNewInternal();
|
||||||
manifest->pub.data.pgVersion = PG_VERSION_90;
|
manifest->pub.data.pgVersion = PG_VERSION_90;
|
||||||
@ -2026,7 +2026,7 @@ testRun(void)
|
|||||||
|
|
||||||
Manifest *manifest = NULL;
|
Manifest *manifest = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(Manifest)
|
OBJ_NEW_BEGIN(Manifest, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
manifest = manifestNewInternal();
|
manifest = manifestNewInternal();
|
||||||
manifest->pub.info = infoNew(NULL);
|
manifest->pub.info = infoNew(NULL);
|
||||||
@ -2431,7 +2431,7 @@ testRun(void)
|
|||||||
#define TEST_PGDATA MANIFEST_TARGET_PGDATA "/"
|
#define TEST_PGDATA MANIFEST_TARGET_PGDATA "/"
|
||||||
#define TEST_REPO_PATH STORAGE_REPO_BACKUP "/" TEST_LABEL "/" TEST_PGDATA
|
#define TEST_REPO_PATH STORAGE_REPO_BACKUP "/" TEST_LABEL "/" TEST_PGDATA
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(Manifest)
|
OBJ_NEW_BEGIN(Manifest, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
manifest = manifestNewInternal();
|
manifest = manifestNewInternal();
|
||||||
manifest->pub.info = infoNew(NULL);
|
manifest->pub.info = infoNew(NULL);
|
||||||
|
@ -118,7 +118,7 @@ ioTestFilterSizeNew(const StringId type)
|
|||||||
{
|
{
|
||||||
IoFilter *this = NULL;
|
IoFilter *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(IoTestFilterSize)
|
OBJ_NEW_BEGIN(IoTestFilterSize, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
IoTestFilterSize *driver = OBJ_NEW_ALLOC();
|
IoTestFilterSize *driver = OBJ_NEW_ALLOC();
|
||||||
*driver = (IoTestFilterSize){0};
|
*driver = (IoTestFilterSize){0};
|
||||||
@ -223,7 +223,7 @@ ioTestFilterMultiplyNew(const StringId type, unsigned int multiplier, unsigned i
|
|||||||
{
|
{
|
||||||
IoFilter *this = NULL;
|
IoFilter *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(IoTestFilterMultiply)
|
OBJ_NEW_BEGIN(IoTestFilterMultiply, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
IoTestFilterMultiply *driver = OBJ_NEW_ALLOC();
|
IoTestFilterMultiply *driver = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -13,7 +13,8 @@ testFree(void *thisVoid)
|
|||||||
{
|
{
|
||||||
MemContext *this = thisVoid;
|
MemContext *this = thisVoid;
|
||||||
|
|
||||||
TEST_RESULT_BOOL(this->active, false, "mem context should be inactive while freeing");
|
TEST_RESULT_BOOL(this->active, false, "mem context inactive in callback");
|
||||||
|
|
||||||
TEST_ERROR(memContextFree(this), AssertError, "assertion 'this->active' failed");
|
TEST_ERROR(memContextFree(this), AssertError, "assertion 'this->active' failed");
|
||||||
TEST_ERROR(memContextCallbackSet(this, testFree, this), AssertError, "assertion 'this->active' failed");
|
TEST_ERROR(memContextCallbackSet(this, testFree, this), AssertError, "assertion 'this->active' failed");
|
||||||
TEST_ERROR(memContextSwitch(this), AssertError, "assertion 'this->active' failed");
|
TEST_ERROR(memContextSwitch(this), AssertError, "assertion 'this->active' failed");
|
||||||
@ -72,13 +73,15 @@ testRun(void)
|
|||||||
{
|
{
|
||||||
TEST_TITLE("struct size");
|
TEST_TITLE("struct size");
|
||||||
|
|
||||||
TEST_RESULT_UINT(sizeof(MemContext), TEST_64BIT() ? 72 : 48, "MemContext size");
|
TEST_RESULT_UINT(sizeof(MemContext), TEST_64BIT() ? 24 : 16, "MemContext size");
|
||||||
|
TEST_RESULT_UINT(sizeof(MemContextChildMany), TEST_64BIT() ? 16 : 12, "MemContextChildMany size");
|
||||||
|
TEST_RESULT_UINT(sizeof(MemContextAllocMany), TEST_64BIT() ? 16 : 12, "MemContextAllocMany size");
|
||||||
|
TEST_RESULT_UINT(sizeof(MemContextCallbackOne), TEST_64BIT() ? 16 : 8, "MemContextCallbackOne size");
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
// Make sure top context was created
|
// Make sure top context was created
|
||||||
TEST_RESULT_Z(memContextTop()->name, "TOP", "top context should exist");
|
TEST_RESULT_Z(memContextTop()->name, "TOP", "top context should exist");
|
||||||
TEST_RESULT_INT(memContextTop()->contextChildListSize, 0, "top context should init with zero children");
|
TEST_RESULT_BOOL(memContextTop()->childInitialized, false, "top context should init with zero children");
|
||||||
TEST_RESULT_PTR(memContextTop()->contextChildList, NULL, "top context child list empty");
|
|
||||||
|
|
||||||
// Current context should equal top context
|
// Current context should equal top context
|
||||||
TEST_RESULT_PTR(memContextCurrent(), memContextTop(), "top context == current context");
|
TEST_RESULT_PTR(memContextCurrent(), memContextTop(), "top context == current context");
|
||||||
@ -86,11 +89,13 @@ testRun(void)
|
|||||||
// Context name length errors
|
// Context name length errors
|
||||||
TEST_ERROR(memContextNewP(""), AssertError, "assertion 'name[0] != '\\0'' failed");
|
TEST_ERROR(memContextNewP(""), AssertError, "assertion 'name[0] != '\\0'' failed");
|
||||||
|
|
||||||
MemContext *memContext = memContextNewP("test1");
|
MemContext *memContext = memContextNewP(
|
||||||
|
"test1", .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX, .callbackQty = 1);
|
||||||
memContextKeep();
|
memContextKeep();
|
||||||
TEST_RESULT_Z(memContext->name, "test1", "test1 context name");
|
TEST_RESULT_Z(memContext->name, "test1", "test1 context name");
|
||||||
TEST_RESULT_PTR(memContext->contextParent, memContextTop(), "test1 context parent is top");
|
TEST_RESULT_PTR(memContext->contextParent, memContextTop(), "test1 context parent is top");
|
||||||
TEST_RESULT_INT(memContextTop()->contextChildListSize, MEM_CONTEXT_INITIAL_SIZE, "initial top context child list size");
|
TEST_RESULT_INT(
|
||||||
|
memContextChildMany(memContextTop())->listSize, MEM_CONTEXT_INITIAL_SIZE, "initial top context child list size");
|
||||||
|
|
||||||
memContextSwitch(memContext);
|
memContextSwitch(memContext);
|
||||||
|
|
||||||
@ -99,62 +104,92 @@ testRun(void)
|
|||||||
TEST_RESULT_PTR(memContext, memContextCurrent(), "current context is now test1");
|
TEST_RESULT_PTR(memContext, memContextCurrent(), "current context is now test1");
|
||||||
|
|
||||||
// Create enough mem contexts to use up the initially allocated block
|
// Create enough mem contexts to use up the initially allocated block
|
||||||
|
memContextSwitch(memContextTop());
|
||||||
|
|
||||||
for (int contextIdx = 1; contextIdx < MEM_CONTEXT_INITIAL_SIZE; contextIdx++)
|
for (int contextIdx = 1; contextIdx < MEM_CONTEXT_INITIAL_SIZE; contextIdx++)
|
||||||
{
|
{
|
||||||
memContextSwitch(memContextTop());
|
memContextNewP("test-filler", .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX, .callbackQty = 1);
|
||||||
memContextNewP("test-filler");
|
|
||||||
memContextKeep();
|
memContextKeep();
|
||||||
TEST_RESULT_BOOL(memContextTop()->contextChildList[contextIdx]->active, true, "new context is active");
|
TEST_RESULT_PTR_NE(memContextChildMany(memContextTop())->list[contextIdx], NULL, "new context exists");
|
||||||
TEST_RESULT_Z(memContextTop()->contextChildList[contextIdx]->name, "test-filler", "new context name");
|
TEST_RESULT_BOOL(memContextChildMany(memContextTop())->list[contextIdx]->active, true, "new context is active");
|
||||||
|
TEST_RESULT_Z(memContextChildMany(memContextTop())->list[contextIdx]->name, "test-filler", "new context name");
|
||||||
}
|
}
|
||||||
|
|
||||||
// This forces the child context array to grow
|
// This forces the child context array to grow
|
||||||
memContext = memContextNewP("test5", .allocExtra = 16);
|
memContext = memContextNewP(
|
||||||
|
"test5", .allocExtra = 16, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX, .callbackQty = 1);
|
||||||
TEST_RESULT_PTR(memContextAllocExtra(memContext), memContext + 1, "mem context alloc extra");
|
TEST_RESULT_PTR(memContextAllocExtra(memContext), memContext + 1, "mem context alloc extra");
|
||||||
TEST_RESULT_PTR(memContextFromAllocExtra(memContext + 1), memContext, "mem context from alloc extra");
|
TEST_RESULT_PTR(memContextFromAllocExtra(memContext + 1), memContext, "mem context from alloc extra");
|
||||||
TEST_RESULT_PTR(memContextConstFromAllocExtra(memContext + 1), memContext, "const mem context from alloc extra");
|
TEST_RESULT_PTR(memContextConstFromAllocExtra(memContext + 1), memContext, "const mem context from alloc extra");
|
||||||
memContextKeep();
|
memContextKeep();
|
||||||
TEST_RESULT_INT(memContextTop()->contextChildListSize, MEM_CONTEXT_INITIAL_SIZE * 2, "increased child context list size");
|
TEST_RESULT_INT(
|
||||||
TEST_RESULT_UINT(memContextTop()->contextChildFreeIdx, MEM_CONTEXT_INITIAL_SIZE + 1, "check context free idx");
|
memContextChildMany(memContextTop())->listSize, MEM_CONTEXT_INITIAL_SIZE * 2, "increased child context list size");
|
||||||
|
TEST_RESULT_UINT(memContextChildMany(memContextTop())->freeIdx, MEM_CONTEXT_INITIAL_SIZE + 1, "check context free idx");
|
||||||
|
|
||||||
// Free a context
|
// Free a context
|
||||||
memContextFree(memContextTop()->contextChildList[1]);
|
memContextFree(memContextChildMany(memContextTop())->list[1]);
|
||||||
TEST_RESULT_PTR(memContextTop()->contextChildList[1], NULL, "child context NULL after free");
|
TEST_RESULT_PTR(memContextChildMany(memContextTop())->list[1], NULL, "child context NULL after free");
|
||||||
TEST_RESULT_PTR(memContextCurrent(), memContextTop(), "current context is top");
|
TEST_RESULT_PTR(memContextCurrent(), memContextTop(), "current context is top");
|
||||||
TEST_RESULT_UINT(memContextTop()->contextChildFreeIdx, 1, "check context free idx");
|
TEST_RESULT_UINT(memContextChildMany(memContextTop())->freeIdx, 1, "check context free idx");
|
||||||
|
|
||||||
// Create a new context and it should end up in the same spot
|
// Create a new context and it should end up in the same spot
|
||||||
memContextNewP("test-reuse");
|
MemContext *const memContextOneChild = memContextNewP("test-reuse", .childQty = 1);
|
||||||
memContextKeep();
|
memContextKeep();
|
||||||
TEST_RESULT_BOOL(
|
TEST_RESULT_BOOL(
|
||||||
memContextTop()->contextChildList[1]->active, true, "new context in same index as freed context is active");
|
memContextChildMany(memContextTop())->list[1]->active, true, "new context in same index as freed context is active");
|
||||||
TEST_RESULT_Z(memContextTop()->contextChildList[1]->name, "test-reuse", "new context name");
|
TEST_RESULT_Z(memContextChildMany(memContextTop())->list[1]->name, "test-reuse", "new context name");
|
||||||
TEST_RESULT_UINT(memContextTop()->contextChildFreeIdx, 2, "check context free idx");
|
TEST_RESULT_UINT(memContextChildMany(memContextTop())->freeIdx, 2, "check context free idx");
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
TEST_TITLE("child context in context with only one child allowed");
|
||||||
|
|
||||||
|
TEST_RESULT_VOID(memContextSwitch(memContextOneChild), "switch");
|
||||||
|
MemContext *memContextSingleChild;
|
||||||
|
TEST_ASSIGN(memContextSingleChild, memContextNewP("single-child", .childQty = 1, .allocQty = 1), "new");
|
||||||
|
TEST_RESULT_VOID(memContextKeep(), "keep");
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
TEST_TITLE("child context freed in context with only one child allowed");
|
||||||
|
|
||||||
|
TEST_RESULT_VOID(memContextSwitch(memContextSingleChild), "switch");
|
||||||
|
TEST_RESULT_VOID(memContextNewP("free-child", .childQty = 1), "new");
|
||||||
|
TEST_RESULT_VOID(memContextDiscard(), "discard");
|
||||||
|
|
||||||
|
TEST_RESULT_VOID(memContextSwitch(memContextTop()), "switch to top");
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
// Next context will be at the end
|
// Next context will be at the end
|
||||||
memContextNewP("test-at-end");
|
memContextNewP("test-at-end");
|
||||||
memContextKeep();
|
memContextKeep();
|
||||||
TEST_RESULT_UINT(memContextTop()->contextChildFreeIdx, MEM_CONTEXT_INITIAL_SIZE + 2, "check context free idx");
|
TEST_RESULT_UINT(memContextChildMany(memContextTop())->freeIdx, MEM_CONTEXT_INITIAL_SIZE + 2, "check context free idx");
|
||||||
|
|
||||||
// Create a child context to test recursive free
|
// Create a child context to test recursive free
|
||||||
memContextSwitch(memContextTop()->contextChildList[MEM_CONTEXT_INITIAL_SIZE]);
|
memContextSwitch(memContextChildMany(memContextTop())->list[MEM_CONTEXT_INITIAL_SIZE]);
|
||||||
memContextNewP("test-reuse");
|
memContextNewP("test-reuse", .childQty = 1);
|
||||||
memContextKeep();
|
memContextKeep();
|
||||||
TEST_RESULT_PTR_NE(
|
TEST_RESULT_PTR_NE(
|
||||||
memContextTop()->contextChildList[MEM_CONTEXT_INITIAL_SIZE]->contextChildList, NULL, "context child list is allocated");
|
memContextChildMany(memContextChildMany(memContextTop())->list[MEM_CONTEXT_INITIAL_SIZE])->list, NULL,
|
||||||
|
"context child list is allocated");
|
||||||
TEST_RESULT_INT(
|
TEST_RESULT_INT(
|
||||||
memContextTop()->contextChildList[MEM_CONTEXT_INITIAL_SIZE]->contextChildListSize, MEM_CONTEXT_INITIAL_SIZE,
|
memContextChildMany(memContextChildMany(memContextTop())->list[MEM_CONTEXT_INITIAL_SIZE])->listSize,
|
||||||
"context child list initial size");
|
MEM_CONTEXT_INITIAL_SIZE, "context child list initial size");
|
||||||
|
|
||||||
// This test will change if the contexts above change
|
// This test will change if the contexts above change
|
||||||
TEST_RESULT_UINT(memContextSize(memContextTop()), TEST_64BIT() ? 688 : 448, "check size");
|
TEST_RESULT_UINT(memContextSize(memContextTop()), TEST_64BIT() ? 584 : 376, "check size");
|
||||||
|
|
||||||
TEST_ERROR(
|
TEST_ERROR(
|
||||||
memContextFree(memContextTop()->contextChildList[MEM_CONTEXT_INITIAL_SIZE]),
|
memContextFree(memContextChildMany(memContextTop())->list[MEM_CONTEXT_INITIAL_SIZE]), AssertError,
|
||||||
AssertError, "cannot free current context 'test5'");
|
"cannot free current context 'test5'");
|
||||||
|
|
||||||
TEST_RESULT_VOID(memContextSwitch(memContextTop()), "switch to top");
|
TEST_RESULT_VOID(memContextSwitch(memContextTop()), "switch to top");
|
||||||
TEST_RESULT_VOID(memContextFree(memContextTop()), "free top");
|
TEST_RESULT_VOID(memContextFree(memContextTop()), "free top");
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
TEST_TITLE("alloc extra not aligned");
|
||||||
|
|
||||||
|
TEST_ASSIGN(memContext, memContextNewP("test-alloc", .allocExtra = 7), "no aligned");
|
||||||
|
TEST_RESULT_UINT(memContext->allocExtra, 8, "check");
|
||||||
|
TEST_RESULT_VOID(memContextDiscard(), "discard");
|
||||||
}
|
}
|
||||||
|
|
||||||
// *****************************************************************************************************************************
|
// *****************************************************************************************************************************
|
||||||
@ -172,7 +207,7 @@ testRun(void)
|
|||||||
memContextSwitch(memContextTop());
|
memContextSwitch(memContextTop());
|
||||||
memNewPtrArray(1);
|
memNewPtrArray(1);
|
||||||
|
|
||||||
MemContext *memContext = memContextNewP("test-alloc");
|
MemContext *memContext = memContextNewP("test-alloc", .allocQty = MEM_CONTEXT_QTY_MAX);
|
||||||
TEST_ERROR(memContextSwitchBack(), AssertError, "current context expected but new context 'test-alloc' found");
|
TEST_ERROR(memContextSwitchBack(), AssertError, "current context expected but new context 'test-alloc' found");
|
||||||
memContextKeep();
|
memContextKeep();
|
||||||
memContextSwitch(memContext);
|
memContextSwitch(memContext);
|
||||||
@ -182,7 +217,7 @@ testRun(void)
|
|||||||
memNew(sizeof(size_t));
|
memNew(sizeof(size_t));
|
||||||
|
|
||||||
TEST_RESULT_INT(
|
TEST_RESULT_INT(
|
||||||
memContextCurrent()->allocListSize,
|
memContextAllocMany(memContextCurrent())->listSize,
|
||||||
allocIdx == MEM_CONTEXT_ALLOC_INITIAL_SIZE ? MEM_CONTEXT_ALLOC_INITIAL_SIZE * 2 : MEM_CONTEXT_ALLOC_INITIAL_SIZE,
|
allocIdx == MEM_CONTEXT_ALLOC_INITIAL_SIZE ? MEM_CONTEXT_ALLOC_INITIAL_SIZE * 2 : MEM_CONTEXT_ALLOC_INITIAL_SIZE,
|
||||||
"allocation list size");
|
"allocation list size");
|
||||||
}
|
}
|
||||||
@ -202,46 +237,83 @@ testRun(void)
|
|||||||
TEST_RESULT_INT(expectedTotal, sizeof(size_t), "all bytes are 0xFE in original portion");
|
TEST_RESULT_INT(expectedTotal, sizeof(size_t), "all bytes are 0xFE in original portion");
|
||||||
|
|
||||||
// Free memory
|
// Free memory
|
||||||
TEST_RESULT_UINT(memContextCurrent()->allocFreeIdx, MEM_CONTEXT_ALLOC_INITIAL_SIZE + 2, "check alloc free idx");
|
TEST_RESULT_UINT(
|
||||||
TEST_RESULT_VOID(memFree(MEM_CONTEXT_ALLOC_BUFFER(memContextCurrent()->allocList[0])), "free allocation");
|
memContextAllocMany(memContextCurrent())->freeIdx, MEM_CONTEXT_ALLOC_INITIAL_SIZE + 2, "check alloc free idx");
|
||||||
TEST_RESULT_UINT(memContextCurrent()->allocFreeIdx, 0, "check alloc free idx");
|
TEST_RESULT_VOID(memFree(MEM_CONTEXT_ALLOC_BUFFER(memContextAllocMany(memContextCurrent())->list[0])), "free allocation");
|
||||||
|
TEST_RESULT_UINT(memContextAllocMany(memContextCurrent())->freeIdx, 0, "check alloc free idx");
|
||||||
|
|
||||||
TEST_RESULT_VOID(memFree(MEM_CONTEXT_ALLOC_BUFFER(memContextCurrent()->allocList[1])), "free allocation");
|
TEST_RESULT_VOID(memFree(MEM_CONTEXT_ALLOC_BUFFER(memContextAllocMany(memContextCurrent())->list[1])), "free allocation");
|
||||||
TEST_RESULT_UINT(memContextCurrent()->allocFreeIdx, 0, "check alloc free idx");
|
TEST_RESULT_UINT(memContextAllocMany(memContextCurrent())->freeIdx, 0, "check alloc free idx");
|
||||||
|
|
||||||
TEST_RESULT_VOID(memNew(3), "new allocation");
|
TEST_RESULT_VOID(memNew(3), "new allocation");
|
||||||
TEST_RESULT_UINT(memContextCurrent()->allocFreeIdx, 1, "check alloc free idx");
|
TEST_RESULT_UINT(memContextAllocMany(memContextCurrent())->freeIdx, 1, "check alloc free idx");
|
||||||
|
|
||||||
TEST_RESULT_VOID(memNew(3), "new allocation");
|
TEST_RESULT_VOID(memNew(3), "new allocation");
|
||||||
TEST_RESULT_UINT(memContextCurrent()->allocFreeIdx, 2, "check alloc free idx");
|
TEST_RESULT_UINT(memContextAllocMany(memContextCurrent())->freeIdx, 2, "check alloc free idx");
|
||||||
|
|
||||||
TEST_RESULT_VOID(memNew(3), "new allocation");
|
TEST_RESULT_VOID(memNew(3), "new allocation");
|
||||||
TEST_RESULT_UINT(memContextCurrent()->allocFreeIdx, MEM_CONTEXT_ALLOC_INITIAL_SIZE + 3, "check alloc free idx");
|
TEST_RESULT_UINT(
|
||||||
|
memContextAllocMany(memContextCurrent())->freeIdx, MEM_CONTEXT_ALLOC_INITIAL_SIZE + 3, "check alloc free idx");
|
||||||
|
|
||||||
// This test will change if the allocations above change
|
// This test will change if the allocations above change
|
||||||
TEST_RESULT_UINT(memContextSize(memContextCurrent()), TEST_64BIT() ? 241 : 165, "check size");
|
TEST_RESULT_UINT(memContextSize(memContextCurrent()), TEST_64BIT() ? 209 : 145, "check size");
|
||||||
|
|
||||||
TEST_ERROR(
|
TEST_ERROR(
|
||||||
memFree(NULL), AssertError,
|
memFree(NULL), AssertError,
|
||||||
"assertion '((MemContextAlloc *)buffer - 1) != NULL"
|
"assertion 'alloc != NULL && "
|
||||||
" && (uintptr_t)((MemContextAlloc *)buffer - 1) != (uintptr_t)-sizeof(MemContextAlloc)"
|
"(uintptr_t)alloc != (uintptr_t)-sizeof(MemContextAlloc) && "
|
||||||
" && ((MemContextAlloc *)buffer - 1)->allocIdx <"
|
"alloc->allocIdx < memContextAllocMany(memContextStack[memContextCurrentStackIdx].memContext)->listSize && "
|
||||||
" memContextStack[memContextCurrentStackIdx].memContext->allocListSize"
|
"memContextAllocMany(memContextStack[memContextCurrentStackIdx].memContext)->list[alloc->allocIdx]' failed");
|
||||||
" && memContextStack[memContextCurrentStackIdx].memContext->allocList[((MemContextAlloc *)buffer - 1)->allocIdx]'"
|
|
||||||
" failed");
|
|
||||||
memFree(buffer);
|
memFree(buffer);
|
||||||
|
|
||||||
memContextSwitch(memContextTop());
|
memContextSwitch(memContextTop());
|
||||||
memContextFree(memContext);
|
memContextFree(memContext);
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
TEST_TITLE("mem context with one allocation");
|
||||||
|
|
||||||
|
TEST_ASSIGN(memContext, memContextNewP("test-alloc", .allocQty = 1), "new");
|
||||||
|
TEST_RESULT_VOID(memContextKeep(), "keep new");
|
||||||
|
TEST_RESULT_VOID(memContextSwitch(memContext), "switch to new");
|
||||||
|
|
||||||
|
TEST_ASSIGN(buffer, memNew(100), "new");
|
||||||
|
TEST_ASSIGN(buffer, memResize(buffer, 150), "resize");
|
||||||
|
TEST_RESULT_VOID(memFree(buffer), "free");
|
||||||
|
|
||||||
|
TEST_ASSIGN(buffer, memNew(200), "new");
|
||||||
|
|
||||||
|
// This test will change if the allocations above change
|
||||||
|
TEST_RESULT_UINT(memContextSize(memContextCurrent()), TEST_64BIT() ? 240 : 228, "check size");
|
||||||
|
|
||||||
|
TEST_RESULT_VOID(memContextSwitch(memContextTop()), "switch to top");
|
||||||
|
TEST_RESULT_VOID(memContextFree(memContext), "context free");
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
TEST_TITLE("mem context with one allocation freed before context free");
|
||||||
|
|
||||||
|
TEST_ASSIGN(memContext, memContextNewP("test-alloc", .allocQty = 1), "new");
|
||||||
|
TEST_RESULT_VOID(memContextKeep(), "keep new");
|
||||||
|
TEST_RESULT_VOID(memContextSwitch(memContext), "switch to new");
|
||||||
|
|
||||||
|
TEST_ASSIGN(buffer, memNew(100), "new");
|
||||||
|
TEST_RESULT_VOID(memFree(buffer), "free");
|
||||||
|
|
||||||
|
// This test will change if the allocations above change
|
||||||
|
TEST_RESULT_UINT(memContextSize(memContextCurrent()), TEST_64BIT() ? 32 : 20, "check size");
|
||||||
|
|
||||||
|
TEST_RESULT_VOID(memContextSwitch(memContextTop()), "switch to top");
|
||||||
|
TEST_RESULT_VOID(memContextFree(memContext), "context free");
|
||||||
}
|
}
|
||||||
|
|
||||||
// *****************************************************************************************************************************
|
// *****************************************************************************************************************************
|
||||||
if (testBegin("memContextCallbackSet()"))
|
if (testBegin("memContextCallbackSet()"))
|
||||||
{
|
{
|
||||||
TEST_ERROR(
|
TEST_ERROR(
|
||||||
memContextCallbackSet(memContextTop(), testFree, NULL), AssertError, "top context may not have a callback");
|
memContextCallbackSet(memContextTop(), testFree, NULL), AssertError,
|
||||||
|
"assertion 'this->callbackQty != memQtyNone' failed");
|
||||||
|
|
||||||
MemContext *memContext = memContextNewP("test-callback");
|
MemContext *memContext = memContextNewP(
|
||||||
|
"test-callback", .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX, .callbackQty = 1);
|
||||||
memContextKeep();
|
memContextKeep();
|
||||||
memContextCallbackSet(memContext, testFree, memContext);
|
memContextCallbackSet(memContext, testFree, memContext);
|
||||||
TEST_ERROR(
|
TEST_ERROR(
|
||||||
@ -257,7 +329,8 @@ testRun(void)
|
|||||||
|
|
||||||
// Now test with an error
|
// Now test with an error
|
||||||
// -------------------------------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
memContext = memContextNewP("test-callback-error");
|
memContext = memContextNewP(
|
||||||
|
"test-callback-error", .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX, .callbackQty = 1);
|
||||||
TEST_RESULT_VOID(memContextKeep(), "keep mem context");
|
TEST_RESULT_VOID(memContextKeep(), "keep mem context");
|
||||||
testFreeThrow = true;
|
testFreeThrow = true;
|
||||||
TEST_RESULT_VOID(memContextCallbackSet(memContext, testFree, memContext), " set callback");
|
TEST_RESULT_VOID(memContextCallbackSet(memContext, testFree, memContext), " set callback");
|
||||||
@ -268,7 +341,8 @@ testRun(void)
|
|||||||
if (testBegin("MEM_CONTEXT_BEGIN() and MEM_CONTEXT_END()"))
|
if (testBegin("MEM_CONTEXT_BEGIN() and MEM_CONTEXT_END()"))
|
||||||
{
|
{
|
||||||
memContextSwitch(memContextTop());
|
memContextSwitch(memContextTop());
|
||||||
MemContext *memContext = memContextNewP("test-block");
|
MemContext *memContext = memContextNewP(
|
||||||
|
"test-block", .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX, .callbackQty = 1);
|
||||||
memContextKeep();
|
memContextKeep();
|
||||||
|
|
||||||
// Check normal block
|
// Check normal block
|
||||||
@ -296,12 +370,12 @@ testRun(void)
|
|||||||
// -------------------------------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
MEM_CONTEXT_TEMP_RESET_BEGIN()
|
MEM_CONTEXT_TEMP_RESET_BEGIN()
|
||||||
{
|
{
|
||||||
TEST_RESULT_PTR(MEM_CONTEXT_TEMP()->allocList, NULL, "nothing allocated");
|
TEST_RESULT_BOOL(MEM_CONTEXT_TEMP()->allocInitialized, false, "nothing allocated");
|
||||||
memNew(99);
|
memNew(99);
|
||||||
TEST_RESULT_PTR_NE(MEM_CONTEXT_TEMP()->allocList[0], NULL, "1 allocation");
|
TEST_RESULT_PTR_NE(memContextAllocMany(MEM_CONTEXT_TEMP())->list[0], NULL, "1 allocation");
|
||||||
|
|
||||||
MEM_CONTEXT_TEMP_RESET(1);
|
MEM_CONTEXT_TEMP_RESET(1);
|
||||||
TEST_RESULT_PTR(MEM_CONTEXT_TEMP()->allocList, NULL, "nothing allocated");
|
TEST_RESULT_BOOL(MEM_CONTEXT_TEMP()->allocInitialized, false, "nothing allocated");
|
||||||
}
|
}
|
||||||
MEM_CONTEXT_TEMP_END();
|
MEM_CONTEXT_TEMP_END();
|
||||||
}
|
}
|
||||||
@ -316,7 +390,7 @@ testRun(void)
|
|||||||
|
|
||||||
TEST_RESULT_PTR(memContextCurrent(), memContextTop(), "context is now 'TOP'");
|
TEST_RESULT_PTR(memContextCurrent(), memContextTop(), "context is now 'TOP'");
|
||||||
|
|
||||||
MEM_CONTEXT_NEW_BEGIN(memContextTestName)
|
MEM_CONTEXT_NEW_BEGIN(test-new-block, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
memContext = MEM_CONTEXT_NEW();
|
memContext = MEM_CONTEXT_NEW();
|
||||||
TEST_RESULT_PTR(memContext, memContextCurrent(), "new mem context is current");
|
TEST_RESULT_PTR(memContext, memContextCurrent(), "new mem context is current");
|
||||||
@ -336,7 +410,7 @@ testRun(void)
|
|||||||
|
|
||||||
TRY_BEGIN()
|
TRY_BEGIN()
|
||||||
{
|
{
|
||||||
MEM_CONTEXT_NEW_BEGIN(memContextTestName)
|
MEM_CONTEXT_NEW_BEGIN(test-new-failed-block, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
memContext = MEM_CONTEXT_NEW();
|
memContext = MEM_CONTEXT_NEW();
|
||||||
TEST_RESULT_Z(memContext->name, memContextTestName, "check mem context name");
|
TEST_RESULT_Z(memContext->name, memContextTestName, "check mem context name");
|
||||||
@ -365,36 +439,36 @@ testRun(void)
|
|||||||
void *mem = NULL;
|
void *mem = NULL;
|
||||||
void *mem2 = NULL;
|
void *mem2 = NULL;
|
||||||
|
|
||||||
MEM_CONTEXT_NEW_BEGIN("outer")
|
MEM_CONTEXT_NEW_BEGIN("outer", .childQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
MEM_CONTEXT_TEMP_BEGIN()
|
MEM_CONTEXT_TEMP_BEGIN()
|
||||||
{
|
{
|
||||||
memContextNewP("not-to-be-moved");
|
memContextNewP("not-to-be-moved", .childQty = MEM_CONTEXT_QTY_MAX);
|
||||||
memContextKeep();
|
memContextKeep();
|
||||||
|
|
||||||
MEM_CONTEXT_NEW_BEGIN("inner")
|
MEM_CONTEXT_NEW_BEGIN("inner", .allocQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
memContext = MEM_CONTEXT_NEW();
|
memContext = MEM_CONTEXT_NEW();
|
||||||
mem = memNew(sizeof(int));
|
mem = memNew(sizeof(int));
|
||||||
}
|
}
|
||||||
MEM_CONTEXT_NEW_END();
|
MEM_CONTEXT_NEW_END();
|
||||||
|
|
||||||
TEST_RESULT_PTR(MEM_CONTEXT_ALLOC_BUFFER(memContext->allocList[0]), mem, "check memory allocation");
|
TEST_RESULT_PTR(MEM_CONTEXT_ALLOC_BUFFER(memContextAllocMany(memContext)->list[0]), mem, "check memory allocation");
|
||||||
TEST_RESULT_PTR(memContextCurrent()->contextChildList[1], memContext, "check memory context");
|
TEST_RESULT_PTR(memContextChildMany(memContextCurrent())->list[1], memContext, "check memory context");
|
||||||
|
|
||||||
// Null out the mem context in the parent so the move will fail
|
// Null out the mem context in the parent so the move will fail
|
||||||
memContextCurrent()->contextChildList[1] = NULL;
|
memContextChildMany(memContextCurrent())->list[1] = NULL;
|
||||||
TEST_ERROR(
|
TEST_ERROR(
|
||||||
memContextMove(memContext, memContextPrior()), AssertError,
|
memContextMove(memContext, memContextPrior()), AssertError,
|
||||||
"assertion 'this->contextParent->contextChildList[this->contextParentIdx] == this' failed");
|
"assertion 'memContextChildMany(this->contextParent)->list[this->contextParentIdx] == this' failed");
|
||||||
|
|
||||||
// Set it back so the move will succeed
|
// Set it back so the move will succeed
|
||||||
memContextCurrent()->contextChildList[1] = memContext;
|
memContextChildMany(memContextCurrent())->list[1] = memContext;
|
||||||
TEST_RESULT_VOID(memContextMove(memContext, memContextPrior()), "move context");
|
TEST_RESULT_VOID(memContextMove(memContext, memContextPrior()), "move context");
|
||||||
TEST_RESULT_VOID(memContextMove(memContext, memContextPrior()), "move context again");
|
TEST_RESULT_VOID(memContextMove(memContext, memContextPrior()), "move context again");
|
||||||
|
|
||||||
// Move another context
|
// Move another context
|
||||||
MEM_CONTEXT_NEW_BEGIN("inner2")
|
MEM_CONTEXT_NEW_BEGIN("inner2", .allocQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
memContext2 = MEM_CONTEXT_NEW();
|
memContext2 = MEM_CONTEXT_NEW();
|
||||||
mem2 = memNew(sizeof(int));
|
mem2 = memNew(sizeof(int));
|
||||||
@ -405,13 +479,36 @@ testRun(void)
|
|||||||
}
|
}
|
||||||
MEM_CONTEXT_TEMP_END();
|
MEM_CONTEXT_TEMP_END();
|
||||||
|
|
||||||
TEST_RESULT_PTR(MEM_CONTEXT_ALLOC_BUFFER(memContext->allocList[0]), mem, "check memory allocation");
|
TEST_RESULT_PTR(MEM_CONTEXT_ALLOC_BUFFER(memContextAllocMany(memContext)->list[0]), mem, "check memory allocation");
|
||||||
TEST_RESULT_PTR(memContextCurrent()->contextChildList[1], memContext, "check memory context");
|
TEST_RESULT_PTR(memContextChildMany(memContextCurrent())->list[1], memContext, "check memory context");
|
||||||
|
|
||||||
TEST_RESULT_PTR(MEM_CONTEXT_ALLOC_BUFFER(memContext2->allocList[0]), mem2, "check memory allocation 2");
|
TEST_RESULT_PTR(MEM_CONTEXT_ALLOC_BUFFER(memContextAllocMany(memContext2)->list[0]), mem2, "check memory allocation 2");
|
||||||
TEST_RESULT_PTR(memContextCurrent()->contextChildList[2], memContext2, "check memory context 2");
|
TEST_RESULT_PTR(memContextChildMany(memContextCurrent())->list[2], memContext2, "check memory context 2");
|
||||||
}
|
}
|
||||||
MEM_CONTEXT_NEW_END();
|
MEM_CONTEXT_NEW_END();
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
TEST_TITLE("outer and inner contexts allow one child");
|
||||||
|
|
||||||
|
MemContext *memContextParent1;
|
||||||
|
TEST_ASSIGN(memContextParent1, memContextNewP("parent1", .childQty = 1), "new parent1");
|
||||||
|
TEST_RESULT_VOID(memContextKeep(), "keep parent1");
|
||||||
|
|
||||||
|
TEST_RESULT_VOID(memContextSwitch(memContextParent1), "switch to parent1");
|
||||||
|
|
||||||
|
MemContext *memContextChild;
|
||||||
|
TEST_ASSIGN(memContextChild, memContextNewP("child", .allocQty = 0), "new child");
|
||||||
|
TEST_RESULT_VOID(memContextKeep(), "keep child");
|
||||||
|
|
||||||
|
TEST_RESULT_VOID(memContextSwitch(memContextTop()), "switch to top");
|
||||||
|
|
||||||
|
MemContext *memContextParent2;
|
||||||
|
TEST_ASSIGN(memContextParent2, memContextNewP("parent2", .childQty = 1), "new parent2");
|
||||||
|
TEST_RESULT_VOID(memContextKeep(), "keep parent2");
|
||||||
|
|
||||||
|
TEST_RESULT_VOID(memContextMove(memContextChild, memContextParent2), "move");
|
||||||
|
TEST_RESULT_PTR(memContextChildOne(memContextParent1)->context, NULL, "check parent1");
|
||||||
|
TEST_RESULT_PTR(memContextChildOne(memContextParent2)->context, memContextChild, "check parent2");
|
||||||
}
|
}
|
||||||
|
|
||||||
memContextFree(memContextTop());
|
memContextFree(memContextTop());
|
||||||
|
@ -49,7 +49,7 @@ testObjectNew(void)
|
|||||||
{
|
{
|
||||||
TestObject *this = NULL;
|
TestObject *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(STRINGIFY(TestObject))
|
OBJ_NEW_BEGIN(TestObject)
|
||||||
{
|
{
|
||||||
this = OBJ_NEW_ALLOC();
|
this = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
@ -69,7 +69,7 @@ testObjectContextNew(void)
|
|||||||
{
|
{
|
||||||
TestObjectContext *this = NULL;
|
TestObjectContext *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(STRINGIFY(TestObjectContext))
|
OBJ_NEW_BEGIN(TestObjectContext)
|
||||||
{
|
{
|
||||||
this = OBJ_NEW_ALLOC();
|
this = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -41,7 +41,8 @@ testRun(void)
|
|||||||
TEST_RESULT_VOID(CHECK_SIZE(555), "valid size");
|
TEST_RESULT_VOID(CHECK_SIZE(555), "valid size");
|
||||||
TEST_ERROR(CHECK_SIZE(STRING_SIZE_MAX + 1), AssertError, "string size must be <= 1073741824 bytes");
|
TEST_ERROR(CHECK_SIZE(STRING_SIZE_MAX + 1), AssertError, "string size must be <= 1073741824 bytes");
|
||||||
|
|
||||||
String *string = strNewZ("static string");
|
String *string = NULL;
|
||||||
|
TEST_ASSIGN(string, strNewZ("static string"), "new");
|
||||||
TEST_RESULT_BOOL(string->pub.buffer == (char *)(string + 1), true, "string has fixed buffer");
|
TEST_RESULT_BOOL(string->pub.buffer == (char *)(string + 1), true, "string has fixed buffer");
|
||||||
TEST_RESULT_STR_Z(string, "static string", "new with static string");
|
TEST_RESULT_STR_Z(string, "static string", "new with static string");
|
||||||
TEST_RESULT_UINT(strSize(string), 13, "check size");
|
TEST_RESULT_UINT(strSize(string), 13, "check size");
|
||||||
@ -89,6 +90,15 @@ testRun(void)
|
|||||||
TEST_TITLE("strNewEncode()");
|
TEST_TITLE("strNewEncode()");
|
||||||
|
|
||||||
TEST_RESULT_STR_Z(strNewEncode(encodeBase64, BUFSTRDEF("zz")), "eno=", "encode base64");
|
TEST_RESULT_STR_Z(strNewEncode(encodeBase64, BUFSTRDEF("zz")), "eno=", "encode base64");
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
TEST_TITLE("fixed string large enough to need separate allocation");
|
||||||
|
|
||||||
|
char *compare = memNew(MEM_CONTEXT_ALLOC_EXTRA_MAX + 1);
|
||||||
|
memset(compare, 'A', MEM_CONTEXT_ALLOC_EXTRA_MAX);
|
||||||
|
compare[MEM_CONTEXT_ALLOC_EXTRA_MAX] = '\0';
|
||||||
|
|
||||||
|
TEST_RESULT_STR_Z(strNewZN(compare, MEM_CONTEXT_ALLOC_EXTRA_MAX), compare, "compare");
|
||||||
}
|
}
|
||||||
|
|
||||||
// *****************************************************************************************************************************
|
// *****************************************************************************************************************************
|
||||||
|
@ -16,7 +16,7 @@ testRun(void)
|
|||||||
{
|
{
|
||||||
// Ensure type sizes are as expected
|
// Ensure type sizes are as expected
|
||||||
TEST_RESULT_UINT(sizeof(VariantBoolPub), 8, "check VariantBoolPub size");
|
TEST_RESULT_UINT(sizeof(VariantBoolPub), 8, "check VariantBoolPub size");
|
||||||
TEST_RESULT_UINT(sizeof(VariantBool), TEST_64BIT() ? 16 : 12, "check VariantBool size");
|
TEST_RESULT_UINT(sizeof(VariantBool), 8, "check VariantBool size");
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
Variant *boolean = varNewBool(false);
|
Variant *boolean = varNewBool(false);
|
||||||
@ -57,7 +57,7 @@ testRun(void)
|
|||||||
{
|
{
|
||||||
// Ensure type sizes are as expected
|
// Ensure type sizes are as expected
|
||||||
TEST_RESULT_UINT(sizeof(VariantIntPub), 8, "check VariantIntPub size");
|
TEST_RESULT_UINT(sizeof(VariantIntPub), 8, "check VariantIntPub size");
|
||||||
TEST_RESULT_UINT(sizeof(VariantInt), TEST_64BIT() ? 16 : 12, "check VariantInt size");
|
TEST_RESULT_UINT(sizeof(VariantInt), 8, "check VariantInt size");
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
Variant *integer = varNewInt(44);
|
Variant *integer = varNewInt(44);
|
||||||
@ -96,7 +96,7 @@ testRun(void)
|
|||||||
{
|
{
|
||||||
// Ensure type sizes are as expected
|
// Ensure type sizes are as expected
|
||||||
TEST_RESULT_UINT(sizeof(VariantInt64Pub), TEST_64BIT() ? 16 : 12, "check VariantInt64Pub size");
|
TEST_RESULT_UINT(sizeof(VariantInt64Pub), TEST_64BIT() ? 16 : 12, "check VariantInt64Pub size");
|
||||||
TEST_RESULT_UINT(sizeof(VariantInt64), TEST_64BIT() ? 24 : 16, "check VariantInt64 size");
|
TEST_RESULT_UINT(sizeof(VariantInt64), TEST_64BIT() ? 16 : 12, "check VariantInt64 size");
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
Variant *integer = varNewInt64(44);
|
Variant *integer = varNewInt64(44);
|
||||||
@ -137,7 +137,7 @@ testRun(void)
|
|||||||
{
|
{
|
||||||
// Ensure type sizes are as expected
|
// Ensure type sizes are as expected
|
||||||
TEST_RESULT_UINT(sizeof(VariantUIntPub), 8, "check VariantUIntPub size");
|
TEST_RESULT_UINT(sizeof(VariantUIntPub), 8, "check VariantUIntPub size");
|
||||||
TEST_RESULT_UINT(sizeof(VariantUInt), TEST_64BIT() ? 16 : 12, "check VariantUInt size");
|
TEST_RESULT_UINT(sizeof(VariantUInt), 8, "check VariantUInt size");
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
Variant *unsignedint = varNewUInt(787);
|
Variant *unsignedint = varNewUInt(787);
|
||||||
@ -178,7 +178,7 @@ testRun(void)
|
|||||||
{
|
{
|
||||||
// Ensure type sizes are as expected
|
// Ensure type sizes are as expected
|
||||||
TEST_RESULT_UINT(sizeof(VariantUInt64Pub), TEST_64BIT() ? 16 : 12, "check VariantUInt64Pub size");
|
TEST_RESULT_UINT(sizeof(VariantUInt64Pub), TEST_64BIT() ? 16 : 12, "check VariantUInt64Pub size");
|
||||||
TEST_RESULT_UINT(sizeof(VariantUInt64), TEST_64BIT() ? 24 : 16, "check VariantUInt64 size");
|
TEST_RESULT_UINT(sizeof(VariantUInt64), TEST_64BIT() ? 16 : 12, "check VariantUInt64 size");
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
Variant *uint64 = varNewUInt64(44);
|
Variant *uint64 = varNewUInt64(44);
|
||||||
@ -220,7 +220,7 @@ testRun(void)
|
|||||||
if (testBegin("keyValue"))
|
if (testBegin("keyValue"))
|
||||||
{
|
{
|
||||||
// Ensure type sizes are as expected
|
// Ensure type sizes are as expected
|
||||||
TEST_RESULT_UINT(sizeof(VariantKeyValue), TEST_64BIT() ? 24 : 12, "check VariantKeyValue size");
|
TEST_RESULT_UINT(sizeof(VariantKeyValue), TEST_64BIT() ? 16 : 8, "check VariantKeyValue size");
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
TEST_ERROR(varKv(VARINT(66)), AssertError, "assertion 'varType(this) == varTypeKeyValue' failed");
|
TEST_ERROR(varKv(VARINT(66)), AssertError, "assertion 'varType(this) == varTypeKeyValue' failed");
|
||||||
@ -254,7 +254,7 @@ testRun(void)
|
|||||||
{
|
{
|
||||||
// Ensure type sizes are as expected
|
// Ensure type sizes are as expected
|
||||||
TEST_RESULT_UINT(sizeof(VariantStringPub), TEST_64BIT() ? 16 : 8, "check VariantStringPub size");
|
TEST_RESULT_UINT(sizeof(VariantStringPub), TEST_64BIT() ? 16 : 8, "check VariantStringPub size");
|
||||||
TEST_RESULT_UINT(sizeof(VariantString), TEST_64BIT() ? 24 : 12, "check VariantString size");
|
TEST_RESULT_UINT(sizeof(VariantString), TEST_64BIT() ? 16 : 8, "check VariantString size");
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
TEST_RESULT_STR(varStr(varNewStr(NULL)), NULL, "new null str");
|
TEST_RESULT_STR(varStr(varNewStr(NULL)), NULL, "new null str");
|
||||||
@ -310,13 +310,22 @@ testRun(void)
|
|||||||
TEST_RESULT_PTR(varDup(NULL), NULL, "dup NULL");
|
TEST_RESULT_PTR(varDup(NULL), NULL, "dup NULL");
|
||||||
TEST_RESULT_BOOL(varEq(VARSTRDEF("expect-equal"), VARSTRDEF("expect-equal")), true, "string, string eq");
|
TEST_RESULT_BOOL(varEq(VARSTRDEF("expect-equal"), VARSTRDEF("expect-equal")), true, "string, string eq");
|
||||||
TEST_RESULT_BOOL(varEq(VARSTRDEF("Y"), VARSTRDEF("X")), false, "string, string not eq");
|
TEST_RESULT_BOOL(varEq(VARSTRDEF("Y"), VARSTRDEF("X")), false, "string, string not eq");
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
TEST_TITLE("string large enough to need separate allocation");
|
||||||
|
|
||||||
|
char *compare = memNew(MEM_CONTEXT_ALLOC_EXTRA_MAX + 1);
|
||||||
|
memset(compare, 'A', MEM_CONTEXT_ALLOC_EXTRA_MAX);
|
||||||
|
compare[MEM_CONTEXT_ALLOC_EXTRA_MAX] = '\0';
|
||||||
|
|
||||||
|
TEST_RESULT_STR_Z(varStr(varNewStrZ(compare)), compare, "compare");
|
||||||
}
|
}
|
||||||
|
|
||||||
// *****************************************************************************************************************************
|
// *****************************************************************************************************************************
|
||||||
if (testBegin("VariantList"))
|
if (testBegin("VariantList"))
|
||||||
{
|
{
|
||||||
// Ensure type sizes are as expected
|
// Ensure type sizes are as expected
|
||||||
TEST_RESULT_UINT(sizeof(VariantVariantList), TEST_64BIT() ? 24 : 12, "check VariantVariantList size");
|
TEST_RESULT_UINT(sizeof(VariantVariantList), TEST_64BIT() ? 16 : 8, "check VariantVariantList size");
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
TEST_ERROR(varVarLst(VARINT(66)), AssertError, "assertion 'varType(this) == varTypeVariantList' failed");
|
TEST_ERROR(varVarLst(VARINT(66)), AssertError, "assertion 'varType(this) == varTypeVariantList' failed");
|
||||||
|
@ -949,7 +949,7 @@ testRun(void)
|
|||||||
|
|
||||||
Manifest *manifest = NULL;
|
Manifest *manifest = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(Manifest)
|
OBJ_NEW_BEGIN(Manifest, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
manifest = manifestNewInternal();
|
manifest = manifestNewInternal();
|
||||||
manifest->pub.data.backupOptionOnline = true;
|
manifest->pub.data.backupOptionOnline = true;
|
||||||
@ -1035,7 +1035,7 @@ testRun(void)
|
|||||||
|
|
||||||
Manifest *manifest = NULL;
|
Manifest *manifest = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(Manifest)
|
OBJ_NEW_BEGIN(Manifest, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
manifest = manifestNewInternal();
|
manifest = manifestNewInternal();
|
||||||
manifest->pub.info = infoNew(NULL);
|
manifest->pub.info = infoNew(NULL);
|
||||||
@ -1072,7 +1072,7 @@ testRun(void)
|
|||||||
|
|
||||||
Manifest *manifestPrior = NULL;
|
Manifest *manifestPrior = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(Manifest)
|
OBJ_NEW_BEGIN(Manifest, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
manifestPrior = manifestNewInternal();
|
manifestPrior = manifestNewInternal();
|
||||||
manifestPrior->pub.data.backupLabel = strNewZ("20190101-010101F");
|
manifestPrior->pub.data.backupLabel = strNewZ("20190101-010101F");
|
||||||
|
@ -118,7 +118,7 @@ testIoRateNew(uint64_t bytesPerSec)
|
|||||||
{
|
{
|
||||||
IoFilter *this = NULL;
|
IoFilter *this = NULL;
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(TestIoRate)
|
OBJ_NEW_BEGIN(TestIoRate, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX)
|
||||||
{
|
{
|
||||||
TestIoRate *driver = OBJ_NEW_ALLOC();
|
TestIoRate *driver = OBJ_NEW_ALLOC();
|
||||||
|
|
||||||
|
@ -263,7 +263,7 @@ testRun(void)
|
|||||||
// -------------------------------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
TEST_TITLE("build manifest");
|
TEST_TITLE("build manifest");
|
||||||
|
|
||||||
MemContext *testContext = memContextNewP("test");
|
MemContext *testContext = memContextNewP("test", .childQty = MEM_CONTEXT_QTY_MAX);
|
||||||
memContextKeep();
|
memContextKeep();
|
||||||
Manifest *manifest = NULL;
|
Manifest *manifest = NULL;
|
||||||
TimeMSec timeBegin = timeMSec();
|
TimeMSec timeBegin = timeMSec();
|
||||||
@ -276,7 +276,7 @@ testRun(void)
|
|||||||
MEM_CONTEXT_END();
|
MEM_CONTEXT_END();
|
||||||
|
|
||||||
TEST_LOG_FMT("completed in %ums", (unsigned int)(timeMSec() - timeBegin));
|
TEST_LOG_FMT("completed in %ums", (unsigned int)(timeMSec() - timeBegin));
|
||||||
TEST_LOG_FMT("memory used %zu", memContextSize(testContext));
|
// TEST_LOG_FMT("memory used %zu", memContextSize(testContext));
|
||||||
|
|
||||||
TEST_RESULT_UINT(manifestFileTotal(manifest), driver.fileTotal, " check file total");
|
TEST_RESULT_UINT(manifestFileTotal(manifest), driver.fileTotal, " check file total");
|
||||||
|
|
||||||
@ -295,7 +295,7 @@ testRun(void)
|
|||||||
// -------------------------------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
TEST_TITLE("load manifest");
|
TEST_TITLE("load manifest");
|
||||||
|
|
||||||
testContext = memContextNewP("test");
|
testContext = memContextNewP("test", .childQty = MEM_CONTEXT_QTY_MAX);
|
||||||
memContextKeep();
|
memContextKeep();
|
||||||
timeBegin = timeMSec();
|
timeBegin = timeMSec();
|
||||||
|
|
||||||
@ -306,7 +306,7 @@ testRun(void)
|
|||||||
MEM_CONTEXT_END();
|
MEM_CONTEXT_END();
|
||||||
|
|
||||||
TEST_LOG_FMT("completed in %ums", (unsigned int)(timeMSec() - timeBegin));
|
TEST_LOG_FMT("completed in %ums", (unsigned int)(timeMSec() - timeBegin));
|
||||||
TEST_LOG_FMT("memory used %zu", memContextSize(testContext));
|
// TEST_LOG_FMT("memory used %zu", memContextSize(testContext));
|
||||||
|
|
||||||
TEST_RESULT_UINT(manifestFileTotal(manifest), driver.fileTotal, " check file total");
|
TEST_RESULT_UINT(manifestFileTotal(manifest), driver.fileTotal, " check file total");
|
||||||
|
|
||||||
|
@ -281,7 +281,7 @@ testRun(void)
|
|||||||
|
|
||||||
IoWrite *write = ioFdWriteNewOpen(STRDEF("invalid"), 0, 0);
|
IoWrite *write = ioFdWriteNewOpen(STRDEF("invalid"), 0, 0);
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(ProtocolClient)
|
OBJ_NEW_BEGIN(ProtocolClient, .childQty = MEM_CONTEXT_QTY_MAX, .callbackQty = 1)
|
||||||
{
|
{
|
||||||
protocolHelperClient.client = OBJ_NEW_ALLOC();
|
protocolHelperClient.client = OBJ_NEW_ALLOC();
|
||||||
*protocolHelperClient.client = (ProtocolClient){
|
*protocolHelperClient.client = (ProtocolClient){
|
||||||
@ -290,7 +290,7 @@ testRun(void)
|
|||||||
}
|
}
|
||||||
OBJ_NEW_END();
|
OBJ_NEW_END();
|
||||||
|
|
||||||
OBJ_NEW_BEGIN(Exec)
|
OBJ_NEW_BEGIN(Exec, .childQty = MEM_CONTEXT_QTY_MAX, .callbackQty = 1)
|
||||||
{
|
{
|
||||||
protocolHelperClient.exec = OBJ_NEW_ALLOC();
|
protocolHelperClient.exec = OBJ_NEW_ALLOC();
|
||||||
*protocolHelperClient.exec = (Exec){.name = strNewZ("test"), .command = strNewZ("test"), .processId = INT_MAX};
|
*protocolHelperClient.exec = (Exec){.name = strNewZ("test"), .command = strNewZ("test"), .processId = INT_MAX};
|
||||||
|
Reference in New Issue
Block a user