当前位置: 首页 > 工具软件 > mempool > 使用案例 >

RT-Thread mempool.c

越望
2023-12-01
    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: 

 类似资料: