home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / oper_sys / emerald / emrldsys.lha / Kernel / EmMalloc / emalloc.c next >
Encoding:
C/C++ Source or Header  |  1990-08-17  |  23.3 KB  |  719 lines

  1.  
  2. #include <stdio.h>
  3.  
  4. struct smallHeader     *p;
  5.  
  6. #ifndef NOEMALLOC
  7. #include "Kernel/h/assert.h"
  8. #include "Kernel/h/emTypes.h"
  9. #include "Kernel/h/kmdTypes.h"
  10. #include "Kernel/h/emkDefs.h"
  11. #endif  NOEMALLOC
  12.  
  13. #ifndef DONTUSEHOLDSIGS
  14. #include "Kernel/h/stdTypes.h"
  15. #include "Kernel/h/kEvents.h"
  16. #endif  DONTUSEHOLDSIGS
  17.  
  18. #include "Kernel/h/system.h"
  19. /*  An implementation of malloc(3), free(3) using the QuickFit method.
  20.  *  Guy Almes, May 1983.
  21.  *
  22.  *  Cf. MALLOC(3) in the Unix manual for external specifications.
  23.  *
  24.  *  Cf. Chuck Weinstock's PhD thesis for a discussion of the techniques
  25.  *  used.  (Charles Weinstock, Dynamic Storage Allocation Techniques,
  26.  *  April 1976, CMU)
  27.  *  nb: Unlike the original QuickFit, this implementation assumes that
  28.  *  TailFit always works.  Also, we want to allow for some other user to
  29.  *  be using sbrk.
  30.  *
  31.  *  NOTE: change made on 11/29/84 by Mike Schwartz to call HoldSigs and
  32.  *  ReleaseSigs at beginning and end of malloc if signals weren't
  33.  *  already held (and running in Eden Kernel or EFT context).  This is needed
  34.  *  in case a Unix routine that uses malloc is called, so that signals
  35.  *  will be held as needed to protect the critical region variables during
  36.  *  the allocation.
  37.  *
  38.  *  Hacked by oystr.  While the external specification was met, the
  39.  *  internal behaviour of the standard malloc(3) was not.  To wit:
  40.  *  areas free'd do not have their contents touched until reallocated
  41.  *  (Almes actually fixed this after considerable pleading); it is
  42.  *  possible to do multiple free's of the same area - that is "x = malloc();
  43.  *  free(x); free(x);" causes no damage.  This turkey originally did
  44.  *  not detect such a situation even though the multiple free's caused
  45.  *  it to trash the list structures and blow up at some future malloc
  46.  *  call.  Realloc was also a disaster area, making the assumption that
  47.  *  the old block was in use, which is not necessarily the case.
  48.  *
  49.  *  Expanded for Emerald, November 1986:
  50.  *  emalloc and emfree added so that Emerald objects can be especially
  51.  *  identified as such.  May be deleted by defining NOEMALLOC.
  52.  *  Modifications to enable EmallocDump to traverse the allocated data areas.
  53.  *  Small blocks now also use a link field.
  54.  *  The reason is that for garbage collection purposes, it is necessary
  55.  *  to keep the size with the data.
  56.  *  EmallocDump: copyright 1986 Eric Jul
  57.  */
  58. /*  The parts of Unix used by this module:
  59.  */
  60.  
  61. /*  From BRK(2):
  62.  */
  63.     extern char *brk();      /* set break to addr */
  64.     extern char *sbrk();     /* add incr to break */
  65.  
  66. /*  From END(3):
  67.  */
  68.     extern int end;                 /* first byte beyond bss region */
  69.  
  70. /*  Design parameters; these can be changed to tune the implementation
  71.  *  to a specific application.
  72.  */
  73.  
  74. #define GrainSize       8
  75. #define LogGrainSize    3
  76. #define HeaderSize      sizeof(int)
  77.     /* number of bytes: every allocated block is
  78.      * (k+1) * GrainSize, for k >= MinGrains
  79.      * GrainSize == (1 << LogGrainSize)
  80.      */
  81.  
  82. #define MinBytes        0
  83. #define MaxBytes        (SBrkChunk - HeaderSize)         /* = 8188 bytes */
  84. #define MinGrains       0
  85. #define MaxGrains       ((MaxBytes-MinBytes+1) >> LogGrainSize)
  86.     /* The implementation is tuned to use ExactFit for blocks in the range
  87.      * MinBytes .. MaxBytes
  88.      */
  89.  
  90. #define BtoG(b) ( ((b)-(GrainSize-HeaderSize) + GrainSize-1) >> LogGrainSize )
  91.     /* convert a number of bytes to a number of grains */
  92. #define GtoB(g) ( ((g) << LogGrainSize) + (GrainSize-HeaderSize) )
  93.     /* and vice versa */
  94.  
  95. #define Nil ((char *) 0)
  96.     /* a nil pointer; often coerced to various flavors of pointers */
  97.  
  98. /* Change (by Eric Jul, July 1986): expanded SBrkChunk from 1024 to 2**13 */
  99. #define SBrkChunk 8192
  100.     /* the number of bytes to get from sbrk when growing the Tail */
  101. #define roundUp(a,b) ((char *) ( ((int)(a) + (b)-1) & ~((b)-1) ))
  102.     /* round up an address to the nearest 1k boundary like sbrk does */
  103.  
  104. /* header for Big blocks allocated via MiscFit */
  105. typedef struct bigHeader {
  106.         struct bigHeader *bNext;  /* the next field links available blocks */
  107.         unsigned bSize;        /* the size of the block in bytes */
  108. } bHeader, *bHeaderPtr;
  109.  
  110. /* header for Small blocks allocated via ExactFit */
  111. typedef struct smallHeader {
  112.         struct smallHeader *sNext;  /* the next field links available blocks */
  113.         unsigned sSize;        /* the size of a used block in bytes */
  114. } sHeader, *sHeaderPtr;
  115.  
  116. static char *TailMin = (char *) &end;     /* points to 1st byte of Tail */
  117. static char *TailMax = (char *) &end;     /* points just beyond end of Tail */
  118. char        *firstAllocated = (char *) &end; /* first addr allocated */
  119.     /* invariants: TailMin and TailMax are each on int boundaries.
  120.      *      The area with addresses TailMin <= addr < TailMax is available.
  121.      *      &end <= TailMin <= TailMax == sbrk(0).
  122.      */
  123.  
  124. /*
  125.  * Free/in use magic numbers.  WARNING: if we ever get into 16MB+
  126.  * virtual addresses ( >24 bits), you will have to change the headers.
  127.  * The upper byte of the size field contains INUSEMAGIC if the
  128.  * block has been malloc'd but not freed, 0 if the block is free.
  129.  */
  130. #define INUSEMAGIC      0x55
  131. #define SETMAGIC        0x55000000
  132. #define CLRMAGIC        0x00FFFFFF
  133.  
  134. #ifndef NOEMALLOC
  135. /*
  136.  * Emerald uses a different MAGIC number as to distinguish Emerald tagged
  137.  * (with an ODTag) data areas from other data areas.
  138.  * The EMINUSEMAGIC is also put into the bNext field of Big blocks.
  139.  */
  140. #define EMINUSEMAGIC    0x57
  141. #define EMSETMAGIC      0x57000000
  142. #endif  NOEMALLOC
  143.  
  144. static char *TailFit(nBytes)
  145. register unsigned nBytes;
  146. {
  147.     register char *oldTailMin;
  148. #ifdef GORP
  149. printf(
  150.     "   TailFit(%d) called.  Tail: %x - %x.\n", nBytes, TailMin, TailMax);
  151. #endif
  152.     while (TailMax < TailMin+nBytes) {
  153.         register char *oldBreak = sbrk(SBrkChunk);
  154.         if ((int) oldBreak == -1) {
  155.             printf( "sbrk returned a -1!!\n");
  156.             printf(
  157.         "Request %d bytes; current max address is 0x%02x\n", nBytes,
  158.         TailMax);
  159.         printf( "OUT OF VIRTUAL MEMORY --- FATAL\n");
  160.             abort();
  161.             return ( Nil );
  162.         }
  163.         if (oldBreak != TailMax) {  /* someone else did an sbrk! */
  164. #ifdef GORP
  165.             printf(
  166.                "TailFit: pushed TailMin from %x to %x.\n",
  167.                  TailMin, roundUp(oldBreak, sizeof(int)));
  168. #endif
  169. #ifdef  GPROF
  170.             /* Gprof uses sbrk, so live with it ! */
  171.             printf( "oldBreak 0x%06x, TailMax 0x%06x end 0x%06x\n",
  172.         oldBreak, TailMax, &end);
  173.             if (TailMax == (char *) & end) {
  174.         /* We have not allocated anything yet */
  175.                 firstAllocated = roundUp(oldBreak, sizeof(int));
  176.                 
  177.         }
  178.         
  179. #else   GPROF
  180. #ifndef NOEMALLOC
  181.             /* must not happen!! */
  182. /*            assert(oldBreak == TailMax);*/
  183. #endif  NOEMALLOC
  184. #endif  GPROF
  185.             TailMin = roundUp(oldBreak, sizeof(int));
  186.         }
  187.         TailMax = oldBreak + SBrkChunk;
  188.         if (TailMax != roundUp(TailMax, SBrkChunk)) {
  189.                                             /* bring TailMax to a page */
  190. #ifdef GORP
  191.             printf(
  192.                 "TailFit: rounding TailMax from %x to %x.\n",
  193.                 TailMax, roundUp(TailMax, SBrkChunk));
  194. #endif
  195. #ifndef BRKISFIXEDONSUNSUSINGGPROF
  196.         sbrk(roundUp(TailMax, SBrkChunk) - TailMax);
  197.         TailMax = roundUp(TailMax, SBrkChunk);
  198. #else
  199.             TailMax = roundUp(TailMax, SBrkChunk);
  200.             (void) brk(TailMax);
  201. #endif
  202.         }
  203.     } /* we now know we have enough in the Tail */
  204.     oldTailMin = TailMin;
  205.     TailMin += nBytes;
  206. #ifdef GORP
  207. printf(
  208.     "   TailFit returns %x.  Tail: %x - %x.\n", oldTailMin, TailMin, TailMax);
  209. #endif
  210.     return ( oldTailMin );
  211. } /* TailFit */
  212.  
  213. static bHeaderPtr BigList;
  214. /* BigLists points to a ring of zero or more available blocks, each marked
  215.  * with both a size and a next field.  This ring is used in the MiscFit
  216.  * portion of the algorithm, which is a simple FirstFit for very large blocks.
  217.  */
  218.  
  219. static char *MiscFit(nBytes)
  220. register unsigned nBytes;
  221. {
  222.     register bHeaderPtr CurrentHdr, PreviousHdr;
  223.     register unsigned oldSize;
  224.     register char *newBlock = Nil;
  225. #ifdef GORP
  226. printf( "   MiscFit(%d) called.\n", nBytes);
  227. #endif
  228.     if (BigList != (bHeaderPtr) Nil) {
  229.         PreviousHdr = BigList;
  230.         CurrentHdr = PreviousHdr->bNext;
  231.         oldSize = PreviousHdr->bSize;  /* save real size field, then ... */
  232.         PreviousHdr->bSize = nBytes;        /* ... forge a stopper value */
  233.         while (CurrentHdr->bSize < nBytes) {
  234.             PreviousHdr = CurrentHdr;
  235.             CurrentHdr = PreviousHdr->bNext;
  236.         } /* this loop always terminates due to the stopper value */
  237.         BigList->bSize = oldSize;    /* restore old size */
  238.         if (CurrentHdr->bSize >= nBytes) {   /* MiscFit worked */
  239.             PreviousHdr->bNext = CurrentHdr->bNext;
  240.             BigList =
  241.                 (PreviousHdr==CurrentHdr ? (bHeaderPtr) Nil : PreviousHdr);
  242.         CurrentHdr->bSize |= SETMAGIC;
  243. #ifndef NOEMALLOC
  244.             CurrentHdr->bNext = (bHeaderPtr) SETMAGIC;
  245. #endif  NOEMALLOC
  246.             newBlock = (char *) (CurrentHdr+1);
  247.         }
  248.     }
  249. #ifdef GORP
  250. printf( "   MiscFit returns %x.\n", newBlock);
  251. #endif
  252.     return( newBlock );
  253. } /* MiscFit */
  254.  
  255. /* p = malloc(nBytes);
  256.  * where nBytes is the number of bytes needed and p is some pointer
  257.  */
  258.  
  259. static sHeaderPtr AvailList[MaxGrains-MinGrains+1];
  260. /* AvailList[MinGrains .. MaxGrains] is for ExactFit blocks
  261.  *
  262.  * AvailList[MinGrains..MaxGrains] each point to a LIFO singly-linked list of
  263.  * equal sized blocks.  These lists are used in the ExactFit portion of the
  264.  * algorithm.
  265.  */
  266.  
  267. char *__malloc(fReqBytes)
  268. int fReqBytes;
  269. {
  270.     register unsigned reqBytes = (unsigned) fReqBytes;
  271.     register char *newBlock;
  272.     register unsigned nGrains = BtoG(reqBytes);
  273. #ifndef DONTUSEHOLDSIGS
  274.     extern int SigsHeld;
  275.     int SigsWereHeld;    
  276.  
  277.     SigsWereHeld = SigsHeld;
  278.     if (!SigsWereHeld) HoldSigs();  /* Make sure HoldSigs is called once (if 
  279.                            it wasn't already) if running in Eden
  280.                        Kernel context */
  281. #endif DONTUSEHOLDSIGS
  282.  
  283. #ifdef GORP
  284. printf( "malloc(%d) called.\n", (unsigned int) reqBytes);
  285. #endif
  286.  
  287.     if (reqBytes > MaxBytes) {
  288.         register unsigned nBytes = GtoB(nGrains);
  289.         newBlock = MiscFit(nBytes);
  290.         if (newBlock == Nil) {
  291.             register bHeaderPtr newRawBlock = 
  292.                             (bHeaderPtr) TailFit(nBytes + sizeof(bHeader));
  293.             if (newRawBlock == (bHeaderPtr) Nil) {
  294.                 newBlock = Nil;
  295.             } else {
  296.                 newBlock = (char *) (newRawBlock+1);
  297.                 newRawBlock->bSize = nBytes | SETMAGIC;
  298. #ifndef NOEMALLOC
  299.                 newRawBlock->bNext = (bHeaderPtr) SETMAGIC;
  300. #endif  NOEMALLOC
  301.             }
  302.         }
  303.     } else {
  304.         register sHeaderPtr newRawBlock = AvailList[nGrains];
  305.         if (newRawBlock != (sHeaderPtr) Nil) {
  306.             AvailList[nGrains] = newRawBlock->sNext;
  307.             newRawBlock->sSize = GtoB(nGrains) | SETMAGIC;
  308.             newBlock = (char *) (newRawBlock + 1);
  309.         } else {
  310.             newRawBlock = (sHeaderPtr) TailFit(GtoB(nGrains)+sizeof(sHeader));
  311.             if (newRawBlock == (sHeaderPtr) Nil) {
  312.                 newBlock = Nil;
  313.             } else {
  314.                 newBlock = (char *) (newRawBlock + 1);
  315.                 newRawBlock->sSize = GtoB(nGrains) | SETMAGIC;
  316.             }
  317.         }
  318.     }
  319. #ifdef GORP
  320.     printf( "malloc returns %x.\n", newBlock);
  321.     (void) fflush(stderr);
  322. #endif
  323.  
  324. #ifndef DONTUSEHOLDSIGS
  325.     if (!SigsWereHeld) ReleaseSigs();
  326. #endif DONTUSEHOLDSIGS
  327.  
  328.     return( newBlock );
  329. } /* malloc */
  330.  
  331. /**********************************************************************/
  332. /*      Free                                                          */
  333. /**********************************************************************/
  334.  
  335. __free(ptr)
  336. char *ptr;
  337. {
  338.     register sHeaderPtr oldBlock = ((sHeaderPtr) ptr) - 1;
  339.     register unsigned nGrains = BtoG( (oldBlock->sSize & CLRMAGIC) );
  340.  
  341. #ifndef DONTUSEHOLDSIGS
  342.     extern int SigsHeld;
  343.     int SigsWereHeld;    
  344.  
  345.     SigsWereHeld = SigsHeld;
  346.     if (!SigsWereHeld) HoldSigs();  /* Make sure HoldSigs is called once (if 
  347.                            it was not already) if running in Eden
  348.                        Kernel context */
  349. #endif  DONTUSEHOLDSIGS
  350.  
  351.     if ( ! (oldBlock->sSize & SETMAGIC) ) {
  352.     /* already free */
  353. printf( "free(%x) called returning %d grains (already free!).\n",
  354.     ptr, nGrains);
  355.     return;
  356.     }
  357.     else oldBlock->sSize &= CLRMAGIC;
  358.  
  359. #ifdef GORP
  360. printf( "free(%x) called returning %d grains.\n", ptr, nGrains);
  361. #endif
  362.  
  363.     if (nGrains <= MaxGrains) {
  364.         oldBlock->sNext = AvailList[nGrains];
  365.         AvailList[nGrains] = oldBlock;
  366.     } else {
  367.         register bHeaderPtr oldBlock2 = ((bHeaderPtr) ptr) - 1;
  368.         if (BigList == (bHeaderPtr) Nil) {
  369.             BigList = oldBlock2;
  370.             oldBlock2->bNext = oldBlock2;
  371.         } else {
  372.             oldBlock2->bNext = BigList->bNext;
  373.             BigList->bNext = oldBlock2;
  374.         }
  375.     }
  376.  
  377. #ifdef GORP
  378.     (void) fflush(stderr);
  379. #endif
  380. #ifndef DONTUSEHOLDSIGS
  381.     if (!SigsWereHeld) ReleaseSigs();
  382. #endif DONTUSEHOLDSIGS
  383.  
  384. } /* free */
  385.  
  386. /**********************************************************************/
  387. /*      Realloc                                                       */
  388. /**********************************************************************/
  389.  
  390. char *__realloc(oldBlock, nBytes)
  391. register char *oldBlock;
  392. unsigned nBytes;
  393. {
  394.     register char *newBlock = __malloc((int) nBytes);
  395.  
  396. #ifndef DONTUSEHOLDSIGS
  397.     extern int SigsHeld;
  398.     int SigsWereHeld;    
  399.  
  400.     SigsWereHeld = SigsHeld;
  401.     if (!SigsWereHeld) HoldSigs();  /* Make sure HoldSigs is called once (if 
  402.                            it wasn't already) if running in Eden
  403.                        Kernel context */
  404. #endif DONTUSEHOLDSIGS
  405.  
  406.     if (newBlock != Nil) {
  407.         register int *newPtr = (int *) newBlock;
  408.         register int *oldPtr = (int *) oldBlock;
  409.         register sHeaderPtr oldRawBlock = ((sHeaderPtr) oldPtr) - 1;
  410.         register unsigned count =  (GrainSize/sizeof(int)) *
  411.             ((oldRawBlock->sSize > nBytes)
  412.              ? BtoG(nBytes)
  413.              : BtoG((oldRawBlock->sSize & CLRMAGIC)));
  414.         while (count != 0) {
  415.             *newPtr++ = *oldPtr++;
  416.             count--;
  417.         }
  418.         *newPtr++ = *oldPtr++;
  419.         __free(oldBlock);
  420.     }
  421.  
  422. #ifndef DONTUSEHOLDSIGS
  423.     if (!SigsWereHeld) ReleaseSigs();
  424. #endif  DONTUSEHOLDSIGS
  425.     return( newBlock );
  426. } /* realloc */
  427.  
  428.  
  429. #ifndef NOEMALLOC
  430. /**********************************************************************/
  431. /*      EmMiscFit                                                     */
  432. /**********************************************************************/
  433.  
  434. static char *EmMiscFit(nBytes)
  435. register unsigned nBytes;
  436. {
  437.     register bHeaderPtr CurrentHdr, PreviousHdr;
  438.     register unsigned oldSize;
  439.     register char *newBlock = Nil;
  440. #ifdef GORP
  441.     printf( "   EmMiscFit(%d) called.\n", nBytes);
  442. #endif
  443.     if (BigList != (bHeaderPtr) Nil) {
  444.         PreviousHdr = BigList;
  445.         CurrentHdr = PreviousHdr->bNext;
  446.         oldSize = PreviousHdr->bSize;  /* save real size field, then ... */
  447.         PreviousHdr->bSize = nBytes;        /* ... forge a stopper value */
  448.         while (CurrentHdr->bSize < nBytes) {
  449.             PreviousHdr = CurrentHdr;
  450.             CurrentHdr = PreviousHdr->bNext;
  451.         } /* this loop always terminates due to the stopper value */
  452.         BigList->bSize = oldSize;    /* restore old size */
  453.         if (CurrentHdr->bSize >= nBytes) {   /* EmMiscFit worked */
  454.             PreviousHdr->bNext = CurrentHdr->bNext;
  455.             BigList =
  456.                 (PreviousHdr==CurrentHdr ? (bHeaderPtr) Nil : PreviousHdr);
  457.         CurrentHdr->bSize |= EMSETMAGIC;
  458.             CurrentHdr->bNext =  (bHeaderPtr) EMSETMAGIC;
  459.             newBlock = (char *) (CurrentHdr+1);
  460.         }
  461.     }
  462. #ifdef GORP
  463.     printf( "   EmMiscFit returns %x.\n", newBlock);
  464. #endif
  465.     return( newBlock );
  466. } /* EmMiscFit */
  467.  
  468. /**********************************************************************/
  469. /*      emalloc                                                       */
  470. /**********************************************************************/
  471.  
  472. char *emalloc(fReqBytes)
  473. int fReqBytes;
  474. {
  475.     register unsigned reqBytes = (unsigned) fReqBytes+sizeof(int) + 0 /* Safety */;
  476.     register char *newBlock;
  477.     register unsigned nGrains = BtoG(reqBytes);
  478. #ifndef DONTUSEHOLDSIGS
  479.     extern int SigsHeld;
  480.     int SigsWereHeld;    
  481.  
  482.     SigsWereHeld = SigsHeld;
  483.     if (!SigsWereHeld) HoldSigs();  /* Make sure HoldSigs is called once (if 
  484.                            it wasn't already) if running in Eden
  485.                        Kernel context */
  486. #endif DONTUSEHOLDSIGS
  487.  
  488. #ifdef GORP
  489.     printf( "emalloc(%d) called.\n", (unsigned int) reqBytes);
  490. #endif
  491.  
  492.  
  493.     if (reqBytes > MaxBytes) {
  494.         register unsigned nBytes = GtoB(nGrains);
  495.         newBlock = EmMiscFit(nBytes);
  496.         if (newBlock == Nil) {
  497.             register bHeaderPtr newRawBlock = 
  498.                             (bHeaderPtr) TailFit(nBytes + sizeof(bHeader));
  499.             if (newRawBlock == (bHeaderPtr) Nil) {
  500.                 newBlock = Nil;
  501.             } else {
  502.                 newBlock = (char *) (newRawBlock+1);
  503.                 newRawBlock->bSize = nBytes | EMSETMAGIC;
  504.                 newRawBlock->bNext = (bHeaderPtr) EMSETMAGIC;
  505.             }
  506.         }
  507.     } else {
  508.         register sHeaderPtr newRawBlock = AvailList[nGrains];
  509.         if (newRawBlock != (sHeaderPtr) Nil) {
  510.             AvailList[nGrains] = newRawBlock->sNext;
  511.             newRawBlock->sSize = GtoB(nGrains) | EMSETMAGIC;
  512.             newBlock = (char *) (newRawBlock + 1);
  513.         } else {
  514.             newRawBlock = (sHeaderPtr) TailFit(GtoB(nGrains)+sizeof(sHeader));
  515.             if (newRawBlock == (sHeaderPtr) Nil) {
  516.                 newBlock = Nil;
  517.             } else {
  518.                 newBlock = (char *) (newRawBlock + 1);
  519.                 newRawBlock->sSize = GtoB(nGrains) | EMSETMAGIC;
  520.             }
  521.         }
  522.     }
  523. #ifdef GORP
  524. printf( "emalloc returns %x.\n", newBlock);
  525. (void) fflush(stderr);
  526. #endif
  527.  
  528. #ifndef DONTUSEHOLDSIGS
  529.     if (!SigsWereHeld) ReleaseSigs();
  530. #endif DONTUSEHOLDSIGS
  531.  
  532.     KMDTrace("Emalloc", 3, "Emalloc %3d bytes returns addr 0x%04x\n",
  533.     reqBytes, newBlock);
  534.  
  535.     return( newBlock );
  536. } /* emalloc */
  537.  
  538. /**********************************************************************/
  539. /*      emfree                                                        */
  540. /**********************************************************************/
  541.  
  542. void emfree(ptr)
  543. char *ptr;
  544. {
  545.     register sHeaderPtr oldBlock = ((sHeaderPtr) ptr) - 1;
  546.     register unsigned nGrains = BtoG( (oldBlock->sSize & CLRMAGIC) );
  547.  
  548. #ifndef DONTUSEHOLDSIGS
  549.     extern int SigsHeld;
  550.     int SigsWereHeld;    
  551.  
  552.     SigsWereHeld = SigsHeld;
  553.     if (!SigsWereHeld) HoldSigs();  /* Make sure HoldSigs is called once (if 
  554.                            it was not already) if running in Eden
  555.                        Kernel context */
  556. #endif  DONTUSEHOLDSIGS
  557.  
  558.     KMDTrace("Emalloc", 3, "emfree(0x%04x)\n", ptr);
  559.     
  560.     if ( ! (oldBlock->sSize & EMSETMAGIC) ) {
  561.     /* already free */
  562.     printf(
  563.         "free(%x) called returning %d grains (already free!).\n",
  564.         ptr, nGrains);
  565.         abort();
  566.     return;
  567.     }
  568.     else oldBlock->sSize &= CLRMAGIC;
  569.  
  570. #ifdef GORP
  571. printf( "free(%x) called returning %d grains.\n", ptr, nGrains);
  572. #endif
  573.  
  574.     if (nGrains <= MaxGrains) {
  575.         oldBlock->sNext = AvailList[nGrains];
  576.         AvailList[nGrains] = oldBlock;
  577.     } else {
  578.         register bHeaderPtr oldBlock2 = ((bHeaderPtr) ptr) - 1;
  579.         if (BigList == (bHeaderPtr) Nil) {
  580.             BigList = oldBlock2;
  581.             oldBlock2->bNext = oldBlock2;
  582.         } else {
  583.             oldBlock2->bNext = BigList->bNext;
  584.             BigList->bNext = oldBlock2;
  585.         }
  586.     }
  587.  
  588. #ifdef GORP
  589.     (void) fflush(stderr);
  590. #endif
  591. #ifndef DONTUSEHOLDSIGS
  592.     if (!SigsWereHeld) ReleaseSigs();
  593. #endif DONTUSEHOLDSIGS
  594.  
  595. } /* emfree */
  596.  
  597. /**********************************************************************/
  598. /*      EmallocDump                                                   */
  599. /**********************************************************************/
  600.  
  601. /* Snapshot */
  602. void EmallocDump()
  603. {
  604.     register sHeaderPtr         s;
  605.     register bHeaderPtr         b;
  606.     register unsigned int       mark;
  607.     register unsigned int       size;
  608.     register int                isBig;
  609.     
  610.     KMDPrint("EmallocDump called\n");
  611.     KMDPrint("Addr\tSize\tSize\tUsage\n");
  612.     
  613.     for (s = (sHeaderPtr) firstAllocated; (char *) s < TailMin;) {
  614.         mark = (s->sSize & ~CLRMAGIC);
  615.         size = (s->sSize & CLRMAGIC);
  616.         
  617.     if (isBig = (size == 0)) {
  618.         /* It is a big block */
  619.             b = (bHeaderPtr) (s);
  620.             size = (b->bSize & CLRMAGIC);
  621.     }
  622.         if (mark == SETMAGIC) {
  623.         KMDPrint("%06x\t%06x\t%06d\tKernel\t%s\n",
  624.         (isBig ? (char *) (b+1) : (char *) (s+1)), size, size,
  625.         (isBig ? "Big" : ""));
  626.     } else if (mark == EMSETMAGIC) {
  627.         KMDPrint("%06x\t%06x\t%06d\tEm\t%s\n",
  628.         (isBig ? (char *) (b+1) : (char *) (s+1)), size, size,
  629.         (isBig ? "Big" : ""));
  630.     } else if (mark == 0) {
  631.         KMDPrint("%06x\t%06x\t%06d\tFree\t%s\n",
  632.         (isBig ? (char *) (b+1) : (char *) (s+1)), size, size,
  633.         (isBig ? "Big" : ""));
  634.     } else {
  635.         /* error */
  636.             abort();
  637.     }
  638.         s = (sHeaderPtr) ( (char *) s + size +
  639.             (isBig ? sizeof(bHeader) : sizeof(sHeader)));
  640.     }
  641.     KMDPrint("Done\n");
  642. }
  643.  
  644. /**********************************************************************/
  645. /*      EmallocDump                                                   */
  646. /**********************************************************************/
  647.  
  648. void EmallocForEach(fHandlerPtr)
  649. GenericHandlerPtr           fHandlerPtr;
  650. /* Calls the given handler for each allocated Emerald Data Area.      */
  651. /* Declaration for callback:  void CallBack(fAddr, fSize)             */
  652. {
  653.     register sHeaderPtr         s;
  654.     register bHeaderPtr         b;
  655.     register unsigned int       mark;
  656.     register unsigned int       size;
  657.     register int                isBig;
  658.     
  659.     
  660.     for (s = (sHeaderPtr) firstAllocated; (char *) s < TailMin;) {
  661.         mark = (s->sSize & ~CLRMAGIC);
  662.         size = (s->sSize & CLRMAGIC);
  663.         
  664.     if (isBig = (size == 0)) {
  665.         /* It is a big block */
  666.             b = (bHeaderPtr) (s);
  667.             size = (b->bSize & CLRMAGIC);
  668.     }
  669.         if (mark == SETMAGIC) {
  670.             /* Skip normal data areas */
  671.     } else if (mark == EMSETMAGIC) {
  672.             /* Call back for Emerald data areas */
  673.             (*fHandlerPtr)(isBig ? (int) (b+1) : (int) (s+1), size);
  674.     } else if (mark == 0) {
  675.             /* Skip unallocated data areas */
  676.     } else {
  677.         ErrMsg("error: allocation invariant broken at 0x%06x\m",
  678.             s);
  679.         ErrMsg("firstAllocated: 0x%06x, mark: 0x%02x\n", firstAllocated,
  680.           mark);
  681.             abort();
  682.     }
  683.         s = (sHeaderPtr) ( (char *) s + size +
  684.             (isBig ? sizeof(bHeader) : sizeof(sHeader)));
  685.     }
  686. }
  687.  
  688. /**********************************************************************/
  689. /*      emallocnil                                                    */
  690. /**********************************************************************/
  691.  
  692. char *emallocnil(fReqBytes)
  693. int fReqBytes;
  694. /* Same as emalloc but nil out the area except for the first two words */
  695. {
  696.     register char          *q;
  697.     register int           *x, *last;
  698.     q                       = emalloc(fReqBytes);
  699.     last                    = (int *) (q + fReqBytes - fReqBytes % 4);
  700.     for (x = ((int *) q) + 2; x < last; x++) {
  701.     *x = (int) EMNIL;
  702.     }
  703.     return ((char *) q);
  704. }
  705.  
  706. /**********************************************************************/
  707. /*      EmallocInit                                                   */
  708. /**********************************************************************/
  709.  
  710. void EmallocInit()
  711. {
  712.     KMDSetSnap(EmallocDump);
  713.     KMDSetTrace(Emalloc);
  714.     KMDTrace("Emalloc", 5, "Emalloc\n");
  715. }
  716.  
  717. #endif  NOEMALLOC
  718.  
  719.