+always_inline int
+f_pos_lt (u32 a, u32 b)
+{
+ return ((i32) (a - b) < 0);
+}
+
+always_inline int
+f_pos_leq (u32 a, u32 b)
+{
+ return ((i32) (a - b) <= 0);
+}
+
+always_inline int
+f_pos_gt (u32 a, u32 b)
+{
+ return ((i32) (a - b) > 0);
+}
+
+always_inline int
+f_pos_geq (u32 a, u32 b)
+{
+ return ((i32) (a - b) >= 0);
+}
+
+always_inline u8
+f_chunk_includes_pos (svm_fifo_chunk_t * c, u32 pos)
+{
+ return (f_pos_geq (pos, c->start_byte)
+ && f_pos_lt (pos, c->start_byte + c->length));
+}
+
+/**
+ * Create fifo of requested size
+ *
+ * Allocates fifo on current heap.
+ *
+ * @param size data size in bytes for fifo to be allocated. Will be
+ * rounded to the next highest power-of-two value.
+ * @return pointer to new fifo
+ */
+svm_fifo_t *svm_fifo_alloc (u32 size);
+/**
+ * Initialize fifo
+ *
+ * @param f fifo
+ * @param size size for fifo
+ */
+void svm_fifo_init (svm_fifo_t * f, u32 size);
+/**
+ * Allocate a fifo chunk on heap
+ *
+ * If the chunk is allocated on a fifo segment, this should be called
+ * with the segment's heap pushed.
+ *
+ * @param size chunk size in bytes. Will be rounded to the next highest
+ * power-of-two
+ * @return new chunk or 0 if alloc failed
+ */
+svm_fifo_chunk_t *svm_fifo_chunk_alloc (u32 size);
+/**
+ * Ensure the whole fifo size is writeable
+ *
+ * Allocates enough chunks to cover the whole fifo size.
+ *
+ * @param f fifo
+ */
+int svm_fifo_fill_chunk_list (svm_fifo_t * f);
+/**
+ * Initialize rbtrees used for ooo lookups
+ *
+ * @param f fifo
+ * @param ooo_type type of ooo operation (0 enqueue, 1 dequeue)
+ */
+void svm_fifo_init_ooo_lookup (svm_fifo_t * f, u8 ooo_type);
+/**
+ * Free fifo and associated state
+ *
+ * @param f fifo
+ */
+void svm_fifo_free (svm_fifo_t * f);
+/**
+ * Cleanup fifo chunk lookup rb tree
+ *
+ * The rb tree is allocated in segment heap so this should be called
+ * with it pushed.
+ *
+ * @param f fifo to cleanup
+ */
+void svm_fifo_free_chunk_lookup (svm_fifo_t * f);
+/**
+ * Cleanup fifo ooo data
+ *
+ * The ooo data is allocated in producer process memory. The fifo
+ * segment heap should not be pushed.
+ *
+ * @param f fifo to cleanup
+ */
+void svm_fifo_free_ooo_data (svm_fifo_t * f);
+/**
+ * Init fifo head and tail
+ *
+ * @param f fifo
+ * @param head head value that will be matched to a chunk
+ * @param tail tail value that will be matched to a chunk
+ */
+void svm_fifo_init_pointers (svm_fifo_t * f, u32 head, u32 tail);
+/**
+ * Clone fifo
+ *
+ * Clones single/default chunk fifo. It does not work for fifos with
+ * multiple chunks.
+ */
+void svm_fifo_clone (svm_fifo_t * df, svm_fifo_t * sf);
+/**
+ * Enqueue data to fifo
+ *
+ * Data is enqueued and tail pointer is updated atomically. If the new data
+ * enqueued partly overlaps or "touches" an out-of-order segment, said segment
+ * is "consumed" and the number of bytes returned is appropriately updated.
+ *
+ * @param f fifo
+ * @param len length of data to copy
+ * @param src buffer from where to copy the data
+ * @return number of contiguous bytes that can be consumed or error
+ */
+int svm_fifo_enqueue (svm_fifo_t * f, u32 len, const u8 * src);
+/**
+ * Enqueue data to fifo with offset
+ *
+ * Data is enqueued without updating tail pointer. Instead, an out-of-order
+ * list of segments is generated and maintained. Fifo takes care of coalescing
+ * contiguous or overlapping segments.
+ *
+ * @param f fifo
+ * @param offset offset at which to copy the data
+ * @param len len of data to copy
+ * @param src buffer from where to copy the data
+ * @return 0 if enqueue was successful, error otherwise
+ */
+int svm_fifo_enqueue_with_offset (svm_fifo_t * f, u32 offset, u32 len,
+ u8 * src);