mempool.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  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. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License along
  17. * with this program; if not, write to the Free Software Foundation, Inc.,
  18. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  19. *
  20. * Change Logs:
  21. * Date Author Notes
  22. * 2006-05-27 Bernard implement memory pool
  23. * 2006-06-03 Bernard fix the thread timer init bug
  24. * 2006-06-30 Bernard fix the allocate/free block bug
  25. * 2006-08-04 Bernard add hook support
  26. * 2006-08-10 Bernard fix interrupt bug in rt_mp_alloc
  27. * 2010-07-13 Bernard fix RT_ALIGN issue found by kuronca
  28. * 2010-10-26 yi.qiu add module support in rt_mp_delete
  29. * 2011-01-24 Bernard add object allocation check.
  30. * 2012-03-22 Bernard fix align issue in rt_mp_init and rt_mp_create.
  31. */
  32. #include <rthw.h>
  33. #include <rtthread.h>
  34. #ifdef RT_USING_MEMPOOL
  35. #ifdef RT_USING_HOOK
  36. static void (*rt_mp_alloc_hook)(struct rt_mempool *mp, void *block);
  37. static void (*rt_mp_free_hook)(struct rt_mempool *mp, void *block);
  38. /**
  39. * @addtogroup Hook
  40. */
  41. /**@{*/
  42. /**
  43. * This function will set a hook function, which will be invoked when a memory
  44. * block is allocated from memory pool.
  45. *
  46. * @param hook the hook function
  47. */
  48. void rt_mp_alloc_sethook(void (*hook)(struct rt_mempool *mp, void *block))
  49. {
  50. rt_mp_alloc_hook = hook;
  51. }
  52. /**
  53. * This function will set a hook function, which will be invoked when a memory
  54. * block is released to memory pool.
  55. *
  56. * @param hook the hook function
  57. */
  58. void rt_mp_free_sethook(void (*hook)(struct rt_mempool *mp, void *block))
  59. {
  60. rt_mp_free_hook = hook;
  61. }
  62. /**@}*/
  63. #endif
  64. /**
  65. * @addtogroup MM
  66. */
  67. /**@{*/
  68. /**
  69. * This function will initialize a memory pool object, normally which is used
  70. * for static object.
  71. *
  72. * @param mp the memory pool object
  73. * @param name the name of memory pool
  74. * @param start the star address of memory pool
  75. * @param size the total size of memory pool
  76. * @param block_size the size for each block
  77. *
  78. * @return RT_EOK
  79. */
  80. rt_err_t rt_mp_init(struct rt_mempool *mp,
  81. const char *name,
  82. void *start,
  83. rt_size_t size,
  84. rt_size_t block_size)
  85. {
  86. rt_uint8_t *block_ptr;
  87. register rt_size_t offset;
  88. /* parameter check */
  89. RT_ASSERT(mp != RT_NULL);
  90. /* initialize object */
  91. rt_object_init(&(mp->parent), RT_Object_Class_MemPool, name);
  92. /* initialize memory pool */
  93. mp->start_address = start;
  94. mp->size = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE);
  95. /* align the block size */
  96. block_size = RT_ALIGN(block_size, RT_ALIGN_SIZE);
  97. mp->block_size = block_size;
  98. /* align to align size byte */
  99. mp->block_total_count = mp->size / (mp->block_size + sizeof(rt_uint8_t *));
  100. mp->block_free_count = mp->block_total_count;
  101. /* initialize suspended thread list */
  102. rt_list_init(&(mp->suspend_thread));
  103. mp->suspend_thread_count = 0;
  104. /* initialize free block list */
  105. block_ptr = (rt_uint8_t *)mp->start_address;
  106. for (offset = 0; offset < mp->block_total_count; offset ++)
  107. {
  108. *(rt_uint8_t **)(block_ptr + offset * (block_size + sizeof(rt_uint8_t *))) =
  109. (rt_uint8_t *)(block_ptr + (offset + 1) * (block_size + sizeof(rt_uint8_t *)));
  110. }
  111. *(rt_uint8_t **)(block_ptr + (offset - 1) * (block_size + sizeof(rt_uint8_t *))) =
  112. RT_NULL;
  113. mp->block_list = block_ptr;
  114. return RT_EOK;
  115. }
  116. RTM_EXPORT(rt_mp_init);
  117. /**
  118. * This function will detach a memory pool from system object management.
  119. *
  120. * @param mp the memory pool object
  121. *
  122. * @return RT_EOK
  123. */
  124. rt_err_t rt_mp_detach(struct rt_mempool *mp)
  125. {
  126. struct rt_thread *thread;
  127. register rt_ubase_t temp;
  128. /* parameter check */
  129. RT_ASSERT(mp != RT_NULL);
  130. RT_ASSERT(rt_object_get_type(&mp->parent) == RT_Object_Class_MemPool);
  131. RT_ASSERT(rt_object_is_systemobject(&mp->parent));
  132. /* wake up all suspended threads */
  133. while (!rt_list_isempty(&(mp->suspend_thread)))
  134. {
  135. /* disable interrupt */
  136. temp = rt_hw_interrupt_disable();
  137. /* get next suspend thread */
  138. thread = rt_list_entry(mp->suspend_thread.next, struct rt_thread, tlist);
  139. /* set error code to RT_ERROR */
  140. thread->error = -RT_ERROR;
  141. /*
  142. * resume thread
  143. * In rt_thread_resume function, it will remove current thread from
  144. * suspend list
  145. */
  146. rt_thread_resume(thread);
  147. /* decrease suspended thread count */
  148. mp->suspend_thread_count --;
  149. /* enable interrupt */
  150. rt_hw_interrupt_enable(temp);
  151. }
  152. /* detach object */
  153. rt_object_detach(&(mp->parent));
  154. return RT_EOK;
  155. }
  156. RTM_EXPORT(rt_mp_detach);
  157. #ifdef RT_USING_HEAP
  158. /**
  159. * This function will create a mempool object and allocate the memory pool from
  160. * heap.
  161. *
  162. * @param name the name of memory pool
  163. * @param block_count the count of blocks in memory pool
  164. * @param block_size the size for each block
  165. *
  166. * @return the created mempool object
  167. */
  168. rt_mp_t rt_mp_create(const char *name,
  169. rt_size_t block_count,
  170. rt_size_t block_size)
  171. {
  172. rt_uint8_t *block_ptr;
  173. struct rt_mempool *mp;
  174. register rt_size_t offset;
  175. RT_DEBUG_NOT_IN_INTERRUPT;
  176. /* allocate object */
  177. mp = (struct rt_mempool *)rt_object_allocate(RT_Object_Class_MemPool, name);
  178. /* allocate object failed */
  179. if (mp == RT_NULL)
  180. return RT_NULL;
  181. /* initialize memory pool */
  182. block_size = RT_ALIGN(block_size, RT_ALIGN_SIZE);
  183. mp->block_size = block_size;
  184. mp->size = (block_size + sizeof(rt_uint8_t *)) * block_count;
  185. /* allocate memory */
  186. mp->start_address = rt_malloc((block_size + sizeof(rt_uint8_t *)) *
  187. block_count);
  188. if (mp->start_address == RT_NULL)
  189. {
  190. /* no memory, delete memory pool object */
  191. rt_object_delete(&(mp->parent));
  192. return RT_NULL;
  193. }
  194. mp->block_total_count = block_count;
  195. mp->block_free_count = mp->block_total_count;
  196. /* initialize suspended thread list */
  197. rt_list_init(&(mp->suspend_thread));
  198. mp->suspend_thread_count = 0;
  199. /* initialize free block list */
  200. block_ptr = (rt_uint8_t *)mp->start_address;
  201. for (offset = 0; offset < mp->block_total_count; offset ++)
  202. {
  203. *(rt_uint8_t **)(block_ptr + offset * (block_size + sizeof(rt_uint8_t *)))
  204. = block_ptr + (offset + 1) * (block_size + sizeof(rt_uint8_t *));
  205. }
  206. *(rt_uint8_t **)(block_ptr + (offset - 1) * (block_size + sizeof(rt_uint8_t *)))
  207. = RT_NULL;
  208. mp->block_list = block_ptr;
  209. return mp;
  210. }
  211. RTM_EXPORT(rt_mp_create);
  212. /**
  213. * This function will delete a memory pool and release the object memory.
  214. *
  215. * @param mp the memory pool object
  216. *
  217. * @return RT_EOK
  218. */
  219. rt_err_t rt_mp_delete(rt_mp_t mp)
  220. {
  221. struct rt_thread *thread;
  222. register rt_ubase_t temp;
  223. RT_DEBUG_NOT_IN_INTERRUPT;
  224. /* parameter check */
  225. RT_ASSERT(mp != RT_NULL);
  226. RT_ASSERT(rt_object_get_type(&mp->parent) == RT_Object_Class_MemPool);
  227. RT_ASSERT(rt_object_is_systemobject(&mp->parent) == RT_FALSE);
  228. /* wake up all suspended threads */
  229. while (!rt_list_isempty(&(mp->suspend_thread)))
  230. {
  231. /* disable interrupt */
  232. temp = rt_hw_interrupt_disable();
  233. /* get next suspend thread */
  234. thread = rt_list_entry(mp->suspend_thread.next, struct rt_thread, tlist);
  235. /* set error code to RT_ERROR */
  236. thread->error = -RT_ERROR;
  237. /*
  238. * resume thread
  239. * In rt_thread_resume function, it will remove current thread from
  240. * suspend list
  241. */
  242. rt_thread_resume(thread);
  243. /* decrease suspended thread count */
  244. mp->suspend_thread_count --;
  245. /* enable interrupt */
  246. rt_hw_interrupt_enable(temp);
  247. }
  248. /* release allocated room */
  249. rt_free(mp->start_address);
  250. /* detach object */
  251. rt_object_delete(&(mp->parent));
  252. return RT_EOK;
  253. }
  254. RTM_EXPORT(rt_mp_delete);
  255. #endif
  256. /**
  257. * This function will allocate a block from memory pool
  258. *
  259. * @param mp the memory pool object
  260. * @param time the waiting time
  261. *
  262. * @return the allocated memory block or RT_NULL on allocated failed
  263. */
  264. void *rt_mp_alloc(rt_mp_t mp, rt_int32_t time)
  265. {
  266. rt_uint8_t *block_ptr;
  267. register rt_base_t level;
  268. struct rt_thread *thread;
  269. rt_uint32_t before_sleep = 0;
  270. /* get current thread */
  271. thread = rt_thread_self();
  272. /* disable interrupt */
  273. level = rt_hw_interrupt_disable();
  274. while (mp->block_free_count == 0)
  275. {
  276. /* memory block is unavailable. */
  277. if (time == 0)
  278. {
  279. /* enable interrupt */
  280. rt_hw_interrupt_enable(level);
  281. rt_set_errno(-RT_ETIMEOUT);
  282. return RT_NULL;
  283. }
  284. RT_DEBUG_NOT_IN_INTERRUPT;
  285. thread->error = RT_EOK;
  286. /* need suspend thread */
  287. rt_thread_suspend(thread);
  288. rt_list_insert_after(&(mp->suspend_thread), &(thread->tlist));
  289. mp->suspend_thread_count++;
  290. if (time > 0)
  291. {
  292. /* get the start tick of timer */
  293. before_sleep = rt_tick_get();
  294. /* init thread timer and start it */
  295. rt_timer_control(&(thread->thread_timer),
  296. RT_TIMER_CTRL_SET_TIME,
  297. &time);
  298. rt_timer_start(&(thread->thread_timer));
  299. }
  300. /* enable interrupt */
  301. rt_hw_interrupt_enable(level);
  302. /* do a schedule */
  303. rt_schedule();
  304. if (thread->error != RT_EOK)
  305. return RT_NULL;
  306. if (time > 0)
  307. {
  308. time -= rt_tick_get() - before_sleep;
  309. if (time < 0)
  310. time = 0;
  311. }
  312. /* disable interrupt */
  313. level = rt_hw_interrupt_disable();
  314. }
  315. /* memory block is available. decrease the free block counter */
  316. mp->block_free_count--;
  317. /* get block from block list */
  318. block_ptr = mp->block_list;
  319. RT_ASSERT(block_ptr != RT_NULL);
  320. /* Setup the next free node. */
  321. mp->block_list = *(rt_uint8_t **)block_ptr;
  322. /* point to memory pool */
  323. *(rt_uint8_t **)block_ptr = (rt_uint8_t *)mp;
  324. /* enable interrupt */
  325. rt_hw_interrupt_enable(level);
  326. RT_OBJECT_HOOK_CALL(rt_mp_alloc_hook,
  327. (mp, (rt_uint8_t *)(block_ptr + sizeof(rt_uint8_t *))));
  328. return (rt_uint8_t *)(block_ptr + sizeof(rt_uint8_t *));
  329. }
  330. RTM_EXPORT(rt_mp_alloc);
  331. /**
  332. * This function will release a memory block
  333. *
  334. * @param block the address of memory block to be released
  335. */
  336. void rt_mp_free(void *block)
  337. {
  338. rt_uint8_t **block_ptr;
  339. struct rt_mempool *mp;
  340. struct rt_thread *thread;
  341. register rt_base_t level;
  342. /* get the control block of pool which the block belongs to */
  343. block_ptr = (rt_uint8_t **)((rt_uint8_t *)block - sizeof(rt_uint8_t *));
  344. mp = (struct rt_mempool *)*block_ptr;
  345. RT_OBJECT_HOOK_CALL(rt_mp_free_hook, (mp, block));
  346. /* disable interrupt */
  347. level = rt_hw_interrupt_disable();
  348. /* increase the free block count */
  349. mp->block_free_count ++;
  350. /* link the block into the block list */
  351. *block_ptr = mp->block_list;
  352. mp->block_list = (rt_uint8_t *)block_ptr;
  353. if (mp->suspend_thread_count > 0)
  354. {
  355. /* get the suspended thread */
  356. thread = rt_list_entry(mp->suspend_thread.next,
  357. struct rt_thread,
  358. tlist);
  359. /* set error */
  360. thread->error = RT_EOK;
  361. /* resume thread */
  362. rt_thread_resume(thread);
  363. /* decrease suspended thread count */
  364. mp->suspend_thread_count --;
  365. /* enable interrupt */
  366. rt_hw_interrupt_enable(level);
  367. /* do a schedule */
  368. rt_schedule();
  369. return;
  370. }
  371. /* enable interrupt */
  372. rt_hw_interrupt_enable(level);
  373. }
  374. RTM_EXPORT(rt_mp_free);
  375. /**@}*/
  376. #endif