mempool.c 12 KB

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