]> granicus.if.org Git - esp-idf/commitdiff
lwip: fix socket memory leak issue
authorLiu Zhi Fu <liuzhifu@espressif.com>
Sat, 19 Nov 2016 06:57:42 +0000 (14:57 +0800)
committerLiu Zhi Fu <liuzhifu@espressif.com>
Sat, 19 Nov 2016 06:57:42 +0000 (14:57 +0800)
1. Add socket memory leak debug counter
2. Fix TCP PCB leak issue

components/lwip/api/lwip_debug.c
components/lwip/core/tcp.c
components/lwip/core/tcp_out.c
components/lwip/include/lwip/lwip/lwip_debug.h
components/lwip/include/lwip/lwip/memp.h
components/lwip/include/lwip/lwip/priv/memp_priv.h
components/lwip/include/lwip/port/lwipopts.h

index d73a23e1a3a9ded4d44da4f49b9149a7aa071ad3..08869149a37a6bd622af5fb08642e7796e9cc9a9 100644 (file)
@@ -18,6 +18,8 @@
 #include "lwip/tcp.h"
 #include "lwip/udp.h"
 #include "lwip/priv/tcp_priv.h"
+#include "lwip/priv/memp_priv.h"
+#include "lwip/memp.h"
 
 #define DBG_LWIP_IP_SHOW(info, ip)  printf("%s type=%d ip=%x\n", (info), (ip).type, (ip).u_addr.ip4.addr)
 #define DBG_LWIP_IP_PCB_SHOW(pcb) \
@@ -127,3 +129,22 @@ void dbg_lwip_udp_rxtx_show(void)
     printf("TBC\n");
 }
 
+#if (ESP_CNT_DEBUG == 1)
+
+uint32_t g_lwip_mem_cnt[MEMP_MAX][2];
+extern const struct memp_desc * const memp_pools[MEMP_MAX];
+
+void dbg_lwip_cnt_show(void)
+{
+    int i=0;
+
+    printf("-----lwip memory counter-----\n");
+    printf("%6s %8s %8s\n", "index", "alloc", "free");
+    for (i=0; i<MEMP_MAX; i++){
+        printf("%6u %8u %8u\n", i, g_lwip_mem_cnt[i][0], g_lwip_mem_cnt[i][1]);
+    }
+}
+
+
+#endif
+
index 627df6d293fd234efd05b964289a6a58aad2b5c4..87452f8230c87969493cb33ce19f63fa5773e893 100755 (executable)
@@ -1389,59 +1389,55 @@ tcp_kill_timewait(void)
 }
 
 #if ESP_LWIP
-/**
- * Kills the oldest connection that is in FIN_WAIT_2 state.
- * Called from tcp_alloc() if no more connections are available.
- */
-static void tcp_kill_finwait2(void)
+typedef struct {
+    u8_t time_wait;
+    u8_t closing;
+    u8_t fin_wait2;
+    u8_t last_ack;
+    u8_t listen;
+    u8_t bound;
+    u8_t total;
+}tcp_pcb_num_t;
+
+void tcp_pcb_num_cal(tcp_pcb_num_t *tcp_pcb_num)
 {
-       struct tcp_pcb *pcb, *inactive;
-       u32_t inactivity;
-       /* Go through the list of FIN_WAIT_2 pcbs and get the oldest pcb. */
-       inactivity = 0;
-       inactive = NULL;
-       for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
-               if (pcb->state == FIN_WAIT_2) {
-                       if ((u32_t) (tcp_ticks - pcb->tmr) >= inactivity) {
-                               inactivity = tcp_ticks - pcb->tmr;
-                               inactive = pcb;
-                       }
-               }
-       }
-       if (inactive != NULL) {
-               tcp_pcb_remove(&tcp_active_pcbs, inactive);
-               memp_free(MEMP_TCP_PCB, inactive);
-       }
-}
+    struct tcp_pcb_listen *listen;
+    struct tcp_pcb *pcb;
 
-/**
- * Kills the oldest connection that is in LAST_ACK state.
- * Called from tcp_alloc() if no more connections are available.
- */
-static void tcp_kill_lastack(void)
-{
-       struct tcp_pcb *pcb, *inactive;
-       u32_t inactivity;
-       /* Go through the list of LAST_ACK pcbs and get the oldest pcb. */
-       inactivity = 0;
-       inactive = NULL;
-       for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
-               if (pcb->state == LAST_ACK) {
-                       if ((u32_t) (tcp_ticks - pcb->tmr) >= inactivity) {
-                               inactivity = tcp_ticks - pcb->tmr;
-                               inactive = pcb;
-                       }
-               }
-       }
-       if (inactive != NULL) {
-               tcp_pcb_remove(&tcp_active_pcbs, inactive);
-               memp_free(MEMP_TCP_PCB, inactive);
-       }
+    if (!tcp_pcb_num){
+        return;
+    }
+
+    memset(tcp_pcb_num, 0, sizeof(*tcp_pcb_num));
+    for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
+        tcp_pcb_num->total ++;
+        tcp_pcb_num->time_wait ++;
+    }
+
+    for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next){
+        tcp_pcb_num->total ++;
+        if (pcb->state == FIN_WAIT_2){
+            tcp_pcb_num->fin_wait2 ++;
+        } else if (pcb->state == LAST_ACK) {
+            tcp_pcb_num->last_ack ++;
+        } else if (pcb->state == CLOSING) {
+            tcp_pcb_num->closing ++;
+        }
+    }
+
+    for (pcb = tcp_listen_pcbs.listen_pcbs; pcb != NULL; pcb = pcb->next){
+        tcp_pcb_num->total ++;
+        tcp_pcb_num->listen ++;
+    }
+
+    for (pcb = tcp_bound_pcbs; pcb != NULL; pcb = pcb->next){
+        tcp_pcb_num->total ++;
+        tcp_pcb_num->bound ++;
+    }
 }
 #endif
 
 
-
 /**
  * Allocate a new tcp_pcb structure.
  *
@@ -1455,34 +1451,32 @@ tcp_alloc(u8_t prio)
   u32_t iss;
 
 #if ESP_LWIP
-    /*Kills the oldest connection that is in TIME_WAIT state.*/
-    u8_t time_wait_num = 0;
-    for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
-        time_wait_num ++;
-    }
-
-    if (time_wait_num >= MEMP_NUM_TCP_PCB)
-        tcp_kill_timewait();
-
-    /*Kills the oldest connection that is in FIN_WAIT_2 state.*/
-    time_wait_num = 0;
-    for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next){
-        if (pcb->state == FIN_WAIT_2)
-            time_wait_num ++;
+    tcp_pcb_num_t tcp_pcb_num;
+
+    tcp_pcb_num_cal(&tcp_pcb_num);
+
+    if (tcp_pcb_num.total >= MEMP_NUM_TCP_PCB){
+        if (tcp_pcb_num.time_wait > 0){
+            tcp_kill_timewait();
+        } else if (tcp_pcb_num.last_ack > 0){
+            tcp_kill_state(LAST_ACK);
+        } else if (tcp_pcb_num.closing > 0){
+            tcp_kill_state(CLOSING);
+        } else if (tcp_pcb_num.fin_wait2 > 0){
+            tcp_kill_state(FIN_WAIT_2);//TODO check whether we have issue here?????
+        } else {
+            tcp_kill_prio(prio);
+        }
     }
 
-    if (time_wait_num >= MEMP_NUM_TCP_PCB)
-        tcp_kill_finwait2();
-
-    /*Kills the oldest connection that is in LAST_ACK state.*/
-    time_wait_num = 0;
-    for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next){
-        if (pcb->state == LAST_ACK)
-            time_wait_num ++;
+    tcp_pcb_num_cal(&tcp_pcb_num);
+    if (tcp_pcb_num.total >= MEMP_NUM_TCP_PCB){
+        LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: no available tcp pcb %d %d %d %d %d %d %d\n",
+           tcp_pcb_num.total, tcp_pcb_num.time_wait, tcp_pcb_num.last_ack, tcp_pcb_num.closing,
+           tcp_pcb_num.fin_wait2, tcp_pcb_num.listen, tcp_pcb_num.bound));
+        return NULL;
     }
 
-    if (time_wait_num >= MEMP_NUM_TCP_PCB)
-         tcp_kill_lastack();
 #endif
 
   pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB);
index 35a8aa145da8c3ab142f8fe18554f71dd190d2cd..fbe879124a127393118ff3569bd50d266e9a40fa 100755 (executable)
@@ -176,7 +176,8 @@ tcp_create_segment(struct tcp_pcb *pcb, struct pbuf *p, u8_t flags, u32_t seqno,
   struct tcp_seg *seg;
   u8_t optlen = LWIP_TCP_OPT_LENGTH(optflags);
 
-  if ((seg = (struct tcp_seg *)memp_malloc(MEMP_TCP_SEG)) == NULL) {
+  seg = (struct tcp_seg *)memp_malloc(MEMP_TCP_SEG);
+  if (seg == NULL) {
     LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("tcp_create_segment: no memory.\n"));
     pbuf_free(p);
     return NULL;
index abfcd2c1c3a16ea5446c0ab3bfa7d799a01def3a..4da520269aeef829055c3fca93bdf35652f4ca9c 100644 (file)
@@ -20,5 +20,6 @@ void dbg_lwip_tcp_pcb_show(void);
 void dbg_lwip_udp_pcb_show(void);
 void dbg_lwip_tcp_rxtx_show(void);
 void dbg_lwip_udp_rxtx_show(void);
+void dbg_lwip_mem_cnt_show(void);
 
 #endif
index d7463f2b33986c250a2fc5f29f8bde6c7b807e43..bc9b021e87f37e89f5bec94e8709175ee9509c86 100755 (executable)
@@ -71,8 +71,8 @@ extern const struct memp_desc* const memp_pools[MEMP_MAX];
 #include "lwip/mem.h"
 
 #define memp_init()
-#define memp_malloc(type)     mem_malloc(memp_pools[type]->size)
-#define memp_free(type, mem)  mem_free(mem)
+#define memp_malloc(type)     mem_malloc(memp_pools[type]->size); ESP_CNT_MEM_MALLOC_INC(type)
+#define memp_free(type, mem)  mem_free(mem); ESP_CNT_MEM_FREE_INC(type)
 
 #define LWIP_MEMPOOL_DECLARE(name,num,size,desc) \
   const struct memp_desc memp_ ## name = { \
index 34edb9d9719569c3baa276c696edacdb203f6541..7bfa94d789e6363bc17e384d251d7992f10d25a9 100755 (executable)
@@ -140,6 +140,16 @@ struct memp_desc {
 #endif /* MEMP_MEM_MALLOC */
 };
 
+#if (ESP_CNT_DEBUG == 1)
+extern uint32_t g_lwip_mem_cnt[MEMP_MAX][2];
+#define ESP_CNT_MEM_MALLOC_INC(type)  g_lwip_mem_cnt[type][0]++
+#define ESP_CNT_MEM_FREE_INC(type)    g_lwip_mem_cnt[type][1]++
+#else
+#define ESP_CNT_MEM_MALLOC_INC(type)
+#define ESP_CNT_MEM_FREE_INC(type)
+#endif
+
+
 #ifdef LWIP_DEBUG
 #define DECLARE_LWIP_MEMPOOL_DESC(desc) (desc),
 #else
index 26bdc3a4e90d7ffb99660e8960272ab5c50201cd..c32aca7273ba90c3506a97dbc1f184a7be243b06 100755 (executable)
@@ -526,6 +526,7 @@ extern unsigned long os_random(void);
 #define ESP_IP4_ATON                    1
 #define ESP_LIGHT_SLEEP                 1
 #define ESP_L2_TO_L3_COPY               CONFIG_L2_TO_L3_COPY
+#define ESP_CNT_DEBUG                   0
 
 #define TCP_WND_DEFAULT                      (4*TCP_MSS)
 #define TCP_SND_BUF_DEFAULT                  (2*TCP_MSS)