📄 memory.c
字号:
/* *---------------------------------------------------------------------- * micro T-Kernel * * Copyright (C) 2006-2007 by Ken Sakamura. All rights reserved. * micro T-Kernel is distributed under the micro T-License. *---------------------------------------------------------------------- * * Version: 1.00.00 * Released by T-Engine Forum(http://www.t-engine.org) at 2007/03/26. * *---------------------------------------------------------------------- *//** [BEGIN Common Definitions] */#include "kernel.h"#include <sys/imalloc.h>#include "memory.h"/** [END Common Definitions] */#ifdef USE_FUNC_SEARCHFREEAREA/* * FreeQue search * Search the free area whose size is equal to 'blksz', * or larger than * 'blksz' but closest. * If it does not exist, return '&imacb->freeque'. */EXPORT QUEUE* knl_searchFreeArea( IMACB *imacb, W blksz ){ QUEUE *q = &imacb->freeque; /* For area whose memory pool size is less than 1/4, search from smaller size. Otherwise, search from larger size. */ if ( blksz > imacb->memsz / 4 ) { /* Search from larger size. */ W fsz = 0; while ( (q = q->prev) != &imacb->freeque ) { fsz = FreeSize(q); if ( fsz <= blksz ) { return ( fsz < blksz )? q->next: q; } } return ( fsz >= blksz )? q->next: q; } else { /* Search from smaller size. */ while ( (q = q->next) != &imacb->freeque ) { if ( FreeSize(q) >= blksz ) { break; } } return q; }}#endif /* USE_FUNC_SEARCHFREEAREA */#ifdef USE_FUNC_APPENDFREEAREA/* * Registration of free area on FreeQue * FreeQue is composed of 2 types: Queue that links the * different size of areas by size and queue that links the * same size of areas. * * freeque * | * | +-----------------------+ +-----------------------+ * | | AreaQue | | AreaQue | * | +-----------------------+ +-----------------------+ * *---> FreeQue Size order | *----> FreeQue Same size -----> * | | FreeQue Same size -----* | EmptyQue | * | | | | | * | | | | | * | +-----------------------+ +-----------------------+ * | | AreaQue | | AreaQue | * v +-----------------------+ +-----------------------+ */EXPORT void knl_appendFreeArea( IMACB *imacb, QUEUE *aq ){ QUEUE *fq; W size = AreaSize(aq); /* Registration position search */ /* Search the free area whose size is equal to 'blksz', * or larger than 'blksz' but closest. * If it does not exist, return '&imacb->freeque'. */ fq = knl_searchFreeArea(imacb, size); /* Register */ clrAreaFlag(aq, AREA_USE); if ( fq != &imacb->freeque && FreeSize(fq) == size ) { (aq + 2)->next = (fq + 1)->next; (fq + 1)->next = aq + 2; (aq + 2)->prev = fq + 1; (aq + 2)->next->prev = aq + 2; (aq + 1)->next = NULL; } else { QueInsert(aq + 1, fq); (aq + 2)->next = NULL; (aq + 2)->prev = (QUEUE*)size; }}#endif /* USE_FUNC_APPENDFREEAREA */#ifdef USE_FUNC_REMOVEFREEQUE/* * Delete from FreeQue */EXPORT void knl_removeFreeQue( QUEUE *fq ){ if ( fq->next == NULL ) { (fq + 1)->prev->next = (fq + 1)->next; if ( (fq + 1)->next != NULL ) { (fq + 1)->next->prev = (fq + 1)->prev; } } else { if ( (fq + 1)->next != NULL ) { QueInsert((fq + 1)->next - 1, fq); (fq + 1)->next->prev = (fq + 1)->prev; } QueRemove(fq); }}#endif /* USE_FUNC_REMOVEFREEQUE */#ifdef USE_FUNC_INSERTAREAQUE/* * Register area * Insert 'ent' just after 'que.' */EXPORT void knl_insertAreaQue( QUEUE *que, QUEUE *ent ){ ent->prev = que; ent->next = que->next; Assign(que->next->prev, ent); que->next = ent;}#endif /* USE_FUNC_INSERTAREAQUE */#ifdef USE_FUNC_REMOVEAREAQUE/* * Delete area */EXPORT void knl_removeAreaQue( QUEUE *aq ){ Mask(aq->prev)->next = aq->next; Assign(aq->next->prev, Mask(aq->prev));}#endif /* USE_FUNC_REMOVEAREAQUE *//* ------------------------------------------------------------------------ */#if USE_IMALLOC/* ------------------------------------------------------------------------ */#ifdef USE_FUNC_IMACBNoinit(EXPORT IMACB *knl_imacb);#endif /* USE_FUNC_IMACB *//* ------------------------------------------------------------------------ */#ifdef USE_FUNC_IMALLOC/* * Get memory */EXPORT void* knl_Imalloc( size_t size ){ QUEUE *q, *aq, *aq2; UINT imask; /* If it is smaller than the minimum fragment size, allocate the minimum size to it. */ if ( size < MIN_FRAGMENT ) { size = MIN_FRAGMENT; } else { size = ROUND(size); } DI(imask); /* Exclusive control by interrupt disable */ /* Search FreeQue */ q = knl_searchFreeArea(knl_imacb, size); if ( q == &(knl_imacb->freeque) ) { return NULL; /* Insufficient memory */ } /* There is free area: Split from FreeQue once */ knl_removeFreeQue(q); aq = q - 1; /* If there are fragments smaller than the minimum fragment size, allocate them also */ if ( FreeSize(q) - size >= MIN_FRAGMENT + sizeof(QUEUE) ) { /* Divide area into 2 */ aq2 = (QUEUE*)((VB*)(aq + 1) + size); knl_insertAreaQue(aq, aq2); /* Register remaining area to FreeQue */ knl_appendFreeArea(knl_imacb, aq2); } setAreaFlag(aq, AREA_USE); EI(imask); return (VP)q;}#endif /* USE_FUNC_IMALLOC */#ifdef USE_FUNC_ICALLOC/* * Get memory */EXPORT void* knl_Icalloc( size_t nmemb, size_t size ){ size_t sz = nmemb * size; void *mem; mem = knl_Imalloc(sz); if ( mem == NULL ) { return NULL; } memset(mem, 0, sz); return mem;}#endif /* USE_FUNC_ICALLOC */#ifdef USE_FUNC_IFREE/* * Free memory * It may be called during interrupt disable. In this case, need to wait * until interrupt is enabled and until free. */EXPORT void knl_Ifree( void *ptr ){ QUEUE *aq; UINT imask; DI(imask); /* Exclusive control by interrupt disable */ aq = (QUEUE*)ptr - 1; clrAreaFlag(aq, AREA_USE); if ( !chkAreaFlag(aq->next, AREA_USE) ) { /* Merge with free area in after location */ knl_removeFreeQue(aq->next + 1); knl_removeAreaQue(aq->next); } if ( !chkAreaFlag(aq->prev, AREA_USE) ) { /* Merge with free area in front location */ aq = aq->prev; knl_removeFreeQue(aq + 1); knl_removeAreaQue(aq->next); } knl_appendFreeArea(knl_imacb, aq); EI(imask);}#endif /* USE_FUNC_IFREE *//* ------------------------------------------------------------------------ */#ifdef USE_FUNC_INIT_IMALLOC/* * IMACB Initialization */LOCAL void initIMACB( void ){ QueInit(&(knl_imacb->areaque)); QueInit(&(knl_imacb->freeque));}/* * Imalloc initial setting */EXPORT ER knl_init_Imalloc( void ){/* Low-level memory management information */IMPORT VP knl_lowmem_top, knl_lowmem_limit; VP memend; QUEUE *top, *end; /* Acquire system configuration definition information */ memend = CFN_REALMEMEND; if ( (UW)memend > (UW)knl_lowmem_limit ) { memend = knl_lowmem_limit; } /* Align top with 8 byte unit alignment */ knl_lowmem_top = (VP)(((UW)knl_lowmem_top + 7) & ~0x00000007UL); knl_imacb = (IMACB*)knl_lowmem_top; knl_lowmem_top = (VP)((UW)knl_lowmem_top + sizeof(IMACB)); top = (QUEUE*)knl_lowmem_top; knl_imacb->memsz = (W)((UW)memend - (UW)knl_lowmem_top - sizeof(QUEUE)*2); knl_lowmem_top = memend; /* Update memory free space */ initIMACB(); /* Register on AreaQue */ end = (QUEUE*)((VB*)top + knl_imacb->memsz) + 1; knl_insertAreaQue(&knl_imacb->areaque, end); knl_insertAreaQue(&knl_imacb->areaque, top); setAreaFlag(end, AREA_USE); setAreaFlag(&knl_imacb->areaque, AREA_USE); knl_appendFreeArea(knl_imacb, top); return E_OK;}#endif /* USE_FUNC_INIT_IMALLOC */#endif /* USE_IMALLOC */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -