mempool.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. /*
  2. * Copyright (c) 2006-2021, 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. */
  18. #include <rthw.h>
  19. #include <rtthread.h>
  20. #ifdef RT_USING_MEMPOOL
  21. #ifdef RT_USING_HOOK
  22. static void (*rt_mp_alloc_hook)(struct rt_mempool *mp, void *block);
  23. static void (*rt_mp_free_hook)(struct rt_mempool *mp, void *block);
  24. /**
  25. * @addtogroup Hook
  26. */
  27. /**@{*/
  28. /**
  29. * @brief This function will set a hook function, which will be invoked when a memory
  30. * block is allocated from the memory pool.
  31. *
  32. * @param hook the hook function
  33. */
  34. void rt_mp_alloc_sethook(void (*hook)(struct rt_mempool *mp, void *block))
  35. {
  36. rt_mp_alloc_hook = hook;
  37. }
  38. /**
  39. * @brief This function will set a hook function, which will be invoked when a memory
  40. * block is released to the memory pool.
  41. *
  42. * @param hook the hook function
  43. */
  44. void rt_mp_free_sethook(void (*hook)(struct rt_mempool *mp, void *block))
  45. {
  46. rt_mp_free_hook = hook;
  47. }
  48. /**@}*/
  49. #endif /* RT_USING_HOOK */
  50. /**
  51. * @addtogroup MM
  52. */
  53. /**@{*/
  54. /**
  55. * @brief This function will initialize a memory pool object, normally which is used
  56. * for static object.
  57. *
  58. * @param mp is the memory pool object.
  59. *
  60. * @param name is the name of the memory pool.
  61. *
  62. * @param start is the start address of the memory pool.
  63. *
  64. * @param size is the total size of the memory pool.
  65. *
  66. * @param block_size is the size for each block..
  67. *
  68. * @return RT_EOK
  69. */
  70. rt_err_t rt_mp_init(struct rt_mempool *mp,
  71. const char *name,
  72. void *start,
  73. rt_size_t size,
  74. rt_size_t block_size)
  75. {
  76. rt_uint8_t *block_ptr;
  77. register rt_size_t offset;
  78. /* parameter check */
  79. RT_ASSERT(mp != RT_NULL);
  80. RT_ASSERT(name != RT_NULL);
  81. RT_ASSERT(start != RT_NULL);
  82. RT_ASSERT(size > 0 && block_size > 0);
  83. /* initialize object */
  84. rt_object_init(&(mp->parent), RT_Object_Class_MemPool, name);
  85. /* initialize memory pool */
  86. mp->start_address = start;
  87. mp->size = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE);
  88. /* align the block size */
  89. block_size = RT_ALIGN(block_size, RT_ALIGN_SIZE);
  90. mp->block_size = block_size;
  91. /* align to align size byte */
  92. mp->block_total_count = mp->size / (mp->block_size + sizeof(rt_uint8_t *));
  93. mp->block_free_count = mp->block_total_count;
  94. /* initialize suspended thread list */
  95. rt_list_init(&(mp->suspend_thread));
  96. /* initialize free block list */
  97. block_ptr = (rt_uint8_t *)mp->start_address;
  98. for (offset = 0; offset < mp->block_total_count; offset ++)
  99. {
  100. *(rt_uint8_t **)(block_ptr + offset * (block_size + sizeof(rt_uint8_t *))) =
  101. (rt_uint8_t *)(block_ptr + (offset + 1) * (block_size + sizeof(rt_uint8_t *)));
  102. }
  103. *(rt_uint8_t **)(block_ptr + (offset - 1) * (block_size + sizeof(rt_uint8_t *))) =
  104. RT_NULL;
  105. mp->block_list = block_ptr;
  106. return RT_EOK;
  107. }
  108. RTM_EXPORT(rt_mp_init);
  109. /**
  110. * @brief This function will detach a memory pool from system object management.
  111. *
  112. * @param mp is the memory pool object.
  113. *
  114. * @return RT_EOK
  115. */
  116. rt_err_t rt_mp_detach(struct rt_mempool *mp)
  117. {
  118. struct rt_thread *thread;
  119. register rt_ubase_t level;
  120. /* parameter check */
  121. RT_ASSERT(mp != RT_NULL);
  122. RT_ASSERT(rt_object_get_type(&mp->parent) == RT_Object_Class_MemPool);
  123. RT_ASSERT(rt_object_is_systemobject(&mp->parent));
  124. /* wake up all suspended threads */
  125. while (!rt_list_isempty(&(mp->suspend_thread)))
  126. {
  127. /* disable interrupt */
  128. level = rt_hw_interrupt_disable();
  129. /* get next suspend thread */
  130. thread = rt_list_entry(mp->suspend_thread.next, struct rt_thread, tlist);
  131. /* set error code to RT_ERROR */
  132. thread->error = -RT_ERROR;
  133. /*
  134. * resume thread
  135. * In rt_thread_resume function, it will remove current thread from
  136. * suspend list
  137. */
  138. rt_thread_resume(thread);
  139. /* enable interrupt */
  140. rt_hw_interrupt_enable(level);
  141. }
  142. /* detach object */
  143. rt_object_detach(&(mp->parent));
  144. return RT_EOK;
  145. }
  146. RTM_EXPORT(rt_mp_detach);
  147. #ifdef RT_USING_HEAP
  148. /**
  149. * @brief This function will create a mempool object and allocate the memory pool from
  150. * heap.
  151. *
  152. * @param name is the name of memory pool.
  153. *
  154. * @param block_count is the count of blocks in memory pool.
  155. *
  156. * @param block_size is the size for each block.
  157. *
  158. * @return the created mempool object
  159. */
  160. rt_mp_t rt_mp_create(const char *name,
  161. rt_size_t block_count,
  162. rt_size_t block_size)
  163. {
  164. rt_uint8_t *block_ptr;
  165. struct rt_mempool *mp;
  166. register rt_size_t offset;
  167. RT_DEBUG_NOT_IN_INTERRUPT;
  168. /* parameter check */
  169. RT_ASSERT(name != RT_NULL);
  170. RT_ASSERT(block_count > 0 && block_size > 0);
  171. /* allocate object */
  172. mp = (struct rt_mempool *)rt_object_allocate(RT_Object_Class_MemPool, name);
  173. /* allocate object failed */
  174. if (mp == RT_NULL)
  175. return RT_NULL;
  176. /* initialize memory pool */
  177. block_size = RT_ALIGN(block_size, RT_ALIGN_SIZE);
  178. mp->block_size = block_size;
  179. mp->size = (block_size + sizeof(rt_uint8_t *)) * block_count;
  180. /* allocate memory */
  181. mp->start_address = rt_malloc((block_size + sizeof(rt_uint8_t *)) *
  182. block_count);
  183. if (mp->start_address == RT_NULL)
  184. {
  185. /* no memory, delete memory pool object */
  186. rt_object_delete(&(mp->parent));
  187. return RT_NULL;
  188. }
  189. mp->block_total_count = block_count;
  190. mp->block_free_count = mp->block_total_count;
  191. /* initialize suspended thread list */
  192. rt_list_init(&(mp->suspend_thread));
  193. /* initialize free block list */
  194. block_ptr = (rt_uint8_t *)mp->start_address;
  195. for (offset = 0; offset < mp->block_total_count; offset ++)
  196. {
  197. *(rt_uint8_t **)(block_ptr + offset * (block_size + sizeof(rt_uint8_t *)))
  198. = block_ptr + (offset + 1) * (block_size + sizeof(rt_uint8_t *));
  199. }
  200. *(rt_uint8_t **)(block_ptr + (offset - 1) * (block_size + sizeof(rt_uint8_t *)))
  201. = RT_NULL;
  202. mp->block_list = block_ptr;
  203. return mp;
  204. }
  205. RTM_EXPORT(rt_mp_create);
  206. /**
  207. * @brief This function will delete a memory pool and release the object memory.
  208. *
  209. * @param mp is the memory pool object.
  210. *
  211. * @return RT_EOK
  212. */
  213. rt_err_t rt_mp_delete(rt_mp_t mp)
  214. {
  215. struct rt_thread *thread;
  216. register rt_ubase_t level;
  217. RT_DEBUG_NOT_IN_INTERRUPT;
  218. /* parameter check */
  219. RT_ASSERT(mp != RT_NULL);
  220. RT_ASSERT(rt_object_get_type(&mp->parent) == RT_Object_Class_MemPool);
  221. RT_ASSERT(rt_object_is_systemobject(&mp->parent) == RT_FALSE);
  222. /* wake up all suspended threads */
  223. while (!rt_list_isempty(&(mp->suspend_thread)))
  224. {
  225. /* disable interrupt */
  226. level = rt_hw_interrupt_disable();
  227. /* get next suspend thread */
  228. thread = rt_list_entry(mp->suspend_thread.next, struct rt_thread, tlist);
  229. /* set error code to RT_ERROR */
  230. thread->error = -RT_ERROR;
  231. /*
  232. * resume thread
  233. * In rt_thread_resume function, it will remove current thread from
  234. * suspend list
  235. */
  236. rt_thread_resume(thread);
  237. /* enable interrupt */
  238. rt_hw_interrupt_enable(level);
  239. }
  240. /* release allocated room */
  241. rt_free(mp->start_address);
  242. /* detach object */
  243. rt_object_delete(&(mp->parent));
  244. return RT_EOK;
  245. }
  246. RTM_EXPORT(rt_mp_delete);
  247. #endif /* RT_USING_HEAP */
  248. /**
  249. * @brief This function will allocate a block from memory pool.
  250. *
  251. * @param mp is the memory pool object.
  252. *
  253. * @param time is the maximum waiting time for allocating memory.
  254. * - 0 for not waiting, allocating memory immediately.
  255. *
  256. * @return the allocated memory block or RT_NULL on allocated failed.
  257. */
  258. void *rt_mp_alloc(rt_mp_t mp, rt_int32_t time)
  259. {
  260. rt_uint8_t *block_ptr;
  261. register rt_base_t level;
  262. struct rt_thread *thread;
  263. rt_uint32_t before_sleep = 0;
  264. /* parameter check */
  265. RT_ASSERT(mp != RT_NULL);
  266. /* get current thread */
  267. thread = rt_thread_self();
  268. /* disable interrupt */
  269. level = rt_hw_interrupt_disable();
  270. while (mp->block_free_count == 0)
  271. {
  272. /* memory block is unavailable. */
  273. if (time == 0)
  274. {
  275. /* enable interrupt */
  276. rt_hw_interrupt_enable(level);
  277. rt_set_errno(-RT_ETIMEOUT);
  278. return RT_NULL;
  279. }
  280. RT_DEBUG_NOT_IN_INTERRUPT;
  281. thread->error = RT_EOK;
  282. /* need suspend thread */
  283. rt_thread_suspend(thread);
  284. rt_list_insert_after(&(mp->suspend_thread), &(thread->tlist));
  285. if (time > 0)
  286. {
  287. /* get the start tick of timer */
  288. before_sleep = rt_tick_get();
  289. /* init thread timer and start it */
  290. rt_timer_control(&(thread->thread_timer),
  291. RT_TIMER_CTRL_SET_TIME,
  292. &time);
  293. rt_timer_start(&(thread->thread_timer));
  294. }
  295. /* enable interrupt */
  296. rt_hw_interrupt_enable(level);
  297. /* do a schedule */
  298. rt_schedule();
  299. if (thread->error != RT_EOK)
  300. return RT_NULL;
  301. if (time > 0)
  302. {
  303. time -= rt_tick_get() - before_sleep;
  304. if (time < 0)
  305. time = 0;
  306. }
  307. /* disable interrupt */
  308. level = rt_hw_interrupt_disable();
  309. }
  310. /* memory block is available. decrease the free block counter */
  311. mp->block_free_count--;
  312. /* get block from block list */
  313. block_ptr = mp->block_list;
  314. RT_ASSERT(block_ptr != RT_NULL);
  315. /* Setup the next free node. */
  316. mp->block_list = *(rt_uint8_t **)block_ptr;
  317. /* point to memory pool */
  318. *(rt_uint8_t **)block_ptr = (rt_uint8_t *)mp;
  319. /* enable interrupt */
  320. rt_hw_interrupt_enable(level);
  321. RT_OBJECT_HOOK_CALL(rt_mp_alloc_hook,
  322. (mp, (rt_uint8_t *)(block_ptr + sizeof(rt_uint8_t *))));
  323. return (rt_uint8_t *)(block_ptr + sizeof(rt_uint8_t *));
  324. }
  325. RTM_EXPORT(rt_mp_alloc);
  326. /**
  327. * @brief This function will release a memory block.
  328. *
  329. * @param block the address of memory block to be released.
  330. */
  331. void rt_mp_free(void *block)
  332. {
  333. rt_uint8_t **block_ptr;
  334. struct rt_mempool *mp;
  335. struct rt_thread *thread;
  336. register rt_base_t level;
  337. /* parameter check */
  338. if (block == RT_NULL) return;
  339. /* get the control block of pool which the block belongs to */
  340. block_ptr = (rt_uint8_t **)((rt_uint8_t *)block - sizeof(rt_uint8_t *));
  341. mp = (struct rt_mempool *)*block_ptr;
  342. RT_OBJECT_HOOK_CALL(rt_mp_free_hook, (mp, block));
  343. /* disable interrupt */
  344. level = rt_hw_interrupt_disable();
  345. /* increase the free block count */
  346. mp->block_free_count ++;
  347. /* link the block into the block list */
  348. *block_ptr = mp->block_list;
  349. mp->block_list = (rt_uint8_t *)block_ptr;
  350. if (!rt_list_isempty(&(mp->suspend_thread)))
  351. {
  352. /* get the suspended thread */
  353. thread = rt_list_entry(mp->suspend_thread.next,
  354. struct rt_thread,
  355. tlist);
  356. /* set error */
  357. thread->error = RT_EOK;
  358. /* resume thread */
  359. rt_thread_resume(thread);
  360. /* enable interrupt */
  361. rt_hw_interrupt_enable(level);
  362. /* do a schedule */
  363. rt_schedule();
  364. return;
  365. }
  366. /* enable interrupt */
  367. rt_hw_interrupt_enable(level);
  368. }
  369. RTM_EXPORT(rt_mp_free);
  370. /**@}*/
  371. #endif /* RT_USING_MEMPOOL */