📄 balloc.c
字号:
/* * balloc.c -- Block allocation module * * Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved. * * See the file "license.txt" for usage and redistribution license requirements *//******************************** Description *********************************//* * This module implements a very fast block allocation scheme suitable for * ROMed environments. It maintains block class queues for rapid allocation * and minimal fragmentation. This module does not coalesce blocks. The * storage space may be populated statically or via the traditional malloc * mechanisms. Large blocks greater than the maximum class size may be * allocated from the O/S or run-time system via malloc. To permit the use * of malloc, call bopen with flags set to B_USE_MALLOC (this is the default). * It is recommended that bopen be called first thing in the application. * If it is not, it will be called with default values on the first call to * balloc(). Note that this code is not designed for multi-threading purposes * and it depends on newly declared variables being initialized to zero. */ /********************************* Includes ***********************************/#define IN_BALLOC#if UEMF #include "uemf.h"#else #include "basic/basicInternal.h"#endif#include <stdarg.h>#include <stdlib.h>#if !NO_BALLOC/********************************* Defines ************************************//* * Define B_STATS if you wish to track memory block and stack usage */#if B_STATS/* * Optional statistics */typedef struct { long alloc; /* Block allocation calls */ long inuse; /* Blocks in use */} bStatsType;typedef struct { char_t file[FNAMESIZE]; long allocated; /* Bytes currently allocated */ long count; /* Current block count */ long times; /* Count of alloc attempts */ long largest; /* largest allocated here */ int q;} bStatsFileType;/* * This one is very expensive but great stats */typedef struct { void *ptr; /* Pointer to memory */ bStatsFileType *who; /* Who allocated the memory */} bStatsBlkType;static bStatsType bStats[B_MAX_CLASS]; /* Per class stats */static bStatsFileType bStatsFiles[B_MAX_FILES];/* Per file stats */static bStatsBlkType bStatsBlks[B_MAX_BLOCKS];/* Per block stats */static int bStatsBlksMax = 0; /* Max block entry */static int bStatsFilesMax = 0; /* Max file entry */static int bStatsMemInUse = 0; /* Memory currently in use */static int bStatsBallocInUse = 0; /* Memory currently balloced */static int bStatsMemMax = 0; /* Max memory ever used */static int bStatsBallocMax = 0; /* Max memory ever balloced */static void *bStackMin = (void*) -1;/* Miniumum stack position */static void *bStackStart; /* Starting stack position */static int bStatsMemMalloc = 0; /* Malloced memory */#endif /* B_STATS *//* * ROUNDUP4(size) returns the next higher integer value of size that is * divisible by 4, or the value of size if size is divisible by 4. * ROUNDUP4() is used in aligning memory allocations on 4-byte boundaries. * * Note: ROUNDUP4() is only required on some operating systems (IRIX). */#define ROUNDUP4(size) ((size) % 4) ? (size) + (4 - ((size) % 4)) : (size)/********************************** Locals ************************************//* * bQhead blocks are created as the original memory allocation is freed up. * See bfree. */static bType *bQhead[B_MAX_CLASS]; /* Per class block q head */static char *bFreeBuf; /* Pointer to free memory */static char *bFreeNext; /* Pointer to next free mem */static int bFreeSize; /* Size of free memory */static int bFreeLeft; /* Size of free left for use */static int bFlags = B_USE_MALLOC; /* Default to auto-malloc */static int bopenCount = 0; /* Num tasks using balloc *//*************************** Forward Declarations *****************************/#if B_STATSstatic void bStatsAlloc(B_ARGS_DEC, void *ptr, int q, int size);static void bStatsFree(B_ARGS_DEC, void *ptr, int q, int size);static void bstatsWrite(int handle, char_t *fmt, ...);static int bStatsFileSort(const void *cp1, const void *cp2);#endif /* B_STATS */#if B_FILL || B_VERIFY_CAUSES_SEVERE_OVERHEADstatic void bFillBlock(void *buf, int bufsize);#endif#if B_VERIFY_CAUSES_SEVERE_OVERHEADstatic void verifyUsedBlock(bType *bp, int q);static void verifyFreeBlock(bType *bp, int q);void verifyBallocSpace();#endifstatic int ballocGetSize(int size, int *q);/********************************** Code **************************************//* * Initialize the balloc module. bopen should be called the very first thing * after the application starts and bclose should be called the last thing * before exiting. If bopen is not called, it will be called on the first * allocation with default values. "buf" points to memory to use of size * "bufsize". If buf is NULL, memory is allocated using malloc. flags may * be set to B_USE_MALLOC if using malloc is okay. This routine will allocate * an initial buffer of size bufsize for use by the application. */int bopen(void *buf, int bufsize, int flags){ bFlags = flags;#if BASTARD_TESTING srand(time(0L));#endif /* BASTARD_TESTING *//* * If bopen already called by a shared process, just increment the count * and return; */ if (++bopenCount > 1) { return 0; } if (buf == NULL) { if (bufsize == 0) { bufsize = B_DEFAULT_MEM; }#ifdef IRIX bufsize = ROUNDUP4(bufsize);#endif if ((buf = malloc(bufsize)) == NULL) { return -1; }#if B_STATS bStatsMemMalloc += bufsize;#endif } else { bFlags |= B_USER_BUF; } bFreeSize = bFreeLeft = bufsize; bFreeBuf = bFreeNext = buf; memset(bQhead, 0, sizeof(bQhead));#if B_FILL || B_VERIFY_CAUSES_SEVERE_OVERHEAD bFillBlock(buf, bufsize);#endif#if B_STATS bStackStart = &buf;#endif#if B_VERIFY_CAUSES_SEVERE_OVERHEAD verifyFreeBlock(buf, bufsize);#endif return 0;}/******************************************************************************//* * Close down the balloc module and free all malloced memory. */void bclose(){#if B_VERIFY_CAUSES_SEVERE_OVERHEAD verifyBallocSpace();#endif if (--bopenCount <= 0 && !(bFlags & B_USER_BUF)) { free(bFreeBuf); bopenCount = 0; }}/******************************************************************************//* * Allocate a block of the requested size. First check the block * queues for a suitable one. */void *balloc(B_ARGS_DEC, int size){ bType *bp; int q, memSize;/* * Call bopen with default values if the application has not yet done so */ if (bFreeBuf == NULL) { if (bopen(NULL, B_DEFAULT_MEM, 0) < 0) { return NULL; } }#if B_VERIFY_CAUSES_SEVERE_OVERHEAD verifyBallocSpace();#endif if (size < 0) { return NULL; }#if BASTARD_TESTING if (rand() == 0x7fff) { return NULL; }#endif /* BASTARD_TESTING */ memSize = ballocGetSize(size, &q); if (q >= B_MAX_CLASS) {/* * Size if bigger than the maximum class. Malloc if use has been okayed */ if (bFlags & B_USE_MALLOC) {#if B_STATS bstats(0, NULL);#endif#ifdef IRIX memSize = ROUNDUP4(memSize);#endif bp = (bType*) malloc(memSize); if (bp == NULL) { traceRaw(T("B: malloc failed\n")); return NULL; }#if B_STATS bStatsMemMalloc += memSize;#endif#if B_FILL || B_VERIFY_CAUSES_SEVERE_OVERHEAD bFillBlock(bp, memSize);#endif } else { traceRaw(T("B: malloc failed\n")); return NULL; }/* * the u.size is the actual size allocated for data */ bp->u.size = memSize - sizeof(bType); bp->flags = B_MALLOCED; } else if ((bp = bQhead[q]) != NULL) {/* * Take first block off the relevant q if non-empty */ bQhead[q] = bp->u.next;#if B_VERIFY_CAUSES_SEVERE_OVERHEAD verifyFreeBlock(bp, q);#endif#if B_FILL || B_VERIFY_CAUSES_SEVERE_OVERHEAD bFillBlock(bp, memSize);#endif bp->u.size = memSize - sizeof(bType); bp->flags = 0; } else { if (bFreeLeft > memSize) {/* * The q was empty, and the free list has spare memory so * create a new block out of the primary free block */ bp = (bType*) bFreeNext;#if B_VERIFY_CAUSES_SEVERE_OVERHEAD verifyFreeBlock(bp, q);#endif bFreeNext += memSize; bFreeLeft -= memSize;#if B_FILL || B_VERIFY_CAUSES_SEVERE_OVERHEAD bFillBlock(bp, memSize);#endif bp->u.size = memSize - sizeof(bType); bp->flags = 0; } else if (bFlags & B_USE_MALLOC) {#if B_STATS static int once = 0; if (once++ == 0) { bstats(0, NULL); }#endif/* * Nothing left on the primary free list, so malloc a new block */#ifdef IRIX memSize = ROUNDUP4(memSize);#endif if ((bp = (bType*) malloc(memSize)) == NULL) { traceRaw(T("B: malloc failed\n")); return NULL; }#if B_STATS bStatsMemMalloc += memSize;#endif#if B_FILL || B_VERIFY_CAUSES_SEVERE_OVERHEAD bFillBlock(bp, memSize);#endif bp->u.size = memSize - sizeof(bType); bp->flags = B_MALLOCED; } else { traceRaw(T("B: malloc failed\n")); return NULL; } }#if B_STATS bStatsAlloc(B_ARGS, bp, q, memSize);#endif bp->flags |= B_INTEGRITY;/* * The following is a good place to put a breakpoint when trying to reduce * determine and reduce maximum memory use. */#if 0#if B_STATS if (bStatsBallocInUse == bStatsBallocMax) { bstats(0, NULL); }#endif#endif return (void*) ((char*) bp + sizeof(bType));}/******************************************************************************//* * Free a block back to the relevant free q. We don't free back to the O/S * or run time system unless the block is greater than the maximum class size. * We also do not coalesce blocks. */void bfree(B_ARGS_DEC, void *mp){ bType *bp; int q, memSize;#if B_VERIFY_CAUSES_SEVERE_OVERHEAD verifyBallocSpace();#endif bp = (bType*) ((char*) mp - sizeof(bType)); a_assert((bp->flags & B_INTEGRITY_MASK) == B_INTEGRITY); if ((bp->flags & B_INTEGRITY_MASK) != B_INTEGRITY) { return; } memSize = ballocGetSize(bp->u.size, &q);#if B_VERIFY_CAUSES_SEVERE_OVERHEAD verifyUsedBlock(bp,q);#endif#if B_STATS bStatsFree(B_ARGS, bp, q, bp->u.size+sizeof(bType));#endif if (bp->flags & B_MALLOCED) { free(bp); return; } #if B_VERIFY_CAUSES_SEVERE_OVERHEAD bFillBlock(bp, memSize);#endif/* * Simply link onto the head of the relevant q */ bp->u.next = bQhead[q]; bQhead[q] = bp; bp->flags = B_FILL_WORD;}/******************************************************************************//* * Safe free */void bfreeSafe(B_ARGS_DEC, void *mp){ if (mp) { bfree(B_ARGS, mp); }}/******************************************************************************/#if UNICODE/* * Duplicate a string, allow NULL pointers and then dup an empty string. */char *bstrdupA(B_ARGS_DEC, char *s){ char *cp; int len; if (s == NULL) { s = ""; } len = strlen(s) + 1; if (cp = balloc(B_ARGS, len)) { strcpy(cp, s); } return cp;}#endif /* UNICODE *//******************************************************************************//* * Duplicate an ascii string, allow NULL pointers and then dup an empty string. * If UNICODE, bstrdup above works with wide chars, so we need this routine * for ascii strings. */char_t *bstrdup(B_ARGS_DEC, char_t *s){ char_t *cp; int len; if (s == NULL) { s = T(""); } len = gstrlen(s) + 1; if ((cp = balloc(B_ARGS, len * sizeof(char_t))) != NULL) { gstrcpy(cp, s); } return cp;}/******************************************************************************//* * Reallocate a block. Allow NULL pointers and just do a malloc. * Note: if the realloc fails, we return NULL and the previous buffer is * preserved. */void *brealloc(B_ARGS_DEC, void *mp, int newsize){ bType *bp; void *newbuf; if (mp == NULL) { return balloc(B_ARGS, newsize); } bp = (bType*) ((char*) mp - sizeof(bType)); a_assert((bp->flags & B_INTEGRITY_MASK) == B_INTEGRITY);/* * If the allocated memory already has enough room just return the previously * allocated address. */ if (bp->u.size >= newsize) { return mp;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -