summaryrefslogtreecommitdiffstats
path: root/lib/vio_fifo.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/vio_fifo.c')
-rw-r--r--lib/vio_fifo.c761
1 files changed, 677 insertions, 84 deletions
diff --git a/lib/vio_fifo.c b/lib/vio_fifo.c
index fb62f192..685f33ec 100644
--- a/lib/vio_fifo.c
+++ b/lib/vio_fifo.c
@@ -23,6 +23,7 @@
#include <string.h>
#include "vio_fifo.h"
+#include "network.h"
#include "list_util.h"
#include "memory.h"
@@ -37,6 +38,9 @@
* The last lump is never released. So, it may be that only one lump is
* ever needed.
*
+ * When releasing lumps, keeps one lump "spare", to be reused as necessary.
+ * This is used in ... TODO <<<< And is released...
+ *
*------------------------------------------------------------------------------
* Implementation notes:
*
@@ -114,13 +118,18 @@ vio_fifo_init_new(vio_fifo vf, size_t size)
/* Zeroising the the vio_fifo_t has set:
*
- * lump -- base pair, both pointers NULL => list is empty
+ * lump -- base pair, both pointers NULL => list is empty
+ *
+ * put_ptr -- NULL ) no lump to put anything into
+ * put_end -- NULL ) put_ptr == put_end => no room in current lump
+ *
+ * get_ptr -- NULL ) no lump to get anything from
+ * get_end -- NULL ) get_ptr -- get_end => nothing left in current lump
*
- * put_ptr -- NULL ) no lump to put anything into
- * put_end -- NULL ) put_ptr == put_end => no room in current lump
+ * rdr_lump -- NULL ) no rdr_lump
+ * rdr_ptr -- NULL
*
- * get_ptr -- NULL ) no lump to get anything from
- * get_end -- NULL ) get_ptr -- get_end => nothing left in current lump
+ * spare -- NULL no spare lump
*
* ALSO put_ptr == get_ptr => FIFO is empty !
*/
@@ -139,6 +148,8 @@ vio_fifo_init_new(vio_fifo vf, size_t size)
*
* If does not free the FIFO structure, resets it all empty.
*
+ * Frees *all* FIFO lumps.
+ *
* See also: vio_fifo_reset_keep(vio_fifo)
* vio_fifo_reset_free(vio_fifo)
*/
@@ -153,6 +164,9 @@ vio_fifo_reset(vio_fifo vf, int free_structure)
while (ddl_pop(&lump, vf->base, list) != NULL)
XFREE(MTYPE_VIO_FIFO_LUMP, lump) ;
+ if (vf->spare != NULL)
+ XFREE(MTYPE_VIO_FIFO_LUMP, vf->spare) ;
+
if (free_structure)
XFREE(MTYPE_VIO_FIFO, vf) ; /* sets vf = NULL */
else
@@ -162,33 +176,105 @@ vio_fifo_reset(vio_fifo vf, int free_structure)
} ;
/*------------------------------------------------------------------------------
- * Set FIFO empty, discarding current contents -- will continue to use the FIFO.
+ * The FIFO is empty, with one lump -- reset all pointers.
+ */
+inline static void
+vio_fifo_ptr_reset(vio_fifo vf, vio_fifo_lump lump)
+{
+ if (vf->rdr_lump != NULL)
+ {
+ assert((lump == vf->rdr_lump) && (vf->rdr_ptr == vf->get_ptr)) ;
+ vf->rdr_ptr = lump->data ;
+ } ;
+
+ /* Note that sets the lump->end to the true lump->end */
+ vf->get_ptr = vf->get_end = vf->put_ptr = lump->data ;
+ vf->put_end = lump->end = lump->data + lump->size ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * The FIFO is utterly empty, with ZERO lumps -- unset all pointers.
+ */
+inline static void
+vio_fifo_ptr_unset(vio_fifo vf)
+{
+ assert((ddl_head(vf->base) == NULL) && (ddl_tail(vf->base) == NULL)) ;
+
+ vf->one = false ;
+
+ vf->put_ptr = NULL ;
+ vf->put_end = NULL ;
+ vf->get_ptr = NULL ;
+ vf->get_end = NULL ;
+
+ vf->rdr_lump = NULL ;
+ vf->rdr_ptr = NULL ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Clear out contents of FIFO -- will continue to use the FIFO.
+ *
+ * Keeps one FIFO lump. (Frees everything else, including any spare.)
*/
extern void
-vio_fifo_set_empty(vio_fifo vf)
+vio_fifo_clear(vio_fifo vf)
{
- vio_fifo_lump lump ;
+ vio_fifo_lump tail ;
+
+ VIO_FIFO_DEBUG_VERIFY(vf) ;
assert(vf != NULL) ;
- while (ddl_head(vf->base) != ddl_tail(vf->base))
- {
- ddl_pop(&lump, vf->base, list) ;
- XFREE(MTYPE_VIO_FIFO_LUMP, lump) ;
- } ;
+ tail = ddl_tail(vf->base) ;
- lump = ddl_head(vf->base) ;
- if (lump != NULL)
+ if (tail != NULL)
{
- vf->get_ptr = vf->get_end = vf->put_ptr = lump->data ;
- vf->put_end = lump->end ;
- } ;
+ while (ddl_head(vf->base) != tail)
+ {
+ vio_fifo_lump lump ;
+ ddl_pop(&lump, vf->base, list) ;
+ XFREE(MTYPE_VIO_FIFO_LUMP, lump) ;
+ } ;
+
+ vf->rdr_lump = NULL ; /* clear rdr */
+ vf->rdr_ptr = NULL ;
+
+ vf->one = true ;
+ vio_fifo_ptr_reset(vf, tail) ;
+ }
+ else
+ vio_fifo_ptr_unset(vf) ;
+
+ if (vf->spare != NULL)
+ XFREE(MTYPE_VIO_FIFO_LUMP, vf->spare) ; /* sets vf->spare = NULL */
+
+ VIO_FIFO_DEBUG_VERIFY(vf) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * See how much room there is in the FIFO.
+ *
+ * If no lumps have been allocated, returns the size of the lump that would
+ * allocate.
+ *
+ * Otherwise, returns the amount of space available *without* allocating any
+ * further lumps.
+ *
+ * Returns: room available as described
+ */
+extern size_t
+vio_fifo_room(vio_fifo vf)
+{
+ if (vf->put_ptr != NULL)
+ return vf->put_end - vf->put_ptr ;
+ else
+ return vf->size ;
} ;
/*------------------------------------------------------------------------------
* Allocate another lump for putting into.
*
- * Call when (vf->put_ptr >= vf->put_end) -- asserts that the pointers are equal.
+ * Call when (vf->put_ptr >= vf->put_end) -- asserts that they are equal.
*
* Set the put_ptr/put_end pointers to point at the new lump.
*
@@ -198,23 +284,19 @@ vio_fifo_set_empty(vio_fifo vf)
* to reflect the fact that the out lump is now full.
*/
extern void
-vio_fifo_lump_new(vio_fifo vf)
+vio_fifo_lump_new(vio_fifo vf, size_t size)
{
vio_fifo_lump lump ;
- size_t size ;
int first_alloc ;
VIO_FIFO_DEBUG_VERIFY(vf) ;
passert(vf->put_ptr == vf->put_end) ; /* must be end of tail lump */
- lump = ddl_tail(vf->base) ;
-
- /* When there is only one lump, the get_end tracks the put_ptr.
- * But when there is more than one lump, it must be the end of that lump.
- */
if (vf->one)
- vf->get_end = lump->end ;
+ vf->get_end = vf->put_ptr ; /* update get_end */
+
+ lump = ddl_tail(vf->base) ;
first_alloc = (lump == NULL) ; /* extra initialisation needed */
@@ -223,9 +305,21 @@ vio_fifo_lump_new(vio_fifo vf)
else
assert(vf->put_ptr == lump->end) ; /* must be end of tail lump */
- size = vio_fifo_size(vf->size) ;
- lump = XMALLOC(MTYPE_VIO_FIFO_LUMP, offsetof(vio_fifo_lump_t, data[size])) ;
- lump->end = (char*)lump->data + vf->size ;
+ size = vio_fifo_size(size) ;
+
+ if ((vf->spare != NULL) && (vf->spare->size >= size))
+ {
+ lump = vf->spare ;
+ vf->spare = NULL ;
+ }
+ else
+ {
+ lump = XMALLOC(MTYPE_VIO_FIFO_LUMP,
+ offsetof(vio_fifo_lump_t, data[size])) ;
+ lump->size = size ;
+ } ;
+
+ lump->end = lump->data + lump->size ;
ddl_append(vf->base, lump, list) ;
@@ -243,6 +337,207 @@ vio_fifo_lump_new(vio_fifo vf)
VIO_FIFO_DEBUG_VERIFY(vf) ;
} ;
+/*------------------------------------------------------------------------------
+ * Release lump, head or tail (or both) and update pointers.
+ *
+ * Note that this does release the lump if it is the only lump.
+ *
+ * Do nothing if nothing is yet allocated.
+ *
+ * If releasing the only lump in the FIFO, resets all pointers to NULL.
+ *
+ * If releasing the head lump:
+ *
+ * * the lump MUST be finished with -- so vf->get_ptr must be at the end
+ *
+ * If releasing the only lump, the FIFO MUST be empty.
+ *
+ * * if the lump is the current vf->rdr_lump, the reader must be at the
+ * end too -- ie it must be the same as the vf->get_ptr !
+ *
+ * If releasing the tail lump:
+ *
+ * * the lump MUST be empty
+ *
+ * If releasing the only lump, the FIFO MUST be empty.
+ *
+ * * if the lump is the current vf->rdr_lump, the reader must be at the
+ * end too -- ie it must be the same as the vf->get_ptr !
+ */
+static void
+vio_fifo_lump_release(vio_fifo vf, vio_fifo_lump lump)
+{
+ vio_fifo_lump head ;
+ vio_fifo_lump tail ;
+ vio_fifo_lump free ;
+ bool release_head ;
+ bool release_tail ;
+
+ VIO_FIFO_DEBUG_VERIFY(vf) ;
+
+ /* Prepare and check whether removing head or tail (or both) */
+ head = ddl_head(vf->base) ;
+ tail = ddl_tail(vf->base) ;
+
+ release_head = (lump == head) ;
+ release_tail = (lump == tail) ;
+
+ assert(release_head || release_tail) ;
+
+ /* Unless nothing ever allocated -- release the lump. */
+ free = lump ; /* expect to free the lump */
+ if (lump != NULL)
+ {
+ vio_fifo_lump keep ;
+
+ /* Consistency checks */
+ if (release_head)
+ {
+ if (release_tail)
+ assert(vf->get_ptr == vf->put_ptr) ;
+ else
+ assert(vf->get_ptr == lump->end) ;
+
+ if (vf->rdr_lump == lump)
+ assert(vf->rdr_ptr == vf->get_ptr) ;
+ }
+ else if (release_tail)
+ {
+ assert(vf->put_ptr == lump->data) ;
+
+ if (vf->rdr_lump == lump)
+ assert(vf->rdr_ptr == vf->put_ptr) ;
+ } ;
+
+ /* Remove lump from FIFO and decide whether to keep as spare, or
+ * which of spare and this to free.
+ */
+ ddl_del(vf->base, lump, list) ;
+
+ keep = vf->spare ; /* expect to keep current spare */
+
+ if ((keep == NULL) || (keep->size < lump->size))
+ {
+ keep = lump ;
+ free = vf->spare ;
+ } ;
+
+ vf->spare = keep ;
+
+ head = ddl_head(vf->base) ; /* changed if released head */
+ tail = ddl_tail(vf->base) ; /* changed if released tail */
+ } ;
+
+ /* Now update pointers... depending on what was released and what have
+ * left.
+ */
+ if (head == NULL)
+ {
+ /* Deal with FIFO that now has no lumps or had none to start with */
+ if (lump != NULL)
+ assert(vf->one) ;
+
+ vio_fifo_ptr_unset(vf) ;
+ }
+ else
+ {
+ /* Have at least one lump left -- so must have had at least two ! */
+ assert(!vf->one) ;
+
+ vf->one = (head == tail) ; /* update */
+
+ if (release_head)
+ {
+ /* Released the head.
+ *
+ * Update the vf->get_ptr and the vf->get_end.
+ */
+ vf->get_ptr = head->data ;
+ if (vf->one)
+ vf->get_end = vf->put_ptr ;
+ else
+ vf->get_end = head->end ;
+
+ /* Update vf->rdr_ptr and vf->rdr_lump. */
+ if (vf->rdr_lump == lump)
+ {
+ vf->rdr_lump = head ;
+ vf->rdr_ptr = head->data ;
+ } ;
+ }
+ else
+ {
+ /* Released the tail.
+ * Update the vf->put_ptr and vf->put_end
+ */
+ vf->put_ptr = vf->put_end = tail->end ;
+
+ /* Update vf->rdr_ptr and vf->rdr_lump. */
+ if (vf->rdr_lump == lump)
+ {
+ vf->rdr_lump = tail ;
+ vf->rdr_ptr = tail->end ;
+ } ;
+ } ;
+ } ;
+
+ /* Finally, free any lump that is actually to be freed */
+
+ if (free != NULL)
+ XFREE(MTYPE_VIO_FIFO_LUMP, free) ;
+
+ VIO_FIFO_DEBUG_VERIFY(vf) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Re-allocate lump for putting into.
+ *
+ * Call when vf->put_ptr == start of last lump, and that lump is not big
+ * enough !
+ *
+ * There must be at least one lump.
+ *
+ * Updates put_ptr/put_end pointers to point at the new lump.
+ *
+ * Updates get_ptr/get_end pointers if required.
+ *
+ * Updates rdr_ptr if required.
+ */
+static void
+vio_fifo_lump_renew(vio_fifo vf, vio_fifo_lump lump, size_t size)
+{
+ bool rdr_set ;
+
+ VIO_FIFO_DEBUG_VERIFY(vf) ;
+
+ /* FIFO may not be completely empty.
+ * This must be the last lump.
+ * The last lump must be empty.
+ */
+ assert((lump != NULL) && (lump == ddl_tail(vf->base))) ;
+
+ /* Remove the last, *empty* lump, and update all pointers to suit. */
+ rdr_set = (vf->rdr_lump == lump) ;
+
+ vio_fifo_lump_release(vf, lump) ;
+
+ /* Now allocate a new lump with the required size */
+ vio_fifo_lump_new(vf, size) ;
+
+ /* Restore the rdr_ptr, if required */
+ if (rdr_set)
+ {
+ vio_fifo_lump tail ;
+
+ tail = ddl_tail(vf->base) ;
+
+ vf->rdr_lump = tail ;
+ vf->rdr_ptr = tail->data ;
+ } ;
+
+ VIO_FIFO_DEBUG_VERIFY(vf) ;
+} ;
+
/*==============================================================================
* Put data to the FIFO.
*/
@@ -260,7 +555,7 @@ vio_fifo_put(vio_fifo vf, const char* src, size_t n)
while (n > 0)
{
if (vf->put_ptr >= vf->put_end)
- vio_fifo_lump_new(vf) ; /* traps broken vf->put_ptr > vf->put_end */
+ vio_fifo_lump_new(vf, vf->size) ; /* traps put_ptr > put_end */
take = (vf->put_end - vf->put_ptr) ;
if (take > n)
@@ -276,6 +571,103 @@ vio_fifo_put(vio_fifo vf, const char* src, size_t n)
VIO_FIFO_DEBUG_VERIFY(vf) ;
} ;
+/*------------------------------------------------------------------------------
+ * Formatted print to fifo -- cf printf()
+ *
+ * Returns: >= 0 -- number of bytes written
+ * < 0 -- failed (unlikely though that is)
+ */
+extern int
+vio_fifo_printf(vio_fifo vf, const char* format, ...)
+{
+ va_list args;
+ int len ;
+
+ va_start (args, format);
+ len = vio_fifo_vprintf(vf, format, args);
+ va_end (args);
+
+ return len;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Formatted print to fifo -- cf vprintf()
+ *
+ * Returns: >= 0 -- number of bytes written
+ * < 0 -- failed (unlikely though that is)
+ */
+extern int
+vio_fifo_vprintf(vio_fifo vf, const char *format, va_list args)
+{
+ va_list ac ;
+ int len ;
+ int have ;
+ size_t size ;
+ vio_fifo_lump lump ;
+
+ VIO_FIFO_DEBUG_VERIFY(vf) ;
+
+ size = vf->size ; /* standard allocation size */
+ while (1)
+ {
+ /* Find what space is left in the tail lump, and allocate a new,
+ * empty lump if required.
+ */
+ if (vf->put_ptr >= vf->put_end)
+ vio_fifo_lump_new(vf, size) ; /* traps put_ptr > put_end */
+
+ have = vf->put_end - vf->put_ptr ;
+ assert(have > 0) ;
+
+ /* Note that vsnprintf() returns the length of what it would like to
+ * have produced, if it had the space. That length does not include
+ * the trailing '\0'.
+ */
+ va_copy(ac, args) ;
+ len = vsnprintf(vf->put_ptr, have, format, ac) ;
+ va_end(ac) ;
+
+ if (len < have)
+ {
+ if (len < 0)
+ break ; /* quit if failed */
+
+ vf->put_ptr += len ;
+ break ; /* done */
+ } ;
+
+ /* Not able to complete the operation in the current buffer.
+ *
+ * If the required space (len + 1) is greater than the standard
+ * allocation, then need to increase the allocation for the next lump.
+ *
+ * If the current lump is empty, need to renew it with a fresh lump of
+ * the now known required size.
+ *
+ * If the current lump is not empty, need to cut the end off and then
+ * allocate a fresh lump (of the standard or now known required size).
+ */
+ if (len >= (int)size)
+ size = len + 1 ; /* need a non-standard size */
+
+ lump = ddl_tail(vf->base) ;
+
+ if (vf->put_ptr == lump->data)
+ /* Need to replace the last, empty, lump with another empty lump, but
+ * big enough.
+ */
+ vio_fifo_lump_renew(vf, lump, size) ;
+ else
+ /* Need to cut this lump short, and allocate new lump at top of loop.
+ */
+ lump->end = vf->put_end = vf->put_ptr ;
+ } ;
+
+ VIO_FIFO_DEBUG_VERIFY(vf) ;
+
+ return len ;
+} ;
+
/*==============================================================================
* Get data from the FIFO.
*/
@@ -293,6 +685,8 @@ static bool vio_fifo_get_next_lump(vio_fifo vf) ;
static inline bool
vio_fifo_get_ready(vio_fifo vf)
{
+ assert(vf->rdr_lump == NULL) ;
+
if (vf->one)
vf->get_end = vf->put_ptr ; /* make sure have everything */
@@ -380,8 +774,8 @@ vio_fifo_get_next_byte(vio_fifo vf)
/*------------------------------------------------------------------------------
* Get pointer to a lump of bytes.
*
- * Returns: address of next byte to get, *have = number of bytes available
- * or: NULL => FIFO is empty, *have = 0
+ * Returns: address of next byte to get, *p_have = number of bytes available
+ * or: NULL => FIFO is empty, *p_have = 0
*
* If the FIFO is not empty, will return pointer to at least one byte.
*
@@ -389,15 +783,15 @@ vio_fifo_get_next_byte(vio_fifo vf)
* further lumps beyond the current one.
*/
extern void*
-vio_fifo_get_lump(vio_fifo vf, size_t* have)
+vio_fifo_get_lump(vio_fifo vf, size_t* p_have)
{
if (!vio_fifo_get_ready(vf))
{
- *have = 0 ;
+ *p_have = 0 ;
return NULL ;
} ;
- *have = (vf->get_end - vf->get_ptr) ;
+ *p_have = (vf->get_end - vf->get_ptr) ;
return vf->get_ptr ;
} ;
@@ -422,6 +816,195 @@ vio_fifo_got_upto(vio_fifo vf, void* here)
} ;
/*------------------------------------------------------------------------------
+ * Write contents of FIFO -- assuming non-blocking file
+ *
+ * Will write all of FIFO, or upto but excluding the last lump.
+ *
+ * Returns: > 0 => blocked
+ * 0 => all gone (up to last lump if !all)
+ * < 0 => failed -- see errno
+ *
+ * Note: will work perfectly well for a non-blocking file -- which should
+ * never return EAGAIN/EWOULDBLOCK, so will return from here "all gone".
+ */
+extern int
+vio_fifo_write_nb(vio_fifo vf, int fd, bool all)
+{
+ char* src ;
+ size_t have ;
+ int done ;
+
+ while ((src = vio_fifo_get_lump(vf, &have)) != NULL)
+ {
+ if (!all && vf->one)
+ break ; /* don't write last lump */
+
+ done = write_nb(fd, src, have) ;
+
+ if (done < 0)
+ return -1 ; /* failed */
+
+ vio_fifo_got_upto(vf, src + done) ;
+
+ if (done < (int)have)
+ return 1 ; /* blocked */
+ } ;
+
+ return 0 ; /* all gone */
+} ;
+
+/*------------------------------------------------------------------------------
+ * Get the current rdr_end value.
+ *
+ * Unlike get_end, do not have a field for this, but find it each time.
+ */
+inline static char*
+vio_fifo_rdr_end(vio_fifo vf)
+{
+ if (vf->rdr_lump == ddl_tail(vf->base))
+ return vf->put_ptr ;
+ else
+ return vf->rdr_lump->end ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Get the current rdr position -- sets it up if not currently set.
+ *
+ * Returns: address of next byte to get, *p_have = number of bytes available
+ * or: NULL => FIFO is empty, *p_have = 0
+ *
+ * If the FIFO is not empty, will return pointer to at least one byte.
+ *
+ * Returns number of bytes to the end of the current lump. There may be
+ * further lumps beyond the current one.
+ *
+ * NB: unless returns FIFO is empty, it is a mistake to now do any "get"
+ * operation other than vio_fifo_step_rdr(), until do vio_fifo_sync_rdr()
+ * or vio_fifo_drop_rdr.
+ */
+extern void*
+vio_fifo_get_rdr(vio_fifo vf, size_t* p_have)
+{
+ if (!vio_fifo_get_ready(vf))
+ {
+ *p_have = 0 ;
+ return NULL ;
+ } ;
+
+ if (vf->rdr_lump == NULL) /* set up new rdr if required */
+ {
+ vf->rdr_lump = ddl_head(vf->base) ;
+ vf->rdr_ptr = vf->get_ptr ;
+ } ;
+
+ VIO_FIFO_DEBUG_VERIFY(vf) ;
+
+ *p_have = vio_fifo_rdr_end(vf) - vf->rdr_ptr ;
+ return vf->rdr_ptr ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Step the rdr forward by the given number of bytes.
+ *
+ * Returns: address of next byte to get, *p_have = number of bytes available
+ * or: NULL => FIFO is empty, *p_have = 0
+ *
+ * If the FIFO is not empty, will return pointer to at least one byte.
+ *
+ * Returns number of bytes to the end of the current lump. There may be
+ * further lumps beyond the current one.
+ *
+ * NB: this does not change the get pointers, so all the data being stepped
+ * over is preserved in the FIFO, until vio_fifo_sync_rdr().
+ *
+ * NB: the step may NOT exceed the last reported "have".
+ */
+extern void*
+vio_fifo_step_rdr(vio_fifo vf, size_t* p_have, size_t step)
+{
+ char* rdr_end ;
+
+ assert(vf->rdr_lump != NULL) ;
+
+ VIO_FIFO_DEBUG_VERIFY(vf) ;
+
+ rdr_end = vio_fifo_rdr_end(vf) ;
+ vf->rdr_ptr += step ;
+
+ if (vf->rdr_ptr >= rdr_end)
+ {
+ assert(vf->rdr_ptr == rdr_end) ;
+
+ if (vf->rdr_lump != ddl_tail(vf->base))
+ {
+ vf->rdr_lump = ddl_next(vf->rdr_lump, list) ;
+ vf->rdr_ptr = vf->rdr_lump->data ;
+
+ rdr_end = vio_fifo_rdr_end(vf) ;
+ } ;
+ } ;
+
+ VIO_FIFO_DEBUG_VERIFY(vf) ;
+
+ *p_have = (rdr_end - vf->rdr_ptr) ;
+ return (*p_have > 0) ? vf->rdr_ptr : NULL ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Move FIFO get position to the rdr position, if any.
+ *
+ * This clears the rdr position, and removes all data between the current and
+ * new get positions from the FIFO.
+ */
+extern void
+vio_fifo_sync_rdr(vio_fifo vf)
+{
+ vio_fifo_lump head ;
+
+ VIO_FIFO_DEBUG_VERIFY(vf) ;
+
+ if (vf->rdr_lump == NULL)
+ return ;
+
+ while ((head = ddl_head(vf->base)) != vf->rdr_lump)
+ {
+ vf->get_ptr = vf->get_end ; /* jump to end of lump */
+ vio_fifo_lump_release(vf, head) ;
+ } ;
+
+ vf->get_ptr = vf->rdr_ptr ; /* jump to rdr_ptr */
+
+ vf->rdr_lump = NULL ; /* clear the rdr */
+ vf->rdr_ptr = NULL ;
+
+ if (vf->one)
+ {
+ if (vf->put_ptr == vf->get_ptr) /* reset pointers if FIFO empty */
+ vio_fifo_ptr_reset(vf, head) ;
+ else
+ vf->get_end = vf->put_ptr ;
+ }
+ else
+ vf->get_end = head->end ;
+
+ VIO_FIFO_DEBUG_VERIFY(vf) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Drop the rdr position (if any).
+ *
+ * This clears the rdr position leaving the get position and FIFO unchanged.
+ */
+extern void
+vio_fifo_drop_rdr(vio_fifo vf)
+{
+ VIO_FIFO_DEBUG_VERIFY(vf) ;
+
+ vf->rdr_lump = NULL ;
+ vf->rdr_ptr = NULL ;
+} ;
+
+/*------------------------------------------------------------------------------
* Move on to next lump to get stuff from.
*
* Advance pointers etc. so that have at least one byte available, unless
@@ -439,70 +1022,51 @@ vio_fifo_got_upto(vio_fifo vf, void* here)
* Returns: true <=> at least one byte in FIFO.
*
* NB: if finds that the FIFO is empty, resets the pointers to the start
- * of the last lump.
+ * of the last lump -- does not release the last lump.
*/
static bool
vio_fifo_get_next_lump(vio_fifo vf)
{
vio_fifo_lump head ;
- vio_fifo_lump tail ;
VIO_FIFO_DEBUG_VERIFY(vf) ;
assert(vf->get_ptr == vf->get_end) ;
- head = ddl_head(vf->base) ; /* current lump for put */
- tail = ddl_tail(vf->base) ; /* current lump for get */
+ head = ddl_head(vf->base) ; /* current lump for get */
- /* Deal with case of one lump only */
+ /* Deal with the simple case of one lump, first.
+ *
+ * To save work when putting data into the FIFO (particularly when putting
+ * a byte at a time) does not keep the vf->get_end up to date (when there is
+ * only one lump).
+ *
+ * If the FIFO is empty, reset pointers and return empty.
+ */
if (vf->one)
{
- assert( (head != NULL)
- && (head == tail) ) ;
+ assert( (head != NULL) && (head == ddl_tail(vf->base)) ) ;
- if (vf->get_ptr == vf->put_ptr)
+ if (vf->get_ptr < vf->put_ptr)
{
- /* FIFO is empty -- reset pointers and exit */
- vf->get_ptr = vf->get_end = vf->put_ptr = head->data ;
- assert(vf->put_end == head->end) ;
+ /* Had an out of date vf->get_end */
+ vf->get_end = vf->put_ptr ;
- return 0 ; /* FIFO empty */
+ return true ; /* FIFO not empty */
} ;
- /* Had an out of date vf->get_end */
- assert(vf->get_end < vf->put_ptr) ;
- vf->get_end = vf->put_ptr ;
-
- return 1 ; /* FIFO not empty after all */
- } ;
+ assert(vf->get_ptr == vf->put_ptr) ;
- /* Deal with case of not yet allocated */
- if (head == NULL)
- {
- assert( (tail == NULL)
- && (vf->put_ptr == vf->get_ptr) );
+ /* FIFO is empty -- reset pointers and exit */
+ vio_fifo_ptr_reset(vf, head) ;
- return 0 ; /* FIFO empty */
+ return false ; /* FIFO empty */
} ;
- /* Deal with (remaining) case of two or more lumps */
- assert(vf->get_ptr == head->end) ;
-
- ddl_del_head(vf->base, list) ;
- XFREE(MTYPE_VIO_FIFO_LUMP, head) ;
-
- head = ddl_head(vf->base) ;
- assert(head != NULL) ;
-
- vf->one = (head == tail) ;
-
- vf->get_ptr = head->data ; /* at start of next lump */
-
- if (vf->one)
- vf->get_end = vf->put_ptr ; /* up to current put */
- else
- vf->get_end = head->end ; /* up to end of lump */
-
- VIO_FIFO_DEBUG_VERIFY(vf) ;
+ /* Release the head and update pointers
+ *
+ * Deals with possibility that nothing has yet been allocated
+ */
+ vio_fifo_lump_release(vf, head) ;
return (vf->get_ptr < vf->get_end) ;
} ;
@@ -514,6 +1078,7 @@ Private void
vio_fifo_verify(vio_fifo vf)
{
vio_fifo_lump head ;
+ vio_fifo_lump lump ;
vio_fifo_lump tail ;
head = ddl_head(vf->base) ;
@@ -524,10 +1089,11 @@ vio_fifo_verify(vio_fifo vf)
if (head == NULL)
{
if ( (tail != NULL)
- || (vf->put_ptr != NULL)
- || (vf->put_end != NULL)
- || (vf->get_ptr != NULL)
- || (vf->get_end != NULL)
+ || (vf->put_ptr != NULL)
+ || (vf->put_end != NULL)
+ || (vf->get_ptr != NULL)
+ || (vf->rdr_lump != NULL)
+ || (vf->rdr_ptr != NULL)
|| (vf->one) )
zabort("nothing allocated, but not all NULL") ;
return ;
@@ -541,7 +1107,7 @@ vio_fifo_verify(vio_fifo vf)
/* Check that all the pointers are within respective lumps
*
* Know that put_end is always tail->end, but get_end need not be.
- * */
+ */
if ( (tail->data > vf->put_ptr)
|| (vf->put_ptr > vf->put_end)
|| (vf->put_end != tail->end) )
@@ -568,5 +1134,32 @@ vio_fifo_verify(vio_fifo vf)
if (vf->get_end != head->end)
zabort("get_end is not head->end when !vf->one") ;
+ } ;
+
+ /* If have an rdr_lump -- make sure everything else is valid */
+ if (vf->rdr_lump != NULL)
+ {
+ lump = head ;
+ while (lump != vf->rdr_lump)
+ {
+ if (lump == tail)
+ zabort("rdr_lump is not part of FIFO") ;
+ lump = ddl_next(lump, list) ;
+ } ;
+
+ if ( (lump->data > vf->rdr_ptr)
+ || (vf->rdr_ptr > lump->end) )
+ zabort("rdr_ptr outside its lump") ;
+
+ if ( (lump == head) && (vf->rdr_ptr < vf->get_ptr))
+ zabort("rdr_ptr is less than get_ptr in first lump") ;
+
+ if ( (lump == tail) && (vf->rdr_ptr > vf->put_ptr))
+ zabort("rdr_ptr is greater than put_ptr in last lump") ;
+ }
+ else
+ {
+ if (vf->rdr_ptr != NULL)
+ zabort("rdr_ptr not NULL when rdr_lump is") ;
}
} ;