#define PFEM_MEMORY_STATS 1
#define PFEM_DIAGNOSTICS 0
#define PFEM_DEBUG 0
#define MINIMIZE_RANGES 1
#define APPLE_OS_X_IMPLEMENTATION 1
#include "config.h"
#include "system.h"
#include <stddef.h>
#include <stdlib.h>
#if APPLE_OS_X_IMPLEMENTATION
#include <mach/mach.h>
#include <mach/mach_error.h>
#endif
#include "pfe-mem.h"
#define PFEM_FRAG_BLOCK_SIZE (64 * 1024)
#define PFEM_MIN_WHOLE_BLOCK_SIZE (64 * 1024)
struct pfem_range {
unsigned long start_addr;
unsigned long end_addr;
};
typedef struct pfem_range pfem_range;
struct pfem_fragment {
size_t size;
struct pfem_fragment *next;
};
typedef struct pfem_fragment pfem_fragment;
#define PFEM_FRAGMENT_OVERHEAD (sizeof (size_t))
struct pfem_block_info {
void *addr;
size_t size;
size_t free_bytes;
size_t largest_free_fragment_size;
pfem_fragment *free_fragments;
struct pfem_block_info *next;
struct pfem_block_info *next_avail;
};
typedef struct pfem_block_info pfem_block_info;
#define PFEM_MAX_FRAGMENT_SIZE (PFEM_FRAG_BLOCK_SIZE \
- (PFEM_FRAGMENT_OVERHEAD \
+ sizeof (pfem_block_info)))
#define PFEM_INVALID_PTR ((void *) -1)
#define PFEM_IS_WHOLE_BLOCK(x) ((x)->free_fragments == PFEM_INVALID_PTR)
static pfem_block_info *pfem_block_list = NULL;
static pfem_block_info *pfem_block_list_last = NULL;
static pfem_block_info *pfem_whole_block_avail_list = NULL;
static pfem_block_info *pfem_frag_block_avail_list = NULL;
#define MAX_FRAGMENT_SIZE_VARIANCE_BEFORE_SPLIT 12
#define PFEM_INITIAL_RANGE_TABLE_SIZE 64
#define PFEM_RANGE_TABLE_INCR 64
#define PFEM_MIN_RECOVERABLE_FRAGMENT_SIZE 1024
static pfem_range *pfem_range_table = NULL;
static int pfem_range_table_size = 0;
static int pfem_range_table_nitems = 0;
static int pfem_initialization_complete = 0;
#if PFEM_MEMORY_STATS
extern int pfe_display_memory_stats;
static size_t pfem_malloc_total_size = 0;
static int pfem_mallocs = 0;
static int pfem_callocs = 0;
static int pfem_reallocs = 0;
static int pfem_frees = 0;
#endif
static void pfem_add_block_to_range_table PARAMS ((void *, size_t));
static void pfem_add_block_to_block_list PARAMS ((pfem_block_info *));
static void * pfem_alloc_block PARAMS ((size_t));
static void * pfem_alloc_fragment PARAMS ((size_t));
static void * pfem_alloc_whole_block PARAMS ((size_t));
static pfem_block_info * pfem_find_containing_block PARAMS ((void *));
static pfem_block_info * pfem_set_up_frag_block PARAMS ((void *, size_t));
#if PFEM_MEMORY_STATS
static void pfem_memory_statistics PARAMS ((void));
#endif
void
pfem_init (void)
{
void *initial_block;
pfem_block_info *block_info;
initial_block = pfem_alloc_block (PFEM_FRAG_BLOCK_SIZE);
block_info = pfem_set_up_frag_block (initial_block, PFEM_FRAG_BLOCK_SIZE);
pfem_add_block_to_block_list (block_info);
pfem_frag_block_avail_list = block_info;
pfem_range_table_size = PFEM_INITIAL_RANGE_TABLE_SIZE;
pfem_range_table = (pfem_range *)
pfem_malloc (sizeof (pfem_range)
* pfem_range_table_size);
pfem_add_block_to_range_table (initial_block, PFEM_FRAG_BLOCK_SIZE);
pfem_initialization_complete = 1;
}
#if PFEM_MEMORY_STATS
void
pfem_memory_statistics (void)
{
int range_idx;
int block_idx;
size_t free_fragments_in_block;
size_t total_free_framents;
size_t total_free_bytes;
pfem_block_info *block;
pfem_fragment *fragment;
pfem_fragment *last_fragment;
size_t free_frament_bytes;
size_t recoverable_fragment_bytes;
printf ("\npfem_term:\n");
printf ("range table:\n");
for (range_idx = 0; range_idx < pfem_range_table_nitems; range_idx++)
printf (" range [%d]: 0x%x - 0x%x; size = %d (0x%x)\n",
range_idx + 1,
pfem_range_table[range_idx].start_addr,
pfem_range_table[range_idx].end_addr,
pfem_range_table[range_idx].end_addr
- pfem_range_table[range_idx].start_addr,
pfem_range_table[range_idx].end_addr
- pfem_range_table[range_idx].start_addr);
printf ("\npfem_whole_block_avail_list:\n");
block_idx = 0;
for (block = pfem_whole_block_avail_list; block != NULL; block = block->next_avail)
{
block_idx++;
printf (" free whole block [%d]: addr = 0x%x; size = %d (0x%x)\n",
block_idx, block->addr, block->size, block->size);
}
printf ("\npfem_frag_block_avail_list:\n");
block_idx = 0;
total_free_bytes = 0;
total_free_framents = 0;
recoverable_fragment_bytes = 0;
for (block = pfem_frag_block_avail_list; block != NULL; block = block->next_avail)
{
block_idx++;
total_free_bytes += block->free_bytes;
free_frament_bytes = 0;
free_fragments_in_block = 0;
last_fragment = NULL;
for (fragment = block->free_fragments; fragment != NULL; fragment = fragment->next)
{
free_frament_bytes += fragment->size;
free_fragments_in_block++;
last_fragment = fragment;
}
if ((last_fragment != NULL)
&& (((unsigned long) last_fragment + last_fragment->size)
== ((unsigned long) block->addr + block->size))
&& (last_fragment->size > 1023))
recoverable_fragment_bytes += last_fragment->size;
total_free_framents += free_fragments_in_block;
printf (" fragment block [%d]: addr = 0x%x; size = %d; "
"free_bytes = %d; free_fragments_in_block = %d\n",
block_idx, block->addr, block->size, block->free_bytes,
free_fragments_in_block);
if (free_frament_bytes != block->free_bytes)
printf (" free_bytes != free_frament_bytes (%d)\n", free_frament_bytes);
}
printf (" total_free_bytes = %d\n", total_free_bytes);
printf (" total_free_framents = %d\n", total_free_framents);
printf (" recoverable_fragment_bytes = %d\n", recoverable_fragment_bytes);
}
#endif
void
pfem_term (void)
{
#if PFEM_MEMORY_STATS
if (pfe_display_memory_stats)
pfem_memory_statistics ();
#endif
}
void
pfem_add_block_to_block_list (new_block_info)
pfem_block_info *new_block_info;
{
pfem_block_info *block;
pfem_block_info *last_block;
if (pfem_block_list_last == NULL)
{
pfem_block_list = new_block_info;
pfem_block_list_last = new_block_info;
return;
}
if ((unsigned long) new_block_info->addr > (unsigned long) pfem_block_list_last->addr)
{
pfem_block_list_last->next = new_block_info;
pfem_block_list_last = new_block_info;
return;
}
if (pfem_block_list == NULL)
{
printf ("pfem_add_block_to_block_list: pfem_block_list == NULL.\n");
exit (1);
}
if ((unsigned long) new_block_info->addr < (unsigned long)pfem_block_list->addr)
{
new_block_info->next = pfem_block_list->next;
pfem_block_list = new_block_info;
return;
}
#if PFEM_DEBUG
printf ("pfem_add_block_to_block_list: new block goes into middle of block list.\n");
#endif
last_block = pfem_block_list;
for (block = pfem_block_list->next; block != NULL; block = block->next)
{
if ((unsigned long) new_block_info->addr < (unsigned long)block->addr)
{
last_block->next = new_block_info;
new_block_info->next = block;
return;
}
last_block = block;
}
#if PFEM_DEBUG
printf ("pfem_add_block_to_block_list: we should not get here.\n");
#endif
}
pfem_block_info *
pfem_find_containing_block (addr)
void *addr;
{
pfem_block_info *block;
pfem_block_info *last_block = NULL;
for (block = pfem_block_list; block != NULL; block = block->next)
{
if ((unsigned long) addr < (unsigned long)block->addr)
break;
last_block = block;
}
if (last_block == NULL)
return NULL;
if ((unsigned long) addr < ((unsigned long) last_block->addr
+ last_block->size))
return last_block;
return NULL;
}
void
pfem_add_block_to_range_table (block_addr, size)
void *block_addr;
size_t size;
{
int range_idx;
unsigned long start_addr = (unsigned long)block_addr;
unsigned long end_addr = start_addr + size;
if (pfem_range_table_nitems >= pfem_range_table_size)
{
pfem_range_table_size += PFEM_RANGE_TABLE_INCR;
pfem_range_table = (pfem_range *)
pfem_realloc (pfem_range_table,
sizeof (pfem_range)
* pfem_range_table_size);
}
for (range_idx = 0; range_idx < pfem_range_table_nitems; range_idx++)
if (start_addr < pfem_range_table[range_idx].start_addr)
if (end_addr == pfem_range_table[range_idx].start_addr)
{
pfem_range_table[range_idx].start_addr = start_addr;
return;
}
else
{
memmove (&pfem_range_table[range_idx + 1],
&pfem_range_table[range_idx],
sizeof (pfem_range)
* (pfem_range_table_nitems - range_idx));
break;
}
else if (start_addr == pfem_range_table[range_idx].end_addr)
{
pfem_range_table[range_idx].end_addr = end_addr;
return;
}
pfem_range_table[range_idx].start_addr = start_addr;
pfem_range_table[range_idx].end_addr = end_addr;
pfem_range_table_nitems++;
}
#if MINIMIZE_RANGES
void
pfem_remove_block_from_range_table (block_addr, size)
void *block_addr;
size_t size;
{
int range_idx;
unsigned long start_addr = (unsigned long)block_addr;
unsigned long end_addr = start_addr + size;
for (range_idx = 0; range_idx < pfem_range_table_nitems; range_idx++)
if (pfem_range_table[range_idx].end_addr >= start_addr)
{
if (start_addr == pfem_range_table[range_idx].start_addr)
{
if (end_addr == pfem_range_table[range_idx].end_addr)
{
pfem_range_table_nitems--;
memmove (&pfem_range_table[range_idx],
&pfem_range_table[range_idx + 1],
sizeof (pfem_range)
* (pfem_range_table_nitems - range_idx));
}
else
{
pfem_range_table[range_idx].start_addr = end_addr;
}
}
else
{
if (end_addr == pfem_range_table[range_idx].end_addr)
{
pfem_range_table[range_idx].end_addr = start_addr;
}
else
{
unsigned long new_start_addr = end_addr;
unsigned long new_end_addr = pfem_range_table[range_idx].end_addr;
pfem_range_table[range_idx].end_addr = start_addr;
if (pfem_range_table_nitems >= pfem_range_table_size)
{
pfem_range_table_size += 2;
pfem_range_table = (pfem_range *)
pfem_realloc (pfem_range_table,
sizeof (pfem_range)
* pfem_range_table_size);
}
memmove (&pfem_range_table[range_idx + 2],
&pfem_range_table[range_idx + 1],
sizeof (pfem_range)
* (pfem_range_table_nitems - range_idx));
pfem_range_table_nitems++;
range_idx++;
pfem_range_table[range_idx].start_addr = new_start_addr;
pfem_range_table[range_idx].end_addr = new_end_addr;
}
}
return;
}
}
#endif
void *
pfem_alloc_block (size)
size_t size;
{
char *data;
#if APPLE_OS_X_IMPLEMENTATION
kern_return_t err;
err = vm_allocate ((vm_map_t) mach_task_self (), (vm_address_t) &data,
size, TRUE);
if (err != KERN_SUCCESS)
data = NULL;
#else
data = xmalloc (size);
#endif
if (data == NULL)
{
printf ("pfem_alloc_block: system allocator failure.\n");
exit (1);
}
if (pfem_initialization_complete)
pfem_add_block_to_range_table (data, size);
#if PFEM_DIAGNOSTICS
{
int alignment;
unsigned long data2 = (unsigned long) data;
for (alignment = 0; (data2 & 1) == 0; alignment++)
data2 >>= 1;
printf ("pfem_alloc_block: allocated block at 0x%x of size %d"
" (2**%d alignment)\n",
data, size, alignment);
}
#endif
return data;
}
pfem_block_info *pfem_set_up_frag_block (block_addr, size)
void *block_addr;
size_t size;
{
pfem_fragment *fragment;
pfem_block_info *block_info;
fragment = (pfem_fragment *) block_addr;
fragment->size = sizeof (pfem_block_info);
block_info = (pfem_block_info *) &fragment->next;
fragment = (pfem_fragment *) ((unsigned long) block_addr
+ sizeof (pfem_block_info)
+ PFEM_FRAGMENT_OVERHEAD);
fragment->size = size - (sizeof (pfem_block_info)
+ PFEM_FRAGMENT_OVERHEAD);
fragment->next = NULL;
block_info->addr = block_addr;
block_info->size = size;
block_info->next = NULL;
block_info->next_avail = NULL;
block_info->free_fragments = fragment;
block_info->free_bytes = fragment->size;
block_info->largest_free_fragment_size = fragment->size;
return block_info;
}
void *
pfem_alloc_whole_block (size)
size_t size;
{
pfem_block_info *block_info;
pfem_block_info *last_block_info;
pfem_block_info *best_block_info = NULL;
size_t bytes_needed;
void *block_addr;
#if PFEM_DEBUG
printf ("pfem_alloc_whole_block: request size = %d\n", size);
#endif
bytes_needed = (size + 1023) & 0xFFFFFC00;
#if PFEM_DEBUG
printf (" pfem_alloc_whole_block: bytes_needed = %d\n", bytes_needed);
#endif
block_info = pfem_whole_block_avail_list;
last_block_info = NULL;
while (block_info != NULL)
{
if (block_info->size == bytes_needed)
{
if (last_block_info == NULL)
pfem_whole_block_avail_list = block_info->next_avail;
else
last_block_info->next_avail = block_info->next_avail;
block_info->free_bytes = 0;
#if PFEM_DEBUG
printf (" pfem_alloc_whole_block: allocated free block at 0x%x\n",
block_info->addr);
#endif
return block_info->addr;
}
else if ((block_info->size > bytes_needed))
{
if ((best_block_info == NULL)
|| (block_info->size < best_block_info->size))
best_block_info = block_info;
}
last_block_info = block_info;
block_info = block_info->next_avail;
}
if (best_block_info != NULL)
{
#if PFEM_DEBUG
printf (" pfem_alloc_whole_block: bytes_needed = %d;"
" best fit found = %d\n",
bytes_needed, best_block_info->size);
#endif
}
block_addr = pfem_alloc_block (bytes_needed);
block_info = (pfem_block_info *) pfem_malloc (sizeof (pfem_block_info));
if (block_info == NULL)
{
printf ("pfem_alloc_whole_block: block_info == NULL.\n");
exit (1);
}
block_info->addr = block_addr;
block_info->size = bytes_needed;
block_info->free_bytes = 0;
block_info->largest_free_fragment_size = 0;
block_info->free_fragments = PFEM_INVALID_PTR;
block_info->next = NULL;
block_info->next_avail = NULL;
pfem_add_block_to_block_list (block_info);
return block_addr;
}
void *
pfem_alloc_fragment (size)
size_t size;
{
#define USE_BLOCK_ROVER 1
#if USE_BLOCK_ROVER
static pfem_block_info *block_rover = NULL;
#endif
pfem_block_info *block_info;
size_t bytes_needed;
void *block_addr;
struct best_match_t {
pfem_block_info *block;
pfem_fragment *fragment;
pfem_fragment *last_fragment;
size_t difference;
int tries;
} best_match = { NULL, NULL, NULL, PFEM_FRAG_BLOCK_SIZE, 0 };
#if PFEM_DEBUG
static int call_nbr = 0;
printf ("pfem_alloc_fragment[%d]: request size = %d\n", ++call_nbr, size);
if (call_nbr == 0)
printf ("break here\n");
#endif
bytes_needed = size + PFEM_FRAGMENT_OVERHEAD;
#if PFEM_DEBUG
printf (" pfem_alloc_fragment: bytes_needed (with overhead) = %d\n",
bytes_needed);
#endif
bytes_needed = (bytes_needed + 3) & 0xFFFFFFFC;
#if PFEM_DEBUG
printf (" pfem_alloc_fragment: bytes_needed (after alignment) = %d\n",
bytes_needed);
#endif
#if USE_BLOCK_ROVER
if ((block_rover == NULL) || (block_rover->next_avail == NULL))
block_rover = pfem_frag_block_avail_list;
else
block_rover = block_rover->next_avail;
block_info = block_rover;
#else
block_info = pfem_frag_block_avail_list;
#endif
while (1)
{
if (block_info == NULL)
{
pfem_block_info *new_block_info;
block_addr = pfem_alloc_block (PFEM_FRAG_BLOCK_SIZE);
new_block_info = pfem_set_up_frag_block (block_addr,
PFEM_FRAG_BLOCK_SIZE);
pfem_add_block_to_block_list (new_block_info);
new_block_info->next_avail = pfem_frag_block_avail_list;
pfem_frag_block_avail_list = new_block_info;
block_info = new_block_info;
#if USE_BLOCK_ROVER
block_rover = block_info;
#endif
#if PFEM_DEBUG
printf (" pfem_alloc_fragment: allocating a new block at 0x%x\n",
block_addr);
#endif
}
#if PFEM_DEBUG
printf (" pfem_alloc_fragment: checking block_info at 0x%x\n",
block_info);
if (block_info != NULL)
{
printf (" pfem_alloc_fragment: block size = %d\n",
block_info->size);
printf (" pfem_alloc_fragment: block free_bytes = %d\n",
block_info->free_bytes);
printf (" pfem_alloc_fragment: block largest_free_fragment_size = %d\n",
block_info->largest_free_fragment_size);
printf (" pfem_alloc_fragment: block free_fragments = 0x%x\n",
block_info->free_fragments);
printf (" pfem_alloc_fragment: block next = 0x%x\n",
block_info->next);
printf (" pfem_alloc_fragment: block next_avail = 0x%x\n",
block_info->next_avail);
}
#endif
#if 0
if (bytes_needed <= block_info->largest_free_fragment_size)
{
#else
if (bytes_needed <= block_info->free_bytes)
{
#endif
pfem_fragment *fragment = block_info->free_fragments;
pfem_fragment *last_fragment = NULL;
while (fragment != NULL)
{
#if PFEM_DEBUG
printf (" pfem_alloc_fragment: checking fragment of size %d [0x%x] at 0x%x\n",
fragment->size, fragment->size, fragment);
if (fragment->size > PFEM_FRAG_BLOCK_SIZE)
printf (" ***pfem_alloc_fragment: invalid fragment size.\n");
#endif
if (fragment->size >= bytes_needed)
{
size_t difference = fragment->size - bytes_needed;
#if PFEM_DEBUG
printf (" pfem_alloc_fragment: difference = %d\n", difference);
#endif
if (difference > MAX_FRAGMENT_SIZE_VARIANCE_BEFORE_SPLIT)
{
pfem_fragment *new_fragment = (pfem_fragment *)
((unsigned long)fragment + bytes_needed);
#if PFEM_DEBUG
printf (" pfem_alloc_fragment: splitting fragment of size %d at 0x%x\n",
fragment->size, fragment);
#endif
new_fragment->size = difference;
new_fragment->next = fragment->next;
#if PFEM_DEBUG
printf (" pfem_alloc_fragment: creating new fragment of size %d at 0x%x\n",
new_fragment->size, new_fragment);
#endif
fragment->size = bytes_needed;
fragment->next = new_fragment;
}
if (last_fragment == NULL)
block_info->free_fragments = fragment->next;
else
last_fragment->next = fragment->next;
block_info->free_bytes -= fragment->size;
#if PFEM_DEBUG
printf (" pfem_alloc_fragment: allocated fragment at 0x%x of size %d\n",
&fragment->next, fragment->size - PFEM_FRAGMENT_OVERHEAD);
#endif
return &fragment->next;
}
last_fragment = fragment;
fragment = fragment->next;
}
#if 0
printf (" ***pfem_alloc_fragment: did not find fragment. "
"largest_free_fragment_size incorrect\n");
#endif
}
block_info = block_info->next_avail;
#if USE_BLOCK_ROVER
if (block_info == NULL)
block_info = pfem_frag_block_avail_list;
if (block_info == block_rover)
block_info = NULL;
#endif
}
}
void *
pfem_malloc (size)
size_t size;
{
#if PFEM_DEBUG
printf ("pfem_malloc: request size = %d\n", size);
#endif
if (size > PFEM_MAX_FRAGMENT_SIZE)
return pfem_alloc_whole_block (size);
else
return pfem_alloc_fragment (size);
}
void
pfem_free (ptr)
void *ptr;
{
pfem_block_info *block_info;
pfem_block_info *last_block_info;
pfem_fragment *fragment_to_free;
pfem_fragment *fragment;
pfem_fragment *last_fragment;
if (!ptr) return;
#if PFEM_DEBUG
printf ("pfem_free: object at 0x%x\n", ptr);
#endif
last_block_info = NULL;
for (block_info = pfem_block_list;
block_info != NULL;
block_info = block_info->next)
{
if ((unsigned long) ptr == (unsigned long) block_info->addr)
{
if (PFEM_IS_WHOLE_BLOCK (block_info))
{
if (block_info->free_bytes == block_info->size)
{
printf ("pfem_free: freeing an already free whole block (0x%x).\n",
ptr);
return;
}
block_info->free_bytes = block_info->size;
block_info->next_avail = pfem_whole_block_avail_list;
pfem_whole_block_avail_list = block_info;
#if PFEM_DEBUG
printf (" pfem_free: freed whole block at 0x%x\n", ptr);
#endif
return;
}
else
{
printf ("pfem_free: trying to free a fragment block (0x%x).\n",
ptr);
exit (1);
}
}
else if ((unsigned long) ptr < (unsigned long) block_info->addr)
{
break;
}
last_block_info = block_info;
}
if (((unsigned long) ptr < (unsigned long) last_block_info->addr)
|| ((unsigned long)ptr >= ((unsigned long) last_block_info->addr
+ last_block_info->size)))
{
printf ("pfem_free: trying to free memory (0x%x) not allocated by "
"the memory manager.\n", ptr);
exit (1);
}
if (PFEM_IS_WHOLE_BLOCK (last_block_info))
{
printf ("pfem_free: trying to free a fragment (0x%x) in a "
"non-fragmentable block (0x%x).\n", ptr, last_block_info->addr);
exit (1);
}
fragment_to_free = (pfem_fragment *) ((unsigned long) ptr - PFEM_FRAGMENT_OVERHEAD);
#if PFEM_DEBUG
printf (" pfem_free: freeing fragment at 0x%x of size %d\n",
fragment_to_free, fragment_to_free->size);
if (fragment_to_free->size > PFEM_FRAG_BLOCK_SIZE)
printf (" ***pfem_free: size > PFEM_FRAG_BLOCK_SIZE\n");
#endif
if (last_block_info->free_fragments == NULL)
{
last_block_info->free_fragments = fragment_to_free;
fragment_to_free->next = NULL;
last_block_info->free_bytes = fragment_to_free->size;
last_block_info->largest_free_fragment_size = fragment_to_free->size;
return;
}
last_fragment = NULL;
for (fragment = last_block_info->free_fragments;
fragment != NULL;
fragment = fragment->next)
{
if ((unsigned long) fragment_to_free < (unsigned long) fragment)
break;
if ((unsigned long) fragment_to_free == (unsigned long) fragment)
{
printf ("pfem_free: attempt to free an already free fragment "
"(0x%x).\n", fragment_to_free);
exit (1);
}
last_fragment = fragment;
}
last_block_info->free_bytes += fragment_to_free->size;
if (last_fragment == NULL)
{
last_block_info->free_fragments = fragment_to_free;
}
else
{
if (((unsigned long) last_fragment + last_fragment->size)
== (unsigned long) fragment_to_free)
{
last_fragment->size += fragment_to_free->size;
fragment_to_free = last_fragment;
#if PFEM_DEBUG
if (last_fragment->size > last_block_info->size)
printf ("***pfem_free: coalesced fragment at 0x%x has size (%d) "
"bigger than containing block at 0x%x.\n",
last_fragment, last_fragment->size, last_block_info);
#endif
}
else
last_fragment->next = fragment_to_free;
}
if (fragment == NULL)
{
fragment_to_free->next = NULL;
}
else
{
if (((unsigned long) fragment_to_free + fragment_to_free->size)
== (unsigned long) fragment)
{
fragment_to_free->size += fragment->size;
fragment_to_free->next = fragment->next;
#if PFEM_DEBUG
if (fragment_to_free->size > last_block_info->size)
printf ("***pfem_free: coalesced fragment at 0x%x has size (%d) "
"bigger than containing block at 0x%x.\n",
fragment_to_free, fragment_to_free->size, last_block_info);
#endif
}
else
{
fragment_to_free->next = fragment;
}
}
if (fragment_to_free->size > last_block_info->largest_free_fragment_size)
last_block_info->largest_free_fragment_size = fragment_to_free->size;
}
void *
pfem_calloc (nobj, size)
size_t nobj;
size_t size;
{
void *p;
p = pfem_malloc (nobj * size);
if (p != NULL)
memset (p, 0, nobj * size);
return p;
}
void *
pfem_realloc (p, size)
void *p;
size_t size;
{
void *p2;
pfem_block_info *block;
size_t old_size;
p2 = pfem_malloc (size);
if (p2 == NULL)
return NULL;
if (p != NULL)
{
block = pfem_find_containing_block (p);
if (block == NULL)
{
printf ("pfem_realloc: attempt to realloc from a pointer not alloced.\n");
exit (1);
}
if (PFEM_IS_WHOLE_BLOCK (block))
if (p == block->addr)
old_size = block->size;
else
{
printf ("pfem_realloc: attempt to realloc from inside an alloced object.\n");
exit (1);
}
else
{
pfem_fragment *f = (pfem_fragment *) ((unsigned long) p - PFEM_FRAGMENT_OVERHEAD);
old_size = f->size;
}
memcpy (p2, p, (size < old_size) ? size : old_size);
pfem_free (p);
}
return p2;
}
void
pfem_id_ranges (id_range_fp)
void (*id_range_fp)(unsigned long, unsigned long);
{
int range_idx;
#if MINIMIZE_RANGES
pfem_block_info *block;
pfem_fragment *fragment;
pfem_fragment *last_fragment;
for (block = pfem_whole_block_avail_list; block != NULL; block = block->next_avail)
pfem_remove_block_from_range_table (block->addr, block->size);
for (block = pfem_frag_block_avail_list; block != NULL; block = block->next_avail)
{
last_fragment = NULL;
for (fragment = block->free_fragments; fragment != NULL; fragment = fragment->next)
last_fragment = fragment;
if ((last_fragment != NULL)
&& (((unsigned long) last_fragment + last_fragment->size)
== ((unsigned long) block->addr + block->size))
&& (last_fragment->size >= PFEM_MIN_RECOVERABLE_FRAGMENT_SIZE))
pfem_remove_block_from_range_table (last_fragment, last_fragment->size);
}
#endif
for (range_idx = 0; range_idx < pfem_range_table_nitems; range_idx++)
(*id_range_fp) (pfem_range_table[range_idx].start_addr,
pfem_range_table[range_idx].end_addr);
}
int
pfem_is_pfe_mem (ptr)
void *ptr;
{
int lower_idx = 0;
int upper_idx = pfem_range_table_nitems - 1;
int middle_idx;
while (lower_idx <= upper_idx)
{
middle_idx = (lower_idx + upper_idx) / 2;
if ((unsigned long) ptr < pfem_range_table[middle_idx].start_addr)
upper_idx = middle_idx - 1;
else if ((unsigned long) ptr >= pfem_range_table[middle_idx].end_addr)
lower_idx = middle_idx + 1;
else
return 1;
}
return 0;
}