RT-Thread RTOS 1.2.0
An open source embedded real-time operating system
载入中...
搜索中...
未找到
mempool.c
浏览该文件的文档.
1/*
2 * Copyright (c) 2006-2022, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2006-05-27 Bernard implement memory pool
9 * 2006-06-03 Bernard fix the thread timer init bug
10 * 2006-06-30 Bernard fix the allocate/free block bug
11 * 2006-08-04 Bernard add hook support
12 * 2006-08-10 Bernard fix interrupt bug in rt_mp_alloc
13 * 2010-07-13 Bernard fix RT_ALIGN issue found by kuronca
14 * 2010-10-26 yi.qiu add module support in rt_mp_delete
15 * 2011-01-24 Bernard add object allocation check.
16 * 2012-03-22 Bernard fix align issue in rt_mp_init and rt_mp_create.
17 * 2022-01-07 Gabriel Moving __on_rt_xxxxx_hook to mempool.c
18 * 2023-09-15 xqyjlj perf rt_hw_interrupt_disable/enable
19 * 2023-12-10 xqyjlj fix spinlock assert
20 */
21
22#include <rthw.h>
23#include <rtthread.h>
24
25#ifdef RT_USING_MEMPOOL
26
27#if defined(RT_USING_HOOK) && defined(RT_HOOK_USING_FUNC_PTR)
28static void (*rt_mp_alloc_hook)(struct rt_mempool *mp, void *block);
29static void (*rt_mp_free_hook)(struct rt_mempool *mp, void *block);
30
34
36
43void rt_mp_alloc_sethook(void (*hook)(struct rt_mempool *mp, void *block))
44{
45 rt_mp_alloc_hook = hook;
46}
47
54void rt_mp_free_sethook(void (*hook)(struct rt_mempool *mp, void *block))
55{
56 rt_mp_free_hook = hook;
57}
58
60#endif /* RT_USING_HOOK */
61
65
67
85 const char *name,
86 void *start,
89{
90 rt_uint8_t *block_ptr;
91 rt_size_t offset;
92
93 /* parameter check */
94 RT_ASSERT(mp != RT_NULL);
95 RT_ASSERT(name != RT_NULL);
96 RT_ASSERT(start != RT_NULL);
97 RT_ASSERT(size > 0 && block_size > 0);
98
99 /* initialize object */
101
102 /* initialize memory pool */
103 mp->start_address = start;
104 mp->size = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE);
105
106 /* align the block size */
107 block_size = RT_ALIGN(block_size, RT_ALIGN_SIZE);
109
110 /* align to align size byte */
111 mp->block_total_count = mp->size / (mp->block_size + sizeof(rt_uint8_t *));
113
114 /* initialize suspended thread list */
116
117 /* initialize free block list */
118 block_ptr = (rt_uint8_t *)mp->start_address;
119 for (offset = 0; offset < mp->block_total_count; offset ++)
120 {
121 *(rt_uint8_t **)(block_ptr + offset * (block_size + sizeof(rt_uint8_t *))) =
122 (rt_uint8_t *)(block_ptr + (offset + 1) * (block_size + sizeof(rt_uint8_t *)));
123 }
124
125 *(rt_uint8_t **)(block_ptr + (offset - 1) * (block_size + sizeof(rt_uint8_t *))) =
126 RT_NULL;
127
128 mp->block_list = block_ptr;
130
131 return RT_EOK;
132}
134
143{
144 rt_base_t level;
145
146 /* parameter check */
147 RT_ASSERT(mp != RT_NULL);
150
151 level = rt_spin_lock_irqsave(&(mp->spinlock));
152 /* wake up all suspended threads */
154
155 /* detach object */
156 rt_object_detach(&(mp->parent));
157 rt_spin_unlock_irqrestore(&(mp->spinlock), level);
158
159 return RT_EOK;
160}
162
163#ifdef RT_USING_HEAP
176rt_mp_t rt_mp_create(const char *name,
177 rt_size_t block_count,
179{
180 rt_uint8_t *block_ptr;
181 struct rt_mempool *mp;
182 rt_size_t offset;
183
185
186 /* parameter check */
187 RT_ASSERT(name != RT_NULL);
188 RT_ASSERT(block_count > 0 && block_size > 0);
189
190 /* allocate object */
192 /* allocate object failed */
193 if (mp == RT_NULL)
194 return RT_NULL;
195
196 /* initialize memory pool */
197 block_size = RT_ALIGN(block_size, RT_ALIGN_SIZE);
199 mp->size = (block_size + sizeof(rt_uint8_t *)) * block_count;
200
201 /* allocate memory */
202 mp->start_address = rt_malloc((block_size + sizeof(rt_uint8_t *)) *
203 block_count);
204 if (mp->start_address == RT_NULL)
205 {
206 /* no memory, delete memory pool object */
207 rt_object_delete(&(mp->parent));
208
209 return RT_NULL;
210 }
211
212 mp->block_total_count = block_count;
214
215 /* initialize suspended thread list */
217
218 /* initialize free block list */
219 block_ptr = (rt_uint8_t *)mp->start_address;
220 for (offset = 0; offset < mp->block_total_count; offset ++)
221 {
222 *(rt_uint8_t **)(block_ptr + offset * (block_size + sizeof(rt_uint8_t *)))
223 = block_ptr + (offset + 1) * (block_size + sizeof(rt_uint8_t *));
224 }
225
226 *(rt_uint8_t **)(block_ptr + (offset - 1) * (block_size + sizeof(rt_uint8_t *)))
227 = RT_NULL;
228
229 mp->block_list = block_ptr;
231
232 return mp;
233}
235
244{
245 rt_base_t level;
246
248
249 /* parameter check */
250 RT_ASSERT(mp != RT_NULL);
253
254 level = rt_spin_lock_irqsave(&(mp->spinlock));
255 /* wake up all suspended threads */
257
258 rt_spin_unlock_irqrestore(&(mp->spinlock), level);
259
260 /* release allocated room */
262
263 /* detach object */
264 rt_object_delete(&(mp->parent));
265
266 return RT_EOK;
267}
269#endif /* RT_USING_HEAP */
270
282{
283 rt_uint8_t *block_ptr;
284 rt_base_t level;
285 struct rt_thread *thread;
286 rt_uint32_t before_sleep = 0;
287
288 /* parameter check */
289 RT_ASSERT(mp != RT_NULL);
290
291 /* get current thread */
292 thread = rt_thread_self();
293
294 level = rt_spin_lock_irqsave(&(mp->spinlock));
295
296 while (mp->block_free_count == 0)
297 {
298 /* memory block is unavailable. */
299 if (time == 0)
300 {
301 rt_spin_unlock_irqrestore(&(mp->spinlock), level);
302
303 rt_set_errno(-RT_ETIMEOUT);
304
305 return RT_NULL;
306 }
307
309
310 thread->error = RT_EOK;
311
312 /* need suspend thread */
314
315 if (time > 0)
316 {
317 /* get the start tick of timer */
318 before_sleep = rt_tick_get();
319
320 /* init thread timer and start it */
323 &time);
324 rt_timer_start(&(thread->thread_timer));
325 }
326
327 /* enable interrupt */
328 rt_spin_unlock_irqrestore(&(mp->spinlock), level);
329
330 /* do a schedule */
331 rt_schedule();
332
333 if (thread->error != RT_EOK)
334 return RT_NULL;
335
336 if (time > 0)
337 {
338 time -= rt_tick_get() - before_sleep;
339 if (time < 0)
340 time = 0;
341 }
342 level = rt_spin_lock_irqsave(&(mp->spinlock));
343 }
344
345 /* memory block is available. decrease the free block counter */
346 mp->block_free_count--;
347
348 /* get block from block list */
349 block_ptr = mp->block_list;
350 RT_ASSERT(block_ptr != RT_NULL);
351
352 /* Setup the next free node. */
353 mp->block_list = *(rt_uint8_t **)block_ptr;
354
355 /* point to memory pool */
356 *(rt_uint8_t **)block_ptr = (rt_uint8_t *)mp;
357
358 rt_spin_unlock_irqrestore(&(mp->spinlock), level);
359
360 RT_OBJECT_HOOK_CALL(rt_mp_alloc_hook,
361 (mp, (rt_uint8_t *)(block_ptr + sizeof(rt_uint8_t *))));
362
363 return (rt_uint8_t *)(block_ptr + sizeof(rt_uint8_t *));
364}
366
372void rt_mp_free(void *block)
373{
374 rt_uint8_t **block_ptr;
375 struct rt_mempool *mp;
376 rt_base_t level;
377
378 /* parameter check */
379 if (block == RT_NULL) return;
380
381 /* get the control block of pool which the block belongs to */
382 block_ptr = (rt_uint8_t **)((rt_uint8_t *)block - sizeof(rt_uint8_t *));
383 mp = (struct rt_mempool *)*block_ptr;
384
385 RT_OBJECT_HOOK_CALL(rt_mp_free_hook, (mp, block));
386
387 level = rt_spin_lock_irqsave(&(mp->spinlock));
388
389 /* increase the free block count */
390 mp->block_free_count ++;
391
392 /* link the block into the block list */
393 *block_ptr = mp->block_list;
394 mp->block_list = (rt_uint8_t *)block_ptr;
395
396 if (rt_susp_list_dequeue(&mp->suspend_thread, RT_EOK))
397 {
398 rt_spin_unlock_irqrestore(&(mp->spinlock), level);
399
400 /* do a schedule */
401 rt_schedule();
402
403 return;
404 }
405 rt_spin_unlock_irqrestore(&(mp->spinlock), level);
406}
408
410
411#endif /* RT_USING_MEMPOOL */
#define RT_ALIGN(size, align)
#define RT_ALIGN_DOWN(size, align)
rt_err_t rt_timer_control(rt_timer_t timer, int cmd, void *arg)
This function will get or set some options of the timer
rt_err_t rt_timer_start(rt_timer_t timer)
This function will start the timer
rt_tick_t rt_tick_get(void)
This function will return current tick from operating system startup.
定义 clock.c:69
#define RT_TIMER_CTRL_SET_TIME
#define RT_IPC_FLAG_FIFO
rt_base_t rt_spin_lock_irqsave(struct rt_spinlock *lock)
This function will disable the local interrupt and then lock the spinlock, will lock the thread sched...
rt_err_t rt_susp_list_resume_all(rt_list_t *susp_list, rt_err_t thread_error)
This function will resume all suspended threads in the IPC object list, including the suspended list ...
定义 ipc.c:165
void rt_spin_lock_init(struct rt_spinlock *lock)
Initialize a static spinlock object.
struct rt_thread * rt_susp_list_dequeue(rt_list_t *susp_list, rt_err_t thread_error)
Dequeue a thread from suspended list and set it to ready. The 2 are taken as an atomic operation,...
定义 ipc.c:105
void rt_spin_unlock_irqrestore(struct rt_spinlock *lock, rt_base_t level)
This function will unlock the spinlock and then restore current cpu interrupt status,...
void rt_object_delete(rt_object_t object)
This function will delete an object and release object memory.
void rt_object_init(struct rt_object *object, enum rt_object_class_type type, const char *name)
This function will initialize an object and add it to object system management.
rt_bool_t rt_object_is_systemobject(rt_object_t object)
This function will judge the object is system object or not.
#define RT_OBJECT_HOOK_CALL(func, argv)
rt_object_t rt_object_allocate(enum rt_object_class_type type, const char *name)
This function will allocate an object from object system.
rt_uint8_t rt_object_get_type(rt_object_t object)
This function will return the type of object without RT_Object_Class_Static flag.
void rt_object_detach(rt_object_t object)
This function will detach a static object from object system, and the memory of static object is not ...
@ RT_Object_Class_MemPool
#define RT_DEBUG_NOT_IN_INTERRUPT
#define RT_ASSERT(EX)
rt_inline void rt_list_init(rt_list_t *l)
initialize a list
rt_weak void rt_free(void *ptr)
This function will release the previously allocated memory block by rt_malloc. The released memory bl...
rt_weak void * rt_malloc(rt_size_t size)
Allocate a block of memory with a minimum of 'size' bytes.
rt_err_t rt_mp_init(struct rt_mempool *mp, const char *name, void *start, rt_size_t size, rt_size_t block_size)
This function will initialize a memory pool object, normally which is used for static object.
void rt_mp_alloc_sethook(void(*hook)(struct rt_mempool *mp, void *block))
void * rt_mp_alloc(rt_mp_t mp, rt_int32_t time)
This function will allocate a block from memory pool.
void rt_mp_free(void *block)
This function will release a memory block.
rt_err_t rt_mp_detach(struct rt_mempool *mp)
This function will detach a memory pool from system object management.
rt_mp_t rt_mp_create(const char *name, rt_size_t block_count, rt_size_t block_size)
This function will create a mempool object and allocate the memory pool from heap.
struct rt_mempool * rt_mp_t
rt_err_t rt_mp_delete(rt_mp_t mp)
This function will delete a memory pool and release the object memory.
void rt_mp_free_sethook(void(*hook)(struct rt_mempool *mp, void *block))
rt_err_t rt_thread_suspend_to_list(rt_thread_t thread, rt_list_t *susp_list, int ipc_flags, int suspend_flag)
This function will suspend the specified thread and change it to suspend state.
rt_thread_t rt_thread_self(void)
This function will return self thread object.
void rt_schedule(void)
This function will perform one scheduling. It will select one thread with the highest priority level ...
@ RT_UNINTERRUPTIBLE
#define RTM_EXPORT(symbol)
定义 rtm.h:33
rt_int32_t rt_base_t
rt_base_t rt_err_t
unsigned char rt_uint8_t
rt_ubase_t rt_size_t
unsigned int rt_uint32_t
#define RT_FALSE
#define RT_NULL
signed int rt_int32_t
struct rt_spinlock spinlock
rt_size_t block_total_count
rt_size_t size
rt_size_t block_size
void * start_address
rt_list_t suspend_thread
struct rt_object parent
rt_uint8_t * block_list
rt_size_t block_free_count
rt_err_t error
RT_SCHED_THREAD_CTX struct rt_timer thread_timer