TNeoKernel  v1.03
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
tn_fmem.h
Go to the documentation of this file.
1 /*******************************************************************************
2  *
3  * TNeoKernel: 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  * TNeoKernel: copyright © 2014 Dmitry Frank.
8  *
9  * TNeoKernel 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: TNeoKernel.
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  *
50  * For the useful pattern on how to use fixed memory pool together with \ref
51  * tn_dqueue.h "queue", refer to the example: `examples/queue`. Be sure to
52  * examine the readme there.
53  */
54 
55 #ifndef _TN_MEM_H
56 #define _TN_MEM_H
57 
58 /*******************************************************************************
59  * INCLUDED FILES
60  ******************************************************************************/
61 
62 #include "tn_list.h"
63 #include "tn_common.h"
64 
65 
66 
67 #ifdef __cplusplus
68 extern "C" { /*}*/
69 #endif
70 
71 /*******************************************************************************
72  * PUBLIC TYPES
73  ******************************************************************************/
74 
75 /**
76  * Fixed memory blocks pool
77  */
78 struct TN_FMem {
79  ///
80  /// list of tasks waiting for free memory block
81  struct TN_ListItem wait_queue;
82 
83  ///
84  /// block size (in bytes); note that it should be a multiple of
85  /// `sizeof(#TN_UWord})`, use a macro `TN_MAKE_ALIG_SIZE()` for that.
86  ///
87  /// @see `TN_MAKE_ALIG_SIZE()`
88  unsigned int block_size;
89  ///
90  /// capacity (total blocks count)
92  ///
93  /// free blocks count
95  ///
96  /// memory pool start address; note that it should be a multiple of
97  /// `sizeof(#TN_UWord)`.
98  void *start_addr;
99  ///
100  /// ptr to free block list
101  void *free_list;
102  ///
103  /// id for object validity verification
105 };
106 
107 
108 /**
109  * FMem-specific fields related to waiting task,
110  * to be included in struct TN_Task.
111  */
113  /// if task tries to receive data from memory pool,
114  /// and there's no more free blocks in the pool, location to store
115  /// pointer is saved in this field
116  void *data_elem;
117 };
118 
119 
120 /*******************************************************************************
121  * GLOBAL VARIABLES
122  ******************************************************************************/
123 
124 /*******************************************************************************
125  * DEFINITIONS
126  ******************************************************************************/
127 
128 /**
129  * Convenience macro for the definition of buffer for memory pool. See
130  * `tn_fmem_create()` for usage example.
131  *
132  * @param name
133  * C variable name of the buffer array (this name should be given
134  * to the `tn_fmem_create()` function as the `start_addr` argument)
135  * @param item_type
136  * Type of item in the memory pool, like `struct MyMemoryItem`.
137  * @param size
138  * Number of items in the memory pool.
139  */
140 #define TN_FMEM_BUF_DEF(name, item_type, size) \
141  TN_UWord name[ \
142  (size) \
143  * (TN_MAKE_ALIG_SIZE(sizeof(item_type)) / sizeof(TN_UWord)) \
144  ]
145 
146 
147 
148 
149 /*******************************************************************************
150  * PUBLIC FUNCTION PROTOTYPES
151  ******************************************************************************/
152 
153 /**
154  * Construct fixed memory blocks pool. `id_fmp` field should not contain
155  * `#TN_ID_FSMEMORYPOOL`, otherwise, `#TN_RC_WPARAM` is returned.
156  *
157  * Note that `start_addr` and `block_size` should be a multiple of
158  * `sizeof(#TN_UWord)`.
159  *
160  * For the definition of buffer, convenience macro `TN_FMEM_BUF_DEF()` was
161  * invented.
162  *
163  * Typical definition looks as follows:
164  *
165  * \code{.c}
166  * //-- number of blocks in the pool
167  * #define MY_MEMORY_BUF_SIZE 8
168  *
169  * //-- type for memory block
170  * struct MyMemoryItem {
171  * // ... arbitrary fields ...
172  * };
173  *
174  * //-- define buffer for memory pool
175  * TN_FMEM_BUF_DEF(my_fmem_buf, struct MyMemoryItem, MY_MEMORY_BUF_SIZE);
176  *
177  * //-- define memory pool structure
178  * struct TN_FMem my_fmem;
179  * \endcode
180  *
181  * And then, construct your `my_fmem` as follows:
182  *
183  * \code{.c}
184  * enum TN_RCode rc;
185  * rc = tn_fmem_create( &my_fmem,
186  * my_fmem_buf,
187  * TN_MAKE_ALIG_SIZE(sizeof(struct MyMemoryItem)),
188  * MY_MEMORY_BUF_SIZE );
189  * if (rc != TN_RC_OK){
190  * //-- handle error
191  * }
192  * \endcode
193  *
194  * If given `start_addr` and/or `block_size` aren't aligned properly,
195  * `#TN_RC_WPARAM` is returned.
196  *
197  * $(TN_CALL_FROM_TASK)
198  * $(TN_CALL_FROM_ISR)
199  * $(TN_LEGEND_LINK)
200  *
201  * @param fmem pointer to already allocated `struct TN_FMem`.
202  * @param start_addr pointer to start of the array; should be aligned properly,
203  * see example above
204  * @param block_size size of memory block; should be a multiple of
205  * `sizeof(#TN_UWord)`, see example above
206  * @param blocks_cnt capacity (total number of blocks in the memory pool)
207  *
208  * @return
209  * * `#TN_RC_OK` if memory pool was successfully created;
210  * * If `#TN_CHECK_PARAM` is non-zero, additional return code
211  * is available: `#TN_RC_WPARAM`.
212  *
213  * @see TN_MAKE_ALIG_SIZE
214  */
216  struct TN_FMem *fmem,
217  void *start_addr,
218  unsigned int block_size,
219  int blocks_cnt
220  );
221 
222 /**
223  * Destruct fixed memory blocks pool.
224  *
225  * All tasks that wait for free memory block become runnable with
226  * `#TN_RC_DELETED` code returned.
227  *
228  * $(TN_CALL_FROM_TASK)
229  * $(TN_CAN_SWITCH_CONTEXT)
230  * $(TN_LEGEND_LINK)
231  *
232  * @param fmem pointer to memory pool to be deleted
233  *
234  * @return
235  * * `#TN_RC_OK` if memory pool is successfully deleted;
236  * * `#TN_RC_WCONTEXT` if called from wrong context;
237  * * If `#TN_CHECK_PARAM` is non-zero, additional return codes
238  * are available: `#TN_RC_WPARAM` and `#TN_RC_INVALID_OBJ`.
239  *
240  */
241 enum TN_RCode tn_fmem_delete(struct TN_FMem *fmem);;
242 
243 /**
244  * Get memory block from the pool. Start address of the memory block is returned
245  * through the `p_data` argument. The content of memory block is undefined.
246  * If there is no free block in the pool, behavior depends on `timeout` value:
247  * refer to `#TN_Timeout`.
248  *
249  * $(TN_CALL_FROM_TASK)
250  * $(TN_CAN_SWITCH_CONTEXT)
251  * $(TN_CAN_SLEEP)
252  * $(TN_LEGEND_LINK)
253  *
254  * @param fmem
255  * Pointer to memory pool
256  * @param p_data
257  * Address of the `(void *)` to which received block address will be saved
258  * @param timeout
259  * Refer to `#TN_Timeout`
260  *
261  * @return
262  * * `#TN_RC_OK` if block was successfully returned through `p_data`;
263  * * `#TN_RC_WCONTEXT` if called from wrong context;
264  * * Other possible return codes depend on `timeout` value,
265  * refer to `#TN_Timeout`
266  * * If `#TN_CHECK_PARAM` is non-zero, additional return codes
267  * are available: `#TN_RC_WPARAM` and `#TN_RC_INVALID_OBJ`.
268  */
269 enum TN_RCode tn_fmem_get(
270  struct TN_FMem *fmem,
271  void **p_data,
272  TN_Timeout timeout
273  );
274 
275 /**
276  * The same as `tn_fmem_get()` with zero timeout
277  *
278  * $(TN_CALL_FROM_TASK)
279  * $(TN_CAN_SWITCH_CONTEXT)
280  * $(TN_LEGEND_LINK)
281  */
282 enum TN_RCode tn_fmem_get_polling(struct TN_FMem *fmem, void **p_data);
283 
284 /**
285  * The same as `tn_fmem_get()` with zero timeout, but for using in the ISR.
286  *
287  * $(TN_CALL_FROM_ISR)
288  * $(TN_CAN_SWITCH_CONTEXT)
289  * $(TN_LEGEND_LINK)
290  */
291 enum TN_RCode tn_fmem_iget_polling(struct TN_FMem *fmem, void **p_data);
292 
293 
294 /**
295  * Release memory block back to the pool. The kernel does not check the
296  * validity of the membership of given block in the memory pool.
297  * If all the memory blocks in the pool are free already, `#TN_RC_OVERFLOW`
298  * is returned.
299  *
300  * $(TN_CALL_FROM_TASK)
301  * $(TN_CAN_SWITCH_CONTEXT)
302  * $(TN_LEGEND_LINK)
303  *
304  * @param fmem
305  * Pointer to memory pool.
306  * @param p_data
307  * Address of the memory block to release.
308  *
309  * @return
310  * * `#TN_RC_OK` on success
311  * * `#TN_RC_WCONTEXT` if called from wrong context;
312  * * If `#TN_CHECK_PARAM` is non-zero, additional return codes
313  * are available: `#TN_RC_WPARAM` and `#TN_RC_INVALID_OBJ`.
314  */
315 enum TN_RCode tn_fmem_release(struct TN_FMem *fmem, void *p_data);
316 
317 /**
318  * The same as `tn_fmem_get()`, but for using in the ISR.
319  *
320  * $(TN_CALL_FROM_ISR)
321  * $(TN_CAN_SWITCH_CONTEXT)
322  * $(TN_LEGEND_LINK)
323  */
324 enum TN_RCode tn_fmem_irelease(struct TN_FMem *fmem, void *p_data);
325 
326 
327 
328 #ifdef __cplusplus
329 } /* extern "C" */
330 #endif
331 
332 #endif // _TN_MEM_H
333 
334 /*******************************************************************************
335  * end of file
336  ******************************************************************************/
337 
338 
struct TN_ListItem wait_queue
list of tasks waiting for free memory block
Definition: tn_fmem.h:81
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:100
TN_ObjId
Magic number for object validity verification.
Definition: tn_common.h:87
unsigned long TN_Timeout
The value representing maximum number of system ticks to wait.
Definition: tn_common.h:203
Definitions used through the whole kernel.
int free_blocks_cnt
free blocks count
Definition: tn_fmem.h:94
enum TN_ObjId id_fmp
id for object validity verification
Definition: tn_fmem.h:104
int blocks_cnt
capacity (total blocks count)
Definition: tn_fmem.h:91
Fixed memory blocks pool.
Definition: tn_fmem.h:78
void * free_list
ptr to free block list
Definition: tn_fmem.h:101
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_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:98
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:116
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:88
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:112
enum TN_RCode tn_fmem_get(struct TN_FMem *fmem, void **p_data, TN_Timeout timeout)
Get memory block from the pool.