Skip to content

Commit cf46ba8

Browse files
committed
feat(lwip): Add socket UDP sync function
1 parent 8af3aa5 commit cf46ba8

File tree

7 files changed

+277
-0
lines changed

7 files changed

+277
-0
lines changed

components/lwip/Kconfig

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,23 @@ config LWIP_SOCKET_MULTITHREAD
2727
Enable the option can enable LWIP socket multithread and all
2828
function will be thread safe.
2929

30+
config ESP_UDP_SYNC_SEND
31+
bool "LWIP socket UDP sync send"
32+
default y
33+
help
34+
Enable the option can enable LWIP socket UDP sync send. CPU cost
35+
should decrease but memory cost increase and it can make UDP
36+
throughput increase a lot.
37+
38+
config ESP_UDP_SYNC_RETRY_MAX
39+
int "LWIP socket UDP sync send retry max count"
40+
range 1 10
41+
default 5
42+
depends on ESP_UDP_SYNC_SEND
43+
help
44+
When UDP sync send count reaches the value, then the packet should
45+
be lost and LWIP core thread wake up the up-level send thread.
46+
3047
config LWIP_MAX_SOCKETS
3148
int "Max number of open sockets"
3249
range 1 16

components/lwip/lwip/src/api/api_msg.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1409,6 +1409,9 @@ lwip_netconn_do_send(void *m)
14091409
#endif
14101410
#if LWIP_UDP
14111411
case NETCONN_UDP:
1412+
#if ESP_UDP
1413+
udp_sync_regitser(msg);
1414+
#endif /* ESP_UDP */
14121415
#if LWIP_CHECKSUM_ON_COPY
14131416
if (ip_addr_isany(&msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) {
14141417
msg->err = udp_send_chksum(msg->conn->pcb.udp, msg->msg.b->p,
@@ -1432,7 +1435,11 @@ lwip_netconn_do_send(void *m)
14321435
}
14331436
}
14341437
}
1438+
#if ESP_UDP
1439+
udp_sync_ack(msg);
1440+
#else
14351441
TCPIP_APIMSG_ACK(msg);
1442+
#endif /* ESP_UDP */
14361443
}
14371444

14381445
#if LWIP_TCP

components/lwip/lwip/src/core/timeouts.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,10 @@ sys_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg)
415415
extern void send_from_list();
416416
send_from_list();
417417

