mempool.c 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. /*
  2. * File : mempool.c
  3. * This file is part of RT-Thread RTOS
  4. * COPYRIGHT (C) 2006 - 2009, 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. */
  20. #include <rthw.h>
  21. #include <rtthread.h>
  22. #include "kservice.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 mempool object, normally which is used for static object.
  59. *
  60. * @param mp the mempool object
  61. * @param name the name of memory pool
  62. * @param start the star address of memory pool
  63. * @param size the total size of memory pool
  64. * @param block_size the size for each block
  65. *
  66. * @return the operation status, RT_EOK on OK; RT_ERROR on error
  67. *
  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. rt_err_t rt_mp_detach(struct rt_mempool* mp)
  99. {
  100. struct rt_thread* thread;
  101. register rt_ubase_t temp;
  102. /* parameter check */
  103. RT_ASSERT(mp != RT_NULL);
  104. /* wakeup all suspended threads */
  105. while (!rt_list_isempty(&(mp->suspend_thread)))
  106. {
  107. /* disable interrupt */
  108. temp = rt_hw_interrupt_disable();
  109. /* get next suspend thread */
  110. thread = rt_list_entry(mp->suspend_thread.next, struct rt_thread, tlist);
  111. /* set error code to RT_ERROR */
  112. thread->error = -RT_ERROR;
  113. /*
  114. * resume thread
  115. * In rt_thread_resume function, it will remove current thread from suspend
  116. * list
  117. */
  118. rt_thread_resume(thread);
  119. /* decrease suspended thread count */
  120. mp->suspend_thread_count --;
  121. /* enable interrupt */
  122. rt_hw_interrupt_enable(temp);
  123. }
  124. /* detach object */
  125. rt_object_detach(&(mp->parent));
  126. return RT_EOK;
  127. }
  128. #ifdef RT_USING_HEAP
  129. /**
  130. * This function will create a mempool object and allocate the memory pool from heap.
  131. *
  132. * @param name the name of memory pool
  133. * @param block_count the count of blocks in memory pool
  134. * @param block_size the size for each block
  135. *
  136. * @return the created mempool object
  137. *
  138. */
  139. rt_mp_t rt_mp_create(const char* name, rt_size_t block_count, rt_size_t block_size)
  140. {
  141. rt_uint8_t *block_ptr;
  142. struct rt_mempool* mp;
  143. register rt_base_t offset;
  144. /* allocate object */
  145. mp = (struct rt_mempool*)rt_object_allocate(RT_Object_Class_MemPool, name);
  146. /* init memory pool */
  147. mp->block_size = RT_ALIGN(block_size, RT_ALIGN_SIZE);
  148. mp->size = (block_size + sizeof(rt_uint8_t*))* block_count;
  149. /* allocate memory */
  150. mp->start_address = rt_malloc((block_size + sizeof(rt_uint8_t*))* block_count);
  151. if (mp->start_address == RT_NULL)
  152. {
  153. /* no memory, delete memory pool object */
  154. rt_object_delete(&(mp->parent));
  155. return RT_NULL;
  156. }
  157. mp->block_total_count = block_count;
  158. mp->block_free_count = mp->block_total_count;
  159. /* init suspended thread list */
  160. rt_list_init(&(mp->suspend_thread));
  161. mp->suspend_thread_count = 0;
  162. /* init free block list */
  163. block_ptr = (rt_uint8_t*) mp->start_address;
  164. for (offset = 0; offset < mp->block_total_count; offset ++)
  165. {
  166. *(rt_uint8_t**)(block_ptr + offset * (block_size + sizeof(rt_uint8_t*)))
  167. = block_ptr + (offset + 1) * (block_size + sizeof(rt_uint8_t*));
  168. }
  169. *(rt_uint8_t**)(block_ptr + (offset - 1) * (block_size + sizeof(rt_uint8_t*))) = RT_NULL;
  170. mp->block_list = block_ptr;
  171. return mp;
  172. }
  173. /**
  174. * This function will delete a memory pool and release the object memory.
  175. *
  176. * @param mp the memory pool object
  177. *
  178. * @return the operation status, RT_EOK on OK; -RT_ERROR on error
  179. *
  180. */
  181. rt_err_t rt_mp_delete(rt_mp_t mp)
  182. {
  183. struct rt_thread* thread;
  184. register rt_ubase_t temp;
  185. /* parameter check */
  186. RT_ASSERT(mp != RT_NULL);
  187. /* wakeup all suspended threads */
  188. while (!rt_list_isempty(&(mp->suspend_thread)))
  189. {
  190. /* disable interrupt */
  191. temp = rt_hw_interrupt_disable();
  192. /* get next suspend thread */
  193. thread = rt_list_entry(mp->suspend_thread.next, struct rt_thread, tlist);
  194. /* set error code to RT_ERROR */
  195. thread->error = -RT_ERROR;
  196. /*
  197. * resume thread
  198. * In rt_thread_resume function, it will remove current thread from suspend
  199. * list
  200. */
  201. rt_thread_resume(thread);
  202. /* decrease suspended thread count */
  203. mp->suspend_thread_count --;
  204. /* enable interrupt */
  205. rt_hw_interrupt_enable(temp);
  206. }
  207. #ifdef RT_USING_MODULE
  208. /* the mp object belongs to an application module */
  209. if(mp->parent.flag & RT_OBJECT_FLAG_MODULE)
  210. rt_module_free(mp->parent.module_id, mp->start_address);
  211. else
  212. #endif
  213. /* release allocated room */
  214. rt_free(mp->start_address);
  215. /* detach object */
  216. rt_object_delete(&(mp->parent));
  217. return RT_EOK;
  218. }
  219. #endif
  220. /**
  221. * This function will allocate a block from memory pool
  222. *
  223. * @param mp the memory pool object
  224. * @param time the waiting time
  225. *
  226. * @return the allocated memory block
  227. *
  228. */
  229. void *rt_mp_alloc (rt_mp_t mp, rt_int32_t time)
  230. {
  231. rt_uint8_t* block_ptr;
  232. register rt_base_t level;
  233. struct rt_thread* thread;
  234. /* disable interrupt */
  235. level = rt_hw_interrupt_disable();
  236. if(mp->block_free_count)
  237. {
  238. /* memory block is available. decrease the free block counter */
  239. mp->block_free_count--;
  240. /* get block from block list */
  241. block_ptr = mp->block_list;
  242. mp->block_list = *(rt_uint8_t**)block_ptr;
  243. /* point to memory pool */
  244. *(rt_uint8_t**)block_ptr = (rt_uint8_t*)mp;
  245. }
  246. else
  247. {
  248. /* memory block is unavailable. */
  249. if (time == 0)
  250. {
  251. /* enable interrupt */
  252. rt_hw_interrupt_enable(level);
  253. return RT_NULL;
  254. }
  255. else
  256. {
  257. /* get current thread */
  258. thread = rt_thread_self();
  259. /* need suspend thread */
  260. rt_thread_suspend(thread);
  261. rt_list_insert_after(&(mp->suspend_thread), &(thread->tlist));
  262. mp->suspend_thread_count++;
  263. if (time > 0)
  264. {
  265. /* init thread timer and start it */
  266. rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &time);
  267. rt_timer_start(&(thread->thread_timer));
  268. }
  269. /* enable interrupt */
  270. rt_hw_interrupt_enable(level);
  271. /* do a schedule */
  272. rt_schedule();
  273. if (thread->error != RT_EOK) return RT_NULL;
  274. /* disable interrupt */
  275. level = rt_hw_interrupt_disable();
  276. /* decrease free block */
  277. mp->block_free_count --;
  278. /* get block from block list */
  279. block_ptr = mp->block_list;
  280. mp->block_list = *(rt_uint8_t**)block_ptr;
  281. /* point to memory pool */
  282. *(rt_uint8_t**)block_ptr = (rt_uint8_t*)mp;
  283. }
  284. }
  285. /* enable interrupt */
  286. rt_hw_interrupt_enable(level);
  287. #ifdef RT_USING_HOOK
  288. if (rt_mp_alloc_hook != RT_NULL) rt_mp_alloc_hook(mp, (rt_uint8_t*)(block_ptr + sizeof(rt_uint8_t*)));
  289. #endif
  290. return (rt_uint8_t*)(block_ptr + sizeof(rt_uint8_t*));
  291. }
  292. /**
  293. * This function will release a memory block
  294. *
  295. * @param block the address of memory block to be released
  296. *
  297. */
  298. void rt_mp_free (void *block)
  299. {
  300. rt_uint8_t **block_ptr;
  301. struct rt_mempool *mp;
  302. struct rt_thread *thread;
  303. register rt_base_t level;
  304. /* get the control block of pool which the block belongs to */
  305. block_ptr = (rt_uint8_t**)((rt_uint8_t*)block - sizeof(rt_uint8_t*));
  306. mp = (struct rt_mempool*) *block_ptr;
  307. #ifdef RT_USING_HOOK
  308. if (rt_mp_free_hook != RT_NULL) rt_mp_free_hook(mp, block);
  309. #endif
  310. /* disable interrupt */
  311. level = rt_hw_interrupt_disable();
  312. /* increase the free block count */
  313. mp->block_free_count ++;
  314. /* link the block into the block list */
  315. *block_ptr = mp->block_list;
  316. mp->block_list = (rt_uint8_t*)block_ptr;
  317. if (mp->suspend_thread_count > 0)
  318. {
  319. /* get the suspended thread */
  320. thread = rt_list_entry(mp->suspend_thread.next, struct rt_thread, tlist);
  321. /* set error */
  322. thread->error = RT_EOK;
  323. /* resume thread */
  324. rt_thread_resume(thread);
  325. /* decrease suspended thread count */
  326. mp->suspend_thread_count --;
  327. /* enable interrupt */
  328. rt_hw_interrupt_enable(level);
  329. /* do a schedule */
  330. rt_schedule();
  331. return;
  332. }
  333. /* enable interrupt */
  334. rt_hw_interrupt_enable(level);
  335. }
  336. #endif
  337. /*@}*/