📄 gmem.c
字号:
/*
* Copyright (C) Obigo AB, 2002-2005.
* All rights reserved.
*
* This software is covered by the license agreement between
* the end user and Obigo AB, and may be
* used and copied only in accordance with the terms of the
* said agreement.
*
* Obigo AB assumes no responsibility or
* liability for any errors or inaccuracies in this software,
* or any consequential, incidental or indirect damage arising
* out of the use of the software.
*
*/
#include "cansilib.h"
#include "cmntypes.h"
#include "cmnconf.h"
#include "aapicmn.h"
#include "gmem.h"
#ifdef USE_G_MALLOC
#define SIZE_S unsigned short
#define SIZE_L unsigned long
#define CHUNKHEADERSIZE 4
#define MINCHUNKSIZE 8
#define OFFSET_T unsigned short
#define MALLOC_ALIGN_MASK 3
#define MINBLOCKSIZE 24
#define NUM_FREE_LISTS 10
typedef unsigned char *Ptr;
typedef struct
{
SIZE_S prevSize;
SIZE_S size;
OFFSET_T fwd;
OFFSET_T bck;
} MemChunk;
typedef struct
{
int isInitiated;
Ptr base;
MemChunk *first;
MemChunk *last;
MemChunk *freelists[NUM_FREE_LISTS];
jmp_buf jmpbuf;
int inside;
#if CMN_LOG_INTERNAL & CMN_LOG_MEMORY
int lognum;
MallocStats stat;
#endif
} MemClient;
#if CMN_LOG_INTERNAL & CMN_LOG_MEMORY
#define MEM_MAX(a, b) ((a) > (b) ? (a) : (b))
#endif
#define chunk2mem(p) ((void*)((Ptr)(p) + CHUNKHEADERSIZE))
#define mem2chunk(mem) ((MemChunk *)((Ptr)(mem) - CHUNKHEADERSIZE))
#define chunksize(p) (((p)->size & ~0x01) << 1)
#define prevsize(p) (((p)->prevSize & ~0x01) << 1)
#define set_size(p, sz) \
(((MemChunk *)(p))->size = (SIZE_S)((((sz) >> 1) & ~0x01) | \
(((MemChunk *)(p))->size & 0x01)))
#define set_prevsize(p, sz) \
(((MemChunk *)(p))->prevSize = (SIZE_S)((((sz) >> 1) & ~0x01) |\
(((MemChunk *)(p))->prevSize & 0x01)))
#define set_hd1(p, v) ((p)->prevSize = (SIZE_S)(v))
#define set_hd2(p, v) ((p)->size = (SIZE_S)(v))
#define prevchunk(p) ((MemChunk *)(((Ptr)(p)) - prevsize(p)))
#define nextchunk(p) ((MemChunk *)(((Ptr)(p)) + chunksize(p)))
#define chunk_isfree(p) ((((MemChunk *)(p))->size & 0x01) == 0)
#define chunk_inuse(p) ((((MemChunk *)(p))->size & 0x01) == 1)
#define set_inuse(p) (((MemChunk *)(p))->size |= 0x01)
#define clear_inuse(p) (((MemChunk *)(p))->size &= ~0x01)
#define chunk_has_gcbit(p) ((((MemChunk *)(p))->prevSize & 0x01) == 1)
#define set_gcbit(p) (((MemChunk *)(p))->prevSize |= 0x01)
#define clear_gcbit(p) (((MemChunk *)(p))->prevSize &= ~0x01)
#define offset2ptr(o) ((MemChunk *)(memClients[id].base + ((o) << 2)))
#define ptr2offset(p) ((OFFSET_T)((((Ptr)(p)) - (Ptr)memClients[id].base) >> 2))
#define forward(p) (offset2ptr(((MemChunk *)(p))->fwd))
#define back(p) (offset2ptr(((MemChunk *)(p))->bck))
#define set_fwd(p, q) (((MemChunk *)(p))->fwd = ptr2offset(q))
#define set_bck(p, q) (((MemChunk *)(p))->bck = ptr2offset(q))
#define remove_from_list(p) do { \
MemChunk *fwd = forward(p); \
MemChunk *bck = back(p); \
fwd->bck = (p)->bck; \
bck->fwd = (p)->fwd; \
} while (0)
#define add_to_list(l, p) do { \
(p)->fwd = (l)->fwd; \
set_bck(p, l); \
set_bck(forward(l), p); \
set_fwd(l, p); \
} while (0)
#define append_to_list(l, p) do { \
set_fwd(p, l); \
set_bck(p, back(l)); \
set_fwd(back(l), p); \
set_bck(l, p); \
} while (0)
#define request2size(req) \
(((SIZE_L)((req) + CHUNKHEADERSIZE + MALLOC_ALIGN_MASK) < \
(SIZE_L)(MINCHUNKSIZE + MALLOC_ALIGN_MASK)) ? MINCHUNKSIZE : \
(SIZE_L)(((req) + CHUNKHEADERSIZE + MALLOC_ALIGN_MASK) & ~(MALLOC_ALIGN_MASK)))
static MemClient memClients[CMN_CLIENT_NUMBER];
static SIZE_L maxsizes[NUM_FREE_LISTS] =
{
16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 0x20000
};
static void gMemFreeChunk(CmnClientId id, MemPtr mem);
static short listIdx(SIZE_L n);
#if CMN_LOG_INTERNAL & CMN_LOG_MEMORY
static void checkAllocatedChunk(CmnClientId id, MemChunk *p);
static void gMemPrintUsage(CmnClientId id, const char *filename, int lineno);
#endif
#ifdef _MSC_VER
#pragma warning(disable: 4127)
#endif
int gMemGetInside(CmnClientId id)
{
return memClients[id].inside;
}
jmp_buf *gMemGetJmpBuf(CmnClientId id)
{
return &memClients[id].jmpbuf;
}
void gMemSetInside(CmnClientId id, int inside)
{
memClients[id].inside = inside;
}
#if CMN_LOG_INTERNAL & CMN_LOG_MEMORY
MemPtr gMemAlloc(CmnClientId id, MemSize size, const char *filename, int lineno)
#else
MemPtr gMemAlloc(CmnClientId id, MemSize size)
#endif
{
void *p = gMemGcMalloc( id, size);
#if CMN_LOG_INTERNAL & CMN_LOG_MEMORY
{
const char *s = strrchr(filename, '\\');
gMemPrintUsage(id,filename,lineno);
if (s == NULL)
{
s = filename;
}
else
{
++s;
}
CMN_LOG_I(("MEM: + %#08x %6d %6d %6d %s (%d)\n",
p, ++memClients[id].lognum, size, id, s, lineno));
}
#endif
if ((p == NULL) && memClients[id].inside)
{
longjmp( memClients[id].jmpbuf, 1);
}
return p;
}
#if CMN_LOG_INTERNAL & CMN_LOG_MEMORY
void gMemFree(CmnClientId id, MemPtr p, const char *filename, int lineno)
#else
void gMemFree(CmnClientId id, MemPtr p)
#endif
{
#if CMN_LOG_INTERNAL & CMN_LOG_MEMORY
if (p != NULL)
{
const char *s = strrchr(filename, '\\');
if (s == NULL)
{
s = filename;
}
else
{
s += 1;
}
CMN_LOG_I(("MEM: - %#08x %6d %6d %s (%d)\n",
p, ++memClients[id].lognum, id, s, lineno));
}
#endif
gMemFreeChunk(id, p);
#if CMN_LOG_INTERNAL & CMN_LOG_MEMORY
gMemPrintUsage(id,filename,lineno);
#endif
}
void gMemTerminate(CmnClientId id)
{
gMemGc(id);
}
static short listIdx(SIZE_L n)
{
short i;
for (i = 0; i < NUM_FREE_LISTS - 1 && maxsizes[i] <= n; i++)
;
return i;
}
short gMemInit(CmnClientId id, MemPtr mem, MemSize memsize)
{
MemChunk *p;
SIZE_L size;
short i;
if (memClients[id].isInitiated)
{
return 0;
}
memset( &memClients[id], 0, sizeof(memClients[id]));
memsize &= ~MALLOC_ALIGN_MASK;
if ((mem == NULL) || (memsize < MINBLOCKSIZE) || (memsize > (1 << 17)))
{
unsigned j;
CMN_LOG_I(("%s(%d): Failed to initialize internal memory pool.\n",
__FILE__, __LINE__));
j = 1 << 17;
if (j == 0 || memsize > j)
{
CMN_LOG_I(("%s(%d): Internal memory pool larger than what can "
"be handled (%u).\n", __FILE__, __LINE__, j));
}
return -1;
}
memClients[id].base = mem;
for (i = 0; i < NUM_FREE_LISTS; i++)
{
p = (MemChunk *)((Ptr)memClients[id].base + i * MINCHUNKSIZE);
set_hd1(p, 0);
set_hd2(p, (MINCHUNKSIZE >> 1) | 0x01);
p->fwd = ptr2offset(p);
p->bck = ptr2offset(p);
memClients[id].freelists[i] = p;
}
memClients[id].first = (MemChunk *)((Ptr)memClients[id].base +
NUM_FREE_LISTS * MINCHUNKSIZE);
set_hd1(memClients[id].first, MINCHUNKSIZE >> 1);
size = memsize - ((NUM_FREE_LISTS + 1) * MINCHUNKSIZE);
set_hd2(memClients[id].first, size >> 1);
add_to_list(memClients[id].freelists[listIdx(size)], memClients[id].first);
memClients[id].last = (MemChunk *)(memClients[id].base + memsize - MINCHUNKSIZE);
set_hd1(memClients[id].last, size >> 1);
set_hd2(memClients[id].last, (MINCHUNKSIZE >> 1) | 0x01);
memClients[id].isInitiated = 1;
return 0;
}
MemPtr gMemMalloc(CmnClientId id, MemSize size)
{
MemChunk *p = 0;
MemChunk *ptmp = 0;
SIZE_L nb;
SIZE_L sz = 250000;
SIZE_L remsize;
short i;
#if CMN_LOG_INTERNAL & CMN_LOG_MEMORY
int tmp_traverse_count = 0;
#endif
nb = request2size(size);
for (i = listIdx(nb); i < NUM_FREE_LISTS; i++)
{
MemChunk *freelist = memClients[id].freelists[i];
for (ptmp = forward(freelist); ptmp != NULL && ptmp != freelist;
ptmp = forward(ptmp))
{
SIZE_L tmpsz = chunksize(ptmp);
#if CMN_LOG_INTERNAL & CMN_LOG_MEMORY
++tmp_traverse_count;
#endif
if (tmpsz == nb)
{
p = ptmp;
sz = tmpsz;
goto found;
}
else if (tmpsz > nb)
{
if (tmpsz < sz)
{
p = ptmp;
sz = tmpsz;
}
}
}
if (p != 0)
{
goto found;
}
}
return 0;
found:
remove_from_list(p);
remsize = sz - nb;
if (remsize >= MINCHUNKSIZE)
{
MemChunk *q;
MemChunk *next;
MemChunk *l;
sz = nb;
q = (MemChunk *)((Ptr)p + sz);
set_hd2(q, remsize >> 1);
set_hd1(q, nb >> 1);
next = nextchunk(q);
set_prevsize(next, remsize);
l = memClients[id].freelists[listIdx(remsize)];
add_to_list(l, q);
}
set_hd2(p, (sz >> 1) | 0x01);
clear_gcbit(p);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -