Update prototype of memory functions

to always get the memory context parameter
(even if it is not needed) to provide a cleaner
and simpler user interface
(instead of requesting the user to use directly m_context).
This commit is contained in:
Patrick Pelissier committed 2025-05-07 21:02:24 +02:00
1 parent f585167fa8
commit 3721129da1
19 files changed
+155 -118

No files matched your search

+64 -35
View File
@@ -1041,18 +1041,37 @@ In which case, this enables you to close the file even if an exception is thrown
Memory Allocation functions can be globally set by overriding the following macros before using the definition `_DEF` macros:
* `M_MEMORY_ALLOC (type)` --> `ptr`: return a pointer to a new object of type `type`.
* `M_MEMORY_DEL (ptr)`: free the single object pointed by `ptr`.
* `M_MEMORY_REALLOC (type, ptr, old_number, new_number)` --> `ptr`: return a pointer to an array of `new_number` objects of type `type`, reusing the old array pointed by `ptr` of `old_number` objects. `ptr` can be NULL, in which case the array will be created.
* `M_MEMORY_FREE (type, ptr, number)`: free the array of `number` objects of type `type` pointed by `ptr`.
* `M_MEMORY_ALLOC (context, type)` --> `ptr`: return a pointer to a new object of type `type`.
* `M_MEMORY_DEL (context, ptr)`: free the single object pointed by `ptr`.
* `M_MEMORY_REALLOC (context, type, ptr, old_number, new_number)` --> `ptr`: return a pointer to an array of `new_number` objects of type `type`, reusing the old array pointed by `ptr` of `old_number` objects. `ptr` can be NULL, in which case the array will be created.
* `M_MEMORY_FREE (context, type, ptr, number)`: free the array of `number` objects of type `type` pointed by `ptr`.
`ALLOC` and `DEL` operators are supposed to allocate fixed size single element object (no array).
> [!NOTE]
> You can use `sizeof (type)` and `alignof (type)` to get the size and the alignement of the object.
> [!NOTE]
> For `M_MEMORY_DEL`, `sizeof *ptr` always identifies the size of the object.
`ALLOC` and `DEL` operators are supposed to allocate **fixed** size single element object (no array).
These objects are not expected to grow.
`REALLOC` and `FREE` operators deal with allocated memory for growing objects.
Do not mix pointers between both: a pointer allocated by `ALLOC` (resp. `REALLOC`) is supposed
to be only freed by `DEL` (resp. `FREE`). There are separated 'free' operators to enable
specialization in the allocator (a good allocator can take this hint into account).
`context` is a local user context used to identify the memory context to use for the allocation.
This parameter **only** exists if the library is compiled with the `M_USE_CONTEXT` customization parameter enabled globally.
Otherwise this parameter identifies a non existing symbol `m_context`.
This parameter shall be discarded if `M_USE_CONTEXT` is not defined (it shall not exist anymore after preprocessing step).
For that, you can define the macros to ignore the first parameter
or you can use GAIA to adapt the call to what your function expects.
> [!NOTE]
> If you get error on `m_context` being undefined
> it is likely because one of your memory is trying to evaluate the memory context
> without defining `M_USE_CONTEXT`.
`M_MEMORY_ALLOC` and `M_MEMORY_REALLOC` are supposed to return NULL in case of memory allocation failure.
The defaults are `malloc`, `free`, `realloc` and `free`.
@@ -4724,7 +4743,7 @@ void f(void) {
shared_data_push(p, 23);
shared_data_push(p, 32);
// And send it through 2 channels of communication
comm_buffer_push(comm1, p); // shared_data_acquire is done by the buffer to acquite ownership of the data
comm_buffer_push(comm1, p); // shared_data_acquire is done by the buffer to acquit ownership of the data
comm_buffer_push(comm2, p);
// Release our ownership of the data
shared_data_clear(p);
@@ -4909,7 +4928,7 @@ This method is created only if the `PUSH` operator is defined.
##### `bool name_try_push_move(name_t *a, sub_type *el)`
Try to push in `*a` the element `*el`,if the container is not full and clear `*el` (return true in this case).
Return false otherwise (cannot push element) and `*el` is still initializated.
Return false otherwise (cannot push element) and `*el` is still initialized.
This method is created only if the `PUSH_MOVE` operator is defined.
##### `bool name_try_emplace<emplace_suffix>(name_t *a[, <emplace_args> args])`
@@ -7967,22 +7986,28 @@ void struct_init_set(struct_t d, struct_t s)
All these macro can be overridden before including the header [m-core.h](#m-core) so that they can be adapted to a particular memory pool.
##### `type *M_MEMORY_ALLOC (type)`
##### `type *M_MEMORY_ALLOC (context, type)`
Return a pointer to a new allocated non-initialized object of type `type`.
In case of allocation error, it returns NULL.
`context` parameter is the memory context parameter as provided by the user.
It only exists if the library is built with `M_USE_CONTEXT`
The default used function is the `malloc` function of the LIBC.
##### `void M_MEMORY_DEL (type *ptr)`
##### `void M_MEMORY_DEL (context, type *ptr)`
Delete the cleared object pointed by the pointer `ptr`
that was previously allocated by the macro `M_MEMORY_ALLOC`.
`ptr` can not be NULL.
`context` parameter is the memory context parameter as provided by the user.
It only exists if the library is built with `M_USE_CONTEXT`
The default used function is the `free` function of the LIBC.
##### `type *M_MEMORY_REALLOC (type, ptr, old_number, new_number)`
##### `type *M_MEMORY_REALLOC (context, type, ptr, old_number, new_number)`
Return a pointer to an array of `new_number` objects of type `type`
`ptr` is either NULL (in which the array is allocated),
@@ -7994,14 +8019,20 @@ The address of the previous objects may have moved and the `MOVE` operator
is not used in this case.
In case of allocation error, it returns NULL.
`context` parameter is the memory context parameter as provided by the user.
It only exists if the library is built with `M_USE_CONTEXT`
The default used function is the `realloc` function of the LIBC.
##### `void M_MEMORY_FREE (type, ptr, number)`
##### `void M_MEMORY_FREE (context, type, ptr, number)`
Delete the cleared array of `number` objects of type `type pointed by the pointer `ptr`.
The pointer was previously allocated by the macro `M_MEMORY_REALLOC`.
If `ptr` is NULL, the function shall do nothing.
`context` parameter is the memory context parameter as provided by the user.
It only exists if the library is built with `M_USE_CONTEXT`
The default used function is the `free` function of the LIBC.
##### `void M_MEMORY_FULL (type, number)`
@@ -9591,8 +9622,8 @@ It is possible to give a custom memory context parameter to the memory methods `
For this, you need to define `M_USE_CONTEXT` to the type of the custom memory context parameter.
The definition of this global parameter modifies the generation of **all** functions
so that the functions that may allocate or free something will add a new argument,
the memory context parameter `m_context` of type `M_USE_CONTEXT`,
as their first arguement.
the memory context parameter `m_context` of the user provided type `M_USE_CONTEXT`,
as their first argument.
It will also modifies the `OPLIST` definition so that they request the parameter named `m_context`
for such methods.
@@ -9601,29 +9632,26 @@ The memory context can be an [arena allocator](https://www.rfleury.com/p/untangl
> [!Note]
> The memory context parameter is not stored in the container
> because it is not efficient in memory usage and is redundant when you
> create container of other containers (example `array` of `string_t)`
> The user shall ensure of the coherence of the memory context for a given container
> so that it is the same memory context since its construction to its destruction.
> create container of other containers (example `array` of `string_t`).
The user shall ensure of the coherence of the memory context for a given container
so that the same memory context is used from its construction to its destruction.
If you master your own memory, you may want to control when performing the Garbage Collecting.
This Garbage Collecting may be quite efficient in reclaiming allocated memory in a single and efficient pass:
in such a case, you may not want calling the destructors of the containers as their operation of freeing the memory
back to the memory allocator will be redundant and inefficient.
As a consequence, the following guarantee is ensured:
The destructors of all containers except the thread safe ones only free back memory.
As such, it is safe not to call the destructors of these containers if you have another way to reclaim your memory.
If the destructor of a mutex is also a no-op on your system, this guarantee is extended to the thread safe containers too.
If the destructor of a mutex is also a no-op on your system, this guarantee is extended to all containers
(including the thread safe containers too).
In order to use such feature, you need to:
* define globally `M_USE_CONTEXT` with your type.
* define globally an override of the memory functions `M_MEMORY_ALLOC`, `M_MEMORY_DEL`, `M_MEMORY_REALLOC` and `M_MEMORY_FREE`.
You will realize that the expected definitions of these macros don't expect the memory context parameter.
Instead, the macros themselves shall directly use the named argument `m_context` for this purpose.
This argument is ensure to be defined by the function when using this macro.
FIXME: Seems bad design when written...
* define globally an override of the memory functions `M_MEMORY_ALLOC`, `M_MEMORY_DEL`, `M_MEMORY_REALLOC` and `M_MEMORY_FREE` to use your context.
Example
@@ -9634,16 +9662,16 @@ typedef int *context_t;
// Define the realloc / free that accepts the memory context.
static void *my_realloc(void *ptr, size_t old, size_t new, size_t base, context_t context)
{
(void) context; // TODO
(void) old; // TODO
(void) context; // TODO what you want with it.
(void) old; // TODO what you want with it.
return realloc(ptr, new*base);
}
static void my_free(void *ptr, size_t old, size_t base, context_t context)
{
(void) context; // TODO
(void) old; // TODO
(void) base; // TODO
(void) context; // TODO what you want with it.
(void) old; // TODO what you want with it.
(void) base; // TODO what you want with it.
free(ptr);
}
@@ -9652,13 +9680,14 @@ static void my_free(void *ptr, size_t old, size_t base, context_t context)
// Overloaded memory functions to use the custom ones.
// m_context is the name of the memory context parameter
# define M_MEMORY_REALLOC(type, ptr, o, n) my_realloc(ptr, o, n, sizeof (type), m_context)
# define M_MEMORY_FREE(type, ptr, o) my_free(ptr, o, sizeof (type), m_context)
# define M_MEMORY_REALLOC(ctx, type, ptr, o, n) my_realloc(ptr, o, n, sizeof (type), ctx)
# define M_MEMORY_FREE(ctx, type, ptr, o) my_free(ptr, o, sizeof (type), ctx)
# define M_MEMORY_ALLOC(type) my_realloc(NULL, 0, 1, sizeof (type), m_context)
# define M_MEMORY_DEL(ptr) my_free(ptr, 1, sizeof (*ptr), m_context)
# define M_MEMORY_ALLOC(ctx, type) my_realloc(NULL, 0, 1, sizeof (type), ctx)
# define M_MEMORY_DEL(ctx, ptr) my_free(ptr, 1, sizeof (*ptr), ctx)
// Now you may include M*LIB headers.
#include "m-array.h"
```
This works great for local allocators for a thread. However some containers are designed to handle
@@ -9667,9 +9696,9 @@ objects accross several threads: shared pointer, communication queue, ...
For such containers, a local allocator has no meaning: it will be very hard to ensure the same allocator
is used for both the producor thread and the user threads.
As a concequence, shared pointer, communication queue container and all thread containers
As a consequence, shared pointer, communication queue container and all thread containers
will use a global memory context:
M\*LIB won't add a new argument `m_context` to the functions of such containers. Instead it will generate
M\*LIB won't add a context argument to the functions of such containers. Instead it will generate
a local parameter initialize to the global memory context.
The global memory context is defined by the macro `M_USE_GLOBAL_CONTEXT` which shall define and initialize
the named argument to the global memory context. In the absence of definition of such macro, the default is
+1
View File
@@ -90,6 +90,7 @@ V0.8.0 : * The prototypes of REALLOC / FREE operators are incompatible:
Add the old number of elements of the array as argument of REALLOC
Add the number of elements of the array and its base type as arguments of FREE.
(You can ignore the new arguments which are only hints provided to memory functions).
Add the memory context argument.
Also impact M_MEMORY_REALLOC & M_MEMORY_FREE
This allows more and efficient integration into custom allocators.
* M_MEMORY_FULL: replace the failed size allocation size argument
+4 -4
View File
@@ -43,12 +43,12 @@ static void my_array_free(void *ptr)
////////////////////////////////////////////////////////////
// Allocate for single object
# define M_MEMORY_ALLOC(type) my_alloc (sizeof (type))
# define M_MEMORY_DEL(ptr) my_free(ptr, sizeof *ptr)
# define M_MEMORY_ALLOC(ctx, type) my_alloc (sizeof (type))
# define M_MEMORY_DEL(ctx, ptr) my_free(ptr, sizeof *ptr)
// Allocate for array of objects
# define M_MEMORY_REALLOC(type, ptr, o, n) my_array_alloc (sizeof (type), ptr, n)
# define M_MEMORY_FREE(type, ptr, n) my_array_free(ptr)
# define M_MEMORY_REALLOC(ctx, type, ptr, o, n) my_array_alloc (sizeof (type), ptr, n)
# define M_MEMORY_FREE(ctx, type, ptr, n) my_array_free(ptr)
#include "m-list.h"
#include "m-array.h"
+4 -4
View File
@@ -23,8 +23,8 @@ static void my_free(void *ptr, size_t s)
}
// Allocate for single object
# define MY_MEMORY_ALLOC(type) my_alloc (sizeof (type))
# define MY_MEMORY_DEL(ptr) my_free(ptr, sizeof *ptr)
# define MY_MEMORY_ALLOC(ctx, type) my_alloc (sizeof (type))
# define MY_MEMORY_DEL(ctx, ptr) my_free(ptr, sizeof *ptr)
////////////////////////////////////////////////////////////
@@ -76,8 +76,8 @@ static void my_array_free(void *ptr)
}
// Allocate for array of objects
# define MY_MEMORY_REALLOC(type, ptr, o, n) my_array_alloc (sizeof (type), ptr, n)
# define MY_MEMORY_FREE(type, ptr, n) my_array_free(ptr)
# define MY_MEMORY_REALLOC(ctx, type, ptr, o, n) my_array_alloc (sizeof (type), ptr, n)
# define MY_MEMORY_FREE(ctx, type, ptr, n) my_array_free(ptr)
////////////////////////////////////////////////////////////
+4 -5
View File
@@ -23,12 +23,11 @@ static void my_free(void *ptr, size_t old, size_t base, context_t context)
# define M_USE_CONTEXT context_t
// Overloaded memory functions to use the custom ones.
// m_context is the name of the memory context parameter
# define M_MEMORY_REALLOC(type, ptr, o, n) my_realloc(ptr, o, n, sizeof (type), m_context)
# define M_MEMORY_FREE(type, ptr, o) my_free(ptr, o, sizeof (*ptr), m_context)
# define M_MEMORY_REALLOC(ctx, type, ptr, o, n) my_realloc(ptr, o, n, sizeof (type), ctx)
# define M_MEMORY_FREE(ctx, type, ptr, o) my_free(ptr, o, sizeof (*ptr), ctx)
# define M_MEMORY_ALLOC(type) my_realloc(NULL, 0, 1, sizeof (type), m_context)
# define M_MEMORY_DEL(ptr) my_free(ptr, 1, sizeof (*ptr), m_context)
# define M_MEMORY_ALLOC(ctx, type) my_realloc(NULL, 0, 1, sizeof (type), ctx)
# define M_MEMORY_DEL(ctx, ptr) my_free(ptr, 1, sizeof (*ptr), ctx)
// Now we can include M*LIB functions.
#include "m-string.h"
+6 -6
View File
@@ -104,7 +104,7 @@ m_bitset_reset(m_bitset_t t)
M_P(void, m_bitset, _clear, m_bitset_t t)
{
m_bitset_reset(t);
M_MEMORY_FREE(m_b1tset_limb_ct, t->ptr, t->alloc);
M_MEMORY_FREE(m_context, m_b1tset_limb_ct, t->ptr, t->alloc);
// This is not really needed, but is safer
// This representation is invalid and will be detected by the contract.
// A C compiler should be able to optimize out theses initializations.
@@ -122,7 +122,7 @@ M_P(void, m_bitset, _set, m_bitset_t d, const m_bitset_t s)
if (M_LIKELY (s->size > 0)) {
// Test if enough space in target
if (s->size > M_B1TSET_FROM_ALLOC (d->alloc)) {
m_b1tset_limb_ct *ptr = M_MEMORY_REALLOC (m_b1tset_limb_ct, d->ptr, d->alloc, needAlloc);
m_b1tset_limb_ct *ptr = M_MEMORY_REALLOC (m_context, m_b1tset_limb_ct, d->ptr, d->alloc, needAlloc);
if (M_UNLIKELY_NOMEM (ptr == NULL)) {
M_MEMORY_FULL(m_b1tset_limb_ct, needAlloc);
}
@@ -209,7 +209,7 @@ M_P(void, m_bitset, _push_back, m_bitset_t v, bool x)
M_MEMORY_FULL(m_b1tset_limb_ct, needAlloc);
}
// Alloc memory
m_b1tset_limb_ct *ptr = M_MEMORY_REALLOC (m_b1tset_limb_ct, v->ptr, v->alloc, needAlloc);
m_b1tset_limb_ct *ptr = M_MEMORY_REALLOC (m_context, m_b1tset_limb_ct, v->ptr, v->alloc, needAlloc);
// Check if success
if (M_UNLIKELY_NOMEM (ptr == NULL) ) {
M_MEMORY_FULL(m_b1tset_limb_ct, needAlloc);
@@ -245,7 +245,7 @@ M_P(void, m_bitset, _resize, m_bitset_t v, size_t size)
size_t newAlloc = M_B1TSET_TO_ALLOC (size);
if (newAlloc > v->alloc) {
// Allocate more limbs to store the bitset.
m_b1tset_limb_ct *ptr = M_MEMORY_REALLOC (m_b1tset_limb_ct, v->ptr, v->alloc, newAlloc);
m_b1tset_limb_ct *ptr = M_MEMORY_REALLOC (m_context, m_b1tset_limb_ct, v->ptr, v->alloc, newAlloc);
if (M_UNLIKELY_NOMEM (ptr == NULL) ) {
M_MEMORY_FULL(m_b1tset_limb_ct, newAlloc);
}
@@ -290,12 +290,12 @@ M_P(void, m_bitset, _reserve, m_bitset_t v, size_t alloc)
}
if (M_UNLIKELY (newAlloc == 0)) {
// Free all memory used by the bitsets
M_MEMORY_FREE (m_b1tset_limb_ct, v->ptr, v->alloc);
M_MEMORY_FREE (m_context, m_b1tset_limb_ct, v->ptr, v->alloc);
v->size = v->alloc = 0;
v->ptr = NULL;
} else {
// Allocate more memory or reduce memory usage
m_b1tset_limb_ct *ptr = M_MEMORY_REALLOC (m_b1tset_limb_ct, v->ptr, v->alloc, newAlloc);
m_b1tset_limb_ct *ptr = M_MEMORY_REALLOC (m_context, m_b1tset_limb_ct, v->ptr, v->alloc, newAlloc);
if (M_UNLIKELY_NOMEM (ptr == NULL) ) {
M_MEMORY_FULL(m_b1tset_limb_ct, newAlloc);
}
+4 -4
View File
@@ -77,7 +77,7 @@ m_bstring_init(m_bstring_t s)
M_P(void, m_bstring, _clear, m_bstring_t s)
{
M_BSTRING_CONTRACT(s);
M_MEMORY_FREE(uint8_t, s->ptr, s->alloc);
M_MEMORY_FREE(m_context, uint8_t, s->ptr, s->alloc);
s->offset = (size_t) -1;
}
@@ -164,7 +164,7 @@ M_P(uint8_t *, m_bstr1ng, _fit2size, m_bstring_t v, size_t size_alloc, bool exac
if (M_UNLIKELY_NOMEM (alloc < size_alloc)) {
goto allocation_error;
}
uint8_t *ptr = M_MEMORY_REALLOC (uint8_t, v->ptr, v->alloc, alloc);
uint8_t *ptr = M_MEMORY_REALLOC (m_context, uint8_t, v->ptr, v->alloc, alloc);
if (M_UNLIKELY_NOMEM (ptr == NULL)) {
goto allocation_error;
}
@@ -396,13 +396,13 @@ M_P(void, m_bstring, _reserve, m_bstring_t v, size_t n)
n = v->offset + size;
}
if (n == 0) {
M_MEMORY_FREE(uint8_t, v->ptr, v->alloc);
M_MEMORY_FREE(m_context, uint8_t, v->ptr, v->alloc);
v->offset = 0;
v->size = 0;
v->alloc = 0;
v->ptr = NULL;
} else {
uint8_t *ptr = M_MEMORY_REALLOC (uint8_t, v->ptr, v->alloc, n);
uint8_t *ptr = M_MEMORY_REALLOC (m_context, uint8_t, v->ptr, v->alloc, n);
if (M_UNLIKELY_NOMEM (ptr == NULL)) {
M_MEMORY_FULL(uint8_t, n);
}
+12 -12
View File
@@ -97,7 +97,7 @@ M_BEGIN_PROTECTED_CODE
M_F(name, _slist_node_ct) *it = *list, *next; \
while (it) { \
next = it->next; \
M_MEMORY_DEL(it); \
M_MEMORY_DEL(m_context, it); \
it = next; \
} \
*list = NULL; \
@@ -292,14 +292,14 @@ M_BEGIN_PROTECTED_CODE
M_F(name, _lf_node_t) *next = atomic_load_explicit(&node->next, \
memory_order_relaxed); \
M_F(name, _slist_clear)(node->list); \
M_MEMORY_DEL(node); \
M_MEMORY_DEL(m_context, node); \
node = next; \
} \
/* Dummy node to free too */ \
M_F(name, _lf_node_t) *dummy; \
dummy = atomic_load_explicit(&list->head, memory_order_relaxed); \
M_F(name, _slist_clear)(dummy->list); \
M_MEMORY_DEL(dummy); \
M_MEMORY_DEL(m_context, dummy); \
} \
/* System node allocator: request memory to the system.
@@ -310,7 +310,7 @@ M_BEGIN_PROTECTED_CODE
M_F(name, _alloc_node)(unsigned int initial) \
{ \
M_F(name, _lf_node_t) * node; \
node = M_MEMORY_ALLOC(M_F(name, _lf_node_t)); \
node = M_MEMORY_ALLOC(m_context, M_F(name, _lf_node_t)); \
if (M_UNLIKELY_NOMEM (node == NULL)) { \
M_MEMORY_FULL(M_F(name, _lf_node_t), 1); \
} \
@@ -319,7 +319,7 @@ M_BEGIN_PROTECTED_CODE
M_F(name, _slist_init)(node->list); \
for(unsigned i = 0; i < initial; i++) { \
M_F(name, _slist_node_ct) *n; \
n = M_MEMORY_ALLOC(M_F(name, _slist_node_ct)); \
n = M_MEMORY_ALLOC(m_context, M_F(name, _slist_node_ct)); \
if (M_UNLIKELY_NOMEM (n == NULL)) { \
M_MEMORY_FULL(M_F(name, _lf_node_t), 1); \
} \
@@ -462,7 +462,7 @@ M_BEGIN_PROTECTED_CODE
{ \
const size_t max_thread = gc_mem->max_thread; \
/* Initialize the thread data of the mempool */ \
mem->thread_data = M_MEMORY_REALLOC(M_F(name, _lfmp_thread_ct), NULL, 0, max_thread); \
mem->thread_data = M_MEMORY_REALLOC(m_context, M_F(name, _lfmp_thread_ct), NULL, 0, max_thread); \
if (M_UNLIKELY_NOMEM (mem->thread_data == NULL)) { \
M_MEMORY_FULL(M_F(name, _lfmp_thread_ct), max_thread); \
} \
@@ -494,7 +494,7 @@ M_BEGIN_PROTECTED_CODE
for(unsigned i = 0; i < max_thread;i++) { \
M_F(name, _lfmp_thread_clear)(&mem->thread_data[i]); \
} \
M_MEMORY_FREE(M_F(name, _lfmp_thread_ct), mem->thread_data, max_thread); \
M_MEMORY_FREE(m_context, M_F(name, _lfmp_thread_ct), mem->thread_data, max_thread); \
mem->thread_data = NULL; \
M_F(name, _lflist_clear)(mem->empty); \
M_F(name, _lflist_clear)(mem->free); \
@@ -584,7 +584,7 @@ m_gc_init(m_gc_t gc_mem, size_t max_thread)
atomic_init(&gc_mem->ticket, 0UL);
m_genint_init(gc_mem->thread_alloc, (unsigned int) max_thread);
gc_mem->thread_data = M_MEMORY_REALLOC(m_gc_lfmp_thread_ct, NULL, 0, max_thread);
gc_mem->thread_data = M_MEMORY_REALLOC(m_context, m_gc_lfmp_thread_ct, NULL, 0, max_thread);
if (M_UNLIKELY_NOMEM (gc_mem->thread_data == NULL)) {
M_MEMORY_FULL(m_gc_lfmp_thread_ct, max_thread);
}
@@ -604,7 +604,7 @@ m_gc_clear(m_gc_t gc_mem)
for(m_gc_tid_t i = 0; i < gc_mem->max_thread;i++) {
m_core_backoff_clear(gc_mem->thread_data[i].bkoff);
}
M_MEMORY_FREE(m_gc_lfmp_thread_ct, gc_mem->thread_data, gc_mem->max_thread);
M_MEMORY_FREE(m_context, m_gc_lfmp_thread_ct, gc_mem->thread_data, gc_mem->max_thread);
gc_mem->thread_data = NULL;
m_genint_clear(gc_mem->thread_alloc);
}
@@ -753,7 +753,7 @@ m_vlapool_init(m_vlapool_t mem, m_gc_t gc_mem)
const size_t max_thread = gc_mem->max_thread;
/* Initialize the thread data of the vlapool */
mem->thread_data = M_MEMORY_REALLOC(m_vlapool_lfmp_thread_ct, NULL, 0, max_thread);
mem->thread_data = M_MEMORY_REALLOC(m_context, m_vlapool_lfmp_thread_ct, NULL, 0, max_thread);
if (M_UNLIKELY_NOMEM (mem->thread_data == NULL)) {
M_MEMORY_FULL(m_vlapool_lfmp_thread_ct, max_thread);
}
@@ -779,7 +779,7 @@ m_vlapool_clear(m_vlapool_t mem)
for(unsigned i = 0; i < max_thread;i++) {
m_vlapool_lfmp_thread_clear(&mem->thread_data[i]);
}
M_MEMORY_FREE(m_vlapool_lfmp_thread_ct, mem->thread_data, max_thread);
M_MEMORY_FREE(m_context, m_vlapool_lfmp_thread_ct, mem->thread_data, max_thread);
mem->thread_data = NULL;
m_vlapool_lflist_clear(mem->empty);
M_ASSERT(m_vlapool_lflist_empty_p(mem->to_be_reclaimed));
@@ -802,7 +802,7 @@ m_vlapool_new(m_vlapool_t mem, m_gc_tid_t id, size_t size)
size += offsetof(struct m_vlapool_slist_node_s, data);
// Simply wrap around a system call to get the memory
char *ptr = M_MEMORY_REALLOC(char, NULL, 0, size);
char *ptr = M_MEMORY_REALLOC(m_context, char, NULL, 0, size);
// TODO: save the allocated size somewhere (create a new field in vla)
// FIXME: Bug, we call DEL operator to free the node, but we have allocated it with the REALLOC one!
// And they are not necessarily compatible as per the spec (even if they are if they both use 'free')
+26 -18
View File
@@ -363,39 +363,47 @@ M_BEGIN_PROTECTED_CODE
explicit cast) */
/* Define allocators for object:
* void *M_MEMORY_ALLOC(type): Return a pointer to a new object of type 'type'
* void *M_MEMORY_ALLOC(ctx, type):
* Return a pointer to a new object of type 'type'
* It returns NULL in case of memory allocation failure.
* void M_MEMORY_DEL(ptr): Free the object associated to the pointer.
* void M_MEMORY_DEL(ctx, ptr):
* Free the object associated to the pointer.
* By default, 'context' does nothing.
* 'context' is the context parameter given to the memory functions to identify where to create the object.
* It exists only if M_USE_CONTEXT has been globally defined.
*/
#ifndef M_MEMORY_ALLOC
#ifdef __cplusplus
# include <cstdlib>
# define M_MEMORY_ALLOC(type) ((type*)std::malloc (sizeof (type)))
# define M_MEMORY_DEL(ptr) std::free(ptr)
# define M_MEMORY_ALLOC(ctx, type) ((type*)std::malloc (sizeof (type)))
# define M_MEMORY_DEL(ctx, ptr) std::free(ptr)
#else
# define M_MEMORY_ALLOC(type) malloc (sizeof (type))
# define M_MEMORY_DEL(ptr) free(ptr)
# define M_MEMORY_ALLOC(ctx, type) malloc (sizeof (type))
# define M_MEMORY_DEL(ctx, ptr) free(ptr)
#endif
#endif
/* Define allocators for array
* void *M_MEMORY_REALLOC(type, ptr, o, n, perm): Return a pointer to a new array of 'n' object of type 'type'.
* void *M_MEMORY_REALLOC(context, type, ptr, o, n, perm):
* Return a pointer to a new array of 'n' object of type 'type'.
* If ptr is NULL, it creates a new array of type 'type' and size 'n'
* If ptr is not null, it reallocates the given array of type 'type' and size 'o' to the new size.
* It returns NULL in case of memory allocation failure.
* void M_MEMORY_FREE(type, ptr, o): Free the object associated to the array of type 'type' at base 'ptr' of size 'o'.
* By default, old size do nothing.
* Can use local optional named parameter "m_context" which is defined by the called of the macro if M_USE_CONTEXT is defined.
* void M_MEMORY_FREE(type, ptr, o):
* Free the object associated to the array of type 'type' at base 'ptr' of size 'o'.
* By default, 'o' size and 'context' do nothing.
* 'context' is the context parameter given to the memory functions to identify where to create the object.
* It exists only if M_USE_CONTEXT has been globally defined.
*/
#ifndef M_MEMORY_REALLOC
#ifdef __cplusplus
# include <cstdlib>
# define M_MEMORY_REALLOC(type, ptr, o, n) \
# define M_MEMORY_REALLOC(ctx, type, ptr, o, n) \
((type*) (M_UNLIKELY ((n) > SIZE_MAX / sizeof(type)) ? NULL : std::realloc ((ptr), (n)*sizeof (type))))
# define M_MEMORY_FREE(type, ptr, o) std::free(ptr)
# define M_MEMORY_FREE(ctx, type, ptr, o) std::free(ptr)
#else
# define M_MEMORY_REALLOC(type, ptr, o, n) (M_UNLIKELY ((n) > SIZE_MAX / sizeof(type)) ? NULL : realloc ((ptr), (n)*sizeof (type)))
# define M_MEMORY_FREE(type, ptr, o) free(ptr)
# define M_MEMORY_REALLOC(ctx, type, ptr, o, n) (M_UNLIKELY ((n) > SIZE_MAX / sizeof(type)) ? NULL : realloc ((ptr), (n)*sizeof (type)))
# define M_MEMORY_FREE(ctx, type, ptr, o) free(ptr)
#endif
#endif
@@ -3632,7 +3640,6 @@ M_INLINE size_t m_core_cstr_hash(const char str[])
#define M_CALL_MOVE(oplist, ...) M_APPLY_API(M_GET_MOVE oplist, oplist, __VA_ARGS__)
#define M_CALL_SWAP(oplist, ...) M_APPLY_API(M_GET_SWAP oplist, oplist, __VA_ARGS__)
#define M_CALL_CLEAR(oplist, ...) M_APPLY_API(M_GET_CLEAR oplist, oplist, __VA_ARGS__)
#define M_CALL_NEW(oplist, ...) M_APPLY_API(M_GET_NEW oplist, oplist, __VA_ARGS__)
#define M_CALL_HASH(oplist, ...) M_APPLY_API(M_GET_HASH oplist, oplist, __VA_ARGS__)
#define M_CALL_EQUAL(oplist, ...) M_APPLY_API(M_GET_EQUAL oplist, oplist, __VA_ARGS__)
#define M_CALL_CMP(oplist, ...) M_APPLY_API(M_GET_CMP oplist, oplist, __VA_ARGS__)
@@ -3691,9 +3698,10 @@ M_INLINE size_t m_core_cstr_hash(const char str[])
//#define M_CALL_PROPERTIES(oplist, ...) M_APPLY_API(M_GET_PROPERTIES oplist, oplist, __VA_ARGS__)
//#define M_CALL_EMPLACE_TYPE(oplist, ...) M_APPLY_API(M_GET_EMPLACE_TYPE oplist, oplist, __VA_ARGS__)
// As attribute customization
#define M_CALL_DEL(oplist, ...) M_APPLY_API(M_GET_DEL oplist, oplist, __VA_ARGS__)
#define M_CALL_REALLOC(oplist, ...) M_APPLY_API(M_GET_REALLOC oplist, oplist, __VA_ARGS__)
#define M_CALL_FREE(oplist, ...) M_APPLY_API(M_GET_FREE oplist, oplist, __VA_ARGS__)
#define M_CALL_NEW(oplist, ...) M_APPLY_API(M_GET_NEW oplist, oplist, m_context, __VA_ARGS__)
#define M_CALL_DEL(oplist, ...) M_APPLY_API(M_GET_DEL oplist, oplist, m_context, __VA_ARGS__)
#define M_CALL_REALLOC(oplist, ...) M_APPLY_API(M_GET_REALLOC oplist, oplist, m_context, __VA_ARGS__)
#define M_CALL_FREE(oplist, ...) M_APPLY_API(M_GET_FREE oplist, oplist, m_context, __VA_ARGS__)
#define M_CALL_MEMPOOL(oplist, ...) M_APPLY_API(M_GET_MEMPOOL oplist, oplist, __VA_ARGS__)
#define M_CALL_MEMPOOL_LINKAGE(oplist, ...) M_APPLY_API(M_GET_MEMPOOL_LINKAGE oplist, oplist, __VA_ARGS__)
//#define M_CALL_SIZE(oplist, ...) M_APPLY_API(M_GET_SIZE oplist, oplist, __VA_ARGS__)
+2 -2
View File
@@ -104,9 +104,9 @@
// OPLIST for the node deletion
#ifdef M_USE_CONTEXT
#define M_D3QU3_NODE_DEL_OPLIST(name) (DEL(API_0P(M_F(name, _node_list_i_del))))
#else
#define M_D3QU3_NODE_DEL_OPLIST(name) (DEL(M_F(name, _node_list_i_del)))
#else
#define M_D3QU3_NODE_DEL_OPLIST(name) (DEL(API(M_F(name, _node_list_i_del), NONE, ARG2)))
#endif
/* Define the types.
+2 -2
View File
@@ -108,7 +108,7 @@ M_P(void, m_genint, _init, m_genint_t s, unsigned int n)
M_ASSERT (s != NULL && n > 0 && n <= M_GENINT_MAX_ALLOC);
const size_t alloc = (n + M_GEN1NT_LIMBSIZE - 1) / M_GEN1NT_LIMBSIZE;
const unsigned int index = n % M_GEN1NT_LIMBSIZE;
atomic_ullong *ptr = M_MEMORY_REALLOC (atomic_ullong, NULL, 0, alloc);
atomic_ullong *ptr = M_MEMORY_REALLOC (m_context, atomic_ullong, NULL, 0, alloc);
if (M_UNLIKELY_NOMEM (ptr == NULL)) {
M_MEMORY_FULL(atomic_ullong, alloc);
}
@@ -127,7 +127,7 @@ M_P(void, m_genint, _init, m_genint_t s, unsigned int n)
M_P(void, m_genint, _clear, m_genint_t s)
{
M_GEN1NT_CONTRACT(s);
M_MEMORY_FREE(atomic_ullong, s->data, s->max+1);
M_MEMORY_FREE(m_context, atomic_ullong, s->data, s->max+1);
s->data = NULL;
}
+3 -3
View File
@@ -116,7 +116,7 @@
M_F(name,_init)(name_t mem) \
{ \
mem->free_list = NULL; \
mem->current_segment = M_MEMORY_ALLOC(M_F(name,_segment_ct)); \
mem->current_segment = M_MEMORY_ALLOC(m_context, M_F(name,_segment_ct)); \
if (M_UNLIKELY_NOMEM(mem->current_segment == NULL)) { \
M_MEMORY_FULL(M_F(name,_segment_ct), 1); \
} \
@@ -132,7 +132,7 @@
M_F(name,_segment_ct) *segment = mem->current_segment; \
while (segment != NULL) { \
M_F(name,_segment_ct) *next = segment->next; \
M_MEMORY_DEL (segment); \
M_MEMORY_DEL (m_context, segment); \
segment = next; \
} \
/* Clean pointers to be safer */ \
@@ -157,7 +157,7 @@
unsigned int count = segment->count; \
/* If segment is full, allocate a new one from the system */ \
if (M_UNLIKELY (count >= M_USE_MEMPOOL_MAX_PER_SEGMENT(type))) { \
M_F(name,_segment_ct) *new_segment = M_MEMORY_ALLOC (M_F(name,_segment_ct)); \
M_F(name,_segment_ct) *new_segment = M_MEMORY_ALLOC (m_context, M_F(name,_segment_ct)); \
if (M_UNLIKELY_NOMEM (new_segment == NULL)) { \
M_MEMORY_FULL(M_F(name,_segment_ct), 1); \
} \
+2 -2
View File
@@ -390,7 +390,7 @@ M_P(void, m_snapsh0t, _mrsw_init, m_snapsh0t_mrsw_ct s, size_t n)
n += M_SNAPSH0T_SPMC_EXTRA_BUFFER;
// Initialize the counters to zero (no reader use it)
atomic_uint *ptr = M_MEMORY_REALLOC (atomic_uint, NULL, 0, n);
atomic_uint *ptr = M_MEMORY_REALLOC (m_context, atomic_uint, NULL, 0, n);
if (M_UNLIKELY_NOMEM (ptr == NULL)) {
M_MEMORY_FULL(atomic_uint, n);
}
@@ -416,7 +416,7 @@ M_P(void, m_snapsh0t, _mrsw_init, m_snapsh0t_mrsw_ct s, size_t n)
M_P(void, m_snapsh0t, _mrsw_clear, m_snapsh0t_mrsw_ct s)
{
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
M_MEMORY_FREE (atomic_uint, s->cptTab, s->n_reader+M_SNAPSH0T_SPMC_EXTRA_BUFFER);
M_MEMORY_FREE (m_context, atomic_uint, s->cptTab, s->n_reader+M_SNAPSH0T_SPMC_EXTRA_BUFFER);
m_genint_clear M_R(s->freeList);
s->cptTab = NULL;
s->n_reader = 0;
+5 -5
View File
@@ -285,7 +285,7 @@ M_P(void, m_string, _clear, m_string_t v)
{
M_STR1NG_CONTRACT(v);
if (!m_str1ng_embedded_p(v)) {
M_MEMORY_FREE(char, v->u.heap.ptr, m_string_capacity(v));
M_MEMORY_FREE(m_context, char, v->u.heap.ptr, m_string_capacity(v));
v->u.heap.ptr = NULL;
}
/* This is not needed but is safer to make
@@ -309,7 +309,7 @@ M_P(char *, m_string, _clear_get_cstr, m_string_t v)
p = &v->u.buffer[0];
// Need to allocate a heap string to return the copy.
size_t alloc = m_string_size(v)+1;
char *ptr = M_MEMORY_REALLOC (char, NULL, 0, alloc);
char *ptr = M_MEMORY_REALLOC (m_context, char, NULL, 0, alloc);
if (M_UNLIKELY_NOMEM (ptr == NULL)) {
M_MEMORY_FULL(char, alloc);
}
@@ -386,7 +386,7 @@ M_P(char *, m_str1ng, _fit2size, m_string_t v, size_t size_alloc)
}
char *ptr = m_str1ng_embedded_p(v) ? NULL : v->u.heap.ptr;
//FIXME: old_alloc may not be NULL if ptr is NULL.
ptr = M_MEMORY_REALLOC (char, ptr, old_alloc, alloc);
ptr = M_MEMORY_REALLOC (m_context, char, ptr, old_alloc, alloc);
if (M_UNLIKELY_NOMEM (ptr == NULL)) {
M_MEMORY_FULL(char, alloc);
}
@@ -429,7 +429,7 @@ M_P(void, m_string, _reserve, m_string_t v, size_t alloc)
char *oldptr = v->u.heap.ptr;
memcpy(ptr, oldptr, size+1);
// Free the allocated memory on the heap
M_MEMORY_FREE(char, oldptr, m_string_capacity(v));
M_MEMORY_FREE(m_context, char, oldptr, m_string_capacity(v));
v->u.buffer[sizeof(m_string_t)-2] = 0;
v->u.buffer[sizeof(m_string_t)-1] = (char) size;
} else {
@@ -444,7 +444,7 @@ M_P(void, m_string, _reserve, m_string_t v, size_t alloc)
M_MEMORY_FULL(char, alloc);
}
char *ptr = m_str1ng_embedded_p(v) ? NULL : v->u.heap.ptr;
ptr = M_MEMORY_REALLOC (char, ptr, m_string_capacity(v), r_alloc);
ptr = M_MEMORY_REALLOC (m_context, char, ptr, m_string_capacity(v), r_alloc);
if (M_UNLIKELY_NOMEM (ptr == NULL) ) {
M_MEMORY_FULL(char, alloc);
}
+4 -4
View File
@@ -237,7 +237,7 @@ typedef struct m_worker_sync_s {
M_GLOBAL_CONTEXT(); \
M_MAP3(M_WORK3R_SPAWN_EXTEND_DEF_CALLBACK_CLEAR, data, __VA_ARGS__) \
/* TODO: Overload */ \
M_MEMORY_DEL(p); \
M_MEMORY_DEL(m_context, p); \
} \
\
M_INLINE void \
@@ -265,7 +265,7 @@ typedef struct m_worker_sync_s {
{ \
M_GLOBAL_CONTEXT(); \
if (!m_work3r_queue_full_p(block->worker->queue_g)) { \
struct M_C3(m_worker_, name, _s) *p = M_MEMORY_ALLOC ( struct M_C3(m_worker_, name, _s)); \
struct M_C3(m_worker_, name, _s) *p = M_MEMORY_ALLOC (m_context, struct M_C3(m_worker_, name, _s)); \
if (M_UNLIKELY_NOMEM(p == NULL)) { \
M_MEMORY_FULL(struct M_C3(m_worker_, name, _s), 1); \
} \
@@ -412,7 +412,7 @@ m_worker_init(m_worker_t g, int numWorker, unsigned int extraQueue, void (*reset
M_ASSERT(numWorker >= 0);
size_t numWorker_st = (size_t) numWorker;
M_GLOBAL_CONTEXT();
g->worker = M_MEMORY_REALLOC(m_work3r_thread_ct, NULL, 0, numWorker_st);
g->worker = M_MEMORY_REALLOC(m_context, m_work3r_thread_ct, NULL, 0, numWorker_st);
if (M_UNLIKELY_NOMEM (g->worker == NULL)) {
M_MEMORY_FULL(m_work3r_thread_ct, numWorker_st);
}
@@ -457,7 +457,7 @@ m_worker_clear(m_worker_t g)
m_thread_join(g->worker[i].id);
}
// Clear memory
M_MEMORY_FREE(m_work3r_thread_ct, g->worker, g->numWorker_g);
M_MEMORY_FREE(m_context, m_work3r_thread_ct, g->worker, g->numWorker_g);
m_mutex_clear(g->lock);
m_cond_clear(g->a_thread_ends);
m_work3r_queue_clear (g->queue_g);
+1 -1
View File
@@ -271,7 +271,7 @@ typedef struct test_s {
static void test_init(test_t *p) { memset(p->buffer, 0x00, 52); }
static void test_clear(test_t *p) { memset(p->buffer, 0xFF, 52); }
ISHARED_PTR_DEF(ishared_itest, test_t,
(INIT(test_init M_IPTR), CLEAR(test_clear M_IPTR), DEL(free)))
(INIT(test_init M_IPTR), CLEAR(test_clear M_IPTR), DEL(API(free, NONE, ARG2))))
typedef struct test2_s {
ISHARED_PTR_INTERFACE(ishared_itest2, struct test_s);
+1 -1
View File
@@ -41,7 +41,7 @@ START_COVERAGE
ILIST_DEF(ilist_tname, test_t, M_OPEXTEND(M_POD_OPLIST, EQUAL(API_6(test_equal_p))))
END_COVERAGE
ILIST_DEF(ilist_free, test_t, (DEL(free)))
ILIST_DEF(ilist_free, test_t, (DEL(API(free, NONE, ARG2))))
typedef struct testd_s {
double n;
+8 -8
View File
@@ -37,16 +37,16 @@ static inline void test_obj_except_trigger(void);
extern int test_obj_except__malloc_counter;
#ifdef __cplusplus
# include <cstdlib>
# define M_MEMORY_ALLOC(type) (test_obj_except_trigger(), test_obj_except__malloc_counter++, (type*)std::malloc (sizeof (type)))
# define M_MEMORY_DEL(ptr) (test_obj_except__malloc_counter-=(ptr != NULL), std::free(ptr))
# define M_MEMORY_REALLOC(type, ptr, o, n) \
# define M_MEMORY_ALLOC(ctx, type) (test_obj_except_trigger(), test_obj_except__malloc_counter++, (type*)std::malloc (sizeof (type)))
# define M_MEMORY_DEL(ctx, ptr) (test_obj_except__malloc_counter-=(ptr != NULL), std::free(ptr))
# define M_MEMORY_REALLOC(ctx, type, ptr, o, n) \
((type*) (test_obj_except_trigger(), test_obj_except__malloc_counter+= (ptr == NULL), std::realloc ((ptr), (n)*sizeof (type))))
# define M_MEMORY_FREE(type, ptr, o) (test_obj_except__malloc_counter-=(ptr != NULL), std::free(ptr))
# define M_MEMORY_FREE(ctx, type, ptr, o) (test_obj_except__malloc_counter-=(ptr != NULL), std::free(ptr))
#else
# define M_MEMORY_ALLOC(type) (test_obj_except_trigger(), test_obj_except__malloc_counter++, malloc (sizeof (type)))
# define M_MEMORY_DEL(ptr) (test_obj_except__malloc_counter-=(ptr != NULL), free(ptr))
# define M_MEMORY_REALLOC(type, ptr, o, n) (test_obj_except_trigger(), test_obj_except__malloc_counter+=(ptr == NULL), realloc ((ptr), (n)*sizeof (type)))
# define M_MEMORY_FREE(type, ptr, o) (test_obj_except__malloc_counter-=(ptr != NULL), free(ptr))
# define M_MEMORY_ALLOC(ctx, type) (test_obj_except_trigger(), test_obj_except__malloc_counter++, malloc (sizeof (type)))
# define M_MEMORY_DEL(ctx, ptr) (test_obj_except__malloc_counter-=(ptr != NULL), free(ptr))
# define M_MEMORY_REALLOC(ctx, type, ptr, o, n) (test_obj_except_trigger(), test_obj_except__malloc_counter+=(ptr == NULL), realloc ((ptr), (n)*sizeof (type)))
# define M_MEMORY_FREE(ctx, type, ptr, o) (test_obj_except__malloc_counter-=(ptr != NULL), free(ptr))
#endif
// Include M*LIB headers
+2 -2
View File
@@ -68,8 +68,8 @@ static inline void overloaded_free(size_t st, void *ptr, size_t n)
free(p);
}
#define M_MEMORY_REALLOC(type, ptr, o, n) (type *) overloaded_realloc(sizeof(type), ptr, o, n)
#define M_MEMORY_FREE(type, ptr, o) overloaded_free(sizeof(type), ptr, o)
#define M_MEMORY_REALLOC(ctx, type, ptr, o, n) (type *) overloaded_realloc(sizeof(type), ptr, o, n)
#define M_MEMORY_FREE(ctx, type, ptr, o) overloaded_free(sizeof(type), ptr, o)
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////