TNeo  v1.08
tn_fmem.h
Go to the documentation of this file.
1 /*******************************************************************************
2  *
3  * TNeo: real-time kernel initially based on TNKernel
4  *
5  * TNKernel: copyright 2004, 2013 Yuri Tiomkin.
6  * PIC32-specific routines: copyright 2013, 2014 Anders Montonen.
7  * TNeo: copyright 2014 Dmitry Frank.
8  *
9  * TNeo was born as a thorough review and re-implementation of
10  * TNKernel. The new kernel has well-formed code, inherited bugs are fixed
11  * as well as new features being added, and it is tested carefully with
12  * unit-tests.
13  *
14  * API is changed somewhat, so it's not 100% compatible with TNKernel,
15  * hence the new name: TNeo.
16  *
17  * Permission to use, copy, modify, and distribute this software in source
18  * and binary forms and its documentation for any purpose and without fee
19  * is hereby granted, provided that the above copyright notice appear
20  * in all copies and that both that copyright notice and this permission
21  * notice appear in supporting documentation.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE DMITRY FRANK AND CONTRIBUTORS "AS IS"
24  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DMITRY FRANK OR CONTRIBUTORS BE
27  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
33  * THE POSSIBILITY OF SUCH DAMAGE.
34  *
35  ******************************************************************************/
36 
37 /**
38  * \file
39  *
40  * Fixed memory blocks pool.
41  *
42  * A fixed-sized memory blocks pool is used for managing fixed-sized memory
43  * blocks dynamically. A pool has a memory area where fixed-sized memory blocks
44  * are allocated and the wait queue for acquiring a memory block. If there are
45  * no free memory blocks, a task trying to acquire a memory block will be
46  * placed into the wait queue until a free memory block arrives (another task
47  * returns it to the memory pool).
48  *
49  * The operations of getting the block from memory pool and releasing it back
50  * take O(1) time independently of number or size of the blocks.
51  *
52  * For the useful pattern on how to use fixed memory pool together with \ref
53  * tn_dqueue.h "queue", refer to the example: `examples/queue`. Be sure to
54  * examine the readme there.
55  */
56 
57 #ifndef _TN_MEM_H
58 #define _TN_MEM_H
59 
60 /*******************************************************************************
61  * INCLUDED FILES
62  ******************************************************************************/
63 
64 #include "tn_list.h"
65 #include "tn_common.h"
66 
67 
68 
69 #ifdef __cplusplus
70 extern "C" { /*}*/
71 #endif
72 
73 /*******************************************************************************
74  * PUBLIC TYPES
75  ******************************************************************************/
76 
77 /**
78  * Fixed memory blocks pool
79  */
80 struct TN_FMem {
81  ///
82  /// id for object validity verification.
83  /// This field is in the beginning of the structure to make it easier
84  /// to detect memory corruption.
86  ///
87  /// list of tasks waiting for free memory block
89 
90  ///
91  /// block size (in bytes); note that it should be a multiple of
92  /// `sizeof(#TN_UWord})`, use a macro `TN_MAKE_ALIG_SIZE()` for that.
93  ///
94  /// @see `TN_MAKE_ALIG_SIZE()`
95  unsigned int block_size;
96  ///
97  /// capacity (total blocks count)
99  ///
100  /// free blocks count
102  ///
103  /// memory pool start address; note that it should be a multiple of
104  /// `sizeof(#TN_UWord)`.
105  void *start_addr;
106  ///
107  /// Pointer to the first free memory block. Each free block contains the
108  /// pointer to the next free memory block as the first word, or `NULL` if
109  /// this is the last block.
110  void *free_list;
111 };
112 
113 
114 /**
115  * FMem-specific fields related to waiting task,
116  * to be included in struct TN_Task.
117  */
119  /// if task tries to receive data from memory pool,
120  /// and there's no more free blocks in the pool, location to store
121  /// pointer is saved in this field
122  void *data_elem;
123 };
124 
125 
126 /*******************************************************************************
127  * PROTECTED GLOBAL DATA
128  ******************************************************************************/
129 
130 /*******************************************************************************
131  * DEFINITIONS
132  ******************************************************************************/
133 
134 /**
135  * Convenience macro for the definition of buffer for memory pool. See
136  * `tn_fmem_create()` for usage example.
137  *
138  * @param name
139  * C variable name of the buffer array (this name should be given
140  * to the `tn_fmem_create()` function as the `start_addr` argument)
141  * @param item_type
142  * Type of item in the memory pool, like `struct MyMemoryItem`.
143  * @param size
144  * Number of items in the memory pool.
145  */
146 #define TN_FMEM_BUF_DEF(name, item_type, size) \
147  TN_UWord name[ \
148  (size) \
149  * (TN_MAKE_ALIG_SIZE(sizeof(item_type)) / sizeof(TN_UWord)) \
150  ]
151 
152 
153 
154 
155 /*******************************************************************************
156  * PUBLIC FUNCTION PROTOTYPES
157  ******************************************************************************/
158 
159 /**
160  * Construct fixed memory blocks pool. `id_fmp` field should not contain
161  * `#TN_ID_FSMEMORYPOOL`, otherwise, `#TN_RC_WPARAM` is returned.
162  *
163  * Note that `start_addr` and `block_size` should be a multiple of
164  * `sizeof(#TN_UWord)`.
165  *
166  * For the definition of buffer, convenience macro `TN_FMEM_BUF_DEF()` was
167  * invented.
168  *
169  * Typical definition looks as follows:
170  *
171  * \code{.c}
172  * //-- number of blocks in the pool
173  * #define MY_MEMORY_BUF_SIZE 8
174  *
175  * //-- type for memory block
176  * struct MyMemoryItem {
177  * // ... arbitrary fields ...
178  * };
179  *
180  * //-- define buffer for memory pool
181  * TN_FMEM_BUF_DEF(my_fmem_buf, struct MyMemoryItem, MY_MEMORY_BUF_SIZE);
182  *
183  * //-- define memory pool structure
184  * struct TN_FMem my_fmem;
185  * \endcode
186  *
187  * And then, construct your `my_fmem` as follows:
188  *
189  * \code{.c}
190  * enum TN_RCode rc;
191  * rc = tn_fmem_create( &my_fmem,
192  * my_fmem_buf,
193  * TN_MAKE_ALIG_SIZE(sizeof(struct MyMemoryItem)),
194  * MY_MEMORY_BUF_SIZE );
195  * if (rc != TN_RC_OK){
196  * //-- handle error
197  * }
198  * \endcode
199  *
200  * If given `start_addr` and/or `block_size` aren't aligned properly,
201  * `#TN_RC_WPARAM` is returned.
202  *
203  * $(TN_CALL_FROM_TASK)
204  * $(TN_CALL_FROM_ISR)
205  * $(TN_LEGEND_LINK)
206  *
207  * @param fmem pointer to already allocated `struct TN_FMem`.
208  * @param start_addr pointer to start of the array; should be aligned properly,
209  * see example above
210  * @param block_size size of memory block; should be a multiple of
211  * `sizeof(#TN_UWord)`, see example above
212  * @param blocks_cnt capacity (total number of blocks in the memory pool)
213  *
214  * @return
215  * * `#TN_RC_OK` if memory pool was successfully created;
216  * * If `#TN_CHECK_PARAM` is non-zero, additional return code
217  * is available: `#TN_RC_WPARAM`.
218  *
219  * @see TN_MAKE_ALIG_SIZE
220  */
222  struct TN_FMem *fmem,
223  void *start_addr,
224  unsigned int block_size,
225  int blocks_cnt
226  );
227 
228 /**
229  * Destruct fixed memory blocks pool.
230  *
231  * All tasks that wait for free memory block become runnable with
232  * `#TN_RC_DELETED` code returned.
233  *
234  * $(TN_CALL_FROM_TASK)
235  * $(TN_CAN_SWITCH_CONTEXT)
236  * $(TN_LEGEND_LINK)
237  *
238  * @param fmem pointer to memory pool to be deleted
239  *
240  * @return
241  * * `#TN_RC_OK` if memory pool is successfully deleted;
242  * * `#TN_RC_WCONTEXT` if called from wrong context;
243  * * If `#TN_CHECK_PARAM` is non-zero, additional return codes
244  * are available: `#TN_RC_WPARAM` and `#TN_RC_INVALID_OBJ`.
245  *
246  */
247 enum TN_RCode tn_fmem_delete(struct TN_FMem *fmem);
248 
249 /**
250  * Get memory block from the pool. Start address of the memory block is returned
251  * through the `p_data` argument. The content of memory block is undefined.
252  * If there is no free block in the pool, behavior depends on `timeout` value:
253  * refer to `#TN_TickCnt`.
254  *
255  * $(TN_CALL_FROM_TASK)
256  * $(TN_CAN_SWITCH_CONTEXT)
257  * $(TN_CAN_SLEEP)
258  * $(TN_LEGEND_LINK)
259  *
260  * @param fmem
261  * Pointer to memory pool
262  * @param p_data
263  * Address of the `(void *)` to which received block address will be saved
264  * @param timeout
265  * Refer to `#TN_TickCnt`
266  *
267  * @return
268  * * `#TN_RC_OK` if block was successfully returned through `p_data`;
269  * * `#TN_RC_WCONTEXT` if called from wrong context;
270  * * Other possible return codes depend on `timeout` value,
271  * refer to `#TN_TickCnt`
272  * * If `#TN_CHECK_PARAM` is non-zero, additional return codes
273  * are available: `#TN_RC_WPARAM` and `#TN_RC_INVALID_OBJ`.
274  */
275 enum TN_RCode tn_fmem_get(
276  struct TN_FMem *fmem,
277  void **p_data,
278  TN_TickCnt timeout
279  );
280 
281 /**
282  * The same as `tn_fmem_get()` with zero timeout
283  *
284  * $(TN_CALL_FROM_TASK)
285  * $(TN_CAN_SWITCH_CONTEXT)
286  * $(TN_LEGEND_LINK)
287  */
288 enum TN_RCode tn_fmem_get_polling(struct TN_FMem *fmem, void **p_data);
289 
290 /**
291  * The same as `tn_fmem_get()` with zero timeout, but for using in the ISR.
292  *
293  * $(TN_CALL_FROM_ISR)
294  * $(TN_CAN_SWITCH_CONTEXT)
295  * $(TN_LEGEND_LINK)
296  */
297 enum TN_RCode tn_fmem_iget_polling(struct TN_FMem *fmem, void **p_data);
298 
299 
300 /**
301  * Release memory block back to the pool. The kernel does not check the
302  * validity of the membership of given block in the memory pool.
303  * If all the memory blocks in the pool are free already, `#TN_RC_OVERFLOW`
304  * is returned.
305  *
306  * $(TN_CALL_FROM_TASK)
307  * $(TN_CAN_SWITCH_CONTEXT)
308  * $(TN_LEGEND_LINK)
309  *
310  * @param fmem
311  * Pointer to memory pool.
312  * @param p_data
313  * Address of the memory block to release.
314  *
315  * @return
316  * * `#TN_RC_OK` on success
317  * * `#TN_RC_WCONTEXT` if called from wrong context;
318  * * If `#TN_CHECK_PARAM` is non-zero, additional return codes
319  * are available: `#TN_RC_WPARAM` and `#TN_RC_INVALID_OBJ`.
320  */
321 enum TN_RCode tn_fmem_release(struct TN_FMem *fmem, void *p_data);
322 
323 /**
324  * The same as `tn_fmem_get()`, but for using in the ISR.
325  *
326  * $(TN_CALL_FROM_ISR)
327  * $(TN_CAN_SWITCH_CONTEXT)
328  * $(TN_LEGEND_LINK)
329  */
330 enum TN_RCode tn_fmem_irelease(struct TN_FMem *fmem, void *p_data);
331 
332 /**
333  * Returns number of free blocks in the memory pool
334  *
335  * $(TN_CALL_FROM_TASK)
336  * $(TN_CALL_FROM_ISR)
337  * $(TN_LEGEND_LINK)
338  *
339  * @param fmem
340  * Pointer to memory pool.
341  *
342  * @return
343  * Number of free blocks in the memory pool, or -1 if wrong params were
344  * given (the check is performed if only `#TN_CHECK_PARAM` is non-zero)
345  */
346 int tn_fmem_free_blocks_cnt_get(struct TN_FMem *fmem);
347 
348 /**
349  * Returns number of used (non-free) blocks in the memory pool
350  *
351  * $(TN_CALL_FROM_TASK)
352  * $(TN_CALL_FROM_ISR)
353  * $(TN_LEGEND_LINK)
354  *
355  * @param fmem
356  * Pointer to memory pool.
357  *
358  * @return
359  * Number of used (non-free) blocks in the memory pool, or -1 if wrong
360  * params were given (the check is performed if only `#TN_CHECK_PARAM` is
361  * non-zero)
362  */
363 int tn_fmem_used_blocks_cnt_get(struct TN_FMem *fmem);
364 
365 
366 #ifdef __cplusplus
367 } /* extern "C" */
368 #endif
369 
370 #endif // _TN_MEM_H
371 
372 /*******************************************************************************
373  * end of file
374  ******************************************************************************/
375 
376 
struct TN_ListItem wait_queue
list of tasks waiting for free memory block
Definition: tn_fmem.h:88
Circular doubly linked list, for internal kernel usage.
enum TN_RCode tn_fmem_release(struct TN_FMem *fmem, void *p_data)
Release memory block back to the pool.
TN_RCode
Result code returned by kernel services.
Definition: tn_common.h:81
TN_ObjId
Magic number for object validity verification.
Definition: tn_common.h:65
unsigned long TN_TickCnt
Type for system tick count, it is used by the kernel to represent absolute tick count value as well a...
Definition: tn_common.h:188
Definitions used through the whole kernel.
int free_blocks_cnt
free blocks count
Definition: tn_fmem.h:101
enum TN_ObjId id_fmp
id for object validity verification.
Definition: tn_fmem.h:85
int blocks_cnt
capacity (total blocks count)
Definition: tn_fmem.h:98
Fixed memory blocks pool.
Definition: tn_fmem.h:80
void * free_list
Pointer to the first free memory block.
Definition: tn_fmem.h:110
int tn_fmem_free_blocks_cnt_get(struct TN_FMem *fmem)
Returns number of free blocks in the memory pool.
enum TN_RCode tn_fmem_iget_polling(struct TN_FMem *fmem, void **p_data)
The same as tn_fmem_get() with zero timeout, but for using in the ISR.
enum TN_RCode tn_fmem_get(struct TN_FMem *fmem, void **p_data, TN_TickCnt timeout)
Get memory block from the pool.
enum TN_RCode tn_fmem_get_polling(struct TN_FMem *fmem, void **p_data)
The same as tn_fmem_get() with zero timeout.
void * start_addr
memory pool start address; note that it should be a multiple of sizeof(TN_UWord). ...
Definition: tn_fmem.h:105
enum TN_RCode tn_fmem_create(struct TN_FMem *fmem, void *start_addr, unsigned int block_size, int blocks_cnt)
Construct fixed memory blocks pool.
enum TN_RCode tn_fmem_irelease(struct TN_FMem *fmem, void *p_data)
The same as tn_fmem_get(), but for using in the ISR.
void * data_elem
if task tries to receive data from memory pool, and there's no more free blocks in the pool...
Definition: tn_fmem.h:122
unsigned int block_size
block size (in bytes); note that it should be a multiple of sizeof(TN_UWord}), use a macro TN_MAKE_AL...
Definition: tn_fmem.h:95
enum TN_RCode tn_fmem_delete(struct TN_FMem *fmem)
Destruct fixed memory blocks pool.
FMem-specific fields related to waiting task, to be included in struct TN_Task.
Definition: tn_fmem.h:118
Circular doubly linked list item, for internal kernel usage.
Definition: tn_list.h:63
int tn_fmem_used_blocks_cnt_get(struct TN_FMem *fmem)
Returns number of used (non-free) blocks in the memory pool.