Similar to the last patch, there was a spot in block recombination
where the lock would be released while the combined block was being
held allocated. That means that when recombining a single top-level
block, it was possible for the entire heap to look allocated.
Make the combination and re-addition of the larger block atomic.
Requires a little surgery to the structure of the code, so this is a
little more involved than the earlier fix.
Signed-off-by: Andy Ross <andrew.j.ross@intel.com>
The mempool operations need to be atomic, but because of latency
concerns (the allocator is intended for use in an ISR) the locking was
designed to be as minimal as possible. And it... mostly got it right.
All the list handling was correctly synchronized. The merging of four
child blocks into a parent block was atomic. The splitting of a block
into four children was atomic.
BUT: there was a moment between the allocation of a large block and
the re-addition of its three unused children where the lock was being
released. This meant that another context (e.g. an ISR that just
fired, interrupting the existing call to k_mem_pool_alloc()) would see
some memory "missing" that wasn't actually allocated. And if this
happens to have been the top level block, it's entirely possible that
the whole heap looks empty, even though the other allocator might have
been doing only the smallest allocation!
Fix that by making the "remove a block then add back the three
children we don't use" into an atomic step. We can still relax the
lock between levels as we split the subblocks further.
(Finally, note that this trick allows a somewhat cleaner API as we can
do our "retry due to race" step internally by walking back up the
block size list instead of forcing our caller to do it via that weird
-EAGAIN return value.)
Fixes#11022
Signed-off-by: Andy Ross <andrew.j.ross@intel.com>
Fix a compile warning if we build using int types defined to match the
compiler. We get the following warnings:
lib/mempool/mempool.c: In function ‘sys_mem_pool_alloc’:
lib/mempool/mempool.c:317:48: warning: passing argument 3 of ‘_sys_mem_pool_block_alloc’ from incompatible pointer type [-Wincompatible-pointer-types]
if (_sys_mem_pool_block_alloc(&p->base, size, &level, &block,
^
lib/mempool/mempool.c:221:5: note: expected ‘u32_t * {aka long unsigned int *}’ but argument is of type ‘int *’
int _sys_mem_pool_block_alloc(struct sys_mem_pool_base *p, size_t size,
^~~~~~~~~~~~~~~~~~~~~~~~~
lib/mempool/mempool.c:317:56: warning: passing argument 4 of ‘_sys_mem_pool_block_alloc’ from incompatible pointer type [-Wincompatible-pointer-types]
if (_sys_mem_pool_block_alloc(&p->base, size, &level, &block,
^
lib/mempool/mempool.c:221:5: note: expected ‘u32_t * {aka long unsigned int *}’ but argument is of type ‘int *’
int _sys_mem_pool_block_alloc(struct sys_mem_pool_base *p, size_t size,
^~~~~~~~~~~~~~~~~~~~~~~~~
Make local variables block & level u32_t to match what
_sys_mem_pool_block_alloc expects.
Signed-off-by: Kumar Gala <kumar.gala@linaro.org>
Under GNU C, sizeof(void) = 1. This commit merely makes it explicit u8.
Pointer arithmetics over void types is:
* A GNU C extension
* Not supported by Clang
* Illegal across all ISO C standards
See also: https://gcc.gnu.org/onlinedocs/gcc/Pointer-Arith.html
Signed-off-by: Mark Ruvald Pedersen <mped@oticon.com>
Make if statement using pointers explicitly check whether the value is
NULL or not.
The C standard does not say that the null pointer is the same as the
pointer to memory address 0 and because of this is a good practice
always compare with the macro NULL.
Signed-off-by: Flavio Ceolin <flavio.ceolin@intel.com>
When a mempool is created with a large number of maximum-size blocks,
the logic for initializing max_inline_level (i.e. when to union the
bitmask with the pointer and when to use the pointer directly) was
wrong. The default state was "zero", which implies that level 0
should be inlined, but that's wrong with >32 base blocks.
Additionally, the type was unsigned, making the "level zero is a
pointer" situation impossible to represent.
Fixes#6727
Signed-off-by: Andy Ross <andrew.j.ross@intel.com>
We would like to offer the capability to have memory pool heap data
structures that are usable from user mode threads. The current
k_mem_pool implementation uses IRQ locking and system-wide membership
lists that make it incompatible with user mode constraints.
However, much of the existing memory pool code can be abstracted to some
common functions that are used by both k_mem_pool and the new
sys_mem_pool implementations.
The sys_mem_pool implementation has the following differences:
* The alloc/free APIs work directly with pointers, no internal memory
block structures are exposed to the end user. A pointer to the source
pool is provided for allocation, but freeing memory just requires the
pointer and nothing else.
* k_mem_pool uses IRQ locks and required very fine-grained locking in
order to not affect system latency. sys_mem_pools just use a semaphore
to protect the pool data structures at the API level, since there aren't
implications for system responsiveness with this kind of concurrency
control.
* sys_mem_pools do not support the notion of timeouts for requesting
memory.
* sys_mem_pools are specified at compile time with macros, just like
kernel memory pools. Alternative forms of specification at runtime
will be a later enhancement.
Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>