memPartLib.c
上传用户:nvosite88
上传日期:2007-01-17
资源大小:4983k
文件大小:30k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* memPartLib.c - core memory partition manager */
  2. /* Copyright 1984-2002 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 02c,22may02,zl   use the ALIGNED() macro for alignment test (SPR#74247).
  8. 02b,23apr02,gls  added check for overflow in memPartAlignedAlloc (SPR #27741)
  9. 02a,04oct01,tam  fixed doc. of arch alignment
  10. 01z,03mar00,zl   merged SH support into T2
  11. 01y,15mar99,c_c  Doc: Fixed alignment for MIPS (SPR #8883).
  12. 01x,21feb99,jdi  doc: listed errnos.
  13. 01w,17feb98,dvs  added instrumentation points (pr)
  14. 01v,17dec97,yp   corrected documentation for memPartIsValid (SPR #8537)
  15. 01u,07oct96,dgp  doc: change description of memPartXxx() (no partition
  16.  deletion available)
  17. 01t,19mar95,dvs  removed tron references.
  18. 01s,19sep94,rhp  added stdlib.h to INCLUDE FILES list in doc (SPR#2285)
  19. 01r,13sep93,jmm  fixed memPartAddToPool to check correct sizes of memory
  20. 01q,24jun93,jmm  fixed memPartAddToPool to reject pool sizes that are too small
  21. 01p,24jun93,jmm  fixed memPartAddToPool to round poolSize down to alignment
  22.                  boundry (spr 2185)
  23. 01o,10feb93,jdi  deleted mention of "error" handling in doc for free();
  24.  fixed spelling of stdlib.h.
  25. 01n,05feb93,jdi  tweaked wording for 01m.
  26. 01m,05feb93,smb  corrected return documentation for free and malloc
  27. 01l,23jan93,jdi  documentation cleanup for 5.1.
  28. 01k,13nov92,dnw  added include of smObjLib.h
  29. 01j,20oct92,pme  added reference to shared memory manager documentation.
  30. 01i,02oct92,jdi  documentation cleanup.
  31. 01h,08sep92,jmm  changed memPartFree() to mark coalesced blocks as not free
  32. 01g,23aug92,jcf  changed bzero to bfill.  removed taskOptionsGet.
  33. 01f,29jul92,pme  added NULL function pointer check for smObj routines.
  34. 01e,28jul92,jcf  changed default memory partition options.
  35.  moved MEM_BLOCK_ERROR_SUSPEND_FLAG handling here.
  36. 01d,19jul92,pme  added shared memory partition support.
  37. 01c,19jul92,smb  added some ANSI documentation.
  38. 01b,18jul92,smb  Changed errno.h to errnoLib.h.
  39. 01a,01jul92,jcf  extracted from v4n memLib.c
  40. */
  41. /*
  42. DESCRIPTION
  43. This library provides core facilities for managing the allocation of
  44. blocks of memory from ranges of memory called memory partitions.  The
  45. library was designed to provide a compact implementation; full-featured
  46. functionality is available with memLib, which provides enhanced memory
  47. management features built as an extension of memPartLib.  (For more
  48. information about enhanced memory partition management options, see the
  49. manual entry for memLib.)  This library consists of two sets of routines.
  50. The first set, memPart...(), comprises a general facility for the creation
  51. and management of memory partitions, and for the allocation and deallocation
  52. of blocks from those partitions.  The second set provides a traditional
  53. ANSI-compatible malloc()/free() interface to the system memory partition.
  54. The system memory partition is created when the kernel is initialized by
  55. kernelInit(), which is called by the root task, usrRoot(), in
  56. usrConfig.c.  The ID of the system memory partition is stored in the
  57. global variable `memSysPartId'; its declaration is included in memLib.h.
  58. The allocation of memory, using malloc() in the typical case and
  59. memPartAlloc() for a specific memory partition, is done with a first-fit
  60. algorithm.  Adjacent blocks of memory are coalesced when they are freed
  61. with memPartFree() and free().  There is also a routine provided for allocating
  62. memory aligned to a specified boundary from a specific memory partition,
  63. memPartAlignedAlloc().
  64. CAVEATS
  65. Architectures have various alignment constraints.  To provide optimal
  66. performance, malloc() returns a pointer to a buffer having the appropriate
  67. alignment for the architecture in use.  The portion of the allocated
  68. buffer reserved for system bookkeeping, known as the overhead, may vary
  69. depending on the architecture.
  70. .ne 12
  71. .TS
  72. center,tab(|);
  73. lf3 cf3 cf3
  74. a n n .
  75. Architecture | Boundary | Overhead
  76. _
  77.  ARM       |   4  |   8
  78.  COLDFIRE  |   4  |   8
  79.  I86       |   4  |   8
  80.  M68K      |   4  |   8
  81.  MCORE     |   8  |   8
  82.  MIPS      |  16  |  16
  83.  PPC *     | 8/16 | 8/16
  84.  SH        |   4  |   8
  85.  SIMNT     |   8  |   8
  86.  SIMSOLARIS|   8  |   8
  87.  SPARC     |   8  |   8
  88. .TE
  89. * On PowerPC, the boundary and overhead values are 16 bytes for system based
  90. on the PPC604 CPU type (including ALTIVEC). For all other PowerPC CPU types
  91. (PPC403, PPC405, PPC440, PPC860, PPC603, etc...), the boundary and overhead 
  92. are 8 bytes.
  93. INCLUDE FILES: memLib.h, stdlib.h
  94. SEE ALSO: memLib, smMemLib
  95. INTERNAL
  96. This package is initialized by kernelInit() which calls memInit() with a
  97. pointer to a block of memory from which memory will be allocated.
  98. Blocks allocated by malloc() are actually larger than the size requested
  99. by the user.  Each block is prefaced by a header which contains the size
  100. and status of that block and a pointer to the previous block.  The pointer
  101. returned to the user points just past this header.  Likewise when a block
  102. is freed, the header is found just in front of the block pointer passed by
  103. the user.
  104. The header data is arranged so that the pointer to the previous block
  105. comes first and is therefore adjacent to that previous block.  Thus each
  106. block has 4 bytes of redundant information on either side of it (the 4
  107. bytes of size and status before it in its own header, and the 4-byte
  108. pointer after it in the next header).  This redundant information is
  109. optionally used in free() and realloc() to make a consistency check on
  110. blocks specified by the user.  This mechanism helps to detect two common
  111. errors: (1) bad block pointers passed to free() or realloc() are usually
  112. detected, and (2) trashing up to 4 bytes on either side of the block will
  113. only affect that block and will also be detected by free() or realloc().
  114. There is a minimum block size which malloc() allocates; this is to insure
  115. that there will be enough room for the free list links that must be used
  116. when the block is freed if it cannot be coalesced with an adjacent block.
  117. The malloc() and realloc() routines always allocate memory aligned to the 
  118. boundary defined in the global variable memDefaultAlignment, which is 
  119. initialized to the alignment required for the specific architecture.
  120. The memory partition semaphore is a structure in the partition descriptor
  121. rather than a pointer to a dynamically created semaphore structure.
  122. This is because of the chicken-and-the-egg problem of memLib using semaphores
  123. and semCreate calling malloc.  Instead the structure is simply declared
  124. directly in the partition structure and we call semInit() instead of
  125. semCreate().
  126. */
  127. #include "vxWorks.h"
  128. #include "semLib.h"
  129. #include "dllLib.h"
  130. #include "logLib.h"
  131. #include "taskLib.h"
  132. #include "stdlib.h"
  133. #include "stdio.h"
  134. #include "string.h"
  135. #include "errnoLib.h"
  136. #include "smObjLib.h"
  137. #include "private/memPartLibP.h"
  138. #include "private/eventP.h"
  139. /* forward static functions */
  140. LOCAL void  memPartSemInit (PART_ID partId);
  141. LOCAL STATUS  memPartDestroy (PART_ID partId);
  142. LOCAL BLOCK_HDR *memAlignedBlockSplit (PART_ID partId, BLOCK_HDR *pHdr, 
  143.        unsigned nWords, unsigned minWords,
  144.        unsigned alignment);
  145. /* local variables */
  146. LOCAL PARTITION memSysPartition; /* system partition used by malloc */
  147. LOCAL OBJ_CLASS memPartClass; /* memory partition object class */
  148. LOCAL BOOL memPartLibInstalled; /* TRUE if library has been installed */
  149. #ifdef WV_INSTRUMENTATION
  150. LOCAL OBJ_CLASS memPartInstClass; /* mem part instrumented object class */
  151. #endif
  152. /* global variables */
  153. FUNCPTR  smMemPartAddToPoolRtn = NULL;
  154. FUNCPTR  smMemPartFreeRtn = NULL;
  155. FUNCPTR  smMemPartAllocRtn = NULL;
  156. CLASS_ID memPartClassId  = &memPartClass; /* partition class id */
  157. #ifdef WV_INSTRUMENTATION
  158. CLASS_ID memPartInstClassId = &memPartInstClass;    /* part inst class id */
  159. #endif
  160. PART_ID  memSysPartId = &memSysPartition; /* sys partition id */
  161. UINT  memDefaultAlignment = _ALLOC_ALIGN_SIZE; /* default alignment */
  162. FUNCPTR  memPartBlockErrorRtn = NULL; /* block error method */
  163. FUNCPTR  memPartAllocErrorRtn = NULL; /* alloc error method */
  164. FUNCPTR  memPartSemInitRtn = (FUNCPTR) memPartSemInit;
  165. unsigned memPartOptionsDefault = MEM_BLOCK_ERROR_SUSPEND_FLAG |
  166.   MEM_BLOCK_CHECK;
  167. /*******************************************************************************
  168. *
  169. * memPartLibInit - initialize the system memory partition
  170. *
  171. * This routine initializes the system partition free list with the
  172. * specified memory block.  It must be called exactly once before invoking any
  173. * other routine in memLib.  It is called by kernelInit() in usrRoot()
  174. * in usrConfig.c.
  175. *
  176. * RETURNS: OK or ERROR.
  177. * NOMANUAL
  178. */
  179. STATUS memPartLibInit 
  180.     (
  181.     char *pPool,        /* pointer to memory block */
  182.     unsigned poolSize   /* block size in bytes */
  183.     )
  184.     {
  185.     if ((!memPartLibInstalled) &&
  186. (classInit (memPartClassId, sizeof (PARTITION),
  187.     OFFSET (PARTITION, objCore), (FUNCPTR) memPartCreate,
  188.     (FUNCPTR) memPartInit, (FUNCPTR) memPartDestroy) == OK))
  189. {
  190. #ifdef WV_INSTRUMENTATION
  191. /* Instrumented class for windview */
  192. memPartClassId->initRtn = (FUNCPTR) memPartInstClassId;
  193. classInstrument (memPartClassId, memPartInstClassId); 
  194. #endif
  195. memPartInit (&memSysPartition, pPool, poolSize);
  196. memPartLibInstalled = TRUE;
  197. }
  198.     return ((memPartLibInstalled) ? OK : ERROR);
  199.     }
  200. /*******************************************************************************
  201. *
  202. * memPartCreate - create a memory partition
  203. *
  204. * This routine creates a new memory partition containing a specified
  205. * memory pool.  It returns a partition ID, which can then be passed to
  206. * other routines to manage the partition (i.e., to allocate and free
  207. * memory blocks in the partition).  Partitions can be created to manage
  208. * any number of separate memory pools.
  209. *
  210. * NOTE
  211. * The descriptor for the new partition is allocated out of the system memory
  212. * partition (i.e., with malloc()).
  213. *
  214. * RETURNS:
  215. * The partition ID, or NULL if there is insufficient memory in the system
  216. * memory partition for a new partition descriptor.
  217. *
  218. * SEE ALSO: smMemLib
  219. */
  220. PART_ID memPartCreate 
  221.     (
  222.     char *pPool,        /* pointer to memory area */
  223.     unsigned poolSize   /* size in bytes */
  224.     )
  225.     {
  226.     FAST PART_ID pPart;
  227.     /* allocate a partition structure from the system memory partition */
  228.     pPart = (PART_ID) objAlloc (memPartClassId);
  229.     if (pPart != NULL)
  230. memPartInit (pPart, pPool, poolSize);
  231. #ifdef WV_INSTRUMENTATION
  232.     EVT_OBJ_2 (OBJ, pPart, memPartClassId, EVENT_MEMPARTCREATE, pPart, poolSize);
  233. #endif
  234.     return (pPart);
  235.     }
  236. /*******************************************************************************
  237. *
  238. * memPartInit - initialize a memory partition
  239. *
  240. * This routine initializes a partition free list, seeding it with the
  241. * memory block passed as an argument.  It must be called exactly once
  242. * for each memory partition created.
  243. *
  244. * SEE ALSO: memPartCreate()
  245. *
  246. * NOMANUAL
  247. */
  248. void memPartInit 
  249.     (
  250.     FAST PART_ID partId,        /* partition to initialize */
  251.     char *pPool,                /* pointer to memory block */
  252.     unsigned poolSize           /* block size in bytes */
  253.     )
  254.     {
  255.     /* initialize partition descriptor */
  256.     bfill ((char *) partId, sizeof (*partId), 0);
  257.     partId->options   = memPartOptionsDefault;
  258.     partId->minBlockWords = sizeof (FREE_BLOCK) >> 1;
  259.     /* initialize partition semaphore with a virtual function so semaphore
  260.      * type is selectable.  By default memPartLibInit() will utilize binary
  261.      * semaphores while memInit() will utilize mutual exclusion semaphores
  262.      * with the options stored in _mutexOptionsMemLib.
  263.      */
  264.     (* memPartSemInitRtn) (partId);
  265.     dllInit (&partId->freeList); /* init. free list */
  266. #ifdef WV_INSTRUMENTATION
  267.     if (wvObjIsEnabled)
  268.     {
  269.     /* windview - connect object class event logging routine */
  270.     objCoreInit (&partId->objCore, memPartInstClassId); 
  271.     }
  272.     else
  273. #endif
  274.     objCoreInit (&partId->objCore, memPartClassId); /* initialize core */
  275.     (void) memPartAddToPool (partId, pPool, poolSize);
  276.     }
  277. /*******************************************************************************
  278. *
  279. * memPartDestroy - destroy a partition and optionally free associated memory
  280. *
  281. * This routine is not currently supported.  Partitions may not be destroyed.
  282. *
  283. * ARGSUSED
  284. */
  285. LOCAL STATUS memPartDestroy 
  286.     (
  287.     PART_ID partId      /* partition to initialize */
  288.     )
  289.     {
  290.     errno = S_memLib_NO_PARTITION_DESTROY;
  291.     return (ERROR);
  292.     }
  293. /*******************************************************************************
  294. *
  295. * memPartAddToPool - add memory to a memory partition
  296. *
  297. * This routine adds memory to a specified memory partition already created
  298. * with memPartCreate().  The memory added need not be contiguous with
  299. * memory previously assigned to the partition.
  300. *
  301. * RETURNS: OK or ERROR.
  302. *
  303. * ERRNO: S_smObjLib_NOT_INITIALIZED, S_memLib_INVALID_NBYTES
  304. *
  305. * SEE ALSO: smMemLib, memPartCreate()
  306. */
  307. STATUS memPartAddToPool 
  308.     (
  309.     FAST PART_ID partId,                /* partition to initialize */
  310.     FAST char *pPool,                   /* pointer to memory block */
  311.     FAST unsigned poolSize              /* block size in bytes */
  312.     )
  313.     {
  314.     FAST BLOCK_HDR *pHdrStart;
  315.     FAST BLOCK_HDR *pHdrMid;
  316.     FAST BLOCK_HDR *pHdrEnd;
  317.     char *          tmp;
  318.     int             reducePool; /* reduce size of pool by this amount*/
  319.     if (ID_IS_SHARED (partId))  /* partition is shared? */
  320.         {
  321. if (smMemPartAddToPoolRtn == NULL)
  322.     {
  323.     errno = S_smObjLib_NOT_INITIALIZED;
  324.     return (ERROR);
  325.     }
  326.         return ((*smMemPartAddToPoolRtn) (SM_OBJ_ID_TO_ADRS (partId), 
  327.   pPool, poolSize));
  328. }
  329.     /* partition is local */
  330.     if (OBJ_VERIFY (partId, memPartClassId) != OK)
  331. return (ERROR);
  332.     /* insure that the pool starts on an even byte boundary */
  333.     tmp       = (char *) MEM_ROUND_UP (pPool); /* get actual start */
  334.     reducePool = tmp - pPool;
  335.     if (poolSize >= reducePool)   /* adjust length */
  336.         poolSize -= reducePool;
  337.     else
  338.         poolSize = 0;
  339.     pPool     = tmp;
  340.     /*
  341.      * Make sure poolSize is an even multiple of the memory alignment size
  342.      * and is large enough to include at least one valid free block and
  343.      * three header blocks.
  344.      */
  345.     poolSize = MEM_ROUND_DOWN (poolSize);
  346.     if (poolSize < ((sizeof (BLOCK_HDR) * 3) + (partId->minBlockWords * 2)))
  347. {
  348. errno = S_memLib_INVALID_NBYTES;
  349.         return (ERROR);
  350. }
  351.     /* initialize three blocks -
  352.      * one at each end of the pool for end cases and real initial free block */
  353.     pHdrStart = (BLOCK_HDR *) pPool;
  354.     pHdrStart->pPrevHdr = NULL;
  355.     pHdrStart->free     = FALSE;
  356.     pHdrStart->nWords   = sizeof (BLOCK_HDR) >> 1;
  357.     pHdrMid = NEXT_HDR (pHdrStart);
  358.     pHdrMid->pPrevHdr   = pHdrStart;
  359.     pHdrMid->free       = TRUE;
  360.     pHdrMid->nWords     = (poolSize - 2 * sizeof (BLOCK_HDR)) >> 1;
  361.     pHdrEnd = NEXT_HDR (pHdrMid);
  362.     pHdrEnd->pPrevHdr   = pHdrMid;
  363.     pHdrEnd->free       = FALSE;
  364.     pHdrEnd->nWords     = sizeof (BLOCK_HDR) >> 1;
  365.     semTake (&partId->sem, WAIT_FOREVER);
  366. #ifdef WV_INSTRUMENTATION
  367.     EVT_OBJ_2 (OBJ, partId, memPartClassId, EVENT_MEMADDTOPOOL, partId, poolSize);
  368. #endif
  369.     dllInsert (&partId->freeList, (DL_NODE *) NULL, HDR_TO_NODE (pHdrMid));
  370.     partId->totalWords += (poolSize >> 1);
  371.     semGive (&partId->sem);
  372.     return (OK);
  373.     }
  374. /*******************************************************************************
  375. *
  376. * memPartAlignedAlloc - allocate aligned memory from a partition
  377. *
  378. * This routine allocates a buffer of size <nBytes> from a specified
  379. * partition.  Additionally, it insures that the allocated buffer begins on a
  380. * memory address evenly divisible by <alignment>.  The <alignment> parameter
  381. * must be a power of 2.
  382. *
  383. * RETURNS:
  384. * A pointer to the newly allocated block, or NULL if the buffer could not be
  385. * allocated.
  386. */
  387. void *memPartAlignedAlloc 
  388.     (
  389.     FAST PART_ID partId, /* memory partition to allocate from */
  390.     unsigned nBytes, /* number of bytes to allocate */
  391.     unsigned alignment /* boundary to align to */
  392.     )
  393.     {
  394.     FAST unsigned nWords;
  395.     FAST unsigned nWordsExtra;
  396.     FAST DL_NODE * pNode;
  397.     FAST BLOCK_HDR * pHdr;
  398.     BLOCK_HDR * pNewHdr;
  399.     BLOCK_HDR  origpHdr;
  400.     if (OBJ_VERIFY (partId, memPartClassId) != OK)
  401. return (NULL);
  402.     /* get actual size to allocate; add overhead, check for minimum */
  403.     nWords = (MEM_ROUND_UP (nBytes) + sizeof (BLOCK_HDR)) >> 1;
  404.     /* check if we have an overflow. if so, set errno and return NULL */
  405.     if ((nWords << 1) < nBytes)
  406. {
  407. if (memPartAllocErrorRtn != NULL)
  408.     (* memPartAllocErrorRtn) (partId, nBytes);
  409. errnoSet (S_memLib_NOT_ENOUGH_MEMORY);
  410. if (partId->options & MEM_ALLOC_ERROR_SUSPEND_FLAG)
  411.     {
  412.     if ((taskIdCurrent->options & VX_UNBREAKABLE) == 0)
  413. taskSuspend (0); /* suspend ourselves */
  414.     }
  415. return (NULL);
  416. }
  417.     if (nWords < partId->minBlockWords)
  418. nWords = partId->minBlockWords;
  419.     /* get exclusive access to the partition */
  420.     semTake (&partId->sem, WAIT_FOREVER);
  421.     /* first fit */
  422.     pNode = DLL_FIRST (&partId->freeList);
  423.     /* We need a free block with extra room to do the alignment.  
  424.      * Worst case we'll need alignment extra bytes.
  425.      */
  426.     nWordsExtra = nWords + alignment / 2;
  427.     FOREVER
  428. {
  429. while (pNode != NULL)
  430.     {
  431.     /* fits if:
  432.      * - blocksize > requested size + extra room for alignment or,
  433.      * - block is already aligned and exactly the right size
  434.      */
  435.     if ((NODE_TO_HDR (pNode)->nWords > nWordsExtra) ||
  436. ((NODE_TO_HDR (pNode)->nWords == nWords) &&
  437.  (ALIGNED (HDR_TO_BLOCK(NODE_TO_HDR(pNode)), alignment))))
  438.   break;
  439.     pNode = DLL_NEXT (pNode);
  440.     }
  441. if (pNode == NULL)
  442.     {
  443.     semGive (&partId->sem);
  444.     if (memPartAllocErrorRtn != NULL)
  445. (* memPartAllocErrorRtn) (partId, nBytes);
  446.     errnoSet (S_memLib_NOT_ENOUGH_MEMORY);
  447.     if (partId->options & MEM_ALLOC_ERROR_SUSPEND_FLAG)
  448. {
  449. if ((taskIdCurrent->options & VX_UNBREAKABLE) == 0)
  450.     taskSuspend (0); /* suspend ourselves */
  451. }
  452.     return (NULL);
  453.     }
  454. pHdr = NODE_TO_HDR (pNode);
  455. origpHdr = *pHdr;
  456. /* now we split off from this block, the amount required by the user;
  457.  * note that the piece we are giving the user is at the end of the
  458.  * block so that the remaining piece is still the piece that is
  459.  * linked in the free list;  if memAlignedBlockSplit returned NULL,
  460.  * it couldn't split the block because the split would leave the
  461.  * first block too small to be hung on the free list, so we continue
  462.  * trying blocks.
  463.  */
  464. pNewHdr = 
  465.     memAlignedBlockSplit (partId, pHdr, nWords, partId->minBlockWords,
  466.   alignment);
  467. if (pNewHdr != NULL)
  468.     {
  469.     pHdr = pNewHdr; /* give split off block */
  470.     break;
  471.     }
  472. pNode = DLL_NEXT (pNode);
  473. }
  474.     /* mark the block we're giving as not free */
  475.     pHdr->free = FALSE;
  476. #ifdef WV_INSTRUMENTATION
  477.     EVT_OBJ_4 (OBJ, partId, memPartClassId, EVENT_MEMALLOC, partId, HDR_TO_BLOCK (pHdr), 2 * (pHdr->nWords), nBytes);
  478. #endif
  479.     /* update allocation statistics */
  480.     partId->curBlocksAllocated++;
  481.     partId->cumBlocksAllocated++;
  482.     partId->curWordsAllocated += pHdr->nWords;
  483.     partId->cumWordsAllocated += pHdr->nWords;
  484.     semGive (&partId->sem);
  485.     return ((void *) HDR_TO_BLOCK (pHdr));
  486.     }
  487. /*******************************************************************************
  488. *
  489. * memPartAlloc - allocate a block of memory from a partition
  490. *
  491. * This routine allocates a block of memory from a specified partition. 
  492. * The size of the block will be equal to or greater than <nBytes>.  
  493. * The partition must already be created with memPartCreate().
  494. *
  495. * RETURNS:
  496. * A pointer to a block, or NULL if the call fails.
  497. *
  498. * ERRNO: S_smObjLib_NOT_INITIALIZED
  499. *
  500. * SEE ALSO: smMemLib, memPartCreate()
  501. */
  502. void *memPartAlloc 
  503.     (
  504.     FAST PART_ID partId,        /* memory partition to allocate from */
  505.     unsigned nBytes             /* number of bytes to allocate */
  506.     )
  507.     {
  508.     if (ID_IS_SHARED (partId))  /* partition is shared? */
  509.         {
  510. if (smMemPartAllocRtn == NULL)
  511.     {
  512.     errno = S_smObjLib_NOT_INITIALIZED;
  513.     return (NULL);
  514.     }
  515.         return ((void *) (*smMemPartAllocRtn) (SM_OBJ_ID_TO_ADRS (partId), 
  516.        nBytes));
  517. }
  518.     /* partition is local */
  519.     return (memPartAlignedAlloc (partId, nBytes, memDefaultAlignment));
  520.     }
  521. /*******************************************************************************
  522. *
  523. * memPartFree - free a block of memory in a partition
  524. *
  525. * This routine returns to a partition's free memory list a block of 
  526. * memory previously allocated with memPartAlloc().
  527. *
  528. * RETURNS: OK, or ERROR if the block is invalid.
  529. *
  530. * ERRNO: S_smObjLib_NOT_INITIALIZED
  531. *
  532. * SEE ALSO: smMemLib, memPartAlloc()
  533. */
  534. STATUS memPartFree 
  535.     (
  536.     PART_ID partId,     /* memory partition to add block to */
  537.     char *pBlock        /* pointer to block of memory to free */
  538.     )
  539.     {
  540.     FAST BLOCK_HDR *pHdr;
  541.     FAST unsigned   nWords;
  542.     FAST BLOCK_HDR *pNextHdr;
  543.     if (ID_IS_SHARED (partId))  /* partition is shared? */
  544.         {
  545. if (smMemPartFreeRtn == NULL)
  546.     {
  547.     errno = S_smObjLib_NOT_INITIALIZED;
  548.     return (ERROR);
  549.     }
  550.         return ((*smMemPartFreeRtn) (SM_OBJ_ID_TO_ADRS (partId), pBlock));
  551. }
  552.     /* partition is local */
  553.     if (OBJ_VERIFY (partId, memPartClassId) != OK)
  554. return (ERROR);
  555.     if (pBlock == NULL)
  556. return (OK); /* ANSI C compatibility */
  557.     pHdr   = BLOCK_TO_HDR (pBlock);
  558.     /* get exclusive access to the partition */
  559.     semTake (&partId->sem, WAIT_FOREVER);
  560.     /* optional check for validity of block */
  561.     if ((partId->options & MEM_BLOCK_CHECK) &&
  562.         !memPartBlockIsValid (partId, pHdr, FALSE))
  563. {
  564. semGive (&partId->sem); /* release mutual exclusion */
  565. if (memPartBlockErrorRtn != NULL)
  566.     (* memPartBlockErrorRtn) (partId, pBlock, "memPartFree");
  567. if (partId->options & MEM_BLOCK_ERROR_SUSPEND_FLAG)
  568.     {
  569.     if ((taskIdCurrent->options & VX_UNBREAKABLE) == 0)
  570. taskSuspend (0);
  571.     }
  572. errnoSet (S_memLib_BLOCK_ERROR);
  573. return (ERROR);
  574. }
  575. #ifdef WV_INSTRUMENTATION
  576.     EVT_OBJ_3 (OBJ, partId, memPartClassId, EVENT_MEMFREE, partId, pBlock, 2 * (pHdr->nWords));
  577. #endif
  578.     nWords = pHdr->nWords; 
  579.     /* check if we can coalesce with previous block;
  580.      * if so, then we just extend the previous block,
  581.      * otherwise we have to add this as a new free block */
  582.     if (PREV_HDR (pHdr)->free)
  583. {
  584. pHdr->free = FALSE;                 /* this isn't a free block */
  585. pHdr = PREV_HDR (pHdr); /* coalesce with prev block */
  586. pHdr->nWords += nWords;
  587. }
  588.     else
  589. {
  590. pHdr->free = TRUE; /* add new free block */
  591. dllInsert (&partId->freeList, (DL_NODE *) NULL, HDR_TO_NODE (pHdr));
  592. }
  593.     /* check if we can coalesce with next block;
  594.      * if so, then we can extend our block delete next block from free list */
  595.     pNextHdr = NEXT_HDR (pHdr);
  596.     if (pNextHdr->free)
  597. {
  598. pHdr->nWords += pNextHdr->nWords; /* coalesce with next */
  599. dllRemove (&partId->freeList, HDR_TO_NODE (pNextHdr));
  600. }
  601.     /* fix up prev info of whatever block is now next */
  602.     NEXT_HDR (pHdr)->pPrevHdr = pHdr;
  603.     /* adjust allocation stats */
  604.     partId->curBlocksAllocated--;
  605.     partId->curWordsAllocated -= nWords;
  606.     semGive (&partId->sem);
  607.     return (OK);
  608.     }
  609. /*******************************************************************************
  610. *
  611. * memPartBlockIsValid - check validity of block
  612. *
  613. * This routine checks the validity of a block. If the pointer to the block
  614. * header is bogus we could run into bus errors and the calling task could take
  615. * the partId semaphore with it. To prvent this from happening we make the task
  616. * preemption proof and release the semaphore before doing the block validity 
  617. * check. 
  618. *
  619. * NOMANUAL
  620. */
  621. BOOL memPartBlockIsValid 
  622.     (
  623.     PART_ID partId,
  624.     FAST BLOCK_HDR *pHdr,
  625.     BOOL isFree                 /* expected status */
  626.     )
  627.     {
  628.     BOOL valid;
  629.     TASK_LOCK (); /* LOCK PREEMPTION */
  630.     semGive (&partId->sem); /* release mutex */
  631.     valid = MEM_ALIGNED (pHdr) /* aligned */
  632.             && MEM_ALIGNED (2 * pHdr->nWords) /* size is round */
  633.             && (pHdr->nWords <= partId->totalWords) /* size <= total */
  634.     && (pHdr->free == isFree) /* right alloc-ness */
  635. #if (CPU_FAMILY == SH)
  636.     && MEM_ALIGNED(NEXT_HDR (pHdr)) /* aligned(08aug95,sa)*/
  637.     && MEM_ALIGNED(PREV_HDR (pHdr)) /* aligned(08aug95,sa)*/
  638. #endif
  639.     && (pHdr == PREV_HDR (NEXT_HDR (pHdr))) /* matches next block */
  640.     && (pHdr == NEXT_HDR (PREV_HDR (pHdr))); /* matches prev block */
  641.     semTake (&partId->sem, WAIT_FOREVER); /* reacquire mutex */
  642.     TASK_UNLOCK (); /* UNLOCK PREEMPTION */
  643.     return (valid);
  644.     }
  645. /*****************************************************************************
  646. *
  647. * memAlignedBlockSplit - split a block on the free list into two blocks
  648. *
  649. * This routine is like memBlockSplit, but also aligns the data block to the
  650. * given alignment.  The block looks like this after it is split:
  651. *
  652. *        |----------------------------------------------------------------|
  653. *        ^                      ^                       ^                 ^
  654. *        |                      |                       | space left over |
  655. *        |                      |<------- nWords ------>| after alignment |
  656. *        |                      |                       |                 |
  657. *   block begin       new aligned buffer begin         end           block end
  658. *
  659. *
  660. * After the split, if the first block has less than minWords in it, the
  661. * block is rejected, and null is returned, since we can't place this first
  662. * block on the free list.
  663. * If the space succeeding the newly allocated aligned buffer is less than the
  664. * minimum block size, then the bytes are added to the newly allocated buffer.
  665. * If the space is greater than the minimum block size,  then a new memory
  666. * fragment is created and added to the free list.
  667. * Care must be taken to insure that the orignal block passed in
  668. * to be split has at least (nWords + alignment/2) words in it.  
  669. * If the block has exactly nWords and is already aligned to the given alignment,
  670. * it will be deleted from the free list and returned unsplit.
  671. * Otherwise, the second block will be returned.
  672. *
  673. * RETURNS: A pointer to a BLOCK_HDR 
  674. */
  675. LOCAL BLOCK_HDR *memAlignedBlockSplit 
  676.     (
  677.     PART_ID partId,
  678.     FAST BLOCK_HDR *pHdr,
  679.     FAST unsigned nWords,            /* number of words in second block */
  680.     unsigned minWords,               /* min num of words allowed in a block */
  681.     unsigned alignment      /* boundary to align to */
  682.     )
  683.     {
  684.     FAST BLOCK_HDR *pNewHdr;
  685.     FAST BLOCK_HDR *pNextHdr;
  686.     FAST char *endOfBlock;
  687.     FAST char *pNewBlock;
  688.     int blockSize;
  689.     /* calculate end of pHdr block */
  690.     endOfBlock = (char *) pHdr + (pHdr->nWords * 2); 
  691.     /* caluclate unaligned beginning of new block */ 
  692.     pNewBlock = (char *) ((unsigned) endOfBlock - 
  693. ((nWords - sizeof (BLOCK_HDR) / 2) * 2));
  694.     /* align the beginning of the block */
  695.     pNewBlock = (char *)((unsigned) pNewBlock & ~(alignment - 1));
  696.     pNewHdr = BLOCK_TO_HDR (pNewBlock);
  697.     /* adjust original block's word count */
  698.     blockSize = ((char *) pNewHdr - (char *) pHdr) / 2;
  699.     if (blockSize < minWords)
  700. {
  701. /* check to see if the new block is the same as the original block -
  702.  * if so, delete if from the free list.  If not, reject the newly
  703.  * split block because it's too small to hang on the free list.
  704.  */
  705. if (pNewHdr == pHdr)
  706.     dllRemove (&partId->freeList, HDR_TO_NODE (pHdr));
  707. else
  708.     return (NULL);
  709. }
  710.     else
  711. {
  712. pNewHdr->pPrevHdr = pHdr;
  713. pHdr->nWords = blockSize;
  714. }
  715.     /* check to see if space left over after we aligned the new buffer
  716.      * is big enough to be a fragment on the free list.
  717.      */
  718.     if (((UINT) endOfBlock - (UINT) pNewHdr - (nWords * 2)) < (minWords * 2))
  719. {
  720. /* nope - give all the memory to the newly allocated block */
  721. pNewHdr->nWords = (endOfBlock - pNewBlock + sizeof (BLOCK_HDR)) / 2;
  722. pNewHdr->free     = TRUE; 
  723. /* fix next block to point to newly allocated block */
  724. NEXT_HDR (pNewHdr)->pPrevHdr = pNewHdr;
  725. }
  726.     else
  727. {
  728. /* the extra bytes are big enough to be a fragment on the free list -
  729.  * first, fix up the newly allocated block.
  730.  */
  731. pNewHdr->nWords = nWords;
  732. pNewHdr->free     = TRUE; 
  733. /* split off the memory after pNewHdr and add it to the free list */
  734. pNextHdr = NEXT_HDR (pNewHdr);
  735. pNextHdr->nWords = ((UINT) endOfBlock - (UINT) pNextHdr) / 2;
  736. pNextHdr->pPrevHdr = pNewHdr;
  737. pNextHdr->free = TRUE;
  738. dllAdd (&partId->freeList, HDR_TO_NODE (pNextHdr));
  739. /* fix next block to point to the new fragment on the free list */
  740. NEXT_HDR (pNextHdr)->pPrevHdr = pNextHdr;
  741. }
  742.     return (pNewHdr);
  743.     }
  744. /******************************************************************************
  745. *
  746. * memAddToPool - add memory to the system memory partition
  747. *
  748. * This routine adds memory to the system memory partition, after the initial
  749. * allocation of memory to the system memory partition.
  750. *
  751. * RETURNS: N/A
  752. *
  753. * SEE ALSO: memPartAddToPool()
  754. */
  755. void memAddToPool 
  756.     (
  757.     FAST char *pPool,           /* pointer to memory block */
  758.     FAST unsigned poolSize      /* block size in bytes */
  759.     )
  760.     {
  761.     (void) memPartAddToPool (&memSysPartition, pPool, poolSize);
  762.     }
  763. /*******************************************************************************
  764. *
  765. * malloc - allocate a block of memory from the system memory partition (ANSI)
  766. *
  767. * This routine allocates a block of memory from the free list.  The size of
  768. * the block will be equal to or greater than <nBytes>.
  769. *
  770. * RETURNS: A pointer to the allocated block of memory, or a null pointer if
  771. * there is an error.
  772. *
  773. * SEE ALSO: 
  774. * .I "American National Standard for Information Systems -"
  775. * .I "Programming Language - C, ANSI X3.159-1989: General Utilities (stdlib.h)"
  776. */
  777. void *malloc 
  778.     (
  779.     size_t nBytes             /* number of bytes to allocate */
  780.     )
  781.     {
  782.     return (memPartAlloc (&memSysPartition, (unsigned) nBytes));
  783.     }
  784. /*******************************************************************************
  785. *
  786. * free - free a block of memory (ANSI)
  787. *
  788. * This routine returns to the free memory pool a block of memory previously
  789. * allocated with malloc() or calloc().
  790. *
  791. * RETURNS: N/A
  792. *
  793. * SEE ALSO: 
  794. * malloc(), calloc(),
  795. * .I "American National Standard for Information Systems -"
  796. * .I "Programming Language - C, ANSI X3.159-1989: General Utilities (stdlib.h)"
  797. */
  798. void free 
  799.     (
  800.     void *ptr       /* pointer to block of memory to free */
  801.     )
  802.     {
  803.     (void) memPartFree (&memSysPartition, (char *) ptr);
  804.     }
  805. /*******************************************************************************
  806. *
  807. * memPartSemInit - initialize the partition semaphore as type binary
  808. *
  809. * This routine initializes the partition semaphore as a binary semaphore.
  810. * This function is called indirectly from memPartInit().  This coupling
  811. * allows alternative semaphore types to serve as the basis for memory
  812. * partition interlocking.
  813. */
  814. LOCAL void memPartSemInit
  815.     (
  816.     PART_ID partId /* partition to initialize semaphore for */
  817.     )
  818.     {
  819.     semBInit (&partId->sem, SEM_Q_PRIORITY, SEM_FULL);
  820.     }