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: 33: #include <rthw.h> 34: #include <rtthread.h> 35: 36: #ifdef RT_USING_MEMPOOL 37: 38: #ifdef RT_USING_HOOK 39: static void (*rt_mp_alloc_hook)(struct rt_mempool *mp, void *block); 40: static void (*rt_mp_free_hook)(struct rt_mempool *mp, void *block); 41: 42: /** 43: * @addtogroup Hook 44: */ 45: 46: /*@{*/ 47: 48: /** 49: * This function will set a hook function, which will be invoked when a memory 50: * block is allocated from memory pool. 51: * 52: * @param hook the hook function 53: */ 54: void rt_mp_alloc_sethook(void (*hook)(struct rt_mempool *mp, void *block)) 55: { 56: rt_mp_alloc_hook = hook; 57: } 58: 59: /** 60: * This function will set a hook function, which will be invoked when a memory 61: * block is released to memory pool. 62: * 63: * @param hook the hook function 64: */ 65: void rt_mp_free_sethook(void (*hook)(struct rt_mempool *mp, void *block)) 66: { 67: rt_mp_free_hook = hook; 68: } 69: 70: /*@}*/ 71: #endif 72: 73: /** 74: * @addtogroup MM 75: */ 76: 77: /*@{*/ 78: 79: /** 80: * This function will initialize a memory pool object, normally which is used 81: * for static object. 82: * 83: * @param mp the memory pool object 84: * @param name the name of memory pool 85: * @param start the star address of memory pool 86: * @param size the total size of memory pool 87: * @param block_size the size for each block 88: * 89: * @return RT_EOK 90: */ 91: rt_err_t rt_mp_init(struct rt_mempool *mp, 92: const char *name, 93: void *start, 94: rt_size_t size, 95: rt_size_t block_size) 96: { 97: rt_uint8_t *block_ptr; 98: register rt_base_t offset; 99: 100: /* parameter check */ 101: RT_ASSERT(mp != RT_NULL); 102: 103: /* initialize object */ 104: rt_object_init(&(mp->parent), RT_Object_Class_MemPool, name); 105: 106: /* initialize memory pool */ 107: mp->start_address = start; 108: mp->size = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE); 109: 110: /* align the block size */ 111: block_size = RT_ALIGN(block_size, RT_ALIGN_SIZE); 112: mp->block_size = block_size; 113: 114: /* align to align size byte */ 115: mp->block_total_count = mp->size / (mp->block_size + sizeof(rt_uint8_t *)); 116: mp->block_free_count = mp->block_total_count; 117: 118: /* initialize suspended thread list */ 119: rt_list_init(&(mp->suspend_thread)); 120: mp->suspend_thread_count = 0; 121: 122: /* initialize free block list */ 123: block_ptr = (rt_uint8_t *)mp->start_address; 124: for (offset = 0; offset < mp->block_total_count; offset ++) 125: { 126: *(rt_uint8_t **)(block_ptr + offset * (block_size + sizeof(rt_uint8_t *))) = 127: (rt_uint8_t *)(block_ptr + (offset + 1) * (block_size + sizeof(rt_uint8_t *))); 128: } 129: 130: *(rt_uint8_t **)(block_ptr + (offset - 1) * (block_size + sizeof(rt_uint8_t *))) = 131: RT_NULL; 132: 133: mp->block_list = block_ptr; 134: 135: return RT_EOK; 136: } « end rt_mp_init » 137: RTM_EXPORT(rt_mp_init); 138: 139: /** 140: * This function will detach a memory pool from system object management. 141: * 142: * @param mp the memory pool object 143: * 144: * @return RT_EOK 145: */ 146: rt_err_t rt_mp_detach(struct rt_mempool *mp) 147: { 148: struct rt_thread *thread; 149: register rt_ubase_t temp; 150: 151: /* parameter check */ 152: RT_ASSERT(mp != RT_NULL); 153: 154: /* wake up all suspended threads */ 155: while (!rt_list_isempty(&(mp->suspend_thread))) 156: { 157: /* disable interrupt */ 158: temp = rt_hw_interrupt_disable(); 159: 160: /* get next suspend thread */ 161: thread = rt_list_entry(mp->suspend_thread.next, struct rt_thread, tlist); 162: /* set error code to RT_ERROR */ 163: thread->error = -RT_ERROR; 164: 165: /* 166: * resume thread 167: * In rt_thread_resume function, it will remove current thread from 168: * suspend list 169: */ 170: rt_thread_resume(thread); 171: 172: /* decrease suspended thread count */ 173: mp->suspend_thread_count --; 174: 175: /* enable interrupt */ 176: rt_hw_interrupt_enable(temp); 177: } « end while !rt_list_isempty(&(mp... » 178: 179: /* detach object */ 180: rt_object_detach(&(mp->parent)); 181: 182: return RT_EOK; 183: } « end rt_mp_detach » 184: RTM_EXPORT(rt_mp_detach); 185: 186: #ifdef RT_USING_HEAP 187: /** 188: * This function will create a mempool object and allocate the memory pool from 189: * heap. 190: * 191: * @param name the name of memory pool 192: * @param block_count the count of blocks in memory pool 193: * @param block_size the size for each block 194: * 195: * @return the created mempool object 196: */ 197: rt_mp_t rt_mp_create(const char *name, 198: rt_size_t block_count, 199: rt_size_t block_size) 200: { 201: rt_uint8_t *block_ptr; 202: struct rt_mempool *mp; 203: register rt_base_t offset; 204: 205: RT_DEBUG_NOT_IN_INTERRUPT; 206: 207: /* allocate object */ 208: mp = (struct rt_mempool *)rt_object_allocate(RT_Object_Class_MemPool, name); 209: /* allocate object failed */ 210: if (mp == RT_NULL) 211: return RT_NULL; 212: 213: /* initialize memory pool */ 214: block_size = RT_ALIGN(block_size, RT_ALIGN_SIZE); 215: mp->block_size = block_size; 216: mp->size = (block_size + sizeof(rt_uint8_t *)) * block_count; 217: 218: /* allocate memory */ 219: mp->start_address = rt_malloc((block_size + sizeof(rt_uint8_t *)) * 220: block_count); 221: if (mp->start_address == RT_NULL) 222: { 223: /* no memory, delete memory pool object */ 224: rt_object_delete(&(mp->parent)); 225: 226: return RT_NULL; 227: } 228: 229: mp->block_total_count = block_count; 230: mp->block_free_count = mp->block_total_count; 231: 232: /* initialize suspended thread list */ 233: rt_list_init(&(mp->suspend_thread)); 234: mp->suspend_thread_count = 0; 235: 236: /* initialize free block list */ 237: block_ptr = (rt_uint8_t *)mp->start_address; 238: for (offset = 0; offset < mp->block_total_count; offset ++) 239: { 240: *(rt_uint8_t **)(block_ptr + offset * (block_size + sizeof(rt_uint8_t *))) 241: = block_ptr + (offset + 1) * (block_size + sizeof(rt_uint8_t *)); 242: } 243: 244: *(rt_uint8_t **)(block_ptr + (offset - 1) * (block_size + sizeof(rt_uint8_t *))) 245: = RT_NULL; 246: 247: mp->block_list = block_ptr; 248: 249: return mp; 250: } « end rt_mp_create » 251: RTM_EXPORT(rt_mp_create); 252: 253: /** 254: * This function will delete a memory pool and release the object memory. 255: * 256: * @param mp the memory pool object 257: * 258: * @return RT_EOK 259: */ 260: rt_err_t rt_mp_delete(rt_mp_t mp) 261: { 262: struct rt_thread *thread; 263: register rt_ubase_t temp; 264: 265: RT_DEBUG_NOT_IN_INTERRUPT; 266: 267: /* parameter check */ 268: RT_ASSERT(mp != RT_NULL); 269: 270: /* wake up all suspended threads */ 271: while (!rt_list_isempty(&(mp->suspend_thread))) 272: { 273: /* disable interrupt */ 274: temp = rt_hw_interrupt_disable(); 275: 276: /* get next suspend thread */ 277: thread = rt_list_entry(mp->suspend_thread.next, struct rt_thread, tlist); 278: /* set error code to RT_ERROR */ 279: thread->error = -RT_ERROR; 280: 281: /* 282: * resume thread 283: * In rt_thread_resume function, it will remove current thread from 284: * suspend list 285: */ 286: rt_thread_resume(thread); 287: 288: /* decrease suspended thread count */ 289: mp->suspend_thread_count --; 290: 291: /* enable interrupt */ 292: rt_hw_interrupt_enable(temp); 293: } « end while !rt_list_isempty(&(mp... » 294: 295: #if defined(RT_USING_MODULE) && defined(RT_USING_SLAB) 296: /* the mp object belongs to an application module */ 297: if (mp->parent.flag & RT_OBJECT_FLAG_MODULE) 298: rt_module_free(mp->parent.module_id, mp->start_address); 299: else 300: #endif 301: 302: /* release allocated room */ 303: rt_free(mp->start_address); 304: 305: /* detach object */ 306: rt_object_delete(&(mp->parent)); 307: 308: return RT_EOK; 309: } « end rt_mp_delete » 310: RTM_EXPORT(rt_mp_delete); 311: #endif 312: 313: /** 314: * This function will allocate a block from memory pool 315: * 316: * @param mp the memory pool object 317: * @param time the waiting time 318: * 319: * @return the allocated memory block or RT_NULL on allocated failed 320: */ 321: void *rt_mp_alloc(rt_mp_t mp, rt_int32_t time) 322: { 323: rt_uint8_t *block_ptr; 324: register rt_base_t level; 325: struct rt_thread *thread; 326: 327: /* disable interrupt */ 328: level = rt_hw_interrupt_disable(); 329: 330: if (mp->block_free_count) 331: { 332: /* memory block is available. decrease the free block counter */ 333: mp->block_free_count --; 334: 335: /* get block from block list */ 336: block_ptr = mp->block_list; 337: mp->block_list = *(rt_uint8_t **)block_ptr; 338: 339: /* point to memory pool */ 340: *(rt_uint8_t **)block_ptr = (rt_uint8_t *)mp; 341: } 342: else 343: { 344: /* memory block is unavailable. */ 345: if (time == 0) 346: { 347: /* enable interrupt */ 348: rt_hw_interrupt_enable(level); 349: 350: return RT_NULL; 351: } 352: else 353: { 354: RT_DEBUG_NOT_IN_INTERRUPT; 355: 356: /* get current thread */ 357: thread = rt_thread_self(); 358: 359: /* need suspend thread */ 360: rt_thread_suspend(thread); 361: rt_list_insert_after(&(mp->suspend_thread), &(thread->tlist)); 362: mp->suspend_thread_count ++; 363: 364: if (time > 0) 365: { 366: /* init thread timer and start it */ 367: rt_timer_control(&(thread->thread_timer), 368: RT_TIMER_CTRL_SET_TIME, 369: &time); 370: rt_timer_start(&(thread->thread_timer)); 371: } 372: 373: /* enable interrupt */ 374: rt_hw_interrupt_enable(level); 375: 376: /* do a schedule */ 377: rt_schedule(); 378: 379: if (thread->error != RT_EOK) 380: return RT_NULL; 381: 382: /* disable interrupt */ 383: level = rt_hw_interrupt_disable(); 384: 385: /* decrease free block */ 386: mp->block_free_count --; 387: 388: /* get block from block list */ 389: block_ptr = mp->block_list; 390: mp->block_list = *(rt_uint8_t **)block_ptr; 391: 392: /* point to memory pool */ 393: *(rt_uint8_t **)block_ptr = (rt_uint8_t *)mp; 394: } « end else » 395: } « end else » 396: 397: /* enable interrupt */ 398: rt_hw_interrupt_enable(level); 399: 400: RT_OBJECT_HOOK_CALL(rt_mp_alloc_hook, 401: (mp, (rt_uint8_t *)(block_ptr + sizeof(rt_uint8_t *)))); 402: 403: return (rt_uint8_t *)(block_ptr + sizeof(rt_uint8_t *)); 404: } « end rt_mp_alloc » 405: RTM_EXPORT(rt_mp_alloc); 406: 407: /** 408: * This function will release a memory block 409: * 410: * @param block the address of memory block to be released 411: */ 412: void rt_mp_free(void *block) 413: { 414: rt_uint8_t **block_ptr; 415: struct rt_mempool *mp; 416: struct rt_thread *thread; 417: register rt_base_t level; 418: 419: /* get the control block of pool which the block belongs to */ 420: block_ptr = (rt_uint8_t **)((rt_uint8_t *)block - sizeof(rt_uint8_t *)); 421: mp = (struct rt_mempool *)*block_ptr; 422: 423: RT_OBJECT_HOOK_CALL(rt_mp_free_hook, (mp, block)); 424: 425: /* disable interrupt */ 426: level = rt_hw_interrupt_disable(); 427: 428: /* increase the free block count */ 429: mp->block_free_count ++; 430: 431: /* link the block into the block list */ 432: *block_ptr = mp->block_list; 433: mp->block_list = (rt_uint8_t *)block_ptr; 434: 435: if (mp->suspend_thread_count > 0) 436: { 437: /* get the suspended thread */ 438: thread = rt_list_entry(mp->suspend_thread.next, 439: struct rt_thread, 440: tlist); 441: 442: /* set error */ 443: thread->error = RT_EOK; 444: 445: /* resume thread */ 446: rt_thread_resume(thread); 447: 448: /* decrease suspended thread count */ 449: mp->suspend_thread_count --; 450: 451: /* enable interrupt */ 452: rt_hw_interrupt_enable(level); 453: 454: /* do a schedule */ 455: rt_schedule(); 456: 457: return; 458: } « end if mp->suspend_thread_co... » 459: 460: /* enable interrupt */ 461: rt_hw_interrupt_enable(level); 462: } « end rt_mp_free » 463: RTM_EXPORT(rt_mp_free); 464: 465: /*@}*/ 466: 467: #endif 468: