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

VxWorks

开发平台:

C/C++

  1. /* zbufLib.c - zbuf interface library */
  2. /* Copyright 1984 - 2001 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01h,07may02,kbw  man page edits
  8. 01g,15oct01,rae  merge from truestack ver 01g, base 01f (AE / 5_X)
  9. 01f,26jan95,jdi  format tweak.
  10. 01e,24jan95,rhp  revisions based on jdi feedback
  11. 01d,16jan95,rhp  fix SEE ALSO subroutine ref format
  12. 01c,15nov94,dzb  doc tweaks.
  13. 01b,09nov94,rhp  library man page added, subroutine man pages edited.
  14. 01a,08nov94,dzb  written.
  15. */
  16. /*
  17. DESCRIPTION
  18. This library contains routines to create, build, manipulate, and
  19. delete zbufs.  Zbufs, also known as "zero copy buffers," are a data
  20. abstraction designed to allow software modules to share buffers
  21. without unnecessarily copying data.
  22. To support the data abstraction, the subroutines in this library hide
  23. the implementation details of zbufs.  This also maintains the
  24. library's independence from any particular implementation mechanism,
  25. thus permitting the zbuf interface to be used with other buffering schemes.
  26. Zbufs have three essential properties.  First, a zbuf holds a
  27. sequence of bytes.  Second, these bytes are organized into one or more
  28. segments of contiguous data, although the successive segments
  29. themselves are not usually contiguous.  Third, the data within a
  30. segment may be shared with other segments; that is, the data may be in use
  31. by more than one zbuf at a time.
  32. ZBUF TYPES
  33. The following data types are used in managing zbufs:
  34. .iP ZBUF_ID 16 3
  35. An arbitrary (but unique) integer that identifies a particular zbuf.
  36. .iP ZBUF_SEG
  37. An arbitrary (but unique within a single zbuf) integer that identifies
  38. a segment within a zbuf.
  39. .LP
  40. ADDRESSING BYTES IN ZBUFS
  41. The bytes in a zbuf are addressed by the combination <zbufSeg>,
  42. <offset>.  The <offset> may be positive or negative, and is simply the
  43. number of bytes from the beginning of the segment <zbufSeg>.
  44. A <zbufSeg> can be specified as NULL, to identify the segment at the
  45. beginning of a zbuf.  If <zbufseg> is NULL, <offset> is the
  46. absolute offset to any byte in the zbuf.  However, it is more
  47. efficient to identify a zbuf byte location relative to the <zbufSeg>
  48. that contains it; see zbufSegFind() to convert any <zbufSeg>, <offset>
  49. pair to the most efficient equivalent.
  50. Negative <offset> values always refer to bytes before the
  51. corresponding <zbufSeg>, and are not usually the most efficient
  52. address formulation (though using them may save your
  53. program other work in some cases).
  54. The following special <offset> values, defined as constants,
  55. allow you to specify the very beginning or the very end of an entire zbuf,
  56. regardless of the <zbufSeg> value:
  57. .iP ZBUF_BEGIN 16 3
  58. The beginning of the entire zbuf.
  59. .iP ZBUF_END
  60. The end of the entire zbuf (useful for appending to a zbuf; see below).
  61. .LP
  62. INSERTION AND LIMITS ON OFFSETS
  63. An <offset> is not valid if it points outside the zbuf.  Thus, to
  64. address data currently within an N-byte zbuf, the valid offsets
  65. relative to the first segment are 0 through N-1.
  66. Insertion routines are a special case: they obey the usual
  67. convention, but they use <offset> to specify where the new data
  68. begins after the insertion is complete.  Therefore, the original
  69. zbuf data is always inserted just before the byte
  70. location addressed by the <offset> value.  The value of this
  71. convention is that it permits inserting (or concatenating) data either
  72. before or after the existing data.  To insert before all the data
  73. currently in a zbuf segment, use 0 as <offset>.  To insert after all
  74. the data in an N-byte segment, use N as <offset>. An <offset> of N-1
  75. inserts the data just before the last byte in an N-byte segment.
  76. An <offset> of 0 is always a valid insertion point; for an empty zbuf,
  77. 0 is the only valid <offset> (and NULL the only valid <zbufSeg>).
  78. SHARING DATA
  79. The routines in this library avoid copying segment data whenever
  80. possible.  Thus, by passing and manipulating ZBUF_IDs rather than
  81. copying data, multiple programs can communicate with greater
  82. efficiency.  However, each program must be aware of data sharing:
  83. changes to the data in a zbuf segment are visible to all zbuf segments
  84. that reference the data.
  85. To alter your own program's view of zbuf data without affecting other
  86. programs, first use zbufDup() to make a new zbuf; then you can use an
  87. insertion or deletion routine, such as zbufInsertBuf(), to add a
  88. segment that only your program sees (until you pass a zbuf containing
  89. it to another program).  It is safest to do all direct data
  90. manipulation in a private buffer, before enrolling it in a zbuf: in
  91. principle, you should regard all zbuf segment data as shared.
  92. Once a data buffer is enrolled in a zbuf segment, the zbuf library is
  93. responsible for noticing when the buffer is no longer in use by any
  94. program, and freeing it.  To support this, zbufInsertBuf() requires
  95. that you specify a callback to a free routine each time you build a
  96. zbuf segment around an existing buffer.  You can use this callback to notify
  97. your application when a data buffer is no longer in use.
  98. VXWORKS AE PROTECTION DOMAINS
  99. Under VxWorks AE, this feature is restricted to the kernel protection 
  100. domain.  This restriction does not apply under non-AE versions of VxWorks.  
  101. To use this feature, include the following component:
  102. INCLUDE_ZBUF_SOCK
  103. SEE ALSO
  104. zbufSockLib
  105. INTERNAL
  106. Extensions:
  107. zbufJoin (zbufId, zbufSeg) - coalesce two adjacent segment fragments
  108.     This routine combines two or more contiguous zbuf segments into a single
  109.     zbuf segment.  Such an operation is only feasible for joining segments
  110.     that have the same freeRtn and freeArg, and that follow eachother in
  111.     the zbuf.  This could be useful for coalescing zbuf segments fragmented
  112.     by split operations.
  113. zbufOwn (zbufId, zbufSeg, offset, len) - own a local copy of zbuf data
  114.     This routine makes a local copy of a portion of a zbuf.  This
  115.     is useful if you want to change the actual data in a zbuf, but want to
  116.     make sure that you are not corrupting another zbuf that shares the
  117.     same data.  If you are the only zbuf segment using a particular buffer,
  118.     this routine does nothing.  If other zbufs reference the same data, this
  119.     routine inserts a copy of the requested data, then deletes reference
  120.     to the original data.
  121. */
  122. /* includes */
  123. #include "vxWorks.h"
  124. #include "zbufLib.h"
  125. #include "stdlib.h"
  126. #include "memPartLib.h"
  127. /* locals */
  128. /*
  129.  * N.B.
  130.  * As other back-ends to zbuf are ever developed, and need to be run
  131.  * concurrently with existing back-ends, the zbufFunc table needs to have
  132.  * the back-end resident function table pointer in the ZBUF_ID.  This will
  133.  * require a modification to the current method of simply passing through
  134.  * the ZBUF_ID to the back-end.  Instead, the ZBUF_ID will have to point
  135.  * to a structure, which would contain the back-end function table pointer
  136.  * and a back-end-specific XX_ID pointer.
  137.  */
  138. LOCAL ZBUF_FUNC zbufFuncNull = /* null funcs for unconnected zbufs */
  139.     {
  140.     NULL, /* zbufCreate() */
  141.     NULL, /* zbufDelete() */
  142.     NULL, /* zbufInsert() */
  143.     NULL, /* zbufInsertBuf() */
  144.     NULL, /* zbufInsertCopy() */
  145.     NULL, /* zbufExtractCopy() */
  146.     NULL, /* zbufCut() */
  147.     NULL, /* zbufSplit() */
  148.     NULL, /* zbufDup() */
  149.     NULL, /* zbufLength() */
  150.     NULL, /* zbufSegFind() */
  151.     NULL, /* zbufSegNext() */
  152.     NULL, /* zbufSegPrev() */
  153.     NULL, /* zbufSegData() */
  154.     NULL /* zbufSegLength() */
  155.     };
  156. LOCAL ZBUF_FUNC * pZbufFunc = &zbufFuncNull;
  157. /*******************************************************************************
  158. *
  159. * zbufLibInit - initialize the zbuf interface library
  160. *
  161. * This routine initializes the zbuf interface facility.  It
  162. * must be called before any zbuf routines are used.  This routine is
  163. * typically called during the initialization of a VxWorks facility which
  164. * uses or extends the zbuf interface, although this is not a requirement.
  165. * The zbuf library may be used on its own, provided an appropriate back-end
  166. * buffer mechanism is available, and is specified by <libInitRtn>.
  167. *
  168. * RETURNS:
  169. * OK, or ERROR if the zbuf interface cannot be initialized.
  170. *
  171. * NOMANUAL
  172. */
  173. STATUS zbufLibInit
  174.     (
  175.     FUNCPTR libInitRtn /* back-end buffer mechanism init rtn */
  176.     )
  177.     {
  178.     ZBUF_FUNC * pZbufFuncTemp; /* temp return of back-end func table */
  179.     /* call the back-end initialization routine - watch for NULL func ptr */
  180.     if ((libInitRtn == NULL) || ((pZbufFuncTemp =
  181. (ZBUF_FUNC *) (libInitRtn) ()) == NULL))
  182. return (ERROR);
  183.     pZbufFunc = pZbufFuncTemp; /* connect back-end func tbl */
  184.     return (OK);
  185.     }
  186. #if FALSE /* Pool routines not in service yet */
  187. /*******************************************************************************
  188. *
  189. * zbufSegPoolCreate - create an empty zbuf segment pool
  190. *
  191. * This routine creates a zbuf segment pool.  It remains empty (that is, does
  192. * not contain any free segments) until segments are added by calling
  193. * zbufSegPoolAdd().  Operations performed on zbuf segments pools require
  194. * a zbuf segment pool ID, which is returned by this routine.
  195. *
  196. * RETURNS:
  197. * A zbuf segment pool ID, or NULL if an ID cannot be created.
  198. *
  199. * SEE ALSO: zbufSegPoolDelete(), zbufSegPoolAdd()
  200. *
  201. * NOMANUAL
  202. */
  203. ZBUF_POOL_ID zbufSegPoolCreate (void)
  204.     {
  205.     ZBUF_POOL_ID zbufPoolId; /* new ID */
  206.     
  207.     if ((zbufPoolId = (ZBUF_POOL_ID) KHEAP_ALLOC(sizeof(struct zbufPoolId))) ==
  208. NULL)
  209. return (NULL); /* malloc pool ID struct */
  210.     /* create mutex sem for guarding access to zbuf segment pool */
  211.     if ((zbufPoolId->poolSem = semMCreate ((SEM_Q_PRIORITY |
  212. SEM_INVERSION_SAFE | SEM_DELETE_SAFE))) == ERROR)
  213. {
  214. KHEAP_FREE(zbufPoolId); /* free resources */
  215. return (NULL);
  216. }
  217.     /* create binary sem for waiting for free segments to come into pool */
  218.     if ((zbufPoolId->waitSem = semBCreate (SEM_Q_PRIORITY, SEM_EMPTY)) == ERROR)
  219. {
  220.         semDelete (zbufPoolId->poolSem); /* free resources */
  221. KHEAP_FREE(zbufPoolId);
  222. return (NULL);
  223. }
  224.     zbufPoolId->use = 0; /* no loaned buffers yet */
  225.     zbufPoolId->blockHead = NULL; /* no blocks/segs yet */
  226.     return (zbufPoolId);
  227.     }
  228. /*******************************************************************************
  229. *
  230. * zbufSegPoolDelete - delete a zbuf segment pool and free associated segments
  231. *
  232. * This routine will free any segments associated with <zbufPoolId>,
  233. * then delete the zbuf segment pool ID itself.  To do this, all segments
  234. * must be in the pool (that is, no segments may currently be part of a zbuf).
  235. * <zbufPoolId> must not be used after this routine executes successfully.
  236. *
  237. * Associated segments will be returned to the system memory pool if they
  238. * were allocated with zbufSegPoolAdd().  No action will be taken upon
  239. * user segments added to the segment pool by specifying the segment block
  240. * start address. These segments should be considered free after this
  241. * routine executes successfully.
  242. * RETURNS:
  243. * OK, or ERROR if the zbuf segment pool has outstanding segments.
  244. *
  245. * SEE ALSO: zbufSegPoolCreate(), zbufSegPoolAdd()
  246. *
  247. * NOMANUAL
  248. */
  249. STATUS zbufSegPoolDelete
  250.     (
  251.     ZBUF_POOL_ID zbufPoolId /* zbuf segment pool to delete */
  252.     )
  253.     {
  254.     ZBUF_BLOCK_ID zbufBlock; /* ptr to block headers */
  255.     ZBUF_BLOCK_ID zbufBlockTemp; /* temp storage of block hdr */
  256.     /* obtain exclusive access to zbuf segment pool structures */
  257.     if ((semTake (zbufPoolId->poolSem, WAIT_FOREVER)) == ERROR)
  258. return (ERROR);
  259.     if (zbufPoolId->use != 0) /* any segments in use ? */
  260. {
  261. semGive (zbufPoolId->poolSem); /* give up access */
  262. return (ERROR); /* cannot feee if in use */
  263. }
  264.     /* go through list of block headers, freein all alloc'ed mem */
  265.     for (zbufBlock = zbufPoolId->blockHead; zbufBlock != NULL;)
  266. {
  267. zbufBlockTemp = zbufBlock->blockNext;
  268. KHEAP_FREE(zbufBlock); /* free each hdr & memory */
  269.         zbufBlock = zbufBlockTemp; /* bump to next block hdr */
  270.         }
  271.     semDelete (zbufPoolId->waitSem); /* free wait binary sem */
  272.     semDelete (zbufPoolId->poolSem); /* free pool mutex sem */
  273.     KHEAP_FREE(zbufPoolId); /* free actual pool ID struct */
  274.     return (OK);
  275.     }
  276. /*******************************************************************************
  277. *
  278. * zbufSegPoolAdd - add a block of zbuf segments to a zbuf segment pool
  279. *
  280. * This routine adds a block of zbuf segments to <zbufPoolId>.  This routine
  281. * may be called multiple times to add segment blocks of different sizes and
  282. * numbers.
  283. *
  284. * The segment size <segSise> will be rounded up to the memory allignment
  285. * requirements of the target architecture.  The minimum size of a
  286. * segment is the size of a void pointer.
  287. *
  288. * If system memory is to be used for the segment allocation, set <blockStart>
  289. * to NULL, in which case <blockLength> parameter will be ignored.
  290. * Otherwise, a block of memory to be used may be specified by <blockStart> and
  291. * <blockLen>.  If a segment block is specified with <blockStart>, the
  292. * <segNum> parameter is ignored.  Instead, the number of alligned segments
  293. * that can be obtained from <memLength> are added to the pool.
  294. * If a zbuf segment pool is deleted with zbufSegPoolDelete(), any allocated
  295. * segment blocks will be returned to the system memory pool.  Specific memory
  296. * blocks obtained through <blockStart> should be considered free after
  297. * zbufSegPoolDelete() executes successfully, but the user will not be
  298. * given any further indication of the memory being released from the pool.
  299. * RETURNS:
  300. * OK, or ERROR if the zbuf segment block cannot be added to the pool.
  301. *
  302. * SEE ALSO: zbufSegPoolDelete()
  303. *
  304. * NOMANUAL
  305. */
  306. STATUS zbufSegPoolAdd
  307.     (
  308.     ZBUF_POOL_ID zbufPoolId, /* pool to add zbuf segments to */
  309.     int segSize, /* size of new segments */
  310.     int segNum, /* number of new segs (system memory) */
  311.     caddr_t blockStart, /* start of seg block (user memory) */
  312.     int blockLen /* length of seg block (user memory) */
  313.     )
  314.     {
  315.     ZBUF_BLOCK_ID zbufBlockNew; /* new block header */
  316.     ZBUF_BLOCK_ID  zbufBlock = NULL; /* location to insert new hdr */
  317.     STATUS status = ERROR; /* return value */
  318.     int ix; /* counter for block init */
  319.     /* obtain exclusive access to zbuf segment pool structures */
  320.     if ((semTake (zbufPoolId->poolSem, WAIT_FOREVER)) == ERROR)
  321. return (ERROR);
  322.     /* adjust segSize for mem allign - must be at least void * (see below) */
  323.     segSize = min (MEM_ROUND_UP(segSize), sizeof (void *));
  324.     if (blockStart == NULL) /* if allocating from system */
  325. {
  326. if ((zbufBlockNew = (ZBUF_BLOCK_ID) KHEAP_ALLOC((sizeof(struct zbufBlockId)
  327.     + (segSize * segNum)))) == NULL) /* allocate hdr and seg block */
  328.     goto release;
  329. blockStart = (caddr_t) (zbufBlockNew + 1);/* set start of seg block */
  330.         }
  331.     else /* use supplied user memory */
  332. {
  333.         /* calc the number of segments that can be obtained from user mem */
  334. if ((segNum = blockLen / segSize) == 0) /* must be at least one */
  335.     goto release;
  336.         if ((zbufBlockNew = (ZBUF_BLOCK_ID) KHEAP_ALLOC
  337.     (sizeof(struct zbufBlockId))) == NULL)/* allocate block hdr only */
  338.     goto release;
  339. }
  340.     zbufBlockNew->length = segSize; /* block is for "segSize" */
  341.     zbufBlockNew->zbufPoolId = zbufPoolId; /* for _zbufSegPoolFree() */
  342.     zbufBlockNew->segFree = (void *) blockStart;/* first seg in block is free */
  343.     /*
  344.      * Go through block, and divide up into segNum number of segments.
  345.      * The first location of each segment points to the next free segment,
  346.      * with the last segment pointing to NULL.  In this way, a sll of free
  347.      * segments is kept, with the pointer in the segment memory itself.
  348.      */
  349.     for (ix = 1; ix < segNum; ix++, blockStart += segSize)
  350. *((void **) blockStart) = (void *) (blockStart + segSize);
  351.     *((void **) blockStart) = NULL;
  352.     /* find the proper location in the pool to insert the new seg block */
  353.     if ((zbufPoolId->blockHead != NULL) &&
  354.         (zbufPoolId->blockHead->length < segSize))
  355. {
  356.         zbufBlock = zbufPoolId->blockHead;
  357.         for (; zbufBlock->blockNext != NULL; zbufBlock = zbufBlock->blockNext)
  358.     if (zbufBlock->blockNext->length >= segSize)
  359.         break;
  360.         }
  361.     if (zbufBlock == NULL) /* insert new block at start */
  362. {
  363. zbufBlockNew->blockNext = zbufPoolId->blockHead;/* new to first */
  364.         zbufPoolId->blockHead = zbufBlockNew; /* head to new */
  365. }
  366.     else /* insert in middle or end */
  367. {
  368. zbufBlockNew->blockNext = zbufBlock->blockNext; /* new to next */
  369. zbufBlock->blockNext = zbufBlockNew; /* prev to new */
  370. }
  371.     status = OK; /* done! */
  372. release: /* error encountered */
  373.     semGive (zbufPoolId->poolSem); /* give up access */
  374.     return (status);
  375.     }
  376. /*******************************************************************************
  377. *
  378. * _zbufSegPoolFree - return a zbuf segment to a zbuf segment pool
  379. *
  380. * This routine returns a zbuf segment to a zbuf segment pool.
  381. * To return <buf> to the zbuf segment block that it was originally allocated
  382. * from, place the segment <buf> at the start of the segment block associated
  383. * with <zbufBlockId>.  If <zbufBlockId> is NULL, the segment <buf> was
  384. * allocated from system memory, and should be returned with free().
  385. *
  386. * RETURNS: N/A.
  387. *
  388. * NOMANUAL
  389. */
  390. void _zbufSegPoolFree 
  391.     (
  392.     caddr_t buf, /* zbuf segment to return */
  393.     ZBUF_BLOCK_ID zbufBlockId /* seg block to return <buf> to */
  394.     )
  395.     {
  396.     ZBUF_POOL_ID zbufPoolId; /* back pointer to pool ID */
  397.     if (zbufBlockId == NULL) /* if originally malloc'ed */
  398. KHEAP_FREE(buf);
  399.     else /* else return to pool */
  400. {
  401. zbufPoolId = zbufBlockId->zbufPoolId; /* obtain back pointer to ID */
  402. /* obtain exclusive access to zbuf segment pool structures */
  403.         if ((semTake (zbufPoolId->poolSem, WAIT_FOREVER)) == ERROR)
  404.     return;
  405.         *((void **) buf) = zbufBlockId->segFree;/* hook my next to first */
  406. zbufBlockId->segFree = (void *) buf; /* hook head to me */
  407.         zbufPoolId->use--; /* check it in */
  408.         semFlush (zbufPoolId->waitSem); /* free those waiting for seg */
  409.         semGive (zbufPoolId->poolSem); /* give up access */
  410. }
  411.     }
  412. /*******************************************************************************
  413. *
  414. * zbufInsertPool - obtain a segment and insert into a zbuf
  415. *
  416. * This routine obtains a zbuf segment from <zbufPoolId> and
  417. * inserts it into zbuf <zbufId> at the specified location.  The requested
  418. * segment is not initialized (that is, it is not zeroed out) by this routine.
  419. * This routine searches <zbufPoolId> looking for a suitably sized free
  420. * segment.  The smallest free segment that is at least <len> bytes in length
  421. * is obtained and inserted into <zbufId>.  If no free segments are found,
  422. * this routine will pend for <timeout> ticks waiting for a zbuf segment to be
  423. * released from another zbuf.  As segments are released from other zbufs,
  424. * they are examined to see if they are at least <len> bytes.  If they are
  425. * not suitable, the timeout is reset to <timeout> ticks, and this routine
  426. * will pend again waiting for a segment to be released.
  427. *
  428. * If <zbufPoolId> is NULL, the system memory pool is used to allocate a
  429. * segment of <len> bytes.  Upon release of this segment from the zbuf, it
  430. * will returned to the system memory pool.
  431. *
  432. * The location of insertion is specified by <zbufSeg> and <offset>.  See
  433. * the zbufLib manual page for more information on specifying
  434. * a byte location within a zbuf.  In particular, insertion within
  435. * a zbuf occurs before the byte location specified by <zbufSeg> and <offset>.
  436. * Additionally, <zbufSeg> and <offset> must be NULL and 0,
  437. * respectively, when inserting into an empty zbuf.
  438. *
  439. * RETURNS:
  440. * The zbuf segment ID of the inserted segment,
  441. * or NULL if the operation fails.
  442. *
  443. * NOMANUAL
  444. */
  445. ZBUF_SEG zbufInsertPool
  446.     (
  447.     ZBUF_POOL_ID zbufPoolId, /* pool to obtain zbuf segment from */
  448.     ZBUF_ID zbufId, /* zbuf to insert segment into */
  449.     ZBUF_SEG zbufSeg, /* zbuf segment base for <offset> */
  450.     int offset, /* relative byte offset */
  451.     int len, /* requested segment length in bytes */
  452.     int timeout /* timeout in ticks */
  453.     )
  454.     {
  455.     ZBUF_BLOCK_ID  zbufBlock = NULL; /* segment block header */
  456.     caddr_t buf = NULL; /* requested segment buf */
  457.     int lenLast = NULL; /* last seg block length seen */
  458.     if (zbufPoolId == NULL) /* alloc from system mem */
  459. if ((buf = KHEAP_ALLOC(len)) == NULL)
  460.     return (NULL);
  461.     /* if not allocating from system memory, try to obtain from seg pool */
  462.     while (buf == NULL)
  463.         {
  464. /* obtain exclusive access to zbuf segment pool structures */
  465.         if ((semTake (zbufPoolId->poolSem, timeout)) == ERROR)
  466.     return (NULL);
  467.         /*
  468.          * Search the pool's seg blocks headers for a suitable size (first fit)
  469.          * and that has free segments attached to it.  An over-sized segment
  470.  * will be taken if no more suitably sized segments are available.
  471.  * No fragmentation is performed.  A segment remains whole.
  472.  * If no segments are available (right-fit or oversized), pend on
  473.  * waitSem for segment to come in from _zbufSegPoolFree().
  474.          */
  475.         zbufBlock = zbufPoolId->blockHead;
  476.         for (; zbufBlock != NULL; zbufBlock = zbufBlock->blockNext)
  477.             if (((lenLast = zbufBlock->length) >= len) &&
  478. (zbufBlock->segFree != NULL))
  479.                 break;
  480.         if (zbufBlock == NULL)
  481.     {
  482.     /* going to pend or exit, so give up access */
  483.             semGive (zbufPoolId->poolSem);
  484.     /* check that there are seg blocks large enough for len */
  485.             if ((lenLast == NULL) || (lenLast < len))
  486. return (NULL);
  487.             /* wait for segments to come back in... */
  488.     if ((semTake (zbufPoolId->waitSem, timeout)) == ERROR)
  489.         return (NULL);
  490.     }
  491.         else /* found suitable segment */
  492.     {
  493.     buf = (caddr_t) zbufBlock->segFree; /* segment is first */
  494.     zbufBlock->segFree = *((void **) buf); /* first is next */
  495.             zbufPoolId->use++; /* check it out */
  496.             semGive (zbufPoolId->poolSem); /* give up access */
  497.     }
  498.         }
  499.     /* insert the new segment into zbufId at the specified location */
  500.     if ((zbufSeg = zbufInsertBuf (zbufId, zbufSeg, offset,
  501. buf, len, _zbufSegPoolFree, (int) zbufBlock)) == NULL)
  502. _zbufSegPoolFree (buf, zbufBlock); /* free seg on failure */
  503.     return (zbufSeg);
  504.     }
  505. #endif /* FALSE */
  506. /*******************************************************************************
  507. *
  508. * zbufCreate - create an empty zbuf
  509. *
  510. * This routine creates a zbuf, which remains empty (that is, it contains
  511. * no data) until segments are added by the zbuf insertion routines.
  512. * Operations performed on zbufs require a zbuf ID, which is returned by
  513. * this routine.
  514. *
  515. * VXWORKS AE PROTECTION DOMAINS
  516. * Under VxWorks AE, you can call this function from within the kernel 
  517. * protection domain only.  In addition, the returned ID is valid within 
  518. * the kernel protection domain only.  This restriction does not apply 
  519. * under non-AE versions of VxWorks.  
  520. *
  521. * RETURNS:
  522. * A zbuf ID, or NULL if a zbuf cannot be created.
  523. *
  524. * SEE ALSO: zbufDelete()
  525. */
  526. ZBUF_ID zbufCreate (void)
  527.     {
  528.     return ((pZbufFunc->createRtn == NULL) ? NULL :
  529. (ZBUF_ID) (pZbufFunc->createRtn) ());
  530.     }
  531. /*******************************************************************************
  532. *
  533. * zbufDelete - delete a zbuf
  534. *
  535. * This routine deletes any zbuf segments in the specified zbuf, then
  536. * deletes the zbuf ID itself.  <zbufId> must not be used after this routine
  537. * executes successfully.
  538. *
  539. * For any data buffers that were not in use by any other zbuf, zbufDelete()
  540. * calls the associated free routine (callback).
  541. *
  542. * VXWORKS AE PROTECTION DOMAINS
  543. * Under VxWorks AE, you can call this function from within the kernel 
  544. * protection domain only.  In addition, all arguments to this function can  
  545. * reference only that data which is valid in the kernel protection domain. 
  546. * This restriction does not apply under non-AE versions of VxWorks.  
  547. *
  548. * RETURNS:
  549. * OK, or ERROR if the zbuf cannot be deleted.
  550. *
  551. * SEE ALSO: zbufCreate(), zbufInsertBuf()
  552. */
  553. STATUS zbufDelete
  554.     (
  555.     ZBUF_ID zbufId /* zbuf to be deleted */
  556.     )
  557.     {
  558.     return ((pZbufFunc->deleteRtn == NULL) ? ERROR :
  559. (pZbufFunc->deleteRtn) (zbufId));
  560.     }
  561. /*******************************************************************************
  562. *
  563. * zbufInsert - insert a zbuf into another zbuf
  564. *
  565. * This routine inserts all <zbufId2> zbuf segments into <zbufId1> at the
  566. * specified byte location.
  567. *
  568. * The location of insertion is specified by <zbufSeg> and <offset>.  See
  569. * the zbufLib manual page for more information on specifying
  570. * a byte location within a zbuf.  In particular, insertion within
  571. * a zbuf occurs before the byte location specified by <zbufSeg> and <offset>.
  572. * Additionally, <zbufSeg> and <offset> must be NULL and 0,
  573. * respectively, when inserting into an empty zbuf.
  574. *
  575. * After all the <zbufId2> segments are inserted into <zbufId1>, the zbuf ID
  576. * <zbufId2> is deleted.  <zbufId2> must not be used after this routine
  577. * executes successfully.
  578. *
  579. * VXWORKS AE PROTECTION DOMAINS
  580. * Under VxWorks AE, you can call this function from within the kernel 
  581. * protection domain only.  In addition, all arguments to this function can  
  582. * reference only that data which is valid in the kernel protection domain. 
  583. * Likewise, the returned ZBUF_SEG is valid within the kernel protection 
  584. * domain only.  This restriction does not apply under non-AE versions of 
  585. * VxWorks.  
  586. *
  587. * RETURNS:
  588. * The zbuf segment ID for the first inserted segment,
  589. * or NULL if the operation fails.
  590. */
  591. ZBUF_SEG zbufInsert
  592.     (
  593.     ZBUF_ID zbufId1, /* zbuf to insert <zbufId2> into */
  594.     ZBUF_SEG zbufSeg, /* zbuf segment base for <offset> */
  595.     int offset, /* relative byte offset */
  596.     ZBUF_ID zbufId2 /* zbuf to insert into <zbufId1> */
  597.     )
  598.     {
  599.     return ((pZbufFunc->insertRtn == NULL) ? NULL :
  600.         (ZBUF_SEG) (pZbufFunc->insertRtn) (zbufId1, zbufSeg, offset, zbufId2));
  601.     }
  602. /*******************************************************************************
  603. *
  604. * zbufInsertBuf - create a zbuf segment from a buffer and insert into a zbuf
  605. *
  606. * This routine creates a zbuf segment from the application buffer <buf>
  607. * and inserts it at the specified byte location in <zbufId>.
  608. *
  609. * The location of insertion is specified by <zbufSeg> and <offset>.  See
  610. * the zbufLib manual page for more information on specifying
  611. * a byte location within a zbuf.  In particular, insertion within
  612. * a zbuf occurs before the byte location specified by <zbufSeg> and <offset>.
  613. * Additionally, <zbufSeg> and <offset> must be NULL and 0,
  614. * respectively, when inserting into an empty zbuf.
  615. *
  616. * The parameter <freeRtn> specifies a free-routine callback that runs when
  617. * the data buffer <buf> is no longer referenced by any zbuf segments.  If
  618. * <freeRtn> is NULL, the zbuf functions normally, except that the
  619. * application is not notified when no more zbufs segments reference <buf>.
  620. * The free-routine callback runs from the context of the task that last
  621. * deletes reference to the buffer.  Declare the <freeRtn> callback as
  622. * follows (using whatever routine name suits your application):
  623. * .CS
  624. * void freeCallback
  625. *     (
  626. *     caddr_t buf, /@ pointer to application buffer @/
  627. *     int freeArg /@ argument to free routine @/
  628. *     )
  629. * .CE
  630. *
  631. * VXWORKS AE PROTECTION DOMAINS
  632. * Under VxWorks AE, you can call this function from within the kernel 
  633. * protection domain only.  In addition, all arguments to this function can  
  634. * reference only that data which is valid in the kernel protection domain. 
  635. * This restriction does not apply under non-AE versions of VxWorks.  
  636. *
  637. * RETURNS:
  638. * The zbuf segment ID of the inserted segment,
  639. * or NULL if the operation fails.
  640. */
  641. ZBUF_SEG zbufInsertBuf
  642.     (
  643.     ZBUF_ID zbufId, /* zbuf in which buffer is inserted */
  644.     ZBUF_SEG zbufSeg, /* zbuf segment base for <offset> */
  645.     int offset, /* relative byte offset */
  646.     caddr_t buf, /* application buffer for segment */
  647.     int len, /* number of bytes to insert */
  648.     VOIDFUNCPTR freeRtn, /* free-routine callback */
  649.     int freeArg /* argument to free routine */
  650.     )
  651.     {
  652.     return ((pZbufFunc->insertBufRtn == NULL) ? NULL :
  653. (ZBUF_SEG) (pZbufFunc->insertBufRtn) (zbufId, zbufSeg, offset,
  654. buf, len, freeRtn, freeArg));
  655.     }
  656. /*******************************************************************************
  657. *
  658. * zbufInsertCopy - copy buffer data into a zbuf
  659. *
  660. * This routine copies <len> bytes of data from the application buffer <buf>
  661. * and inserts it at the specified byte location in <zbufId>.  The
  662. * application buffer is in no way tied to the zbuf after this operation;
  663. * a separate copy of the data is made.
  664. *
  665. * The location of insertion is specified by <zbufSeg> and <offset>.  See
  666. * the zbufLib manual page for more information on specifying
  667. * a byte location within a zbuf.  In particular, insertion within
  668. * a zbuf occurs before the byte location specified by <zbufSeg> and <offset>.
  669. * Additionally, <zbufSeg> and <offset> must be NULL and 0,
  670. * respectively, when inserting into an empty zbuf.
  671. *
  672. * VXWORKS AE PROTECTION DOMAINS
  673. * Under VxWorks AE, you can call this function from within the kernel 
  674. * protection domain only.  In addition, all arguments to this function can  
  675. * reference only that data which is valid in the kernel protection domain. 
  676. * Likewise, the returned value is valid in the protection domain only.
  677. * This restriction does not apply under non-AE versions of VxWorks.  
  678. *
  679. * RETURNS:
  680. * The zbuf segment ID of the first inserted segment,
  681. * or NULL if the operation fails.
  682. */
  683. ZBUF_SEG zbufInsertCopy
  684.     (
  685.     ZBUF_ID zbufId, /* zbuf into which data is copied */
  686.     ZBUF_SEG zbufSeg, /* zbuf segment base for <offset> */
  687.     int offset, /* relative byte offset */
  688.     caddr_t buf, /* buffer from which data is copied */
  689.     int len /* number of bytes to copy */
  690.     )
  691.     {
  692.     return ((pZbufFunc->insertCopyRtn == NULL) ? NULL :
  693.         (ZBUF_SEG) (pZbufFunc->insertCopyRtn) (zbufId, zbufSeg,
  694. offset, buf, len));
  695.     }
  696. /*******************************************************************************
  697. *
  698. * zbufExtractCopy - copy data from a zbuf to a buffer
  699. *
  700. * This routine copies <len> bytes of data from <zbufId> to the application
  701. * buffer <buf>.
  702. *
  703. * The starting location of the copy is specified by <zbufSeg> and <offset>.
  704. * See the zbufLib manual page for more information on
  705. * specifying a byte location within a zbuf.  In particular, the first
  706. * byte copied is the exact byte specified by <zbufSeg> and <offset>.
  707. *
  708. * The number of bytes to copy is given by <len>.  If this parameter
  709. * is negative, or is larger than the number of bytes in the zbuf after the
  710. * specified byte location, the rest of the zbuf is copied.
  711. * The bytes copied may span more than one segment.
  712. * VXWORKS AE PROTECTION DOMAINS
  713. * Under VxWorks AE, you can call this function from within the kernel 
  714. * protection domain only.  In addition, all arguments to this function can  
  715. * reference only that data which is valid in the kernel protection domain. 
  716. * This restriction does not apply under non-AE versions of VxWorks.  
  717. *
  718. * RETURNS:
  719. * The number of bytes copied from the zbuf to the buffer,
  720. * or ERROR if the operation fails.
  721. */
  722. int zbufExtractCopy
  723.     (
  724.     ZBUF_ID zbufId, /* zbuf from which data is copied */
  725.     ZBUF_SEG zbufSeg, /* zbuf segment base for <offset> */
  726.     int offset, /* relative byte offset */
  727.     caddr_t buf, /* buffer into which data is copied */
  728.     int len /* number of bytes to copy */
  729.     )
  730.     {
  731.     return ((pZbufFunc->extractCopyRtn == NULL) ? ERROR :
  732.         (pZbufFunc->extractCopyRtn) (zbufId, zbufSeg, offset, buf, len));
  733.     }
  734. /*******************************************************************************
  735. *
  736. * zbufCut - delete bytes from a zbuf
  737. *
  738. * This routine deletes <len> bytes from <zbufId> starting at the specified
  739. * byte location.
  740. *
  741. * The starting location of deletion is specified by <zbufSeg> and <offset>.
  742. * See the zbufLib manual page for more information on
  743. * specifying a byte location within a zbuf.  In particular, the first
  744. * byte deleted is the exact byte specified by <zbufSeg> and <offset>.
  745. *
  746. * The number of bytes to delete is given by <len>.  If this parameter
  747. * is negative, or is larger than the number of bytes in the zbuf after the
  748. * specified byte location, the rest of the zbuf is deleted.
  749. * The bytes deleted may span more than one segment.
  750. *
  751. * If all the bytes in any one segment are deleted, then the segment is
  752. * deleted, and the data buffer that it referenced will be freed if no
  753. * other zbuf segments reference it.  No segment may survive with zero bytes
  754. * referenced.
  755. * Deleting bytes out of the middle of a segment splits the segment
  756. * into two.  The first segment contains the portion of the data buffer
  757. * before the deleted bytes, while the other segment contains the end
  758. * portion that remains after deleting <len> bytes.
  759. *
  760. * This routine returns the zbuf segment ID of the segment just
  761. * after the deleted bytes.  In the case where bytes are cut off the end
  762. * of a zbuf, a value of ZBUF_NONE is returned.
  763. *
  764. * VXWORKS AE PROTECTION DOMAINS
  765. * Under VxWorks AE, you can call this function from within the kernel 
  766. * protection domain only.  In addition, all arguments to this function can  
  767. * reference only that data which is valid in the kernel protection domain. 
  768. * Likewise, the returned value is valid in the protection domain only.
  769. * This restriction does not apply under non-AE versions of VxWorks.  
  770. *
  771. * RETURNS:
  772. * The zbuf segment ID of the segment following the deleted bytes,
  773. * or NULL if the operation fails.
  774. */
  775. ZBUF_SEG zbufCut
  776.     (
  777.     ZBUF_ID zbufId, /* zbuf from which bytes are cut */
  778.     ZBUF_SEG zbufSeg, /* zbuf segment base for <offset> */
  779.     int offset, /* relative byte offset */
  780.     int len /* number of bytes to cut */
  781.     )
  782.     {
  783.     return ((pZbufFunc->cutRtn == NULL) ? NULL :
  784. (ZBUF_SEG) (pZbufFunc->cutRtn) (zbufId, zbufSeg, offset, len));
  785.     }
  786. /*******************************************************************************
  787. *
  788. * zbufSplit - split a zbuf into two separate zbufs
  789. *
  790. * This routine splits <zbufId> into two separate zbufs at the specified
  791. * byte location.  The first portion remains in <zbufId>, while the end
  792. * portion is returned in a newly created zbuf.
  793. *
  794. * The location of the split is specified by <zbufSeg> and <offset>.  See
  795. * the zbufLib manual page for more information on specifying
  796. * a byte location within a zbuf.  In particular, after the split
  797. * operation, the first byte of the returned zbuf is the exact byte
  798. * specified by <zbufSeg> and <offset>.
  799. *
  800. * VXWORKS AE PROTECTION DOMAINS
  801. * Under VxWorks AE, you can call this function from within the kernel 
  802. * protection domain only.  In addition, all arguments to this function can  
  803. * reference only that data which is valid in the kernel protection domain. 
  804. * Likewise, the returned value is valid in the protection domain only.
  805. * This restriction does not apply under non-AE versions of VxWorks.  
  806. *
  807. * RETURNS:
  808. * The zbuf ID of a newly created zbuf containing the end portion of <zbufId>,
  809. * or NULL if the operation fails.
  810. */
  811. ZBUF_ID zbufSplit
  812.     (
  813.     ZBUF_ID zbufId, /* zbuf to split into two */
  814.     ZBUF_SEG zbufSeg, /* zbuf segment base for <offset> */
  815.     int offset /* relative byte offset */
  816.     )
  817.     {
  818.     return ((pZbufFunc->splitRtn == NULL) ? NULL :
  819. (ZBUF_ID) (pZbufFunc->splitRtn) (zbufId, zbufSeg, offset));
  820.     }
  821. /*******************************************************************************
  822. *
  823. * zbufDup - duplicate a zbuf
  824. *
  825. * This routine duplicates <len> bytes of <zbufId> starting at the specified
  826. * byte location, and returns the zbuf ID of the newly created duplicate zbuf. 
  827. *
  828. * The starting location of duplication is specified by <zbufSeg> and <offset>.
  829. * See the zbufLib manual page for more information on
  830. * specifying a byte location within a zbuf.  In particular, the first
  831. * byte duplicated is the exact byte specified by <zbufSeg> and <offset>.
  832. *
  833. * The number of bytes to duplicate is given by <len>.  If this parameter
  834. * is negative, or is larger than the number of bytes in the zbuf after the
  835. * specified byte location, the rest of the zbuf is duplicated.
  836. * Duplication of zbuf data does not usually involve copying of the data.
  837. * Instead, the zbuf segment pointer information is duplicated, while the data
  838. * is not, which means that the data is shared among all zbuf segments
  839. * that reference the data.  See the zbufLib manual
  840. * page for more information on copying and sharing zbuf data.
  841. *
  842. * RETURNS:
  843. * The zbuf ID of a newly created duplicate zbuf,
  844. * or NULL if the operation fails.
  845. */
  846. ZBUF_ID zbufDup
  847.     (
  848.     ZBUF_ID zbufId, /* zbuf to duplicate */
  849.     ZBUF_SEG zbufSeg, /* zbuf segment base for <offset> */
  850.     int offset, /* relative byte offset */
  851.     int len /* number of bytes to duplicate */
  852.     )
  853.     {
  854.     return ((pZbufFunc->dupRtn == NULL) ? NULL :
  855. (ZBUF_ID) (pZbufFunc->dupRtn) (zbufId, zbufSeg, offset, len));
  856.     }
  857. /*******************************************************************************
  858. *
  859. * zbufLength - determine the length in bytes of a zbuf
  860. *
  861. * This routine returns the number of bytes in the zbuf <zbufId>.
  862. *
  863. * VXWORKS AE PROTECTION DOMAINS
  864. * Under VxWorks AE, you can call this function from within the kernel 
  865. * protection domain only.  In addition, all arguments to this function can  
  866. * reference only that data which is valid in the kernel protection domain. 
  867. * This restriction does not apply under non-AE versions of VxWorks.  
  868. *
  869. * RETURNS:
  870. * The number of bytes in the zbuf,
  871. * or ERROR if the operation fails.
  872. */
  873. int zbufLength
  874.     (
  875.     ZBUF_ID zbufId /* zbuf to determine length */
  876.     )
  877.     {
  878.     return ((pZbufFunc->lengthRtn == NULL) ? ERROR :
  879. (pZbufFunc->lengthRtn) (zbufId));
  880.     }
  881. /*******************************************************************************
  882. *
  883. * zbufSegFind - find the zbuf segment containing a specified byte location
  884. *
  885. * This routine translates an address within a zbuf to its most local
  886. * formulation.  zbufSegFind() locates the zbuf segment in <zbufId>
  887. * that contains the byte location specified by <zbufSeg> and *<pOffset>,
  888. * then returns that zbuf segment, and writes in *<pOffset> the new offset
  889. * relative to the returned segment.
  890. *
  891. * If the <zbufSeg>, *<pOffset> pair specify a byte location past the end
  892. * of the zbuf, or before the first byte in the zbuf, zbufSegFind()
  893. * returns NULL.
  894. *
  895. * See the zbufLib manual page for a full discussion of addressing zbufs
  896. * by segment and offset.
  897. *
  898. * VXWORKS AE PROTECTION DOMAINS
  899. * Under VxWorks AE, you can call this function from within the kernel 
  900. * protection domain only.  In addition, all arguments to this function can  
  901. * reference only that data which is valid in the kernel protection domain. 
  902. * Likewise, the returned value is valid in the protection domain only.
  903. * This restriction does not apply under non-AE versions of VxWorks.  
  904. *
  905. * RETURNS:
  906. * The zbuf segment ID of the segment containing the specified byte,
  907. * or NULL if the operation fails.
  908. */
  909. ZBUF_SEG zbufSegFind
  910.     (
  911.     ZBUF_ID zbufId, /* zbuf to examine */
  912.     ZBUF_SEG zbufSeg, /* zbuf segment base for <pOffset> */
  913.     int * pOffset /* relative byte offset */
  914.     )
  915.     {
  916.     return ((pZbufFunc->segFindRtn == NULL) ? NULL :
  917. (ZBUF_SEG) (pZbufFunc->segFindRtn) (zbufId, zbufSeg, pOffset));
  918.     }
  919. /*******************************************************************************
  920. *
  921. * zbufSegNext - get the next segment in a zbuf
  922. *
  923. * This routine finds the zbuf segment in <zbufId> that is just after
  924. * the zbuf segment <zbufSeg>.  If <zbufSeg> is NULL, the segment after
  925. * the first segment in <zbufId> is returned.  If <zbufSeg> is the last
  926. * segment in <zbufId>, NULL is returned.
  927. *
  928. * RETURNS:
  929. * The zbuf segment ID of the segment after <zbufSeg>,
  930. * or NULL if the operation fails.
  931. */
  932. ZBUF_SEG zbufSegNext
  933.     (
  934.     ZBUF_ID zbufId, /* zbuf to examine */
  935.     ZBUF_SEG zbufSeg /* segment to get next segment */
  936.     )
  937.     {
  938.     return ((pZbufFunc->segNextRtn == NULL) ? NULL :
  939.         (ZBUF_SEG) (pZbufFunc->segNextRtn) (zbufId, zbufSeg));
  940.     }
  941. /*******************************************************************************
  942. *
  943. * zbufSegPrev - get the previous segment in a zbuf
  944. *
  945. * This routine finds the zbuf segment in <zbufId> that is just before the zbuf 
  946. * segment <zbufSeg>. If <zbufSeg> is NULL, or is the first segment in <zbufId>,
  947. * NULL is returned.
  948. *
  949. * VXWORKS AE PROTECTION DOMAINS
  950. * Under VxWorks AE, you can call this function from within the kernel 
  951. * protection domain only.  In addition, all arguments to this function can  
  952. * reference only that data which is valid in the kernel protection domain. 
  953. * Likewise, the returned value is valid in the protection domain only.
  954. * This restriction does not apply under non-AE versions of VxWorks.  
  955. *
  956. * RETURNS:
  957. * The zbuf segment ID of the segment before <zbufSeg>, or NULL if the 
  958. * operation fails.
  959. */
  960. ZBUF_SEG zbufSegPrev
  961.     (
  962.     ZBUF_ID zbufId, /* zbuf to examine */
  963.     ZBUF_SEG zbufSeg /* segment to get previous segment */
  964.     )
  965.     {
  966.     return ((pZbufFunc->segPrevRtn == NULL) ? NULL :
  967.         (ZBUF_SEG) (pZbufFunc->segPrevRtn) (zbufId, zbufSeg));
  968.     }
  969. /*******************************************************************************
  970. *
  971. * zbufSegData - determine the location of data in a zbuf segment
  972. *
  973. * This routine returns the location of the first byte of data in the zbuf
  974. * segment <zbufSeg>.  If <zbufSeg> is NULL, the location of data in the
  975. * first segment in <zbufId> is returned.
  976. * VXWORKS AE PROTECTION DOMAINS
  977. * Under VxWorks AE, you can call this function from within the kernel 
  978. * protection domain only.  In addition, all arguments to this function can  
  979. * reference only that data which is valid in the kernel protection domain. 
  980. * Likewise, the returned value is valid in the protection domain only.
  981. * This restriction does not apply under non-AE versions of VxWorks.  
  982. *
  983. * RETURNS:
  984. * A pointer to the first byte of data in the specified zbuf segment,
  985. * or NULL if the operation fails.
  986. *
  987. */
  988. caddr_t zbufSegData
  989.     (
  990.     ZBUF_ID zbufId, /* zbuf to examine */
  991.     ZBUF_SEG zbufSeg /* segment to get pointer to data */
  992.     )
  993.     {
  994.     return ((pZbufFunc->segDataRtn == NULL) ? NULL :
  995. (caddr_t) (pZbufFunc->segDataRtn) (zbufId, zbufSeg));
  996.     }
  997. /*******************************************************************************
  998. *
  999. * zbufSegLength - determine the length of a zbuf segment
  1000. *
  1001. * This routine returns the number of bytes in the zbuf segment <zbufSeg>.
  1002. * If <zbufSeg> is NULL, the length of the first segment in <zbufId> is
  1003. * returned.
  1004. *
  1005. * VXWORKS AE PROTECTION DOMAINS
  1006. * Under VxWorks AE, you can call this function from within the kernel 
  1007. * protection domain only.  In addition, all arguments to this function can  
  1008. * reference only that data which is valid in the kernel protection domain. 
  1009. * This restriction does not apply under non-AE versions of VxWorks.  
  1010. *
  1011. * RETURNS:
  1012. * The number of bytes in the specified zbuf segment,
  1013. * or ERROR if the operation fails.
  1014. */
  1015. int zbufSegLength
  1016.     (
  1017.     ZBUF_ID zbufId, /* zbuf to examine */
  1018.     ZBUF_SEG zbufSeg /* segment to determine length of */
  1019.     )
  1020.     {
  1021.     return ((pZbufFunc->segLengthRtn == NULL) ? ERROR :
  1022. (pZbufFunc->segLengthRtn) (zbufId, zbufSeg));
  1023.     }