home *** CD-ROM | disk | FTP | other *** search
/ The Fred Fish Collection 1.5 / ffcollection-1-5-1992-11.iso / ff_disks / 200-299 / ff280.lzh / Graph / divers / tracker.c
C/C++ Source or Header  |  1989-11-20  |  12KB  |  425 lines

  1. /* Resource tracking routines, by Karl Lehenbauer
  2.    Lattice version by David Gay.
  3.    This code is in the public domain
  4. */
  5.  
  6. /* tracking memory allocator */
  7.  
  8. #include <exec/types.h>
  9. #include <exec/memory.h>
  10. #include <stdio.h>
  11. #include <string.h>
  12.  
  13. #include <proto/exec.h>
  14. #include <proto/dos.h>
  15.  
  16. /* comment out the following line if you want locks freed twice reported
  17.  * at the cost of getting spurious resource error messages when
  18.  * reusing the lock */
  19. /* #define FORGET_LOCKS_WHEN_UNLOCKED */
  20.  
  21. /* comment out the following line if you want memory freed twice reported
  22.  * at the cost of getting spurious resource error messages when
  23.  * freeing and reallocating memory */
  24. #define FORGET_MEMORY_WHEN_FREED
  25.  
  26. /* make sure our invocations of the real routines on behalf of the user
  27.    don't cause us to recurse */
  28.  
  29. #ifdef AllocMem
  30. #undef AllocMem
  31. #undef FreeMem
  32. #undef AllocSignal
  33. #undef FreeSignal
  34. #undef Lock
  35. #undef UnLock
  36. #undef DupLock
  37. #undef ParentDir
  38. #endif
  39.  
  40. /* my flags */
  41. #define FREED_IT 1
  42.  
  43. struct TrackingAllocMemData
  44. {
  45.     UBYTE *where;             /* address returned by allocator */
  46.     long amount;             /* number of bytes allocated */
  47.     long alloc_flags;         /* flags passed to allocator */
  48.     char *file;         /* filename of caller from the macro */
  49.     int line;                 /* line number of caller from macro */
  50.     long my_flags;             /* flags internal to tracker */
  51.     struct TrackingAllocMemData *next;    /* pointer to next entry */
  52. };
  53.  
  54. struct TrackingAllocMemData *TrackingAllocMemList = NULL;
  55. long MemAllocCount = 0, MemFreeCount = 0;
  56.  
  57. void *TrackingAllocMem(amount,flags,file,line)
  58. long amount;
  59. long flags;
  60. char *file;
  61. int line;
  62. {
  63.     struct TrackingAllocMemData *rp;
  64.     UBYTE *users_memory;
  65.  
  66.     /* perform the actual alloc */
  67.     users_memory = AllocMem(amount,flags);
  68.  
  69.     /* if it succeeded, record tracking info */
  70.     if (users_memory)
  71.     {
  72.          MemAllocCount++;
  73.  
  74.          if ((rp = AllocMem((long)sizeof(struct TrackingAllocMemData),0L)) == N
  75. ULL)
  76.              fprintf(stderr, "tracker: can't alloc memory to record AllocMem da
  77. ta");
  78.  
  79.          /* add new alloc data entry to linked list */
  80.          rp->next = TrackingAllocMemList;
  81.          TrackingAllocMemList = rp;
  82.  
  83.          /* shove in save values */
  84.          rp->amount = amount;
  85.          rp->alloc_flags = flags;
  86.          rp->where = users_memory;
  87.          rp->file = file;
  88.          rp->line = line;
  89.          rp->my_flags = 0;
  90.     }
  91.     /* return pointer to the space allocated */
  92.     return(users_memory);
  93. }
  94.  
  95. void TrackingFreeMem(where,amount,file,line)
  96. UBYTE *where;
  97. long amount;
  98. char *file;
  99. int line;
  100. {
  101.     struct TrackingAllocMemData *rp, *op, *freep;
  102.  
  103.     MemFreeCount++;
  104.     /* scan the memory tracking list for a match */
  105.     for (rp = TrackingAllocMemList, op = NULL; rp != NULL; op = rp, rp = rp->ne
  106. xt)
  107.     {
  108.          /* if we matched the address */
  109.          if (rp->where == where)
  110.          {
  111.              /* if they got the amount wrong, tell them */
  112.              if (rp->amount != amount)
  113.              {
  114.                  fprintf(stderr,"freed addr %lx OK but length differs, talloc'e
  115. d %ld, freed %ld,\n\tallocated at file %s line %d, freed at file %s line %d\n",
  116.                  where,rp->amount,amount,rp->file,rp->line,file,line);
  117.              }
  118. #ifndef FORGET_MEMORY_WHEN_FREED
  119.              /* if it's already free, tell them they freed twice */
  120.              if (rp->my_flags & FREED_IT)
  121.              {
  122.                  fprintf(stderr,"freed memory twice at %lx, amount %ld,\n\tallo
  123. cated in file %s at line %d, freed in file %s at line %d\n",where,amount,rp->fil
  124. e,rp->line,file,line);
  125.                  return;
  126.              }
  127.              else
  128.              {
  129.                  /* mark this entry as free */
  130.                  rp->my_flags |= FREED_IT;
  131.              }
  132. #else
  133.              /* remove entry from linked list and free it */
  134.              if (op != NULL) op->next = rp->next;
  135.              else
  136.                  TrackingAllocMemList = rp->next;
  137.              freep = rp;
  138.              rp = rp->next;
  139.              FreeMem(freep,(long)sizeof(struct TrackingAllocMemData));
  140. #endif
  141.              /* Munge memory block */
  142.              memset((char *)where, amount, 3); /* Set to an odd number ... */
  143.              FreeMem(where,(long)amount);
  144.  
  145.              return;
  146.          }
  147.     }
  148.     fprintf(stderr,"Freed memory at %lx of amount %ld that wasn't allocated,\n\
  149. tfreed at file %s line %d\n",where,amount,file,line);
  150.     FreeMem(where,amount);
  151. }
  152.  
  153. void ReportUnfreedMemory()
  154. {
  155.     struct TrackingAllocMemData *rp = TrackingAllocMemList, *freep;
  156.  
  157.     while (rp != NULL)
  158.     {
  159.          if (!(rp->my_flags & FREED_IT))
  160.          {
  161.              fprintf(stderr,"FreeMem was never called for memory at %lx, amount
  162.  %ld,\n\tthe alloc was performed at file %s line %d\n",rp->where,rp->amount,rp->
  163. file,rp->line);
  164.          }
  165.          freep = rp;
  166.          rp = rp->next;
  167.          FreeMem(freep,(long)sizeof(struct TrackingAllocMemData));
  168.     }
  169.     printf("Total tracked AllocMem calls %ld, FreeMem calls %ld\n",MemAllocCoun
  170. t,MemFreeCount);
  171. }
  172.  
  173.  
  174. /* track signals */
  175. /* tracking AllocSignal doesn't currently track where it was called from */
  176.  
  177. long TrackingSignalMask = 0;
  178. long SignalAllocCount = 0, SignalFreeCount = 0;
  179.  
  180. long TrackingAllocSignal(signal_num,file,line)
  181. long signal_num;
  182. char *file;
  183. int line;
  184. {
  185.     SignalAllocCount++;
  186.  
  187.     signal_num = AllocSignal(signal_num);
  188.  
  189.     if (signal_num != -1)
  190.          TrackingSignalMask |= (1 << signal_num);
  191.  
  192.     return(signal_num);
  193. }
  194.  
  195. void TrackingFreeSignal(signal_num,file,line)
  196. long signal_num;
  197. char *file;
  198. int line;
  199. {
  200.     SignalFreeCount++;
  201.  
  202.     if (!(TrackingSignalMask & (1 << signal_num)))
  203.     {
  204.          fprintf(stderr, "freed a signal (%ld) that was never allocated, at fil
  205. e %s line %d\n",
  206.              signal_num,file,line);
  207.     }
  208.     TrackingSignalMask &= ~(1 << signal_num);
  209. }
  210.  
  211. void ReportUnfreedSignals()
  212. {
  213.     if (TrackingSignalMask)
  214.          fprintf(stderr, "failed to free signals indicated by this mask: %8lx\n
  215. ",
  216.              TrackingSignalMask);
  217.     printf("Total tracked AllocSignal calls %ld, FreeSignal calls %ld\n",Signal
  218. AllocCount,SignalFreeCount);
  219. }
  220.  
  221. /* tracking lock and unlock */
  222.  
  223. struct TrackingLockData
  224. {
  225.     BPTR lock;    /* lock returned by Lock */
  226.     char *name;         /* name of file that was locked */
  227.     long accessMode;         /* access mode of the file that was locked */
  228.     char *file;         /* ptr to file name of line of caller */
  229.     int line;                 /* ptr to line number text of locker */
  230.     long my_flags;             /* flags internal to tracker */
  231.     struct TrackingLockData *next;    /* pointer to next entry */
  232. };
  233.  
  234. /* flags */
  235. #define CREATED_BY_DUPLOCK 1
  236.  
  237. struct TrackingLockData *TrackingLockList = NULL;
  238. long TrackerLockCount = 0, TrackerUnLockCount = 0;
  239.  
  240. BPTR TheTrackingLock(name, accessMode, file, line)
  241. char *name;
  242. long accessMode;
  243. char *file;
  244. int line;
  245. {
  246.     struct TrackingLockData *lp;
  247.     BPTR users_lock;
  248.  
  249.     users_lock = Lock(name, (long)accessMode);
  250.  
  251.     if (users_lock)
  252.     {
  253.          TrackerLockCount++;
  254.  
  255.          if ((lp = AllocMem((long)sizeof(struct TrackingLockData),0L)) == NULL)
  256.      
  257.              fprintf(stderr, "tracker: can't alloc memory to record lock data")
  258. ;
  259.  
  260.          /* add new alloc data entry to linked list */
  261.          lp->next = TrackingLockList;
  262.          TrackingLockList = lp;
  263.  
  264.          /* shove in save values */
  265.          lp->accessMode = accessMode;
  266.          lp->file = file;
  267.          lp->line = line;
  268.          lp->my_flags = 0;
  269.          lp->lock = users_lock;
  270.  
  271.          /* alloc space for filename and save */
  272.          if ((lp->name = AllocMem((long)(strlen(name)+1),0L)) == NULL)
  273.              fprintf(stderr, "tracker: can't alloc memory to record lock filena
  274. me");
  275.          strcpy(lp->name,name);
  276.     }
  277.     return(users_lock);
  278. }
  279.  
  280. BPTR TheTrackingDupLock(lock, file, line)
  281. BPTR lock;
  282. char *file;
  283. int line;
  284. {
  285.     struct TrackingLockData *lp;
  286.     BPTR users_lock;
  287.  
  288.     users_lock = DupLock(lock);
  289.  
  290.     if (users_lock)
  291.     {
  292.          TrackerLockCount++;
  293.  
  294.          if ((lp = AllocMem((long)sizeof(struct TrackingLockData),0L)) == NULL)
  295.      
  296.              fprintf(stderr, "tracker: can't alloc memory to record lock data")
  297. ;
  298.  
  299.          /* add new alloc data entry to linked list */
  300.          lp->next = TrackingLockList;
  301.          TrackingLockList = lp;
  302.  
  303.          lp->file = file;
  304.          lp->line = line;
  305.          lp->name = NULL;
  306.          lp->lock = users_lock;
  307.          lp->my_flags = CREATED_BY_DUPLOCK;
  308.     }
  309.     return(users_lock);
  310. }
  311.  
  312. void TheTrackingUnLock(lock,file,line)
  313. BPTR lock;
  314. char *file;
  315. int line;
  316. {
  317.     struct TrackingLockData *lp, *op, *freep;
  318.  
  319.     TrackerUnLockCount++;
  320.  
  321.     /* scan the lock tracking list for a match */
  322.     for (lp = TrackingLockList, op = NULL; lp != NULL; op = lp, lp = lp->next)
  323.     {
  324.          /* if we matched the lock */
  325.          if (lp->lock == lock)
  326.          {
  327. #ifndef FORGET_LOCKS_WHEN_UNLOCKED
  328.              /* if it's already free, tell them they freed twice */
  329.              if (lp->my_flags & FREED_IT)
  330.              {
  331.                  fprintf(stderr,"freed lock twice, lock %lx, filename %s\n\tloc
  332. ked at file %s line %d, freed at file %s line %d\n",lock,lp->name,lp->file,lp->l
  333. ine,file,line);
  334.                  return;
  335.              }
  336.              else
  337.              {
  338.                  /* mark this entry as free */
  339.                  lp->my_flags |= FREED_IT;
  340.              }
  341. #else
  342.              if (op != NULL) op->next = lp->next;
  343.              else TrackingLockList = lp->next;
  344.              freep = lp;
  345.              lp = lp->next;
  346.              if (lp->name != NULL)
  347.                  FreeMem(lp->name,(long)(strlen(lp->name)+1));
  348.              FreeMem(freep,(long)(sizeof(struct TrackingLockData)));
  349. #endif
  350.              UnLock(lock);
  351.              return;
  352.          }
  353.     }
  354.     fprintf(stderr,"Freed lock %lx that hadn't been allocated at file %s line %
  355. d\n",lock,file,line);
  356. }
  357.  
  358. BPTR TheTrackingParentDir(BPTR lock, char *file, int line)
  359. {
  360.     struct TrackingLockData *lp;
  361.     BPTR users_lock;
  362.  
  363.     users_lock = ParentDir(lock);
  364.  
  365.     if (users_lock)
  366.     {
  367.          TrackerLockCount++;
  368.  
  369.          if ((lp = AllocMem((long)sizeof(struct TrackingLockData),0L)) == NULL)
  370.      
  371.              fprintf(stderr, "tracker: can't alloc memory to record lock data")
  372. ;
  373.  
  374.          /* add new alloc data entry to linked list */
  375.          lp->next = TrackingLockList;
  376.          TrackingLockList = lp;
  377.  
  378.          /* shove in save values */
  379.          lp->accessMode = 0;
  380.          lp->file = file;
  381.          lp->line = line;
  382.          lp->my_flags = 0;
  383.          lp->lock = users_lock;
  384.          lp->name = NULL;
  385.     }
  386.     return(users_lock);
  387. }
  388.  
  389. void ReportUnfreedLocks()
  390. {
  391.     struct TrackingLockData *lp = TrackingLockList, *freep;
  392.  
  393.     while (lp != NULL)
  394.     {
  395.          if (!(lp->my_flags & FREED_IT))
  396.          {
  397.              if (lp->my_flags & CREATED_BY_DUPLOCK)
  398.              {
  399.                  fprintf(stderr,"UnLock was never called for lock %lx,\n\It was
  400.  created by DupLock at file %s line %d\n",lp->lock,lp->file,lp->line);
  401.              }
  402.              else
  403.              {
  404.                  fprintf(stderr,"UnLock was never called for lock %lx,\n\It was
  405.  created by a Lock of %s\nat file %s line %d\n",lp->lock,lp->name,lp->file,lp->l
  406. ine);
  407.              }
  408.          }
  409.          if (lp->name != NULL)
  410.              FreeMem(lp->name,(long)(strlen(lp->name)+1));
  411.          freep = lp;
  412.          lp = lp->next;
  413.          FreeMem(freep,(long)sizeof(struct TrackingLockData));
  414.     }
  415.     printf("Total tracked Lock and DupLock calls %ld, UnLock calls %ld\n",Track
  416. erLockCount,TrackerUnLockCount);
  417. }
  418.  
  419. void TrackerExitReport()
  420. {
  421.     ReportUnfreedMemory();
  422.     ReportUnfreedLocks();
  423.     ReportUnfreedSignals();
  424. }
  425.