mempool.c 9.5 KB

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