From cf46ba82be75b51b4bad1e9247e6ef0219f27825 Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Thu, 26 Jul 2018 14:28:33 +0800 Subject: [PATCH] feat(lwip): Add socket UDP sync function --- components/lwip/Kconfig | 17 ++ components/lwip/lwip/src/api/api_msg.c | 7 + components/lwip/lwip/src/core/timeouts.c | 4 + .../lwip/port/esp8266/freertos/udp_sync.c | 175 ++++++++++++++++++ .../lwip/port/esp8266/include/lwipopts.h | 12 ++ .../lwip/port/esp8266/include/udp_sync.h | 59 ++++++ .../lwip/port/esp8266/netif/ethernetif.c | 3 + 7 files changed, 277 insertions(+) create mode 100644 components/lwip/port/esp8266/freertos/udp_sync.c create mode 100644 components/lwip/port/esp8266/include/udp_sync.h diff --git a/components/lwip/Kconfig b/components/lwip/Kconfig index 39da85f4..90006e03 100644 --- a/components/lwip/Kconfig +++ b/components/lwip/Kconfig @@ -27,6 +27,23 @@ config LWIP_SOCKET_MULTITHREAD Enable the option can enable LWIP socket multithread and all function will be thread safe. +config ESP_UDP_SYNC_SEND + bool "LWIP socket UDP sync send" + default y + help + Enable the option can enable LWIP socket UDP sync send. CPU cost + should decrease but memory cost increase and it can make UDP + throughput increase a lot. + +config ESP_UDP_SYNC_RETRY_MAX + int "LWIP socket UDP sync send retry max count" + range 1 10 + default 5 + depends on ESP_UDP_SYNC_SEND + help + When UDP sync send count reaches the value, then the packet should + be lost and LWIP core thread wake up the up-level send thread. + config LWIP_MAX_SOCKETS int "Max number of open sockets" range 1 16 diff --git a/components/lwip/lwip/src/api/api_msg.c b/components/lwip/lwip/src/api/api_msg.c index 5a8dad9b..f8143323 100644 --- a/components/lwip/lwip/src/api/api_msg.c +++ b/components/lwip/lwip/src/api/api_msg.c @@ -1409,6 +1409,9 @@ lwip_netconn_do_send(void *m) #endif #if LWIP_UDP case NETCONN_UDP: +#if ESP_UDP + udp_sync_regitser(msg); +#endif /* ESP_UDP */ #if LWIP_CHECKSUM_ON_COPY if (ip_addr_isany(&msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) { msg->err = udp_send_chksum(msg->conn->pcb.udp, msg->msg.b->p, @@ -1432,7 +1435,11 @@ lwip_netconn_do_send(void *m) } } } +#if ESP_UDP + udp_sync_ack(msg); +#else TCPIP_APIMSG_ACK(msg); +#endif /* ESP_UDP */ } #if LWIP_TCP diff --git a/components/lwip/lwip/src/core/timeouts.c b/components/lwip/lwip/src/core/timeouts.c index 2e0ec540..6d64ac48 100644 --- a/components/lwip/lwip/src/core/timeouts.c +++ b/components/lwip/lwip/src/core/timeouts.c @@ -415,6 +415,10 @@ again: extern void send_from_list(); send_from_list(); +#if ESP_UDP + udp_sync_proc(); +#endif + sleeptime = sys_timeouts_sleeptime(); if (sleeptime == 0 || sys_arch_mbox_fetch(mbox, msg, sleeptime) == SYS_ARCH_TIMEOUT) { /* If a SYS_ARCH_TIMEOUT value is returned, a timeout occurred diff --git a/components/lwip/port/esp8266/freertos/udp_sync.c b/components/lwip/port/esp8266/freertos/udp_sync.c new file mode 100644 index 00000000..8ddc8458 --- /dev/null +++ b/components/lwip/port/esp8266/freertos/udp_sync.c @@ -0,0 +1,175 @@ +// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include "lwip/udp.h" +#include "lwip/priv/api_msg.h" +#include "lwip/priv/tcp_priv.h" + +#include "esp_log.h" + +#if ESP_UDP + +#define UDP_SYNC_MAX MEMP_NUM_NETCONN +#define UDP_SYNC_RETRY_MAX CONFIG_ESP_UDP_SYNC_RETRY_MAX + +/* + * All function has no mutex, so they must put into one task(LWIP main task). + */ + +#if LWIP_TCPIP_CORE_LOCKING +#define TCPIP_APIMSG_ACK(m) NETCONN_SET_SAFE_ERR((m)->conn, (m)->err) +#else /* LWIP_TCPIP_CORE_LOCKING */ +#define TCPIP_APIMSG_ACK(m) do { NETCONN_SET_SAFE_ERR((m)->conn, (m)->err); sys_sem_signal(LWIP_API_MSG_SEM(m)); } while(0) +#endif /* LWIP_TCPIP_CORE_LOCKING */ + +typedef struct udp_sync { + struct api_msg *msg; + + int ret; + + int retry; +} udp_sync_t; + +static const char *TAG = "udp_sync"; +static size_t s_udp_sync_num; +static udp_sync_t s_udp_sync[UDP_SYNC_MAX]; +static bool s_register_locked; +static struct api_msg *s_cur_msg; + +/* + * @brief initialize UDP sync module + */ +void udp_sync_init(void) +{ + memset(s_udp_sync, 0, sizeof(s_udp_sync)); + s_register_locked = false; + s_udp_sync_num = 0; +} + +/* + * @brief register a UDP API message(struct api_msg) to module + */ +void udp_sync_regitser(void *in_msg) +{ + s_cur_msg = in_msg; + + if (s_register_locked == true) + return ; + + struct api_msg *msg = (struct api_msg *)in_msg; + int s = msg->conn->socket; + + if (s < 0 || s >= UDP_SYNC_MAX) { + ESP_LOGE(TAG, "UDP sync register error, socket is %d", s); + return ; + } else if (s_udp_sync[s].msg) { + ESP_LOGE(TAG, "UDP sync register error, msg is %p", s_udp_sync[s].msg); + return ; + } + + s_udp_sync_num++; + s_udp_sync[s].ret = ERR_OK; + s_udp_sync[s].retry = 0; + s_udp_sync[s].msg = msg; +} + +/* + * @brief ack the message + */ +void udp_sync_ack(void *in_msg) +{ + struct api_msg *msg = (struct api_msg *)in_msg; + int s = msg->conn->socket; + + if (s < 0 || s >= UDP_SYNC_MAX) { + ESP_LOGE(TAG, "UDP sync ack error, socket is %d", s); + return ; + } else if (!s_udp_sync[s].msg) { + ESP_LOGE(TAG, "UDP sync ack error, msg is NULL"); + return ; + } + + /* Only cache when low-level has no buffer to send packet */ + if (s_udp_sync[s].ret != ERR_MEM || s_udp_sync[s].retry >= UDP_SYNC_RETRY_MAX) { + s_udp_sync[s].msg = NULL; + s_udp_sync[s].retry = 0; + s_udp_sync[s].ret = ERR_OK; + s_udp_sync_num--; + + /* Todo: return real result */ + msg->err = ESP_OK; + + TCPIP_APIMSG_ACK(msg); + } else { + s_udp_sync[s].retry++; + ESP_LOGD(TAG, "UDP sync ack error, errno %d", s_udp_sync[s].ret); + } + + s_cur_msg = NULL; +} + +/* + * @brief set the current message send result + */ +void udp_sync_set_ret(int ret) +{ + /* Only poll and regitser can set current message */ + if (!s_cur_msg) { + /* You may use it to debug */ + //ESP_LOGE(TAG, "UDP sync ack error, current message is NULL"); + return ; + } + + struct api_msg *msg = s_cur_msg; + int s = msg->conn->socket; + + if (s < 0 || s >= UDP_SYNC_MAX) { + ESP_LOGE(TAG, "UDP sync ack error, socket is %d", s); + return ; + } else if (!s_udp_sync[s].msg) { + ESP_LOGE(TAG, "UDP sync ack error, msg is NULL"); + return ; + } + + s_udp_sync[s].ret = ret; +} + +/* + * @brief process the sync + */ +void udp_sync_proc(void) +{ + if (!s_udp_sync_num) + return ; + + s_register_locked = true; + for (int i = 0; i < UDP_SYNC_MAX; i++) { + if (!s_udp_sync[i].msg) + continue; + + lwip_netconn_do_send(s_udp_sync[i].msg); +#if 0 + //Todo: Add this later + if (s_udp_sync[i].ret != ERR_OK) + break; +#endif + } + s_register_locked = false; +} + +#endif /* ESP_UDP */ diff --git a/components/lwip/port/esp8266/include/lwipopts.h b/components/lwip/port/esp8266/include/lwipopts.h index a802ec23..97da94dc 100644 --- a/components/lwip/port/esp8266/include/lwipopts.h +++ b/components/lwip/port/esp8266/include/lwipopts.h @@ -52,6 +52,10 @@ #define ESP_LWIP 1 +#ifdef CONFIG_ESP_UDP_SYNC_SEND +#define ESP_UDP 1 +#endif + #ifdef CONFIG_LWIP_SOCKET_MULTITHREAD #define SOCKETS_MT #endif @@ -2213,4 +2217,12 @@ void *memp_malloc_ll(size_t type); * @} */ +#if ESP_UDP +#if !LWIP_UDP || !LWIP_SOCKET || !ESP_LWIP +#error "LWIP_UDP & LWIP_SOCKET & ESP_LWIP must be enable" +#else +#include "udp_sync.h" +#endif +#endif + #endif /* __LWIP_HDR_LWIPOPTS_H__ */ diff --git a/components/lwip/port/esp8266/include/udp_sync.h b/components/lwip/port/esp8266/include/udp_sync.h new file mode 100644 index 00000000..29184fbf --- /dev/null +++ b/components/lwip/port/esp8266/include/udp_sync.h @@ -0,0 +1,59 @@ +// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef _UDP_SYNC_H +#define _UDP_SYNC_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * @brief initialize UDP sync module + */ +void udp_sync_init(void); + +/* + * @brief register a UDP API message(struct api_msg) to module + * + * @param in_msg message pointer + */ +void udp_sync_regitser(void *in_msg); + +/* + * @brief ack the message + * + * @param in_msg message pointer + */ +void udp_sync_ack(void *in_msg); + +/* + * @brief set the current message send result + * + * @param ret current message send result + */ +void udp_sync_set_ret(int ret); + +/* + * @brief process the sync + * + * @param ret current message send result + */ +void udp_sync_proc(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _UDP_SYNC_H */ diff --git a/components/lwip/port/esp8266/netif/ethernetif.c b/components/lwip/port/esp8266/netif/ethernetif.c index e9c5c185..45a7a5d6 100644 --- a/components/lwip/port/esp8266/netif/ethernetif.c +++ b/components/lwip/port/esp8266/netif/ethernetif.c @@ -302,6 +302,9 @@ static int8_t low_level_output(struct netif* netif, struct pbuf* p) * header, meaning we should not pass target low-level address here. */ err = esp_aio_sendto(&aio, NULL, 0); +#if ESP_UDP + udp_sync_set_ret(err); +#endif if (err != ERR_OK) { if (err == ERR_MEM){ insert_to_list(aio.fd, p);