mempool.c 12 KB

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