+static void
+ct_session_dealloc_fifos (ct_connection_t *ct, svm_fifo_t *rx_fifo,
+ svm_fifo_t *tx_fifo)
+{
+ ct_segments_ctx_t *seg_ctx;
+ ct_main_t *cm = &ct_main;
+ ct_segment_flags_t flags;
+ segment_manager_t *sm;
+ app_worker_t *app_wrk;
+ ct_segment_t *ct_seg;
+ fifo_segment_t *fs;
+ u32 seg_index;
+ u8 cnt;
+
+ /*
+ * Cleanup fifos
+ */
+
+ sm = segment_manager_get (rx_fifo->segment_manager);
+ seg_index = rx_fifo->segment_index;
+
+ fs = segment_manager_get_segment_w_lock (sm, seg_index);
+ fifo_segment_free_fifo (fs, rx_fifo);
+ fifo_segment_free_fifo (fs, tx_fifo);
+ segment_manager_segment_reader_unlock (sm);
+
+ /*
+ * Update segment context
+ */
+
+ clib_rwlock_reader_lock (&cm->app_segs_lock);
+
+ seg_ctx = pool_elt_at_index (cm->app_seg_ctxs, ct->seg_ctx_index);
+ ct_seg = pool_elt_at_index (seg_ctx->segments, ct->ct_seg_index);
+
+ if (ct->flags & CT_CONN_F_CLIENT)
+ {
+ cnt =
+ __atomic_sub_fetch (&ct_seg->client_n_sessions, 1, __ATOMIC_RELAXED);
+ if (!cnt)
+ ct_seg->flags |= CT_SEGMENT_F_CLIENT_DETACHED;
+ }
+ else
+ {
+ cnt =
+ __atomic_sub_fetch (&ct_seg->server_n_sessions, 1, __ATOMIC_RELAXED);
+ if (!cnt)
+ ct_seg->flags |= CT_SEGMENT_F_SERVER_DETACHED;
+ }
+
+ flags = ct_seg->flags;
+
+ clib_rwlock_reader_unlock (&cm->app_segs_lock);
+
+ /*
+ * No need to do any app updates, return
+ */
+ if (cnt)
+ return;
+
+ if (ct->flags & CT_CONN_F_CLIENT)
+ {
+ app_wrk = app_worker_get_if_valid (ct->client_wrk);
+ /* Determine if client app still needs notification, i.e., if it is
+ * still attached. If client detached and this is the last ct session
+ * on this segment, then its connects segment manager should also be
+ * detached, so do not send notification */
+ if (app_wrk)
+ {
+ segment_manager_t *csm;
+ csm = app_worker_get_connect_segment_manager (app_wrk);
+ if (!segment_manager_app_detached (csm))
+ app_worker_del_segment_notify (app_wrk, ct->segment_handle);
+ }
+ }
+ else if (!segment_manager_app_detached (sm))
+ {
+ app_wrk = app_worker_get (ct->server_wrk);
+ app_worker_del_segment_notify (app_wrk, ct->segment_handle);
+ }
+
+ if (!(flags & CT_SEGMENT_F_CLIENT_DETACHED) ||
+ !(flags & CT_SEGMENT_F_SERVER_DETACHED))
+ return;
+
+ /*
+ * Remove segment context because both client and server detached
+ */
+
+ clib_rwlock_writer_lock (&cm->app_segs_lock);
+
+ seg_ctx = pool_elt_at_index (cm->app_seg_ctxs, ct->seg_ctx_index);
+ pool_put_index (seg_ctx->segments, ct->ct_seg_index);
+
+ /*
+ * No more segment indices left, remove the segments context
+ */
+ if (!pool_elts (seg_ctx->segments))
+ {
+ u64 table_handle = seg_ctx->client_wrk << 16 | seg_ctx->server_wrk;
+ table_handle = (u64) seg_ctx->sm_index << 32 | table_handle;
+ hash_unset (cm->app_segs_ctxs_table, table_handle);
+ pool_free (seg_ctx->segments);
+ pool_put_index (cm->app_seg_ctxs, ct->seg_ctx_index);
+ }
+
+ clib_rwlock_writer_unlock (&cm->app_segs_lock);
+
+ segment_manager_lock_and_del_segment (sm, seg_index);
+
+ /* Cleanup segment manager if needed. If server detaches there's a chance
+ * the client's sessions will hold up segment removal */
+ if (segment_manager_app_detached (sm) && !segment_manager_has_fifos (sm))
+ segment_manager_free_safe (sm);
+}
+