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:
parent
1af78b07a7
commit
7eaacdaca6
3 changed files with 41 additions and 0 deletions
|
@ -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) {
|
if (conn->unacked_len) {
|
||||||
subscribe = true;
|
subscribe = true;
|
||||||
}
|
}
|
||||||
|
@ -1140,6 +1144,8 @@ static void tcp_resend_data(struct k_work *work)
|
||||||
conn->data_mode = TCP_DATA_MODE_RESEND;
|
conn->data_mode = TCP_DATA_MODE_RESEND;
|
||||||
conn->unacked_len = 0;
|
conn->unacked_len = 0;
|
||||||
|
|
||||||
|
(void)k_sem_take(&conn->tx_sem, K_NO_WAIT);
|
||||||
|
|
||||||
ret = tcp_send_data(conn);
|
ret = tcp_send_data(conn);
|
||||||
conn->send_data_retries++;
|
conn->send_data_retries++;
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
|
@ -1163,6 +1169,11 @@ static void tcp_resend_data(struct k_work *work)
|
||||||
}
|
}
|
||||||
} else if (ret == -ENODATA) {
|
} else if (ret == -ENODATA) {
|
||||||
conn->data_mode = TCP_DATA_MODE_SEND;
|
conn->data_mode = TCP_DATA_MODE_SEND;
|
||||||
|
|
||||||
|
if (!tcp_window_full(conn)) {
|
||||||
|
k_sem_give(&conn->tx_sem);
|
||||||
|
}
|
||||||
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1253,6 +1264,7 @@ static struct tcp *tcp_conn_alloc(struct net_context *context)
|
||||||
k_mutex_init(&conn->lock);
|
k_mutex_init(&conn->lock);
|
||||||
k_fifo_init(&conn->recv_data);
|
k_fifo_init(&conn->recv_data);
|
||||||
k_sem_init(&conn->connect_sem, 0, K_SEM_MAX_LIMIT);
|
k_sem_init(&conn->connect_sem, 0, K_SEM_MAX_LIMIT);
|
||||||
|
k_sem_init(&conn->tx_sem, 1, 1);
|
||||||
|
|
||||||
conn->in_connect = false;
|
conn->in_connect = false;
|
||||||
conn->state = TCP_LISTEN;
|
conn->state = TCP_LISTEN;
|
||||||
|
@ -1822,6 +1834,12 @@ static void tcp_in(struct tcp *conn, struct net_pkt *pkt)
|
||||||
|
|
||||||
conn->send_win = max_win;
|
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:
|
next_state:
|
||||||
|
@ -1968,6 +1986,11 @@ next_state:
|
||||||
} else {
|
} else {
|
||||||
conn->unacked_len -= len_acked;
|
conn->unacked_len -= len_acked;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!tcp_window_full(conn)) {
|
||||||
|
k_sem_give(&conn->tx_sem);
|
||||||
|
}
|
||||||
|
|
||||||
conn_seq(conn, + len_acked);
|
conn_seq(conn, + len_acked);
|
||||||
net_stats_update_tcp_seg_recv(conn->iface);
|
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);
|
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)
|
void net_tcp_init(void)
|
||||||
{
|
{
|
||||||
#if defined(CONFIG_NET_TEST_PROTOCOL)
|
#if defined(CONFIG_NET_TEST_PROTOCOL)
|
||||||
|
|
|
@ -367,6 +367,16 @@ void net_tcp_init(void);
|
||||||
#define net_tcp_init(...)
|
#define net_tcp_init(...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Obtain a semaphore indicating if transfers are blocked (either due to
|
||||||
|
* filling TX window or entering retransmission mode).
|
||||||
|
*
|
||||||
|
* @param context Network context
|
||||||
|
*
|
||||||
|
* @return semaphore indicating if transfers are blocked
|
||||||
|
*/
|
||||||
|
struct k_sem *net_tcp_tx_sem_get(struct net_context *context);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -234,6 +234,7 @@ struct tcp { /* TCP connection */
|
||||||
};
|
};
|
||||||
struct k_mutex lock;
|
struct k_mutex lock;
|
||||||
struct k_sem connect_sem; /* semaphore for blocking connect */
|
struct k_sem connect_sem; /* semaphore for blocking connect */
|
||||||
|
struct k_sem tx_sem; /* Semaphore indicating if transfers are blocked . */
|
||||||
struct k_fifo recv_data; /* temp queue before passing data to app */
|
struct k_fifo recv_data; /* temp queue before passing data to app */
|
||||||
struct tcp_options recv_options;
|
struct tcp_options recv_options;
|
||||||
struct tcp_options send_options;
|
struct tcp_options send_options;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue