mempool.c 10 KB

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