Optimized the implementation of BlockHeap

This commit is contained in:
Vincent Wei
2021-03-28 19:36:05 +08:00
parent 6a5c9ba048
commit c089adf2b7
3 changed files with 112 additions and 94 deletions

View File

@@ -581,35 +581,14 @@ enum {
* @{
*/
struct _BLOCKHEAP;
/**
* MiniGUI's private block data heap.
*
* \sa InitBlockDataHeap, DestroyBlockDataHeap
*/
typedef struct _BLOCKHEAP
{
#ifdef _MGRM_THREADS
pthread_mutex_t lock;
#endif
/**
* Size of one block element.
*/
size_t bd_size;
/**
* Size of the heap in blocks.
*/
size_t heap_size;
/**
* The first free element in the heap.
*/
size_t free;
/**
* Pointer to the pre-allocated heap.
*/
void* heap;
size_t nr_alloc;
} BLOCKHEAP;
typedef struct _BLOCKHEAP BLOCKHEAP;
/**
* \var typedef BLOCKHEAP* PBLOCKHEAP
@@ -620,7 +599,7 @@ typedef struct _BLOCKHEAP
typedef BLOCKHEAP* PBLOCKHEAP;
/**
* \fn void InitBlockDataHeap (PBLOCKHEAP heap, \
* \fn BOOL InitBlockDataHeap (PBLOCKHEAP heap,
size_t bd_size, size_t heap_size)
* \brief Initializes a private block data heap.
*
@@ -633,15 +612,14 @@ typedef BLOCKHEAP* PBLOCKHEAP;
* \param bd_size The size of one block in bytes.
* \param heap_size The size of the heap in blocks.
*
* \return \a heap->heap will contains a valid pointer on success,
* NULL on error.
* \return TRUE on success, FALSE on error.
*
* \note This function does not return anything. You should check the \a heap
* field of the \a heap structure.
*
* \sa BLOCKHEAP
*/
MG_EXPORT extern void InitBlockDataHeap (PBLOCKHEAP heap,
MG_EXPORT BOOL InitBlockDataHeap (PBLOCKHEAP heap,
size_t bd_size, size_t heap_size);
/**
@@ -659,7 +637,7 @@ MG_EXPORT extern void InitBlockDataHeap (PBLOCKHEAP heap,
* \sa InitBlockDataHeap, BlockDataFree
*/
MG_EXPORT extern void* BlockDataAlloc (PBLOCKHEAP heap);
MG_EXPORT void* BlockDataAlloc (PBLOCKHEAP heap);
/**
* \fn void BlockDataFree (PBLOCKHEAP heap, void* data)
@@ -674,7 +652,7 @@ MG_EXPORT extern void* BlockDataAlloc (PBLOCKHEAP heap);
*
* \sa InitBlockDataHeap, BlockDataAlloc
*/
MG_EXPORT extern void BlockDataFree (PBLOCKHEAP heap, void* data);
MG_EXPORT void BlockDataFree (PBLOCKHEAP heap, void* data);
/**
* \fn void DestroyBlockDataHeap (PBLOCKHEAP heap)
@@ -684,7 +662,7 @@ MG_EXPORT extern void BlockDataFree (PBLOCKHEAP heap, void* data);
*
* \sa InitBlockDataHeap, BLOCKHEAP
*/
MG_EXPORT extern void DestroyBlockDataHeap (PBLOCKHEAP heap);
MG_EXPORT void DestroyBlockDataHeap (PBLOCKHEAP heap);
/** @} end of block_heap_fns */

View File

@@ -52,21 +52,28 @@
#ifndef GUI_BLOCKHEAP_H
#define GUI_BLOCKHEAP_H
#define BDS_FREE 0x0000
#define BDS_SPECIAL 0x0001
#define BDS_USED 0x0002
#ifndef _MGUI_GDI_H /* included in include/gdi.h */
typedef struct tagBLOCKHEAP {
struct _BLOCKHEAP {
#ifdef _MGRM_THREADS
pthread_mutex_t lock;
#endif
size_t bd_size;
size_t heap_size;
int free;
void* heap;
} BLOCKHEAP;
/* Size of one block element. */
size_t sz_block;
/* Size of the heap in blocks. */
size_t sz_heap;
/* The first free element in the heap. */
size_t sz_usage_bmp;
/* The number of blocks extra allocated. */
size_t nr_alloc;
/* Pointer to the pre-allocated heap. */
unsigned char* heap;
/* Pointer to the usage bitmap. */
unsigned char* usage_bmp;
};
#ifndef _MGUI_GDI_H /* included in include/gdi.h */
typedef struct _BLOCKHEAP BLOCKHEAP;
typedef BLOCKHEAP* PBLOCKHEAP;
#ifdef __cplusplus

View File

@@ -59,96 +59,93 @@
#include "common.h"
#include "minigui.h"
#include "gdi.h"
#include "constants.h"
#include "blockheap.h"
#include "misc.h"
void InitBlockDataHeap (PBLOCKHEAP heap, size_t bd_size, size_t heap_size)
BOOL InitBlockDataHeap (PBLOCKHEAP heap, size_t sz_block, size_t sz_heap)
{
#ifdef _MGRM_THREADS
pthread_mutex_init (&heap->lock, NULL);
#endif
heap->heap = NULL;
heap->bd_size = bd_size + sizeof (DWORD);
heap->heap_size = heap_size;
heap->free = 0;
heap->sz_usage_bmp = (sz_heap + 7) >> 3;
heap->sz_block = ROUND_TO_MULTIPLE (sz_block, SIZEOF_PTR);
heap->sz_heap = heap->sz_usage_bmp << 3;
if (heap->sz_heap == 0 || heap->sz_block == 0)
return FALSE;
if ((heap->heap = calloc (heap->sz_heap, heap->sz_block)) == NULL)
return FALSE;
if ((heap->usage_bmp = calloc (heap->sz_usage_bmp, sizeof (char))) == NULL) {
free (heap->heap);
return FALSE;
}
heap->nr_alloc = 0;
memset (heap->usage_bmp, 0xFF, heap->sz_usage_bmp);
return TRUE;
}
extern BLOCKHEAP __mg_FreeClipRectList;
void* BlockDataAlloc (PBLOCKHEAP heap)
{
size_t i;
char* block_data = NULL;
int free_slot;
unsigned char* block_data = NULL;
#ifdef _MGRM_THREADS
pthread_mutex_lock (&heap->lock);
#endif
if (heap->heap == NULL) {
if (!(heap->heap = calloc (heap->heap_size, heap->bd_size)))
goto ret;
heap->free = 0;
}
free_slot = __mg_lookfor_unused_slot (heap->usage_bmp, heap->sz_usage_bmp, 1);
if (free_slot >= 0) {
block_data = heap->heap + heap->sz_block * free_slot;
_DBG_PRINTF ("Allocated one block in the block heap: %p (%d)\n",
heap, free_slot);
block_data = (char*) heap->heap + heap->bd_size*heap->free;
for (i = heap->free; i < heap->heap_size; i++) {
if (*((DWORD*)block_data) == BDS_FREE) {
heap->free = i + 1;
*((DWORD*)block_data) = BDS_USED;
goto ret;
}
block_data += heap->bd_size;
}
#if 1
if (!(block_data = calloc (1, heap->bd_size)))
goto ret;
#else
if (!(block_data = mg_slice_alloc0 (heap->bd_size)))
goto ret;
#if 0
if (!mgIsServer && heap == &__mg_FreeClipRectList && free_slot == 5)
assert (0);
#endif
goto ret;
}
if ((block_data = calloc (1, heap->sz_block)) == NULL)
goto ret;
heap->nr_alloc++;
*((DWORD*)block_data) = BDS_SPECIAL;
ret:
#ifdef _MGRM_THREADS
pthread_mutex_unlock (&heap->lock);
#endif
if (block_data)
return block_data + sizeof (DWORD);
return NULL;
return block_data;
}
void BlockDataFree (PBLOCKHEAP heap, void* data)
{
size_t i;
char* block_data;
unsigned char* block_data = data;
#ifdef _MGRM_THREADS
pthread_mutex_lock (&heap->lock);
#endif
block_data = (char*) data - sizeof (DWORD);
if (*((DWORD*)block_data) == BDS_SPECIAL) {
#if 1
if (block_data < heap->heap ||
block_data > (heap->heap + heap->sz_block * heap->sz_heap)) {
free (block_data);
#else
mg_slice_free (heap->bd_size, block_data);
heap->nr_alloc--;
#endif
}
else if (*((DWORD*)block_data) == BDS_USED) {
*((DWORD*)block_data) = BDS_FREE;
else {
int slot;
slot = (block_data - heap->heap) / heap->sz_block;
__mg_slot_clear_use (heap->usage_bmp, slot);
i = (block_data - (char*)heap->heap)/heap->bd_size;
if (heap->free > i)
heap->free = i;
_DBG_PRINTF ("Freed one block in the block heap: %p (%d)\n",
heap, slot);
}
#ifdef _MGRM_THREADS
@@ -158,9 +155,45 @@ void BlockDataFree (PBLOCKHEAP heap, void* data)
void DestroyBlockDataHeap (PBLOCKHEAP heap)
{
int nr_free_slots;
if (heap->nr_alloc > 0) {
_WRN_PRINTF ("There are still not freed extra blocks in the block heap: %p (%zu)\n",
heap, heap->nr_alloc);
}
nr_free_slots = __mg_get_nr_idle_slots (heap->usage_bmp, heap->sz_usage_bmp);
if (nr_free_slots != heap->sz_heap) {
_WRN_PRINTF ("There are still not freed blocks in the block heap: %p (%zu)\n",
heap, heap->sz_heap - nr_free_slots);
#ifdef _DEBUG
{
unsigned char* bitmap = heap->usage_bmp;
int slot = 0;
int i, j;
for (i = 0; i < heap->sz_usage_bmp; i++) {
for (j = 0; j < 8; j++) {
if (!(*bitmap & (0x80 >> j))) {
_WRN_PRINTF ("Still used slot in the block heap: %p (%d)\n",
heap, slot);
}
slot++;
}
bitmap++;
}
}
assert (0);
#endif
}
free (heap->heap);
free (heap->usage_bmp);
#ifdef _MGRM_THREADS
pthread_mutex_destroy (&heap->lock);
#endif
free (heap->heap);
}