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.c1823
1 files changed, 1162 insertions, 661 deletions
diff --git a/lib/vio_fifo.c b/lib/vio_fifo.c
index 10c4a343..e6365861 100644
--- a/lib/vio_fifo.c
+++ b/lib/vio_fifo.c
@@ -20,14 +20,13 @@
*/
#include "misc.h"
+#include <stdio.h>
#include <string.h>
#include "vio_fifo.h"
#include "network.h"
-#include "list_util.h"
#include "memory.h"
-#include "zassert.h"
/*==============================================================================
* VTY I/O FIFO manages an arbitrary length byte-wise FIFO buffer.
@@ -39,7 +38,6 @@
* ever needed.
*
* When releasing lumps, keeps one lump "spare", to be reused as necessary.
- * This is used in ... TODO <<<< And is released...
*
*------------------------------------------------------------------------------
* Implementation notes:
@@ -48,97 +46,218 @@
*
* Once a lump has been allocated there is always one lump in the FIFO.
*
+ * The hold_mark allows the get_ptr to move forward, but retaining the data in
+ * the FIFO until the hold_mark is cleared. Can move the get_ptr back to the
+ * hold_mark to reread the data.
+ *
+ * The end_mark allows put_ptr to move forward, but the new data cannot be got
+ * from the FIFO until the end_mark is cleared. Can discard the new data
+ * and move the put_ptr back to the end_mark.
+ *
+ * There are four lumps of interest:
+ *
+ * * head -- where the hold_mark is, if there is one.
+ *
+ * * get_lump -- where the get_ptr is.
+ * Same as head when no hold_mark.
+ *
+ * * end_lump -- where the end_mark is, if there is one.
+ * Same as tail when no end mark.
+ *
+ * * tail -- where the put_ptr is.
+ *
+ * Some or all of those may be the same, depending on how big the FIFO is.
+ *
* The following are expected to be true:
*
- * * put_ptr == get_ptr => FIFO empty
+ * * set <=> at least one lump in the FIFO
+ *
+ * * as_one <=> set && get_lump == tail && !end_mark
+ * => get_end moves with put_ptr
*
- * * put_ptr == tail->end -- at all times (NULL when no lumps)
+ * * hold_mark => there is a hold mark & hold_ptr is valid
+ * & head lump contains mark
+ * !hold_mark => get_lump == head & hold_ptr == NULL
+ *
+ * * end_mark => there is an end_mark & end_end is valid
+ * & end_lump contains mark
+ * !end_mark => end_lump == tail & end_ptr == NULL
+ *
+ * * put_ptr == get_ptr => FIFO empty -- unless hold_mark and
+ * hold_ptr != get_ptr.
+ *
+ * * put_end == tail->end -- at all times (NULL when no lumps)
*
* put_ptr >= tail->data ) otherwise something is broken
* put_ptr <= tail->end )
*
- * * get_ptr == head->end -- when there is more than one lump
- * get_ptr <= put_ptr -- when there is only one lump
+ * * get_end == get_lump->end -- when get_lump != end_lump
+ * == end_end -- when get_lump == end_lump & end_mark set
+ * <= put_ptr -- when get_lump == end_lump & no end_mark
+ *
+ * See note below on get_end and as_one flag.
*
- * get_ptr >= head->data ) otherwise something is broken
- * get_ptr <= head->end )
+ * get_ptr >= get_lump->data ) otherwise something is broken
+ * get_ptr <= get_lump->end )
*
* * put_ptr == put_end => tail lump is full
* put_ptr < put_end => space exists in the tail lump
* put_ptr > put_end => broken
*
- * * get_ptr == get_end => head lump is empty
- * BUT if there is only one lump, make sure that
- * get_end == put_ptr.
- * get_ptr < get_end => data exists in the head lump
+ * * get_ptr == get_end => nothing to get from current get_lump
+ * BUT if as_one, make sure that get_end == put_ptr
+ * get_ptr < get_end => data exists in the current get_lump
* get_ptr > get_end => broken
*
* Note that:
*
- * * when the get_ptr reaches the put_ptr the pointers are reset to the
- * start of the one and only lump.
+ * * while get_ptr <= get_end can get stuff without worrying about other
+ * pointers or moving between lumps etc. It is permissible to leave
+ * get_ptr == get_end -- this will be tidied up on the next get operation,
+ * or any other time vio_fifo_sync_get() is called. Leaving get_ptr in
+ * that state delays the discard of the now empty lump, but has no other
+ * real downside.
+ *
+ * Similarly, while put_ptr <= put_end, can put stuff without worrying
+ * about other pointers or moving between lumps etc.
+ *
+ * When getting, if get_ptr == get_end, or require more data than is
+ * immediately available, need to use vio_fifo_sync_get(), to do that.
+ *
+ * * the value of get_end depends on whether get_lump == end_lump, and then
+ * whether there is an end_mark.
+ *
+ * When get_lump == end_lump && !end_mark, then get_end may be out of date
+ * because get_ptr has been advanced. This is dealt with by
+ * vio_fifo_sync_get(), which uses the as_one flag to signal that it should
+ * set get_end = put_ptr and then (re)check for anything to get.
*
- * Everywhere that the get_ptr is moved, must check for meeting the
- * put_ptr and reset pointers. At the same time, when reaches the end of
- * a lump, gets rid of it.
+ * The as_one flag is there to save a little work. Making sure that the
+ * get_end is up to date can be done often when getting from the FIFO. So
+ * the maintenance of the flag should be worth the effort.
*
- * * when advancing the put_ptr does not check for advancing the get_end.
+ * * some care must be taken to ensure that are not fooled by the
+ * ambiguity of a pointer to the end of one lump and a pointer to the
+ * start of the next -- these are really equal, but they don't look as if
+ * they are !
*
- * The one exception to this, is that when the put_ptr advances to a new
- * block, if there was one lump, sets the get_end to the end of that block.
+ * - put_ptr -- if at the end of the last lump there is no next lump !
*
- * Everywhere that the get_end is used, must check for there being one
- * lump and the possibility that put_ptr has changed.
+ * When a new lump is added, the put_ptr advances to the
+ * start of the new last lump.
+ *
+ * - end_end -- when set from the put_ptr, this can be at the end of
+ * the last lump, but as above, there is no next lump.
+ *
+ * When a new lump is added, if the end_end is at the
+ * end of the last lump, it is moved to the start of the
+ * new last lump (along with the out_ptr).
+ *
+ * So... end_end will never be ambiguous.
+ *
+ * - get_ptr -- this can be ambiguous.
+ *
+ * When getting bytes, if the segment get_ptr..get_end
+ * is sufficient, then nothing else is required.
+ *
+ * Otherwise, vio_fifo_sync_get() will sort things out,
+ * including resetting all pointers if the FIFO has been
+ * emptied.
+ *
+ * - hold_ptr -- when set from get_ptr this could be at the end of the
+ * first lump -- but when vio_fifo_sync_get() is called,
+ * that will be spotted and sorted out.
+ *
+ * If get_ptr is set from an ambiguous hold_ptr, that is
+ * also taken care of by the next vio_fifo_sync_get().
+ *
+ * When doing things with hold_ptr, does a number of
+ * vio_fifo_sync_get() operations, so the hold_ptr should
+ * not, in practice, be ambiguous.
+ *
+ * * Before the first lump is allocated the FIFO appears empty (of course)
+ * but may have hold_mark and/or end_mark set, and these work as expected.
*/
/*==============================================================================
* Initialisation, allocation and freeing of FIFO and lumps thereof.
*/
-/* Return default size, or given size rounded up to 16 byte boundary */
+/*------------------------------------------------------------------------------
+ * Return default size, or given size rounded up to 128 byte boundary
+ */
static size_t
vio_fifo_size(size_t size)
{
+#if VIO_FIFO_DEBUG
+#warning VIO_FIFO_DEBUG and 29 byte lumps !
+ return 29 ;
+#else
if (size == 0)
return 4096 ;
else
- return ((size + 16 - 1) / 16) * 16 ;
+ return ((size + 128 - 1) / 128) * 128 ;
+#endif
+} ;
+
+/*------------------------------------------------------------------------------
+ * Set and return true end of lump.
+ *
+ * End of lump can be set short of true end when putting stuff, if wish to
+ * move to next lump early (eg if not enough room left in current lump).
+ *
+ * When reusing a lump, need to restore the true lump end.
+ */
+static inline char*
+vio_fifo_true_lump_size(vio_fifo_lump lump)
+{
+ return lump->end = lump->data + lump->size ;
} ;
/*==============================================================================
* Initialise VTY I/O FIFO -- allocating if required.
*/
extern vio_fifo
-vio_fifo_init_new(vio_fifo vf, size_t size)
+vio_fifo_init_new(vio_fifo vff, size_t size)
{
- if (vf == NULL)
- vf = XCALLOC(MTYPE_VIO_FIFO, sizeof(vio_fifo_t)) ;
+ if (vff == NULL)
+ vff = XCALLOC(MTYPE_VIO_FIFO, sizeof(vio_fifo_t)) ;
else
- memset(vf, 0, sizeof(vio_fifo_t)) ;
+ memset(vff, 0, sizeof(vio_fifo_t)) ;
/* Zeroising the the vio_fifo_t has set:
*
- * lump -- base pair, both pointers NULL => list is empty
+ * base -- 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
+ * set -- false -- nothing set, yet.
+ * as_one -- false -- get_lump != tail or end_mark
+ * hold_mark -- false -- no hold mark
+ * end_mark -- false -- no end mark
+ *
+ * hold_ptr -- NULL no hold_mark
*
+ * get_lump -- NULL )
* get_ptr -- NULL ) no lump to get anything from
* get_end -- NULL ) get_ptr -- get_end => nothing left in current lump
*
- * rdr_lump -- NULL ) no rdr_lump
- * rdr_ptr -- NULL
+ * end_lump -- NULL no lump at end of what can get
+ * end_end -- NULL no end_mark
*
- * spare -- NULL no spare lump
+ * put_ptr -- NULL ) no lump to put anything into
+ * put_end -- NULL ) put_ptr == put_end => no room in current lump
*
- * ALSO put_ptr == get_ptr => FIFO is empty !
+ * size -- 0 no size set for lumps (yet)
+ *
+ * spare -- NULL no spare lump
*/
+ confirm(VIO_FIFO_INIT_ALL_ZEROS) ;
- vf->size = vio_fifo_size(size) ;
+ if (size != 0)
+ vff->size = vio_fifo_size(size) ;
- VIO_FIFO_DEBUG_VERIFY(vf) ;
+ VIO_FIFO_DEBUG_VERIFY(vff) ;
- return vf ;
+ return vff ;
}
/*------------------------------------------------------------------------------
@@ -146,7 +265,8 @@ vio_fifo_init_new(vio_fifo vf, size_t size)
*
* Does nothing if given a NULL pointer -- must already have been freed !
*
- * If does not free the FIFO structure, resets it all empty.
+ * If does not free the FIFO structure, resets it all empty, keeping the
+ * current size setting.
*
* Frees *all* FIFO lumps.
*
@@ -154,104 +274,289 @@ vio_fifo_init_new(vio_fifo vf, size_t size)
* vio_fifo_reset_free(vio_fifo)
*/
extern vio_fifo
-vio_fifo_reset(vio_fifo vf, int free_structure)
+vio_fifo_reset(vio_fifo vff, free_keep_b free_structure)
{
vio_fifo_lump lump ;
- if (vf == NULL)
+ if (vff == NULL)
return NULL ;
- while (ddl_pop(&lump, vf->base, list) != NULL)
+ while (ddl_pop(&lump, vff->base, list) != NULL)
XFREE(MTYPE_VIO_FIFO_LUMP, lump) ;
- if (vf->spare != NULL)
- XFREE(MTYPE_VIO_FIFO_LUMP, vf->spare) ;
+ if (vff->spare != NULL)
+ XFREE(MTYPE_VIO_FIFO_LUMP, vff->spare) ;
+
+ confirm(free_it == true) ;
if (free_structure)
- XFREE(MTYPE_VIO_FIFO, vf) ; /* sets vf = NULL */
+ XFREE(MTYPE_VIO_FIFO, vff) ; /* sets vff = NULL */
else
- vio_fifo_init_new(vf, vf->size) ;
+ vio_fifo_init_new(vff, vff->size) ;
- return vf ;
+ return vff ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * The FIFO has one lump -- set all pointers.
+ *
+ * Preserves end_mark -- setting to new put_ptr position
+ * Preserves hold_mark -- setting to new put_ptr position
+ *
+ * Sets as_one if no end_mark.
+ */
+inline static void
+vio_fifo_ptr_set(vio_fifo vff, vio_fifo_lump lump)
+{
+ vff->as_one = !vff->end_mark ;
+
+ vff->put_ptr = lump->data ;
+ vff->put_end = vio_fifo_true_lump_size(lump) ;
+
+ vff->hold_ptr = vff->hold_mark ? vff->put_ptr : NULL ;
+
+ vff->get_lump = lump ;
+ vff->get_ptr = vff->put_ptr ;
+ vff->get_end = vff->put_ptr ;
+
+ vff->end_lump = lump ;
+ vff->end_end = vff->end_mark ? vff->put_ptr : NULL ;
} ;
/*------------------------------------------------------------------------------
* The FIFO is empty, with one lump -- reset all pointers.
+ *
+ * Preserves end_mark -- setting to new put_ptr position
+ * Preserves hold_mark -- setting to new put_ptr position
+ *
+ * Sets as_one if no end_mark.
*/
inline static void
-vio_fifo_ptr_reset(vio_fifo vf, vio_fifo_lump lump)
+vio_fifo_ptr_reset(vio_fifo vff, 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 ;
- } ;
+ assert(vff->set) ;
+ assert(lump == ddl_tail(vff->base)) ; /* must be tail */
+ assert(lump == ddl_head(vff->base)) ; /* and must be head */
+
+ vio_fifo_ptr_set(vff, lump) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Synchronise get_end and put_ptr (if required)
+ *
+ * When in the same lump, the get_end and the put_ptr should be the same. But
+ * maintaining that every time something is put into the buffer is a pain, so
+ * we allow the put_ptr to get ahead, and re-synchronise when get_ptr hits
+ * get_end, or any other time we need the pointers to be straight.
+ *
+ * The as_one flag takes a little maintenance... it means:
+ *
+ * (get_lump == tail) && set && !end_mark
+ *
+ * If get_ptr is at the end of what can be got from the current lump, advances
+ * to the next lump if possible, releasing anything that can be released.
+ *
+ * If the FIFO is empty (with one lump), will crash all pointers down to start
+ * of current lump. The FIFO is empty if get_ptr == put_ptr, and there are no
+ * bytes held before the get_ptr.
+ *
+ * NB: object of the hold_mark is to allow users of the FIFO to store pointers
+ * to sections of the FIFO returned by vio_fifo_get_lump() and stepped
+ * over by vio_fifo_got_upto(). Note that where there is nothing to
+ * read vio_fifo_get_lump() returns NULL -- so do not have to preserve
+ * the hold_ptr when hold_ptr == get_ptr (== end_end) == put_ptr -- that
+ * is, if hold_ptr == get_ptr, we can move the hold_ptr around with the
+ * get_ptr.
+ *
+ * Can reach empty state without realising it, because the "get" stuff is not
+ * required to check every time a byte is read -- in fact, it is not necessary
+ * to check until cannot get anything because get_ptr == get_end.
+ *
+ * NB: with an end_mark there is the ambiguous position at the end of a
+ * lump -- which is the same as the start of the next lump, if any.
+ *
+ * Elsewhere we advance the end_end if it was at the very end of the FIFO
+ * and we advance the put_ptr to a new lump. But we cope here in any
+ * case.
+ *
+ * Returns: true <=> there is something in the (now) current get_lump.
+ * false <=> there is nothing else to be got (though if there is an
+ * end_mark, there may be stuff beyond that).
+ */
+static bool vio_fifo_sync_get_next(vio_fifo vff) ;
+static void vio_fifo_release_head(vio_fifo vff, vio_fifo_lump lump) ;
+
+inline static bool
+vio_fifo_sync_get(vio_fifo vff)
+{
+ if (vff->as_one) /* false if !vff->set */
+ vff->get_end = vff->put_ptr ;
- /* 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 ;
+ if (vff->get_ptr < vff->get_end) /* both NULL if !vff->set */
+ return true ; /* have at least one byte */
+
+ return vio_fifo_sync_get_next(vff) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * See if fifo really is or is not empty (get_ptr == end_end or == put_ptr).
+ *
+ * Used by vio_fifo_empty(). Called iff get_ptr >= get_end !
+ *
+ * So need to vio_fifo_sync_get() and test again against end_end & put_ptr.
+ */
+Private bool
+vio_fifo_do_empty(vio_fifo vff)
+{
+ return ! vio_fifo_sync_get(vff) ;
} ;
/*------------------------------------------------------------------------------
- * The FIFO is utterly empty, with ZERO lumps -- unset all pointers.
+ * Set a new get_lump/get_ptr/get_end set. And set as_one to suit.
*/
inline static void
-vio_fifo_ptr_unset(vio_fifo vf)
+vio_fifo_set_get_ptr(vio_fifo vff, void* ptr, vio_fifo_lump lump)
{
- assert((ddl_head(vf->base) == NULL) && (ddl_tail(vf->base) == NULL)) ;
+ vff->get_lump = lump ;
+ vff->get_ptr = ptr ;
- vf->one = false ;
+ if (lump != vff->end_lump)
+ {
+ vff->get_end = lump->end ;
+ vff->as_one = false ;
+ }
+ else if (vff->end_mark)
+ {
+ vff->get_end = vff->end_end ;
+ vff->as_one = false ;
+ }
+ else
+ {
+ vff->get_end = vff->put_ptr ;
+ vff->as_one = true ;
+ } ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Move on to next lump to get stuff from.
+ *
+ * For use by vio_fifo_sync_get() *ONLY*.
+ *
+ * Asserts that (vff->get_ptr == vff->get_end) and assumes that if as_one, then
+ * get_end == put_ptr !
+ *
+ * Returns: true <=> at least one byte in FIFO available to get.
+ */
+static bool
+vio_fifo_sync_get_next(vio_fifo vff)
+{
+ bool hold_empty ;
- vf->put_ptr = NULL ;
- vf->put_end = NULL ;
- vf->get_ptr = NULL ;
- vf->get_end = NULL ;
+ assert(vff->get_ptr == vff->get_end) ;
- vf->rdr_lump = NULL ;
- vf->rdr_ptr = NULL ;
+ VIO_FIFO_DEBUG_VERIFY(vff) ;
+
+ if (!vff->set)
+ return false ; /* quit before get into any trouble */
+
+ /* Worry about whether there is anything held.
+ *
+ * NB: we know that at this point the get_ptr == get_end, so is at the end
+ * of the current get_lump. The hold_ptr cannot be ahead of get_ptr,
+ * so the test hold_ptr == get_ptr is sufficient to detect that there
+ * is nothing, in fact, held.
+ */
+ hold_empty = !vff->hold_mark || (vff->hold_ptr == vff->get_ptr) ;
+
+ /* If we are not at the end_lump, step forward, discarding current
+ * lump unless hold_mark.
+ */
+ if (vff->get_lump != vff->end_lump)
+ {
+ vio_fifo_lump next ;
+ next = ddl_next(vff->get_lump, list) ;
+
+ vio_fifo_set_get_ptr(vff, next->data, next) ;
+
+ if (hold_empty)
+ {
+ vio_fifo_release_head(vff, next) ;
+
+ /* If there is a hold_mark, then had hold_ptr == get_ptr
+ * and this is where we keep hold_ptr & get_ptr in sync.
+ */
+ if (vff->hold_mark)
+ vff->hold_ptr = vff->get_ptr ;
+ } ;
+
+ /* Return the get state now */
+ if (vff->get_ptr < vff->get_end)
+ return true ;
+ } ;
+
+ /* Still have get_ptr == get_end => nothing more to get.
+ *
+ * Check now for empty FIFO, and reset all pointers if that is the case.
+ */
+ if ((vff->get_ptr == vff->put_ptr) && hold_empty)
+ {
+ if (vff->hold_mark)
+ assert(vff->hold_ptr == vff->get_ptr) ;
+
+ if (vff->end_mark)
+ assert(vff->end_end == vff->put_ptr) ;
+
+ vio_fifo_ptr_reset(vff, vff->end_lump) ;
+ }
+
+ return false ; /* nothing to get */
} ;
/*------------------------------------------------------------------------------
* Clear out contents of FIFO -- will continue to use the FIFO.
*
+ * If required, clears any hold mark and/or end mark.
+ *
* Keeps one FIFO lump. (Frees everything else, including any spare.)
*
* Does nothing if there is no FIFO !
*/
extern void
-vio_fifo_clear(vio_fifo vf)
+vio_fifo_clear(vio_fifo vff, bool clear_marks)
{
- vio_fifo_lump tail ;
-
- if (vf == NULL)
+ if (vff == NULL)
return ;
- VIO_FIFO_DEBUG_VERIFY(vf) ;
+ VIO_FIFO_DEBUG_VERIFY(vff) ;
- tail = ddl_tail(vf->base) ;
+ vff->as_one = vff->set ;
+ if (clear_marks)
+ {
+ vff->hold_mark = false ; /* Discard marks */
+ vff->end_mark = false ;
+ } ;
- if (tail != NULL)
+ if (vff->set)
{
- while (ddl_head(vf->base) != tail)
+ vio_fifo_lump lump ;
+
+ while (1)
{
- vio_fifo_lump lump ;
- ddl_pop(&lump, vf->base, list) ;
+ lump = ddl_head(vff->base) ;
+ if (lump == ddl_tail(vff->base))
+ break ;
+
+ ddl_pop(&lump, vff->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) ;
+ vio_fifo_ptr_reset(vff, lump) ;
+ } ;
- if (vf->spare != NULL)
- XFREE(MTYPE_VIO_FIFO_LUMP, vf->spare) ; /* sets vf->spare = NULL */
+ if (vff->spare != NULL)
+ XFREE(MTYPE_VIO_FIFO_LUMP, vff->spare) ; /* sets vff->spare = NULL */
- VIO_FIFO_DEBUG_VERIFY(vf) ;
+ VIO_FIFO_DEBUG_VERIFY(vff) ;
} ;
/*------------------------------------------------------------------------------
@@ -266,279 +571,226 @@ vio_fifo_clear(vio_fifo vf)
* Returns: room available as described
*/
extern size_t
-vio_fifo_room(vio_fifo vf)
+vio_fifo_room(vio_fifo vff)
{
- if (vf->put_ptr != NULL)
- return vf->put_end - vf->put_ptr ;
+ if (vff->set)
+ return vff->put_end - vff->put_ptr ;
else
- return vf->size ;
+ return vff->size ;
} ;
/*------------------------------------------------------------------------------
- * Allocate another lump for putting into.
+ * Need a new lump to put stuff into.
*
- * Call when (vf->put_ptr >= vf->put_end) -- asserts that they are equal.
+ * Call when (vff->put_ptr >= vff->put_end) -- asserts that they are equal.
*
- * Set the put_ptr/put_end pointers to point at the new lump.
+ * If the FIFO is, in fact, empty but with at least one lump, then does not
+ * allocate anything more, but releases all lumps but the last lump and then
+ * resets all pointers to the start of that lump.
*
- * If this is the first lump allocated, set the get_ptr/get_end pointers too.
+ * Otherwise, allocates a new lump (or reuses the spare) to the requested size,
+ * and updates all pointers as required. (Allocates to vff->size if
+ * requested size is zero.)
*
- * If have just filled the first lump on the list, update the get_end pointer
- * to reflect the fact that the out lump is now full.
+ * NB: if there is an end_mark, makes sure that it advances with the put_ptr
+ * if currently end_end == the put_ptr.
*/
-extern void
-vio_fifo_lump_new(vio_fifo vf, size_t size)
+Private void
+vio_fifo_lump_new(vio_fifo vff, size_t size)
{
vio_fifo_lump lump ;
- int first_alloc ;
+ size_t std_size ;
- VIO_FIFO_DEBUG_VERIFY(vf) ;
+ passert(vff->put_ptr == vff->put_end) ; /* must be end of tail lump
+ (or both NULL) */
+ VIO_FIFO_DEBUG_VERIFY(vff) ;
- passert(vf->put_ptr == vf->put_end) ; /* must be end of tail lump */
+ /* First, make sure that the get side is synchronised, which may advance
+ * various pointers, release lumps and possibly reset now empty FIFO.
+ *
+ * If synchronising the get side does not yield space, then the FIFO is
+ * either not set or it has something in it (including held stuff).
+ */
+ vio_fifo_sync_get(vff) ;
- if (vf->one)
- vf->get_end = vf->put_ptr ; /* update get_end */
+ if (vff->put_ptr < vff->put_end)
+ return ; /* Done if have created space */
- lump = ddl_tail(vf->base) ;
+ /* If we can use the spare, do so, otherwise make it to size */
+ lump = vff->spare ;
+ vff->spare = NULL ;
- first_alloc = (lump == NULL) ; /* extra initialisation needed */
+ std_size = vio_fifo_size(vff->size) ; /* normalised standard */
- if (first_alloc)
- assert(vf->put_ptr == NULL) ; /* must all be NULL together */
+ if (size <= std_size)
+ size = std_size ; /* use standard as a minimum */
else
- assert(vf->put_ptr == lump->end) ; /* must be end of tail lump */
+#if VIO_FIFO_DEBUG
+ size |= 3 ; /* most of the time a little bigger */
+#else
+ size = vio_fifo_size(size) ; /* normalise requested size */
+#endif
- size = vio_fifo_size(size) ;
-
- if ((vf->spare != NULL) && (vf->spare->size >= size))
- {
- lump = vf->spare ;
- vf->spare = NULL ;
- }
- else
+ if ((lump == NULL) || (lump->size < size))
{
- lump = XMALLOC(MTYPE_VIO_FIFO_LUMP,
- offsetof(vio_fifo_lump_t, data[size])) ;
+ /* If there was no spare, lump == NULL and XREALLOC == XMALLOC.
+ * If there was a spare that was too small, better extend that than
+ * keep a sub-standard spare.
+ */
+ lump = XREALLOC(MTYPE_VIO_FIFO_LUMP, lump,
+ offsetof(vio_fifo_lump_t, data[size])) ;
lump->size = size ;
+ lump->end = lump->data + size ;
} ;
- lump->end = lump->data + lump->size ;
-
- ddl_append(vf->base, lump, list) ;
-
- vf->one = first_alloc ;
-
- vf->put_ptr = lump->data ;
- vf->put_end = lump->end ;
-
- if (first_alloc)
- {
- vf->get_ptr = vf->put_ptr ; /* get_ptr == put_ptr => empty */
- vf->get_end = vf->put_ptr ;
- } ;
-
- VIO_FIFO_DEBUG_VERIFY(vf) ;
-} ;
+ ddl_append(vff->base, lump, list) ;
-/*------------------------------------------------------------------------------
- * 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)
+ /* If not just allocated the first lump, set the put_ptr and normalise any
+ * end_mark or update end_lump.
+ *
+ * If is first block to be allocated, set all pointers, taking into account
+ * any end_mark and/or hold_mark.
+ */
+ if (vff->set)
{
- vio_fifo_lump keep ;
+ /* Allocated new lump on the end of a not-empty fifo.
+ *
+ * Have to watch out for cases where the get_ptr and/or end_end are
+ * equal to the put_ptr, which is about to move to the start of a new
+ * lump, so as to avoid ambiguity !
+ */
- /* Consistency checks */
- if (release_head)
+ if (vff->get_ptr == vff->put_ptr)
{
- if (release_tail)
- assert(vf->get_ptr == vf->put_ptr) ;
- else
- assert(vf->get_ptr == lump->end) ;
+ /* If the fifo is empty, the vio_fifo_sync_get() above will have
+ * spotted it. So can only get here iff there is something held in
+ * the fifo behind the get_ptr.
+ *
+ * If was as_one, is still as_one.
+ *
+ * If was not as_one then must have end_mark with end_end == put_ptr,
+ * which will be dealt with below.
+ */
+ assert(vff->hold_mark && (vff->get_ptr != vff->hold_ptr)) ;
- if (vf->rdr_lump == lump)
- assert(vf->rdr_ptr == vf->get_ptr) ;
+ vff->get_ptr = lump->data ;
+ vff->get_end = lump->data ;
+ vff->get_lump = lump ;
}
- else if (release_tail)
+ else
{
- assert(vf->put_ptr == lump->data) ;
-
- if (vf->rdr_lump == lump)
- assert(vf->rdr_ptr == vf->put_ptr) ;
+ /* If were as_one, then will no longer be, because put_ptr is about
+ * to advance to the start of the new lump.
+ */
+ vff->as_one = false ;
} ;
- /* 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 (vff->end_mark)
+ {
+ assert(!vff->as_one) ;
- if ((keep == NULL) || (keep->size < lump->size))
+ /* The end_end follows the put_ptr iff they are equal
+ *
+ * If the get_ptr also equals the put_ptr, it has already advanced.
+ */
+ if (vff->end_end == vff->put_ptr)
+ {
+ vff->end_end = lump->data ;
+ vff->end_lump = lump ;
+ } ;
+ }
+ else
{
- keep = lump ;
- free = vf->spare ;
+ /* No end_mark => end_lump simply follows the put_ptr. */
+ vff->end_lump = lump ;
} ;
- vf->spare = keep ;
-
- head = ddl_head(vf->base) ; /* changed if released head */
- tail = ddl_tail(vf->base) ; /* changed if released tail */
+ vff->put_ptr = lump->data ;
+ vff->put_end = vio_fifo_true_lump_size(lump) ;
+ }
+ else
+ {
+ /* Allocated lump for previously empty fifo -- set all pointers to the
+ * start of the lump, except for put_end.
+ */
+ vff->set = true ;
+ vio_fifo_ptr_set(vff, lump) ;
} ;
- /* 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_DEBUG_VERIFY(vff) ;
+} ;
- vio_fifo_ptr_unset(vf) ;
- }
- else
+/*------------------------------------------------------------------------------
+ * Release the given lump, provided it is neither get_lump nor end_lump.
+ *
+ * If don't have a spare lump, keep this one. Otherwise, keep larger of
+ * this and current spare.
+ */
+static void
+vio_fifo_release_lump(vio_fifo vff, vio_fifo_lump lump)
+{
+ assert(lump != NULL) ;
+ assert(lump != vff->get_lump) ;
+ assert(lump != vff->end_lump) ;
+
+ if (vff->spare != NULL)
{
- /* Have at least one lump left -- so must have had at least two ! */
- assert(!vf->one) ;
+ vio_fifo_lump free ;
- vf->one = (head == tail) ; /* update */
+ free = vff->spare ;
- if (release_head)
+ if (free->size > lump->size)
{
- /* 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 ;
- } ;
+ free = lump ;
+ lump = vff->spare ;
} ;
- } ;
-
- /* Finally, free any lump that is actually to be freed */
- if (free != NULL)
- XFREE(MTYPE_VIO_FIFO_LUMP, free) ;
+ XFREE(MTYPE_VIO_FIFO_LUMP, free) ;
+ } ;
- VIO_FIFO_DEBUG_VERIFY(vf) ;
+ vff->spare = lump ;
} ;
/*------------------------------------------------------------------------------
- * Re-allocate lump for putting into.
- *
- * Call when vf->put_ptr == start of last lump, and that lump is not big
- * enough !
+ * Release lumps from head up to, but not including, given lump.
*
- * There must be at least one lump.
+ * NB: must be "set" and must not attempt to release the get_lump or the
+ * end_lump.
*
- * Updates put_ptr/put_end pointers to point at the new lump.
+ * So MUST advance at least the get_lump before calling this.
*
- * Updates get_ptr/get_end pointers if required.
- *
- * Updates rdr_ptr if required.
+ * It is the caller's responsibility to update get and/or hold pointers.
*/
static void
-vio_fifo_lump_renew(vio_fifo vf, vio_fifo_lump lump, size_t size)
+vio_fifo_release_head(vio_fifo vff, vio_fifo_lump upto)
{
- 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) ;
+ assert(vff->set) ;
- /* Now allocate a new lump with the required size */
- vio_fifo_lump_new(vf, size) ;
-
- /* Restore the rdr_ptr, if required */
- if (rdr_set)
+ while (upto != ddl_head(vff->base))
{
- vio_fifo_lump tail ;
+ vio_fifo_lump lump ;
+ vio_fifo_release_lump(vff, ddl_pop(&lump, vff->base, list)) ;
+ } ;
+} ;
- tail = ddl_tail(vf->base) ;
+/*------------------------------------------------------------------------------
+ * Release lumps from tail back to, but not including, given lump.
+ *
+ * NB: must be "set" and must not attempt to release the get_lump or the
+ * end_lump.
+ *
+ * It is the caller's responsibility to update end and/or put pointers.
+ */
+static void
+vio_fifo_release_tail(vio_fifo vff, vio_fifo_lump backto)
+{
+ assert(vff->set) ;
- vf->rdr_lump = tail ;
- vf->rdr_ptr = tail->data ;
+ while (backto != ddl_tail(vff->base))
+ {
+ vio_fifo_lump lump ;
+ vio_fifo_release_lump(vff, ddl_crop(&lump, vff->base, list)) ;
} ;
-
- VIO_FIFO_DEBUG_VERIFY(vf) ;
} ;
/*==============================================================================
@@ -546,196 +798,461 @@ vio_fifo_lump_renew(vio_fifo vf, vio_fifo_lump lump, size_t size)
*/
/*------------------------------------------------------------------------------
- * Store 'n' bytes -- allocate new lump if current is exhausted.
+ * Put 'n' bytes -- allocating as required.
*/
extern void
-vio_fifo_put(vio_fifo vf, const char* src, size_t n)
+vio_fifo_put_bytes(vio_fifo vff, const char* src, size_t n)
{
- size_t take ;
-
- VIO_FIFO_DEBUG_VERIFY(vf) ;
+ VIO_FIFO_DEBUG_VERIFY(vff) ;
while (n > 0)
{
- if (vf->put_ptr >= vf->put_end)
- vio_fifo_lump_new(vf, vf->size) ; /* traps put_ptr > put_end */
+ size_t take ;
- take = (vf->put_end - vf->put_ptr) ;
+ if (vff->put_ptr >= vff->put_end)
+ vio_fifo_lump_new(vff, 0) ; /* traps put_ptr > put_end */
+
+ take = (vff->put_end - vff->put_ptr) ;
if (take > n)
take = n ;
- memcpy(vf->put_ptr, src, take) ;
- vf->put_ptr += take ;
+ memcpy(vff->put_ptr, src, take) ;
+ vff->put_ptr += take ;
src += take ;
n -= take ;
} ;
- VIO_FIFO_DEBUG_VERIFY(vf) ;
+ VIO_FIFO_DEBUG_VERIFY(vff) ;
} ;
/*------------------------------------------------------------------------------
- * Formatted print to fifo -- cf printf()
+ * 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, ...)
+vio_fifo_printf(vio_fifo vff, const char* format, ...)
{
va_list args;
int len ;
va_start (args, format);
- len = vio_fifo_vprintf(vf, format, args);
+ len = vio_fifo_vprintf(vff, format, args);
va_end (args);
return len;
} ;
/*------------------------------------------------------------------------------
- * Formatted print to fifo -- cf vprintf()
+ * Formatted print to FIFO -- cf vprintf()
+ *
+ * Does nothing if vff is NULL !
*
* Returns: >= 0 -- number of bytes written
* < 0 -- failed (unlikely though that is)
+ *
+ * NB: does not extend an existing lump in order to make things fit, but
+ * splits the result across two lumps. This ensures that at all times
+ * pointers into existing lumps are stable -- so pointer returned by
+ * vio_fifo_get_lump(), for example, cannot be upset !
*/
extern int
-vio_fifo_vprintf(vio_fifo vf, const char *format, va_list args)
+vio_fifo_vprintf(vio_fifo vff, const char *format, va_list args)
{
va_list ac ;
int len ;
int have ;
- size_t size ;
- vio_fifo_lump lump ;
+ int had ;
+ int need ;
+ char* last ;
- VIO_FIFO_DEBUG_VERIFY(vf) ;
+ if (vff == NULL)
+ return 0 ;
- size = vf->size ; /* standard allocation size */
- while (1)
+ VIO_FIFO_DEBUG_VERIFY(vff) ;
+
+ /* First the simple way.
+ *
+ * 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'. In the meantime, it has output as much as it
+ * can, with a trailing '\0'.
+ */
+ assert(vff->put_ptr <= vff->put_end) ;
+
+ have = vff->put_end - vff->put_ptr ; /* what can do in current lump
+ if any. */
+ va_copy(ac, args) ;
+ len = vsnprintf(vff->put_ptr, have, format, ac) ;
+ va_end(ac) ;
+
+ if ((len < have) || (len == 0)) /* OK, or failed ! */
{
- /* 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 */
+ if (len > 0)
+ vff->put_ptr += len ; /* advance put_ptr as required */
- have = vf->put_end - vf->put_ptr ;
- assert(have > 0) ;
+ return len ;
+ } ;
- /* 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) ;
+ /* Now know that we need len + 1 bytes in all to complete the task, and
+ * that it has written have - 1 bytes to the existing lump (if any).
+ *
+ * Also, len > 0.
+ *
+ * Allocate a new lump in which we can write the entire result, even if
+ * that is a non-standard size.
+ */
+ need = len + 1 ; /* need includes the '\0' */
+ had = have ;
- if (len < have)
- {
- if (len < 0)
- break ; /* quit if failed */
+ if (had > 0)
+ vff->put_ptr += had ; /* step to the end */
+ last = vff->put_ptr ; /* point at end of lump (NULL if none) */
- vf->put_ptr += len ;
- break ; /* done */
- } ;
+ vio_fifo_lump_new(vff, need) ;/* new lump to do it all */
- /* 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 */
+ have = vff->put_end - vff->put_ptr ;
+ assert(have >= need) ; /* have >= 2 */
- lump = ddl_tail(vf->base) ;
+ /* We really expect to get the same result a second time ! */
+ va_copy(ac, args) ;
+ len = vsnprintf(vff->put_ptr, have, format, ac) ;
+ va_end(ac) ;
- 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 ;
+ /* Since have >= what previously said it needed, things have gone
+ * badly wrong if the new len is >= have.
+ *
+ * Also, things have gone badly wrong if new len is < what previously
+ * had, which was then not enough !
+ *
+ * Also, things have gone badly wrong if new len == 0, because previously
+ * it was > 0 !
+ */
+ if ((len >= have) || (len < had) || (len == 0))
+ return (len < 0) ? len : -1 ;
+
+ /* Move result around if required -- len >= had */
+ have = len ;
+ if (had > 0)
+ {
+ char* frag ;
+ frag = vff->put_ptr + had ; /* first character to keep */
+ *(last - 1) = *(frag - 1) ; /* replace the '\0' */
+
+ have -= had ; /* amount to keep */
+ if (have > 0)
+ memmove(vff->put_ptr, frag, have) ;
} ;
- VIO_FIFO_DEBUG_VERIFY(vf) ;
+ /* Advance the put_ptr past what we have in the new lump. */
+ vff->put_ptr += have ;
+
+ VIO_FIFO_DEBUG_VERIFY(vff) ;
return len ;
} ;
+/*------------------------------------------------------------------------------
+ * Read part of file into FIFO -- assuming non-blocking file
+ *
+ * Will read up to the end of the lump which meets, or exceeds the number of
+ * bytes requested, or until would block.
+ *
+ * Returns: 0..n -- number of bytes read
+ * -1 => failed -- see errno
+ * -2 => EOF met immediately
+ *
+ * Note: will work perfectly well for a non-blocking file -- which should
+ * never return EAGAIN/EWOULDBLOCK, so will return from here with
+ * something, error or EOF.
+ */
+extern int
+vio_fifo_read_nb(vio_fifo vff, int fd, size_t request)
+{
+ size_t total ;
+
+ total = 0 ;
+
+ do
+ {
+ int got ;
+
+ if (vff->put_ptr >= vff->put_end)
+ vio_fifo_lump_new(vff, 0) ; /* traps put_ptr > put_end */
+
+ got = read_nb(fd, vff->put_ptr, vff->put_end - vff->put_ptr) ;
+
+ if (got <= 0)
+ {
+ if (got == -2) /* EOF met */
+ return (total > 0) ? (int)total : got ;
+ else
+ return (got == 0) ? (int)total : got ;
+ } ;
+
+ vff->put_ptr += got ;
+ total += got ;
+
+ } while (total < request) ;
+
+ return total ;
+} ;
+
/*==============================================================================
- * Get data from the FIFO.
+ * Copy operations -- from one fifo to another.
*/
-static bool vio_fifo_get_next_lump(vio_fifo vf) ;
+/*------------------------------------------------------------------------------
+ * Copy src fifo (everything from get_ptr to end_mark or put_ptr) to dst fifo.
+ *
+ * Create a dst fifo if there isn't one.
+ *
+ * Appends to the dst fifo.
+ *
+ * Does not change the src fifo in any way.
+ */
+extern vio_fifo
+vio_fifo_copy(vio_fifo dst, vio_fifo src)
+{
+ if (dst == NULL)
+ dst = vio_fifo_init_new(dst, 0) ;
+
+ if ((src != 0) && (src->set))
+ {
+ vio_fifo_lump src_lump ;
+ char* src_ptr ;
+
+ if (src->get_ptr >= src->get_end)
+ vio_fifo_sync_get(src) ;
+
+ src_lump = src->get_lump ;
+ src_ptr = src->get_ptr ;
+
+ while (1)
+ {
+ char* src_end ;
+
+ if (src_lump != src->end_lump)
+ src_end = src_lump->end ;
+ else
+ src_end = (src->end_mark) ? src->end_end : src->put_ptr ;
+
+ vio_fifo_put_bytes(dst, src_ptr, src_end - src_ptr) ;
+
+ if (src_lump == src->end_lump)
+ break ;
+
+ src_lump = ddl_next(src_lump, list) ;
+ src_ptr = src_lump->data ;
+ } ;
+ } ;
+
+ return dst ;
+} ;
/*------------------------------------------------------------------------------
- * Get ready to read something out of the FIFO.
+ * Copy tail of src fifo (everything from end_mark to put_ptr) to dst fifo.
+ *
+ * Create a dst fifo if there isn't one.
*
- * Makes sure vf->get_end is up to date (if required) and if the FIFO is not
- * empty, makes sure vf->get_ptr points at the next byte to be read.
+ * Appends to the dst fifo.
*
- * Returns: true <=> there is something in the FIFO.
+ * Does not change the src fifo in any way.
*/
-static inline bool
-vio_fifo_get_ready(vio_fifo vf)
+extern vio_fifo
+vio_fifo_copy_tail(vio_fifo dst, vio_fifo src)
{
- assert(vf->rdr_lump == NULL) ;
+ if (dst == NULL)
+ dst = vio_fifo_init_new(dst, 0) ;
- if (vf->one)
- vf->get_end = vf->put_ptr ; /* make sure have everything */
+ if ((src != 0) && (src->end_mark) && (src->set))
+ {
+ vio_fifo_lump src_lump ;
+ char* src_ptr ;
+ vio_fifo_lump tail ;
- if (vf->get_ptr >= vf->get_end)
- if (!vio_fifo_get_next_lump(vf))
- return 0 ; /* quit now if nothing there */
+ src_lump = src->end_lump ;
+ src_ptr = src->end_end ;
+ tail = ddl_tail(src->base) ;
- VIO_FIFO_DEBUG_VERIFY(vf) ;
+ while (1)
+ {
+ char* src_end ;
- return 1 ;
+ if (src_lump != tail)
+ src_end = src_lump->end ;
+ else
+ src_end = src->put_ptr ;
+
+ vio_fifo_put_bytes(dst, src_ptr, src_end - src_ptr) ;
+
+ if (src_lump == tail)
+ break ;
+
+ src_lump = ddl_next(src_lump, list) ;
+ src_ptr = src_lump->data ;
+ } ;
+ } ;
+
+ return dst ;
} ;
+/*==============================================================================
+ * End Mark Operations.
+ */
+
+/*------------------------------------------------------------------------------
+ * Set end_mark at the current put position.
+ *
+ * If there was an end_mark before, move it (forward) to the current put_ptr,
+ * which keeps everything in between in the FIFO.
+ *
+ * Set the get_end to the new reality.
+ */
+extern void
+vio_fifo_set_end_mark(vio_fifo vff)
+{
+ if (vff->set)
+ {
+ vio_fifo_sync_get(vff) ; /* in case is currently empty */
+
+ vff->end_lump = ddl_tail(vff->base) ;
+ vff->end_end = vff->put_ptr ;
+
+ vff->get_end = (vff->get_lump == vff->end_lump) ? vff->end_end
+ : vff->get_lump->end ;
+ } ;
+
+ vff->as_one = false ; /* not as_one with end_mark */
+ vff->end_mark = true ;
+
+ VIO_FIFO_DEBUG_VERIFY(vff) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * If there is an end mark, advance it to the put_ptr.
+ *
+ * If there was an end_mark before, move it (forward) to the current put_ptr,
+ * which keeps everything in between in the FIFO.
+ *
+ * If there was no end_mark before, do nothing.
+ *
+ * Set the get_end to the new reality.
+ */
+extern void
+vio_fifo_step_end_mark(vio_fifo vff)
+{
+ if (vff->end_mark)
+ vio_fifo_set_end_mark(vff) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * If there is an end_mark, clear it -- everything between end mark and
+ * current put_ptr is kept in the FIFO.
+ *
+ * Set the get_end to the new reality.
+ */
+extern void
+vio_fifo_clear_end_mark(vio_fifo vff)
+{
+ if (vff->end_mark)
+ {
+ vff->end_mark = false ;
+
+ if (vff->set)
+ {
+ vff->end_lump = ddl_tail(vff->base) ;
+ vff->end_end = NULL ;
+
+ vff->as_one = (vff->get_lump == vff->end_lump) ;
+ /* since now no end_mark */
+ if (!vff->as_one)
+ vff->get_end = vff->get_lump->end ;
+ /* would have been end_end */
+
+ vio_fifo_sync_get(vff) ; /* sets get_end if as_one and
+ tidies up if now empty (!) */
+ } ;
+ } ;
+
+ VIO_FIFO_DEBUG_VERIFY(vff) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Move put_ptr back to the end mark, if any, and discard data.
+ *
+ * If there is an end_mark, keep it if required.
+ *
+ * If there is no end mark, do nothing.
+ */
+extern void
+vio_fifo_back_to_end_mark(vio_fifo vff, bool keep)
+{
+ if (vff->end_mark)
+ {
+ if (vff->set)
+ {
+ vio_fifo_release_tail(vff, vff->end_lump) ;
+
+ vff->put_ptr = vff->end_end ;
+ vff->put_end = vio_fifo_true_lump_size(vff->end_lump) ;
+
+ /* If retaining the existing end_mark, we retain the end_end and
+ * the current as_one (false).
+ *
+ * Otherwise...
+ */
+ if (!keep)
+ {
+ vff->end_mark = false ;
+ vff->end_end = NULL ;
+ vff->as_one = (vff->get_lump == vff->end_lump) ;
+ } ;
+
+ vio_fifo_sync_get(vff) ; /* in case now empty */
+
+ VIO_FIFO_DEBUG_VERIFY(vff) ;
+ }
+ else
+ vff->end_mark = keep ;
+ } ;
+} ;
+
+/*==============================================================================
+ * Get data from the FIFO.
+ */
+
/*------------------------------------------------------------------------------
* Get upto 'n' bytes.
*
* Returns: number of bytes got -- may be zero.
*/
extern size_t
-vio_fifo_get(vio_fifo vf, void* dst, size_t n)
+vio_fifo_get_bytes(vio_fifo vff, void* dst, size_t n)
{
size_t have ;
void* dst_in ;
- if (!vio_fifo_get_ready(vf))
- return 0 ; /* quit now if nothing there */
+ VIO_FIFO_DEBUG_VERIFY(vff) ;
dst_in = dst ;
- while (n > 0)
+ while (vio_fifo_sync_get(vff) && (n > 0))
{
- have = vf->get_end - vf->get_ptr ;
+ have = vff->get_end - vff->get_ptr ;
if (have > n)
have = n ;
- memcpy(dst, vf->get_ptr, have) ;
- vf->get_ptr += have ;
+ memcpy(dst, vff->get_ptr, have) ;
+ vff->get_ptr += have ;
dst = (char*)dst + have ;
- if (vf->get_ptr >= vf->get_end) /* deal with exhausted lump */
- if (!vio_fifo_get_next_lump(vf))
- break ; /* quit if nothing more to come */
-
n -= have ;
} ;
- VIO_FIFO_DEBUG_VERIFY(vf) ;
+ VIO_FIFO_DEBUG_VERIFY(vff) ;
return (char*)dst - (char*)dst_in ;
} ;
@@ -752,76 +1269,84 @@ vio_fifo_get(vio_fifo vf, void* dst, size_t n)
* Returns: 0x00..0xFF -- byte value (as an int)
* -1 => FIFO is empty.
*/
-
-extern int
-vio_fifo_get_next_byte(vio_fifo vf)
+Private int
+vio_fifo_get_next_byte(vio_fifo vff)
{
- unsigned char u ;
-
- if (!vio_fifo_get_ready(vf))
- return -1 ; /* quit now if nothing there */
-
- u = *vf->get_ptr++ ;
-
- /* As soon as reach the end want either to discard empty lump, or reset
- * the pointers.
- */
- if (vf->get_ptr >= vf->get_end) /* deal with exhausted lump */
- vio_fifo_get_next_lump(vf) ;
-
- VIO_FIFO_DEBUG_VERIFY(vf) ;
+ if (vio_fifo_sync_get(vff))
+ return (uchar)*vff->get_ptr++ ;
- return u ;
+ return -1 ;
} ;
/*------------------------------------------------------------------------------
- * Get pointer to a lump of bytes.
+ * Get pointer to as many bytes as are available in the current lump (or next
+ * lump if nothing available in the current).
*
* 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.
+ * If the FIFO is not empty and not at the end_mark, will return pointer to at
+ * least one byte. There may be more bytes to get in further lumps.
*/
extern void*
-vio_fifo_get_lump(vio_fifo vf, size_t* p_have)
+vio_fifo_get(vio_fifo vff, size_t* p_have)
{
- if (!vio_fifo_get_ready(vf))
+ if (vio_fifo_sync_get(vff))
{
- *p_have = 0 ;
- return NULL ;
+ *p_have = (vff->get_end - vff->get_ptr) ;
+ return vff->get_ptr ;
} ;
- *p_have = (vf->get_end - vf->get_ptr) ;
- return vf->get_ptr ;
+ *p_have = 0 ;
+ return NULL ;
} ;
/*------------------------------------------------------------------------------
- * Advance FIFO to position reached.
+ * Step FIFO past bytes used.
*
- * Having done vio_fifo_get_lump(), can take any number of bytes (up to the
- * number that "have"), then call this function to advance the pointers.
+ * Can be called after a vio_fifo_get() or vio_fifo_step_get().
*
- * The "here" argument must the the address returned by vio_fifo_get_lump()
- * plus the number of bytes taken.
+ * NB: the "step" argument MUST not exceed the "have" previously returned.
*/
extern void
-vio_fifo_got_upto(vio_fifo vf, void* here)
+vio_fifo_step(vio_fifo vff, size_t step)
+{
+ vff->get_ptr += step ;
+ vio_fifo_sync_get(vff) ; /* ensure up to date with that */
+
+ VIO_FIFO_DEBUG_VERIFY(vff) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Step FIFO past bytes used, the get pointer to as many bytes as are available
+ * in the current lump (or next lump if nothing available in the current).
+ *
+ * Same as vio_fifo_step() followed by vio_fifo_get().
+ *
+ * Can be called after a vio_fifo_get() or vio_fifo_step_get().
+ *
+ * NB: the "step" argument MUST not exceed the "have" previously returned.
+ */
+extern void*
+vio_fifo_step_get(vio_fifo vff, size_t* p_have, size_t step)
{
- vf->get_ptr = here ;
+ vff->get_ptr += step ;
- VIO_FIFO_DEBUG_VERIFY(vf) ;
+ if (vio_fifo_sync_get(vff))
+ {
+ *p_have = (vff->get_end - vff->get_ptr) ;
+ return vff->get_ptr ;
+ } ;
- if (vf->get_ptr >= vf->get_end)
- vio_fifo_get_next_lump(vf) ;
+ *p_have = 0 ;
+ return NULL ;
} ;
/*------------------------------------------------------------------------------
* Write contents of FIFO -- assuming non-blocking file
*
- * Will write all of FIFO, or upto but excluding the last lump.
+ * Will write all of FIFO up to end mark or put_ptr, or upto but excluding
+ * the last lump.
*
* Returns: > 0 => blocked
* 0 => all gone (up to last lump if !all)
@@ -831,338 +1356,314 @@ vio_fifo_got_upto(vio_fifo vf, void* here)
* never return EAGAIN/EWOULDBLOCK, so will return from here "all gone".
*/
extern int
-vio_fifo_write_nb(vio_fifo vf, int fd, bool all)
+vio_fifo_write_nb(vio_fifo vff, int fd, bool all)
{
char* src ;
size_t have ;
- int done ;
- while ((src = vio_fifo_get_lump(vf, &have)) != NULL)
+ while ((src = vio_fifo_get(vff, &have)) != NULL)
{
- if (!all && vf->one)
- break ; /* don't write last lump */
+ int done ;
+
+ if ((vff->get_lump == vff->end_lump) && !all)
+ break ; /* don't write last lump */
done = write_nb(fd, src, have) ;
if (done < 0)
- return -1 ; /* failed */
+ return -1 ; /* failed */
- vio_fifo_got_upto(vf, src + done) ;
+ vio_fifo_step(vff, done) ;
if (done < (int)have)
- return 1 ; /* blocked */
+ 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 ;
+ return 0 ; /* all gone */
} ;
/*------------------------------------------------------------------------------
- * 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
+ * Write contents of FIFO -- assuming blocking file
*
- * If the FIFO is not empty, will return pointer to at least one byte.
+ * Will write all of FIFO up to end mark or put_ptr.
*
- * Returns number of bytes to the end of the current lump. There may be
- * further lumps beyond the current one.
+ * Returns: 0 => all gone
+ * < 0 => failed -- see errno
*
- * 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.
+ * Note: will work perfectly well for a non-blocking file -- which should
+ * never return EAGAIN/EWOULDBLOCK, so will return from here "all gone".
*/
-extern void*
-vio_fifo_get_rdr(vio_fifo vf, size_t* p_have)
+extern int
+vio_fifo_fwrite(vio_fifo vff, FILE* file)
{
- if (!vio_fifo_get_ready(vf))
- {
- *p_have = 0 ;
- return NULL ;
- } ;
+ char* src ;
+ size_t have ;
- if (vf->rdr_lump == NULL) /* set up new rdr if required */
+ while ((src = vio_fifo_get(vff, &have)) != NULL)
{
- vf->rdr_lump = ddl_head(vf->base) ;
- vf->rdr_ptr = vf->get_ptr ;
- } ;
+ size_t done ;
- VIO_FIFO_DEBUG_VERIFY(vf) ;
+ done = fwrite(src, have, 1, file) ;
- *p_have = vio_fifo_rdr_end(vf) - vf->rdr_ptr ;
- return vf->rdr_ptr ;
+ if (done < 1)
+ return -1 ; /* failed */
+
+ vio_fifo_step(vff, have) ;
+ } ;
+
+ return 0 ; /* all gone */
} ;
/*------------------------------------------------------------------------------
- * 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.
+ * Skip get_ptr to the current end -- which may be the current end_mark.
*
- * 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".
+ * Does not clear any hold_mark or end_mark.
*/
-extern void*
-vio_fifo_step_rdr(vio_fifo vf, size_t* p_have, size_t step)
+extern void
+vio_fifo_skip_to_end(vio_fifo vff)
{
- char* rdr_end ;
+ vio_fifo_sync_get(vff) ; /* ensure all straight */
- assert(vf->rdr_lump != NULL) ;
+ /* Setting the get_ptr to the start of the end_lump does the bulk
+ * of the work -- then just skip to the get_end which that sets.
+ */
+ vio_fifo_set_get_ptr(vff, vff->end_lump->data, vff->end_lump) ;
+ vff->get_ptr = vff->get_end ;
- VIO_FIFO_DEBUG_VERIFY(vf) ;
+ vio_fifo_sync_get(vff) ; /* crunch */
+} ;
- rdr_end = vio_fifo_rdr_end(vf) ;
- vf->rdr_ptr += step ;
+/*==============================================================================
+ * Hold Mark Operations.
+ */
- if (vf->rdr_ptr >= rdr_end)
+/*------------------------------------------------------------------------------
+ * If there is a hold_mark, clear it -- discard all contents up to the
+ * current get_ptr.
+ *
+ * Set hold_mark at the current get_ptr.
+ */
+extern void
+vio_fifo_set_hold_mark(vio_fifo vff)
+{
+ if (vff->set)
{
- 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 ;
+ if (vff->hold_mark)
+ vio_fifo_clear_hold_mark(vff) ; /* clear existing mark & sync */
+ else
+ vio_fifo_sync_get(vff) ; /* ensure all straight */
- rdr_end = vio_fifo_rdr_end(vf) ;
- } ;
+ vff->hold_ptr = vff->get_ptr ;
} ;
- VIO_FIFO_DEBUG_VERIFY(vf) ;
+ vff->hold_mark = true ;
- *p_have = (rdr_end - vf->rdr_ptr) ;
- return (*p_have > 0) ? vf->rdr_ptr : NULL ;
+ VIO_FIFO_DEBUG_VERIFY(vff) ;
} ;
/*------------------------------------------------------------------------------
- * Move FIFO get position to the rdr position, if any.
+ * If there is a hold_mark, clear it -- discard all contents up to the
+ * current get_ptr.
*
- * This clears the rdr position, and removes all data between the current and
- * new get positions from the FIFO.
+ * The get_ptr is synchronised.
*/
extern void
-vio_fifo_sync_rdr(vio_fifo vf)
+vio_fifo_clear_hold_mark(vio_fifo vff)
{
- vio_fifo_lump head ;
-
- VIO_FIFO_DEBUG_VERIFY(vf) ;
-
- if (vf->rdr_lump == NULL)
- return ;
+ /* Make sure all is up to date, and in particular that the get_ptr
+ * is not sitting at the end of a lump when there is a following lump.
+ */
+ vio_fifo_sync_get(vff) ;
- while ((head = ddl_head(vf->base)) != vf->rdr_lump)
+ if ((vff->hold_mark) && (vff->set))
{
- vf->get_ptr = vf->get_end ; /* jump to end of lump */
- vio_fifo_lump_release(vf, head) ;
- } ;
+ /* Release everything upto but not including the current get_lump.
+ *
+ * This has no effect on the get_ptr etc. so they remain straight.
+ */
+ vio_fifo_release_head(vff, vff->get_lump) ;
- vf->get_ptr = vf->rdr_ptr ; /* jump to rdr_ptr */
+ vff->hold_ptr = NULL ;
+ } ;
- vf->rdr_lump = NULL ; /* clear the rdr */
- vf->rdr_ptr = NULL ;
+ vff->hold_mark = false ;
- 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) ;
+ VIO_FIFO_DEBUG_VERIFY(vff) ;
} ;
/*------------------------------------------------------------------------------
- * Drop the rdr position (if any).
+ * If there is an hold_mark, reset get_ptr *back* to it.
*
- * This clears the rdr position leaving the get position and FIFO unchanged.
+ * Leave hold mark set or clear.
*/
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
- * the FIFO is entirely empty.
- *
- * This should be called if (vf->get_ptr >= vf->get_end) -- asserts that
- * these are equal !
- *
- * NB: when there is only one block, it may be that get_end is out of date,
- * and should be advanced to the current put_ptr position.
- *
- * That is done here, but may be worth updating get_end before testing
- * against get_ptr.
- *
- * 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 -- does not release the last lump.
- */
-static bool
-vio_fifo_get_next_lump(vio_fifo vf)
+vio_fifo_back_to_hold_mark(vio_fifo vff, bool mark)
{
- vio_fifo_lump head ;
-
- VIO_FIFO_DEBUG_VERIFY(vf) ;
- assert(vf->get_ptr == vf->get_end) ;
-
- head = ddl_head(vf->base) ; /* current lump for get */
-
- /* 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)
+ if (vff->hold_mark)
{
- assert( (head != NULL) && (head == ddl_tail(vf->base)) ) ;
-
- if (vf->get_ptr < vf->put_ptr)
+ if (vff->set)
{
- /* Had an out of date vf->get_end */
- vf->get_end = vf->put_ptr ;
+ vio_fifo_set_get_ptr(vff, vff->hold_ptr, ddl_head(vff->base)) ;
+ /* Set back to hold position */
- return true ; /* FIFO not empty */
- } ;
-
- assert(vf->get_ptr == vf->put_ptr) ;
-
- /* FIFO is empty -- reset pointers and exit */
- vio_fifo_ptr_reset(vf, head) ;
-
- return false ; /* FIFO empty */
- } ;
+ vff->end_mark = mark ; /* new state */
+ if (!mark)
+ vff->hold_ptr = NULL ; /* clear if required */
- /* Release the head and update pointers
- *
- * Deals with possibility that nothing has yet been allocated
- */
- vio_fifo_lump_release(vf, head) ;
+ vio_fifo_sync_get(vff) ; /* to be absolutely sure ! */
+ } ;
- return (vf->get_ptr < vf->get_end) ;
+ VIO_FIFO_DEBUG_VERIFY(vff) ;
+ }
+ else if (mark)
+ vio_fifo_set_end_mark(vff) ;
} ;
/*==============================================================================
* For debug purposes -- verify the state of the given FIFO
*/
Private void
-vio_fifo_verify(vio_fifo vf)
+vio_fifo_verify(vio_fifo vff)
{
vio_fifo_lump head ;
vio_fifo_lump lump ;
vio_fifo_lump tail ;
- head = ddl_head(vf->base) ;
- tail = ddl_tail(vf->base) ;
+ head = ddl_head(vff->base) ;
+ tail = ddl_tail(vff->base) ;
- /* If nothing allocated, should all be NULL & !vf->one */
+ /* If nothing allocated, should all be NULL & !vff->set */
/* If something allocated, tail must not be NULL */
if (head == NULL)
{
if ( (tail != NULL)
- || (vf->put_ptr != NULL)
- || (vf->put_end != NULL)
- || (vf->get_ptr != NULL)
- || (vf->rdr_lump != NULL)
- || (vf->rdr_ptr != NULL)
- || (vf->one) )
+ || (vff->set)
+ || (vff->as_one)
+ || (vff->hold_ptr != NULL)
+ || (vff->get_lump != NULL)
+ || (vff->get_ptr != NULL)
+ || (vff->get_end != NULL)
+ || (vff->end_lump != NULL)
+ || (vff->end_end != NULL)
+ || (vff->put_ptr != NULL)
+ || (vff->put_end != NULL) )
zabort("nothing allocated, but not all NULL") ;
return ;
}
else
{
if (tail == NULL)
- zabort("head pointer not NULL, but tail pointer is") ;
+ zabort("head not NULL, but tail is") ;
} ;
- /* Check that all the pointers are within respective lumps
+ /* Must now be set ! */
+ if (!vff->set)
+ zabort("head not NULL, but set is false") ;
+
+ /* Make sure that the lump pointers all work
*
- * Know that put_end is always tail->end, but get_end need not be.
+ * When finished, know that head <= get_lump <= end_lump <= tail.
*/
- if ( (tail->data > vf->put_ptr)
- || (vf->put_ptr > vf->put_end)
- || (vf->put_end != tail->end) )
- zabort("put pointers outside the tail lump") ;
+ lump = head ;
+ while (lump != vff->get_lump)
+ {
+ lump = ddl_next(lump, list) ;
+ if (lump == NULL)
+ zabort("ran out of lumps looking for get_lump") ;
+ } ;
- if ( (head->data > vf->get_ptr)
- || (vf->get_ptr > vf->get_end)
- || (vf->get_end > head->end) )
- zabort("get pointers outside the head lump") ;
+ while (lump != vff->end_lump)
+ {
+ lump = ddl_next(lump, list) ;
+ if (lump == NULL)
+ zabort("ran out of lumps looking for end_lump") ;
+ } ;
- /* If head == tail, should be vf->one, etc. */
- if (head == tail)
+ while (lump != tail)
{
- if (!vf->one)
- zabort("have one lump, but !vf->one") ;
+ lump = ddl_next(lump, list) ;
+ if (lump == NULL)
+ zabort("ran out of lumps looking for tail") ;
+ } ;
- if (vf->get_end > vf->put_ptr)
- zabort("get_end is greater than put_ptr when vf->one") ;
+ /* Check that all the pointers are within respective lumps
+ *
+ * Know that put_end is always tail->end, but get_end need not be.
+ *
+ * When finished, know that:
+ *
+ * - get_lump == head if !hold_mark
+ * - end_lump == tail if !end_mark
+ * - that all pointers are within their respective lumps
+ * - all ptr are <= their respective ends
+ * - if hold_mark: hold_ptr <= get_ptr or head != get_lump
+ * - if end_mark: end_end <= put_ptr or tail != end_lump
+ */
+ if (vff->hold_mark)
+ {
+ if ( (head->data > vff->hold_ptr)
+ || (vff->hold_ptr > head->end) )
+ zabort("hold pointer outside the head lump") ;
+
+ if ((vff->get_lump == head) && (vff->hold_ptr > vff->get_ptr))
+ zabort("hold pointer greater than get pointer") ;
}
else
{
- if (vf->one)
- zabort("have two or more lumps, but vf->one is true") ;
-
- if (vf->get_end != head->end)
- zabort("get_end is not head->end when !vf->one") ;
+ if (vff->hold_ptr != NULL)
+ zabort("no hold_mark, but hold pointer not NULL") ;
+ if (vff->get_lump != head)
+ zabort("no hold_mark, but get_lump is not head") ;
} ;
- /* If have an rdr_lump -- make sure everything else is valid */
- if (vf->rdr_lump != NULL)
+ if ( (vff->get_lump->data > vff->get_ptr)
+ || (vff->get_ptr > vff->get_end)
+ || (vff->get_end > vff->get_lump->end))
+ zabort("get pointers outside the get lump") ;
+
+ if (vff->end_mark)
{
- lump = head ;
- while (lump != vf->rdr_lump)
- {
- if (lump == tail)
- zabort("rdr_lump is not part of FIFO") ;
- lump = ddl_next(lump, list) ;
- } ;
+ if ( (vff->end_lump->data > vff->end_end)
+ || (vff->end_end > vff->end_lump->end) )
+ zabort("end pointer outside the end lump") ;
- if ( (lump->data > vf->rdr_ptr)
- || (vf->rdr_ptr > lump->end) )
- zabort("rdr_ptr outside its lump") ;
+ if ((vff->end_lump == tail) && (vff->end_end > vff->put_ptr))
+ zabort("end pointer greater than put pointer") ;
+ }
+ else
+ {
+ if (vff->end_end != NULL)
+ zabort("no end_mark, but end end not NULL") ;
+ if (vff->end_lump != tail)
+ zabort("no end_mark, but end_lump is not tail") ;
+ } ;
- if ( (lump == head) && (vf->rdr_ptr < vf->get_ptr))
- zabort("rdr_ptr is less than get_ptr in first lump") ;
+ if ( (tail->data > vff->put_ptr)
+ || (vff->put_ptr > vff->put_end)
+ || (vff->put_end != tail->end) )
+ zabort("put pointers outside the tail lump") ;
- if ( (lump == tail) && (vf->rdr_ptr > vf->put_ptr))
- zabort("rdr_ptr is greater than put_ptr in last lump") ;
+ /* The as_one state & get_end
+ */
+ if (vff->get_lump != vff->end_lump)
+ {
+ if (vff->as_one)
+ zabort("get_lump != end_lump, but as_one true") ;
+ if (vff->get_end != vff->get_lump->end)
+ zabort("get_lump != end_lump, but get_end != get_lump->end") ;
}
- else
+ else if (vff->end_mark)
{
- if (vf->rdr_ptr != NULL)
- zabort("rdr_ptr not NULL when rdr_lump is") ;
+ if (vff->as_one)
+ zabort("end_mark true, but as_one also true") ;
+ if (vff->get_end != vff->end_end)
+ zabort("get_lump == end_lump and end_mark, but get_end != end_end") ;
}
+ else
+ {
+ if (!vff->as_one)
+ zabort("get_lump == end_lump and !end_mark, but as_one not true") ;
+ if (vff->get_end > vff->put_ptr)
+ zabort("is as_one, but get_end > put_ptr") ;
+ } ;
} ;