home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Club Amiga de Montreal - CAM
/
CAM_CD_1.iso
/
files
/
378.lha
/
MemEater_v1.0
/
MemEater1
/
MemEater.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-05-02
|
15KB
|
512 lines
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <exec/execbase.h>
#include <exec/memory.h>
#include <intuition/intuition.h>
#include <functions.h>
#include "MRTimer.h"
extern struct ExecBase *SysBase;
#define CHIP_WANTED_GADGET 1
#define FAST_WANTED_GADGET 2
#define TOTAL_WANTED_GADGET 3
#define CHIP_AVAIL_GADGET 4
#define FAST_AVAIL_GADGET 5
#define TOTAL_AVAIL_GADGET 6
#include "MemEater-pw.h"
/* We represent our "held-in-reserve" blocks with the following structure. */
struct MemNode {
struct MemNode *next;
LONG blockSize;
/* ... remainder of allocated memory ... */
};
/* ReserveMem describes the entries in a given "reserve" list. */
struct MemSpecs {
ULONG memType; /* MEMF_CHIP or MEMF_FAST */
struct MemNode *list; /* list of nodes allocated */
LONG avail; /* amount currently available */
LONG limit; /* amount we want */
LONG maximum;
};
long _stack = 4000;
long _priority = 1;
long _BackGroundIO;
char *_procname = "MemEater Process";
struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct MemSpecs chipSpecs; /* chip memory in reserve */
struct MemSpecs fastSpecs; /* fast memory specifications */
LONG minBlockSize = sizeof(struct MemNode);
struct Window *myWindow;
ULONG myWindowBit;
struct timerequest *timer;
ULONG timerBit;
#ifndef min
#define min(a, b) ( (a) < (b) ? (a) : (b) )
#endif
/* Get the pointer to a gadget string, given a pointer to a gadget. */
#define GadgetString(g) ((struct StringInfo *) ((g)->SpecialInfo))->Buffer
void DoGadget(struct Gadget *theGadget);
void FreeSome(struct MemSpecs *spec, LONG newLimit);
void GrabMem(struct MemSpecs *spec);
void InitSpecs(struct MemSpecs *specs, ULONG memType);
LONG MaxSize(LONG t);
void ReleaseMem(struct MemSpecs *specs);
void ResetStringInfo(struct StringInfo *s);
void SetNumberGadget(struct Gadget *gadget, LONG value);
void SetStringGadget(struct Gadget *gadget,
struct Window *window,
struct Requester *requester,
const char *s);
void Update(void);
main(int argc, char **argv)
{
static char *noTimerMsg = "MemEater: can't create timer!\n";
static char *noWindowMsg = "MemEater: can't open my window!\n";
static char *whereIntuition = "MemEater: where is intuition.library?\n";
static char *whereGraphics = "MemEater: where is graphics.library?\n";
ULONG bits; /* returned by Wait() */
LONG class;
struct Gadget *gadget;
struct IntuiMessage *msg;
BOOL quit = FALSE;
struct RastPort *rp;
IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library", 0L);
if (IntuitionBase == NULL) {
Write(Output(), whereIntuition, sizeof(whereIntuition));
exit(1);
}
GfxBase = (struct GfxBase *) OpenLibrary("graphics.library", 0L);
if (GfxBase == NULL) {
Write(Output(), whereGraphics, sizeof(whereGraphics));
exit(1);
}
timer = CreateTimer(1); /* Use VBLANK timer. */
if (! timer ) {
Write(Output(), noTimerMsg, sizeof(noTimerMsg));
exit(1);
}
myWindow = OpenWindow(&NewWindowStructure1);
if (! myWindow) {
Write(Output(), noWindowMsg, sizeof(noWindowMsg));
exit(1);
}
rp = myWindow->RPort;
PrintIText(rp, &IntuiTextList1, 0L, 0L);
/* Get system maximums. We should only have to do this once. If the user pulls
* an AddMem behind our backs, he'll have to restart us. T. S.
*/
InitSpecs(&chipSpecs, MEMF_CHIP);
InitSpecs(&fastSpecs, MEMF_FAST);
SetNumberGadget(&chipWantedGadget, chipSpecs.limit / 1024L);
SetNumberGadget(&fastWantedGadget, fastSpecs.limit / 1024L);
SetNumberGadget(&totalWantedGadget, (chipSpecs.limit + fastSpecs.limit) / 1024L);
myWindowBit = (1L << myWindow->UserPort->mp_SigBit);
timerBit = (1L << timer->tr_node.io_Message.mn_ReplyPort->mp_SigBit);
while (! quit ) {
StartTimer(timer, 0L, 500000L); /* Start 1/2 second timer. */
bits = Wait(myWindowBit | timerBit);
if (! bits & timerBit)
StopTimer(timer);
else
WaitIO(&timer->tr_node);
chipSpecs.avail = AvailMem(MEMF_CHIP);
fastSpecs.avail = AvailMem(MEMF_FAST);
if (bits & myWindowBit) {
while (msg = (struct IntuiMessage *) GetMsg(myWindow->UserPort)) {
class = msg->Class;
gadget = (struct Gadget *) msg->IAddress;
ReplyMsg( (struct Message *) msg);
if (class == CLOSEWINDOW) {
quit = TRUE;
break;
}
if (class == GADGETUP) {
DoGadget(gadget);
continue;
}
if (class == WINDOWREFRESH) {
BeginRefresh(myWindow);
EndRefresh(myWindow, TRUE);
}
}
}
GrabMem(&chipSpecs);
GrabMem(&fastSpecs);
Update();
}
ReleaseMem(&chipSpecs);
ReleaseMem(&fastSpecs);
CloseWindow(myWindow);
DeleteTimer(timer);
}
/* FUNCTION
* DoGadget - process gadget event.
*
* SYNOPSIS
* void DoGadget(struct Gadget *theGadget);
*
* DESCRIPTION
* DoGadget is called whenever a gadget-related Intuition message is
* received. There are only two gadgets that will cause messages to be
* generated: CHIP_WANTED_GADGET and FAST_WANTED_GADGET. The value for the
* respective gadget is verified and the display is updated, if necessary.
*/
void
DoGadget(struct Gadget *theGadget)
{
LONG newValue;
struct StringInfo *si;
struct MemSpecs *specs = NULL;
BOOL updateTotal = FALSE;
switch (theGadget->GadgetID) {
case CHIP_WANTED_GADGET:
specs = &chipSpecs;
break;
case FAST_WANTED_GADGET:
specs = &fastSpecs;
break;
default:
break;
}
if (specs) {
si = (struct StringInfo *) theGadget->SpecialInfo;
newValue = si->LongInt * 1024L;
if (newValue > specs->maximum) {
specs->limit = specs->maximum;
SetNumberGadget(theGadget, specs->limit / 1024L);
}
else {
/* Are we giving some back? */
if (newValue > specs->limit) FreeSome(specs, newValue);
specs->limit = newValue;
updateTotal = TRUE;
}
}
if (updateTotal) {
SetNumberGadget(&totalWantedGadget,
(chipSpecs.limit + fastSpecs.limit) / 1024L);
}
}
/* FUNCTION
* FreeSome - free up some of our reserve memory.
*
* SYNOPSIS
* void FreeSome(struct MemSpecs *specs, LONG newLimit);
*
* DESCRIPTION
* FreeSome is called whenever the user ups the limit on a given class of
* memory (described by parameter <specs>). The <newLimit> parameter defines
* the new upper limit for the memory class.
*/
void
FreeSome(struct MemSpecs *specs, LONG newLimit)
{
struct MemNode *nextNode;
while (specs->list && (newLimit > specs->limit)) {
nextNode = specs->list->next;
newLimit -= specs->list->blockSize;
FreeMem(specs->list, specs->list->blockSize);
specs->list = nextNode;
}
}
/* FUNCTION
* GrabMem - grab memory from the system.
*
* SYNOPSIS
* GrabMem is called once each timer interval (or upon receipt of an
* Intuition message) for each class of memory being maintained. If the
* current amount of memory available for the class described by
* <specs> exceeds the desired limit, memory is "consumed", preserving
* the limit.
*/
void
GrabMem(struct MemSpecs *specs)
{
LONG blockSize;
LONG diff;
LONG largest;
struct MemNode *node;
while ((diff = (specs->avail - specs->limit)) > minBlockSize) {
/* What's the largest block available? */
largest = AvailMem(specs->memType | MEMF_LARGEST);
/* Figure the size that we need. */
blockSize = min(diff, largest);
/* If it's less than the size of a MemNode, just forget it. */
if (blockSize < minBlockSize)
break;
node = AllocMem(blockSize, specs->memType); /* Grab the block. */
if (! node) break; /* Something went very wrong. */
node->blockSize = blockSize;
node->next = specs->list;
specs->list = node;
specs->avail = AvailMem(specs->memType); /* Reassess available memory. */
}
}
/* FUNCTION
* InitSpecs - initialize a memory specifications packet.
*
* SYNOPSIS
* void InitSpecs(struct MemSpecs *specs, ULONG memType);
*
* DESCRIPTION
* InitSpecs initializes a memory specifications packet with information
* pertinent to the class of memory defined by <memType>.
*/
void
InitSpecs(struct MemSpecs *specs, ULONG memType)
{
specs->memType = memType;
specs->avail = AvailMem(memType);
Forbid();
specs->maximum = MaxSize(memType);
Permit();
specs->limit = specs->maximum;
specs->list = NULL;
}
/* FUNCTION
* MaxSize - determine maximum memory available for a given type
*
* SYNOPSIS
* LONG MaxSize(LONG t);
*
* DESCRIPTION
* MaxSize determines the maximum amount of memory available for a given
* class (MEMF_CHIP or MEMF_FAST) as defined by <t>. MaxSize must be bracketed
* by calls to Forbid/Permit since system structures are accessed.
*
* CREDITS
* This code was lifted from the "avail" program.
*/
LONG
MaxSize (LONG t)
{
/* THIS CODE MUST ALWAYS BE CALLED WHILE FORBIDDEN */
LONG size = 0;
struct MemHeader *mem;
struct ExecBase *eb = SysBase;
for (mem = (struct MemHeader *)eb->MemList.lh_Head;
mem->mh_Node.ln_Succ;
mem = (struct MemHeader *)mem->mh_Node.ln_Succ) {
if (mem -> mh_Attributes & t) {
size += ((LONG) mem -> mh_Upper - (LONG) mem -> mh_Lower);
}
}
return size;
}
/* FUNCTION
* ReleaseMem - release all memory for a given class.
*
* SYNOPSIS
* void ReleaseMem(struct MemSpecs *specs);
*
* DESCRIPTION
* ReleaseMem is called at program termination to free up all memory consumed
* by this program.
*/
void
ReleaseMem(struct MemSpecs *specs)
{
specs->limit = 0;
FreeSome(specs, 0x7fffffff);
}
/* FUNCTION
ResetStringInfo - reset information in a StringInfo structure.
SYNOPSIS
void ResetStringInfo(struct StringInfo *s);
DESCRIPTION
ResetStringInfo resets certain parameters in the StringInfo
structure pointed to by <s>, including:
UndoBuffer
DispPos
UndoPos
NumChars
*/
void
ResetStringInfo(struct StringInfo *s)
{
*(s->UndoBuffer) = '\0';
s->BufferPos = 0;
s->DispPos = 0;
s->UndoPos = 0;
s->NumChars = strlen((char *) s->Buffer);
}
/* FUNCTION
* SetNumberGadget - update the contents of a numerical gadget.
*
* SYNOPSIS
* void SetNumberGadget(struct Gadget *gadget, LONG value);
*
* DESCRIPTION
* SetNumberGadget provides an economical way to update the contents of
* number (string) gadgets without requiring runtime library support. It
* calls SetStringGadget to actually change the gadget's contents.
*/
void
SetNumberGadget(struct Gadget *gadget, LONG value)
{
int digitCount = 0;
char digits[12];
char numString[12], *ns;
do {
digits[digitCount++] = (value % 10) + '0';
value /= 10;
} while (value > 0);
ns = numString;
while (--digitCount >= 0) {
*ns++ = digits[digitCount];
}
*ns = '\0'; /* Add terminating null. */
SetStringGadget(gadget, myWindow, NULL, numString);
}
/* FUNCTION
SetStringGadget - set the value of a string gadget.
SYNOPSIS
void SetStringGadget(gadget, window, requester, s)
struct Gadget *gadget;
struct Window *window;
struct Requester *requester;
const char *s;
DESCRIPTION
SetStringGadget sets the string value of a <gadget>, which
belongs to <window>, to the character string pointed to by <s>.
It does this in a "polite" way, first removing the gadget from
the list, modifying it, then adding it back and refreshing the
gadget list.
If the <gadget> belongs to a requester, <requester> must contain
the address of that requester. Otherwise, it must be NULL.
If <window> is NULL, the gadget is modified without attempting
to remove/restore it to/from a window gadget list.
*/
void
SetStringGadget(gadget, window, requester, s)
struct Gadget *gadget;
struct Window *window;
struct Requester *requester;
const char *s;
{
char *gs; /* pointer to gadget's text */
int max;
ULONG position;
struct StringInfo *sInfo;
char *s1;
/* Make sure we are trying to modify a string gadget. If we aren't,
* just don't do anything.
*/
if (gadget->GadgetType & STRGADGET) {
gs = (char *) GadgetString(gadget);
sInfo = (struct StringInfo *) (gadget->SpecialInfo);
max = sInfo->MaxChars;
if (window)
position = RemoveGList(window, gadget, 1L);
strncpy(gs, s, max); /* Don't exceed gadget capacity. */
if (s1 = strchr(gs, '\n')) /* Eliminate newline characters. */
*s1 = '\0';
ResetStringInfo(sInfo);
if (window) {
AddGList(window, gadget, position, 1L, requester);
RefreshGList(gadget, window, requester, 1L);
}
}
}
/* FUNCTION
* Update - update the "Current" information in our display window.
*
* SYNOPSIS
* void Update(void);
*
* DESCRIPTION
* Update is called periodically to refresh the display window's "Current"
* information.
*/
void
Update(void)
{
SetNumberGadget(&chipAvailGadget, chipSpecs.avail / 1024L);
SetNumberGadget(&fastAvailGadget, fastSpecs.avail / 1024L);
SetNumberGadget(&totalAvailGadget, (chipSpecs.avail + fastSpecs.avail) / 1024L);
}