mempool.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  1. /*
  2. * File : mempool.c
  3. * This file is part of RT-Thread RTOS
  4. * COPYRIGHT (C) 2006 - 2012, RT-Thread Development Team
  5. *
  6. * The license and distribution terms for this file may be
  7. * found in the file LICENSE in this distribution or at
  8. * http://www.rt-thread.org/license/LICENSE
  9. *
  10. * Change Logs:
  11. * Date Author Notes
  12. * 2006-05-27 Bernard implement memory pool
  13. * 2006-06-03 Bernard fix the thread timer init bug
  14. * 2006-06-30 Bernard fix the allocate/free block bug
  15. * 2006-08-04 Bernard add hook support
  16. * 2006-08-10 Bernard fix interrupt bug in rt_mp_alloc
  17. * 2010-07-13 Bernard fix RT_ALIGN issue found by kuronca
  18. * 2010-10-26 yi.qiu add module support in rt_mp_delete
  19. * 2011-01-24 Bernard add object allocation check.
  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 for
  59. * 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, const char *name, void *start, rt_size_t size, rt_size_t block_size)
  70. {
  71. rt_uint8_t *block_ptr;
  72. register rt_base_t offset;
  73. /* parameter check */
  74. RT_ASSERT(mp != RT_NULL);
  75. /* init object */
  76. rt_object_init(&(mp->parent), RT_Object_Class_MemPool, name);
  77. /* init memory pool */
  78. mp->start_address = start;
  79. mp->size = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE);
  80. mp->block_size = block_size;
  81. /* align to align size byte */
  82. mp->block_total_count = mp->size / (mp->block_size + sizeof(rt_uint8_t *));
  83. mp->block_free_count = mp->block_total_count;
  84. /* init suspended thread list */
  85. rt_list_init(&(mp->suspend_thread));
  86. mp->suspend_thread_count = 0;
  87. /* init free block list */
  88. block_ptr = (rt_uint8_t *)mp->start_address;
  89. for (offset = 0; offset < mp->block_total_count; offset ++)
  90. {
  91. *(rt_uint8_t **)(block_ptr + offset * (block_size + sizeof(rt_uint8_t *)))
  92. = (rt_uint8_t *)(block_ptr + (offset + 1) * (block_size + sizeof(rt_uint8_t *)));
  93. }
  94. *(rt_uint8_t **)(block_ptr + (offset - 1) * (block_size + sizeof(rt_uint8_t *))) = RT_NULL;
  95. mp->block_list = block_ptr;
  96. return RT_EOK;
  97. }
  98. /**
  99. * This function will detach a memory pool from system object management.
  100. *
  101. * @param mp the memory pool object
  102. *
  103. * @return RT_EOK
  104. */
  105. rt_err_t rt_mp_detach(struct rt_mempool *mp)
  106. {
  107. struct rt_thread *thread;
  108. register rt_ubase_t temp;
  109. /* parameter check */
  110. RT_ASSERT(mp != RT_NULL);
  111. /* wakeup all suspended threads */
  112. while (!rt_list_isempty(&(mp->suspend_thread)))
  113. {
  114. /* disable interrupt */
  115. temp = rt_hw_interrupt_disable();
  116. /* get next suspend thread */
  117. thread = rt_list_entry(mp->suspend_thread.next, struct rt_thread, tlist);
  118. /* set error code to RT_ERROR */
  119. thread->error = -RT_ERROR;
  120. /*
  121. * resume thread
  122. * In rt_thread_resume function, it will remove current thread from suspend
  123. * list
  124. */
  125. rt_thread_resume(thread);
  126. /* decrease suspended thread count */
  127. mp->suspend_thread_count --;
  128. /* enable interrupt */
  129. rt_hw_interrupt_enable(temp);
  130. }
  131. /* detach object */
  132. rt_object_detach(&(mp->parent));
  133. return RT_EOK;
  134. }
  135. #ifdef RT_USING_HEAP
  136. /**
  137. * This function will create a mempool object and allocate the memory pool from heap.
  138. *
  139. * @param name the name of memory pool
  140. * @param block_count the count of blocks in memory pool
  141. * @param block_size the size for each block
  142. *
  143. * @return the created mempool object
  144. */
  145. rt_mp_t rt_mp_create(const char *name, rt_size_t block_count, rt_size_t block_size)
  146. {
  147. rt_uint8_t *block_ptr;
  148. struct rt_mempool *mp;
  149. register rt_base_t offset;
  150. RT_DEBUG_NOT_IN_INTERRUPT;
  151. /* allocate object */
  152. mp = (struct rt_mempool *)rt_object_allocate(RT_Object_Class_MemPool, name);
  153. if (mp == RT_NULL)
  154. return RT_NULL; /* allocate object failed */
  155. /* init memory pool */
  156. mp->block_size = RT_ALIGN(block_size, RT_ALIGN_SIZE);
  157. mp->size = (block_size + sizeof(rt_uint8_t *)) * block_count;
  158. /* allocate memory */
  159. mp->start_address = rt_malloc((block_size + sizeof(rt_uint8_t *)) * block_count);
  160. if (mp->start_address == RT_NULL)
  161. {
  162. /* no memory, delete memory pool object */
  163. rt_object_delete(&(mp->parent));
  164. return RT_NULL;
  165. }
  166. mp->block_total_count = block_count;
  167. mp->block_free_count = mp->block_total_count;
  168. /* init suspended thread list */
  169. rt_list_init(&(mp->suspend_thread));
  170. mp->suspend_thread_count = 0;
  171. /* init free block list */
  172. block_ptr = (rt_uint8_t *)mp->start_address;
  173. for (offset = 0; offset < mp->block_total_count; offset ++)
  174. {
  175. *(rt_uint8_t **)(block_ptr + offset * (block_size + sizeof(rt_uint8_t *)))
  176. = block_ptr + (offset + 1) * (block_size + sizeof(rt_uint8_t *));
  177. }
  178. *(rt_uint8_t **)(block_ptr + (offset - 1) * (block_size + sizeof(rt_uint8_t *))) = RT_NULL;
  179. mp->block_list = block_ptr;
  180. return mp;
  181. }
  182. /**
  183. * This function will delete a memory pool and release the object memory.
  184. *
  185. * @param mp the memory pool object
  186. *
  187. * @return RT_EOK
  188. */
  189. rt_err_t rt_mp_delete(rt_mp_t mp)
  190. {
  191. struct rt_thread *thread;
  192. register rt_ubase_t temp;
  193. RT_DEBUG_NOT_IN_INTERRUPT;
  194. /* parameter check */
  195. RT_ASSERT(mp != RT_NULL);
  196. /* wakeup all suspended threads */
  197. while (!rt_list_isempty(&(mp->suspend_thread)))
  198. {
  199. /* disable interrupt */
  200. temp = rt_hw_interrupt_disable();
  201. /* get next suspend thread */
  202. thread = rt_list_entry(mp->suspend_thread.next, struct rt_thread, tlist);
  203. /* set error code to RT_ERROR */
  204. thread->error = -RT_ERROR;
  205. /*
  206. * resume thread
  207. * In rt_thread_resume function, it will remove current thread from suspend
  208. * list
  209. */
  210. rt_thread_resume(thread);
  211. /* decrease suspended thread count */
  212. mp->suspend_thread_count --;
  213. /* enable interrupt */
  214. rt_hw_interrupt_enable(temp);
  215. }
  216. #if defined(RT_USING_MODULE) && defined(RT_USING_SLAB)
  217. /* the mp object belongs to an application module */
  218. if (mp->parent.flag & RT_OBJECT_FLAG_MODULE)
  219. rt_module_free(mp->parent.module_id, mp->start_address);
  220. else
  221. #endif
  222. /* release allocated room */
  223. rt_free(mp->start_address);
  224. /* detach object */
  225. rt_object_delete(&(mp->parent));
  226. return RT_EOK;
  227. }
  228. #endif
  229. /**
  230. * This function will allocate a block from memory pool
  231. *
  232. * @param mp the memory pool object
  233. * @param time the waiting time
  234. *
  235. * @return the allocated memory block or RT_NULL on allocated failed
  236. */
  237. void *rt_mp_alloc(rt_mp_t mp, rt_int32_t time)
  238. {
  239. rt_uint8_t *block_ptr;
  240. register rt_base_t level;
  241. struct rt_thread *thread;
  242. /* disable interrupt */
  243. level = rt_hw_interrupt_disable();
  244. if (mp->block_free_count)
  245. {
  246. /* memory block is available. decrease the free block counter */
  247. mp->block_free_count --;
  248. /* get block from block list */
  249. block_ptr = mp->block_list;
  250. mp->block_list = *(rt_uint8_t **)block_ptr;
  251. /* point to memory pool */
  252. *(rt_uint8_t **)block_ptr = (rt_uint8_t *)mp;
  253. }
  254. else
  255. {
  256. /* memory block is unavailable. */
  257. if (time == 0)
  258. {
  259. /* enable interrupt */
  260. rt_hw_interrupt_enable(level);
  261. return RT_NULL;
  262. }
  263. else
  264. {
  265. RT_DEBUG_NOT_IN_INTERRUPT;
  266. /* get current thread */
  267. thread = rt_thread_self();
  268. /* need suspend thread */
  269. rt_thread_suspend(thread);
  270. rt_list_insert_after(&(mp->suspend_thread), &(thread->tlist));
  271. mp->suspend_thread_count ++;
  272. if (time > 0)
  273. {
  274. /* init thread timer and start it */
  275. rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &time);
  276. rt_timer_start(&(thread->thread_timer));
  277. }
  278. /* enable interrupt */
  279. rt_hw_interrupt_enable(level);
  280. /* do a schedule */
  281. rt_schedule();
  282. if (thread->error != RT_EOK)
  283. return RT_NULL;
  284. /* disable interrupt */
  285. level = rt_hw_interrupt_disable();
  286. /* decrease free block */
  287. mp->block_free_count --;
  288. /* get block from block list */
  289. block_ptr = mp->block_list;
  290. mp->block_list = *(rt_uint8_t **)block_ptr;
  291. /* point to memory pool */
  292. *(rt_uint8_t **)block_ptr = (rt_uint8_t *)mp;
  293. }
  294. }
  295. /* enable interrupt */
  296. rt_hw_interrupt_enable(level);
  297. RT_OBJECT_HOOK_CALL(rt_mp_alloc_hook, (mp, (rt_uint8_t *)(block_ptr + sizeof(rt_uint8_t *))));
  298. return (rt_uint8_t *)(block_ptr + sizeof(rt_uint8_t *));
  299. }
  300. /**
  301. * This function will release a memory block
  302. *
  303. * @param block the address of memory block to be released
  304. */
  305. void rt_mp_free(void *block)
  306. {
  307. rt_uint8_t **block_ptr;
  308. struct rt_mempool *mp;
  309. struct rt_thread *thread;
  310. register rt_base_t level;
  311. /* get the control block of pool which the block belongs to */
  312. block_ptr = (rt_uint8_t **)((rt_uint8_t *)block - sizeof(rt_uint8_t *));
  313. mp = (struct rt_mempool *)*block_ptr;
  314. RT_OBJECT_HOOK_CALL(rt_mp_free_hook, (mp, block));
  315. /* disable interrupt */
  316. level = rt_hw_interrupt_disable();
  317. /* increase the free block count */
  318. mp->block_free_count ++;
  319. /* link the block into the block list */
  320. *block_ptr = mp->block_list;
  321. mp->block_list = (rt_uint8_t *)block_ptr;
  322. if (mp->suspend_thread_count > 0)
  323. {
  324. /* get the suspended thread */
  325. thread = rt_list_entry(mp->suspend_thread.next, struct rt_thread, tlist);
  326. /* set error */
  327. thread->error = RT_EOK;
  328. /* resume thread */
  329. rt_thread_resume(thread);
  330. /* decrease suspended thread count */
  331. mp->suspend_thread_count --;
  332. /* enable interrupt */
  333. rt_hw_interrupt_enable(level);
  334. /* do a schedule */
  335. rt_schedule();
  336. return;
  337. }
  338. /* enable interrupt */
  339. rt_hw_interrupt_enable(level);
  340. }
  341. /*@}*/
  342. #endif