+ f = clib_mem_bulk_alloc (pfss->fifos);
+ clib_memset (f, 0, sizeof (*f));
+ return f;
+}
+
+void
+fs_fifo_free (fifo_segment_t *fs, svm_fifo_t *f, u32 slice_index)
+{
+ fifo_slice_private_t *pfss;
+
+ if (CLIB_DEBUG)
+ clib_memset (f, 0xfc, sizeof (*f));
+
+ pfss = &fs->slices[slice_index];
+ clib_mem_bulk_free (pfss->fifos, f);
+}
+
+void
+fifo_segment_cleanup (fifo_segment_t *fs)
+{
+ int slice_index;
+ svm_msg_q_t *mq = 0;
+
+ for (slice_index = 0; slice_index < fs->n_slices; slice_index++)
+ clib_mem_bulk_destroy (fs->slices[slice_index].fifos);
+
+ vec_free (fs->slices);
+
+ vec_foreach (mq, fs->mqs)
+ svm_msg_q_cleanup (mq);
+
+ vec_free (fs->mqs);
+}
+
+/**
+ * Allocate fifo in fifo segment
+ */
+svm_fifo_t *
+fifo_segment_alloc_fifo_w_slice (fifo_segment_t * fs, u32 slice_index,
+ u32 data_bytes, fifo_segment_ftype_t ftype)
+{
+ fifo_segment_header_t *fsh = fs->h;
+ fifo_slice_private_t *pfss;
+ fifo_segment_slice_t *fss;
+ svm_fifo_shared_t *sf;
+ svm_fifo_t *f = 0;
+
+ ASSERT (slice_index < fs->n_slices);
+
+ if (PREDICT_FALSE (data_bytes > 1 << fsh->max_log2_fifo_size))
+ return 0;
+
+ sf = fs_try_alloc_fifo (fsh, slice_index, data_bytes);
+ if (!sf)
+ goto done;
+
+ f = fs_fifo_alloc (fs, slice_index);
+ f->fs_hdr = fsh;
+ f->shr = sf;
+
+ svm_fifo_init (f, data_bytes);
+
+ f->segment_manager = fs->sm_index;
+ f->segment_index = fs->fs_index;
+
+ fss = fsh_slice_get (fsh, slice_index);
+ pfss = fs_slice_private_get (fs, slice_index);
+
+ /* If rx fifo type add to active fifos list. When cleaning up segment,
+ * we need a list of active sessions that should be disconnected. Since
+ * both rx and tx fifos keep pointers to the session, it's enough to track
+ * only one. */
+ if (ftype == FIFO_SEGMENT_RX_FIFO)
+ {
+ pfss_fifo_add_active_list (pfss, f);
+ f->flags |= SVM_FIFO_F_LL_TRACKED;
+ }
+
+ fsh_active_fifos_update (fsh, 1);
+ fss->virtual_mem += svm_fifo_size (f);
+
+done:
+ return (f);
+}
+
+svm_fifo_t *
+fifo_segment_alloc_fifo_w_offset (fifo_segment_t *fs, uword offset)
+{
+ svm_fifo_t *f = fs_fifo_alloc (fs, 0);
+ svm_fifo_shared_t *sf;
+
+ sf = (svm_fifo_shared_t *) ((u8 *) fs->h + offset);
+ f->fs_hdr = fs->h;
+ f->shr = sf;
+
+ f->ooos_list_head = OOO_SEGMENT_INVALID_INDEX;
+ f->segment_index = SVM_FIFO_INVALID_INDEX;
+ f->refcnt = 1;
+ return f;
+}
+
+svm_fifo_t *
+fifo_segment_duplicate_fifo (fifo_segment_t *fs, svm_fifo_t *f)
+{
+ svm_fifo_t *nf = fs_fifo_alloc (fs, 0);
+ clib_memcpy (nf, f, sizeof (*f));
+ return nf;
+}
+
+/**
+ * Free fifo allocated in fifo segment
+ */
+void
+fifo_segment_free_fifo (fifo_segment_t * fs, svm_fifo_t * f)
+{
+ fifo_segment_header_t *fsh = fs->h;
+ fifo_slice_private_t *pfss;
+ fifo_segment_slice_t *fss;
+ svm_fifo_shared_t *sf;
+
+ ASSERT (f->refcnt > 0);
+
+ if (--f->refcnt > 0)
+ return;
+
+ /*
+ * Cleanup shared state
+ */
+
+ sf = f->shr;
+ fss = fsh_slice_get (fsh, sf->slice_index);
+ pfss = fs_slice_private_get (fs, sf->slice_index);
+
+ /* Free fifo chunks */
+ fsh_slice_collect_chunks (fsh, fss, fs_chunk_ptr (fsh, f->shr->start_chunk));
+
+ sf->start_chunk = sf->end_chunk = 0;
+ sf->head_chunk = sf->tail_chunk = 0;
+
+ /* Add to free list */
+ fss_fifo_free_list_push (fsh, fss, sf);
+
+ fss->virtual_mem -= svm_fifo_size (f);
+
+ /*
+ * Cleanup private state
+ */
+
+ /* Remove from active list. Only rx fifos are tracked */
+ if (f->flags & SVM_FIFO_F_LL_TRACKED)
+ {
+ pfss_fifo_del_active_list (pfss, f);
+ f->flags &= ~SVM_FIFO_F_LL_TRACKED;
+ }
+
+ svm_fifo_free_chunk_lookup (f);
+ svm_fifo_free_ooo_data (f);
+
+ if (CLIB_DEBUG)
+ {
+ sf->master_session_index = ~0;
+ f->master_thread_index = ~0;
+ }
+
+ f->ooo_enq = f->ooo_deq = 0;
+ f->prev = 0;
+
+ fs_fifo_free (fs, f, f->shr->slice_index);
+
+ fsh_active_fifos_update (fsh, -1);
+}
+
+void
+fifo_segment_free_client_fifo (fifo_segment_t *fs, svm_fifo_t *f)
+{
+ fs_fifo_free (fs, f, 0 /* clients attach fifos in slice 0 */);
+}