mirror of
https://github.com/lwip-tcpip/lwip.git
synced 2024-10-06 06:39:46 +00:00
Fixed up and made work a PBUF_REF type. Most of the code uses this now
instead of PBUF_ROM. This addition allows support of copy-on-demand where the lower layers can call pbuf_unref() which tests for any PBUF_REF buffers and replaces them with PBUF_POOL buffers. This is now used everywhere. pbuf_unref() is called in ARP queueing and in the coldfire driver, which puts frames on a DMA queue and frees them later. Along with this change pbuf_free() now goes through the entire chain of buffers and tests all the ref counters, not just the first one. Generally now pbuf_ref_chain() should be called and not pbuf_ref(). This change was made because it is possible for the head of the pbuf chain to have a different count than the payload pbuf which might have been passed by the application.
This commit is contained in:
parent
2f7e4bd587
commit
32d9f25a6f
@ -96,7 +96,7 @@ netbuf_ref(struct netbuf *buf, void *dataptr, u16_t size)
|
|||||||
if(buf->p != NULL) {
|
if(buf->p != NULL) {
|
||||||
pbuf_free(buf->p);
|
pbuf_free(buf->p);
|
||||||
}
|
}
|
||||||
buf->p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_ROM);
|
buf->p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF);
|
||||||
buf->p->payload = dataptr;
|
buf->p->payload = dataptr;
|
||||||
buf->p->len = buf->p->tot_len = size;
|
buf->p->len = buf->p->tot_len = size;
|
||||||
buf->ptr = buf->p;
|
buf->ptr = buf->p;
|
||||||
|
@ -299,7 +299,7 @@ ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest)
|
|||||||
u16_t tmp;
|
u16_t tmp;
|
||||||
|
|
||||||
/* Get a RAM based MTU sized pbuf */
|
/* Get a RAM based MTU sized pbuf */
|
||||||
rambuf = pbuf_alloc(PBUF_LINK, 0, PBUF_ROM);
|
rambuf = pbuf_alloc(PBUF_LINK, 0, PBUF_REF);
|
||||||
rambuf->tot_len = rambuf->len = mtu;
|
rambuf->tot_len = rambuf->len = mtu;
|
||||||
rambuf->payload = buf;
|
rambuf->payload = buf;
|
||||||
|
|
||||||
@ -349,7 +349,6 @@ ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest)
|
|||||||
#ifdef IP_STATS
|
#ifdef IP_STATS
|
||||||
++lwip_stats.ip_frag.xmit;
|
++lwip_stats.ip_frag.xmit;
|
||||||
#endif /* IP_STATS */
|
#endif /* IP_STATS */
|
||||||
pbuf_dechain(header);
|
|
||||||
pbuf_free(header);
|
pbuf_free(header);
|
||||||
|
|
||||||
left -= cop;
|
left -= cop;
|
||||||
|
143
src/core/pbuf.c
143
src/core/pbuf.c
@ -200,7 +200,14 @@ pbuf_pool_free(struct pbuf *p)
|
|||||||
* * PBUF_ROM: no buffer memory is allocated for the pbuf, even for
|
* * PBUF_ROM: no buffer memory is allocated for the pbuf, even for
|
||||||
* protocol headers. Additional headers must be prepended
|
* protocol headers. Additional headers must be prepended
|
||||||
* by allocating another pbuf and chain in to the front of
|
* by allocating another pbuf and chain in to the front of
|
||||||
* the ROM pbuf.
|
* the ROM pbuf. It is assumed that the memory used is really
|
||||||
|
* similar to ROM in that it is immutable and will not be
|
||||||
|
* changed. Memory which is dynamic should generally not
|
||||||
|
* be attached to PBUF_ROM pbufs. Use PBUF_REF instead.
|
||||||
|
* * PBUF_REF: no buffer memory is allocated for the pbuf, even for
|
||||||
|
* protocol headers. It is assumed that the pbuf is only
|
||||||
|
* being used in a single thread. If the pbuf gets queued,
|
||||||
|
* then pbuf_unref should be called to copy the buffer.
|
||||||
* * PBUF_POOL: the pbuf is allocated as a pbuf chain, with pbufs from
|
* * PBUF_POOL: the pbuf is allocated as a pbuf chain, with pbufs from
|
||||||
* the pbuf pool that is allocated during pbuf_init().
|
* the pbuf pool that is allocated during pbuf_init().
|
||||||
*/
|
*/
|
||||||
@ -297,7 +304,8 @@ pbuf_alloc(pbuf_layer l, u16_t size, pbuf_flag flag)
|
|||||||
LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned",
|
LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned",
|
||||||
((u32_t)p->payload % MEM_ALIGNMENT) == 0);
|
((u32_t)p->payload % MEM_ALIGNMENT) == 0);
|
||||||
break;
|
break;
|
||||||
case PBUF_ROM:
|
case PBUF_ROM:
|
||||||
|
case PBUF_REF:
|
||||||
/* If the pbuf should point to ROM, we only need to allocate
|
/* If the pbuf should point to ROM, we only need to allocate
|
||||||
memory for the pbuf structure. */
|
memory for the pbuf structure. */
|
||||||
p = memp_mallocp(MEMP_PBUF);
|
p = memp_mallocp(MEMP_PBUF);
|
||||||
@ -307,7 +315,10 @@ pbuf_alloc(pbuf_layer l, u16_t size, pbuf_flag flag)
|
|||||||
p->payload = NULL;
|
p->payload = NULL;
|
||||||
p->len = p->tot_len = size;
|
p->len = p->tot_len = size;
|
||||||
p->next = NULL;
|
p->next = NULL;
|
||||||
p->flags = PBUF_FLAG_ROM;
|
if (flag == PBUF_ROM)
|
||||||
|
p->flags = PBUF_FLAG_ROM;
|
||||||
|
else
|
||||||
|
p->flags = PBUF_FLAG_REF;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LWIP_ASSERT("pbuf_alloc: erroneous flag", 0);
|
LWIP_ASSERT("pbuf_alloc: erroneous flag", 0);
|
||||||
@ -408,8 +419,9 @@ pbuf_realloc(struct pbuf *p, u16_t size)
|
|||||||
u16_t rsize;
|
u16_t rsize;
|
||||||
|
|
||||||
LWIP_ASSERT("pbuf_realloc: sane p->flags", p->flags == PBUF_FLAG_POOL ||
|
LWIP_ASSERT("pbuf_realloc: sane p->flags", p->flags == PBUF_FLAG_POOL ||
|
||||||
p->flags == PBUF_FLAG_ROM ||
|
p->flags == PBUF_FLAG_ROM ||
|
||||||
p->flags == PBUF_FLAG_RAM);
|
p->flags == PBUF_FLAG_RAM ||
|
||||||
|
p->flags == PBUF_FLAG_REF);
|
||||||
|
|
||||||
|
|
||||||
if(p->tot_len <= size) {
|
if(p->tot_len <= size) {
|
||||||
@ -439,6 +451,7 @@ pbuf_realloc(struct pbuf *p, u16_t size)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PBUF_FLAG_ROM:
|
case PBUF_FLAG_ROM:
|
||||||
|
case PBUF_FLAG_REF:
|
||||||
p->len = size;
|
p->len = size;
|
||||||
break;
|
break;
|
||||||
case PBUF_FLAG_RAM:
|
case PBUF_FLAG_RAM:
|
||||||
@ -486,7 +499,8 @@ pbuf_header(struct pbuf *p, s16_t header_size)
|
|||||||
{
|
{
|
||||||
void *payload;
|
void *payload;
|
||||||
|
|
||||||
if(p->flags & PBUF_FLAG_ROM) {
|
if(p->flags == PBUF_FLAG_ROM ||
|
||||||
|
p->flags == PBUF_FLAG_REF) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -530,7 +544,8 @@ pbuf_free(struct pbuf *p)
|
|||||||
|
|
||||||
LWIP_ASSERT("pbuf_free: sane flags", p->flags == PBUF_FLAG_POOL ||
|
LWIP_ASSERT("pbuf_free: sane flags", p->flags == PBUF_FLAG_POOL ||
|
||||||
p->flags == PBUF_FLAG_ROM ||
|
p->flags == PBUF_FLAG_ROM ||
|
||||||
p->flags == PBUF_FLAG_RAM);
|
p->flags == PBUF_FLAG_RAM ||
|
||||||
|
p->flags == PBUF_FLAG_REF );
|
||||||
|
|
||||||
LWIP_ASSERT("pbuf_free: p->ref > 0", p->ref > 0);
|
LWIP_ASSERT("pbuf_free: p->ref > 0", p->ref > 0);
|
||||||
|
|
||||||
@ -554,7 +569,7 @@ pbuf_free(struct pbuf *p)
|
|||||||
q = p->next;
|
q = p->next;
|
||||||
PBUF_POOL_FREE(p);
|
PBUF_POOL_FREE(p);
|
||||||
} else {
|
} else {
|
||||||
if(p->flags == PBUF_FLAG_ROM) {
|
if(p->flags == PBUF_FLAG_ROM || p->flags == PBUF_FLAG_REF) {
|
||||||
q = p->next;
|
q = p->next;
|
||||||
memp_freep(MEMP_PBUF, p);
|
memp_freep(MEMP_PBUF, p);
|
||||||
} else {
|
} else {
|
||||||
@ -564,6 +579,15 @@ pbuf_free(struct pbuf *p)
|
|||||||
}
|
}
|
||||||
|
|
||||||
p = q;
|
p = q;
|
||||||
|
/* Only free the next one in a chain if it's reference count is 0.
|
||||||
|
This allows buffer chains to have multiple headers pointing to them. */
|
||||||
|
if (p)
|
||||||
|
{
|
||||||
|
p->ref--;
|
||||||
|
if (p->ref > 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
++count;
|
++count;
|
||||||
}
|
}
|
||||||
pbuf_refresh();
|
pbuf_refresh();
|
||||||
@ -673,56 +697,71 @@ pbuf_dechain(struct pbuf *p)
|
|||||||
return q;
|
return q;
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------------------*/
|
||||||
|
/** Replace any pbufs of type PBUF_FLAG_REF with PBUF_POOL buffers.
|
||||||
|
|
||||||
|
Go through pbuf chain and replace any PBUF_REF buffers with PBUF_POOL
|
||||||
|
buffers. This is generally done for buffer chains which need to be queued
|
||||||
|
in some way (either on an output queue or on the arp queue). All pbufs
|
||||||
|
replaced will be freed immediately.
|
||||||
|
|
||||||
|
@param f Head of pbuf chain to process
|
||||||
|
|
||||||
|
@return Pointer to new head of pbuf chain.
|
||||||
|
*/
|
||||||
struct pbuf *
|
struct pbuf *
|
||||||
pbuf_unref(struct pbuf *f)
|
pbuf_unref(struct pbuf *f)
|
||||||
{
|
{
|
||||||
struct pbuf *p, *q;
|
struct pbuf *p, *prev, *q, *top;
|
||||||
DEBUGF(PBUF_DEBUG, ("pbuf_unref: %p \n", (void*)f));
|
DEBUGF(PBUF_DEBUG, ("pbuf_unref: %p \n", (void*)f));
|
||||||
/* first pbuf is of type PBUF_REF? */
|
|
||||||
if (f->flags == PBUF_FLAG_REF)
|
prev = 0;
|
||||||
{
|
|
||||||
/* allocate a pbuf (w/ payload) fully in RAM */
|
|
||||||
p = pbuf_alloc(PBUF_RAW, f->len, PBUF_RAM);
|
|
||||||
if (p != 0)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
unsigned char *src, *dst;
|
|
||||||
/* copy pbuf struct */
|
|
||||||
p->next = f->next;
|
|
||||||
src = f->payload;
|
|
||||||
dst = p->payload;
|
|
||||||
i = 0;
|
|
||||||
/* copy payload to RAM pbuf */
|
|
||||||
while(i < p->len)
|
|
||||||
{
|
|
||||||
*dst = *src;
|
|
||||||
dst++;
|
|
||||||
src++;
|
|
||||||
}
|
|
||||||
f->next = NULL;
|
|
||||||
/* de-allocate PBUF_REF */
|
|
||||||
pbuf_free(f);
|
|
||||||
f = p;
|
|
||||||
DEBUGF(PBUF_DEBUG, ("pbuf_unref: succesful %p \n", (void *)f));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* deallocate chain */
|
|
||||||
pbuf_free(f);
|
|
||||||
f = NULL;
|
|
||||||
DEBUGF(PBUF_DEBUG, ("pbuf_unref: failed\n"));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* p = previous pbuf == first pbuf */
|
|
||||||
p = f;
|
p = f;
|
||||||
/* q = current pbuf */
|
top = f;
|
||||||
q = f->next;
|
do
|
||||||
while (q != NULL)
|
|
||||||
{
|
{
|
||||||
q = q->next;
|
/* pbuf is of type PBUF_REF? */
|
||||||
}
|
if (p->flags == PBUF_FLAG_REF)
|
||||||
return f;
|
{
|
||||||
|
/* allocate a pbuf (w/ payload) fully in RAM */
|
||||||
|
/* PBUF_POOL buffers are faster if we can use them */
|
||||||
|
if (p->len <= PBUF_POOL_BUFSIZE)
|
||||||
|
q = pbuf_alloc(PBUF_RAW, p->len, PBUF_POOL);
|
||||||
|
else
|
||||||
|
q = pbuf_alloc(PBUF_RAW, p->len, PBUF_RAM);
|
||||||
|
if (q != 0)
|
||||||
|
{
|
||||||
|
/* copy pbuf struct */
|
||||||
|
q->next = p->next;
|
||||||
|
if (prev)
|
||||||
|
/* Break chain and insert new pbuf instead */
|
||||||
|
prev->next = q;
|
||||||
|
else
|
||||||
|
top = q;
|
||||||
|
p->next = NULL;
|
||||||
|
|
||||||
|
memcpy(q->payload, p->payload, p->len);
|
||||||
|
q->tot_len = p->tot_len;
|
||||||
|
q->len = p->len;
|
||||||
|
|
||||||
|
/* Don't copy ref, since someone else might be using the old buffer */
|
||||||
|
|
||||||
|
/* de-allocate PBUF_REF */
|
||||||
|
/* pbuf is not freed because it is assumed that some upper level
|
||||||
|
program has a direct pointer to this pbuf and will free it. */
|
||||||
|
p = q;
|
||||||
|
DEBUGF(PBUF_DEBUG, ("pbuf_unref: succesful %p \n", (void *)p));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* deallocate chain */
|
||||||
|
pbuf_free(top);
|
||||||
|
DEBUGF(PBUF_DEBUG, ("pbuf_unref: failed\n"));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prev = p;
|
||||||
|
p = p->next;
|
||||||
|
} while (p);
|
||||||
|
|
||||||
|
return top;
|
||||||
}
|
}
|
||||||
|
@ -713,7 +713,7 @@ tcp_seg_copy(struct tcp_seg *seg)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
memcpy((char *)cseg, (const char *)seg, sizeof(struct tcp_seg));
|
memcpy((char *)cseg, (const char *)seg, sizeof(struct tcp_seg));
|
||||||
pbuf_ref(cseg->p);
|
pbuf_ref_chain(cseg->p);
|
||||||
return cseg;
|
return cseg;
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------------------*/
|
||||||
|
@ -184,7 +184,7 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
|
|||||||
/* Do not copy the data. */
|
/* Do not copy the data. */
|
||||||
|
|
||||||
/* First, allocate a pbuf for holding the data. */
|
/* First, allocate a pbuf for holding the data. */
|
||||||
if((p = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_ROM)) == NULL) {
|
if((p = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_REF)) == NULL) {
|
||||||
DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: could not allocate memory for pbuf non-copy\n"));
|
DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: could not allocate memory for pbuf non-copy\n"));
|
||||||
goto memerr;
|
goto memerr;
|
||||||
}
|
}
|
||||||
|
@ -411,7 +411,6 @@ udp_send(struct udp_pcb *pcb, struct pbuf *p)
|
|||||||
}
|
}
|
||||||
/* dechain and free the header pbuf */
|
/* dechain and free the header pbuf */
|
||||||
if(hdr != NULL) {
|
if(hdr != NULL) {
|
||||||
pbuf_dechain(hdr);
|
|
||||||
pbuf_free(hdr);
|
pbuf_free(hdr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,6 +235,7 @@ update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *e
|
|||||||
{
|
{
|
||||||
u8_t i, k;
|
u8_t i, k;
|
||||||
#if ARP_QUEUEING
|
#if ARP_QUEUEING
|
||||||
|
struct pbuf *p;
|
||||||
struct eth_hdr *ethhdr;
|
struct eth_hdr *ethhdr;
|
||||||
#endif
|
#endif
|
||||||
DEBUGF(ETHARP_DEBUG, ("update_arp_entry()"));
|
DEBUGF(ETHARP_DEBUG, ("update_arp_entry()"));
|
||||||
@ -270,21 +271,20 @@ update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *e
|
|||||||
arp_table[i].ctime = 0;
|
arp_table[i].ctime = 0;
|
||||||
#if ARP_QUEUEING
|
#if ARP_QUEUEING
|
||||||
/* queued packet present? */
|
/* queued packet present? */
|
||||||
if(arp_table[i].p != NULL) {
|
if((p = arp_table[i].p) != NULL) {
|
||||||
|
/* Null out attached buffer immediately */
|
||||||
|
arp_table[i].p = NULL;
|
||||||
/* fill-in Ethernet header */
|
/* fill-in Ethernet header */
|
||||||
ethhdr = arp_table[i].p->payload;
|
ethhdr = p->payload;
|
||||||
for(k = 0; k < 6; ++k) {
|
for(k = 0; k < 6; ++k) {
|
||||||
ethhdr->dest.addr[k] = ethaddr->addr[k];
|
ethhdr->dest.addr[k] = ethaddr->addr[k];
|
||||||
}
|
}
|
||||||
ethhdr->type = htons(ETHTYPE_IP);
|
ethhdr->type = htons(ETHTYPE_IP);
|
||||||
DEBUGF(ETHARP_DEBUG, ("update_arp_entry: sending queued IP packet.\n"));
|
DEBUGF(ETHARP_DEBUG, ("update_arp_entry: sending queued IP packet.\n"));
|
||||||
/* send the queued IP packet */
|
/* send the queued IP packet */
|
||||||
netif->linkoutput(netif, arp_table[i].p);
|
netif->linkoutput(netif, p);
|
||||||
/* free the queued IP packet */
|
/* free the queued IP packet */
|
||||||
pbuf_free(arp_table[i].p);
|
pbuf_free(p);
|
||||||
/* remove queued packet from ARP entry (must be freed by the caller) */
|
|
||||||
arp_table[i].p = NULL;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return NULL;
|
return NULL;
|
||||||
|
Loading…
Reference in New Issue
Block a user