home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Kosovo Orphans' Appeal Charity CD
/
KosovoOrphansAppeal.iso
/
commercialdemos
/
claresmicrosupplies
/
pca
/
flexlib
/
c
/
flex
Wrap
Text File
|
1996-04-30
|
20KB
|
839 lines
/************************************************************************/
/* Acorn Computers Ltd, 1992. */
/* */
/* This file forms part of an unsupported source release of RISC_OSLib. */
/* */
/* It may be freely used to create executable images for saleable */
/* products but cannot be sold in source form or as an object library */
/* without the prior written consent of Acorn Computers Ltd. */
/* */
/* If this file is re-distributed (even if modified) it should retain */
/* this copyright notice. */
/* */
/************************************************************************/
/* Title: c.flex
* Purpose: provide memory allocation for interactive programs requiring
* large chunks of store.
* History: IDJ: 06-Feb-92: prepared for source release
* Andy Armstrong: 21-Oct-94: modified to use dynamic areas and callbacks.
* David Jackson : 06-Sep-95: modified to use Virtual Memory
* David Jackson : 19-Apr-96: modified to use Acorn Toolbox (Ugh!)
*/
#define BOOL int
#define TRUE 1
#define FALSE 0
#define TRACE 0
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <stdio.h>
#include "kernel.h"
#include "swis.h"
#include "h.flex"
#include "wimplib.h"
/* #include "tracker.h" */
#ifndef OS_DynamicArea
#define OS_DynamicArea 0x00066
#endif
#ifndef Virtualise_Configure
#define Virtualise_Configure 0x04b6c0
#endif
#ifndef Virtualise_Start
#define Virtualise_Start 0x04b6c1
#endif
#ifndef Virtualise_End
#define Virtualise_End 0x04b6c2
#endif
#ifndef Virtualise_Lock
#define Virtualise_Lock 0x04b6c3
#endif
#ifndef Virtualise_Unlock
#define Virtualise_Unlock 0x04b6c4
#endif
#ifndef Virtualise_MiscOp
#define Virtualise_MiscOp 0x04b6c5
#endif
static int flex__initialised = 0;
static int flex__da = -1; /* or da number */
static BOOL flex__VM = FALSE; /* is VM in use? */
static int _mblk;
static void werr(int fatal, char* format, ...);
static char* msgs_lookup(char* tag);
/* This implementation goes above the original value of GetEnv,
to memory specifically requested from the Wimp. The heap is kept
totally compacted all the time, with pages being given back to
the Wimp whenever possible. */
typedef struct {
flex_ptr anchor; /* *anchor should point back to here. */
#ifdef flex_CALLBACK
flex_cbfunc cb;
void *handle;
#endif
int size; /* in bytes. Exact size of logical area. */
/* then the actual store follows. */
} flex__rec;
static void flex__fail(int i)
{
werr(TRUE, msgs_lookup("flex1:Flex memory error (%d)"), i);
#if TRACE
i = *(int *)-4 ; /* go bang! */
#else
i = i; /* avoid compiler warning. */
#endif
}
static void flex__check(void)
{
if(flex__initialised == 0)
werr(TRUE, msgs_lookup("flex3:Flex not initialised"));
}
/* macro to avoid stack usage */
#define roundup(n) (0xfffffffc & (n + 3))
static char *flex__base; /* lowest flex__rec - only for budging. */
static char *flex__freep; /* free flex memory */
static char *flex__lim; /* limit of flex memory */
/* From base upwards, it's divided into store blocks of
a flex__rec
the space
align up to next word.
*/
static void flex__wimpslot(char **top)
{
/* read/write the top of available memory. *top == 0 -> just read. */
int dud = -1;
int slot = ((int) *top);
_kernel_swi_regs r;
_kernel_oserror *err;
int memlim, appspace, oldmemlim;
if (slot != -1) slot -= 0x8000;
/* read memory limit value */
r.r[0] = 0;
r.r[1] = 0;
r.r[2] = 0;
err = _kernel_swi(OS_ChangeEnvironment, &r, &r);
oldmemlim = memlim = r.r[1];
/* read appspace value */
r.r[0] = 14; /* Application space */
r.r[1] = 0;
r.r[2] = 0;
err = _kernel_swi(OS_ChangeEnvironment, &r, &r);
appspace = r.r[1];
/* set memory limit before slot size change ... */
if(appspace > memlim)
{
r.r[0] = 0;
r.r[1] = appspace;
r.r[2] = 0;
err = _kernel_swi(OS_ChangeEnvironment, &r, &r);
}
/* set wimpslot size (or read it) */
if (wimp_slot_size(slot,dud,&slot, &dud, &dud)!=NULL) werr(TRUE,msgs_lookup("fatal:Fatal Flex memory error"));
*top = (char*) slot + 0x8000;
/* .... and set memory limit back again */
if (appspace > memlim)
{
r.r[0] = 0;
r.r[1] = oldmemlim;
r.r[2] = 0;
err = _kernel_swi(OS_ChangeEnvironment, &r, &r);
}
}
static BOOL flex__more(int n)
{
/* Tries to get at least n more bytes, raising flex__lim and
returning TRUE if it can. */
char *prev = flex__lim;
if (flex__da != -1)
{ _kernel_swi_regs regs;
_kernel_oserror *err;
regs.r[0] = flex__da;
regs.r[1] = n;
err = _kernel_swi(OS_ChangeDynamicArea, ®s, ®s);
if (err || regs.r[1] < n)
{ regs.r[1] = -regs.r[1];
_kernel_swi(OS_ChangeDynamicArea, ®s, ®s);
return FALSE;
}
err = _kernel_swi(OS_ReadDynamicArea, ®s, ®s);
flex__lim = flex__base + regs.r[1];
return TRUE;
}
else
{ flex__lim += n;
flex__wimpslot(&flex__lim);
if (flex__lim < prev + n)
{
flex__lim = prev; /* restore starting state:
extra memory is useless */
flex__wimpslot(&flex__lim);
return FALSE ;
}
else
return TRUE ;
}
}
static void flex__give(void)
{
if (flex__da != -1)
{ _kernel_swi_regs regs;
_kernel_oserror *err;
regs.r[0] = flex__da;
regs.r[1] = flex__freep - flex__lim; /* -ve */
err = _kernel_swi(OS_ChangeDynamicArea, ®s, ®s);
if (!err)
{ err = _kernel_swi(OS_ReadDynamicArea, ®s, ®s);
flex__lim = flex__base + regs.r[1];
}
}
else
{
/* Gives away memory, lowering flex__lim, if possible. */
#if TRACE
int prev = (int) flex__lim;
#endif
flex__lim = flex__freep;
flex__wimpslot(&flex__lim);
}
}
static BOOL flex__ensure(int n)
{
n -= flex__lim - flex__freep;
if (n <= 0 || flex__more(n))
return TRUE;
else return FALSE;
}
BOOL flex_alloc(flex_ptr anchor, int n)
{
flex__rec *p;
flex__check();
if (n < 0 || ! flex__ensure(sizeof(flex__rec) + roundup(n)))
{
*anchor = 0;
return FALSE;
}
p = (flex__rec*) flex__freep;
flex__freep += sizeof(flex__rec) + roundup(n);
p->anchor = anchor;
p->size = n;
#ifdef flex_CALLBACK
p->cb = NULL;
p->handle = NULL;
#endif
*anchor = p + 1; /* sizeof(flex__rec), that is */
return TRUE;
}
static void flex__reanchor(flex__rec *p, int by)
{
/* Move all the anchors from p upwards. This is in anticipation
of that block of the heap being shifted. */
while (1)
{
if ((int) p >= (int) flex__freep) break;
if (*(p->anchor) != p + 1) flex__fail(6);
*(p->anchor) = ((char*) (p + 1)) + by;
p = (flex__rec*) (((char*) (p + 1)) + roundup(p->size));
}
}
/* Notify all the blocks after and including p that the are about to move / have
moved */
#ifdef flex_CALLBACK
#define flex__inlinenotify(b4, p) \
do \
{ flex__rec *p2 = (p); \
for (;;) \
{ if ((int) p2 >= (int) flex__freep) break; \
if (*(p2->anchor) != p2 + 1) flex__fail(6); \
if (p2->cb) p2->cb(b4, p2->handle); \
p2 = (flex__rec*) (((char*) (p2 + 1)) + roundup(p2->size)); \
} \
} while (0)
static void flex__notify(BOOL b4, flex__rec *p)
{ flex__inlinenotify(b4, p);
}
#else
#define flex__inlinenotify(b4, p) (void) 0
#define flex__notify(b4, p) (void) 0
#endif
void flex_free(flex_ptr anchor)
{
flex__rec *p = ((flex__rec*) *anchor) - 1;
int roundsize = roundup(p->size);
flex__rec *next = (flex__rec*) (((char*) (p + 1)) + roundsize);
flex__check();
if (p->anchor != anchor)
{
flex__fail(0);
}
flex__notify(TRUE, next);
flex__reanchor(next, - (sizeof(flex__rec) + roundsize));
memmove(p, next, flex__freep - (char*) next);
flex__freep -= sizeof(flex__rec) + roundsize;
flex__notify(FALSE, p);
flex__give();
*anchor = 0;
}
int flex_size(flex_ptr anchor)
{
flex__rec *p = ((flex__rec*) *anchor) - 1;
flex__check();
if (p->anchor != anchor)
{
flex__fail(4);
}
return(p->size);
}
int flex_extend(flex_ptr anchor, int newsize)
{
flex__rec *p = ((flex__rec*) *anchor) - 1;
flex__check();
return(flex_midextend(anchor, p->size, newsize - p->size));
}
BOOL flex_midextend(flex_ptr anchor, int at, int by)
{
flex__rec *p;
flex__rec *next;
flex__check();
p = ((flex__rec*) *anchor) - 1;
if (p->anchor != anchor)
flex__fail(1);
if (at > p->size)
flex__fail(2);
if (by < 0 && (-by) > at)
flex__fail(3);
if (by == 0)
{
/* do nothing */
}
else if (by > 0)
{
/* extend */
int growth = roundup(p->size + by) - roundup(p->size);
/* Amount by which the block will actually grow. */
if (! flex__ensure(growth))
return FALSE;
next = (flex__rec*) (((char*) (p + 1)) + roundup(p->size));
/* The move has to happen in two parts because the moving
of objects above is word-aligned, while the extension within
the object may not be. */
flex__notify(TRUE, next);
flex__reanchor(next, growth);
memmove(((char*) next) + roundup(growth), next, flex__freep - (char*) next
);
flex__freep += growth;
flex__notify(FALSE, (flex__rec *) (((char *) next) + roundup(growth)));
memmove(((char*) (p + 1)) + at + by, ((char*) (p + 1)) + at, p->size - at)
;
p->size += by;
}
else
{
/* The block shrinks. */
int shrinkage;
next = (flex__rec*) (((char*) (p + 1)) + roundup(p->size));
by = -by; /* a positive value now */
shrinkage = roundup(p->size) - roundup(p->size - by);
/* a positive value */
memmove(((char*) (p + 1)) + at - by, ((char*) (p + 1)) + at, p->size - at)
;
p->size -= by;
flex__notify(TRUE, next);
flex__reanchor(next, - shrinkage);
memmove(((char*) next) - shrinkage, next, flex__freep - (char*) next);
flex__freep -= shrinkage;
flex__notify(FALSE, (flex__rec *) (((char *) next) - shrinkage));
flex__give();
}
return TRUE;
}
#ifdef flex_CALLBACK
void flex_register(flex_ptr anchor, flex_cbfunc cb, void *handle)
{ flex__rec *p = ((flex__rec*) *anchor) - 1;
flex__check();
if (p->anchor != anchor)
{
flex__fail(4);
}
p->cb = cb;
p->handle = handle;
}
#endif
/* stack checking off */
#pragma -s1
/* The underlying system asks us to move all flex store up (if n +ve) or
down by n bytes. If you succeed, put the store allocated in *a and return
the size. size >= roundup(n) on successful exit, and will be a multiple of
four. If you fail, return what we can.
If n is -ve, no result is required: success is assumed.
*/
extern int flex_budge(int n, void **a)
{ if (flex__da != -1)
return flex_dont_budge(n, a);
flex__inlinenotify(TRUE, (flex__rec *) flex__base);
if (n >= 0) /* all moving up */
{
int roundupn = roundup(n);
int more = roundupn - (flex__lim - flex__freep);
/* try to satisfy the request */
if (more > 0) /* ie we have to increase slot */
{
char *prev = flex__lim;
flex__lim += more;
/* in-line implementation (of flex__wimpslot) */
/* to reduce stack requirements */
{
int slot = ((int) flex__lim);
_kernel_swi_regs r;
_kernel_oserror *err;
int memlim, appspace, oldmemlim;
if (slot != -1)
slot -= 0x8000;
/* read memory limit value */
r.r[0] = 0;
r.r[1] = 0;
r.r[2] = 0;
err = _kernel_swi(OS_ChangeEnvironment, &r, &r);
oldmemlim = memlim = r.r[1];
/* read appspace value */
r.r[0] = 14; /* Application space */
r.r[1] = 0;
r.r[2] = 0;
err = _kernel_swi(OS_ChangeEnvironment, &r, &r);
appspace = r.r[1];
/* set memory limit before slot size change ... */
if(appspace > memlim)
{
r.r[0] = 0;
r.r[1] = appspace;
r.r[2] = 0;
err = _kernel_swi(OS_ChangeEnvironment, &r, &r);
}
/* set wimpslot size */
r.r[0] = slot;
r.r[1] = -1;
err =_kernel_swi(Wimp_SlotSize, &r, &r);
slot = r.r[0];
flex__lim = (char*) slot + 0x8000;
/* .... and set memory limit back again */
if (appspace > memlim)
{
r.r[0] = 0;
r.r[1] = oldmemlim;
r.r[2] = 0;
err = _kernel_swi(OS_ChangeEnvironment, &r, &r);
}
}
/* if we couldn't satisfy it, still give back what we can, */
/* _kernel_alloc may be able to use it!!!!! */
if (flex__lim < prev + more)
roundupn = flex__lim - flex__freep; /*all we got*/
}
{
flex__rec *p = (flex__rec*)flex__base;
while (1) {
if ((int) p >= (int) flex__freep) break;
*(p->anchor) = ((char*) (p + 1)) + roundupn;
p = (flex__rec*) (((char*) (p + 1)) + roundup(p->size));
}
}
memmove(flex__base + roundupn, flex__base, flex__freep - flex__base);
*a = flex__base;
flex__base += roundupn;
flex__freep += roundupn;
flex__inlinenotify(FALSE, (flex__rec *) flex__base);
return(roundupn);
}
else
{
/* all moving down */
int roundupn = roundup(-n); /* a +ve value */
{
flex__rec *p = (flex__rec*)flex__base;
while (1)
{
if ((int) p >= (int) flex__freep) break;
*(p->anchor) = ((char*) (p + 1)) + roundupn;
p = (flex__rec*) (((char*) (p + 1)) + roundup(p->size));
}
}
memmove(flex__base - roundupn, flex__base, flex__freep - flex__base);
flex__base -= roundupn;
flex__freep -= roundupn;
flex__inlinenotify(FALSE, (flex__rec *) flex__base);
}
return(0);
}
extern int flex_dont_budge(int n, void **a)
{ n = n;
a = a;
return 0;
}
/* stack checks on again */
#pragma -s0
static void flex__exit(void)
{ _kernel_swi_regs regs;
if (flex__da != -1)
{ regs.r[0] = 1;
regs.r[1] = flex__da;
_kernel_swi(OS_DynamicArea, ®s, ®s);
}
}
void flex_initx(char *program_name, int *error_fd,int da,int maxsize,BOOL virtualise)
{ flex__lim = (char *) -1;
_mblk=(int)error_fd;
if (da) /* try to create a DA */
{ _kernel_oserror *err;
_kernel_swi_regs regs;
regs.r[0] = 0; /* create DA */
regs.r[1] = -1; /* area number */
regs.r[2] = 0; /* initial size */
regs.r[3] = -1; /* logical address */
regs.r[4] = 0x80; /* access privileges */
regs.r[5] = maxsize; /* max size */
if (virtualise) /*DJ */
{ /*DJ */
regs.r[4] = regs.r[4] | (1U <<31); /*DJ */
regs.r[5]=maxsize; /*DJ */
/*DJ */
} /*DJ */
regs.r[6] = 0; /* no routine yet */
regs.r[7] = 0; /* ws pointer */
regs.r[8] = (int) program_name; /* area name */
err = _kernel_swi(OS_DynamicArea, ®s, ®s);
if (!err)
{ flex__da = regs.r[1];
flex__freep = flex__lim = flex__base = (char *) regs.r[3];
atexit(flex__exit);
if (virtualise)
{
_kernel_swi(OS_ReadMemMapInfo,®s,®s);
regs.r[0]=regs.r[0]*regs.r[1];
regs.r[1]=regs.r[0];
regs.r[2]=regs.r[0]*.05;
_kernel_swi(Virtualise_Configure,®s,®s);
flex__VM=TRUE;
}
goto initok;
}
}
flex__wimpslot(&flex__lim); /* shrink */
flex__freep = flex__lim;
flex__base = flex__freep;
_kernel_register_slotextend(flex_dont_budge);
initok:
flex__initialised = 1;
/* Check that we're in the Wimp environment. */
{
void *a;
if (! flex_alloc(&a, 1))
werr(TRUE, msgs_lookup("flex2:Not enough memory, or not within *desktop world."));
flex_free(&a);
}
}
/* default flex_init() disables use of DA */
void flex_init(char *program_name, int *error_fd)
{ flex_initx(program_name,error_fd,FALSE,-1,FALSE /* DJ 060995 */);
}
int flex_isdynamic(void)
{ return flex__da != -1;
}
BOOL flex_isVM(void)
{
return flex__VM;
}
_kernel_oserror * flex_VMConfigure(int def,int cache,int left)
{
_kernel_swi_regs regs;
regs.r[0]=def;
regs.r[1]=cache;
regs.r[2]=left;
return _kernel_swi(Virtualise_Configure,®s,®s);
}
_kernel_oserror * flex_readVMConfigure(int * def ,int *cache,int *left)
{
_kernel_oserror *err;
_kernel_swi_regs regs;
regs.r[0]=-1;
regs.r[1]=-1;
regs.r[2]=-1;
err=_kernel_swi(Virtualise_Configure,®s,®s);
if (!err)
{
*def =regs.r[0];
*cache =regs.r[1];
*left =regs.r[2];
regs.r[0]=2;
regs.r[1]=flex__da;
_kernel_swi(OS_DynamicArea,®s,®s);
*def=regs.r[5];
}
return(err);
}
_kernel_oserror * flex_virtualstart(char * swapfile)
{
_kernel_swi_regs regs;
_kernel_oserror *err;
regs.r[0]=flex__da;
regs.r[1]=-1;
regs.r[2]=(int) swapfile;
err=_kernel_swi(Virtualise_Start,®s,®s);
if (!err) flex__VM=TRUE;
return(err);
}
_kernel_oserror * flex_virtualstop(void)
{
_kernel_swi_regs regs;
_kernel_oserror *err;
regs.r[0]=flex__da;
err=_kernel_swi(Virtualise_End,®s,®s);
if (!err) flex__VM=FALSE;
return(err);
}
_kernel_oserror * flex_lock(int start,int end)
{
_kernel_swi_regs regs;
_kernel_oserror *err=NULL;
if (flex__VM)
{
regs.r[0]=start;
regs.r[1]=end;
err=_kernel_swi(Virtualise_Lock,®s,®s);
}
return(err);
}
_kernel_oserror * flex_unlock(int start,int end)
{
_kernel_swi_regs regs;
_kernel_oserror *err=NULL;
if (flex__VM)
{
regs.r[0]=start;
regs.r[1]=end;
err=_kernel_swi(Virtualise_Unlock,®s,®s);
}
return(err);
}
static void werr(int fatal, char* format, ...)
{
va_list va;
_kernel_oserror e;
e.errnum = 0;
va_start(va, format);
vsprintf(&e.errmess[0], format, va);
va_end(va);
wimp_report_error(&e, 0, "FlexLibrary",0,0,0);
if (fatal) exit(1);
}
static char* msgs_lookup(char* tag)
{
_kernel_swi_regs regs;
char* p=tag;
while (*p++!=':') NULL;
p--;
*p++=0;
regs.r[0] = _mblk;
regs.r[1] = (int) tag;
regs.r[2] = 0;
if (_kernel_swi(MessageTrans_Lookup,®s,®s))
return p;
else return (char *) regs.r[2];
}
/* end */