net: tcp: Add semaphore indicating if transfer is possible

The semaphore is reset when TCP layer would normally reject transfer
request (either due to TX window being full or entering retransmission
mode). Once data is acnowledged, or the reatransmission is done, the
semaphore is set again.

Upper layers can monitor the semaphore with `k_poll()` instead of
waiting blindly before attempting to transmit again.

Signed-off-by: Robert Lubos <robert.lubos@nordicsemi.no>
This commit is contained in:
Robert Lubos 2022-05-10 10:17:36 +02:00 committed by Carles Cufí
commit 7eaacdaca6
3 changed files with 41 additions and 0 deletions

View file

@ -1078,6 +1078,10 @@ static int tcp_send_queued_data(struct tcp *conn)
}
}
if (tcp_window_full(conn)) {
(void)k_sem_take(&conn->tx_sem, K_NO_WAIT);
}
if (conn->unacked_len) {
subscribe = true;
}
@ -1140,6 +1144,8 @@ static void tcp_resend_data(struct k_work *work)
conn->data_mode = TCP_DATA_MODE_RESEND;
conn->unacked_len = 0;
(void)k_sem_take(&conn->tx_sem, K_NO_WAIT);
ret = tcp_send_data(conn);
conn->send_data_retries++;
if (ret == 0) {
@ -1163,6 +1169,11 @@ static void tcp_resend_data(struct k_work *work)
}
} else if (ret == -ENODATA) {
conn->data_mode = TCP_DATA_MODE_SEND;
if (!tcp_window_full(conn)) {
k_sem_give(&conn->tx_sem);
}
goto out;
}
@ -1253,6 +1264,7 @@ static struct tcp *tcp_conn_alloc(struct net_context *context)
k_mutex_init(&conn->lock);
k_fifo_init(&conn->recv_data);
k_sem_init(&conn->connect_sem, 0, K_SEM_MAX_LIMIT);
k_sem_init(&conn->tx_sem, 1, 1);
conn->in_connect = false;
conn->state = TCP_LISTEN;
@ -1822,6 +1834,12 @@ static void tcp_in(struct tcp *conn, struct net_pkt *pkt)
conn->send_win = max_win;
}
if (tcp_window_full(conn)) {
(void)k_sem_take(&conn->tx_sem, K_NO_WAIT);
} else {
k_sem_give(&conn->tx_sem);
}
}
next_state:
@ -1968,6 +1986,11 @@ next_state:
} else {
conn->unacked_len -= len_acked;
}
if (!tcp_window_full(conn)) {
k_sem_give(&conn->tx_sem);
}
conn_seq(conn, + len_acked);
net_stats_update_tcp_seg_recv(conn->iface);
@ -2908,6 +2931,13 @@ const char *net_tcp_state_str(enum tcp_state state)
return tcp_state_to_str(state, false);
}
struct k_sem *net_tcp_tx_sem_get(struct net_context *context)
{
struct tcp *conn = context->tcp;
return &conn->tx_sem;
}
void net_tcp_init(void)
{
#if defined(CONFIG_NET_TEST_PROTOCOL)