+static void
+ct_handle_cleanups (void *args)
+{
+ uword thread_index = pointer_to_uword (args);
+ const u32 max_cleanups = 100;
+ ct_main_t *cm = &ct_main;
+ ct_cleanup_req_t *req;
+ ct_connection_t *ct;
+ u32 n_to_handle = 0;
+ session_t *s;
+
+ cm->heave_cleanups[thread_index] = 0;
+ n_to_handle = clib_fifo_elts (cm->pending_cleanups[thread_index]);
+ n_to_handle = clib_min (n_to_handle, max_cleanups);
+
+ while (n_to_handle)
+ {
+ clib_fifo_sub2 (cm->pending_cleanups[thread_index], req);
+ ct = ct_connection_get (req->ct_index, thread_index);
+ s = session_get (ct->c_s_index, ct->c_thread_index);
+ if (!svm_fifo_has_event (s->tx_fifo))
+ ct_session_postponed_cleanup (ct);
+ else
+ clib_fifo_add1 (cm->pending_cleanups[thread_index], *req);
+ n_to_handle -= 1;
+ }
+
+ if (clib_fifo_elts (cm->pending_cleanups[thread_index]))
+ {
+ cm->heave_cleanups[thread_index] = 1;
+ session_send_rpc_evt_to_thread_force (
+ thread_index, ct_handle_cleanups,
+ uword_to_pointer (thread_index, void *));
+ }
+}
+
+static void
+ct_program_cleanup (ct_connection_t *ct)
+{
+ ct_main_t *cm = &ct_main;
+ ct_cleanup_req_t *req;
+ uword thread_index;
+
+ thread_index = ct->c_thread_index;
+ clib_fifo_add2 (cm->pending_cleanups[thread_index], req);
+ req->ct_index = ct->c_c_index;
+
+ if (cm->heave_cleanups[thread_index])
+ return;
+
+ cm->heave_cleanups[thread_index] = 1;
+ session_send_rpc_evt_to_thread_force (
+ thread_index, ct_handle_cleanups, uword_to_pointer (thread_index, void *));
+}
+
+static void
+ct_session_close (u32 ct_index, u32 thread_index)
+{
+ ct_connection_t *ct, *peer_ct;
+ session_t *s;
+
+ ct = ct_connection_get (ct_index, thread_index);
+ s = session_get (ct->c_s_index, ct->c_thread_index);
+ peer_ct = ct_connection_get (ct->peer_index, thread_index);
+ if (peer_ct)
+ {
+ peer_ct->peer_index = ~0;
+ /* Make sure session was allocated */
+ if (peer_ct->flags & CT_CONN_F_HALF_OPEN)
+ {
+ ct_session_connect_notify (s, SESSION_E_REFUSED);
+ }
+ else if (peer_ct->c_s_index != ~0)
+ session_transport_closing_notify (&peer_ct->connection);
+ else
+ {
+ /* should not happen */
+ clib_warning ("ct peer without session");
+ ct_connection_free (peer_ct);
+ }
+ }
+
+ /* Do not send closed notify to make sure pending tx events are
+ * still delivered and program cleanup */
+ ct_program_cleanup (ct);
+}
+