418+
#if ESP_UDP
419+
udp_sync_proc();
420+
#endif
421+
418422
sleeptime = sys_timeouts_sleeptime();
419423
if (sleeptime == 0 || sys_arch_mbox_fetch(mbox, msg, sleeptime) == SYS_ARCH_TIMEOUT) {
420424
/* If a SYS_ARCH_TIMEOUT value is returned, a timeout occurred
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include <stddef.h>
16+
#include <string.h>
17+
#include <stdbool.h>
18+
#include <sys/errno.h>
19+
#include "lwip/udp.h"
20+
#include "lwip/priv/api_msg.h"
21+
#include "lwip/priv/tcp_priv.h"
22+
23+
#include "esp_log.h"
24+
25+
#if ESP_UDP
26+
27+
#define UDP_SYNC_MAX MEMP_NUM_NETCONN
28+
#define UDP_SYNC_RETRY_MAX CONFIG_ESP_UDP_SYNC_RETRY_MAX
29+
30+
/*
31+
* All function has no mutex, so they must put into one task(LWIP main task).
32+
*/
33+
34+
#if LWIP_TCPIP_CORE_LOCKING
35+
#define TCPIP_APIMSG_ACK(m) NETCONN_SET_SAFE_ERR((m)->conn, (m)->err)
36+
#else /* LWIP_TCPIP_CORE_LOCKING */
37+
#define TCPIP_APIMSG_ACK(m) do { NETCONN_SET_SAFE_ERR((m)->conn, (m)->err); sys_sem_signal(LWIP_API_MSG_SEM(m)); } while(0)
38+
#endif /* LWIP_TCPIP_CORE_LOCKING */
39+
40+
typedef struct udp_sync {
41+
struct api_msg *msg;
42+
43+
int ret;
44+
45+
int retry;
46+
} udp_sync_t;
47+
48+
static const char *TAG = "udp_sync";
49+
static size_t s_udp_sync_num;
50+
static udp_sync_t s_udp_sync[UDP_SYNC_MAX];
51+
static bool s_register_locked;
52+
static struct api_msg *s_cur_msg;
53+
54+
/*
55+
* @brief initialize UDP sync module
56+
*/
57+
void udp_sync_init(void)
58+
{
59+
memset(s_udp_sync, 0, sizeof(s_udp_sync));
60+
s_register_locked = false;
61+
s_udp_sync_num = 0;
62+
}
63+
64+
/*
65+
* @brief register a UDP API message(struct api_msg) to module
66+
*/
67+
void udp_sync_regitser(void *in_msg)
68+
{
69+
s_cur_msg = in_msg;
70+
71+
if (s_register_locked == true)
72+
return ;
73+
74+
struct api_msg *msg = (struct api_msg *)in_msg;
75+
int s = msg->conn->socket;
76+
77+
if (s < 0 || s >= UDP_SYNC_MAX) {
78+
ESP_LOGE(TAG, "UDP sync register error, socket is %d", s);
79+
return ;
80+
} else if (s_udp_sync[s].msg) {
81+
ESP_LOGE(TAG, "UDP sync register error, msg is %p", s_udp_sync[s].msg);
82+
return ;
83+
}
84+
85+
s_udp_sync_num++;
86+
s_udp_sync[s].ret = ERR_OK;
87+
s_udp_sync[s].retry = 0;
88+
s_udp_sync[s].msg = msg;
89+
}
90+
91+
/*
92+
* @brief ack the message
93+
*/
94+
void udp_sync_ack(void *in_msg)
95+
{
96+
struct api_msg *msg = (struct api_msg *)in_msg;
97+
int s = msg->conn->socket;
98+
99+
if (s < 0 || s >= UDP_SYNC_MAX) {
100+
ESP_LOGE(TAG, "UDP sync ack error, socket is %d", s);
101+
return ;
102+
} else if (!s_udp_sync[s].msg) {
103+
ESP_LOGE(TAG, "UDP sync ack error, msg is NULL");
104+
return ;
105+
}
106+
107+
/* Only cache when low-level has no buffer to send packet */
108+
if (s_udp_sync[s].ret != ERR_MEM || s_udp_sync[s].retry >= UDP_SYNC_RETRY_MAX) {
109+
s_udp_sync[s].msg = NULL;
110+
s_udp_sync[s].retry = 0;
111+
s_udp_sync[s].ret = ERR_OK;
112+
s_udp_sync_num--;
113+
114+
/* Todo: return real result */
115+
msg->err = ESP_OK;
116+
117+
TCPIP_APIMSG_ACK(msg);
118+
} else {
119+
s_udp_sync[s].retry++;
120+
ESP_LOGD(TAG, "UDP sync ack error, errno %d", s_udp_sync[s].ret);
121+
}
122+
123+
s_cur_msg = NULL;
124+
}
125+
126+
/*
127+
* @brief set the current message send result
128+
*/
129+
void udp_sync_set_ret(int ret)
130+
{
131+
/* Only poll and regitser can set current message */
132+
if (!s_cur_msg) {
133+
/* You may use it to debug */
134+
//ESP_LOGE(TAG, "UDP sync ack error, current message is NULL");
135+
return ;
136+
}
137+
138+
struct api_msg *msg = s_cur_msg;
139+
int s = msg->conn->socket;
140+
141+
if (s < 0 || s >= UDP_SYNC_MAX) {
142+
ESP_LOGE(TAG, "UDP sync ack error, socket is %d", s);
143+
return ;
144+
} else if (!s_udp_sync[s].msg) {
145+
ESP_LOGE(TAG, "UDP sync ack error, msg is NULL");
146+
return ;
147+
}
148+
149+
s_udp_sync[s].ret = ret;
150+
}
151+
152+
/*
153+
* @brief process the sync
154+
*/
155+
void udp_sync_proc(void)
156+
{
157+
if (!s_udp_sync_num)
158+
return ;
159+
160+
s_register_locked = true;
161+
for (int i = 0; i < UDP_SYNC_MAX; i++) {
162+
if (!s_udp_sync[i].msg)
163+
continue;
164+
165+
lwip_netconn_do_send(s_udp_sync[i].msg);
166+
#if 0
167+
//Todo: Add this later
168+
if (s_udp_sync[i].ret != ERR_OK)
169+
break;
170+
#endif
171+
}
172+
s_register_locked = false;
173+
}
174+
175+
#endif /* ESP_UDP */

components/lwip/port/esp8266/include/lwipopts.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@
5252

5353
#define ESP_LWIP 1
5454

55+
#ifdef CONFIG_ESP_UDP_SYNC_SEND
56+
#define ESP_UDP 1
57+
#endif
58+
5559
#ifdef CONFIG_LWIP_SOCKET_MULTITHREAD
5660
#define SOCKETS_MT
5761
#endif
@@ -2213,4 +2217,12 @@ void *memp_malloc_ll(size_t type);
22132217
* @}
22142218
*/
22152219

2220+
#if ESP_UDP
2221+
#if !LWIP_UDP || !LWIP_SOCKET || !ESP_LWIP
2222+
#error "LWIP_UDP & LWIP_SOCKET & ESP_LWIP must be enable"
2223+
#else
2224+
#include "udp_sync.h"
2225+
#endif
2226+
#endif
2227+
22162228
#endif /* __LWIP_HDR_LWIPOPTS_H__ */
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#ifndef _UDP_SYNC_H
16+
#define _UDP_SYNC_H
17+
18+
#ifdef __cplusplus
19+
extern "C" {
20+
#endif
21+
22+
/*
23+
* @brief initialize UDP sync module
24+
*/
25+
void udp_sync_init(void);
26+
27+
/*
28+
* @brief register a UDP API message(struct api_msg) to module
29+
*
30+
* @param in_msg message pointer
31+
*/
32+
void udp_sync_regitser(void *in_msg);
33+
34+
/*
35+
* @brief ack the message
36+
*
37+
* @param in_msg message pointer
38+
*/
39+
void udp_sync_ack(void *in_msg);
40+
41+
/*
42+
* @brief set the current message send result
43+
*
44+
* @param ret current message send result
45+
*/
46+
void udp_sync_set_ret(int ret);
47+
48+
/*
49+
* @brief process the sync
50+
*
51+
* @param ret current message send result
52+
*/
53+
void udp_sync_proc(void);
54+
55+
#ifdef __cplusplus
56+
}
57+
#endif
58+
59+
#endif /* _UDP_SYNC_H */

components/lwip/port/esp8266/netif/ethernetif.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,9 @@ static int8_t low_level_output(struct netif* netif, struct pbuf* p)
302302
* header, meaning we should not pass target low-level address here.
303303
*/
304304
err = esp_aio_sendto(&aio, NULL, 0);
305+
#if ESP_UDP
306+
udp_sync_set_ret(err);
307+
#endif
305308
if (err != ERR_OK) {
306309
if (err == ERR_MEM){
307310
insert_to_list(aio.fd, p);

0 commit comments

Comments
 (0)