Index: /branches/rel_apv_10_7_2_5_irule/usr/click/lib/libuinet-atcp/lib/libuinet/uinet_if_dpdk.c
===================================================================
--- /branches/rel_apv_10_7_2_5_irule/usr/click/lib/libuinet-atcp/lib/libuinet/uinet_if_dpdk.c	(revision 39490)
+++ /branches/rel_apv_10_7_2_5_irule/usr/click/lib/libuinet-atcp/lib/libuinet/uinet_if_dpdk.c	(working copy)
@@ -83,6 +83,7 @@
 extern int rts_enable;
 extern int ertbsd_enable;
 extern LIST_HEAD(, vlan_adapter) vlan_adapter_list;
+uint32_t __thread thread_idle_counter = 0;
 
 char cloud_platform[16] = {0};
 TUNABLE_STR("cloud_platform", cloud_platform, sizeof(cloud_platform));
@@ -145,6 +146,7 @@
 #define IS_KNI_REQ(sc)		(ATCP_IS_MANAGEMENT() && (sc)->is_kni_req)
 
 #define MAX_QUEUE_NUM 16
+#define MAX_THREAD_IDLE_CNT 20
 
 struct if_dpdk_port_queue {
 	uint16_t port;
@@ -163,6 +165,7 @@
 struct if_dpdk_queue_map {
 	struct if_dpdk_port_queue pq[MAX_NIC*MAX_QUEUE_NUM];
 	int queue_number;
+	struct mtx map_mtx;
 };
 
 static struct if_dpdk_queue_map queue_bind_map[ATCP_L4_MAXTHREADS];
@@ -311,6 +314,14 @@
 	return max_queue;
 }
 
+static void init_queue_bind_map_lock(int idx)
+{
+	if (!mtx_initialized(&queue_bind_map[idx].map_mtx))
+	{
+		mtx_init(&queue_bind_map[idx].map_mtx, "queue_bind_map_lock", NULL, MTX_DEF);
+	}
+}
+
 /* 
  * When binding each port, keep a global state to
  * help CPU balanced when queue num < core number 
@@ -332,6 +343,7 @@
 			num = queue_bind_map[index].queue_number++;
 			queue_bind_map[index].pq[num].port = port_id;
 			queue_bind_map[index].pq[num].queue = i;
+			init_queue_bind_map_lock(index);
 		}
 		queuemap_nextidx_dm[domain] = (index + 1) % cpu_per_domain + domain * cpu_per_domain;
 	} else {
@@ -340,6 +352,7 @@
 			num = queue_bind_map[index].queue_number++;
 			queue_bind_map[index].pq[num].port = port_id;
 			queue_bind_map[index].pq[num].queue = i;
+			init_queue_bind_map_lock(index);
 		}
 		queuemap_nextidx = (index + 1) % cpu_per_domain;
 	}
@@ -1517,7 +1530,7 @@
 	struct if_dpdk_port_queue *pq_p;
 	uint32_t rx_atcp_sleep = atcp_sleep;
 
-	if (queue_number) {
+	if (queue_number && mtx_trylock(&queue_bind_map_p->map_mtx)) {
 		for (i = 0; i < queue_number; i++) {
 			pq_p = &queue_bind_map_p->pq[i];
 			sc = if_dpdk_softc_arr[pq_p->port];
@@ -1607,7 +1620,10 @@
 			}
 		}
 
+		mtx_unlock(&queue_bind_map_p->map_mtx);
+
 		if (idle_count == queue_number) {
+			thread_idle_counter++;
 			if (dpdk_intr_enable) {
 				atcp_dpdk_turn_on_intr();
 				atcp_sleep_until_rx_intr(queue_number);
@@ -1617,10 +1633,116 @@
 					usleep(rx_atcp_sleep);
 				}
 			}
+		} else {
+			thread_idle_counter = 0;
 		}
 	} else {
 		usleep(1000); /* 1ms */
 	}
