+/**
+ * Fifo segment free space
+ *
+ * Queries the underlying memory manager, dlmalloc, for free space. Since this
+ * ends up walking the internal data structures, it should not be called
+ * indiscriminately.
+ *
+ * @param fs fifo segment
+ * @return number of free bytes
+ */
+static uword
+fsh_free_space (fifo_segment_header_t * fsh)
+{
+ struct dlmallinfo dlminfo;
+
+ dlminfo = mspace_mallinfo (fsh->ssvm_sh->heap);
+ return dlminfo.fordblks;
+}
+
+static inline void
+fsh_free_bytes_sub (fifo_segment_header_t * fsh, int size)
+{
+ clib_atomic_fetch_sub_rel (&fsh->n_free_bytes, size);
+}
+
+static inline uword
+fsh_n_free_bytes (fifo_segment_header_t * fsh)
+{
+ uword n_free = clib_atomic_load_relax_n (&fsh->n_free_bytes);
+ return n_free > fsh->n_reserved_bytes ? n_free - fsh->n_reserved_bytes : 0;
+}
+
+static inline void
+fsh_update_free_bytes (fifo_segment_header_t * fsh)
+{
+ clib_atomic_store_rel_n (&fsh->n_free_bytes, fsh_free_space (fsh));
+}
+
+static void
+fsh_check_mem (fifo_segment_header_t * fsh)
+{
+ uword thresh;
+
+ if (fsh->flags & FIFO_SEGMENT_F_MEM_LIMIT)
+ return;
+
+ thresh = clib_max (0.01 * fsh->ssvm_sh->ssvm_size,
+ 2 * fsh->n_reserved_bytes);
+ if (fsh->n_free_bytes > thresh)
+ return;
+
+ fsh->flags |= FIFO_SEGMENT_F_MEM_LIMIT;
+ fsh_update_free_bytes (fsh);
+}
+
+static inline fifo_segment_slice_t *
+fsh_slice_get (fifo_segment_header_t * fsh, u32 slice_index)
+{
+ return &fsh->slices[slice_index];
+}
+
+static inline void
+fsh_active_fifos_update (fifo_segment_header_t * fsh, int inc)
+{
+ clib_atomic_fetch_add_rel (&fsh->n_active_fifos, inc);
+}
+