1.. _sys_mem_blocks:
2
3Memory Blocks Allocator
4#######################
5
6The Memory Blocks Allocator allows memory blocks to be dynamically
7allocated from a designated memory region, where:
8
9* All memory blocks have a single fixed size.
10
11* Multiple blocks can be allocated or freed at the same time.
12
13* A group of blocks allocated together may not be contiguous.
14  This is useful for operations such as scatter-gather DMA transfers.
15
16* Bookkeeping of allocated blocks is done outside of the associated
17  buffer (unlike memory slab). This allows the buffer to reside in
18  memory regions where these can be powered down to conserve energy.
19
20.. contents::
21    :local:
22    :depth: 2
23
24Concepts
25********
26
27Any number of Memory Blocks Allocator can be defined (limited only by
28available RAM). Each allocator is referenced by its memory address.
29
30A memory blocks allocator has the following key properties:
31
32* The **block size** of each block, measured in bytes.
33  It must be at least 4N bytes long, where N is greater than 0.
34
35* The **number of blocks** available for allocation.
36  It must be greater than zero.
37
38* A **buffer** that provides the memory for the memory slab's blocks.
39  It must be at least "block size" times "number of blocks" bytes long.
40
41* A **blocks bitmap** to keep track of which block has been allocated.
42
43The buffer must be aligned to an N-byte boundary, where N is a power of 2
44larger than 2 (i.e. 4, 8, 16, ...). To ensure that all memory blocks in
45the buffer are similarly aligned to this boundary, the block size must
46also be a multiple of N.
47
48Due to the use of internal bookkeeping structures and their creation,
49each memory blocks allocator must be declared and defined at compile time.
50
51Internal Operation
52==================
53
54Each buffer associated with an allocator is an array of fixed-size blocks,
55with no wasted space between the blocks.
56
57The memory blocks allocator keeps track of unallocated blocks using
58a bitmap.
59
60Memory Blocks Allocator
61***********************
62
63Internally, the memory blocks allocator uses a bitmap to keep track of
64which blocks have been allocated. Each allocator, utilizing
65the ``sys_bitarray`` interface, gets memory blocks one by one from
66the backing buffer up to the requested number of blocks.
67All the metadata about an allocator is stored outside of the backing
68buffer. This allows the memory region of the backing buffer to be
69powered down to conserve energy, as the allocator code never touches
70the content of the buffer.
71
72Multi Memory Blocks Allocator Group
73***********************************
74
75The Multi Memory Blocks Allocator Group utility functions provide
76a convenient to manage a group of allocators. A custom allocator
77choosing function is used to choose which allocator to use among
78this group.
79
80An allocator group should be initialized at runtime via
81:c:func:`sys_multi_mem_blocks_init`. Each allocator can then be
82added via :c:func:`sys_multi_mem_blocks_add_allocator`.
83
84To allocate memory blocks from group,
85:c:func:`sys_multi_mem_blocks_alloc` is called with an opaque
86"configuration" parameter. This parameter is passed directly to
87the allocator choosing function so that an appropriate allocator
88can be chosen. After an allocator is chosen, memory blocks are
89allocated via :c:func:`sys_mem_blocks_alloc`.
90
91Allocated memory blocks can be freed via
92:c:func:`sys_multi_mem_blocks_free`. The caller does not need to
93pass a configuration parameter. The allocator code matches
94the passed in memory addresses to find the correct allocator
95and then memory blocks are freed via :c:func:`sys_mem_blocks_free`.
96
97Usage
98*****
99
100Defining a Memory Blocks Allocator
101==================================
102
103A memory blocks allocator is defined using a variable of type
104:c:type:`sys_mem_blocks_t`. It needs to be defined and initialized
105at compile time by calling :c:macro:`SYS_MEM_BLOCKS_DEFINE`.
106
107The following code defines and initializes a memory blocks allocator
108which has 4 blocks that are 64 bytes long, each of which is aligned
109to a 4-byte boundary:
110
111.. code-block:: c
112
113   SYS_MEM_BLOCKS_DEFINE(allocator, 64, 4, 4);
114
115Similarly, you can define a memory blocks allocator in private scope:
116
117.. code-block:: c
118
119   SYS_MEM_BLOCKS_DEFINE_STATIC(static_allocator, 64, 4, 4);
120
121A pre-defined buffer can also be provided to the allocator where
122the buffer can be placed separately. Note that the alignment of
123the buffer needs to be done at its definition.
124
125.. code-block:: c
126
127   uint8_t __aligned(4) backing_buffer[64 * 4];
128   SYS_MEM_BLOCKS_DEFINE_WITH_EXT_BUF(allocator, 64, 4, backing_buffer);
129
130Allocating Memory Blocks
131========================
132
133Memory blocks can be allocated by calling :c:func:`sys_mem_blocks_alloc`.
134
135.. code-block:: c
136
137   int ret;
138   uintptr_t blocks[2];
139
140   ret = sys_mem_blocks_alloc(allocator, 2, blocks);
141
142If ``ret == 0``, the array ``blocks`` will contain an array of memory
143addresses pointing to the allocated blocks.
144
145Releasing a Memory Block
146========================
147
148Memory blocks are released by calling :c:func:`sys_mem_blocks_free`.
149
150The following code builds on the example above which allocates 2 memory blocks,
151then releases them once they are no longer needed.
152
153.. code-block:: c
154
155   int ret;
156   uintptr_t blocks[2];
157
158   ret = sys_mem_blocks_alloc(allocator, 2, blocks);
159   ... /* perform some operations on the allocated memory blocks */
160   ret = sys_mem_blocks_free(allocator, 2, blocks);
161
162Using Multi Memory Blocks Allocator Group
163=========================================
164
165The following code demonstrates how to initialize an allocator group:
166
167.. code-block:: c
168
169   sys_mem_blocks_t *choice_fn(struct sys_multi_mem_blocks *group, void *cfg)
170   {
171       ...
172   }
173
174   SYS_MEM_BLOCKS_DEFINE(allocator0, 64, 4, 4);
175   SYS_MEM_BLOCKS_DEFINE(allocator1, 64, 4, 4);
176
177   static sys_multi_mem_blocks_t alloc_group;
178
179   sys_multi_mem_blocks_init(&alloc_group, choice_fn);
180   sys_multi_mem_blocks_add_allocator(&alloc_group, &allocator0);
181   sys_multi_mem_blocks_add_allocator(&alloc_group, &allocator1);
182
183To allocate and free memory blocks from the group:
184
185.. code-block:: c
186
187   int ret;
188   uintptr_t blocks[1];
189   size_t blk_size;
190
191   ret = sys_multi_mem_blocks_alloc(&alloc_group, UINT_TO_POINTER(0),
192                                    1, blocks, &blk_size);
193
194   ret = sys_multi_mem_blocks_free(&alloc_group, 1, blocks);
195
196API Reference
197*************
198
199.. doxygengroup:: mem_blocks_apis
200