mempool.c 12 KB

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