+
+	if (thread_idle_counter >= MAX_THREAD_IDLE_CNT) {
+		if ((tq_thread_id + 2) >= atcp_ePolicy_id_min && (tq_thread_id + 2) <= atcp_ePolicy_id_max) {
+			thread_idle_counter = 0;
+			return;
+		}
+		// Todo: Help adjacent ATCP thread process its RX queues
+		int prev_index, prev_num;
+		int cpu_per_domain = (atcp_L4_nthreads >> 1);
+		prev_index = (tq_thread_id + 1) % cpu_per_domain;
+
+		struct if_dpdk_queue_map *queue_bind_map_next_p = &queue_bind_map[prev_index];
+		prev_num = queue_bind_map_next_p->queue_number;
+
+		if (prev_num > 0 && mtx_trylock(&queue_bind_map_next_p->map_mtx)) {
+			for (i = 0; i < prev_num; ++i) {
+				pq_p = &queue_bind_map_next_p->pq[i];
+				sc = if_dpdk_softc_arr[pq_p->port];
+				queue_id = pq_p->queue;
+				nb_mbuf = if_dpdk_eth_recv_pkts(sc->dpdk_host_ctx, queue_id, m_pkts);
+
+				if (rx_poll_window == 0 || min_zero_poll_count > 0) {
+					pq_p->min_zero_poll_count = min_zero_poll_count;
+				} else {
+					pq_p->rx_poll_count++;
+					if (nb_mbuf <= (int)rx_poll_lowthresh) {
+						pq_p->rx_low_poll_count++;
+						if (nb_mbuf == 0) {
+							pq_p->rx_zero_poll_count++;
+						}
+					}
+
+					if ((pq_p->rx_poll_count % rx_poll_window) == 0) {
+						uint32_t low_activity, poll_activity, poll_sleep, low_percent, zero_percent;
+						low_percent = (pq_p->rx_low_poll_count * 100 / rx_poll_window);
+						zero_percent = (pq_p->rx_zero_poll_count * 100 / rx_poll_window);
+
+						low_activity = low_percent * rx_poll_maxactivity / 100;
+						poll_activity = rx_poll_maxactivity - low_activity;
+						if (poll_activity < rx_poll_minactivity) {
+							poll_activity = rx_poll_minactivity;
+						} else if (poll_activity > rx_poll_maxactivity) {
+							poll_activity = rx_poll_maxactivity;
+						}
+
+						if (pq_p->avg_poll_activity == 0) {
+							pq_p->avg_poll_activity = poll_activity;
+						} else {
+							pq_p->avg_poll_activity = (pq_p->avg_poll_activity + poll_activity) / 2;
+						}
+						if (poll_activity > pq_p->min_zero_poll_count) {
+							pq_p->min_zero_poll_count = poll_activity;
+						}
+
+						poll_sleep = zero_percent * rx_poll_maxsleep / 100;
+						if (poll_sleep < rx_poll_minsleep) {
+							poll_sleep = rx_poll_minsleep;
+						} else if (poll_sleep > rx_poll_maxsleep) {
+							poll_sleep = rx_poll_maxsleep;
+						}
+
+						if (pq_p->avg_poll_sleep == 0) {
+							pq_p->avg_poll_sleep = poll_sleep;
+						} else {
+							pq_p->avg_poll_sleep = (pq_p->avg_poll_sleep + poll_sleep) / 2;
+						}
+						if (poll_sleep < pq_p->rx_poll_sleep) {
+							pq_p->rx_poll_sleep = poll_sleep;
+						}
+
+						pq_p->rx_low_poll_count = 0;
+						pq_p->rx_zero_poll_count = 0;
+					}
+
+					if (ticks - pq_p->rx_poll_ticks < 0 || ticks - pq_p->rx_poll_ticks >= rx_poll_period) {
+						pq_p->min_zero_poll_count = pq_p->avg_poll_activity;
+						if (clickosstat &&
+								clickosstat->cpu_util >= rx_poll_cputhresh &&
+								pq_p->min_zero_poll_count < rx_poll_busyactivity) {
+							pq_p->min_zero_poll_count = rx_poll_busyactivity;
+						}
+						pq_p->rx_poll_sleep = pq_p->avg_poll_sleep;
+						pq_p->rx_poll_ticks = ticks;
+					}
+
+					if (pq_p->rx_poll_sleep < rx_atcp_sleep) {
+						rx_atcp_sleep = pq_p->rx_poll_sleep;
+					}
+				}
+
+				if (nb_mbuf == 0) {
+					pq_p->zero_rx_packet_count++;
+				} else {
+					pq_p->zero_rx_packet_count = 0;
+					for (j = 0; j < nb_mbuf; ++j) {
+						if_dpdk_deliver_frame(sc->ifp, m_pkts[j]);
+					}
+				}
+			}
+
+			mtx_unlock(&queue_bind_map_next_p->map_mtx);
+			thread_idle_counter = 0;
+		}
+	}
 }
 
 int
