+ /*
+ * VCL session on current vcl worker already allocated. Update current
+ * owner worker and index and return
+ */
+ if ((p = hash_get (vls->vcl_wrk_index_to_session_index, wrk_index)))
+ {
+ vls->vcl_wrk_index = wrk_index;
+ vls->session_index = (u32) p[0];
+ return vls;
+ }
+
+ /*
+ * Ask vcl worker that owns the original vcl session to clone it into
+ * current vcl worker session pool
+ */
+
+ if (!(p = hash_get (vls->vcl_wrk_index_to_session_index,
+ vls->owner_vcl_wrk_index)))
+ {
+ VERR ("session in owner worker(%u) is free", vls->owner_vcl_wrk_index);
+ ASSERT (0);
+ vls_unlock (vls);
+ vls_mt_pool_runlock ();
+ return 0;
+ }
+
+ src_sid = (u32) p[0];
+ wrk = vcl_worker_get_current ();
+ session = vcl_session_alloc (wrk);
+ sid = session->session_index;
+ VDBG (1, "migrate session of worker (session): %u (%u) -> %u (%u)",
+ vls->owner_vcl_wrk_index, src_sid, wrk_index, sid);
+
+ /* Drop lock to prevent dead lock when dst wrk trying to get lock. */
+ vls_index = vls->vls_index;
+ own_vcl_wrk_index = vls->owner_vcl_wrk_index;
+ vls_unlock (vls);
+ vls_mt_pool_runlock ();
+ vls_send_clone_and_share_rpc (wrk, vls_index, sid, vls_get_worker_index (),
+ own_vcl_wrk_index, vls_index, src_sid);
+
+ if (PREDICT_FALSE (wrk->rpc_done == VLS_RPC_STATE_SESSION_NOT_EXIST))
+ {
+ VWRN ("session %u not exist", src_sid);
+ goto err;
+ }
+ else if (PREDICT_FALSE (wrk->rpc_done == VLS_RPC_STATE_INIT))
+ {
+ VWRN ("failed to wait rpc response");
+ goto err;
+ }
+ else if (PREDICT_FALSE ((session->flags & VCL_SESSION_F_IS_VEP) &&
+ session->vep.next_sh != ~0))
+ {
+ VERR ("can't migrate nonempty epoll session");
+ ASSERT (0);
+ goto err;
+ }
+ else if (PREDICT_FALSE (!(session->flags & VCL_SESSION_F_IS_VEP) &&
+ session->session_state != VCL_STATE_CLOSED))
+ {
+ VERR ("migrate NOT supported, session_status (%u)",
+ session->session_state);
+ ASSERT (0);
+ goto err;
+ }
+
+ vls = vls_get_w_dlock (vls_index);
+ if (PREDICT_FALSE (!vls))
+ {
+ VWRN ("failed to get vls %u", vls_index);
+ goto err;
+ }
+
+ session->session_index = sid;
+ vls->vcl_wrk_index = wrk_index;
+ vls->session_index = sid;
+ hash_set (vls->vcl_wrk_index_to_session_index, wrk_index, sid);
+ vls_sh_to_vlsh_table_add (vls_wrk, vcl_session_handle (session),
+ vls->vls_index);
+ return vls;
+
+err:
+ vcl_session_free (wrk, session);
+ return 0;
+}
+
+static inline void
+vls_mt_detect (void)
+{
+ if (PREDICT_FALSE (vcl_get_worker_index () == ~0))
+ vls_mt_add ();
+}
+
+#define vls_mt_guard(_vls, _op) \
+ int _locks_acq = 0; \
+ if (vls_mt_wrk_supported ()) \
+ { \
+ if (PREDICT_FALSE (_vls && \
+ ((vcl_locked_session_t *) _vls)->vcl_wrk_index != \
+ vcl_get_worker_index ())) \
+ { \
+ _vls = vls_mt_session_migrate (_vls); \
+ if (PREDICT_FALSE (!_vls)) \
+ return VPPCOM_EBADFD; \
+ } \
+ } \
+ else \
+ { \
+ if (PREDICT_FALSE (vlsl->vls_mt_n_threads > 1)) \
+ vls_mt_acq_locks (_vls, _op, &_locks_acq); \
+ }
+
+#define vls_mt_unguard() \
+ if (PREDICT_FALSE (_locks_acq)) \