/*-----------------------------------------------------------------------------------*/ uint8_t pbuf_free(struct pbuf *p) { struct pbuf *q; uint8_t count = 0; if(p == NULL) { return 0; } ASSERT("pbuf_free: sane flags", p->flags == PBUF_FLAG_POOL || p->flags == PBUF_FLAG_ROM || p->flags == PBUF_FLAG_RAM); ASSERT("pbuf_free: p->ref > 0", p->ref > 0); /* Decrement reference count. */ p->ref--; q = NULL; /* If reference count == 0, actually deallocate pbuf. */ if(p->ref == 0) { while(p != NULL) { /* Check if this is a pbuf from the pool. */ if(p->flags == PBUF_FLAG_POOL) { p->len = p->tot_len = PBUF_POOL_BUFSIZE; p->payload = (void *)((uint8_t *)p + sizeof(struct pbuf)); q = p->next; PBUF_POOL_FREE(p); #ifdef PBUF_STATS --stats.pbuf.used; #endif /* PBUF_STATS */ } else if(p->flags == PBUF_FLAG_ROM) { q = p->next; memp_freep(MEMP_PBUF, p); } else { q = p->next; mem_free(p); } p = q; count++; } pbuf_refresh(); } return count; }
/** * Dereference a pbuf chain or queue and deallocate any no-longer-used * pbufs at the head of this chain or queue. * * Decrements the pbuf reference count. If it reaches zero, the pbuf is * deallocated. * * For a pbuf chain, this is repeated for each pbuf in the chain, * up to the first pbuf which has a non-zero reference count after * decrementing. So, when all reference counts are one, the whole * chain is free'd. * * @param pbuf The pbuf (chain) to be dereferenced. * * @return the number of pbufs that were de-allocated * from the head of the chain. * * @note MUST NOT be called on a packet queue (Not verified to work yet). * @note the reference counter of a pbuf equals the number of pointers * that refer to the pbuf (or into the pbuf). * * @internal examples: * * Assuming existing chains a->b->c with the following reference * counts, calling pbuf_free(a) results in: * * 1->2->3 becomes ...1->3 * 3->3->3 becomes 2->3->3 * 1->1->2 becomes ......1 * 2->1->1 becomes 1->1->1 * 1->1->1 becomes ....... * */ u8_t pbuf_free(struct pbuf *p) { struct pbuf *q; u8_t count; SYS_ARCH_DECL_PROTECT(old_level); LWIP_ASSERT("p != NULL", p != NULL); /* if assertions are disabled, proceed with debug output */ if (p == NULL) { LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_free(p == NULL) was called.\n")); return 0; } LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_free(%p)\n", (void *)p)); PERF_START; LWIP_ASSERT("pbuf_free: sane flags", p->flags == PBUF_FLAG_RAM || p->flags == PBUF_FLAG_ROM || p->flags == PBUF_FLAG_REF || p->flags == PBUF_FLAG_POOL); count = 0; /* Since decrementing ref cannot be guaranteed to be a single machine operation * we must protect it. Also, the later test of ref must be protected. */ SYS_ARCH_PROTECT(old_level); /* de-allocate all consecutive pbufs from the head of the chain that * obtain a zero reference count after decrementing*/ while (p != NULL) { /* all pbufs in a chain are referenced at least once */ LWIP_ASSERT("pbuf_free: p->ref > 0", p->ref > 0); /* decrease reference count (number of pointers to pbuf) */ p->ref--; /* this pbuf is no longer referenced to? */ if (p->ref == 0) { /* remember next pbuf in chain for next iteration */ q = p->next; LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_free: deallocating %p\n", (void *)p)); /* is this a pbuf from the pool? */ if (p->flags == PBUF_FLAG_POOL) { p->len = p->tot_len = PBUF_POOL_BUFSIZE; p->payload = (void *)((u8_t *)p + sizeof(struct pbuf)); PBUF_POOL_FREE(p); /* is this a ROM or RAM referencing pbuf? */ } else if (p->flags == PBUF_FLAG_ROM || p->flags == PBUF_FLAG_REF) { memp_free(MEMP_PBUF, p); /* p->flags == PBUF_FLAG_RAM */ } else { mem_free(p); } count++; /* proceed to next pbuf */ p = q; /* p->ref > 0, this pbuf is still referenced to */ /* (and so the remaining pbufs in chain as well) */ } else { LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_free: %p has ref %u, ending here.\n", (void *)p, (unsigned int)p->ref)); /* stop walking through the chain */ p = NULL; } } SYS_ARCH_UNPROTECT(old_level); PERF_STOP("pbuf_free"); /* return number of de-allocated pbufs */ return count; }
/*-----------------------------------------------------------------------------------*/ void pbuf_realloc(struct pbuf *p, uint16_t size) { struct pbuf *q, *r; uint16_t rsize; ASSERT("pbuf_realloc: sane p->flags", p->flags == PBUF_FLAG_POOL || p->flags == PBUF_FLAG_ROM || p->flags == PBUF_FLAG_RAM); if(p->tot_len <= size) { return; } switch(p->flags) { case PBUF_FLAG_POOL: /* First, step over any pbufs that should still be in the chain. */ rsize = size; q = p; while(rsize > q->len) { rsize -= q->len; q = q->next; } /* Adjust the length of the pbuf that will be halved. */ q->len = rsize; /* And deallocate any left over pbufs. */ r = q->next; q->next = NULL; q = r; while(q != NULL) { r = q->next; PBUF_POOL_FREE(q); #ifdef PBUF_STATS --stats.pbuf.used; #endif /* PBUF_STATS */ q = r; } break; case PBUF_FLAG_ROM: p->len = size; break; case PBUF_FLAG_RAM: /* First, step over the pbufs that should still be in the chain. */ rsize = size; q = p; while(rsize > q->len) { rsize -= q->len; q = q->next; } if(q->flags == PBUF_FLAG_RAM) { /* Reallocate and adjust the length of the pbuf that will be halved. */ mem_realloc(q, (uint8_t *)q->payload - (uint8_t *)q + rsize); } q->len = rsize; /* And deallocate any left over pbufs. */ r = q->next; q->next = NULL; q = r; while(q != NULL) { r = q->next; pbuf_free(q); q = r; } break; } p->tot_len = size; pbuf_refresh(); }