home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
lxapi32.zip
/
Lib32
/
lxmalloc.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
2002-04-27
|
9KB
|
445 lines
/* $Id: lxmalloc.cpp,v 1.2 2002/04/26 23:09:23 smilcke Exp $ */
/*
* malloc.cpp
* Autor: Stefan Milcke
* Erstellt am: 26.10.2001
* Letzte Aenderung am: 28.04.2002
*
*/
extern "C" {
#define INCL_NOPMAPI
#define INCL_DOSERRORS // for ERROR_INVALID_FUNCTION
#include <os2.h>
}
#include <devhelp.h>
#include <ldefos2.h>
#include <string.h>
#ifdef KEE
#include <kee.h>
#endif
extern "C" {
#include <linux/types.h>
#include <linux/spinlock.h>
#include <asm/page.h>
}
#define DEFAULT_HEAP_SIZE 4096
#define MEMFLAG_USED 1
#define MEMFLAG_FREE 2
#pragma pack(1)
unsigned long default_heap_size=DEFAULT_HEAP_SIZE;
#ifdef DEBUG
#define USE_SIGNATURE
#define SIGNATURE 0x2817EAFD
#define DEBUG_INLINE
#else
#define DEBUG_INLINE inline
#endif
extern "C"
{
typedef struct _MEMBLOCK
{
#ifdef USE_SIGNATURE
unsigned long signature;
#endif
unsigned long size;
unsigned long flags;
struct _MEMBLOCK *pNext;
} MEMBLOCK, near *PMEMBLOCK;
typedef struct _HEAP
{
#ifdef USE_SIGNATURE
unsigned long signature;
#endif
unsigned long size;
struct _HEAP *pNext;
struct _MEMBLOCK *pMem;
} HEAP, near *PHEAP;
#pragma pack()
PHEAP root_heap=NULL;
static spinlock_t memlock=SPIN_LOCK_UNLOCKED;
#define MEMFLAGS (VMDHA_FIXED | VMDHA_CONTIG)
//--------------------------------- allocHeap ----------------------------------
static DEBUG_INLINE PHEAP allocHeap(unsigned long heapSize)
{
char near *heap;
#ifdef KEE
SHORT sel;
if(KernVMAlloc(heapSize,MEMFLAGS,(PVOID*)&heap,(PVOID*)-1,&sel))
{
#else
if(DevVMAlloc(MEMFLAGS,heapSize,(LINEAR)-1,__StackToFlat((ULONG)&heap)))
{
#endif
return (PHEAP)0;
}
*(ULONG *)heap=0;
{
PHEAP pHeap=(PHEAP)heap;
PMEMBLOCK pMem=NULL;
#ifdef USE_SIGNATURE
pHeap->signature=SIGNATURE;
#endif
pHeap->size=heapSize-sizeof(HEAP);
pHeap->pNext=NULL;
pHeap->pMem=(PMEMBLOCK)((unsigned long)heap+sizeof(HEAP));
pMem=(PMEMBLOCK)pHeap->pMem;
#ifdef USE_SIGNATURE
pMem->signature=SIGNATURE;
#endif
pMem->size=pHeap->size-sizeof(MEMBLOCK);
pMem->flags=MEMFLAG_FREE;
pMem->pNext=NULL;
}
return (PHEAP)heap;
}
//---------------------------------- freeHeap ----------------------------------
// returns 1, if the heap was removed
static DEBUG_INLINE int freeHeap(PHEAP pHeap)
{
char near *heap=0;
// Special for zero pointer
if(!pHeap)
return 0;
// Special for root heap
if(pHeap==root_heap)
{
if((!pHeap->pNext))
return 0;
root_heap=(PHEAP)pHeap->pNext;
heap=(char near *)pHeap;
}
else
{ // Walk through the heap chain until we found our heap
PHEAP p=root_heap;
while(p)
{
if(p->pNext==pHeap)
{ // Fond it, so move this heap out of the chain
if(p->pNext)
p->pNext=p->pNext->pNext;
heap=(char near *)pHeap;
break;
}
else
p=(PHEAP)p->pNext;
}
}
if(heap)
{
#ifdef KEE
KernVMFree(heap);
#else
DevVMFree((LINEAR)heap);
#endif
return 1;
}
return 0;
}
//-------------------------------- compressHeap --------------------------------
// returns 1, if the heap was empty and so removed
static DEBUG_INLINE int compressHeap(PHEAP pHeap)
{
PMEMBLOCK pm;
PMEMBLOCK previous;
PMEMBLOCK next=(PMEMBLOCK)NULL;
if(!pHeap)
return 0;
pm=(PMEMBLOCK)pHeap->pMem;
previous=(PMEMBLOCK)pHeap->pMem;
while(pm)
{
if(pm->flags & MEMFLAG_FREE)
{ // Check, if next block is also free.
next=(PMEMBLOCK)pm->pNext;
if(next)
{
if(next->flags & MEMFLAG_FREE)
{
PMEMBLOCK tmp=(PMEMBLOCK)next->pNext;
pm->pNext=(_MEMBLOCK *)tmp;
pm->size=pm->size+next->size;
pm=previous;
}
}
}
previous=pm;
pm=(PMEMBLOCK)pm->pNext;
}
pm=(PMEMBLOCK)pHeap->pMem;
if(!pm->pNext)
{
freeHeap(pHeap);
return 1;
}
return 0;
}
//------------------------------------ free ------------------------------------
void free(void *ptr)
{
PHEAP p=root_heap;
PMEMBLOCK pm=NULL;
if(!ptr)
return;
spin_lock_irq(&memlock);
while(p)
{
pm=(PMEMBLOCK)p->pMem;
while(pm)
{
if((pm->flags & MEMFLAG_USED)
&& (void *)((unsigned long)pm+sizeof(MEMBLOCK))==ptr)
{
p->size+=pm->size;
pm->flags=MEMFLAG_FREE;
compressHeap(p);
spin_unlock_irq(&memlock);
return;
}
pm=(PMEMBLOCK)pm->pNext;
}
p=(PHEAP)p->pNext;
}
spin_unlock_irq(&memlock);
}
//----------------------------------- malloc -----------------------------------
void *malloc(unsigned long size)
{
PHEAP p;
PMEMBLOCK pm=NULL;
spin_lock_irq(&memlock);
p=root_heap;
while(p)
{
// Is there enough room in this heap ?
if(p->size>=size)
{
pm=(PMEMBLOCK)p->pMem;
while(pm)
{
if((pm->flags & MEMFLAG_FREE) && (pm->size >= size))
{ // Found a free block
long remaining_size=pm->size-size-sizeof(MEMBLOCK);
pm->flags=MEMFLAG_USED;
pm->size=size;
if(remaining_size>0)
{
PMEMBLOCK npm=(PMEMBLOCK)(((unsigned long)pm)+pm->size+sizeof(MEMBLOCK));
pm->pNext=npm;
#ifdef USE_SIGNATURE
npm->signature=SIGNATURE;
#endif
npm->size=remaining_size;
npm->pNext=NULL;
npm->flags=MEMFLAG_FREE;
}
p->size-=pm->size;
spin_unlock_irq(&memlock);
return (void *)((unsigned long)pm+sizeof(MEMBLOCK));
}
#ifdef USE_SIGNATURE
if(pm->pNext && pm->pNext->signature==SIGNATURE)
#else
if(pm->pNext)
#endif
pm=(PMEMBLOCK)pm->pNext;
else
break;
}
}
#ifdef USE_SIGNATURE
if(p->pNext && p->pNext->signature==SIGNATURE)
#else
if(p->pNext)
#endif
p=(PHEAP)p->pNext;
else
{ // No heaps left, so allocate a new one
unsigned long requested_size=size+sizeof(HEAP)+sizeof(MEMBLOCK);
if(requested_size>default_heap_size)
{
requested_size=((unsigned long)((requested_size/default_heap_size)+1))*default_heap_size;
p->pNext=allocHeap(requested_size);
}
else
p->pNext=allocHeap(default_heap_size);
p=(PHEAP)p->pNext;
}
}
spin_unlock_irq(&memlock);
return NULL;
}
//---------------------------------- realloc -----------------------------------
void *realloc(void *oldPtr,unsigned long newSize)
{
void *p=malloc(newSize);
void *pf=NULL;
unsigned long oldSize=0;
spin_lock_irq(&memlock);
if(p)
{
if(oldPtr)
{
PHEAP p=root_heap;
PMEMBLOCK pm=NULL;
while(p)
{
pm=(PMEMBLOCK)p->pMem;
while(pm)
{
if((pm->flags & MEMFLAG_USED)
&& (void *)((unsigned long)pm+sizeof(MEMBLOCK))==oldPtr)
{
pf=oldPtr;
oldSize=pm->size;
memcpy(p,pf,oldSize);
p->size+=pm->size;
pm->flags=MEMFLAG_FREE;
compressHeap(p);
spin_unlock_irq(&memlock);
return p;
}
pm=(PMEMBLOCK)pm->pNext;
}
p=(PHEAP)p->pNext;
}
}
}
spin_unlock_irq(&memlock);
return p;
}
//-------------------------------- __mallocInit --------------------------------
int __mallocInit(void)
{
if(!root_heap)
if(0==(root_heap=allocHeap(default_heap_size)))
return 1;
return 0;
}
#define VMMEMFLAGS (VMDHA_PROCESS)
typedef struct _VMMEMADDR
{
struct _VMMEMADDR *next;
unsigned long size;
unsigned long pid;
void *ptr;
#ifdef KEE
KEEVMLock lock;
#else
char lock[12];
#endif
} VMMEMADDR,*PVMMEMADDR;
PVMMEMADDR vm_root_addr=NULL;
extern "C" unsigned long OS2_get_current_pid(void);
//--------------------------------- __vmalloc ----------------------------------
void *__vmalloc(unsigned long size,int gfp_mask,pgprot_t prot)
{
PVMMEMADDR p=NULL;
unsigned long sz=PAGE_ALIGN(size);
#ifdef KEE
void *ptr=NULL;
#else
char near *ptr=NULL;
#endif
p=(PVMMEMADDR)malloc(sizeof(VMMEMADDR));
if(p)
{
#ifdef KEE
SHORT sel;
if(KernVMAlloc(sz,VMMEMFLAGS,(PVOID*)&ptr,(PVOID*)-1,&sel))
#else
if(DevVMAlloc(VMMEMFLAGS,sz,(LINEAR)-1,__StackToFlat((ULONG)&ptr)))
#endif
{
free(p);
return NULL;
}
#ifdef KEE
if(KernVMLock(KEE_VML_CONTIG | KEE_VML_LONGLOCK | KEE_VML_WRITEABLE
,ptr,sz,&(p->lock),(KEEVMPageList*)-1,0))
{
KernVMFree(ptr);
#else
if(DevVMLock(VMDHL_CONTIG | VMDHL_LONG | VMDHL_WRITE
,ptr,sz,(LINEAR)-1,&(p->lock)
,(LINEAR)__StackToFlat((ULONG)&PgCount)))
{
DevVMFree((LINEAR)ptr);
#endif
free(p);
return NULL;
}
p->size=sz;
p->pid=OS2_get_current_pid();
p->ptr=ptr;
spin_lock_irq(&memlock);
p->next=vm_root_addr;
vm_root_addr=p;
spin_unlock_irq(&memlock);
}
return (void *)ptr;
}
//----------------------------------- vfree ------------------------------------
void vfree(void *ptr)
{
void *p=NULL;
PVMMEMADDR pm;
PVMMEMADDR previous_pm=NULL;
unsigned long pid=OS2_get_current_pid();
spin_lock_irq(&memlock);
pm=vm_root_addr;
while(pm)
{
if(pm->ptr==ptr && pm->pid==pid)
{
p=pm->ptr;
if(pm==vm_root_addr)
vm_root_addr=pm->next;
else if(previous_pm)
previous_pm->next=pm->next;
break;
}
previous_pm=pm;
pm=pm->next;
}
spin_unlock_irq(&memlock);
if(p && pm)
{
#ifdef KEE
if(!KernVMUnlock(&pm->lock))
KernVMFree(pm->ptr);
#else
if(!DevVMUnLock(&pm->lock))
DevVMFree(pm->ptr);
#endif
free(pm);
}
}
}; // extern "C"