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

VxWorks

开发平台:

C/C++

  1. /* smMemLib.c - shared memory management library (VxMP Option) */
  2. /* Copyright 1995-2002 Wind River Systems, Inc. */
  3. /*
  4. modification history
  5. --------------------
  6. 01p,03may02,mas  default now is always MEM_BLOCK_CHECK (SPR 3756); cache flush
  7.  and volatile fix (SPR 68334); bridge flush fix (SPR 68844)
  8. 01o,24oct01,mas  doc update (SPR 71149)
  9. 01n,09oct01,mas  smMemPartFindMax() can now return zero; code cleanup(SPR70280)
  10. 01m,14mar99,dat  SPR 20308, fixed smMemBlockSplit.
  11. 01l,14mar99,jdi  doc: removed refs to config.h and/or configAll.h (SPR 25663).
  12. 01k,21jun96,dbt  Update copyright.
  13.  Removed warning concerning SM_ALIGN_BOUNDARY (SPR #4903).
  14. 01j,08feb93,jdi  documentation cleanup.
  15.             pme  removed BLOCK_CHECK default option.
  16. 01i,29jan93,pme  added little endian support.
  17.  added partOptions where needed to get rid of i960 cc warnings.
  18.  made smMemAddToPool() return STATUS. Made smMemFindMax() 
  19.  return ERROR if access to the partition fails.
  20.  documentation.
  21. 01h,21nov92,jdi  documentation cleanup.
  22. 01g,02oct92,pme  added SPARC support. documentation cleanup.
  23. 01f,29sep92,pme  changed user callable routine names for coherency
  24.                  added ERRNO section in comments. 
  25.  rounded down poolSize in smMemPartAddToPool
  26.  changed smMemPartFree() to mark coalesced blocks as not free
  27. 01e,29jul92,pme  removed partition access release from smMemPartBlockIsValid.
  28. 01d,28jul92,pme  made smMemPartCreate return PART_ID instead of SM_PART_ID.
  29. 01c,28jul92,pme  changed SM_OBJ_ALIGN_BOUNDARY to SM_ALIGN_BOUNDARY.
  30. 01b,28jul92,pme  changed memory alignement to SM_OBJ_ALIGN_BOUNDARY bytes.
  31.  replaced MEM_ROUND_UP by SM_MEM_ROUND_UP and
  32.  MEM_IS_ROUND by SM_MEM_IS_ROUND.
  33.  added smMemPartAlignedAlloc() and smMemAlignedBlockSplit().
  34. 01a,19jul92,pme  simplified smMemPartBlockError and smMemPartAllocError.
  35.                  moved smMemShow() and smMemPartShow() to smMemShow.c
  36.                  written from 04l memLib.c
  37. */
  38. /*
  39. DESCRIPTION
  40. This library provides facilities for managing the allocation of blocks of
  41. shared memory from ranges of memory called shared memory partitions.  The
  42. routine memPartSmCreate() is used to create shared memory partitions in
  43. the shared memory pool.  The created partition can be manipulated using
  44. the generic memory partition calls, memPartAlloc(), memPartFree(), etc.
  45. (for a complete list of these routines, see the manual entry for
  46. memPartLib).  The maximum number of partitions that can be created is
  47. determined by the configuration parameter SM_OBJ_MAX_MEM_PART .
  48. The smMem...() routines provide an easy-to-use interface to the shared
  49. memory system partition.  The shared memory system partition is created 
  50. when the shared memory object facility is initialized.
  51. Shared memory management information and statistics display routines are
  52. provided by smMemShow.
  53. The allocation of memory, using memPartAlloc() in the general case and 
  54. smMemMalloc() for the shared memory system partition, is done with a 
  55. first-fit algorithm.  Adjacent blocks of memory are coalesced when freed
  56. using memPartFree() and smMemFree().
  57. There is a 28-byte overhead per allocated block (architecture dependent),
  58. and allocated blocks are aligned on a 16-byte boundary.
  59. All memory used by the shared memory facility must be in the same 
  60. address space, that is, it must be reachable from all the CPUs with the 
  61. same offset as the one used for the shared memory anchor.
  62. CONFIGURATION
  63. Before routines in this library can be called, the shared memory objects
  64. facility must be initialized by a call to usrSmObjInit(), which is 
  65. found in f3target/config/comps/src/usrSmObj.cf1.  This is done automatically
  66. by VxWorks when the INCLUDE_SM_OBJ component is included.
  67. ERROR OPTIONS
  68. Various debug options can be selected for each partition using
  69. memPartOptionsSet() and smMemOptionsSet().  Two kinds of errors are
  70. detected:  attempts to allocate more memory than is available, and bad
  71. blocks found when memory is freed.  In both cases, options can be selected
  72. for system actions to take place when the error is detected: (1) return
  73. the error status, (2) log an error message and return the error status, or
  74. (3) log an error message and suspend the calling task.
  75. One of the following options can be specified to determine
  76. the action to be taken when there is an attempt to allocate more
  77. memory than is available in the partition:
  78. is
  79. i `MEM_ALLOC_ERROR_RETURN'
  80. just return the error status to the calling task.
  81. i `MEM_ALLOC_ERROR_LOG_MSG'
  82. log an error message and return the status to the calling task.
  83. i `MEM_ALLOC_ERROR_LOG_AND_SUSPEND'
  84. log an error message and suspend the calling task.
  85. ie
  86. The following option is specified by default to check every
  87. block freed to the partition.  If this option is specified, memPartFree()
  88. and smMemFree() will make a consistency check of various pointers and values
  89. in the header of the block being freed.
  90. is
  91. i `MEM_BLOCK_CHECK'
  92. check each block freed.
  93. ie
  94. One of the following options can be specified to determine the action to
  95. be taken when a bad block is detected when freed.  These options apply
  96. only if the MEM_BLOCK_CHECK option is selected.
  97. is
  98. i `MEM_BLOCK_ERROR_RETURN'
  99. just return the status to the calling task.
  100. i `MEM_BLOCK_ERROR_LOG_MSG'
  101. log an error message and return the status to the calling task.
  102. i `MEM_BLOCK_ERROR_LOG_AND_SUSPEND'
  103. log an error message and suspend the calling task.
  104. ie
  105. The default options when a shared partition is created are
  106. MEM_ALLOC_ERROR_LOG_MSG, MEM_BLOCK_CHECK, MEM_BLOCK_ERROR_RETURN.
  107. When setting options for a partition with memPartOptionsSet() or
  108. smMemOptionsSet(), use the logical OR operator between each specified
  109. option to construct the <options> parameter.  For example:
  110. cs
  111.     memPartOptionsSet (myPartId, MEM_ALLOC_ERROR_LOG_MSG |
  112.                                  MEM_BLOCK_CHECK | 
  113.  MEM_BLOCK_ERROR_LOG_MSG);
  114. ce
  115. AVAILABILITY
  116. This module is distributed as a component of the unbundled shared memory
  117. objects support option, VxMP.
  118. INCLUDE FILES: smMemLib.h
  119. SEE ALSO: smMemShow, memLib, memPartLib, smObjLib, usrSmObjInit(),
  120. tb VxWorks Programmer's Guide: Shared Memory Objects
  121. INTERNAL
  122. Blocks allocated by smMemMalloc() are actually larger than the size
  123. requested by the user.  Each block is prefaced by a header which contains
  124. the size and status of that block and a pointer to the previous block.
  125. The pointer returned to the user points just past this header.  Likewise
  126. when a block is freed, the header is found just in front of the block
  127. pointer passed by the user.
  128. The header data is arranged so that the pointer to the previous block
  129. comes first and is therefore adjacent to that previous block.  Thus each
  130. block has 4 bytes of redundant information on either side of it (the 4
  131. bytes of size and status before it in its own header, and the 4-byte
  132. pointer after it in the next header).  This redundant information is
  133. optionally used in smMemFree() and smMemRealloc() to make a consistency
  134. check on blocks specified by the user.  This mechanism helps to detect two
  135. common errors: (1) bad block pointers passed to smMemFree() or
  136. smMemRealloc() are usually detected, and (2) trashing up to 4 bytes on
  137. either side of the block will only affect that block and will also be
  138. detected by smMemFree() or smMemRealloc().
  139. There is a minimum block size which malloc() allocates; this is to insure
  140. that there will be enough room for the free list links that must be used
  141. when the block is freed if it cannot be coalesced with an adjacent block.
  142. The malloc() and realloc() routines always force the requested block size to
  143. be multiple of SM_ALIGN_BOUNDARY; since smMemPartInit() forces the 
  144. initial pool to be on a SM_ALIGN_BOUNDARY-byte boundary, this causes 
  145. all blocks to lie on a SM_ALIGN_BOUNDARY-byte boundaries, 
  146. thus insuring that the block passed back to the user will always 
  147. lie on a SM_ALIGN_BOUNDARY byte boundary.
  148. The memory partition shared semaphore is a structure in the partition
  149. descriptor rather than a pointer to a dynamically created shared semaphore
  150. structure.  This is because of the chicken-and-the-egg problem of smMemLib
  151. using semaphores and semBSmCreate calling smMemPartAlloc.  Instead the
  152. structure is simply declared directly in the partition structure and we call
  153. semSmBInit() instead of semBSmCreate().
  154. All blocks allocated from a shared memory partition are aligned on
  155. SM_ALIGN_BOUNDARY which defines the minimum common alignement value
  156. needed by all the supported architecture. 
  157. */
  158. /* includes */
  159. #include "vxWorks.h"
  160. #include "memLib.h"
  161. #include "semLib.h"
  162. #include "logLib.h"
  163. #include "intLib.h"
  164. #include "taskLib.h"
  165. #include "cacheLib.h"
  166. #include "string.h"
  167. #include "errnoLib.h"
  168. #include "netinet/in.h"
  169. #include "smLib.h"
  170. #include "smMemLib.h"
  171. #include "private/smObjLibP.h"
  172. #include "private/memPartLibP.h"
  173. /* defines */
  174. /* 
  175.  * Macros for rounding: all allocated blocks are aligned 
  176.  * on the maximum required alignement value across all available 
  177.  * architectures.  This value named SM_ALIGN_BOUNDARY 
  178.  * is set to 16 bytes since i960 version is available.
  179.  */
  180. #define SM_MEM_ROUND_UP(x) (ROUND_UP(x, SM_ALIGN_BOUNDARY))
  181. #define SM_MEM_ROUND_DOWN(x)    (ROUND_DOWN(x, SM_ALIGN_BOUNDARY))
  182. #define SM_MEM_IS_ROUND(x) (ALIGNED(x, SM_ALIGN_BOUNDARY))
  183. /* locals */
  184. LOCAL char * smMemMsgBlockTooBig =
  185.       "smMemPartAlloc: block too big - %d in shared partition %#x.n";
  186. LOCAL char * smMemMsgBlockError =
  187.       "%s: invalid block %#x in shared partition %#x.n";
  188. /* forward declarations */
  189. LOCAL void smMemPartAllocError (SM_PART_ID volatile pPart, unsigned nBytes);
  190. LOCAL void smMemPartBlockError (SM_PART_ID volatile pPart, char * pBlock,
  191.  char * label);
  192. LOCAL SM_BLOCK_HDR volatile * smMemBlockSplit (SM_BLOCK_HDR volatile * pHdr,
  193.                                                unsigned nWords,
  194.                                                unsigned minWords);
  195. LOCAL SM_BLOCK_HDR volatile * smMemAlignedBlockSplit (
  196.                                         SM_PART_ID volatile partId,
  197. SM_BLOCK_HDR volatile * pHdr,
  198.         unsigned nWords, unsigned minWords,
  199.        unsigned alignment);
  200. /******************************************************************************
  201. *
  202. * smMemPartLibInit - initialize the shared memory manager facility
  203. *
  204. * This routine initializes the shared memory manager function pointers to
  205. * allow generic memory management calls to manipulate shared memory
  206. * partitions.  It is called by smObjInit().
  207. *
  208. * RETURNS: N/A.
  209. *
  210. * NOMANUAL
  211. */
  212. void smMemPartLibInit (void)
  213.     {
  214.     /* Initialize shared memory manager function pointers */
  215.     smMemPartAddToPoolRtn  = (FUNCPTR) smMemPartAddToPool;
  216.     smMemPartFreeRtn       = (FUNCPTR) smMemPartFree;
  217.     smMemPartAllocRtn      = (FUNCPTR) smMemPartAlloc;
  218.     smMemPartOptionsSetRtn = (FUNCPTR) smMemPartOptionsSet;
  219.     smMemPartFindMaxRtn    = (FUNCPTR) smMemPartFindMax;
  220.     smMemPartReallocRtn    = (FUNCPTR) smMemPartRealloc;
  221.     }
  222. /******************************************************************************
  223. *
  224. * memPartSmCreate - create a shared memory partition (VxMP Option)
  225. *
  226. * This routine creates a shared memory partition that can be used by tasks
  227. * on all CPUs in the system.  It returns a partition ID which can then be
  228. * passed to generic memPartLib routines to manage the partition (i.e., to
  229. * allocate and free memory blocks in the partition).
  230. *
  231. * <pPool> is the global address of shared memory dedicated to the
  232. * partition.  The memory area pointed to by <pPool> must be in the same
  233. * address space as the shared memory anchor and shared memory pool.
  234. *
  235. * <poolSize> is the size in bytes of shared memory dedicated to the partition.
  236. *
  237. * Before this routine can be called, the shared memory objects facility must
  238. * be initialized (see smMemLib).
  239. *
  240. * NOTE
  241. * The descriptor for the new partition is allocated out of an internal
  242. * dedicated shared memory partition.  The maximum number of partitions that can
  243. * be created is SM_OBJ_MAX_MEM_PART .
  244. *
  245. * Memory pool size is rounded down to a 16-byte boundary.
  246. *
  247. * AVAILABILITY
  248. * This routine is distributed as a component of the unbundled shared memory
  249. * objects support option, VxMP.
  250. * RETURNS:
  251. * The partition ID, or NULL if there is insufficient memory in the dedicated
  252. * partition for a new partition descriptor.
  253. *
  254. * ERRNO:
  255. *  S_memLib_NOT_ENOUGH_MEMORY
  256. *  S_smObjLib_LOCK_TIMEOUT 
  257. *
  258. * SEE ALSO: memLib
  259. */
  260. PART_ID memPartSmCreate
  261.     (
  262.     char * pPool, /* global address of shared memory area */
  263.     unsigned poolSize /* size in bytes */
  264.     )
  265.     {
  266.     SM_PART_ID pPart;           /* created partition ID */
  267.     int        tmp;             /* temp storage */
  268.     /* 
  269.      * Allocate a shared partition structure from the internal 
  270.      * shared partition memory pool.
  271.      */
  272.     pPart = (SM_PART_ID) smMemPartAlloc ((SM_PART_ID) smPartPartId,
  273.                                          sizeof (SM_PARTITION));
  274.     if (pPart != LOC_NULL)
  275. {
  276.         smMemPartInit ((SM_PART_ID) pPart, pPool, poolSize);
  277.         /* update smObj statistics */
  278.         CACHE_PIPE_FLUSH ();            /* CACHE FLUSH   [SPR 68334] */
  279.         tmp = pSmObjHdr->curNumPart;    /* PCI bridge bug [SPR 68844] */
  280.      pSmObjHdr->curNumPart = htonl (ntohl (pSmObjHdr->curNumPart) + 1);
  281.         CACHE_PIPE_FLUSH ();            /* CACHE FLUSH   [SPR 68334] */
  282.         tmp = pSmObjHdr->curNumPart;    /* BRIDGE FLUSH  [SPR 68334] */
  283. }
  284.     /* now return the global address of the partition */
  285.     return ((PART_ID) SM_OBJ_ADRS_TO_ID (pPart));
  286.     }
  287. /******************************************************************************
  288. *
  289. * smMemPartInit - initialize a shared memory partition
  290. *
  291. * This routine initializes a shared partition free list, seeding it with the
  292. * memory block passed as an argument.  It must be called exactly once
  293. * for each memory partition created. 
  294. * <partId> is the local address of the partition structure 
  295. * previously allocated from the shared partitions structures partition 
  296. * (smPartPartId).  
  297. *
  298. * <pPool> is the global address of shared memory dedicated to the partition.
  299. *
  300. * <poolSize> is the size in bytes of shared memory dedicated to the partition.
  301. *
  302. * SEE ALSO: memPartSmCreate()
  303. *
  304. * NOMANUAL
  305. */
  306. void smMemPartInit 
  307.     (
  308.     SM_PART_ID volatile partId,      /* partition to initialize */
  309.     char *              pPool,       /* pointer to memory pool */
  310.     unsigned            poolSize     /* pool size in bytes */
  311.     )
  312.     {
  313.     int                 tmp;         /* temp storage */
  314.     /* initialize partition descriptor */
  315.     bzero ((char *) partId, sizeof (*partId));
  316.     partId->options = htonl (MEM_ALLOC_ERROR_LOG_FLAG | MEM_BLOCK_CHECK |
  317.                              MEM_BLOCK_ERROR_RETURN);
  318.     partId->minBlockWords = htonl (sizeof (SM_FREE_BLOCK) >> 1);
  319.     CACHE_PIPE_FLUSH ();            /* CACHE FLUSH   [SPR 68334] */
  320.     tmp = partId->options;          /* BRIDGE FLUSH  [SPR 68334] */
  321.     /* initialize partition semaphore and free list and add memory to pool */
  322.     semSmBInit (&partId->sem,  SEM_Q_FIFO, SEM_FULL);
  323.     smDllInit (&partId->freeList);
  324.     partId->objType = htonl (MEM_PART_TYPE_SM_STD);
  325.     /* verify field must contain partition header global address */
  326.     partId->verify = (UINT32) htonl (LOC_TO_GLOB_ADRS (partId));
  327.     CACHE_PIPE_FLUSH ();            /* CACHE FLUSH   [SPR 68334] */
  328.     tmp = partId->options;          /* BRIDGE FLUSH  [SPR 68334] */
  329.     (void) smMemPartAddToPool (partId, pPool, poolSize);
  330.     }
  331. /******************************************************************************
  332. *
  333. * smMemPartAddToPool - add memory to a shared memory partition
  334. *
  335. * This routine adds memory to a shared memory partition after the initial 
  336. * call to memPartSmCreate().  The memory added need not be contiguous with 
  337. * memory previously assigned to the partition but it must be in the same
  338. * address space.
  339. *
  340. * This routine is not user callable, it is called by the generic memory
  341. * partition routine memPartAddToPool().
  342. *
  343. * <partId> is the shared partition header local address of partition to use.
  344. *
  345. * <pPool> is the global address of shared memory dedicated to the partition.
  346. * The memory area pointed to by <pPool> must be in the same address space
  347. * than the shared memory anchor and shared memory pool since shared
  348. * memory cannot be referenced using different offsets.
  349. *
  350. * <poolSize> is the size in bytes of shared memory added to the partition.
  351. * NOTE: Internally memory pool size is rounded down to a 16-byte boundary.
  352. *
  353. * RETURNS: OK or ERROR.
  354. *
  355. * ERRNO:
  356. *  S_objLib_OBJ_ID_ERROR
  357. *  S_smObjLib_LOCK_TIMEOUT 
  358. *
  359. * SEE ALSO: memPartSmCreate()
  360. *
  361. * NOMANUAL
  362. */
  363. STATUS smMemPartAddToPool 
  364.     (
  365.     SM_PART_ID volatile partId,     /* partition to modify */
  366.     char *              pPool,      /* pointer to memory pool */
  367.     unsigned            poolSize    /* pool size in bytes */
  368.     )
  369.     {
  370.     SM_BLOCK_HDR volatile * pHdrStart;
  371.     SM_BLOCK_HDR volatile * pHdrMid;
  372.     SM_BLOCK_HDR volatile * pHdrEnd;
  373.     char *                  pTmp;
  374.     int                     tmp;         /* temp storage */
  375.     CACHE_PIPE_FLUSH ();            /* CACHE FLUSH   [SPR 68334] */
  376.     tmp = partId->verify;           /* PCI bridge bug [SPR 68844] */
  377.     if (SM_OBJ_VERIFY (partId) != OK)
  378.         {
  379. return (ERROR);
  380.         }
  381.  
  382.     /* insure that the pool starts on an even byte boundry */
  383.     pTmp      = (char *) SM_MEM_ROUND_UP (pPool);  /* get actual start */
  384.     poolSize  = SM_MEM_ROUND_DOWN (poolSize - (pTmp - pPool)); /* adj length */
  385.     pPool     = (char *) GLOB_TO_LOC_ADRS (pTmp);        /* get local adrs */
  386.     /* 
  387.      * initialize three blocks one at each end of the pool 
  388.      * for end cases and real initial free block 
  389.      */
  390.     pHdrStart = (SM_BLOCK_HDR volatile *) pPool;
  391.     pHdrStart->pPrevHdr = NULL;
  392.     pHdrStart->free     = htonl (FALSE);
  393.     pHdrStart->nWords   = htonl (sizeof (SM_BLOCK_HDR) >> 1);
  394.     pHdrMid = (SM_BLOCK_HDR volatile *) SM_NEXT_HDR (pHdrStart);
  395.     pHdrMid->pPrevHdr   = (SM_BLOCK_HDR *)htonl (LOC_TO_GLOB_ADRS (pHdrStart));
  396.     pHdrMid->free       = htonl (TRUE);
  397.     pHdrMid->nWords     = htonl ((poolSize - 2 * sizeof (SM_BLOCK_HDR)) >> 1);
  398.     pHdrEnd = (SM_BLOCK_HDR volatile *) SM_NEXT_HDR (pHdrMid);
  399.     pHdrEnd->pPrevHdr   = (SM_BLOCK_HDR *) htonl (LOC_TO_GLOB_ADRS (pHdrMid));
  400.     pHdrEnd->free       = htonl (FALSE);
  401.     pHdrEnd->nWords     = htonl (sizeof (SM_BLOCK_HDR) >> 1);
  402.     CACHE_PIPE_FLUSH ();            /* CACHE FLUSH   [SPR 68334] */
  403.     tmp = partId->options;          /* BRIDGE FLUSH  [SPR 68334] */
  404.     if (smMemPartAccessGet (partId) != OK)
  405.         {
  406.         return (ERROR);
  407.         }
  408.     smDllInsert(&partId->freeList, (SM_DL_NODE *)NULL, SM_HDR_TO_NODE(pHdrMid));
  409.     CACHE_PIPE_FLUSH ();            /* CACHE FLUSH   [SPR 68334] */
  410.     tmp = partId->totalWords;       /* PCI bug       [SPR 68844] */
  411.     partId->totalWords = htonl (ntohl (partId->totalWords) + (poolSize >> 1));
  412.     CACHE_PIPE_FLUSH ();            /* CACHE FLUSH   [SPR 68334] */
  413.     tmp = partId->options;          /* BRIDGE FLUSH  [SPR 68334] */
  414.     if (smMemPartAccessRelease (partId) != OK)
  415.         {
  416.         return (ERROR);
  417.         }
  418.     return (OK);
  419.     }
  420. /******************************************************************************
  421. *
  422. * smMemPartOptionsSet - set the debug options for a shared memory partition
  423. *
  424. * This routine sets the debug options for a specified shared memory partition.
  425. * Two kinds of errors are detected:  attempts to allocate more memory than
  426. * is available, and bad blocks found when memory is freed.  In both cases,
  427. * the following options can be selected for actions to be taken when the error
  428. * is detected:  (1) return the error status, (2) log an error message and
  429. * return the error status, or (3) log an error message and suspend the
  430. * calling task.  These options are discussed in detail in the library manual
  431. * entry for smMemLib.
  432. *
  433. * This routine is not user callable, it is called by the generic memory
  434. * partition routine memPartOptionsSet().
  435. *
  436. * RETURNS: OK or ERROR.
  437. *
  438. * ERRNO:
  439. *  S_objLib_OBJ_ID_ERROR
  440. *  S_smObjLib_LOCK_TIMEOUT
  441. *
  442. * NOMANUAL
  443. */
  444. STATUS smMemPartOptionsSet
  445.     (
  446.     SM_PART_ID volatile partId,    /* partition for which to set option */
  447.     unsigned            options    /* memory management options */
  448.     )
  449.     {
  450.     int                 tmp;       /* temp storage */
  451.     CACHE_PIPE_FLUSH ();            /* CACHE FLUSH   [SPR 68334] */
  452.     tmp = partId->verify;           /* PCI bridge bug [SPR 68844] */
  453.     if (SM_OBJ_VERIFY (partId) != OK)
  454.         {
  455.         return (ERROR);
  456.         }
  457.     if (smMemPartAccessGet(partId) != OK)
  458.         {
  459.         return (ERROR);
  460.         }
  461.     partId->options = htonl (options);
  462.     CACHE_PIPE_FLUSH ();            /* CACHE FLUSH   [SPR 68334] */
  463.     tmp = partId->options;          /* BRIDGE FLUSH  [SPR 68334] */
  464.     if (smMemPartAccessRelease (partId) != OK)
  465.         {
  466.         return (ERROR);
  467.         }
  468.     return (OK);
  469.     }
  470. /******************************************************************************
  471. *
  472. * smMemPartAlignedAlloc - allocate aligned memory from a partition
  473. *
  474. * This routine allocates a buffer of size nBytes from the given 
  475. * shared partition.  Additionally, it will insure the allocated buffer 
  476. * begins on a memory address that is evenly divisable by the given 
  477. * alignment parameter.  The alignment parameter must be a power of 2.
  478. *
  479. * RETURNS:
  480. * A pointer to the newly allocated block, or NULL if the buffer could not be
  481. * allocated.
  482. *
  483. * NOMANUAL
  484. */
  485. void * smMemPartAlignedAlloc 
  486.     (
  487.     SM_PART_ID volatile partId, /* memory partition to allocate from */
  488.     unsigned nBytes, /* number of bytes to allocate */
  489.     unsigned alignment /* boundry to align to */
  490.     )
  491.     {
  492.     unsigned nWords;
  493.     unsigned nWordsExtra;
  494.     SM_DL_NODE volatile * pNode;
  495.     SM_BLOCK_HDR volatile * pHdr;
  496.     SM_BLOCK_HDR volatile * pNewHdr;
  497.     SM_BLOCK_HDR  origpHdr;
  498.     unsigned                    tmp;       /* temp storage */
  499.     CACHE_PIPE_FLUSH ();            /* CACHE FLUSH   [SPR 68334] */
  500.     tmp = partId->verify;           /* PCI bridge bug [SPR 68844] */
  501.     if (SM_OBJ_VERIFY (partId) != OK)
  502.         {
  503. return (NULL);
  504.         }
  505.     /* get actual size to allocate; add overhead, check for minimum */
  506.     nWords = (SM_MEM_ROUND_UP (nBytes) + sizeof (SM_BLOCK_HDR)) >> 1;
  507.     tmp = partId->minBlockWords;    /* PCI bug       [SPR 68844] */
  508.     if (nWords < ntohl (partId->minBlockWords))
  509.         {
  510. nWords = ntohl (partId->minBlockWords);
  511.         }
  512.     /* get exclusive access to the partition */
  513.     if (smMemPartAccessGet (partId) != OK)
  514.         {
  515.         return (NULL);
  516.         }
  517.     /* first fit */
  518.     pNode = (SM_DL_NODE volatile *) SM_DL_FIRST (&partId->freeList);
  519.     /*
  520.      * We need a free block with extra room to do the alignment.  
  521.      * Worst case we'll need alignment extra bytes.
  522.      */
  523.     nWordsExtra = nWords + alignment / 2;
  524.     FOREVER
  525. {
  526. while (pNode != LOC_NULL)
  527.     {
  528.     /*
  529.      * fits if:
  530.      * - blocksize > requested size + extra room for alignment or,
  531.      * - block is already aligned and exactly the right size
  532.      */
  533.     if ((ntohl (SM_NODE_TO_HDR (pNode)->nWords) > nWordsExtra) ||
  534. ((((UINT) SM_HDR_TO_BLOCK (SM_NODE_TO_HDR (pNode)) % alignment)
  535.   == 0) &&
  536.  (ntohl (SM_NODE_TO_HDR (pNode)->nWords) == nWords)))
  537.                 {
  538. break;
  539.                 }
  540.     pNode = (SM_DL_NODE volatile *) SM_DL_NEXT (pNode);
  541.     }
  542. if (pNode == LOC_NULL)
  543.     {
  544.          if (smMemPartAccessRelease (partId) != OK)
  545.              {
  546.              return (NULL);
  547.              }
  548.     smMemPartAllocError (partId, nBytes);
  549.     return (NULL);
  550.     }
  551. pHdr = (SM_BLOCK_HDR volatile *) SM_NODE_TO_HDR (pNode);
  552. origpHdr = *pHdr;
  553. /* 
  554.  * Now we split off from this block, the amount required by the user;
  555.  * note that the piece we are giving the user is at the end of the
  556.  * block so that the remaining piece is still the piece that is
  557.  * linked in the free list;  if smMemAlignedBlockSplit returned NULL,
  558.  * it couldn't split the block because the split would leave the
  559.  * first block too small to be hung on the free list, so we continue
  560.  * trying blocks.
  561.  */
  562. pNewHdr = smMemAlignedBlockSplit (partId, pHdr, nWords,
  563.                                           ntohl (partId->minBlockWords),
  564.                                           alignment);
  565. if (pNewHdr != NULL)
  566.     {
  567.     pHdr = pNewHdr; /* give split off block */
  568.     break;
  569.     }
  570. pNode = (SM_DL_NODE volatile *) SM_DL_NEXT (pNode);
  571. }
  572.     /* mark the block we're giving as not free  */
  573.     pHdr->free = htonl (FALSE);
  574.     /* update allocation statistics */
  575.     partId->curBlocksAllocated = htonl (ntohl (partId->curBlocksAllocated) +1);
  576.     partId->cumBlocksAllocated = htonl (ntohl (partId->cumBlocksAllocated) +1);
  577.     partId->curWordsAllocated  = htonl (ntohl (partId->curWordsAllocated) + 
  578. ntohl (pHdr->nWords));
  579.     partId->cumWordsAllocated  = htonl (ntohl (partId->cumWordsAllocated) + 
  580. ntohl (pHdr->nWords));
  581.     CACHE_PIPE_FLUSH ();            /* CACHE FLUSH   [SPR 68334] */
  582.     tmp = partId->options;          /* BRIDGE FLUSH  [SPR 68334] */
  583.     if (smMemPartAccessRelease (partId) != OK)
  584.         {
  585.         return (NULL);
  586.         }
  587.     return ((void *) SM_HDR_TO_BLOCK (pHdr));
  588.     }
  589. /******************************************************************************
  590. *
  591. * smMemPartAlloc - allocate a block of memory from a specified shared partition
  592. *
  593. * From a specified shared partition, this routine allocates a block of memory
  594. * whose size is equal to or greater than <nBytes>.  The shared partition 
  595. * must have been previously created with memPartSmCreate().
  596. *
  597. * This routine is not user callable, it is called by the generic memory
  598. * partition routine memPartAlloc.
  599. *
  600. * RETURNS:
  601. * A pointer to a block, or
  602. * NULL if the call fails.
  603. *
  604. * ERRNO:
  605. *  S_objLib_OBJ_ID_ERROR
  606. *  S_memLib_NOT_ENOUGH_MEMORY
  607. *  S_smObjLib_LOCK_TIMEOUT
  608. *
  609. * SEE ALSO: smMemPartInit()
  610. *
  611. * NOMANUAL
  612. */
  613. void * smMemPartAlloc 
  614.     (
  615.     SM_PART_ID partId,     /* partition to allocate from */
  616.     unsigned   nBytes      /* number of bytes to allocate */
  617.     )
  618.     {
  619.     return (smMemPartAlignedAlloc (partId, nBytes, SM_ALIGN_BOUNDARY));
  620.     }
  621. /******************************************************************************
  622. *
  623. * smMemPartRealloc - reallocate a block of memory in specified shared partition
  624. *
  625. * This routine changes the size of a specified block and returns a pointer to
  626. * the new block of memory.  The contents that fit inside the new size (or old
  627. * size if smaller) remain unchanged.
  628. *
  629. * This routine is not user callable, it is called by the generic memory
  630. * partition routine memPartRealloc.
  631. *
  632. * RETURNS:
  633. * A pointer to the new block of memory, or NULL if the call fails.
  634. *
  635. * ERRNO:
  636. *  S_objLib_OBJ_ID_ERROR
  637. *  S_memLib_NOT_ENOUGH_MEMORY
  638. *  S_memLib_BLOCK_ERROR
  639. *  S_smObjLib_LOCK_TIMEOUT
  640. *
  641. * NOMANUAL
  642. */
  643. void * smMemPartRealloc 
  644.     (
  645.     SM_PART_ID volatile partId, /* partition to reallocate from */
  646.     char *              pBlock, /* block to be reallocated */
  647.     unsigned            nBytes /* new block size in bytes */
  648.     )
  649.     {
  650.     SM_BLOCK_HDR volatile * pHdr = SM_BLOCK_TO_HDR (pBlock);
  651.     SM_BLOCK_HDR volatile * pNextHdr;
  652.     unsigned                nWords;
  653.     void *                  pNewBlock;
  654.     int              partOptions; /* partition options */
  655.     unsigned                tmp;                /* temp storage */
  656.     CACHE_PIPE_FLUSH ();            /* CACHE FLUSH   [SPR 68334] */
  657.     tmp = partId->verify;           /* PCI bridge bug [SPR 68844] */
  658.     if (SM_OBJ_VERIFY (partId) != OK)
  659.         {
  660.         return (NULL);
  661.         }
  662.     /* get exclusive access to the partition */
  663.     if (smMemPartAccessGet (partId) != OK)
  664.         {
  665.         return (NULL);
  666.         }
  667.     /* get actual new size; round-up, add overhead, check for minimum */
  668.     nWords = (SM_MEM_ROUND_UP (nBytes) + sizeof (SM_BLOCK_HDR)) >> 1;
  669.     tmp = partId->minBlockWords;    /* PCI bug       [SPR 68844] */
  670.     if (nWords < ntohl (partId->minBlockWords))
  671.         {
  672. nWords = ntohl (partId->minBlockWords);
  673.         }
  674.     /* optional check for validity of block */
  675.     partOptions = ntohl (partId->options);
  676.     if ((partOptions & MEM_BLOCK_CHECK) &&
  677.         !smMemPartBlockIsValid (partId, pHdr, FALSE))
  678.         {
  679.         smMemPartAccessRelease (partId);  /* release access */
  680.         smMemPartBlockError (partId, pBlock, "smMemPartRealloc");
  681.         return (NULL);
  682.         }
  683.     /* test if we are trying to increase size of block */
  684.     tmp = pHdr->nWords;             /* PCI bug       [SPR 68844] */
  685.     if (nWords > ntohl (pHdr->nWords))
  686. {
  687. /*
  688.  * increase size of block -
  689.  * check if next block is free and is big enough to satisfy request
  690.  */
  691. pNextHdr = (SM_BLOCK_HDR volatile *) SM_NEXT_HDR (pHdr);
  692. if (!(ntohl (pNextHdr->free)) || 
  693.     ((ntohl (pHdr->nWords) + ntohl (pNextHdr->nWords)) < nWords))
  694.     {
  695.     /*
  696.      * can't use adjacent free block -
  697.      * allocate an entirely new block and copy data
  698.      */
  699.             if (smMemPartAccessRelease (partId) != OK)
  700.                 {
  701.                 return (NULL);
  702.                 }
  703.     if ((pNewBlock = smMemPartAlloc (partId, nBytes)) == NULL)
  704.         {
  705. return (NULL);
  706.         }
  707.             CACHE_PIPE_FLUSH ();            /* CACHE FLUSH   [SPR 68334] */
  708.             tmp = pHdr->nWords;             /* PCI bug       [SPR 68844] */
  709.     bcopy (pBlock, (char *) pNewBlock,
  710.    (int) (2 * ntohl (pHdr->nWords) - sizeof (SM_BLOCK_HDR)));
  711.             CACHE_PIPE_FLUSH ();            /* CACHE FLUSH   [SPR 68334] */
  712.             tmp = pHdr->nWords;             /* BRIDGE FLUSH  [SPR 68334] */
  713.     (void) smMemPartFree (partId, pBlock);
  714.     return (pNewBlock); /* RETURN, don't fall through */
  715.     }
  716. else
  717.     {
  718.     /* 
  719.      * append next block to this one -
  720.      *  - delete next block from freelist,
  721.      *  - add its size to this block,
  722.      *  - update allocation statistics,
  723.      *  - fix prev info in new "next" block header 
  724.      */
  725.     smDllRemove (&partId->freeList, SM_HDR_TO_NODE (pNextHdr));
  726.             /* fix size */
  727.             CACHE_PIPE_FLUSH ();            /* CACHE FLUSH   [SPR 68334] */
  728.             tmp = pHdr->nWords;             /* PCI bug       [SPR 68844] */
  729.     pHdr->nWords = htonl (ntohl (pHdr->nWords) + 
  730.   ntohl (pNextHdr->nWords));
  731.             /* fix stats */
  732.     partId->curWordsAllocated = htonl (ntohl (partId->curWordsAllocated)
  733.        + ntohl (pNextHdr->nWords));
  734.     partId->cumWordsAllocated = htonl (ntohl (partId->cumWordsAllocated)
  735.        + ntohl (pNextHdr->nWords));
  736. /* fix next */
  737.     SM_NEXT_HDR (pHdr)->pPrevHdr = (SM_BLOCK_HDR *) 
  738.     htonl (LOC_TO_GLOB_ADRS (pHdr));
  739.             CACHE_PIPE_FLUSH ();            /* CACHE FLUSH   [SPR 68334] */
  740.             tmp = pHdr->nWords;             /* BRIDGE FLUSH  [SPR 68334] */
  741.     /* if this combined block is too big, it will get fixed below */
  742.     }
  743. }
  744.     /* 
  745.      * split off any extra and give it back;
  746.      * note that this covers both the case of a realloc for smaller space
  747.      * and the case of a realloc for bigger space that caused a coalesce
  748.      * with the next block that resulted in larger than required block 
  749.      */
  750.     pNextHdr = smMemBlockSplit (pHdr, ntohl (pHdr->nWords) - nWords,
  751.                                 ntohl (partId->minBlockWords));
  752.     if (smMemPartAccessRelease (partId) != OK)
  753.         {
  754.         return (NULL);
  755.         }
  756.     if (pNextHdr != NULL)
  757. {
  758. (void) smMemPartFree (partId, SM_HDR_TO_BLOCK (pNextHdr));
  759.         /* adjust statistics */
  760.         partId->curBlocksAllocated = htonl(ntohl(partId->curBlocksAllocated)+1);
  761.         CACHE_PIPE_FLUSH ();                /* CACHE FLUSH   [SPR 68334] */
  762.         tmp = pHdr->nWords;                 /* BRIDGE FLUSH  [SPR 68334] */
  763. }
  764.     return ((void *) pBlock);
  765.     }
  766. /******************************************************************************
  767. *
  768. * smMemPartFree - free a block of memory in a specified shared partition
  769. *
  770. * This routine takes a block of memory previously allocated with
  771. * smMemPartAlloc() and returns it to the shared partition's free memory list.
  772. *
  773. * This routine is not user callable, it is called by the generic memory
  774. * partition routine memPartFree().
  775. *
  776. * RETURNS: OK or ERROR if there is an invalid block.
  777. *
  778. * ERRNO:
  779. *  S_objLib_OBJ_ID_ERROR
  780. *  S_memLib_BLOCK_ERROR
  781. *  S_smObjLib_LOCK_TIMEOUT:
  782. *
  783. * NOMANUAL
  784. */
  785. STATUS smMemPartFree 
  786.     (
  787.     SM_PART_ID volatile partId, /* partition to use */
  788.     char *              pBlock /* pointer to block of memory to be freed */
  789.     )
  790.     {
  791.     SM_BLOCK_HDR volatile * pHdr;
  792.     SM_BLOCK_HDR volatile * pNextHdr;
  793.     unsigned                nWords;
  794.     int                     partOptions; /* partition options */
  795.     unsigned                tmp;                /* temp storage */
  796.     CACHE_PIPE_FLUSH ();            /* CACHE FLUSH   [SPR 68334] */
  797.     tmp = partId->verify;           /* PCI bridge bug [SPR 68844] */
  798.     if (SM_OBJ_VERIFY (partId) != OK)
  799.         {
  800.         return (ERROR);
  801.         }
  802.     if (pBlock == NULL)
  803.         {
  804. return (OK); /* ANSI C compatibility */
  805.         }
  806.     pHdr   = (SM_BLOCK_HDR volatile *) SM_BLOCK_TO_HDR (pBlock);
  807.     nWords = ntohl (pHdr->nWords);
  808.     /* get exclusive access to the partition */
  809.     if (smMemPartAccessGet (partId) != OK)
  810.         {
  811.         return (ERROR);
  812.         }
  813.     /* optional check for validity of block */
  814.     tmp = partId->options;          /* PCI bug       [SPR 68844] */
  815.     partOptions = ntohl (partId->options);
  816.     if ((partOptions & MEM_BLOCK_CHECK) &&
  817.         !smMemPartBlockIsValid (partId, pHdr, FALSE))
  818.         {
  819.         smMemPartAccessRelease (partId);  /* release access */
  820.         smMemPartBlockError (partId, pBlock, "smMemPartFree");
  821.         return (ERROR);
  822.         }
  823.     /* 
  824.      * Check if we can coalesce with previous block;
  825.      * if so, then we just extend the previous block,
  826.      * otherwise we have to add this as a new free block.
  827.      */
  828.     if (ntohl (SM_PREV_HDR (pHdr)->free))
  829. {
  830. pHdr->free = htonl (FALSE);  /* this isn't a free block */
  831. pHdr = SM_PREV_HDR (pHdr); /* coalesce with prev block */
  832.         CACHE_PIPE_FLUSH ();            /* CACHE FLUSH   [SPR 68334] */
  833.         tmp = pHdr->nWords;             /* PCI bug       [SPR 68844] */
  834. pHdr->nWords = htonl (ntohl (pHdr->nWords) + nWords);
  835. }
  836.     else
  837. {
  838. pHdr->free = htonl (TRUE); /* add new free block */
  839. smDllInsert (&partId->freeList, (SM_DL_NODE *) NULL, 
  840.      SM_HDR_TO_NODE (pHdr));
  841. }
  842.     CACHE_PIPE_FLUSH ();            /* CACHE FLUSH   [SPR 68334] */
  843.     tmp = pHdr->nWords;             /* BRIDGE FLUSH  [SPR 68334] */
  844.     /* 
  845.      * Check if we can coalesce with next block;
  846.      * if so, then we can extend our block delete next block from free list 
  847.      */
  848.     pNextHdr = (SM_BLOCK_HDR volatile *) SM_NEXT_HDR (pHdr);
  849.     if (ntohl (pNextHdr->free))
  850. {
  851.         /* coalesce with next */
  852. pHdr->nWords = htonl (ntohl (pHdr->nWords) + ntohl (pNextHdr->nWords));
  853. smDllRemove (&partId->freeList, SM_HDR_TO_NODE (pNextHdr));
  854. }
  855.     /* fix up prev info of whatever block is now next */
  856.     SM_NEXT_HDR (pHdr)->pPrevHdr = (SM_BLOCK_HDR *) 
  857. htonl (LOC_TO_GLOB_ADRS (pHdr));
  858.     /* adjust allocation stats */
  859.     partId->curBlocksAllocated = htonl (ntohl (partId->curBlocksAllocated) - 1);
  860.     partId->curWordsAllocated  = htonl (ntohl (partId->curWordsAllocated) - 
  861. nWords);
  862.     CACHE_PIPE_FLUSH ();            /* CACHE FLUSH   [SPR 68334] */
  863.     tmp = pHdr->nWords;             /* BRIDGE FLUSH  [SPR 68334] */
  864.     if (smMemPartAccessRelease (partId) != OK)
  865.         {
  866.         return (ERROR);
  867.         }
  868.     return (OK);
  869.     }
  870. /******************************************************************************
  871. *
  872. * smMemPartFindMax - find the size of the largest available free block
  873. *
  874. * This routine searches for the largest block in a shared memory partition free
  875. * list, and returns its size.
  876. *
  877. * This routine is not user callable, it is called by the generic memory
  878. * partition routine memPartFindMax().
  879. *
  880. * RETURNS: The size (in bytes) of the largest available block or ERROR if
  881. * <partId> is not a valid partition or if attempt to get access to the 
  882. * partition fails.
  883. *
  884. * ERRNO:
  885. *  S_objLib_OBJ_ID_ERROR
  886. *  S_smObjLib_LOCK_TIMEOUT
  887. *
  888. * NOMANUAL
  889. */
  890. int smMemPartFindMax 
  891.     (
  892.     SM_PART_ID volatile partId     /* partition to use */
  893.     )
  894.     {
  895.     SM_BLOCK_HDR volatile *    pHdr;
  896.     SM_DL_NODE volatile *      pNode;
  897.     unsigned                   biggestWords = 0;
  898.     unsigned                   tmp;                /* temp storage */
  899.     CACHE_PIPE_FLUSH ();            /* CACHE FLUSH   [SPR 68334] */
  900.     tmp = partId->verify;           /* PCI bridge bug [SPR 68844] */
  901.     if (SM_OBJ_VERIFY (partId) != OK)
  902.         {
  903.         return (ERROR);
  904.         }
  905.     if (smMemPartAccessGet (partId) != OK)
  906.         {
  907.         return (ERROR);
  908.         }
  909.     /* go through free list and find largest free */
  910.     for (pNode = (SM_DL_NODE volatile *) SM_DL_FIRST (&partId->freeList);
  911.  pNode != LOC_NULL;
  912.  pNode = (SM_DL_NODE volatile *) SM_DL_NEXT (pNode))
  913. {
  914. pHdr = (SM_BLOCK_HDR volatile *) SM_NODE_TO_HDR (pNode);
  915. if (ntohl (pHdr->nWords) > biggestWords)
  916.     {
  917.     biggestWords = ntohl (pHdr->nWords);
  918.     }
  919. }
  920.     if (smMemPartAccessRelease (partId) != OK)
  921.         {
  922.         return (ERROR);
  923.         }
  924.     /* convert words to bytes only if non-zero value [SPR 70280] */
  925.     if (biggestWords > 0)
  926.         {
  927.         biggestWords *= 2;
  928.         biggestWords -= sizeof (SM_BLOCK_HDR);
  929.         }
  930.     return (biggestWords);
  931.     }
  932. /******************************************************************************
  933. *
  934. * smMemAlignedBlockSplit - split a block on the free list into two blocks
  935. *
  936. * This routine is like smMemBlockSplit(), but also aligns the data block to
  937. * the given alignment.  The block looks like this after it is split:
  938. *
  939. *        |----------------------------------------------------------------|
  940. *        ^                      ^                       ^                 ^
  941. *        |                      |                       | space left over |
  942. *        |                      |<------- nWords ------>| after alignment |
  943. *        |                      |                       |                 |
  944. *   block begin       new aligned buffer begin         end           block end
  945. *
  946. *
  947. * After the split, if the first block has less than minWords in it, the
  948. * block is rejected, and null is returned, since we can't place this first
  949. * block on the free list.  If the space succeeding the newly allocated
  950. * aligned buffer is less than the minimum block size, then the bytes are
  951. * added to the newly allocated buffer.  If the space is greater than the
  952. * minimum block size,  then a new memory fragment is created and added to
  953. * the free list.  Care must be taken to insure that the orignal block passed
  954. * in to be split has at least (nWords + alignment/2) words in it.  If the
  955. * block has exactly nWords and is already aligned to the given alignment, it
  956. * will be deleted from the free list and returned unsplit.  Otherwise, the
  957. * second block will be returned.
  958. *
  959. * RETURNS: A pointer to a BLOCK_HDR 
  960. *
  961. * NOMANUAL
  962. */
  963. LOCAL SM_BLOCK_HDR volatile * smMemAlignedBlockSplit 
  964.     (
  965.     SM_PART_ID volatile     partId,
  966.     SM_BLOCK_HDR volatile * pHdr,
  967.     unsigned                nWords,   /* number of words in second block */
  968.     unsigned                minWords, /* min num of words allowed in a block */
  969.     unsigned                alignment /* boundry to align to */
  970.     )
  971.     {
  972.     SM_BLOCK_HDR volatile * pNewHdr;
  973.     SM_BLOCK_HDR volatile * pNextHdr;
  974.     char *     endOfBlock;
  975.     char *     pNewBlock;
  976.     int      blockSize;
  977.     unsigned                   tmp;                /* temp storage */
  978.     CACHE_PIPE_FLUSH ();            /* CACHE FLUSH   [SPR 68334] */
  979.     tmp = pHdr->nWords;             /* PCI bridge bug [SPR 68844] */
  980.     /* calculate end of pHdr block */
  981.     endOfBlock = (char *) pHdr + (ntohl (pHdr->nWords) * 2); 
  982.     /* calculate unaligned beginning of new block */ 
  983.     pNewBlock = (char *) ((unsigned) endOfBlock - 
  984. ((nWords - sizeof (SM_BLOCK_HDR) / 2) * 2));
  985.     /* align the beginning of the block */
  986.     pNewBlock = (char *)((unsigned) pNewBlock & ~(alignment - 1));
  987.     pNewHdr = (SM_BLOCK_HDR volatile *) SM_BLOCK_TO_HDR (pNewBlock);
  988.     /* adjust original block's word count */
  989.     blockSize = ((char *) pNewHdr - (char *) pHdr) / 2;
  990.     if (blockSize < minWords)
  991. {
  992. /* 
  993.  * Check to see if the new block is the same as the original block -
  994.  * if so, delete if from the free list.  If not, reject the newly
  995.  * split block because it's too small to hang on the free list.
  996.  */
  997. if (pNewHdr == pHdr)
  998.     {
  999.     smDllRemove (&partId->freeList, SM_HDR_TO_NODE (pHdr));
  1000.     }
  1001. else
  1002.     {
  1003.     return (NULL);
  1004.     }
  1005. }
  1006.     else
  1007. {
  1008. pNewHdr->pPrevHdr = (SM_BLOCK_HDR *) htonl (LOC_TO_GLOB_ADRS (pHdr));
  1009. pHdr->nWords = htonl (blockSize);
  1010. }
  1011.     CACHE_PIPE_FLUSH ();            /* CACHE FLUSH   [SPR 68334] */
  1012.     tmp = pNewHdr->nWords;          /* BRIDGE FLUSH  [SPR 68844] */
  1013.     /* 
  1014.      * Check to see if space left over after we aligned the new buffer
  1015.      * is big enough to be a fragment on the free list.
  1016.      */
  1017.     if (((UINT) endOfBlock - (UINT) pNewHdr - (nWords * 2)) < (minWords * 2))
  1018. {
  1019. /* nope - give all the memory to the newly allocated block */
  1020. pNewHdr->nWords = htonl ((endOfBlock - pNewBlock + 
  1021.  sizeof (SM_BLOCK_HDR)) / 2);
  1022. pNewHdr->free   = htonl (TRUE); 
  1023. /* fix next block to point to newly allocated block */
  1024. SM_NEXT_HDR (pNewHdr)->pPrevHdr = (SM_BLOCK_HDR *) 
  1025.    htonl (LOC_TO_GLOB_ADRS (pNewHdr));
  1026. }
  1027.     else
  1028. {
  1029. /* 
  1030.  * The extra bytes are big enough to be a fragment on the free list -
  1031.  * first, fix up the newly allocated block.
  1032.  */
  1033. pNewHdr->nWords = htonl (nWords);
  1034. pNewHdr->free   = htonl (TRUE); 
  1035. /* split off the memory after pNewHdr and add it to the free list */
  1036. pNextHdr = SM_NEXT_HDR (pHdr);
  1037. pNextHdr->nWords   = htonl (((UINT) endOfBlock - (UINT) pNextHdr) / 2);
  1038. pNextHdr->pPrevHdr = (SM_BLOCK_HDR *) htonl (LOC_TO_GLOB_ADRS (pHdr)); 
  1039. pNextHdr->free     = htonl (TRUE);
  1040. smDllAdd (&partId->freeList, SM_HDR_TO_NODE (pNextHdr));
  1041. /* fix next block to point to the new fragment on the free list */
  1042. SM_NEXT_HDR (pNextHdr)->pPrevHdr = (SM_BLOCK_HDR *) 
  1043.     htonl (LOC_TO_GLOB_ADRS (pNewHdr)); 
  1044. }
  1045.     CACHE_PIPE_FLUSH ();            /* CACHE FLUSH   [SPR 68334] */
  1046.     tmp = pNewHdr->nWords;          /* BRIDGE FLUSH  [SPR 68334] */
  1047.     return (pNewHdr);
  1048.     }
  1049. /******************************************************************************
  1050. *
  1051. * smMemBlockSplit - split a block into two blocks
  1052. *
  1053. * This routine splits the block pointed to into two blocks.  The second 
  1054. * block will have nWords words in it.  A pointer is returned to this block.
  1055. * If either resultant block would end up having less than minWords in it,
  1056. * NULL is returned.
  1057. *
  1058. * RETURNS: A pointer to the second block, or NULL.
  1059. * NOMANUAL
  1060. */
  1061. LOCAL SM_BLOCK_HDR volatile * smMemBlockSplit 
  1062.     (
  1063.     SM_BLOCK_HDR volatile * pHdr,
  1064.     unsigned                nWords,  /* number of words in second block */
  1065.     unsigned                minWords /* min num of words allowed in a block */
  1066.     )
  1067.     {
  1068.     unsigned                wordsLeft;
  1069.     SM_BLOCK_HDR volatile * pNewHdr;
  1070.     unsigned                tmp;                /* temp storage */
  1071.     CACHE_PIPE_FLUSH ();            /* CACHE FLUSH   [SPR 68334] */
  1072.     tmp = pHdr->nWords;             /* PCI bug       [SPR 68844] */
  1073.     /* check if block can be split */
  1074.     if ((nWords < minWords) ||
  1075.         ((wordsLeft = (ntohl (pHdr->nWords) - nWords)) < minWords))
  1076.         {
  1077.         return (NULL);                  /* not enough space left */
  1078.         }
  1079.     /* adjust original block size and create new block */
  1080.     pHdr->nWords = htonl (wordsLeft);
  1081.     pNewHdr = (SM_BLOCK_HDR volatile *) SM_NEXT_HDR (pHdr);
  1082.     pNewHdr->pPrevHdr = (SM_BLOCK_HDR *) htonl (LOC_TO_GLOB_ADRS (pHdr));
  1083.     pNewHdr->nWords   = htonl (nWords);
  1084.     pNewHdr->free     = pHdr->free;
  1085.     /* fix next block */
  1086.     SM_NEXT_HDR (pNewHdr)->pPrevHdr = (SM_BLOCK_HDR *) 
  1087. htonl (LOC_TO_GLOB_ADRS (pNewHdr));
  1088.     CACHE_PIPE_FLUSH ();            /* CACHE FLUSH   [SPR 68334] */
  1089.     tmp = pNewHdr->nWords;          /* BRIDGE FLUSH  [SPR 68334] */
  1090.     return (pNewHdr);
  1091.     }
  1092. /******************************************************************************
  1093. *
  1094. * smMemAddToPool - add memory to shared memory system partition (VxMP Option)
  1095. *
  1096. * This routine adds memory to the shared memory system partition after the
  1097. * initial allocation of memory.  The memory added need not be contiguous
  1098. * with memory previously assigned, but it must be in the same address
  1099. * space.
  1100. *
  1101. * <pPool> is the global address of shared memory added to the partition.
  1102. * The memory area pointed to by <pPool> must be in the same address space
  1103. * as the shared memory anchor and shared memory pool.
  1104. *
  1105. * <poolSize> is the size in bytes of shared memory added to the partition.
  1106. *
  1107. * AVAILABILITY
  1108. * This routine is distributed as a component of the unbundled shared memory
  1109. * objects support option, VxMP.
  1110. * RETURNS: OK, or ERROR if access to the shared memory system partition fails.
  1111. *
  1112. * ERRNO:
  1113. *  S_smObjLib_LOCK_TIMEOUT
  1114. */
  1115. STATUS smMemAddToPool 
  1116.     (
  1117.     char * pPool, /* pointer to memory pool */
  1118.     unsigned poolSize /* block size in bytes */
  1119.     )
  1120.     {
  1121.     return (smMemPartAddToPool ((SM_PART_ID) smSystemPartId, pPool, poolSize));
  1122.     }
  1123. /******************************************************************************
  1124. *
  1125. * smMemOptionsSet - set debug options for shared memory system partition (VxMP Option)
  1126. *
  1127. * This routine sets the debug options for the shared system memory partition.
  1128. * Two kinds of errors are detected:  attempts to allocate more memory than
  1129. * is available, and bad blocks found when memory is freed or reallocated.  
  1130. * In both cases, the following options can be selected for actions to be 
  1131. * taken when an error is detected:  (1) return the error status, (2) log 
  1132. * an error message and return the error status, or (3) log an error message 
  1133. * and suspend the calling task.  These options are discussed in detail in 
  1134. * the library manual entry for smMemLib.
  1135. *
  1136. * AVAILABILITY
  1137. * This routine is distributed as a component of the unbundled shared memory
  1138. * objects support option, VxMP.
  1139. * RETURNS: OK or ERROR.
  1140. *
  1141. * ERRNO
  1142. *  S_smObjLib_LOCK_TIMEOUT
  1143. */
  1144. STATUS smMemOptionsSet
  1145.     (
  1146.     unsigned options    /* options for system partition */
  1147.     )
  1148.     {
  1149.     return (smMemPartOptionsSet ((SM_PART_ID) smSystemPartId, options));
  1150.     }
  1151. /******************************************************************************
  1152. *
  1153. * smMemMalloc - allocate block of memory from shared memory system partition (VxMP Option)
  1154. *
  1155. * This routine allocates a block of memory from the shared memory 
  1156. * system partition whose size is equal to or greater than <nBytes>.
  1157. * The return value is the local address of the allocated shared memory block.
  1158. *
  1159. * AVAILABILITY
  1160. * This routine is distributed as a component of the unbundled shared memory
  1161. * objects support option, VxMP.
  1162. * RETURNS:
  1163. * A pointer to the block, or NULL if the memory cannot be allocated.
  1164. *
  1165. * ERRNO:
  1166. *  S_memLib_NOT_ENOUGH_MEMORY
  1167. *  S_smObjLib_LOCK_TIMEOUT
  1168. */
  1169. void * smMemMalloc 
  1170.     (
  1171.     unsigned nBytes             /* number of bytes to allocate */
  1172.     )
  1173.     {
  1174.     return (smMemPartAlloc ((SM_PART_ID) smSystemPartId, (unsigned) nBytes));
  1175.     }
  1176. /******************************************************************************
  1177. *
  1178. * smMemCalloc - allocate memory for array from shared memory system partition (VxMP Option)
  1179. *
  1180. * This routine allocates a block of memory for an array that contains
  1181. * <elemNum> elements of size <elemSize> from the shared memory system 
  1182. * partition.
  1183. * The return value is the local address of the allocated shared memory block.
  1184. *
  1185. * AVAILABILITY
  1186. * This routine is distributed as a component of the unbundled shared memory
  1187. * objects support option, VxMP.
  1188. * RETURNS:
  1189. * A pointer to the block, or NULL if the memory cannot be allocated.
  1190. *
  1191. * ERRNO:
  1192. *  S_memLib_NOT_ENOUGH_MEMORY
  1193. *  S_smObjLib_LOCK_TIMEOUT
  1194. */
  1195. void * smMemCalloc 
  1196.     (
  1197.     int elemNum, /* number of elements */
  1198.     int elemSize /* size of elements */
  1199.     )
  1200.     {
  1201.     void * pMem;
  1202.     size_t nBytes = elemNum * elemSize;
  1203.     
  1204.     if ((pMem = smMemPartAlloc ((SM_PART_ID) smSystemPartId,
  1205.                                 (unsigned) nBytes))
  1206.              != NULL)
  1207.         {
  1208. bzero ((char *) pMem, (int) nBytes);
  1209.         }
  1210.     return (pMem);
  1211.     }
  1212. /******************************************************************************
  1213. *
  1214. * smMemRealloc - reallocate block of memory from shared memory system partition (VxMP Option)
  1215. *
  1216. * This routine changes the size of a specified block and returns a pointer to
  1217. * the new block of shared memory.  The contents that fit inside the new 
  1218. * size (or old size, if smaller) remain unchanged.
  1219. * The return value is the local address of the reallocated shared memory block.
  1220. *
  1221. * AVAILABILITY
  1222. * This routine is distributed as a component of the unbundled shared memory
  1223. * objects support option, VxMP.
  1224. * RETURNS:
  1225. * A pointer to the new block of memory, or NULL if the reallocation cannot
  1226. * be completed.
  1227. *
  1228. * ERRNO:
  1229. *  S_memLib_NOT_ENOUGH_MEMORY
  1230. *  S_memLib_BLOCK_ERROR
  1231. *  S_smObjLib_LOCK_TIMEOUT
  1232. */
  1233. void * smMemRealloc 
  1234.     (
  1235.     void * pBlock, /* block to be reallocated */
  1236.     unsigned newSize /* new block size */
  1237.     )
  1238.     {
  1239.     return (smMemPartRealloc ((SM_PART_ID) smSystemPartId, (char *) pBlock,
  1240.     (unsigned) newSize));
  1241.     }
  1242. /******************************************************************************
  1243. *
  1244. * smMemFree - free a shared memory system partition block of memory (VxMP Option)
  1245. *
  1246. * This routine takes a block of memory previously allocated with smMemMalloc() 
  1247. * or smMemCalloc() and returns it to the free shared memory system pool.
  1248. *
  1249. * It is an error to free a block of memory that was not previously allocated.
  1250. *
  1251. * AVAILABILITY
  1252. * This routine is distributed as a component of the unbundled shared memory
  1253. * objects support option, VxMP.
  1254. * RETURNS: OK, or ERROR if the block is invalid.
  1255. *
  1256. * ERRNO:
  1257. *  S_memLib_BLOCK_ERROR
  1258. *  S_smObjLib_LOCK_TIMEOUT
  1259. *
  1260. * SEE ALSO: smMemMalloc(), smMemCalloc()
  1261. */
  1262. STATUS smMemFree 
  1263.     (
  1264.     void * ptr       /* pointer to block of memory to be freed */
  1265.     )
  1266.     {
  1267.     return (smMemPartFree ((SM_PART_ID) smSystemPartId, (char *) ptr));
  1268.     }
  1269. /******************************************************************************
  1270. *
  1271. * smMemFindMax - find largest free block in shared memory system partition (VxMP Option)
  1272. *
  1273. * This routine searches for the largest block in the shared memory 
  1274. * system partition free list and returns its size.
  1275. *
  1276. * AVAILABILITY
  1277. * This routine is distributed as a component of the unbundled shared memory
  1278. * objects support option, VxMP.
  1279. * RETURNS: The size (in bytes) of the largest available block, or ERROR if
  1280. * the attempt to access the partition fails.
  1281. *
  1282. * ERRNO:
  1283. *  S_smObjLib_LOCK_TIMEOUT
  1284. */
  1285. int smMemFindMax (void)
  1286.     {
  1287.     return (smMemPartFindMax ((SM_PART_ID) smSystemPartId));
  1288.     }
  1289. /******************************************************************************
  1290. *
  1291. * smMemPartAllocError - handle allocation error
  1292. *
  1293. * This routine handles an allocation error according to the options set for
  1294. * the specified partition.  <pPart> is the local address of partition to use.
  1295. *
  1296. * RETURNS: N/A
  1297. */
  1298. LOCAL void smMemPartAllocError
  1299.     (
  1300.     SM_PART_ID volatile pPart,
  1301.     unsigned            nBytes
  1302.     )
  1303.     {
  1304.     int taskOptions;
  1305.     int partOptions; /* partition options */
  1306.     unsigned    tmp;            /* temp storage */
  1307.     errno = S_memLib_NOT_ENOUGH_MEMORY;
  1308.     CACHE_PIPE_FLUSH ();            /* CACHE FLUSH   [SPR 68334] */
  1309.     tmp = pPart->options;           /* PCI bridge bug [SPR 68844] */
  1310.     partOptions = ntohl (pPart->options);
  1311.     if (partOptions & MEM_ALLOC_ERROR_LOG_FLAG)
  1312.         {
  1313.         logMsg (smMemMsgBlockTooBig, nBytes, (int) SM_OBJ_ADRS_TO_ID (pPart), 
  1314.                 0, 0, 0, 0);
  1315.         }
  1316.     if (partOptions & MEM_ALLOC_ERROR_SUSPEND_FLAG)
  1317.         {
  1318.         taskOptionsGet (0, &taskOptions);
  1319.         if ((taskOptions & VX_UNBREAKABLE) == 0)
  1320.             {
  1321.             taskSuspend (0);
  1322.             }
  1323.         }
  1324.     }
  1325. /******************************************************************************
  1326. *
  1327. * smMemPartBlockError - handle invalid block error
  1328. *
  1329. * This routine handles an invalid block error according to the options set for
  1330. * the specified partition.  <pPart> is the local address of partition to use.
  1331. *
  1332. * RETURNS: N/A
  1333. *
  1334. * NOMANUAL
  1335. */
  1336. LOCAL void smMemPartBlockError
  1337.     (
  1338.     SM_PART_ID volatile pPart,
  1339.     char *              pBlock,
  1340.     char *              label
  1341.     )
  1342.     {
  1343.     int taskOptions;
  1344.     int partOptions; /* partition options */
  1345.     unsigned    tmp;            /* temp storage */
  1346.     errno = S_memLib_BLOCK_ERROR;
  1347.     /*
  1348.      * if ...LOG_FLAG is set, send a log message
  1349.      */
  1350.     CACHE_PIPE_FLUSH ();            /* CACHE FLUSH   [SPR 68334] */
  1351.     tmp = pPart->options;           /* PCI bridge bug [SPR 68844] */
  1352.     partOptions = ntohl (pPart->options);
  1353.     if (partOptions & MEM_BLOCK_ERROR_LOG_FLAG)
  1354.         {
  1355.         logMsg (smMemMsgBlockError, (int) label, (int) pBlock, 
  1356.                 (int) SM_OBJ_ADRS_TO_ID (pPart), 0, 0, 0);
  1357.         }
  1358.     /*
  1359.      * If ...SUSPEND_FLAG is set, suspend the task
  1360.      */
  1361.     if (partOptions & MEM_BLOCK_ERROR_SUSPEND_FLAG)  
  1362.         {
  1363.         taskOptionsGet (0, &taskOptions);
  1364.         if ((taskOptions & VX_UNBREAKABLE) == 0)
  1365.             {
  1366.             taskSuspend (0);
  1367.             }
  1368.         }
  1369.     }
  1370. /******************************************************************************
  1371. *
  1372. * smMemPartBlockIsValid - check validity of block
  1373. *
  1374. * NOTE: This routine should NOT be called with the partition semaphore taken
  1375. * if possible, because if the block IS screwed up, then a bus error is
  1376. * not unlikely and we would hate to have the task die with the semaphore
  1377. * taken, thus hanging the partition.
  1378. *
  1379. * <pPart> is the local address of partition to use.
  1380. *
  1381. * NOMANUAL
  1382. */
  1383. BOOL smMemPartBlockIsValid
  1384.     (
  1385.     SM_PART_ID volatile     partId,
  1386.     SM_BLOCK_HDR volatile * pHdr,
  1387.     BOOL                    isFree       /* expected status */
  1388.     )
  1389.     {
  1390.     BOOL valid;
  1391.     valid = SM_MEM_IS_ROUND (pHdr) /* aligned */
  1392. /* size is round */
  1393.             && SM_MEM_IS_ROUND (2 * ntohl (pHdr->nWords))
  1394. /* size <= total */
  1395.             && (ntohl (pHdr->nWords) <= ntohl (partId->totalWords))
  1396.             && (ntohl (pHdr->free) == isFree) /* right alloc-ness */
  1397.             && (pHdr == SM_PREV_HDR(SM_NEXT_HDR (pHdr)))/* matches next block*/
  1398.             && (pHdr ==SM_NEXT_HDR(SM_PREV_HDR (pHdr)));/* matches prev block*/
  1399.     return (valid);
  1400.     }
  1401. /******************************************************************************
  1402. *
  1403. * smMemPartAccessGet - obtain exclusive access to a partition
  1404. *
  1405. * <pPart> is the local address of partition to use. <pOldLvl> is a pointer 
  1406. * to the processor status register value.
  1407. *
  1408. * RETURNS: OK, or ERROR if access cannot be obtained
  1409. *
  1410. * NOMANUAL
  1411. */
  1412. STATUS smMemPartAccessGet 
  1413.     (
  1414.     SM_PART_ID volatile partId   /* partition to access */
  1415.     )
  1416.     {
  1417.     TASK_SAFE (); /* prevent task deletion */
  1418.     if (semSmTake (&partId->sem, WAIT_FOREVER) != OK)
  1419. {                               /* get exclusive access */
  1420. TASK_UNSAFE ();
  1421. return (ERROR);
  1422. }
  1423.     return (OK);
  1424.     }
  1425. /******************************************************************************
  1426. *
  1427. * smMemPartAccessRelease - release exclusive access to a partition
  1428. *
  1429. * <pPart> is the local address of partition to use. 
  1430. *
  1431. * RETURNS: OK, or ERROR if access cannot be released
  1432. *
  1433. * NOMANUAL
  1434. */
  1435. STATUS smMemPartAccessRelease 
  1436.     (
  1437.     SM_PART_ID volatile partId       /* partition to release */
  1438.     )
  1439.     {
  1440.     if (semSmGive (&partId->sem) != OK) /* give back partition sem */
  1441.         {              
  1442. TASK_UNSAFE (); /* allow task deletion */
  1443. return (ERROR);
  1444. }
  1445.     TASK_UNSAFE (); /* allow task deletion */
  1446.     return (OK);
  1447.     }