mirror of
https://github.com/lwip-tcpip/lwip.git
synced 2025-04-16 08:43:17 +00:00
Fixed bug #28064: pbuf_alloc(PBUF_POOL) is not thread-safe by queueing a call into tcpip_thread to free ooseq-bufs if the pool is empty
This commit is contained in:
parent
902ad897b8
commit
aeef0a21f3
@ -46,6 +46,10 @@ HISTORY
|
|||||||
|
|
||||||
++ Bugfixes:
|
++ Bugfixes:
|
||||||
|
|
||||||
|
2009-11-29: Simon Goldschmidt
|
||||||
|
* pbuf.c: Fixed bug #28064: pbuf_alloc(PBUF_POOL) is not thread-safe by
|
||||||
|
queueing a call into tcpip_thread to free ooseq-bufs if the pool is empty
|
||||||
|
|
||||||
2009-11-26: Simon Goldschmidt
|
2009-11-26: Simon Goldschmidt
|
||||||
* tcp.h: Fixed bug #28098: Nagle can prevent fast retransmit from sending
|
* tcp.h: Fixed bug #28098: Nagle can prevent fast retransmit from sending
|
||||||
segment
|
segment
|
||||||
|
@ -81,41 +81,71 @@
|
|||||||
aligned there. Therefore, PBUF_POOL_BUFSIZE_ALIGNED can be used here. */
|
aligned there. Therefore, PBUF_POOL_BUFSIZE_ALIGNED can be used here. */
|
||||||
#define PBUF_POOL_BUFSIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE)
|
#define PBUF_POOL_BUFSIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE)
|
||||||
|
|
||||||
#if TCP_QUEUE_OOSEQ
|
#if !TCP_QUEUE_OOSEQ || NO_SYS
|
||||||
#define ALLOC_POOL_PBUF(p) do { (p) = alloc_pool_pbuf(); } while (0)
|
#define PBUF_POOL_IS_EMPTY()
|
||||||
#else
|
#else /* !TCP_QUEUE_OOSEQ || NO_SYS */
|
||||||
#define ALLOC_POOL_PBUF(p) do { (p) = memp_malloc(MEMP_PBUF_POOL); } while (0)
|
/** Define this to 0 to prevent freeing ooseq pbufs when the PBUF_POOL is empty */
|
||||||
#endif
|
#ifndef PBUF_POOL_FREE_OOSEQ
|
||||||
|
#define PBUF_POOL_FREE_OOSEQ 1
|
||||||
|
#endif /* PBUF_POOL_FREE_OOSEQ */
|
||||||
|
|
||||||
|
#if PBUF_POOL_FREE_OOSEQ
|
||||||
#if TCP_QUEUE_OOSEQ
|
#include "lwip/tcpip.h"
|
||||||
|
#define PBUF_POOL_IS_EMPTY() pbuf_pool_is_empty()
|
||||||
|
static u8_t pbuf_free_ooseq_queued;
|
||||||
/**
|
/**
|
||||||
* Attempt to reclaim some memory from queued out-of-sequence TCP segments
|
* Attempt to reclaim some memory from queued out-of-sequence TCP segments
|
||||||
* if we run out of pool pbufs. It's better to give priority to new packets
|
* if we run out of pool pbufs. It's better to give priority to new packets
|
||||||
* if we're running out.
|
* if we're running out.
|
||||||
*
|
*
|
||||||
* @return the allocated pbuf.
|
* This must be done in the correct thread context therefore this function
|
||||||
|
* can only be used with NO_SYS=0 and through tcpip_callback.
|
||||||
*/
|
*/
|
||||||
static struct pbuf *
|
static void
|
||||||
alloc_pool_pbuf(void)
|
pbuf_free_ooseq(void* arg)
|
||||||
{
|
{
|
||||||
struct tcp_pcb *pcb;
|
struct tcp_pcb* pcb;
|
||||||
struct pbuf *p;
|
SYS_ARCH_DECL_PROTECT(old_level);
|
||||||
|
LWIP_UNUSED_ARG(arg);
|
||||||
|
|
||||||
retry:
|
SYS_ARCH_PROTECT(old_level);
|
||||||
p = memp_malloc(MEMP_PBUF_POOL);
|
pbuf_free_ooseq_queued = 0;
|
||||||
if (NULL == p) {
|
SYS_ARCH_UNPROTECT(old_level);
|
||||||
for (pcb=tcp_active_pcbs; NULL != pcb; pcb = pcb->next) {
|
|
||||||
if (NULL != pcb->ooseq) {
|
for (pcb = tcp_active_pcbs; NULL != pcb; pcb = pcb->next) {
|
||||||
tcp_segs_free(pcb->ooseq);
|
if (NULL != pcb->ooseq) {
|
||||||
pcb->ooseq = NULL;
|
/** Free the ooseq pbufs of one PCB only */
|
||||||
goto retry;
|
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free_ooseq: freeing out-of-sequence pbufs\n"));
|
||||||
}
|
tcp_segs_free(pcb->ooseq);
|
||||||
|
pcb->ooseq = NULL;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return p;
|
|
||||||
}
|
}
|
||||||
#endif /* TCP_QUEUE_OOSEQ */
|
|
||||||
|
/** Queue a call to pbuf_free_ooseq if not already queued. */
|
||||||
|
static void
|
||||||
|
pbuf_pool_is_empty(void)
|
||||||
|
{
|
||||||
|
u8_t queued;
|
||||||
|
SYS_ARCH_DECL_PROTECT(old_level);
|
||||||
|
|
||||||
|
SYS_ARCH_PROTECT(old_level);
|
||||||
|
queued = pbuf_free_ooseq_queued;
|
||||||
|
pbuf_free_ooseq_queued = 1;
|
||||||
|
SYS_ARCH_UNPROTECT(old_level);
|
||||||
|
|
||||||
|
if(!queued) {
|
||||||
|
/* queue a call to pbuf_free_ooseq if not already queued */
|
||||||
|
if(tcpip_callback_with_block(pbuf_free_ooseq, NULL, 0) != ERR_OK) {
|
||||||
|
SYS_ARCH_PROTECT(old_level);
|
||||||
|
pbuf_free_ooseq_queued = 0;
|
||||||
|
SYS_ARCH_UNPROTECT(old_level);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* PBUF_POOL_FREE_OOSEQ */
|
||||||
|
#endif /* !TCP_QUEUE_OOSEQ || NO_SYS */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type).
|
* Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type).
|
||||||
@ -181,9 +211,10 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
|
|||||||
switch (type) {
|
switch (type) {
|
||||||
case PBUF_POOL:
|
case PBUF_POOL:
|
||||||
/* allocate head of pbuf chain into p */
|
/* allocate head of pbuf chain into p */
|
||||||
ALLOC_POOL_PBUF(p);
|
p = memp_malloc(MEMP_PBUF_POOL);
|
||||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc: allocated pbuf %p\n", (void *)p));
|
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc: allocated pbuf %p\n", (void *)p));
|
||||||
if (p == NULL) {
|
if (p == NULL) {
|
||||||
|
PBUF_POOL_IS_EMPTY();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
p->type = type;
|
p->type = type;
|
||||||
@ -213,8 +244,9 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
|
|||||||
rem_len = length - p->len;
|
rem_len = length - p->len;
|
||||||
/* any remaining pbufs to be allocated? */
|
/* any remaining pbufs to be allocated? */
|
||||||
while (rem_len > 0) {
|
while (rem_len > 0) {
|
||||||
ALLOC_POOL_PBUF(q);
|
q = memp_malloc(MEMP_PBUF_POOL);
|
||||||
if (q == NULL) {
|
if (q == NULL) {
|
||||||
|
PBUF_POOL_IS_EMPTY();
|
||||||
/* free chain so far allocated */
|
/* free chain so far allocated */
|
||||||
pbuf_free(p);
|
pbuf_free(p);
|
||||||
/* bail out unsuccesfully */
|
/* bail out unsuccesfully */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user