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 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 date="2022-05-16" version="2.39" title="Verify and File Bundling">
|
||||
|
@ -47,7 +47,7 @@ yamlNew(const Buffer *const buffer)
|
||||
|
||||
Yaml *this = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(Yaml)
|
||||
OBJ_NEW_BEGIN(Yaml, .childQty = MEM_CONTEXT_QTY_MAX, .callbackQty = 1)
|
||||
{
|
||||
// Create object
|
||||
this = OBJ_NEW_ALLOC();
|
||||
|
@ -235,7 +235,7 @@ pageChecksumNew(const unsigned int segmentNo, const unsigned int segmentPageTota
|
||||
|
||||
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();
|
||||
|
||||
|
@ -46,7 +46,7 @@ cmdServerInit(void)
|
||||
{
|
||||
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.processList = lstNewP(sizeof(pid_t));
|
||||
|
@ -167,7 +167,7 @@ bz2CompressNew(int level)
|
||||
|
||||
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();
|
||||
|
||||
|
@ -150,7 +150,7 @@ bz2DecompressNew(void)
|
||||
|
||||
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
|
||||
Bz2Decompress *driver = OBJ_NEW_ALLOC();
|
||||
|
@ -172,7 +172,7 @@ gzCompressNew(int level)
|
||||
|
||||
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();
|
||||
|
||||
|
@ -150,7 +150,7 @@ gzDecompressNew(void)
|
||||
|
||||
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
|
||||
GzDecompress *driver = OBJ_NEW_ALLOC();
|
||||
|
@ -253,7 +253,7 @@ lz4CompressNew(int level)
|
||||
|
||||
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();
|
||||
|
||||
|
@ -163,7 +163,7 @@ lz4DecompressNew(void)
|
||||
|
||||
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();
|
||||
*driver = (Lz4Decompress){0};
|
||||
|
@ -174,7 +174,7 @@ zstCompressNew(int level)
|
||||
|
||||
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();
|
||||
|
||||
|
@ -162,7 +162,7 @@ zstDecompressNew(void)
|
||||
|
||||
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();
|
||||
|
||||
|
@ -421,7 +421,7 @@ cipherBlockNew(CipherMode mode, CipherType cipherType, const Buffer *pass, const
|
||||
// Allocate memory to hold process state
|
||||
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();
|
||||
|
||||
|
@ -185,7 +185,7 @@ cryptoHashNew(const String *type)
|
||||
// Allocate memory to hold process state
|
||||
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();
|
||||
*driver = (CryptoHash){0};
|
||||
|
@ -127,7 +127,7 @@ execNew(const String *command, const StringList *param, const String *name, Time
|
||||
|
||||
Exec *this = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(Exec)
|
||||
OBJ_NEW_BEGIN(Exec, .childQty = MEM_CONTEXT_QTY_MAX, .callbackQty = 1)
|
||||
{
|
||||
this = OBJ_NEW_ALLOC();
|
||||
|
||||
|
@ -29,7 +29,7 @@ iniNew(void)
|
||||
|
||||
Ini *this = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(Ini)
|
||||
OBJ_NEW_BEGIN(Ini, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
this = OBJ_NEW_ALLOC();
|
||||
|
||||
|
@ -94,7 +94,7 @@ ioBufferReadNew(const Buffer *buffer)
|
||||
|
||||
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();
|
||||
|
||||
|
@ -58,7 +58,7 @@ ioBufferWriteNew(Buffer *buffer)
|
||||
|
||||
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();
|
||||
|
||||
|
@ -156,7 +156,7 @@ ioFdReadNew(const String *name, int fd, TimeMSec timeout)
|
||||
|
||||
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();
|
||||
|
||||
|
@ -112,7 +112,7 @@ ioFdWriteNew(const String *name, int fd, TimeMSec timeout)
|
||||
|
||||
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();
|
||||
|
||||
|
@ -110,7 +110,7 @@ ioBufferNew(void)
|
||||
|
||||
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();
|
||||
*driver = (IoBuffer){0};
|
||||
|
@ -63,7 +63,7 @@ ioFilterGroupNew(void)
|
||||
|
||||
IoFilterGroup *this = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(IoFilterGroup)
|
||||
OBJ_NEW_BEGIN(IoFilterGroup, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
this = OBJ_NEW_ALLOC();
|
||||
|
||||
|
@ -54,7 +54,7 @@ ioSinkNew(void)
|
||||
|
||||
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();
|
||||
this = ioFilterNewP(SINK_FILTER_TYPE, driver, NULL, .inOut = ioSinkProcess);
|
||||
|
@ -93,7 +93,7 @@ ioSizeNew(void)
|
||||
|
||||
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();
|
||||
*driver = (IoSize){0};
|
||||
|
@ -43,7 +43,7 @@ httpClientNew(IoClient *ioClient, TimeMSec timeout)
|
||||
|
||||
HttpClient *this = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(HttpClient)
|
||||
OBJ_NEW_BEGIN(HttpClient, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
this = OBJ_NEW_ALLOC();
|
||||
|
||||
|
@ -25,7 +25,7 @@ httpHeaderNew(const StringList *redactList)
|
||||
|
||||
HttpHeader *this = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(HttpHeader)
|
||||
OBJ_NEW_BEGIN(HttpHeader, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
// Allocate state and set context
|
||||
this = OBJ_NEW_ALLOC();
|
||||
@ -54,7 +54,7 @@ httpHeaderDup(const HttpHeader *header, const StringList *redactList)
|
||||
|
||||
if (header != NULL)
|
||||
{
|
||||
OBJ_NEW_BEGIN(HttpHeader)
|
||||
OBJ_NEW_BEGIN(HttpHeader, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
// Allocate state and set context
|
||||
this = OBJ_NEW_ALLOC();
|
||||
|
@ -27,7 +27,7 @@ httpQueryNew(HttpQueryNewParam param)
|
||||
|
||||
HttpQuery *this = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(HttpQuery)
|
||||
OBJ_NEW_BEGIN(HttpQuery, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
// Allocate state and set context
|
||||
this = OBJ_NEW_ALLOC();
|
||||
@ -55,7 +55,7 @@ httpQueryNewStr(const String *query)
|
||||
|
||||
HttpQuery *this = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(HttpQuery)
|
||||
OBJ_NEW_BEGIN(HttpQuery, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
this = OBJ_NEW_ALLOC();
|
||||
|
||||
@ -108,7 +108,7 @@ httpQueryDup(const HttpQuery *query, HttpQueryDupParam param)
|
||||
|
||||
if (query != NULL)
|
||||
{
|
||||
OBJ_NEW_BEGIN(HttpQuery)
|
||||
OBJ_NEW_BEGIN(HttpQuery, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
// Allocate state and set context
|
||||
this = OBJ_NEW_ALLOC();
|
||||
|
@ -192,7 +192,7 @@ httpRequestNew(HttpClient *client, const String *verb, const String *path, HttpR
|
||||
|
||||
HttpRequest *this = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(HttpRequest)
|
||||
OBJ_NEW_BEGIN(HttpRequest, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
this = OBJ_NEW_ALLOC();
|
||||
|
||||
|
@ -220,7 +220,7 @@ httpResponseNew(HttpSession *session, const String *verb, bool contentCache)
|
||||
|
||||
HttpResponse *this = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(HttpResponse)
|
||||
OBJ_NEW_BEGIN(HttpResponse, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
this = OBJ_NEW_ALLOC();
|
||||
|
||||
|
@ -31,7 +31,7 @@ httpSessionNew(HttpClient *httpClient, IoSession *ioSession)
|
||||
|
||||
HttpSession *this = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(HttpSession)
|
||||
OBJ_NEW_BEGIN(HttpSession, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
this = OBJ_NEW_ALLOC();
|
||||
|
||||
|
@ -62,7 +62,7 @@ httpUrlNewParse(const String *const url, HttpUrlNewParseParam param)
|
||||
|
||||
HttpUrl *this = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(HttpUrl)
|
||||
OBJ_NEW_BEGIN(HttpUrl, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
// Allocate state and set context
|
||||
this = OBJ_NEW_ALLOC();
|
||||
|
@ -35,7 +35,7 @@ ioReadNew(void *driver, IoReadInterface interface)
|
||||
|
||||
IoRead *this = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(IoRead)
|
||||
OBJ_NEW_BEGIN(IoRead, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
this = OBJ_NEW_ALLOC();
|
||||
|
||||
|
@ -172,7 +172,7 @@ sckClientNew(const String *const host, const unsigned int port, const TimeMSec t
|
||||
|
||||
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();
|
||||
|
||||
|
@ -155,7 +155,7 @@ sckServerNew(const String *const address, const unsigned int port, const TimeMSe
|
||||
|
||||
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();
|
||||
|
||||
|
@ -178,7 +178,7 @@ sckSessionNew(IoSessionRole role, int fd, const String *host, unsigned int port,
|
||||
|
||||
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();
|
||||
|
||||
|
@ -365,7 +365,7 @@ tlsClientNew(
|
||||
|
||||
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();
|
||||
|
||||
|
@ -282,7 +282,7 @@ tlsServerNew(
|
||||
|
||||
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();
|
||||
|
||||
|
@ -371,7 +371,7 @@ tlsSessionNew(SSL *session, IoSession *ioSession, TimeMSec timeout)
|
||||
|
||||
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();
|
||||
|
||||
|
@ -41,7 +41,7 @@ ioWriteNew(void *driver, IoWriteInterface interface)
|
||||
|
||||
IoWrite *this = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(IoWrite)
|
||||
OBJ_NEW_BEGIN(IoWrite, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
this = OBJ_NEW_ALLOC();
|
||||
|
||||
|
@ -415,7 +415,7 @@ lockAcquire(
|
||||
{
|
||||
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.execId = strDup(execId);
|
||||
|
@ -8,6 +8,7 @@ Memory Context Manager
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "common/error.h"
|
||||
#include "common/macro.h"
|
||||
#include "common/memContext.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
@ -27,52 +28,180 @@ typedef struct MemContextAlloc
|
||||
// Get the allocation header pointer given the allocation buffer pointer
|
||||
#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
|
||||
// belongs to another context. Otherwise, there is likely to be a segfault.
|
||||
#define ASSERT_ALLOC_VALID(alloc) \
|
||||
// Make sure the allocation is valid for the current memory context. This check only works correctly if the allocation is valid and
|
||||
// allocated as one of many but belongs to another context. Otherwise, there is likely to be a segfault.
|
||||
#define ASSERT_ALLOC_MANY_VALID(alloc) \
|
||||
ASSERT( \
|
||||
alloc != NULL && (uintptr_t)alloc != (uintptr_t)-sizeof(MemContextAlloc) && \
|
||||
alloc->allocIdx < memContextStack[memContextCurrentStackIdx].memContext->allocListSize && \
|
||||
memContextStack[memContextCurrentStackIdx].memContext->allocList[alloc->allocIdx]);
|
||||
alloc->allocIdx < memContextAllocMany(memContextStack[memContextCurrentStackIdx].memContext)->listSize && \
|
||||
memContextAllocMany(memContextStack[memContextCurrentStackIdx].memContext)->list[alloc->allocIdx]);
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
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
|
||||
{
|
||||
#ifdef DEBUG
|
||||
const char *name; // Indicates what the context is being used for
|
||||
bool active:1; // Is the context currently active?
|
||||
#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)
|
||||
|
||||
unsigned int contextParentIdx; // Index in the parent context list
|
||||
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
|
||||
|
||||
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.
|
||||
***********************************************************************************************************************************/
|
||||
static MemContext contextTop =
|
||||
static struct MemContextTop
|
||||
{
|
||||
MemContext memContext;
|
||||
MemContextChildMany memContextChildMany;
|
||||
MemContextAllocMany memContextAllocMany;
|
||||
} contextTop =
|
||||
{
|
||||
.memContext =
|
||||
{
|
||||
#ifdef DEBUG
|
||||
.name = "TOP",
|
||||
.active = true,
|
||||
#endif
|
||||
.childQty = memQtyMany,
|
||||
.allocQty = memQtyMany,
|
||||
},
|
||||
};
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
@ -94,7 +223,7 @@ static struct MemContextStack
|
||||
MemContext *memContext;
|
||||
MemContextStackType type;
|
||||
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 memContextMaxStackIdx = 0;
|
||||
@ -209,49 +338,51 @@ memFreeInternal(void *buffer)
|
||||
Find space for a new mem context
|
||||
***********************************************************************************************************************************/
|
||||
static unsigned int
|
||||
memContextNewIndex(MemContext *memContext)
|
||||
memContextNewIndex(MemContext *const memContext, MemContextChildMany *const memContextChild)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(MEM_CONTEXT, memContext);
|
||||
FUNCTION_TEST_PARAM_P(VOID, memContextChild);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(memContext != NULL);
|
||||
ASSERT(memContextChild != NULL);
|
||||
|
||||
// Try to find space for the new context
|
||||
for (; memContext->contextChildFreeIdx < memContext->contextChildListSize; memContext->contextChildFreeIdx++)
|
||||
// Initialize (free space will always be index 0)
|
||||
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;
|
||||
}
|
||||
|
||||
// If no space was found then allocate more
|
||||
if (memContext->contextChildFreeIdx == memContext->contextChildListSize)
|
||||
{
|
||||
// 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
|
||||
if (memContextChild->freeIdx == memContextChild->listSize)
|
||||
{
|
||||
// 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
|
||||
memContext->contextChildList = memReAllocPtrArrayInternal(
|
||||
memContext->contextChildList, memContext->contextChildListSize, contextChildListSizeNew);
|
||||
memContextChild->list = memReAllocPtrArrayInternal(memContextChild->list, memContextChild->listSize, listSizeNew);
|
||||
|
||||
// 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_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_END();
|
||||
|
||||
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
|
||||
ASSERT(name[0] != '\0');
|
||||
|
||||
// Find space for the new context
|
||||
MemContext *contextCurrent = memContextStack[memContextCurrentStackIdx].memContext;
|
||||
unsigned int contextIdx = memContextNewIndex(contextCurrent);
|
||||
// Pad allocExtra so that optional structures will be aligned. There may not be any optional structures but it doesn't seem
|
||||
// worth the cost of checking since memory allocations are aligned so the extra bytes would be wasted anyway.
|
||||
size_t allocExtra = param.allocExtra;
|
||||
|
||||
// Allocate memory for the context
|
||||
contextCurrent->contextChildList[contextIdx] = memAllocInternal(sizeof(MemContext) + param.allocExtra);
|
||||
if (allocExtra % ALIGN_OF(void *) != 0)
|
||||
allocExtra += ALIGN_OFFSET(void *, allocExtra);
|
||||
|
||||
// Get the context
|
||||
MemContext *this = contextCurrent->contextChildList[contextIdx];
|
||||
// Create the new context
|
||||
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)
|
||||
{
|
||||
@ -290,16 +435,37 @@ memContextNew(
|
||||
// Set new context active
|
||||
.active = true,
|
||||
#endif
|
||||
// Set flags
|
||||
.childQty = childQty,
|
||||
.allocQty = allocQty,
|
||||
.callbackQty = callbackQty,
|
||||
|
||||
// Set extra allocation
|
||||
.allocExtra = param.allocExtra,
|
||||
.allocExtra = (uint16_t)allocExtra,
|
||||
|
||||
// Set current context as the parent
|
||||
.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
|
||||
contextCurrent->contextChildFreeIdx++;
|
||||
memContextChild->freeIdx++;
|
||||
}
|
||||
|
||||
// Add to the mem context stack so it will be automatically freed on error if memContextKeep() has not been called
|
||||
memContextMaxStackIdx++;
|
||||
@ -369,20 +535,18 @@ memContextCallbackSet(MemContext *this, void (*callbackFunction)(void *), void *
|
||||
ASSERT(this != NULL);
|
||||
ASSERT(this->active);
|
||||
ASSERT(callbackFunction != NULL);
|
||||
|
||||
// Top context cannot have a callback
|
||||
if (this == &contextTop)
|
||||
THROW(AssertError, "top context may not have a callback");
|
||||
ASSERT(this->active);
|
||||
ASSERT(this->callbackQty != memQtyNone);
|
||||
|
||||
#ifdef DEBUG
|
||||
// Error if callback has already been set - there may be valid use cases for this but error until one is found
|
||||
if (this->callbackFunction)
|
||||
// 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->callbackInitialized)
|
||||
THROW_FMT(AssertError, "callback is already set for context '%s'", this->name);
|
||||
#endif
|
||||
|
||||
// Set callback function and argument
|
||||
this->callbackFunction = callbackFunction;
|
||||
this->callbackArgument = callbackArgument;
|
||||
*(memContextCallbackOne(this)) = (MemContextCallbackOne){.function = callbackFunction, .argument = callbackArgument};
|
||||
this->callbackInitialized = true;
|
||||
|
||||
FUNCTION_TEST_RETURN_VOID();
|
||||
}
|
||||
@ -396,13 +560,12 @@ memContextCallbackClear(MemContext *this)
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(this != NULL);
|
||||
|
||||
// Top context cannot have a callback
|
||||
ASSERT(this != &contextTop);
|
||||
ASSERT(this->callbackQty != memQtyNone);
|
||||
ASSERT(this->active);
|
||||
|
||||
// Clear callback function and argument
|
||||
this->callbackFunction = NULL;
|
||||
this->callbackArgument = NULL;
|
||||
*(memContextCallbackOne(this)) = (MemContextCallbackOne){0};
|
||||
this->callbackInitialized = false;
|
||||
|
||||
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
|
||||
***********************************************************************************************************************************/
|
||||
static MemContextAlloc *
|
||||
memContextAllocNew(size_t size)
|
||||
memContextAllocNew(const size_t size)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(SIZE, size);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
// Find space for the new allocation
|
||||
MemContext *contextCurrent = memContextStack[memContextCurrentStackIdx].memContext;
|
||||
// Allocate memory
|
||||
MemContextAlloc *const result = memAllocInternal(sizeof(MemContextAlloc) + size);
|
||||
|
||||
for (; contextCurrent->allocFreeIdx < contextCurrent->allocListSize; contextCurrent->allocFreeIdx++)
|
||||
if (contextCurrent->allocList[contextCurrent->allocFreeIdx] == NULL)
|
||||
// Find space for the new allocation
|
||||
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;
|
||||
|
||||
// If no space was found then allocate more
|
||||
if (contextCurrent->allocFreeIdx == contextCurrent->allocListSize)
|
||||
{
|
||||
// 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
|
||||
if (contextAlloc->freeIdx == contextAlloc->listSize)
|
||||
{
|
||||
// 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
|
||||
contextCurrent->allocList = memReAllocPtrArrayInternal(
|
||||
contextCurrent->allocList, contextCurrent->allocListSize, allocListSizeNew);
|
||||
contextAlloc->list = memReAllocPtrArrayInternal(contextAlloc->list, contextAlloc->listSize, listSizeNew);
|
||||
|
||||
// Set new size
|
||||
contextCurrent->allocListSize = allocListSizeNew;
|
||||
contextAlloc->listSize = listSizeNew;
|
||||
}
|
||||
}
|
||||
|
||||
// Create new allocation
|
||||
MemContextAlloc *result = memAllocInternal(sizeof(MemContextAlloc) + size);
|
||||
|
||||
*result = (MemContextAlloc)
|
||||
{
|
||||
.allocIdx = contextCurrent->allocFreeIdx,
|
||||
.size = (unsigned int)(sizeof(MemContextAlloc) + size),
|
||||
};
|
||||
// Initialize allocation header
|
||||
*result = (MemContextAlloc){.allocIdx = contextAlloc->freeIdx, .size = (unsigned int)(sizeof(MemContextAlloc) + size)};
|
||||
|
||||
// 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.
|
||||
contextCurrent->allocFreeIdx++;
|
||||
// Update free index to next location. This location may not be free but it is where the search should start next time.
|
||||
contextAlloc->freeIdx++;
|
||||
}
|
||||
|
||||
FUNCTION_TEST_RETURN_TYPE_P(MemContextAlloc, result);
|
||||
}
|
||||
@ -480,14 +660,27 @@ memContextAllocResize(MemContextAlloc *alloc, size_t size)
|
||||
FUNCTION_TEST_PARAM(SIZE, size);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT_ALLOC_VALID(alloc);
|
||||
|
||||
// Resize the allocation
|
||||
alloc = memReAllocInternal(alloc, sizeof(MemContextAlloc) + size);
|
||||
alloc->size = (unsigned int)(sizeof(MemContextAlloc) + size);
|
||||
|
||||
// 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);
|
||||
}
|
||||
@ -500,7 +693,9 @@ memNew(size_t size)
|
||||
FUNCTION_TEST_PARAM(SIZE, size);
|
||||
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
|
||||
memFree(void *buffer)
|
||||
memFree(void *const buffer)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM_P(VOID, buffer);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT_ALLOC_VALID(MEM_CONTEXT_ALLOC_HEADER(buffer));
|
||||
|
||||
// Get the allocation
|
||||
MemContext *contextCurrent = memContextStack[memContextCurrentStackIdx].memContext;
|
||||
MemContextAlloc *alloc = MEM_CONTEXT_ALLOC_HEADER(buffer);
|
||||
MemContext *const contextCurrent = memContextStack[memContextCurrentStackIdx].memContext;
|
||||
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 (alloc->allocIdx < contextCurrent->allocFreeIdx)
|
||||
contextCurrent->allocFreeIdx = alloc->allocIdx;
|
||||
MemContextAllocMany *const contextAlloc = memContextAllocMany(contextCurrent);
|
||||
|
||||
if (alloc->allocIdx < contextAlloc->freeIdx)
|
||||
contextAlloc->freeIdx = alloc->allocIdx;
|
||||
|
||||
// Null the allocation
|
||||
contextAlloc->list[alloc->allocIdx] = NULL;
|
||||
}
|
||||
|
||||
// Free the allocation
|
||||
contextCurrent->allocList[alloc->allocIdx] = NULL;
|
||||
memFreeInternal(alloc);
|
||||
|
||||
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
|
||||
if (this != NULL && this->contextParent != parentNew)
|
||||
{
|
||||
// Null out the context in the old parent
|
||||
ASSERT(this->contextParent->contextChildList[this->contextParentIdx] == this);
|
||||
this->contextParent->contextChildList[this->contextParentIdx] = NULL;
|
||||
ASSERT(this->active);
|
||||
ASSERT(this->contextParent->active);
|
||||
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
|
||||
// index and use it with (what might be) the new pointer.
|
||||
// Null out the context in the old parent
|
||||
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->contextParentIdx = memContextNewIndex(parentNew);
|
||||
parentNew->contextChildList[this->contextParentIdx] = this;
|
||||
}
|
||||
|
||||
FUNCTION_TEST_RETURN_VOID();
|
||||
@ -691,7 +935,7 @@ MemContext *
|
||||
memContextTop(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
|
||||
memContextSize(const MemContext *this)
|
||||
memContextSize(const MemContext *const this)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(MEM_CONTEXT, this);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
// Size of struct and child context/alloc arrays
|
||||
size_t result =
|
||||
sizeof(MemContext) + this->allocExtra + (this->contextChildListSize * sizeof(MemContext *)) +
|
||||
(this->allocListSize * sizeof(MemContextAlloc *));
|
||||
ASSERT(this != NULL);
|
||||
ASSERT(this->active);
|
||||
|
||||
// Add child contexts
|
||||
for (unsigned int contextIdx = 0; contextIdx < this->contextChildListSize; contextIdx++)
|
||||
// Size of struct and extra
|
||||
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])
|
||||
result += memContextSize(this->contextChildList[contextIdx]);
|
||||
if (this->childInitialized)
|
||||
{
|
||||
const MemContextChildOne *const contextChild = (const MemContextChildOne *const)offset;
|
||||
|
||||
if (contextChild->context != NULL)
|
||||
total += memContextSize(contextChild->context);
|
||||
}
|
||||
|
||||
// Add allocations
|
||||
for (unsigned int allocIdx = 0; allocIdx < this->allocListSize; allocIdx++)
|
||||
offset += sizeof(MemContextChildOne);
|
||||
}
|
||||
else if (this->childQty == memQtyMany)
|
||||
{
|
||||
if (this->allocList[allocIdx] != NULL)
|
||||
result += this->allocList[allocIdx]->size;
|
||||
if (this->childInitialized)
|
||||
{
|
||||
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
|
||||
|
||||
// Callback
|
||||
if (this->callbackFunction)
|
||||
if (this->callbackInitialized)
|
||||
{
|
||||
this->callbackFunction(this->callbackArgument);
|
||||
this->callbackFunction = NULL;
|
||||
MemContextCallbackOne *const callback = memContextCallbackOne(this);
|
||||
callback->function(callback->argument);
|
||||
this->callbackInitialized = false;
|
||||
}
|
||||
|
||||
// Child callbacks
|
||||
for (unsigned int contextIdx = 0; contextIdx < this->contextChildListSize; contextIdx++)
|
||||
if (this->childInitialized)
|
||||
{
|
||||
if (this->contextChildList[contextIdx] != NULL)
|
||||
memContextCallbackRecurse(this->contextChildList[contextIdx]);
|
||||
if (this->childQty == memQtyOne)
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
// Helper to free the context and all its children
|
||||
/**********************************************************************************************************************************/
|
||||
static void
|
||||
memContextFreeRecurse(MemContext *const this)
|
||||
{
|
||||
@ -826,55 +1141,95 @@ memContextFreeRecurse(MemContext *const this)
|
||||
|
||||
#ifdef DEBUG
|
||||
// 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);
|
||||
#endif
|
||||
|
||||
// Free child contexts and list
|
||||
if (this->contextChildListSize > 0)
|
||||
{
|
||||
// Free child contexts
|
||||
for (unsigned int contextIdx = 0; contextIdx < this->contextChildListSize; contextIdx++)
|
||||
if (this->childInitialized)
|
||||
{
|
||||
if (this->contextChildList[contextIdx] != NULL)
|
||||
memContextFreeRecurse(this->contextChildList[contextIdx]);
|
||||
if (this->childQty == memQtyOne)
|
||||
{
|
||||
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
|
||||
memFreeInternal(this->contextChildList);
|
||||
this->contextChildListSize = 0;
|
||||
memFreeInternal(memContextChildMany(this)->list);
|
||||
}
|
||||
}
|
||||
|
||||
// Free memory allocations and list
|
||||
if (this->allocListSize > 0)
|
||||
if (this->allocInitialized)
|
||||
{
|
||||
for (unsigned int allocIdx = 0; allocIdx < this->allocListSize; allocIdx++)
|
||||
if (this->allocList[allocIdx] != NULL)
|
||||
memFreeInternal(this->allocList[allocIdx]);
|
||||
ASSERT(this->allocQty != memQtyNone);
|
||||
|
||||
memFreeInternal(this->allocList);
|
||||
this->allocListSize = 0;
|
||||
if (this->allocQty == memQtyOne)
|
||||
{
|
||||
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)
|
||||
if (this != &contextTop)
|
||||
if (this != memContextTop())
|
||||
{
|
||||
ASSERT(this->contextParent != NULL);
|
||||
|
||||
this->contextParent->contextChildList[this->contextParentIdx] = NULL;
|
||||
memFreeInternal(this);
|
||||
}
|
||||
#ifdef DEBUG
|
||||
// Else make the top mem context active again
|
||||
if (this->contextParent->childQty == memQtyOne)
|
||||
memContextChildOne(this->contextParent)->context = NULL;
|
||||
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
|
||||
}
|
||||
|
||||
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, ...) \
|
||||
do \
|
||||
{ \
|
||||
MemContext *MEM_CONTEXT_NEW() = memContextNewP(memContextName, __VA_ARGS__); \
|
||||
MemContext *MEM_CONTEXT_NEW() = memContextNewP(STRINGIFY(memContextName), __VA_ARGS__); \
|
||||
memContextSwitch(MEM_CONTEXT_NEW());
|
||||
|
||||
#define MEM_CONTEXT_NEW_ALLOC() \
|
||||
@ -150,7 +150,8 @@ MEM_CONTEXT_TEMP_END();
|
||||
#define MEM_CONTEXT_TEMP_BEGIN() \
|
||||
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());
|
||||
|
||||
#define MEM_CONTEXT_TEMP_RESET_BEGIN() \
|
||||
@ -166,7 +167,7 @@ MEM_CONTEXT_TEMP_END();
|
||||
{ \
|
||||
memContextSwitchBack(); \
|
||||
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()); \
|
||||
MEM_CONTEXT_TEMP_loopTotal = 0; \
|
||||
} \
|
||||
@ -204,9 +205,18 @@ Use the MEM_CONTEXT*() macros when possible rather than reimplement the boilerpl
|
||||
typedef struct MemContextNewParam
|
||||
{
|
||||
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
|
||||
} 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
|
||||
#define memContextNewP(name, ...) \
|
||||
memContextNew(name, (MemContextNewParam){VAR_PARAM_INIT, __VA_ARGS__})
|
||||
|
@ -74,7 +74,7 @@ regExpNew(const String *expression)
|
||||
|
||||
RegExp *this = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(RegExp)
|
||||
OBJ_NEW_BEGIN(RegExp, .childQty = MEM_CONTEXT_QTY_MAX, .callbackQty = 1)
|
||||
{
|
||||
this = OBJ_NEW_ALLOC();
|
||||
*this = (RegExp){{0}}; // Extra braces are required for older gcc versions
|
||||
|
@ -37,7 +37,7 @@ statInit(void)
|
||||
|
||||
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.stat = lstNewP(sizeof(Stat), .sortOrder = sortOrderAsc, .comparator = lstComparatorStr);
|
||||
|
@ -39,7 +39,7 @@ bufNew(size_t size)
|
||||
|
||||
Buffer *this = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(Buffer)
|
||||
OBJ_NEW_BEGIN(Buffer, .allocQty = 1)
|
||||
{
|
||||
// Create object
|
||||
this = OBJ_NEW_ALLOC();
|
||||
|
@ -92,7 +92,7 @@ jsonReadNew(const String *const json)
|
||||
|
||||
JsonRead *this = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(JsonRead)
|
||||
OBJ_NEW_BEGIN(JsonRead, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
this = OBJ_NEW_ALLOC();
|
||||
|
||||
@ -1309,7 +1309,7 @@ jsonWriteNew(JsonWriteNewParam param)
|
||||
|
||||
JsonWrite *this = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(JsonWrite)
|
||||
OBJ_NEW_BEGIN(JsonWrite, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
this = OBJ_NEW_ALLOC();
|
||||
|
||||
|
@ -36,7 +36,7 @@ kvNew(void)
|
||||
|
||||
KeyValue *this = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(KeyValue)
|
||||
OBJ_NEW_BEGIN(KeyValue, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
// Allocate state and set context
|
||||
this = OBJ_NEW_ALLOC();
|
||||
|
@ -35,7 +35,7 @@ lstNew(size_t itemSize, ListParam param)
|
||||
|
||||
List *this = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(List)
|
||||
OBJ_NEW_BEGIN(List, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
// Create object
|
||||
this = OBJ_NEW_ALLOC();
|
||||
|
@ -29,8 +29,11 @@ OBJ_NEW_BEGIN(MyObj)
|
||||
}
|
||||
OBJ_NEW_END();
|
||||
***********************************************************************************************************************************/
|
||||
#define OBJ_NEW_BEGIN(type) \
|
||||
MEM_CONTEXT_NEW_BEGIN(STRINGIFY(type), .allocExtra = sizeof(type))
|
||||
#define OBJ_NEW_EXTRA_BEGIN(type, extra, ...) \
|
||||
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() \
|
||||
memContextAllocExtra(memContextCurrent())
|
||||
|
@ -336,7 +336,7 @@ pckReadNewInternal(void)
|
||||
|
||||
PackRead *this = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(PackRead)
|
||||
OBJ_NEW_BEGIN(PackRead, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
this = OBJ_NEW_ALLOC();
|
||||
|
||||
@ -1295,7 +1295,7 @@ pckWriteNewInternal(void)
|
||||
|
||||
PackWrite *this = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(PackWrite)
|
||||
OBJ_NEW_BEGIN(PackWrite, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
this = OBJ_NEW_ALLOC();
|
||||
|
||||
|
@ -66,7 +66,6 @@ Object type
|
||||
struct String
|
||||
{
|
||||
StringPub pub; // Publicly accessible variables
|
||||
MemContext *memContext; // Required for dynamically allocated strings
|
||||
};
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
@ -75,8 +74,11 @@ strNew(void)
|
||||
{
|
||||
FUNCTION_TEST_VOID();
|
||||
|
||||
// Create object
|
||||
String *this = memNew(sizeof(String));
|
||||
String *this = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(String, .allocQty = 1)
|
||||
{
|
||||
this = OBJ_NEW_ALLOC();
|
||||
|
||||
*this = (String)
|
||||
{
|
||||
@ -85,8 +87,9 @@ strNew(void)
|
||||
// Set empty so nothing is allocated until needed
|
||||
.buffer = STR_EMPTY_BUFFER,
|
||||
},
|
||||
.memContext = memContextCurrent(),
|
||||
};
|
||||
}
|
||||
OBJ_NEW_END();
|
||||
|
||||
FUNCTION_TEST_RETURN(STRING, this);
|
||||
}
|
||||
@ -103,7 +106,34 @@ strNewFixed(const size_t 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)
|
||||
{
|
||||
@ -112,8 +142,9 @@ strNewFixed(const size_t size)
|
||||
.size = (unsigned int)size,
|
||||
.buffer = STR_FIXED_BUFFER,
|
||||
},
|
||||
.memContext = memContextCurrent(),
|
||||
};
|
||||
}
|
||||
OBJ_NEW_END();
|
||||
|
||||
FUNCTION_TEST_RETURN(STRING, this);
|
||||
}
|
||||
@ -330,14 +361,14 @@ strResize(String *this, size_t requested)
|
||||
if (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())
|
||||
this->pub.buffer = memNew(strSize(this) + this->pub.extra + 1);
|
||||
else
|
||||
this->pub.buffer = memResize(this->pub.buffer, strSize(this) + this->pub.extra + 1);
|
||||
}
|
||||
MEM_CONTEXT_END();
|
||||
MEM_CONTEXT_OBJ_END();
|
||||
}
|
||||
|
||||
FUNCTION_TEST_RETURN_VOID();
|
||||
@ -1065,28 +1096,3 @@ strSizeFormat(const uint64_t size)
|
||||
|
||||
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
|
||||
***********************************************************************************************************************************/
|
||||
void strFree(String *this);
|
||||
__attribute__((always_inline)) static inline void
|
||||
strFree(String *const this)
|
||||
{
|
||||
objFree(this);
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Macros for constant strings
|
||||
|
@ -37,51 +37,43 @@ struct Variant
|
||||
typedef struct VariantBool
|
||||
{
|
||||
VariantBoolPub pub; // Publicly accessible variables
|
||||
MemContext *memContext;
|
||||
} VariantBool;
|
||||
|
||||
typedef struct VariantInt
|
||||
{
|
||||
VariantIntPub pub; // Publicly accessible variables
|
||||
MemContext *memContext;
|
||||
} VariantInt;
|
||||
|
||||
typedef struct VariantInt64
|
||||
{
|
||||
VariantInt64Pub pub; // Publicly accessible variables
|
||||
MemContext *memContext;
|
||||
} VariantInt64;
|
||||
|
||||
typedef struct VariantKeyValue
|
||||
{
|
||||
VARIANT_COMMON
|
||||
KeyValue *data; // KeyValue data
|
||||
MemContext *memContext;
|
||||
} VariantKeyValue;
|
||||
|
||||
typedef struct VariantString
|
||||
{
|
||||
VariantStringPub pub; // Publicly accessible variables
|
||||
MemContext *memContext;
|
||||
} VariantString;
|
||||
|
||||
typedef struct VariantUInt
|
||||
{
|
||||
VariantUIntPub pub; // Publicly accessible variables
|
||||
MemContext *memContext;
|
||||
} VariantUInt;
|
||||
|
||||
typedef struct VariantUInt64
|
||||
{
|
||||
VariantUInt64Pub pub; // Publicly accessible variables
|
||||
MemContext *memContext;
|
||||
} VariantUInt64;
|
||||
|
||||
typedef struct VariantVariantList
|
||||
{
|
||||
VARIANT_COMMON
|
||||
VariantList *data; // VariantList data
|
||||
MemContext *memContext;
|
||||
} VariantVariantList;
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
@ -127,16 +119,7 @@ varDup(const Variant *this)
|
||||
|
||||
case varTypeKeyValue:
|
||||
{
|
||||
VariantKeyValue *keyValue = memNew(sizeof(VariantKeyValue));
|
||||
|
||||
*keyValue = (VariantKeyValue)
|
||||
{
|
||||
.memContext = memContextCurrent(),
|
||||
.type = varTypeKeyValue,
|
||||
.data = kvDup(varKv(this)),
|
||||
};
|
||||
|
||||
result = (Variant *)keyValue;
|
||||
result = varNewKv(kvDup(varKv(this)));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -224,8 +207,11 @@ varNewBool(bool data)
|
||||
FUNCTION_TEST_PARAM(BOOL, data);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
// Allocate memory for the variant and set the type and data
|
||||
VariantBool *this = memNew(sizeof(VariantBool));
|
||||
VariantBool *this = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(VariantBool)
|
||||
{
|
||||
this = OBJ_NEW_ALLOC();
|
||||
|
||||
*this = (VariantBool)
|
||||
{
|
||||
@ -234,8 +220,9 @@ varNewBool(bool data)
|
||||
.type = varTypeBool,
|
||||
.data = data,
|
||||
},
|
||||
.memContext = memContextCurrent(),
|
||||
};
|
||||
}
|
||||
OBJ_NEW_END();
|
||||
|
||||
FUNCTION_TEST_RETURN(VARIANT, (Variant *)this);
|
||||
}
|
||||
@ -329,8 +316,11 @@ varNewInt(int data)
|
||||
FUNCTION_TEST_PARAM(INT, data);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
// Allocate memory for the variant and set the type and data
|
||||
VariantInt *this = memNew(sizeof(VariantInt));
|
||||
VariantInt *this = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(VariantInt)
|
||||
{
|
||||
this = OBJ_NEW_ALLOC();
|
||||
|
||||
*this = (VariantInt)
|
||||
{
|
||||
@ -339,8 +329,9 @@ varNewInt(int data)
|
||||
.type = varTypeInt,
|
||||
.data = data,
|
||||
},
|
||||
.memContext = memContextCurrent(),
|
||||
};
|
||||
}
|
||||
OBJ_NEW_END();
|
||||
|
||||
FUNCTION_TEST_RETURN(VARIANT, (Variant *)this);
|
||||
}
|
||||
@ -441,8 +432,11 @@ varNewInt64(int64_t data)
|
||||
FUNCTION_TEST_PARAM(INT64, data);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
// Allocate memory for the variant and set the type and data
|
||||
VariantInt64 *this = memNew(sizeof(VariantInt64));
|
||||
VariantInt64 *this = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(VariantInt64)
|
||||
{
|
||||
this = OBJ_NEW_ALLOC();
|
||||
|
||||
*this = (VariantInt64)
|
||||
{
|
||||
@ -451,8 +445,9 @@ varNewInt64(int64_t data)
|
||||
.type = varTypeInt64,
|
||||
.data = data,
|
||||
},
|
||||
.memContext = memContextCurrent(),
|
||||
};
|
||||
}
|
||||
OBJ_NEW_END();
|
||||
|
||||
FUNCTION_TEST_RETURN(VARIANT, (Variant *)this);
|
||||
}
|
||||
@ -537,8 +532,11 @@ varNewUInt(unsigned int data)
|
||||
FUNCTION_TEST_PARAM(UINT, data);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
// Allocate memory for the variant and set the type and data
|
||||
VariantUInt *this = memNew(sizeof(VariantUInt));
|
||||
VariantUInt *this = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(VariantUInt)
|
||||
{
|
||||
this = OBJ_NEW_ALLOC();
|
||||
|
||||
*this = (VariantUInt)
|
||||
{
|
||||
@ -547,8 +545,9 @@ varNewUInt(unsigned int data)
|
||||
.type = varTypeUInt,
|
||||
.data = data,
|
||||
},
|
||||
.memContext = memContextCurrent(),
|
||||
};
|
||||
}
|
||||
OBJ_NEW_END();
|
||||
|
||||
FUNCTION_TEST_RETURN(VARIANT, (Variant *)this);
|
||||
}
|
||||
@ -658,8 +657,11 @@ varNewUInt64(uint64_t data)
|
||||
FUNCTION_TEST_PARAM(UINT64, data);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
// Allocate memory for the variant and set the type and data
|
||||
VariantUInt64 *this = memNew(sizeof(VariantUInt64));
|
||||
VariantUInt64 *this = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(VariantUInt64)
|
||||
{
|
||||
this = OBJ_NEW_ALLOC();
|
||||
|
||||
*this = (VariantUInt64)
|
||||
{
|
||||
@ -668,8 +670,9 @@ varNewUInt64(uint64_t data)
|
||||
.type = varTypeUInt64,
|
||||
.data = data,
|
||||
},
|
||||
.memContext = memContextCurrent(),
|
||||
};
|
||||
}
|
||||
OBJ_NEW_END();
|
||||
|
||||
FUNCTION_TEST_RETURN(VARIANT, (Variant *)this);
|
||||
}
|
||||
@ -766,17 +769,21 @@ varNewKv(KeyValue *data)
|
||||
FUNCTION_TEST_PARAM(KEY_VALUE, data);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
// Allocate memory for the variant and set the type and data
|
||||
VariantKeyValue *this = memNew(sizeof(VariantKeyValue));
|
||||
VariantKeyValue *this = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(VariantKeyValue, .childQty = 1)
|
||||
{
|
||||
this = OBJ_NEW_ALLOC();
|
||||
|
||||
*this = (VariantKeyValue)
|
||||
{
|
||||
.memContext = memContextCurrent(),
|
||||
.type = varTypeKeyValue,
|
||||
};
|
||||
|
||||
if (data != NULL)
|
||||
this->data = kvMove(data, memContextCurrent());
|
||||
}
|
||||
OBJ_NEW_END();
|
||||
|
||||
FUNCTION_TEST_RETURN(VARIANT, (Variant *)this);
|
||||
}
|
||||
@ -808,8 +815,36 @@ varNewStr(const String *data)
|
||||
FUNCTION_TEST_PARAM(STRING, data);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
// Allocate memory for the variant
|
||||
VariantString *this = memNew(sizeof(VariantString) + (data != NULL ? sizeof(StringPub) + strSize(data) + 1 : 0));
|
||||
VariantString *this = NULL;
|
||||
|
||||
// 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)
|
||||
{
|
||||
@ -817,7 +852,6 @@ varNewStr(const String *data)
|
||||
{
|
||||
.type = varTypeString,
|
||||
},
|
||||
.memContext = memContextCurrent(),
|
||||
};
|
||||
|
||||
if (data != NULL)
|
||||
@ -837,6 +871,8 @@ varNewStr(const String *data)
|
||||
strncpy(pubData->buffer, strZ(data), strSize(data));
|
||||
pubData->buffer[strSize(data)] = '\0';
|
||||
}
|
||||
}
|
||||
OBJ_NEW_END();
|
||||
|
||||
FUNCTION_TEST_RETURN(VARIANT, (Variant *)this);
|
||||
}
|
||||
@ -942,17 +978,21 @@ varNewVarLst(const VariantList *data)
|
||||
FUNCTION_TEST_PARAM(VARIANT_LIST, data);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
// Allocate memory for the variant and set the type and data
|
||||
VariantVariantList *this = memNew(sizeof(VariantVariantList));
|
||||
VariantVariantList *this = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(VariantVariantList, .childQty = 1)
|
||||
{
|
||||
this = OBJ_NEW_ALLOC();
|
||||
|
||||
*this = (VariantVariantList)
|
||||
{
|
||||
.memContext = memContextCurrent(),
|
||||
.type = varTypeVariantList,
|
||||
};
|
||||
|
||||
if (data != NULL)
|
||||
this->data = varLstDup(data);
|
||||
}
|
||||
OBJ_NEW_END();
|
||||
|
||||
FUNCTION_TEST_RETURN(VARIANT, (Variant *)this);
|
||||
}
|
||||
@ -1014,62 +1054,3 @@ varToLog(const Variant *this)
|
||||
|
||||
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
|
||||
***********************************************************************************************************************************/
|
||||
void varFree(Variant *this);
|
||||
__attribute__((always_inline)) static inline void
|
||||
varFree(Variant *const this)
|
||||
{
|
||||
objFree(this);
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Macros for constant variants
|
||||
|
@ -332,7 +332,7 @@ xmlDocumentNew(const String *rootName)
|
||||
// Create object
|
||||
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();
|
||||
|
||||
@ -368,7 +368,7 @@ xmlDocumentNewBuf(const Buffer *buffer)
|
||||
// Create object
|
||||
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 = (XmlDocument){{0}}; // Extra braces are required for older gcc versions
|
||||
|
@ -34,7 +34,7 @@ userInitInternal(void)
|
||||
|
||||
MEM_CONTEXT_BEGIN(memContextTop())
|
||||
{
|
||||
MEM_CONTEXT_NEW_BEGIN("UserLocalData")
|
||||
MEM_CONTEXT_NEW_BEGIN(UserLocalData, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
userLocalData.memContext = MEM_CONTEXT_NEW();
|
||||
|
||||
|
@ -32,7 +32,7 @@ waitNew(TimeMSec waitTime)
|
||||
// Allocate wait object
|
||||
Wait *this = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(Wait)
|
||||
OBJ_NEW_BEGIN(Wait, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
// Create object
|
||||
this = OBJ_NEW_ALLOC();
|
||||
|
@ -1380,7 +1380,7 @@ configParse(const Storage *storage, unsigned int argListSize, const char *argLis
|
||||
// Create the config struct
|
||||
Config *config;
|
||||
|
||||
OBJ_NEW_BEGIN(Config)
|
||||
OBJ_NEW_BEGIN(Config, .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
config = OBJ_NEW_ALLOC();
|
||||
|
||||
|
@ -76,7 +76,7 @@ dbNew(PgClient *client, ProtocolClient *remoteClient, const Storage *const stora
|
||||
|
||||
Db *this = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(Db)
|
||||
OBJ_NEW_BEGIN(Db, .childQty = MEM_CONTEXT_QTY_MAX, .callbackQty = 1)
|
||||
{
|
||||
this = OBJ_NEW_ALLOC();
|
||||
|
||||
|
@ -121,7 +121,7 @@ infoNew(const String *cipherPass)
|
||||
|
||||
Info *this = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(Info)
|
||||
OBJ_NEW_BEGIN(Info, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
this = infoNewInternal();
|
||||
|
||||
@ -256,7 +256,7 @@ infoNewLoad(IoRead *read, InfoLoadNewCallback *callbackFunction, void *callbackD
|
||||
|
||||
Info *this = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(Info)
|
||||
OBJ_NEW_BEGIN(Info, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
this = infoNewInternal();
|
||||
|
||||
|
@ -69,7 +69,7 @@ infoArchiveNew(unsigned int pgVersion, uint64_t pgSystemId, const String *cipher
|
||||
|
||||
InfoArchive *this = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(InfoArchive)
|
||||
OBJ_NEW_BEGIN(InfoArchive, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
this = infoArchiveNewInternal();
|
||||
|
||||
@ -94,7 +94,7 @@ infoArchiveNewLoad(IoRead *read)
|
||||
|
||||
InfoArchive *this = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(InfoArchive)
|
||||
OBJ_NEW_BEGIN(InfoArchive, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
this = infoArchiveNewInternal();
|
||||
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;
|
||||
|
||||
OBJ_NEW_BEGIN(InfoBackup)
|
||||
OBJ_NEW_BEGIN(InfoBackup, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
this = infoBackupNewInternal();
|
||||
|
||||
@ -225,7 +225,7 @@ infoBackupNewLoad(IoRead *read)
|
||||
|
||||
InfoBackup *this = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(InfoBackup)
|
||||
OBJ_NEW_BEGIN(InfoBackup, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
this = infoBackupNewInternal();
|
||||
this->pub.infoPg = infoPgNewLoad(read, infoPgBackup, infoBackupLoadCallback, this);
|
||||
|
@ -69,7 +69,7 @@ infoPgNew(InfoPgType type, const String *cipherPassSub)
|
||||
|
||||
InfoPg *this = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(InfoPg)
|
||||
OBJ_NEW_BEGIN(InfoPg, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
this = infoPgNewInternal(type);
|
||||
this->pub.info = infoNew(cipherPassSub);
|
||||
@ -164,7 +164,7 @@ infoPgNewLoad(IoRead *read, InfoPgType type, InfoLoadNewCallback *callbackFuncti
|
||||
|
||||
InfoPg *this = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(InfoPg)
|
||||
OBJ_NEW_BEGIN(InfoPg, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
this = infoPgNewInternal(type);
|
||||
|
||||
|
@ -1112,7 +1112,7 @@ manifestNewBuild(
|
||||
|
||||
Manifest *this = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(Manifest)
|
||||
OBJ_NEW_BEGIN(Manifest, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
this = manifestNewInternal();
|
||||
this->pub.info = infoNew(NULL);
|
||||
@ -2050,14 +2050,14 @@ manifestNewLoad(IoRead *read)
|
||||
|
||||
Manifest *this = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(Manifest)
|
||||
OBJ_NEW_BEGIN(Manifest, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
this = manifestNewInternal();
|
||||
|
||||
// Load the manifest
|
||||
ManifestLoadData loadData =
|
||||
{
|
||||
.memContext = memContextNewP("load"),
|
||||
.memContext = memContextNewP("load", .childQty = MEM_CONTEXT_QTY_MAX),
|
||||
.manifest = this,
|
||||
};
|
||||
|
||||
|
@ -55,7 +55,7 @@ pgClientNew(const String *host, const unsigned int port, const String *database,
|
||||
|
||||
PgClient *this = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(PgClient)
|
||||
OBJ_NEW_BEGIN(PgClient, .childQty = MEM_CONTEXT_QTY_MAX, .callbackQty = 1)
|
||||
{
|
||||
this = OBJ_NEW_ALLOC();
|
||||
|
||||
|
@ -90,7 +90,7 @@ protocolClientNew(const String *name, const String *service, IoRead *read, IoWri
|
||||
|
||||
ProtocolClient *this = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(ProtocolClient)
|
||||
OBJ_NEW_BEGIN(ProtocolClient, .childQty = MEM_CONTEXT_QTY_MAX, .callbackQty = 1)
|
||||
{
|
||||
this = OBJ_NEW_ALLOC();
|
||||
|
||||
|
@ -30,7 +30,7 @@ protocolCommandNew(const StringId command)
|
||||
|
||||
ProtocolCommand *this = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(ProtocolCommand)
|
||||
OBJ_NEW_BEGIN(ProtocolCommand, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
this = OBJ_NEW_ALLOC();
|
||||
|
||||
|
@ -63,7 +63,7 @@ protocolHelperInit(void)
|
||||
// Create a mem context to store protocol objects
|
||||
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();
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ protocolParallelNew(TimeMSec timeout, ParallelJobCallback *callbackFunction, voi
|
||||
|
||||
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();
|
||||
|
||||
|
@ -27,7 +27,7 @@ protocolParallelJobNew(const Variant *key, ProtocolCommand *command)
|
||||
|
||||
ProtocolParallelJob *this = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(ProtocolParallelJob)
|
||||
OBJ_NEW_BEGIN(ProtocolParallelJob, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
this = OBJ_NEW_ALLOC();
|
||||
|
||||
|
@ -42,7 +42,7 @@ protocolServerNew(const String *name, const String *service, IoRead *read, IoWri
|
||||
|
||||
ProtocolServer *this = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(ProtocolServer)
|
||||
OBJ_NEW_BEGIN(ProtocolServer, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
this = OBJ_NEW_ALLOC();
|
||||
|
||||
|
@ -125,7 +125,7 @@ storageReadAzureNew(
|
||||
|
||||
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();
|
||||
|
||||
|
@ -719,7 +719,7 @@ storageAzureNew(
|
||||
|
||||
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();
|
||||
|
||||
|
@ -274,7 +274,7 @@ storageWriteAzureNew(StorageAzure *storage, const String *name, uint64_t fileId,
|
||||
|
||||
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();
|
||||
|
||||
|
@ -132,7 +132,7 @@ storageReadGcsNew(
|
||||
|
||||
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();
|
||||
|
||||
|
@ -954,7 +954,7 @@ storageGcsNew(
|
||||
|
||||
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();
|
||||
|
||||
|
@ -333,7 +333,7 @@ storageWriteGcsNew(StorageGcs *storage, const String *name, size_t chunkSize)
|
||||
|
||||
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();
|
||||
|
||||
|
@ -71,7 +71,7 @@ storageHelperContextInit(void)
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
@ -223,7 +223,7 @@ storageReadPosixNew(
|
||||
|
||||
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();
|
||||
|
||||
|
@ -592,7 +592,7 @@ storagePosixNewInternal(
|
||||
// Create the object
|
||||
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();
|
||||
|
||||
|
@ -245,7 +245,7 @@ storageWritePosixNew(
|
||||
|
||||
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();
|
||||
|
||||
|
@ -114,7 +114,7 @@ storageRemoteFeatureProtocol(PackRead *const param, ProtocolServer *const server
|
||||
{
|
||||
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.driver = storageDriver(storage);
|
||||
|
@ -232,7 +232,7 @@ storageReadRemoteNew(
|
||||
|
||||
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();
|
||||
|
||||
|
@ -451,7 +451,7 @@ storageRemoteNew(
|
||||
|
||||
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();
|
||||
|
||||
|
@ -211,7 +211,7 @@ storageWriteRemoteNew(
|
||||
|
||||
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();
|
||||
|
||||
|
@ -128,7 +128,7 @@ storageReadS3New(
|
||||
|
||||
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();
|
||||
|
||||
|
@ -1111,7 +1111,7 @@ storageS3New(
|
||||
|
||||
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();
|
||||
|
||||
|
@ -278,7 +278,7 @@ storageWriteS3New(StorageS3 *storage, const String *name, size_t partSize)
|
||||
|
||||
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();
|
||||
|
||||
|
@ -253,7 +253,7 @@ hrnLogReplaceAdd(const char *expression, const char *expressionSub, const char *
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
@ -1757,7 +1757,7 @@ testRun(void)
|
||||
|
||||
Manifest *manifest = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(Manifest)
|
||||
OBJ_NEW_BEGIN(Manifest, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
manifest = manifestNewInternal();
|
||||
manifest->pub.data.backupType = backupTypeFull;
|
||||
@ -1778,7 +1778,7 @@ testRun(void)
|
||||
|
||||
Manifest *manifestResume = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(Manifest)
|
||||
OBJ_NEW_BEGIN(Manifest, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
manifestResume = manifestNewInternal();
|
||||
manifestResume->pub.info = infoNew(NULL);
|
||||
@ -1912,7 +1912,7 @@ testRun(void)
|
||||
// Create manifest with file
|
||||
Manifest *manifest = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(Manifest)
|
||||
OBJ_NEW_BEGIN(Manifest, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
manifest = manifestNewInternal();
|
||||
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;
|
||||
|
||||
OBJ_NEW_BEGIN(Manifest)
|
||||
OBJ_NEW_BEGIN(Manifest, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
result = manifestNewInternal();
|
||||
result->pub.info = infoNew(NULL);
|
||||
@ -1294,7 +1294,7 @@ testRun(void)
|
||||
|
||||
Manifest *manifest = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(Manifest)
|
||||
OBJ_NEW_BEGIN(Manifest, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
manifest = manifestNewInternal();
|
||||
manifest->pub.data.pgVersion = PG_VERSION_90;
|
||||
@ -2026,7 +2026,7 @@ testRun(void)
|
||||
|
||||
Manifest *manifest = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(Manifest)
|
||||
OBJ_NEW_BEGIN(Manifest, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
manifest = manifestNewInternal();
|
||||
manifest->pub.info = infoNew(NULL);
|
||||
@ -2431,7 +2431,7 @@ testRun(void)
|
||||
#define TEST_PGDATA MANIFEST_TARGET_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->pub.info = infoNew(NULL);
|
||||
|
@ -118,7 +118,7 @@ ioTestFilterSizeNew(const StringId type)
|
||||
{
|
||||
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();
|
||||
*driver = (IoTestFilterSize){0};
|
||||
@ -223,7 +223,7 @@ ioTestFilterMultiplyNew(const StringId type, unsigned int multiplier, unsigned i
|
||||
{
|
||||
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();
|
||||
|
||||
|
@ -13,7 +13,8 @@ testFree(void *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(memContextCallbackSet(this, testFree, 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_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
|
||||
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_PTR(memContextTop()->contextChildList, NULL, "top context child list empty");
|
||||
TEST_RESULT_BOOL(memContextTop()->childInitialized, false, "top context should init with zero children");
|
||||
|
||||
// Current context should equal top context
|
||||
TEST_RESULT_PTR(memContextCurrent(), memContextTop(), "top context == current context");
|
||||
@ -86,11 +89,13 @@ testRun(void)
|
||||
// Context name length errors
|
||||
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();
|
||||
TEST_RESULT_Z(memContext->name, "test1", "test1 context name");
|
||||
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);
|
||||
|
||||
@ -99,62 +104,92 @@ testRun(void)
|
||||
TEST_RESULT_PTR(memContext, memContextCurrent(), "current context is now test1");
|
||||
|
||||
// Create enough mem contexts to use up the initially allocated block
|
||||
memContextSwitch(memContextTop());
|
||||
|
||||
for (int contextIdx = 1; contextIdx < MEM_CONTEXT_INITIAL_SIZE; contextIdx++)
|
||||
{
|
||||
memContextSwitch(memContextTop());
|
||||
memContextNewP("test-filler");
|
||||
memContextNewP("test-filler", .childQty = MEM_CONTEXT_QTY_MAX, .allocQty = MEM_CONTEXT_QTY_MAX, .callbackQty = 1);
|
||||
memContextKeep();
|
||||
TEST_RESULT_BOOL(memContextTop()->contextChildList[contextIdx]->active, true, "new context is active");
|
||||
TEST_RESULT_Z(memContextTop()->contextChildList[contextIdx]->name, "test-filler", "new context name");
|
||||
TEST_RESULT_PTR_NE(memContextChildMany(memContextTop())->list[contextIdx], NULL, "new context exists");
|
||||
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
|
||||
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(memContextFromAllocExtra(memContext + 1), memContext, "mem context from alloc extra");
|
||||
TEST_RESULT_PTR(memContextConstFromAllocExtra(memContext + 1), memContext, "const mem context from alloc extra");
|
||||
memContextKeep();
|
||||
TEST_RESULT_INT(memContextTop()->contextChildListSize, MEM_CONTEXT_INITIAL_SIZE * 2, "increased child context list size");
|
||||
TEST_RESULT_UINT(memContextTop()->contextChildFreeIdx, MEM_CONTEXT_INITIAL_SIZE + 1, "check context free idx");
|
||||
TEST_RESULT_INT(
|
||||
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
|
||||
memContextFree(memContextTop()->contextChildList[1]);
|
||||
TEST_RESULT_PTR(memContextTop()->contextChildList[1], NULL, "child context NULL after free");
|
||||
memContextFree(memContextChildMany(memContextTop())->list[1]);
|
||||
TEST_RESULT_PTR(memContextChildMany(memContextTop())->list[1], NULL, "child context NULL after free");
|
||||
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
|
||||
memContextNewP("test-reuse");
|
||||
MemContext *const memContextOneChild = memContextNewP("test-reuse", .childQty = 1);
|
||||
memContextKeep();
|
||||
TEST_RESULT_BOOL(
|
||||
memContextTop()->contextChildList[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_UINT(memContextTop()->contextChildFreeIdx, 2, "check context free idx");
|
||||
memContextChildMany(memContextTop())->list[1]->active, true, "new context in same index as freed context is active");
|
||||
TEST_RESULT_Z(memContextChildMany(memContextTop())->list[1]->name, "test-reuse", "new context name");
|
||||
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
|
||||
memContextNewP("test-at-end");
|
||||
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
|
||||
memContextSwitch(memContextTop()->contextChildList[MEM_CONTEXT_INITIAL_SIZE]);
|
||||
memContextNewP("test-reuse");
|
||||
memContextSwitch(memContextChildMany(memContextTop())->list[MEM_CONTEXT_INITIAL_SIZE]);
|
||||
memContextNewP("test-reuse", .childQty = 1);
|
||||
memContextKeep();
|
||||
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(
|
||||
memContextTop()->contextChildList[MEM_CONTEXT_INITIAL_SIZE]->contextChildListSize, MEM_CONTEXT_INITIAL_SIZE,
|
||||
"context child list initial size");
|
||||
memContextChildMany(memContextChildMany(memContextTop())->list[MEM_CONTEXT_INITIAL_SIZE])->listSize,
|
||||
MEM_CONTEXT_INITIAL_SIZE, "context child list initial size");
|
||||
|
||||
// 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(
|
||||
memContextFree(memContextTop()->contextChildList[MEM_CONTEXT_INITIAL_SIZE]),
|
||||
AssertError, "cannot free current context 'test5'");
|
||||
memContextFree(memContextChildMany(memContextTop())->list[MEM_CONTEXT_INITIAL_SIZE]), AssertError,
|
||||
"cannot free current context 'test5'");
|
||||
|
||||
TEST_RESULT_VOID(memContextSwitch(memContextTop()), "switch to 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());
|
||||
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");
|
||||
memContextKeep();
|
||||
memContextSwitch(memContext);
|
||||
@ -182,7 +217,7 @@ testRun(void)
|
||||
memNew(sizeof(size_t));
|
||||
|
||||
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,
|
||||
"allocation list size");
|
||||
}
|
||||
@ -202,46 +237,83 @@ testRun(void)
|
||||
TEST_RESULT_INT(expectedTotal, sizeof(size_t), "all bytes are 0xFE in original portion");
|
||||
|
||||
// Free memory
|
||||
TEST_RESULT_UINT(memContextCurrent()->allocFreeIdx, MEM_CONTEXT_ALLOC_INITIAL_SIZE + 2, "check alloc free idx");
|
||||
TEST_RESULT_VOID(memFree(MEM_CONTEXT_ALLOC_BUFFER(memContextCurrent()->allocList[0])), "free allocation");
|
||||
TEST_RESULT_UINT(memContextCurrent()->allocFreeIdx, 0, "check alloc free idx");
|
||||
TEST_RESULT_UINT(
|
||||
memContextAllocMany(memContextCurrent())->freeIdx, MEM_CONTEXT_ALLOC_INITIAL_SIZE + 2, "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_UINT(memContextCurrent()->allocFreeIdx, 0, "check alloc free idx");
|
||||
TEST_RESULT_VOID(memFree(MEM_CONTEXT_ALLOC_BUFFER(memContextAllocMany(memContextCurrent())->list[1])), "free allocation");
|
||||
TEST_RESULT_UINT(memContextAllocMany(memContextCurrent())->freeIdx, 0, "check alloc free idx");
|
||||
|
||||
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_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_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
|
||||
TEST_RESULT_UINT(memContextSize(memContextCurrent()), TEST_64BIT() ? 241 : 165, "check size");
|
||||
TEST_RESULT_UINT(memContextSize(memContextCurrent()), TEST_64BIT() ? 209 : 145, "check size");
|
||||
|
||||
TEST_ERROR(
|
||||
memFree(NULL), AssertError,
|
||||
"assertion '((MemContextAlloc *)buffer - 1) != NULL"
|
||||
" && (uintptr_t)((MemContextAlloc *)buffer - 1) != (uintptr_t)-sizeof(MemContextAlloc)"
|
||||
" && ((MemContextAlloc *)buffer - 1)->allocIdx <"
|
||||
" memContextStack[memContextCurrentStackIdx].memContext->allocListSize"
|
||||
" && memContextStack[memContextCurrentStackIdx].memContext->allocList[((MemContextAlloc *)buffer - 1)->allocIdx]'"
|
||||
" failed");
|
||||
"assertion 'alloc != NULL && "
|
||||
"(uintptr_t)alloc != (uintptr_t)-sizeof(MemContextAlloc) && "
|
||||
"alloc->allocIdx < memContextAllocMany(memContextStack[memContextCurrentStackIdx].memContext)->listSize && "
|
||||
"memContextAllocMany(memContextStack[memContextCurrentStackIdx].memContext)->list[alloc->allocIdx]' failed");
|
||||
memFree(buffer);
|
||||
|
||||
memContextSwitch(memContextTop());
|
||||
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()"))
|
||||
{
|
||||
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();
|
||||
memContextCallbackSet(memContext, testFree, memContext);
|
||||
TEST_ERROR(
|
||||
@ -257,7 +329,8 @@ testRun(void)
|
||||
|
||||
// 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");
|
||||
testFreeThrow = true;
|
||||
TEST_RESULT_VOID(memContextCallbackSet(memContext, testFree, memContext), " set callback");
|
||||
@ -268,7 +341,8 @@ testRun(void)
|
||||
if (testBegin("MEM_CONTEXT_BEGIN() and MEM_CONTEXT_END()"))
|
||||
{
|
||||
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();
|
||||
|
||||
// Check normal block
|
||||
@ -296,12 +370,12 @@ testRun(void)
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
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);
|
||||
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);
|
||||
TEST_RESULT_PTR(MEM_CONTEXT_TEMP()->allocList, NULL, "nothing allocated");
|
||||
TEST_RESULT_BOOL(MEM_CONTEXT_TEMP()->allocInitialized, false, "nothing allocated");
|
||||
}
|
||||
MEM_CONTEXT_TEMP_END();
|
||||
}
|
||||
@ -316,7 +390,7 @@ testRun(void)
|
||||
|
||||
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();
|
||||
TEST_RESULT_PTR(memContext, memContextCurrent(), "new mem context is current");
|
||||
@ -336,7 +410,7 @@ testRun(void)
|
||||
|
||||
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();
|
||||
TEST_RESULT_Z(memContext->name, memContextTestName, "check mem context name");
|
||||
@ -365,36 +439,36 @@ testRun(void)
|
||||
void *mem = NULL;
|
||||
void *mem2 = NULL;
|
||||
|
||||
MEM_CONTEXT_NEW_BEGIN("outer")
|
||||
MEM_CONTEXT_NEW_BEGIN("outer", .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
MEM_CONTEXT_TEMP_BEGIN()
|
||||
{
|
||||
memContextNewP("not-to-be-moved");
|
||||
memContextNewP("not-to-be-moved", .childQty = MEM_CONTEXT_QTY_MAX);
|
||||
memContextKeep();
|
||||
|
||||
MEM_CONTEXT_NEW_BEGIN("inner")
|
||||
MEM_CONTEXT_NEW_BEGIN("inner", .allocQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
memContext = MEM_CONTEXT_NEW();
|
||||
mem = memNew(sizeof(int));
|
||||
}
|
||||
MEM_CONTEXT_NEW_END();
|
||||
|
||||
TEST_RESULT_PTR(MEM_CONTEXT_ALLOC_BUFFER(memContext->allocList[0]), mem, "check memory allocation");
|
||||
TEST_RESULT_PTR(memContextCurrent()->contextChildList[1], memContext, "check memory context");
|
||||
TEST_RESULT_PTR(MEM_CONTEXT_ALLOC_BUFFER(memContextAllocMany(memContext)->list[0]), mem, "check memory allocation");
|
||||
TEST_RESULT_PTR(memContextChildMany(memContextCurrent())->list[1], memContext, "check memory context");
|
||||
|
||||
// Null out the mem context in the parent so the move will fail
|
||||
memContextCurrent()->contextChildList[1] = NULL;
|
||||
memContextChildMany(memContextCurrent())->list[1] = NULL;
|
||||
TEST_ERROR(
|
||||
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
|
||||
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 again");
|
||||
|
||||
// Move another context
|
||||
MEM_CONTEXT_NEW_BEGIN("inner2")
|
||||
MEM_CONTEXT_NEW_BEGIN("inner2", .allocQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
memContext2 = MEM_CONTEXT_NEW();
|
||||
mem2 = memNew(sizeof(int));
|
||||
@ -405,13 +479,36 @@ testRun(void)
|
||||
}
|
||||
MEM_CONTEXT_TEMP_END();
|
||||
|
||||
TEST_RESULT_PTR(MEM_CONTEXT_ALLOC_BUFFER(memContext->allocList[0]), mem, "check memory allocation");
|
||||
TEST_RESULT_PTR(memContextCurrent()->contextChildList[1], memContext, "check memory context");
|
||||
TEST_RESULT_PTR(MEM_CONTEXT_ALLOC_BUFFER(memContextAllocMany(memContext)->list[0]), mem, "check memory allocation");
|
||||
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(memContextCurrent()->contextChildList[2], memContext2, "check memory context 2");
|
||||
TEST_RESULT_PTR(MEM_CONTEXT_ALLOC_BUFFER(memContextAllocMany(memContext2)->list[0]), mem2, "check memory allocation 2");
|
||||
TEST_RESULT_PTR(memContextChildMany(memContextCurrent())->list[2], memContext2, "check memory context 2");
|
||||
}
|
||||
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());
|
||||
|
@ -49,7 +49,7 @@ testObjectNew(void)
|
||||
{
|
||||
TestObject *this = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(STRINGIFY(TestObject))
|
||||
OBJ_NEW_BEGIN(TestObject)
|
||||
{
|
||||
this = OBJ_NEW_ALLOC();
|
||||
|
||||
@ -69,7 +69,7 @@ testObjectContextNew(void)
|
||||
{
|
||||
TestObjectContext *this = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(STRINGIFY(TestObjectContext))
|
||||
OBJ_NEW_BEGIN(TestObjectContext)
|
||||
{
|
||||
this = OBJ_NEW_ALLOC();
|
||||
|
||||
|
@ -41,7 +41,8 @@ testRun(void)
|
||||
TEST_RESULT_VOID(CHECK_SIZE(555), "valid size");
|
||||
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_STR_Z(string, "static string", "new with static string");
|
||||
TEST_RESULT_UINT(strSize(string), 13, "check size");
|
||||
@ -89,6 +90,15 @@ testRun(void)
|
||||
TEST_TITLE("strNewEncode()");
|
||||
|
||||
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
|
||||
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);
|
||||
@ -57,7 +57,7 @@ testRun(void)
|
||||
{
|
||||
// Ensure type sizes are as expected
|
||||
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);
|
||||
@ -96,7 +96,7 @@ testRun(void)
|
||||
{
|
||||
// Ensure type sizes are as expected
|
||||
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);
|
||||
@ -137,7 +137,7 @@ testRun(void)
|
||||
{
|
||||
// Ensure type sizes are as expected
|
||||
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);
|
||||
@ -178,7 +178,7 @@ testRun(void)
|
||||
{
|
||||
// Ensure type sizes are as expected
|
||||
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);
|
||||
@ -220,7 +220,7 @@ testRun(void)
|
||||
if (testBegin("keyValue"))
|
||||
{
|
||||
// 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");
|
||||
@ -254,7 +254,7 @@ testRun(void)
|
||||
{
|
||||
// Ensure type sizes are as expected
|
||||
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");
|
||||
@ -310,13 +310,22 @@ testRun(void)
|
||||
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("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"))
|
||||
{
|
||||
// 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");
|
||||
|
@ -949,7 +949,7 @@ testRun(void)
|
||||
|
||||
Manifest *manifest = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(Manifest)
|
||||
OBJ_NEW_BEGIN(Manifest, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
manifest = manifestNewInternal();
|
||||
manifest->pub.data.backupOptionOnline = true;
|
||||
@ -1035,7 +1035,7 @@ testRun(void)
|
||||
|
||||
Manifest *manifest = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(Manifest)
|
||||
OBJ_NEW_BEGIN(Manifest, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
manifest = manifestNewInternal();
|
||||
manifest->pub.info = infoNew(NULL);
|
||||
@ -1072,7 +1072,7 @@ testRun(void)
|
||||
|
||||
Manifest *manifestPrior = NULL;
|
||||
|
||||
OBJ_NEW_BEGIN(Manifest)
|
||||
OBJ_NEW_BEGIN(Manifest, .childQty = MEM_CONTEXT_QTY_MAX)
|
||||
{
|
||||
manifestPrior = manifestNewInternal();
|
||||
manifestPrior->pub.data.backupLabel = strNewZ("20190101-010101F");
|
||||
|
@ -118,7 +118,7 @@ testIoRateNew(uint64_t bytesPerSec)
|
||||
{
|
||||
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();
|
||||
|
||||
|
@ -263,7 +263,7 @@ testRun(void)
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
TEST_TITLE("build manifest");
|
||||
|
||||
MemContext *testContext = memContextNewP("test");
|
||||
MemContext *testContext = memContextNewP("test", .childQty = MEM_CONTEXT_QTY_MAX);
|
||||
memContextKeep();
|
||||
Manifest *manifest = NULL;
|
||||
TimeMSec timeBegin = timeMSec();
|
||||
@ -276,7 +276,7 @@ testRun(void)
|
||||
MEM_CONTEXT_END();
|
||||
|
||||
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");
|
||||
|
||||
@ -295,7 +295,7 @@ testRun(void)
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
TEST_TITLE("load manifest");
|
||||
|
||||
testContext = memContextNewP("test");
|
||||
testContext = memContextNewP("test", .childQty = MEM_CONTEXT_QTY_MAX);
|
||||
memContextKeep();
|
||||
timeBegin = timeMSec();
|
||||
|
||||
@ -306,7 +306,7 @@ testRun(void)
|
||||
MEM_CONTEXT_END();
|
||||
|
||||
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");
|
||||
|
||||
|
@ -281,7 +281,7 @@ testRun(void)
|
||||
|
||||
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 = (ProtocolClient){
|
||||
@ -290,7 +290,7 @@ testRun(void)
|
||||
}
|
||||
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 = (Exec){.name = strNewZ("test"), .command = strNewZ("test"), .processId = INT_MAX};
|
||||
|
Reference in New Issue
Block a user