mempool.c 9.6 KB

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