home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 378.lha / MemEater_v1.0 / MemEater.c < prev    next >
C/C++ Source or Header  |  1990-05-02  |  15KB  |  512 lines

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <exec/execbase.h>
  5. #include <exec/memory.h>
  6. #include <intuition/intuition.h>
  7. #include <functions.h>
  8.  
  9. #include "MRTimer.h"
  10.  
  11. extern struct ExecBase *SysBase;
  12.  
  13. #define CHIP_WANTED_GADGET      1
  14. #define FAST_WANTED_GADGET      2
  15. #define TOTAL_WANTED_GADGET     3
  16. #define CHIP_AVAIL_GADGET       4
  17. #define FAST_AVAIL_GADGET       5
  18. #define TOTAL_AVAIL_GADGET      6
  19.  
  20.  
  21. #include "MemEater-pw.h"
  22.  
  23. /*  We represent our "held-in-reserve" blocks with the following structure. */
  24.  
  25. struct MemNode {  
  26.     struct MemNode  *next;
  27.     LONG            blockSize;
  28.     /* ... remainder of allocated memory ... */
  29.     };
  30.  
  31. /*  ReserveMem describes the entries in a given "reserve" list. */
  32.  
  33. struct MemSpecs {
  34.     ULONG           memType;        /* MEMF_CHIP or MEMF_FAST */
  35.     struct MemNode  *list;          /* list of nodes allocated */
  36.     LONG            avail;          /* amount currently available */
  37.     LONG            limit;          /* amount we want */
  38.     LONG            maximum;
  39.     };
  40.  
  41. long _stack = 4000;
  42. long _priority = 1;
  43. long _BackGroundIO;
  44. char *_procname = "MemEater Process";
  45.  
  46. struct IntuitionBase    *IntuitionBase;
  47. struct GfxBase          *GfxBase;
  48.  
  49. struct MemSpecs         chipSpecs;      /* chip memory in reserve */
  50. struct MemSpecs         fastSpecs;      /* fast memory specifications */
  51.  
  52. LONG                    minBlockSize = sizeof(struct MemNode);
  53. struct Window           *myWindow;
  54. ULONG                   myWindowBit;
  55.  
  56. struct timerequest      *timer;
  57. ULONG                   timerBit;
  58.  
  59. #ifndef min
  60. #define min(a, b) ( (a) < (b) ? (a) : (b) )
  61. #endif
  62.  
  63. /* Get the pointer to a gadget string, given a pointer to a gadget. */
  64. #define GadgetString(g) ((struct StringInfo *) ((g)->SpecialInfo))->Buffer
  65.  
  66. void    DoGadget(struct Gadget *theGadget);
  67. void    FreeSome(struct MemSpecs *spec, LONG newLimit);
  68. void    GrabMem(struct MemSpecs *spec);
  69. void    InitSpecs(struct MemSpecs *specs, ULONG memType);
  70. LONG    MaxSize(LONG t);
  71. void    ReleaseMem(struct MemSpecs *specs);
  72. void    ResetStringInfo(struct StringInfo *s);
  73. void    SetNumberGadget(struct Gadget *gadget, LONG value);
  74. void    SetStringGadget(struct Gadget *gadget, 
  75.                         struct Window *window, 
  76.                         struct Requester *requester, 
  77.                         const char *s);
  78. void    Update(void);
  79.  
  80.  
  81. main(int argc, char **argv)
  82. {
  83.     static char *noTimerMsg =       "MemEater: can't create timer!\n";
  84.     static char *noWindowMsg =      "MemEater: can't open my window!\n";
  85.     static char *whereIntuition =   "MemEater: where is intuition.library?\n";
  86.     static char *whereGraphics =    "MemEater: where is graphics.library?\n";
  87.  
  88.     ULONG               bits;       /* returned by Wait() */
  89.     LONG                class;
  90.     struct Gadget       *gadget;
  91.     struct IntuiMessage *msg;
  92.     BOOL                quit = FALSE;
  93.     struct RastPort     *rp;
  94.  
  95.     IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library", 0L);
  96.     if (IntuitionBase == NULL) {
  97.         Write(Output(), whereIntuition, sizeof(whereIntuition));
  98.         exit(1);
  99.     }
  100.     
  101.     GfxBase = (struct GfxBase *) OpenLibrary("graphics.library", 0L);
  102.     if (GfxBase == NULL) {
  103.         Write(Output(), whereGraphics, sizeof(whereGraphics));
  104.         exit(1);
  105.     }
  106.  
  107.     timer = CreateTimer(1);             /* Use VBLANK timer. */
  108.     if (! timer ) {
  109.         Write(Output(), noTimerMsg, sizeof(noTimerMsg));
  110.         exit(1);
  111.     }
  112.  
  113.     myWindow = OpenWindow(&NewWindowStructure1);
  114.  
  115.     if (! myWindow) {
  116.         Write(Output(), noWindowMsg, sizeof(noWindowMsg));
  117.         exit(1);
  118.     }
  119.     rp = myWindow->RPort;
  120.  
  121.     PrintIText(rp, &IntuiTextList1, 0L, 0L);
  122.  
  123.     
  124.     /* Get system maximums. We should only have to do this once. If the user pulls
  125.      * an AddMem behind our backs, he'll have to restart us. T. S.
  126.      */
  127.  
  128.     InitSpecs(&chipSpecs, MEMF_CHIP);
  129.     InitSpecs(&fastSpecs, MEMF_FAST);
  130.  
  131.     SetNumberGadget(&chipWantedGadget, chipSpecs.limit / 1024L);
  132.     SetNumberGadget(&fastWantedGadget, fastSpecs.limit / 1024L);
  133.     SetNumberGadget(&totalWantedGadget, (chipSpecs.limit + fastSpecs.limit) / 1024L);
  134.  
  135.     myWindowBit = (1L << myWindow->UserPort->mp_SigBit);
  136.     timerBit = (1L << timer->tr_node.io_Message.mn_ReplyPort->mp_SigBit);
  137.  
  138.     while (! quit ) {
  139.         StartTimer(timer, 0L, 500000L);     /* Start 1/2 second timer. */ 
  140.         bits = Wait(myWindowBit | timerBit);
  141.         if (! bits & timerBit)
  142.             StopTimer(timer);
  143.         else 
  144.             WaitIO(&timer->tr_node);
  145.         
  146.         chipSpecs.avail = AvailMem(MEMF_CHIP);
  147.         fastSpecs.avail = AvailMem(MEMF_FAST);
  148.  
  149.         if (bits & myWindowBit) {
  150.             while (msg  = (struct IntuiMessage *) GetMsg(myWindow->UserPort)) {
  151.                 class = msg->Class;
  152.                 gadget = (struct Gadget *) msg->IAddress;
  153.         
  154.                 ReplyMsg( (struct Message *) msg);
  155.                 if (class == CLOSEWINDOW) {
  156.                     quit = TRUE;
  157.                     break;
  158.                 }
  159.  
  160.                 if (class == GADGETUP) {
  161.                     DoGadget(gadget);
  162.                     continue;
  163.                 }
  164.                 
  165.                 if (class == WINDOWREFRESH) {
  166.                     BeginRefresh(myWindow);
  167.                     EndRefresh(myWindow, TRUE);
  168.                 }
  169.             }
  170.         }
  171.         GrabMem(&chipSpecs);
  172.         GrabMem(&fastSpecs);
  173.         Update();
  174.     }
  175.  
  176.     ReleaseMem(&chipSpecs);
  177.     ReleaseMem(&fastSpecs);
  178.     CloseWindow(myWindow);
  179.     DeleteTimer(timer);
  180. }
  181.  
  182. /*  FUNCTION
  183.  *      DoGadget - process gadget event.
  184.  *
  185.  *  SYNOPSIS
  186.  *      void DoGadget(struct Gadget *theGadget);
  187.  *
  188.  *  DESCRIPTION
  189.  *      DoGadget is called whenever a gadget-related Intuition message is
  190.  *      received. There are only two gadgets that will cause messages to be
  191.  *      generated: CHIP_WANTED_GADGET and FAST_WANTED_GADGET. The value for the
  192.  *      respective gadget is verified and the display is updated, if necessary.
  193.  */
  194.  
  195. void
  196. DoGadget(struct Gadget *theGadget)
  197. {
  198.     LONG               newValue;
  199.     struct StringInfo   *si;
  200.     struct MemSpecs     *specs = NULL;
  201.     BOOL                updateTotal = FALSE;
  202.  
  203.     switch (theGadget->GadgetID) {
  204.  
  205.     case CHIP_WANTED_GADGET:
  206.         specs = &chipSpecs;
  207.         break;
  208.  
  209.     case FAST_WANTED_GADGET:
  210.         specs = &fastSpecs;
  211.         break;
  212.  
  213.     default:
  214.         break;
  215.     }
  216.  
  217.     if (specs) {
  218.         si = (struct StringInfo *) theGadget->SpecialInfo;
  219.         newValue = si->LongInt * 1024L;
  220.         if (newValue > specs->maximum) {
  221.             specs->limit = specs->maximum;
  222.             SetNumberGadget(theGadget, specs->limit / 1024L);
  223.         }
  224.         else {
  225.             /* Are we giving some back? */
  226.             if (newValue > specs->limit) FreeSome(specs, newValue);
  227.             specs->limit = newValue;
  228.             updateTotal = TRUE;
  229.         }
  230.     }
  231.  
  232.     if (updateTotal) {
  233.         SetNumberGadget(&totalWantedGadget, 
  234.             (chipSpecs.limit + fastSpecs.limit) / 1024L);
  235.     }
  236. }
  237.  
  238. /*  FUNCTION
  239.  *      FreeSome - free up some of our reserve memory.
  240.  *
  241.  *  SYNOPSIS
  242.  *      void FreeSome(struct MemSpecs *specs, LONG newLimit);
  243.  *
  244.  *  DESCRIPTION
  245.  *      FreeSome is called whenever the user ups the limit on a given class of
  246.  *      memory (described by parameter <specs>). The <newLimit> parameter defines
  247.  *      the new upper limit for the memory class.
  248.  */
  249.  
  250. void
  251. FreeSome(struct MemSpecs *specs, LONG newLimit)
  252. {
  253.     struct MemNode  *nextNode;
  254.  
  255.     while (specs->list && (newLimit > specs->limit)) {
  256.         nextNode = specs->list->next;
  257.         newLimit -= specs->list->blockSize;
  258.         FreeMem(specs->list, specs->list->blockSize);
  259.         specs->list = nextNode;
  260.     }
  261. }
  262.  
  263. /*  FUNCTION
  264.  *      GrabMem - grab memory from the system.
  265.  *
  266.  *  SYNOPSIS
  267.  *      GrabMem is called once each timer interval (or upon receipt of an
  268.  *      Intuition message) for each class of memory being maintained. If the
  269.  *      current amount of memory available for the class described by 
  270.  *      <specs> exceeds the desired limit, memory is "consumed", preserving
  271.  *      the limit.
  272.  */
  273.  
  274. void
  275. GrabMem(struct MemSpecs *specs)
  276. {
  277.     LONG            blockSize;
  278.     LONG            diff;
  279.     LONG            largest;
  280.     struct MemNode  *node;
  281.  
  282.     while ((diff = (specs->avail - specs->limit)) > minBlockSize) {
  283.  
  284.         /* What's the largest block available? */
  285.         largest = AvailMem(specs->memType | MEMF_LARGEST);
  286.     
  287.         /* Figure the size that we need. */
  288.         blockSize = min(diff, largest);
  289.  
  290.         /* If it's less than the size of a MemNode, just forget it. */
  291.         if (blockSize < minBlockSize)
  292.             break;
  293.  
  294.         node = AllocMem(blockSize, specs->memType); /* Grab the block. */
  295.         if (! node) break;                          /* Something went very wrong. */
  296.  
  297.         node->blockSize = blockSize;
  298.         node->next = specs->list;
  299.         specs->list = node;
  300.         specs->avail = AvailMem(specs->memType);    /* Reassess available memory. */
  301.     }
  302. }
  303.  
  304. /*  FUNCTION
  305.  *      InitSpecs - initialize a memory specifications packet.
  306.  *
  307.  *  SYNOPSIS
  308.  *      void InitSpecs(struct MemSpecs *specs, ULONG memType);
  309.  *
  310.  *  DESCRIPTION
  311.  *      InitSpecs initializes a memory specifications packet with information
  312.  *      pertinent to the class of memory defined by <memType>.
  313.  */
  314.  
  315. void
  316. InitSpecs(struct MemSpecs *specs, ULONG memType)
  317. {
  318.     specs->memType = memType;
  319.     specs->avail = AvailMem(memType);
  320.     Forbid();
  321.     specs->maximum = MaxSize(memType);
  322.     Permit();
  323.     specs->limit = specs->maximum;
  324.     specs->list = NULL;
  325. }
  326.  
  327. /*  FUNCTION
  328.  *      MaxSize - determine maximum memory available for a given type
  329.  *
  330.  *  SYNOPSIS
  331.  *      LONG MaxSize(LONG t);
  332.  *
  333.  *  DESCRIPTION
  334.  *      MaxSize determines the maximum amount of memory available for a given
  335.  *      class (MEMF_CHIP or MEMF_FAST) as defined by <t>. MaxSize must be bracketed
  336.  *        by calls to Forbid/Permit since system structures are accessed.
  337.  *
  338.  *  CREDITS
  339.  *      This code was lifted from the "avail" program.
  340.  */
  341.  
  342. LONG
  343. MaxSize (LONG t)
  344. {
  345.     /* THIS CODE MUST ALWAYS BE CALLED WHILE FORBIDDEN */
  346.     LONG               size = 0;
  347.     struct MemHeader    *mem;
  348.     struct ExecBase     *eb = SysBase;
  349.  
  350.     for (mem = (struct MemHeader *)eb->MemList.lh_Head;
  351.          mem->mh_Node.ln_Succ;
  352.          mem = (struct MemHeader *)mem->mh_Node.ln_Succ) {
  353.         if (mem -> mh_Attributes & t) {
  354.             size += ((LONG) mem -> mh_Upper - (LONG) mem -> mh_Lower);
  355.         }
  356.     }
  357.  
  358.     return size;
  359. }
  360.  
  361. /*  FUNCTION
  362.  *      ReleaseMem - release all memory for a given class.
  363.  *
  364.  *  SYNOPSIS
  365.  *      void ReleaseMem(struct MemSpecs *specs);
  366.  *
  367.  *  DESCRIPTION
  368.  *      ReleaseMem is called at program termination to free up all memory consumed
  369.  *      by this program.
  370.  */
  371.  
  372. void
  373. ReleaseMem(struct MemSpecs *specs)
  374. {
  375.     specs->limit = 0;
  376.     FreeSome(specs, 0x7fffffff);
  377. }
  378.  
  379.  
  380. /*  FUNCTION
  381.         ResetStringInfo - reset information in a StringInfo structure.
  382.  
  383.     SYNOPSIS
  384.         void ResetStringInfo(struct StringInfo *s);
  385.  
  386.     DESCRIPTION
  387.         ResetStringInfo resets certain parameters in the StringInfo
  388.         structure pointed to by <s>, including:
  389.  
  390.             UndoBuffer
  391.             DispPos
  392.             UndoPos
  393.             NumChars
  394. */
  395. void
  396. ResetStringInfo(struct StringInfo *s)
  397. {
  398.     *(s->UndoBuffer) = '\0';
  399.     s->BufferPos = 0;
  400.     s->DispPos = 0;
  401.     s->UndoPos = 0;
  402.     s->NumChars = strlen((char *) s->Buffer);
  403. }
  404.  
  405. /*  FUNCTION
  406.  *      SetNumberGadget - update the contents of a numerical gadget.
  407.  *
  408.  *  SYNOPSIS
  409.  *      void SetNumberGadget(struct Gadget *gadget, LONG value);
  410.  *
  411.  *  DESCRIPTION
  412.  *      SetNumberGadget provides an economical way to update the contents of
  413.  *      number (string) gadgets without requiring runtime library support. It
  414.  *      calls SetStringGadget to actually change the gadget's contents.
  415.  */
  416.  
  417. void
  418. SetNumberGadget(struct Gadget *gadget, LONG value)
  419. {
  420.     int     digitCount = 0;
  421.     char    digits[12];
  422.     char    numString[12], *ns;
  423.  
  424.     do {
  425.         digits[digitCount++] = (value % 10) + '0';
  426.         value /= 10;
  427.     } while (value > 0);
  428.  
  429.     ns = numString;
  430.     while (--digitCount >= 0) {
  431.         *ns++ = digits[digitCount];
  432.     }
  433.  
  434.     *ns = '\0';                         /* Add terminating null. */
  435.     SetStringGadget(gadget, myWindow, NULL, numString);
  436. }
  437.  
  438. /*  FUNCTION
  439.         SetStringGadget - set the value of a string gadget.
  440.  
  441.     SYNOPSIS
  442.         void SetStringGadget(gadget, window, requester, s)
  443.              struct Gadget      *gadget;
  444.              struct Window      *window;
  445.              struct Requester   *requester;
  446.              const char         *s;
  447.  
  448.     DESCRIPTION
  449.         SetStringGadget sets the string value of a <gadget>, which
  450.         belongs to <window>, to the character string pointed to by <s>.
  451.         It does this in a "polite" way, first removing the gadget from
  452.         the list, modifying it, then adding it back and refreshing the
  453.         gadget list. 
  454.  
  455.         If the <gadget> belongs to a requester, <requester> must contain
  456.         the address of that requester.  Otherwise, it must be NULL.
  457.  
  458.         If <window> is NULL, the gadget is modified without attempting
  459.         to remove/restore it to/from a window gadget list.
  460. */
  461. void
  462. SetStringGadget(gadget, window, requester, s)
  463.     struct Gadget       *gadget;
  464.     struct Window       *window;
  465.     struct Requester    *requester;
  466.     const char          *s;
  467. {
  468.     char    *gs;                        /* pointer to gadget's text */
  469.     int     max;
  470.     ULONG   position;
  471.     struct StringInfo *sInfo;
  472.     char    *s1;
  473.  
  474.     /* Make sure we are trying to modify a string gadget. If we aren't,
  475.      * just don't do anything.
  476.      */
  477.     if (gadget->GadgetType & STRGADGET) {
  478.         gs = (char *) GadgetString(gadget);
  479.         sInfo = (struct StringInfo *) (gadget->SpecialInfo);
  480.         max = sInfo->MaxChars;
  481.         if (window)
  482.             position = RemoveGList(window, gadget, 1L);
  483.         strncpy(gs, s, max);            /* Don't exceed gadget capacity. */
  484.         if (s1 = strchr(gs, '\n'))      /* Eliminate newline characters. */
  485.             *s1 = '\0';
  486.         ResetStringInfo(sInfo);
  487.         if (window) {
  488.             AddGList(window, gadget, position, 1L, requester);
  489.             RefreshGList(gadget, window, requester, 1L);
  490.         }
  491.     }
  492. }
  493.  
  494. /*  FUNCTION
  495.  *      Update - update the "Current" information in our display window.
  496.  *
  497.  *  SYNOPSIS
  498.  *      void Update(void);
  499.  *
  500.  *  DESCRIPTION
  501.  *      Update is called periodically to refresh the display window's "Current"
  502.  *      information.
  503.  */
  504.  
  505. void
  506. Update(void)
  507. {
  508.     SetNumberGadget(&chipAvailGadget, chipSpecs.avail / 1024L);
  509.     SetNumberGadget(&fastAvailGadget, fastSpecs.avail / 1024L);
  510.     SetNumberGadget(&totalAvailGadget, (chipSpecs.avail + fastSpecs.avail) / 1024L);    
  511. }
  512.