Thu Feb 16 18:57:31 1995 Alexandre Julliard (julliard@sunsite.unc.edu) * [if1632/call.S] Only save the lower 16-bits of SP and BP. * [if1632/callback.c] When calling to 16-bit code, restore DS from its previous value on entry to the 32-bit code, instead of from the code segment owner. * [if1632/relay.c] [include/stackframe.h] Use a structure to represent the 16-bit stack frame layout instead of hard-coded offsets. * [rc/Imakefile] Use y.tab.c for bison output file for compatibility with yacc. * [tools/build.c] Small optimization for calls to 32-bit code. Sun Feb 12 03:19:47 1995 Michael Veksler (s1678223@t2.technion.ac.il) * [tools/build.c] Fixed bug (inflicted by previous change) - SEGV on ZMAGIC file format. Sun Feb 11 20:00:00 1995 Göran Thyni (goran@norrsken.bildbasen.se) * [debugger/dbg.y] Remove unnecessary sym-table loading when stopped in 16-bit mode. * [include/segmem.h] [loader/selector.c] Added dynamic alloction of selectors. Fixed some problems with large programs SIGSEGV-ing while running out of selectors. * [include/segmem.h] [loader/selector.c] [if1632/callback.c] [memory/global.c] [memory/heap.c] [memory/linear.c] Use __AHSHIFT and __AHINCR instead of 3 and 8. Mon Feb 6 18:07:38 1995 Cameron Heide (heide@ee.ualberta.ca) * [misc/dos_fs.c] Better relative path handling when converting filenames between dos and unix, allowing '.' to be used in the Windows path. Startup working dir is now based on current working dir. Sat Feb 4 21:21:13 1995 Michael Veksler (s1678223@t2.technion.ac.il) * [if1632/relay.c] [include/dlls.h] [tools/build.c] Squeezed data structure that references internal dll's (mostly "struct dll_table_entry_s"). Caused 20% reduction in executable code size. Fri Feb 3 18:53:15 1995 Martin v. Loewis (loewis@marie) * [Imakefile] make wine.sym only when making emulator * [misc/file.c] OpenFile(): report as not implemented for WINELIB * [misc/winsock.c] Fix CONVERT_HOSTENT and friends for use with WINELIB * [rc/Imakefile][rc/rc.y][rc/parser.c] Rename rc.y to parser.y Use flex and bison on Sun * [toolkit/sup.c] CallWindowProc: fix parameter type * [windows/event.c] Commented #ifdef sparc
906 lines
18 KiB
C
906 lines
18 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";
|
||
*/
|
||
|
||
#define GLOBAL_SOURCE
|
||
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include "windows.h"
|
||
#include "prototypes.h"
|
||
#include "toolhelp.h"
|
||
#include "heap.h"
|
||
#include "segmem.h"
|
||
#include "selectors.h"
|
||
#include "stddebug.h"
|
||
/* #define DEBUG_HEAP */
|
||
#include "debug.h"
|
||
|
||
|
||
GDESC *GlobalList = NULL;
|
||
static unsigned short next_unused_handle = 1;
|
||
|
||
/**********************************************************************
|
||
* GlobalGetGDesc
|
||
*/
|
||
GDESC *GlobalGetGDesc(unsigned int block)
|
||
{
|
||
GDESC *g;
|
||
|
||
if (block == 0)
|
||
return NULL;
|
||
|
||
/*
|
||
* 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;
|
||
}
|
||
|
||
return g;
|
||
}
|
||
|
||
/**********************************************************************
|
||
* GlobalGetFreeSegments
|
||
*/
|
||
GDESC *
|
||
GlobalGetFreeSegments(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.
|
||
*/
|
||
s = CreateNewSegments(0, 0, 0x10000, n_segments);
|
||
if (s == NULL)
|
||
{
|
||
fprintf(stderr,"GlobalGetFreeSegments // bad CreateNewSegments !\n");
|
||
return NULL;
|
||
}
|
||
for (count = 0; count < n_segments; count++, s++)
|
||
{
|
||
g = (GDESC *) malloc(sizeof(*g));
|
||
if (g == NULL)
|
||
{
|
||
fprintf(stderr,"GlobalGetFreeSegments // bad GDESC malloc !\n");
|
||
return NULL;
|
||
}
|
||
g->prev = g_prev;
|
||
g->next = NULL;
|
||
g->handle = s->selector;
|
||
g->sequence = -1;
|
||
g->addr = s->base_addr;
|
||
g->length = s->length;
|
||
g->alias = 0;
|
||
g->linear_addr = NULL;
|
||
g->linear_key = 0;
|
||
g->linear_count = 0;
|
||
if (!(flags & GLOBAL_FLAGS_MOVEABLE))
|
||
g->lock_count = 1;
|
||
else
|
||
g->lock_count = 0;
|
||
|
||
if (count == 0) g_start = g;
|
||
|
||
if (g_prev != NULL)
|
||
{
|
||
g_prev->next = g;
|
||
}
|
||
else
|
||
GlobalList = g;
|
||
g_prev = 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)
|
||
{
|
||
if (g == NULL)
|
||
{
|
||
fprintf(stderr,"GlobalGetFreeSegments // bad Segments chain !\n");
|
||
return NULL;
|
||
}
|
||
g->sequence = i + 1;
|
||
g->length = n_segments;
|
||
g->alias = 0;
|
||
g->linear_addr = NULL;
|
||
g->linear_key = 0;
|
||
g->linear_count = 0;
|
||
}
|
||
|
||
return g_start;
|
||
}
|
||
|
||
/**********************************************************************
|
||
* GlobalAlloc
|
||
*/
|
||
HANDLE
|
||
GlobalAlloc(unsigned int flags, unsigned long size)
|
||
{
|
||
GDESC *g;
|
||
GDESC *g_prev;
|
||
void *m;
|
||
|
||
dprintf_heap(stddeb,"GlobalAlloc flags %4X, size %ld\n", flags, size);
|
||
|
||
if (size == 0) size = 1;
|
||
|
||
/*
|
||
* If this block is fixed or very big we need to allocate entire
|
||
* segments.
|
||
*/
|
||
if (size > 0x8000 || !(flags & GLOBAL_FLAGS_MOVEABLE))
|
||
{
|
||
int segments = ((size - 1) >> 16) + 1;
|
||
|
||
g = GlobalGetFreeSegments(flags, segments);
|
||
if (g == NULL)
|
||
{
|
||
dprintf_heap(stddeb, "==> NULL\n");
|
||
return 0;
|
||
}
|
||
else
|
||
{
|
||
dprintf_heap(stddeb, "==> %04x\n",g->handle);
|
||
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 (g == NULL)
|
||
{
|
||
g = GlobalGetFreeSegments(0, 1);
|
||
if (g == NULL)
|
||
{
|
||
dprintf_heap(stddeb, "==> Null\n");
|
||
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, flags & GLOBAL_FLAGS_ZEROINIT,
|
||
size);
|
||
if (m == NULL)
|
||
{
|
||
dprintf_heap(stddeb, "==> Null\n");
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
/*
|
||
* Save position of heap descriptor.
|
||
*/
|
||
g_prev = g;
|
||
|
||
/*
|
||
* We have a new block. Let's create a GDESC entry for it.
|
||
*/
|
||
g = malloc(sizeof(*g));
|
||
dprintf_heap(stddeb,"New GDESC %08x\n", (unsigned int) g);
|
||
if (g == NULL)
|
||
return 0;
|
||
|
||
g->handle = next_unused_handle;
|
||
g->sequence = 0;
|
||
g->addr = m;
|
||
g->alias = 0;
|
||
g->linear_addr = NULL;
|
||
g->linear_key = 0;
|
||
g->linear_count = 0;
|
||
g->length = size;
|
||
g->next = g_prev->next;
|
||
if (g->next) g->next->prev = g;
|
||
g->lock_count = 0;
|
||
|
||
g_prev->next = g;
|
||
g->prev = g_prev;
|
||
|
||
next_unused_handle++;
|
||
if ((next_unused_handle & 7) == 7)
|
||
next_unused_handle++;
|
||
|
||
dprintf_heap(stddeb,"GlobalAlloc: returning %04x\n", g->handle);
|
||
return g->handle;
|
||
}
|
||
}
|
||
|
||
/**********************************************************************
|
||
* WIN16_GlobalAlloc
|
||
*/
|
||
HANDLE
|
||
WIN16_GlobalAlloc(unsigned int flags, unsigned long size)
|
||
{
|
||
return GlobalAlloc(flags & ~GLOBAL_FLAGS_MOVEABLE, size);
|
||
}
|
||
|
||
/**********************************************************************
|
||
* GlobalFree
|
||
*
|
||
* Windows programs will pass a handle in the "block" parameter, but
|
||
* this function will also accept a 32-bit address.
|
||
*/
|
||
HANDLE
|
||
GlobalFree(unsigned int block)
|
||
{
|
||
GDESC *g;
|
||
|
||
if (block == 0)
|
||
return 0;
|
||
|
||
/*
|
||
* Find GDESC for this block.
|
||
*/
|
||
g = GlobalGetGDesc(block);
|
||
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 **) ((int) g->addr & 0xffff0000), (void *) g->addr);
|
||
|
||
g->prev->next = g->next;
|
||
|
||
if (g->next != NULL)
|
||
g->next->prev = g->prev;
|
||
|
||
free(g);
|
||
}
|
||
|
||
/*
|
||
* Otherwise just mark these descriptors as free.
|
||
*/
|
||
else
|
||
{
|
||
int i, limit;
|
||
|
||
limit = g->length;
|
||
for (i = g->sequence - 1; i < limit && g != NULL; i++, g = g->next)
|
||
{
|
||
g->sequence = -1;
|
||
g->length = 0x10000;
|
||
}
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
/**********************************************************************
|
||
* GlobalLock
|
||
*
|
||
*/
|
||
void *
|
||
GlobalLock(unsigned int block)
|
||
{
|
||
GDESC *g;
|
||
|
||
if ((g = GlobalGetGDesc(block)) == NULL)
|
||
return 0;
|
||
|
||
g->lock_count++;
|
||
|
||
dprintf_heap(stddeb,"GlobalLock: returning %08x\n",(unsigned int)g->addr);
|
||
return g->addr;
|
||
}
|
||
|
||
/**********************************************************************
|
||
* GlobalUnlock
|
||
*
|
||
*/
|
||
int
|
||
GlobalUnlock(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 && g->lock_count > 0)
|
||
{
|
||
g->lock_count--;
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
return 1;
|
||
}
|
||
|
||
/**********************************************************************
|
||
* GlobalFlags
|
||
*
|
||
*/
|
||
unsigned int
|
||
GlobalFlags(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->lock_count;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
/**********************************************************************
|
||
* GlobalSize
|
||
*
|
||
*/
|
||
unsigned int
|
||
GlobalSize(unsigned int block)
|
||
{
|
||
GDESC *g = GlobalGetGDesc(block);
|
||
|
||
if (g == NULL)
|
||
return 0;
|
||
|
||
if (g->sequence == 0)
|
||
{
|
||
MDESC *m = (MDESC *) g->addr - 1;
|
||
|
||
return m->length;
|
||
}
|
||
else if (g->sequence >= 1)
|
||
{
|
||
return g->length * 0x10000;
|
||
}
|
||
|
||
return g->length;
|
||
}
|
||
|
||
/**********************************************************************
|
||
* GlobalHandle
|
||
*
|
||
* This routine is not strictly correct. MS Windows creates a selector
|
||
* for every locked global block. We do not. If the allocation is small
|
||
* enough, we only give out a little piece of a selector. Thus this
|
||
* function cannot be implemented.
|
||
*/
|
||
unsigned int
|
||
GlobalHandle(unsigned int selector)
|
||
{
|
||
GDESC *g;
|
||
|
||
if (selector == 0)
|
||
return 0;
|
||
|
||
/*
|
||
* Find GDESC for this block.
|
||
*/
|
||
for (g = GlobalList; g != NULL; g = g->next)
|
||
{
|
||
if (g->handle == selector)
|
||
{
|
||
if (g->sequence > 0)
|
||
return MAKELONG(g->handle, selector);
|
||
else
|
||
{
|
||
fprintf(stderr, "Attempt to get a handle "
|
||
"from a selector to a far heap.\n");
|
||
return 0;
|
||
}
|
||
}
|
||
}
|
||
dprintf_heap(stddeb, "GlobalHandle ==> Null\n");
|
||
return 0;
|
||
}
|
||
|
||
/**********************************************************************
|
||
* GlobalCompact
|
||
*
|
||
*/
|
||
unsigned int
|
||
GlobalCompact(unsigned int desired)
|
||
{
|
||
GDESC *g;
|
||
unsigned char free_map[512];
|
||
unsigned int max_selector_used = 0;
|
||
unsigned int i;
|
||
unsigned int selector;
|
||
int current_free;
|
||
int max_free;
|
||
|
||
/*
|
||
* Initialize free list to all items not controlled by GlobalAlloc()
|
||
*/
|
||
for (i = 0; i < 512; i++)
|
||
free_map[i] = -1;
|
||
|
||
/*
|
||
* Traverse table looking for used and free selectors.
|
||
*/
|
||
for (g = GlobalList; g != NULL; g = g->next)
|
||
{
|
||
/*
|
||
* Check for free segments.
|
||
*/
|
||
if (g->sequence == -1)
|
||
{
|
||
free_map[g->handle >> __AHSHIFT] = 1;
|
||
if (g->handle > max_selector_used)
|
||
max_selector_used = g->handle;
|
||
}
|
||
|
||
/*
|
||
* Check for heap allocated segments.
|
||
*/
|
||
else if (g->handle == 0)
|
||
{
|
||
selector = (unsigned int) g->addr >> 16;
|
||
free_map[selector >> __AHSHIFT] = 0;
|
||
if (selector > max_selector_used)
|
||
max_selector_used = selector;
|
||
}
|
||
}
|
||
|
||
/*
|
||
* All segments past the biggest selector used are free.
|
||
*/
|
||
for (i = (max_selector_used >> __AHSHIFT) + 1; i < 512; i++)
|
||
free_map[i] = 1;
|
||
|
||
/*
|
||
* Find the largest free block of segments
|
||
*/
|
||
current_free = 0;
|
||
max_free = 0;
|
||
for (i = 0; i < 512; i++)
|
||
{
|
||
if (free_map[i] == 1)
|
||
{
|
||
current_free++;
|
||
}
|
||
else
|
||
{
|
||
if (current_free > max_free)
|
||
max_free = current_free;
|
||
current_free = 0;
|
||
}
|
||
}
|
||
|
||
/* One final check just in case the last block was also marked free, in
|
||
* which case the above test against max_free doesn't occur for the
|
||
* last run of free blocks.
|
||
*/
|
||
if (current_free > max_free)
|
||
max_free = current_free;
|
||
|
||
return max_free << 16;
|
||
}
|
||
|
||
/**********************************************************************
|
||
* GlobalReAlloc
|
||
*
|
||
*/
|
||
unsigned int
|
||
GlobalReAlloc(unsigned int block, unsigned int new_size, unsigned int flags)
|
||
{
|
||
GDESC *g;
|
||
unsigned int n_segments;
|
||
int i;
|
||
|
||
if (block == 0)
|
||
return 0;
|
||
|
||
/*
|
||
* Find GDESC for this block.
|
||
*/
|
||
g = GlobalGetGDesc(block);
|
||
if (g == NULL)
|
||
return 0;
|
||
|
||
/*
|
||
* If this is a heap allocated block, then use HEAP_ReAlloc() to
|
||
* reallocate the block. If this fails, call GlobalAlloc() to get
|
||
* a new block.
|
||
*/
|
||
if (g->sequence == 0)
|
||
{
|
||
MDESC **free_list;
|
||
void *p;
|
||
|
||
free_list = (MDESC **) ((unsigned int) g->addr & 0xffff0000);
|
||
p = HEAP_ReAlloc(free_list, g->addr, new_size, flags) ;
|
||
if (p == NULL)
|
||
{
|
||
unsigned int handle = GlobalAlloc(flags, new_size);
|
||
if (handle == 0)
|
||
return 0;
|
||
p = GlobalLock(handle);
|
||
memcpy(p, g->addr, g->length);
|
||
GlobalUnlock(handle);
|
||
GlobalFree(g->handle);
|
||
|
||
return handle;
|
||
}
|
||
else
|
||
{
|
||
g->addr = p;
|
||
g->length = new_size;
|
||
return g->handle;
|
||
}
|
||
}
|
||
|
||
/*
|
||
* Otherwise, we need to do the work ourselves. First verify the
|
||
* handle.
|
||
*/
|
||
else
|
||
{
|
||
if (g->sequence != 1)
|
||
return 0;
|
||
|
||
/*
|
||
* Do we need more memory? Segments are in ascending order in
|
||
* the GDESC list.
|
||
*/
|
||
n_segments = (new_size >> 16) + 1;
|
||
if (n_segments > g->length)
|
||
{
|
||
GDESC *g_new;
|
||
GDESC *g_start = g;
|
||
/* int old_segments = g_start->length;*/
|
||
unsigned short next_handle = g_start->handle;
|
||
|
||
for (i = 1; i <= n_segments; i++, g = g->next)
|
||
{
|
||
/*
|
||
* If we run into a block allocated to something else,
|
||
* try GlobalGetFreeSegments() and memcpy(). (Yuk!)
|
||
*/
|
||
if (g->sequence != i || g->handle != next_handle)
|
||
{
|
||
g = GlobalGetFreeSegments(flags, n_segments);
|
||
if (g == NULL)
|
||
return 0;
|
||
|
||
memcpy(g->addr, g_start->addr,
|
||
g_start->length << 16);
|
||
|
||
GlobalFree(block);
|
||
return g->handle;
|
||
}
|
||
|
||
/*
|
||
* Otherwise this block is used by us or free. So,
|
||
* snatch it. If this block is new and we are supposed to
|
||
* zero init, then do some erasing.
|
||
*/
|
||
if (g->sequence == -1 && (flags & GLOBAL_FLAGS_ZEROINIT))
|
||
memset(g->addr, 0, 0x10000);
|
||
|
||
g->sequence = i;
|
||
g->length = n_segments;
|
||
next_handle += 8;
|
||
|
||
/*
|
||
* If the next descriptor is non-existant, then use
|
||
* GlobalGetFreeSegments to create them.
|
||
*/
|
||
if (i != n_segments && g->next == NULL)
|
||
{
|
||
g_new = GlobalGetFreeSegments(flags, n_segments - i);
|
||
if (g_new == NULL)
|
||
return 0;
|
||
GlobalFree(g_new->handle);
|
||
}
|
||
}
|
||
|
||
return g_start->handle;
|
||
}
|
||
|
||
/*
|
||
* Do we need less memory?
|
||
*/
|
||
else if (n_segments < g->length)
|
||
{
|
||
GDESC *g_free;
|
||
int old_length = g->length;
|
||
|
||
g_free = g;
|
||
for (i = 0; i < n_segments; i++)
|
||
{
|
||
if (g_free->sequence != i + 1)
|
||
return 0;
|
||
g_free->length = n_segments;
|
||
g_free = g_free->next;
|
||
}
|
||
|
||
for ( ; i < old_length; i++)
|
||
{
|
||
g_free->length = 0x10000;
|
||
g_free->sequence = -1;
|
||
g_free = g_free->next;
|
||
}
|
||
|
||
return g->handle;
|
||
}
|
||
|
||
/*
|
||
* We already have exactly the right amount of memory.
|
||
*/
|
||
else
|
||
return block;
|
||
}
|
||
|
||
/*
|
||
* If we fall through it must be an error.
|
||
*/
|
||
return 0;
|
||
}
|
||
|
||
/**********************************************************************
|
||
* GlobalQuickAlloc
|
||
*/
|
||
void *
|
||
GlobalQuickAlloc(int size)
|
||
{
|
||
unsigned int hmem;
|
||
|
||
hmem = GlobalAlloc(GLOBAL_FLAGS_MOVEABLE, size);
|
||
if (hmem == 0)
|
||
return NULL;
|
||
else
|
||
return GlobalLock(hmem);
|
||
}
|
||
|
||
/**********************************************************************
|
||
* GlobalHandleFromPointer
|
||
|
||
*/
|
||
unsigned int
|
||
GlobalHandleFromPointer(void *block)
|
||
{
|
||
GDESC *g;
|
||
|
||
if (block == NULL)
|
||
return 0;
|
||
|
||
/*
|
||
* Find GDESC for this block.
|
||
*/
|
||
for (g = GlobalList; g != NULL; g = g->next)
|
||
if (g->handle > 0 && g->addr == block)
|
||
break;
|
||
|
||
if (g == NULL)
|
||
return 0;
|
||
else
|
||
return g->handle;
|
||
}
|
||
|
||
/**********************************************************************
|
||
* GetFreeSpace (kernel.169)
|
||
|
||
*/
|
||
DWORD GetFreeSpace(UINT wFlags)
|
||
/* windows 3.1 doesn't use the wFlags parameter !!
|
||
(so I won't either) */
|
||
{
|
||
GDESC *g;
|
||
unsigned char free_map[512];
|
||
unsigned int max_selector_used = 0;
|
||
unsigned int i;
|
||
unsigned int selector;
|
||
int total_free;
|
||
|
||
/*
|
||
* Initialize free list to all items not controlled by GlobalAlloc()
|
||
*/
|
||
for (i = 0; i < 512; i++)
|
||
free_map[i] = -1;
|
||
|
||
/*
|
||
* Traverse table looking for used and free selectors.
|
||
*/
|
||
for (g = GlobalList; g != NULL; g = g->next)
|
||
{
|
||
/*
|
||
* Check for free segments.
|
||
*/
|
||
if (g->sequence == -1)
|
||
{
|
||
free_map[g->handle >> __AHSHIFT] = 1;
|
||
if (g->handle > max_selector_used)
|
||
max_selector_used = g->handle;
|
||
}
|
||
|
||
/*
|
||
* Check for heap allocated segments.
|
||
*/
|
||
else if (g->handle == 0)
|
||
{
|
||
selector = (unsigned int) g->addr >> 16;
|
||
free_map[selector >> __AHSHIFT] = 0;
|
||
if (selector > max_selector_used)
|
||
max_selector_used = selector;
|
||
}
|
||
}
|
||
|
||
/*
|
||
* All segments past the biggest selector used are free.
|
||
*/
|
||
for (i = (max_selector_used >> __AHSHIFT) + 1; i < 512; i++)
|
||
free_map[i] = 1;
|
||
|
||
/*
|
||
* Add up the total free segments (obviously this amount of memory
|
||
may not be contiguous, use GlobalCompact to get largest contiguous
|
||
memory available).
|
||
*/
|
||
total_free=0;
|
||
for (i = 0; i < 512; i++)
|
||
if (free_map[i] == 1)
|
||
total_free++;
|
||
|
||
dprintf_heap(stddeb,"GetFreeSpace // return %ld !\n", (long) (total_free << 16));
|
||
return total_free << 16;
|
||
}
|
||
|
||
/**********************************************************************
|
||
* MemManInfo (toolhelp.72)
|
||
*/
|
||
BOOL MemManInfo(LPMEMMANINFO lpmmi)
|
||
{
|
||
return 1;
|
||
}
|
||
|
||
/***********************************************************************
|
||
* SetSwapAreaSize (KERNEL.106)
|
||
*/
|
||
LONG SetSwapAreaSize( WORD size )
|
||
{
|
||
dprintf_heap(stdnimp, "STUB: SetSwapAreaSize(%d)\n", size );
|
||
return MAKELONG( size, 0xffff );
|
||
}
|
||
|
||
/***********************************************************************
|
||
* IsBadCodePtr (KERNEL.336)
|
||
*/
|
||
BOOL IsBadCodePtr( FARPROC lpfn )
|
||
{
|
||
printf( "STUB: IsBadCodePtr(%p)\n", lpfn );
|
||
return FALSE;
|
||
}
|
||
|
||
/***********************************************************************
|
||
* IsBadHugeWritePtr (KERNEL.347)
|
||
*/
|
||
BOOL IsBadHugeWritePtr( const char *lp, DWORD cb )
|
||
{
|
||
return !test_memory(&lp[cb-1], TRUE);
|
||
}
|
||
|
||
/***********************************************************************
|
||
* IsBadWritePtr (KERNEL.335)
|
||
*/
|
||
BOOL IsBadWritePtr( const char *lp, DWORD cb )
|
||
{
|
||
if ((0xffff & (unsigned int) lp) + cb > 0xffff)
|
||
return TRUE;
|
||
return !test_memory(&lp[cb-1], TRUE);
|
||
}
|
||
|
||
/***********************************************************************
|
||
* IsBadReadPtr (KERNEL.334)
|
||
*/
|
||
BOOL IsBadReadPtr( const char *lp, DWORD cb )
|
||
{
|
||
if ((0xffff & (unsigned int) lp) + cb > 0xffff)
|
||
return TRUE;
|
||
return !test_memory(&lp[cb-1], FALSE);
|
||
}
|
||
|
||
/***********************************************************************
|
||
* IsBadHugeReadPtr (KERNEL.346)
|
||
*/
|
||
BOOL IsBadHugeReadPtr( const char *lp, DWORD cb )
|
||
{
|
||
if ((0xffff & (unsigned int) lp) + cb > 0xffff)
|
||
return TRUE;
|
||
return !test_memory(&lp[cb-1], FALSE);
|
||
}
|
||
|
||
/***********************************************************************
|
||
* IsBadStringPtr (KERNEL.337)
|
||
*/
|
||
BOOL IsBadStringPtr( const char *lp, UINT cb )
|
||
{
|
||
if (!IsBadReadPtr(lp, cb+1))
|
||
return FALSE;
|
||
if (lp[cb])
|
||
return FALSE;
|
||
return TRUE;
|
||
}
|