blob: 3ef21eebf82ac3ed92667129fb21b4ff281241d2 [file] [log] [blame]
static char RCSId[] = "$Id: global.c,v 1.2 1993/07/04 04:04:21 root Exp root $";
static char Copyright[] = "Copyright Robert J. Amstadt, 1993";
#include <stdio.h>
#include <stdlib.h>
#include "prototypes.h"
#include "heap.h"
#include "segmem.h"
/*
* Global memory pool descriptor.
*
* handle = 0, this descriptor contains the address of a free pool.
* != 0, this describes an allocated block.
*
* sequence = 0, this is not a huge block
* > 0, this is a portion of a huge block
* =-1, this is a free segment
*
* addr - address of this memory block.
*
* length - used to maintain huge blocks.
*
*/
typedef struct global_mem_desc_s
{
struct global_mem_desc_s *next;
struct global_mem_desc_s *prev;
unsigned short handle;
short sequence;
void *addr;
int length;
} GDESC;
GDESC *GlobalList = NULL;
/**********************************************************************
* GLOBAL_GetFreeSegments
*/
GDESC *
GLOBAL_GetFreeSegments(unsigned int flags, int n_segments)
{
struct segment_descriptor_s *s;
GDESC *g;
GDESC *g_start;
GDESC *g_prev;
int count, i;
/*
* Try to find some empty segments in our list.
*/
count = 0;
for (g = GlobalList; g != NULL && count != n_segments; g = g->next)
{
if ((int) g->sequence == -1)
{
if (count > 0)
{
if (g->prev->handle + 8 != g->handle)
count = 0;
else
count++;
}
else
{
g_start = g;
count = 1;
}
}
else if (count)
count = 0;
}
/*
* If we couldn't find enough segments, then we need to create some.
*/
if (count != n_segments)
{
/*
* Find list tail.
*/
g_prev = NULL;
for (g = GlobalList; g != NULL; g = g->next)
g_prev = g;
/*
* Allocate segments.
*/
for (count = 0; count < n_segments; count++)
{
s = GetNextSegment(flags, 0x10000);
if (s == NULL)
return NULL;
g = (GDESC *) malloc(sizeof(*g));
g->prev = g_prev;
g->next = NULL;
g->handle = s->selector;
g->sequence = -1;
g->addr = s->base_addr;
g->length = s->length;
free(s);
if (count == 0)
g_start = g;
if (g_prev != NULL)
{
g_prev->next = g;
g->prev = g_prev;
}
else
GlobalList = g;
}
}
/*
* We have all of the segments we need. Let's adjust their contents.
*/
g = g_start;
for (i = 0; i < n_segments; i++, g = g->next)
{
g->sequence = i + 1;
g->length = n_segments;
}
return g_start;
}
/**********************************************************************
* GLOBAL_Alloc
*/
unsigned int
GLOBAL_Alloc(unsigned int flags, unsigned long size)
{
GDESC *g;
GDESC *g_prev;
void *m;
int i;
/*
* If this block is fixed or very big we need to allocate entire
* segments.
*/
if (size > 0x8000 || !(flags & GLOBAL_FLAGS_MOVEABLE))
{
int segments = (size >> 16) + 1;
g = GLOBAL_GetFreeSegments(flags, segments);
if (g == NULL)
return 0;
else
return g->handle;
}
/*
* Otherwise we just need a little piece of a segment.
*/
else
{
/*
* Try to allocate from active free lists.
*/
for (g = GlobalList; g != NULL; g = g->next)
{
if (g->handle == 0 && g->sequence == 0)
{
m = HEAP_Alloc((MDESC **) g->addr, 0, size);
if (m != NULL)
break;
}
}
/*
* If we couldn't get the memory there, then we need to create
* a new free list.
*/
if (m == NULL)
{
g = GLOBAL_GetFreeSegments(0, 1);
if (g == NULL)
return 0;
g->handle = 0;
g->sequence = 0;
HEAP_Init((MDESC **) g->addr, (MDESC **) g->addr + 1,
0x10000 - sizeof(MDESC **));
m = HEAP_Alloc((MDESC **) g->addr, 0, size);
if (m == NULL)
return 0;
}
/*
* We have a new block. Let's create a GDESC entry for it.
*/
g_prev = NULL;
i = 0;
for (g = GlobalList; g != NULL; g = g->next, i++)
g_prev = g;
g = malloc(sizeof(*g));
if (g == NULL)
return 0;
g->handle = i << 3;
g->sequence = 0;
g->addr = m;
g->length = size;
g->next = NULL;
if (g_prev != NULL)
{
g_prev->next = g;
g->prev = g_prev;
}
else
{
GlobalList = g;
g->prev = NULL;
}
return g->handle;
}
}
/**********************************************************************
* GLOBAL_Free
*
* Windows programs will pass a handle in the "block" parameter, but
* this function will also accept a 32-bit address.
*/
unsigned int
GLOBAL_Free(unsigned int block)
{
GDESC *g;
if (block == 0)
return 0;
/*
* Find GDESC for this block.
*/
if (block & 0xffff0000)
{
for (g = GlobalList; g != NULL; g = g->next)
if (g->handle > 0 && (unsigned int) g->addr == block)
break;
}
else
{
for (g = GlobalList; g != NULL; g = g->next)
if (g->handle == block)
break;
}
if (g == NULL)
return block;
/*
* If the sequence number is zero then use HEAP_Free to deallocate
* memory, and throw away this descriptor.
*/
if (g->sequence == 0)
{
HEAP_Free((MDESC **) (block & 0xffff0000), (void *) block);
if (g->prev != NULL)
g->prev->next = g->next;
else
GlobalList = g->next;
if (g->next != NULL)
g->next->prev = g->prev;
free(g);
}
/*
* Otherwise just mark these descriptors as free.
*/
else
{
int i, limit;
g->length;
for (i = 0; i < limit; i++)
{
g->sequence = -1;
g->length = 0x10000;
}
}
return 0;
}
/**********************************************************************
* GLOBAL_Lock
*
*/
void *
GLOBAL_Lock(unsigned int block)
{
GDESC *g;
if (block == 0)
return 0;
/*
* Find GDESC for this block.
*/
for (g = GlobalList; g != NULL; g = g->next)
if (g->handle == block)
return g->addr;
return NULL;
}