mirror of
https://github.com/lwip-tcpip/lwip.git
synced 2025-03-14 01:26:52 +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) {
|
||||
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->len = buf->p->tot_len = size;
|
||||
buf->ptr = buf->p;
|
||||
|
@ -299,7 +299,7 @@ ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest)
|
||||
u16_t tmp;
|
||||
|
||||
/* 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->payload = buf;
|
||||
|
||||
@ -349,7 +349,6 @@ ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest)
|
||||
#ifdef IP_STATS
|
||||
++lwip_stats.ip_frag.xmit;
|
||||
#endif /* IP_STATS */
|
||||
pbuf_dechain(header);
|
||||
pbuf_free(header);
|
||||
|
||||
left -= cop;
|
||||
|
145
src/core/pbuf.c
145
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
|
||||
* protocol headers. Additional headers must be prepended
|
||||
* 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
|
||||
* 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",
|
||||
((u32_t)p->payload % MEM_ALIGNMENT) == 0);
|
||||
break;
|
||||
case PBUF_ROM:
|
||||
case PBUF_ROM:
|
||||
case PBUF_REF:
|
||||
/* If the pbuf should point to ROM, we only need to allocate
|
||||
memory for the pbuf structure. */
|
||||
p = memp_mallocp(MEMP_PBUF);
|
||||
@ -307,7 +315,10 @@ pbuf_alloc(pbuf_layer l, u16_t size, pbuf_flag flag)
|
||||
p->payload = NULL;
|
||||
p->len = p->tot_len = size;
|
||||
p->next = NULL;
|
||||
p->flags = PBUF_FLAG_ROM;
|
||||
if (flag == PBUF_ROM)
|
||||
p->flags = PBUF_FLAG_ROM;
|
||||
else
|
||||
p->flags = PBUF_FLAG_REF;
|
||||
break;
|
||||
default:
|
||||
LWIP_ASSERT("pbuf_alloc: erroneous flag", 0);
|
||||
@ -408,8 +419,9 @@ pbuf_realloc(struct pbuf *p, u16_t size)
|
||||
u16_t rsize;
|
||||
|
||||
LWIP_ASSERT("pbuf_realloc: sane p->flags", p->flags == PBUF_FLAG_POOL ||
|
||||
p->flags == PBUF_FLAG_ROM ||
|
||||
p->flags == PBUF_FLAG_RAM);
|
||||
p->flags == PBUF_FLAG_ROM ||
|
||||
p->flags == PBUF_FLAG_RAM ||
|
||||
p->flags == PBUF_FLAG_REF);
|
||||
|
||||
|
||||
if(p->tot_len <= size) {
|
||||
@ -438,7 +450,8 @@ pbuf_realloc(struct pbuf *p, u16_t size)
|
||||
q = r;
|
||||
}
|
||||
break;
|
||||
case PBUF_FLAG_ROM:
|
||||
case PBUF_FLAG_ROM:
|
||||
case PBUF_FLAG_REF:
|
||||
p->len = size;
|
||||
break;
|
||||
case PBUF_FLAG_RAM:
|
||||
@ -486,7 +499,8 @@ pbuf_header(struct pbuf *p, s16_t header_size)
|
||||
{
|
||||
void *payload;
|
||||
|
||||
if(p->flags & PBUF_FLAG_ROM) {
|
||||
if(p->flags == PBUF_FLAG_ROM ||
|
||||
p->flags == PBUF_FLAG_REF) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -530,7 +544,8 @@ pbuf_free(struct pbuf *p)
|
||||
|
||||
LWIP_ASSERT("pbuf_free: sane flags", p->flags == PBUF_FLAG_POOL ||
|
||||
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);
|
||||
|
||||
@ -554,7 +569,7 @@ pbuf_free(struct pbuf *p)
|
||||
q = p->next;
|
||||
PBUF_POOL_FREE(p);
|
||||
} else {
|
||||
if(p->flags == PBUF_FLAG_ROM) {
|
||||
if(p->flags == PBUF_FLAG_ROM || p->flags == PBUF_FLAG_REF) {
|
||||
q = p->next;
|
||||
memp_freep(MEMP_PBUF, p);
|
||||
} else {
|
||||
@ -564,6 +579,15 @@ pbuf_free(struct pbuf *p)
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
pbuf_refresh();
|
||||
@ -673,56 +697,71 @@ pbuf_dechain(struct pbuf *p)
|
||||
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 *
|
||||
pbuf_unref(struct pbuf *f)
|
||||
{
|
||||
struct pbuf *p, *q;
|
||||
struct pbuf *p, *prev, *q, *top;
|
||||
DEBUGF(PBUF_DEBUG, ("pbuf_unref: %p \n", (void*)f));
|
||||
/* first pbuf is of type PBUF_REF? */
|
||||
if (f->flags == PBUF_FLAG_REF)
|
||||
{
|
||||
/* 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 */
|
||||
|
||||
prev = 0;
|
||||
p = f;
|
||||
/* q = current pbuf */
|
||||
q = f->next;
|
||||
while (q != NULL)
|
||||
top = f;
|
||||
do
|
||||
{
|
||||
q = q->next;
|
||||
}
|
||||
return f;
|
||||
/* pbuf is of type PBUF_REF? */
|
||||
if (p->flags == PBUF_FLAG_REF)
|
||||
{
|
||||
/* 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;
|
||||
}
|
||||
memcpy((char *)cseg, (const char *)seg, sizeof(struct tcp_seg));
|
||||
pbuf_ref(cseg->p);
|
||||
pbuf_ref_chain(cseg->p);
|
||||
return cseg;
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
@ -184,7 +184,7 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
|
||||
/* Do not copy 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"));
|
||||
goto memerr;
|
||||
}
|
||||
|
@ -411,7 +411,6 @@ udp_send(struct udp_pcb *pcb, struct pbuf *p)
|
||||
}
|
||||
/* dechain and free the header pbuf */
|
||||
if(hdr != NULL) {
|
||||
pbuf_dechain(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;
|
||||
#if ARP_QUEUEING
|
||||
struct pbuf *p;
|
||||
struct eth_hdr *ethhdr;
|
||||
#endif
|
||||
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;
|
||||
#if ARP_QUEUEING
|
||||
/* 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 */
|
||||
ethhdr = arp_table[i].p->payload;
|
||||
ethhdr = p->payload;
|
||||
for(k = 0; k < 6; ++k) {
|
||||
ethhdr->dest.addr[k] = ethaddr->addr[k];
|
||||
}
|
||||
ethhdr->type = htons(ETHTYPE_IP);
|
||||
DEBUGF(ETHARP_DEBUG, ("update_arp_entry: sending queued IP packet.\n"));
|
||||
/* send the queued IP packet */
|
||||
netif->linkoutput(netif, arp_table[i].p);
|
||||
netif->linkoutput(netif, p);
|
||||
/* free the queued IP packet */
|
||||
pbuf_free(arp_table[i].p);
|
||||
/* remove queued packet from ARP entry (must be freed by the caller) */
|
||||
arp_table[i].p = NULL;
|
||||
pbuf_free(p);
|
||||
}
|
||||
#endif
|
||||
return NULL;
|
||||
|
Loading…
x
Reference in New Issue
Block a user