home *** CD-ROM | disk | FTP | other *** search
/ The Fred Fish Collection 1.5 / ffcollection-1-5-1992-11.iso / ff_disks / 200-299 / ff240.lzh / MemLib / mwcontrol.c < prev    next >
C/C++ Source or Header  |  1989-08-28  |  9KB  |  359 lines

  1. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
  2. * |_o_o|\\ Copyright (c) 1989 The Software Distillery.                    *
  3. * |. o.| ||          All Rights Reserved                                  *
  4. * | .  | ||          Written by Doug Walker                               *
  5. * | o  | ||          The Software Distillery                              *
  6. * |  . |//           235 Trillingham Lane                                 *
  7. * ======             Cary, NC 27513                                       *
  8. *                    BBS:(919)-471-6436                                   *
  9. \* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  10.  
  11. /* This file contains the routines that must be linked in to every pgm   */
  12. /* that wants to use MemWatchIII - MWInit, MWTerm, MWCheck, MWSend,      */
  13. /* MWHold, MWPurge, MWSend                                               */
  14.  
  15. #include "mempriv.h"
  16.  
  17. struct MWGlobal mwg = {0L};  /* Make sure the 'flags' field is 0's */
  18.  
  19. /* Initialization routine - should be called once before any memory */
  20. /* is allocated                                                     */
  21.  
  22. void MWInit(dbfh, flags)
  23. BPTR dbfh;
  24. LONG flags;
  25. {
  26.    if(mwg.flags & MWF_ACTIVE)
  27.    {
  28.       if(!dbfh && mwg.dbfh) dbfh = mwg.dbfh;
  29.       if(dbfh)
  30.       {
  31.          MSG(dbfh, "MemWatch ERROR: MWInit called twice\n");
  32.       }
  33.  
  34.       return;
  35.    }
  36.  
  37.    memset((char *)&mwg, 0, sizeof(struct MWGlobal));
  38.  
  39.    mwg.flags = flags|MWF_ACTIVE;
  40.  
  41.    if(!(flags & MWF_NOLOG)) mwg.dbfh = (dbfh ? dbfh : Output());
  42.  
  43.    MWSend(MWM_INIT);
  44.  
  45.    mwg.lim[MWT_CHIP] = mwg.lim[MWT_FAST] = 0x7fffffff;
  46.  
  47.    mwg.task = FindTask(0L);
  48. }
  49.  
  50. /* Termination routine - should be called after all memory usage is done */
  51.  
  52. void MWTerm()
  53. {
  54.    int msgdone = 0;
  55.  
  56.    MWCheck();
  57.  
  58.    MWSend(MWM_TERM);
  59.  
  60.    /* no need to trash the mem we may be about to free for good */
  61.    mwg.flags |= MWF_NOFTRASH;
  62.  
  63.    if(!(mwg.flags & MWF_NOFREE))
  64.    {
  65.       while(mwg.first)
  66.       {
  67.          if(mwg.dbfh) 
  68.          {
  69.             if(!msgdone)
  70.             {
  71.                MSG(mwg.dbfh, 
  72.           "MemWatch ERROR: The following allocations were not freed:\n");
  73.                msgdone = 1;
  74.             }
  75.             MWPrint(mwg.first, 0, 0, 0);
  76.          }
  77.          MWFreeMem(mwg.first->memory, mwg.first->size, 0);
  78.       }
  79.    }
  80.  
  81.    MWPurge();  /* Really free all mem on the 'free' chain */
  82.  
  83.    memset((char *)&mwg, 0, sizeof(struct MWGlobal));
  84. }
  85.  
  86. /* Validity check routine - checks all known allocations for overwrites */
  87. /* Called from every alloc and free routine, plus when specifically     */
  88. /* invoked                                                              */
  89.  
  90. void MWCheck()
  91. {
  92.    struct MWAlc *mwa;
  93.    char *tmpchar;
  94.    int error, header, trailer;
  95.  
  96.    if(mwg.flags & MWF_ERROR)
  97.    {
  98.       /* Error already found by external process */
  99.       if(mwg.dbfh) 
  100.          MSG(mwg.dbfh, 
  101.             "MemWatch ERROR: External process found memory error\n");
  102.       MWHold();
  103.       return;
  104.    }
  105.  
  106.    error = 0;
  107.    for(mwa=mwg.first; mwa; mwa=mwa->next)
  108.    {
  109.       if( (mwa->myflags & MWF_REPMASK) == MWF_REPORTED) continue;
  110.  
  111.       if(header=memcmp((char *)&mwa->header, MWHEADER, 4))
  112.       {
  113.          if(mwg.dbfh) MSG(mwg.dbfh, "MemWatch ERROR: Header trashed\n");
  114.       }
  115.  
  116.       if(trailer=memcmp(mwa->memory+mwa->size, MWTRAILER, 4))
  117.       {
  118.          if(mwg.dbfh) MSG(mwg.dbfh, "MemWatch ERROR: Trailer trashed\n");
  119.       }
  120.  
  121.       if(header || trailer)
  122.       {
  123.          error = 1;
  124.          mwa->myflags |= MWF_REPORTED;
  125.          MWPrint(mwa, 0, 0, 0);
  126.       }
  127.    }
  128.  
  129.    for(mwa=mwg.freed; mwa; mwa=mwa->next)
  130.    {
  131.       if( (mwa->myflags & MWF_REPMASK) == MWF_REPORTED) continue;
  132.  
  133.       for(header=0, tmpchar=mwa->memory; 
  134.           header<mwa->size; 
  135.           header++, tmpchar++)
  136.       {
  137.          if(*tmpchar != MWFTRASH)
  138.          {
  139.             mwa->myflags |= MWF_REPORTED;
  140.             if(mwg.dbfh)
  141.             {
  142.                error = 1;
  143.                MSG(mwg.dbfh, "MemWatch ERROR: Freed memory modified\n");
  144.                MWPrint(mwa, 0, 0, 0);
  145.                break;
  146.             }
  147.          }
  148.       }
  149.    }
  150.  
  151.    if(error) MWHold();
  152. }
  153.  
  154. void MWHold()
  155. {
  156.    struct MWAlc *mwa;
  157.  
  158.    if(mwg.flags & MWF_EXT)
  159.    {
  160.       if(mwg.dbfh) MSG(mwg.dbfh, "***Process Held By MemWatch***\n");
  161.       MWSend(MWM_KILLME);      /* Should never return...               */
  162.    }
  163.    mwg.flags &= ~MWF_ERROR; /* But if it does, clear the error flag */
  164.  
  165.    /* If we're attempting to go on, make all the sentinals correct */
  166.    for(mwa=mwg.first; mwa; mwa=mwa->next)
  167.    {
  168.       mwa->myflags = ~MWF_REPMASK;
  169.       memcpy((char *)&mwa->header, MWHEADER, 4);
  170.       memcpy((mwa->memory + mwa->size), MWTRAILER, 4);
  171.    }
  172.  
  173.    for(mwa=mwg.freed; mwa; mwa=mwa->next)
  174.    {
  175.       mwa->myflags = ~MWF_REPMASK;
  176.       memset(mwa->memory, MWFTRASH, mwa->size);
  177.    }
  178. }
  179.  
  180. /* MWPurge really frees all memory placed on the 'freed' chain by */
  181. /* FreeMem() or free()                                            */
  182.  
  183. void MWPurge()
  184. {
  185.    struct MWAlc *cur, *next;
  186.  
  187.    for(cur=mwg.freed; cur; cur=next)
  188.    {
  189.       next = cur->next;
  190.       FreeMem(cur, cur->size + sizeof(struct MWAlc));
  191.    }
  192.    mwg.freed = NULL;
  193. }
  194.  
  195. /* MWSend communicates with the external MemWatch process */
  196.  
  197. int MWSend(type)
  198. int type;
  199. {
  200.    struct MsgPort *extport;
  201.    struct MWMsg mwmsg;
  202.  
  203.    if(!(mwg.flags & MWF_ACTIVE) ||
  204.       !(mwg.flags & MWF_EXT)) return(1);
  205.  
  206.    if(!(extport = FindPort(MWPORTNAME)) || 
  207.       !(mwmsg.msgpart.mn_ReplyPort = CreatePort(NULL, 0)))
  208.       goto exterror;
  209.  
  210.    mwmsg.msgpart.mn_Length = sizeof(struct MWMsg);
  211.    mwmsg.type = type|MWM_REPLY;
  212.    mwmsg.mwg = &mwg;
  213.    PutMsg(extport, &mwmsg.msgpart);
  214.    WaitPort(mwmsg.msgpart.mn_ReplyPort);
  215.    GetMsg(mwmsg.msgpart.mn_ReplyPort);
  216.    DeletePort(mwmsg.msgpart.mn_ReplyPort);
  217.    if(mwmsg.type != MWM_OK) 
  218.    {
  219.       goto exterror;
  220.    }
  221.  
  222.    return(0);
  223.  
  224. exterror:
  225.    if(mwg.dbfh) 
  226.       MSG(mwg.dbfh, 
  227.           "MemWatch ERROR: Can't communicate with external process\n");
  228.    mwg.flags &= ~MWF_EXT;
  229.    return(1);
  230. }
  231.  
  232. #define ALCMSG \
  233.   "0x00000000 length 00000000 allocated line 00000 file xxxxxxxxxxxxxxx\n"
  234.  /*0         1         2         3         4         5         6*/
  235.  /*0123456789012345678901234567890123456789012345678901234567890*/
  236. #define ALC_MEM  2
  237. #define ALC_LEN 18
  238. #define ALC_LIN 42
  239. #define ALC_FIL 53
  240.  
  241. #define FREMSG \
  242.   "Invalid FreeMem call, addr 0x00000000 length 00000000\n"
  243.  /*0         1         2         3         4         5         6*/
  244.  /*0123456789012345678901234567890123456789012345678901234567890*/
  245. #define FRE_MEM 29
  246. #define FRE_LEN 45
  247.  
  248. #define LENMSG \
  249.   "FreeMem called with length 00000000 on the following allocation:\n"
  250.  /*0         1         2         3         4         5         6*/
  251.  /*0123456789012345678901234567890123456789012345678901234567890*/
  252. #define LEN_LEN 27
  253.   
  254. #define USEMSG \
  255.   "00000000 bytes in 00000000 allocations\n"
  256.  /*0         1         2         3         4         5         6*/
  257.  /*0123456789012345678901234567890123456789012345678901234567890*/
  258. #define USE_SIZ 0
  259. #define USE_ALC 18
  260.  
  261. #define MAXMSG \
  262.   "Max chip usage = 00000000 bytes; Max fast usage = 00000000 bytes\n\n"
  263.  /*0         1         2         3         4         5         6*/
  264.  /*0123456789012345678901234567890123456789012345678901234567890*/
  265. #define MAX_CHP 17
  266. #define MAX_FST 50
  267.  
  268. #define DIGITS "0123456789ABCDEF"
  269.  
  270. static void fmtdec(char *, long, LONG);
  271. static void fmthex(char *, LONG);
  272.  
  273. static char *msgs[] =
  274. {
  275.    ALCMSG, FREMSG, LENMSG, USEMSG, MAXMSG
  276. };
  277.  
  278. void MWPrint(mwa, msgnum, val1, val2)
  279. struct MWAlc *mwa;
  280. int msgnum;
  281. LONG val1, val2;
  282. {
  283.    char *buffer;
  284.    int i;
  285.  
  286.    if(!(mwg.flags & MWF_ACTIVE) || !mwg.dbfh) return;
  287.  
  288.    buffer = msgs[msgnum];
  289.  
  290.    switch(msgnum)
  291.    {
  292.       case 0:
  293.          fmthex(msgs[0]+ALC_MEM, (LONG)mwa->memory);
  294.          fmtdec(msgs[0]+ALC_LEN, 8, mwa->size);
  295.          fmtdec(msgs[0]+ALC_LIN, 5, mwa->line);
  296.  
  297.          if( (i = strlen(mwa->file)) > 15) i=15;
  298.          memcpy(msgs[0]+ALC_FIL, mwa->file, i);
  299.          msgs[0][ALC_FIL+i]   = '\n';
  300.          msgs[0][ALC_FIL+i+1] = '\0';
  301.          break;
  302.  
  303.       case 1:
  304.          fmthex(msgs[1]+FRE_MEM, val1);
  305.          fmtdec(msgs[1]+FRE_LEN, 8, val2);
  306.          break;
  307.  
  308.       case 2:
  309.          fmtdec(msgs[2]+LEN_LEN, 8, val1);
  310.          break;
  311.  
  312.       case 3:
  313.          fmtdec(msgs[3]+USE_SIZ, 8, val1);
  314.          fmtdec(msgs[3]+USE_ALC, 8, val2);
  315.          break;
  316.  
  317.       case 4:
  318.          fmtdec(msgs[4]+MAX_CHP, 8, val1);
  319.          fmtdec(msgs[4]+MAX_FST, 8, val2);
  320.          break;
  321.  
  322.       default:
  323.          /* What do we do here?  Give up, I guess*/
  324.          return;
  325.    }
  326.  
  327.    MSG(mwg.dbfh, buffer);
  328. }
  329.  
  330. static void fmtdec(buf, len, val)
  331. char *buf;
  332. long len;
  333. LONG val;
  334. {
  335.    int i;
  336.    for(i=1; i<=len; i++, val/=10)
  337.       buf[len-i] = (val ? DIGITS[val%10] : ' ');
  338. }
  339.  
  340. static void fmthex(buf, val)
  341. char *buf;
  342. LONG val;
  343. {
  344.    int i, j;
  345.    union
  346.    {
  347.       LONG l;
  348.       char c[4];
  349.    } u;
  350.  
  351.    u.l = val;
  352.    for(i=j=0; i<4; i++)
  353.    {
  354.       buf[j++] = DIGITS[(u.c[i]&0xf0)>>4];
  355.       buf[j++] = DIGITS[u.c[i]&0x0f];
  356.    }
  357. }
  358.  
  359.