mirror of
https://github.com/reactos/wine.git
synced 2025-02-10 14:23:52 +00:00
317 lines
5.8 KiB
C
317 lines
5.8 KiB
C
![]() |
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;
|
|||
|
}
|