📄 heap.c
字号:
/* ============================================================ */
/* File: HEAP.C */
/* */
/* Copyright (C) 2001, Daniel W. Lewis and Prentice-Hall */
/* */
/* Purpose: Library routines for managing heaps. */
/* See file LIBEPC.H for function descriptions. */
/* */
/* Designed for use with the DJGPP port of the GNU C/C++ */
/* protected mode 386 compiler. */
/* */
/* Modification History: */
/* */
/* ============================================================ */
#include "libepc.h"
extern BYTE8 heap_frst __asm__("heap_frst") ;
/* Set the following defines to 1 if these public functions are desired: */
#define LARGEST_FREE 0
#define TOTAL_FREE 0
#define BEGIN_CRITICAL PUSHF; CLI
#define END_CRITICAL POPF
#define SMALLEST_BLOCK 32
typedef void REGION ;
typedef struct TAG
{
char type ;
unsigned size ;
} __attribute__((packed)) TAG ;
typedef struct FREE
{
REGION * prev ;
REGION * next ;
} __attribute__((packed)) FREE ;
#define PREV(base) ((FREE *) (base))->prev
#define NEXT(base) ((FREE *) (base))->next
PRIVATE REGION * free_list = NULL ;
PRIVATE TAG * Btm_Tag(REGION *) ;
PRIVATE TAG * Top_Tag(REGION *) ;
PRIVATE REGION * Prev_Region(REGION *) ;
PRIVATE REGION * Next_Region(REGION *) ;
PRIVATE REGION * Next_Free(REGION *) ;
PRIVATE REGION * Allocate(REGION *, unsigned) ;
PRIVATE void Ins_Free(REGION *, REGION *) ;
PRIVATE void Del_Free(REGION *) ;
PRIVATE void Combine(REGION *, REGION *) ;
PRIVATE void Init_Tags(REGION *, unsigned, char) ;
PRIVATE void Init_Heap(void) ;
/* -------------------------------------------------------------------- */
/* Public functions */
/* -------------------------------------------------------------------- */
void *malloc(long unsigned int bytes)
{
REGION *newblock, *end ;
Init_Heap() ;
if (!free_list) return NULL ;
if (bytes < SMALLEST_BLOCK) bytes = SMALLEST_BLOCK ;
end = free_list ;
newblock = NULL ;
BEGIN_CRITICAL ;
do /* First-Fit */
{
if (Btm_Tag(free_list)->size >= bytes)
{
newblock = Allocate(free_list, bytes) ;
}
else free_list = Next_Free(free_list) ;
} while (!newblock && free_list != end) ;
END_CRITICAL ;
return newblock ;
}
void free(REGION *newhole)
{
register TAG *btm = Btm_Tag(newhole) ;
register TAG *top = Top_Tag(newhole) ;
if (btm->type != 'A' || top->size != btm->size) return ;
BEGIN_CRITICAL ;
btm->type = 'F';
top->type = 'F' ;
if (!free_list)
{
free_list = newhole ;
NEXT(newhole) = newhole ;
PREV(newhole) = newhole ;
}
else
{
BOOL changed = FALSE ;
REGION *adjacent ;
adjacent = Next_Region(newhole) ;
if (adjacent != NULL && Btm_Tag(adjacent)->type == 'F')
{
Combine(newhole, adjacent) ;
Ins_Free(newhole, adjacent) ;
Del_Free(adjacent) ;
changed = TRUE ;
}
adjacent = Prev_Region(newhole) ;
if (adjacent != NULL && Btm_Tag(adjacent)->type == 'F')
{
Combine(adjacent, newhole) ;
if (changed) Del_Free(newhole) ;
changed = TRUE ;
}
if (!changed) Ins_Free(newhole, free_list) ;
}
END_CRITICAL ;
}
#if LARGEST_FREE==1
unsigned Largest_Free(void)
{
unsigned largest ;
REGION *end ;
Init_Heap() ;
if (!free_list) return 0 ;
largest = 0 ;
end = free_list ;
BEGIN_CRITICAL ;
do
{
unsigned size = Btm_Tag(free_list)->size ;
if (size > largest) largest = size ;
free_list = Next_Free(free_list) ;
} while (free_list != end) ;
END_CRITICAL ;
return largest ;
}
#endif
#if TOTAL_FREE==1
unsigned Total_Free(void)
{
unsigned total ;
REGION *end ;
Init_Heap() ;
if (!free_list) return 0 ;
total = 0 ;
end = free_list ;
BEGIN_CRITICAL ;
do
{
total += Btm_Tag(free_list)->size ;
free_list = Next_Free(free_list) ;
} while (free_list != end) ;
END_CRITICAL ;
return total ;
}
#endif
/* -------------------------------------------------------------------- */
/* Private functions */
/* -------------------------------------------------------------------- */
PRIVATE TAG *Btm_Tag(REGION *base)
{
return (TAG *) ((BYTE8 *) base - sizeof(TAG)) ;
}
PRIVATE TAG *Top_Tag(REGION *base)
{
return (TAG *) ((BYTE8 *) base + Btm_Tag(base)->size) ;
}
PRIVATE void Init_Tags(REGION *r, unsigned bytes, char type)
{
register TAG *tag ;
tag = Btm_Tag(r) ;
tag->type = type ;
tag->size = bytes ;
tag = Top_Tag(r) ;
tag->type = type ;
tag->size = bytes ;
}
PRIVATE REGION *Prev_Region(REGION *base)
{
register TAG *prev = Btm_Tag(base) - 1 ;
if (prev->type == 'B') return NULL ;
return (REGION *) ((BYTE8 *) prev - prev->size) ;
}
PRIVATE REGION *Next_Region(REGION *base)
{
register TAG *next = Top_Tag(base) + 1 ;
if (next->type == 'T') return NULL ;
return (REGION *) ((BYTE8 *) next + sizeof(TAG)) ;
}
PRIVATE REGION *Next_Free(REGION *base)
{
return base ? NEXT(base) : NULL ;
}
PRIVATE REGION *Allocate(REGION *hole, unsigned bytes)
{
unsigned hole_size = Btm_Tag(hole)->size ;
if ((hole_size - bytes) <= SMALLEST_BLOCK)
{
Init_Tags(hole, hole_size, 'A') ;
Del_Free(hole) ;
return hole ;
}
free_list = hole + bytes + 2 * sizeof(TAG) ;
hole_size -= bytes + 2 * sizeof(TAG) ;
Init_Tags(free_list, hole_size, 'F') ;
Ins_Free(free_list, hole) ;
Init_Tags(hole, bytes, 'A') ;
Del_Free(hole) ;
return hole ;
}
PRIVATE void Combine(REGION *a, REGION *b)
{
unsigned size = Btm_Tag(a)->size + Btm_Tag(b)->size + 2*sizeof(TAG) ;
Btm_Tag(a)->size = size ;
Top_Tag(a)->size = size ;
}
PRIVATE void Ins_Free(REGION *this, REGION *prev)
{
register REGION *next = NEXT(prev) ;
PREV(this) = prev ;
NEXT(this) = next ;
PREV(next) = this ;
NEXT(prev) = this ;
}
PRIVATE void Del_Free(REGION *this)
{
REGION *prev = PREV(this) ;
REGION *next = NEXT(this) ;
if (prev == next && prev == this)
{
free_list = NULL ; /* Only one in the list */
}
else
{
if (free_list == this) free_list = prev ;
NEXT(prev) = next ;
PREV(next) = prev ;
}
NEXT(this) = PREV(this) = NULL ;
}
PRIVATE void Init_Heap(void)
{
# define EXT_MEM_START ((BYTE8 *) 0x100000)
# define RSVD_MEM_START ((BYTE8 *) 0x0A0000)
# define RSVD_MEM_SIZE (EXT_MEM_START - RSVD_MEM_START)
static BOOL initialized = FALSE ;
BYTE8 *top = (BYTE8 *) LastMemoryAddress() + 1 - sizeof(TAG) ;
BYTE8 *btm = &heap_frst + sizeof(TAG) ;
unsigned bytes ;
REGION *r ;
if (initialized) return ;
free_list = NULL ;
/* Sanity check - Is there anything left to use? */
bytes = SMALLEST_BLOCK + 2 * sizeof(TAG) ;
if (RSVD_MEM_START <= btm + bytes) btm = EXT_MEM_START + sizeof(TAG) ;
if (top < btm + bytes) return ;
/* Mark top and bottom of entire heap */
((TAG *) btm - 1)->type = 'B' ;
((TAG *) top)->type = 'T' ;
/* Create initial free block (ignore reserved memory) */
r = (REGION *) (btm + sizeof(TAG)) ;
Init_Tags(r, (top - btm) - 2 * sizeof(TAG), 'A') ;
/* Cut a hole for reserved memory if necessary */
if (btm < RSVD_MEM_START && top >= EXT_MEM_START)
{
bytes = (RSVD_MEM_START - (BYTE8 *) r) - 2 * sizeof(TAG) ;
Init_Tags(r, bytes, 'A') ;
Init_Tags(RSVD_MEM_START, RSVD_MEM_SIZE, 'A') ;
r = (REGION *) (EXT_MEM_START + 2 * sizeof(TAG)) ;
bytes = (top - (BYTE8 *) r) - sizeof(TAG) ;
Init_Tags(r, bytes, 'A') ;
free(r) ;
}
free(btm + sizeof(TAG)) ;
initialized = TRUE ;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -