loopif: only schedule poll when first packet is enqueued

This optimizes the netif_loop_output to only schedule a call to poll when
the first packet is enqueued. This ensures netif_poll is ran once per
burst of packets that are sent (which is typical in a TCP transfer)

The old behavior scheduled a call to poll for every packet that was
enqueued and this lead to exhaustion of the MEMP_TCPIP_MSG_API memory pool
and tcpip_mbox (if port is using static mbox size). The extra callbacks are
wasted work because netif_poll drains the entire queue when ran

This issue presented itself when large TCP transfer go across the loopback
netif
This commit is contained in:
Joel Cunningham 2018-04-27 17:42:30 -05:00
parent 070e449690
commit ffaee59f3e

View File

@ -1060,6 +1060,9 @@ netif_loop_output(struct netif *netif, struct pbuf *p)
struct netif *stats_if = netif;
#endif /* LWIP_HAVE_LOOPIF */
#endif /* MIB2_STATS */
#if LWIP_NETIF_LOOPBACK_MULTITHREADING
u8_t schedule_poll = 0;
#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */
SYS_ARCH_DECL_PROTECT(lev);
/* Allocate a new pbuf */
@ -1109,6 +1112,10 @@ netif_loop_output(struct netif *netif, struct pbuf *p)
} else {
netif->loop_first = r;
netif->loop_last = last;
#if LWIP_NETIF_LOOPBACK_MULTITHREADING
/* No existing packets queued, schedule poll */
schedule_poll = 1;
#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */
}
SYS_ARCH_UNPROTECT(lev);
@ -1118,7 +1125,9 @@ netif_loop_output(struct netif *netif, struct pbuf *p)
#if LWIP_NETIF_LOOPBACK_MULTITHREADING
/* For multithreading environment, schedule a call to netif_poll */
tcpip_try_callback((tcpip_callback_fn)netif_poll, netif);
if (schedule_poll) {
tcpip_try_callback((tcpip_callback_fn)netif_poll, netif);
}
#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */
return ERR_OK;