📄 pbuf.c
字号:
case PBUF_REF: /* only allocate memory for the pbuf structure */ p = memp_malloc(MEMP_PBUF); if (p == NULL) { LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_%s.\n", flag == PBUF_ROM?"ROM":"REF")); return NULL; } /* caller must set this field properly, afterwards */ p->payload = NULL; p->len = p->tot_len = length; p->next = NULL; p->flags = (flag == PBUF_ROM? PBUF_FLAG_ROM: PBUF_FLAG_REF); break; default: LWIP_ASSERT("pbuf_alloc: erroneous flag", 0); return NULL; } /* set reference count */ p->ref = 1; LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_alloc(length=%"U16_F") == %p\n", length, (void *)p)); return p;}#if PBUF_STATS#define DEC_PBUF_STATS do { --lwip_stats.pbuf.used; } while (0)#else /* PBUF_STATS */#define DEC_PBUF_STATS#endif /* PBUF_STATS */#define PBUF_POOL_FAST_FREE(p) do { \ p->next = pbuf_pool; \ pbuf_pool = p; \ DEC_PBUF_STATS; \ } while (0)#if SYS_LIGHTWEIGHT_PROT#define PBUF_POOL_FREE(p) do { \ SYS_ARCH_DECL_PROTECT(old_level); \ SYS_ARCH_PROTECT(old_level); \ PBUF_POOL_FAST_FREE(p); \ SYS_ARCH_UNPROTECT(old_level); \ } while (0)#else /* SYS_LIGHTWEIGHT_PROT */#define PBUF_POOL_FREE(p) do { \ sys_sem_wait(pbuf_pool_free_sem); \ PBUF_POOL_FAST_FREE(p); \ sys_sem_signal(pbuf_pool_free_sem); \ } while (0)#endif /* SYS_LIGHTWEIGHT_PROT *//** * Shrink a pbuf chain to a desired length. * * @param p pbuf to shrink. * @param new_len desired new length of pbuf chain * * Depending on the desired length, the first few pbufs in a chain might * be skipped and left unchanged. The new last pbuf in the chain will be * resized, and any remaining pbufs will be freed. * * @note If the pbuf is ROM/REF, only the ->tot_len and ->len fields are adjusted. * @note May not be called on a packet queue. * * @bug Cannot grow the size of a pbuf (chain) (yet). */voidpbuf_realloc(struct pbuf *p, u16_t new_len){ struct pbuf *q; u16_t rem_len; /* remaining length */ s16_t grow; 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_REF); /* desired length larger than current length? */ if (new_len >= p->tot_len) { /* enlarging not yet supported */ return; } /* the pbuf chain grows by (new_len - p->tot_len) bytes * (which may be negative in case of shrinking) */ grow = new_len - p->tot_len; /* first, step over any pbufs that should remain in the chain */ rem_len = new_len; q = p; /* should this pbuf be kept? */ while (rem_len > q->len) { /* decrease remaining length by pbuf length */ rem_len -= q->len; /* decrease total length indicator */ q->tot_len += grow; /* proceed to next pbuf in chain */ q = q->next; } /* we have now reached the new last pbuf (in q) */ /* rem_len == desired length for pbuf q */ /* shrink allocated memory for PBUF_RAM */ /* (other types merely adjust their length fields */ if ((q->flags == PBUF_FLAG_RAM) && (rem_len != q->len)) { /* reallocate and adjust the length of the pbuf that will be split */ mem_realloc(q, (u8_t *)q->payload - (u8_t *)q + rem_len); } /* adjust length fields for new last pbuf */ q->len = rem_len; q->tot_len = q->len; /* any remaining pbufs in chain? */ if (q->next != NULL) { /* free remaining pbufs in chain */ pbuf_free(q->next); } /* q is last packet in chain */ q->next = NULL;}/** * Adjusts the payload pointer to hide or reveal headers in the payload. * * Adjusts the ->payload pointer so that space for a header * (dis)appears in the pbuf payload. * * The ->payload, ->tot_len and ->len fields are adjusted. * * @param hdr_size_inc Number of bytes to increment header size which * increases the size of the pbuf. New space is on the front. * (Using a negative value decreases the header size.) * If hdr_size_inc is 0, this function does nothing and returns succesful. * * PBUF_ROM and PBUF_REF type buffers cannot have their sizes increased, so * the call will fail. A check is made that the increase in header size does * not move the payload pointer in front of the start of the buffer. * @return non-zero on failure, zero on success. * */u8_tpbuf_header(struct pbuf *p, s16_t header_size_increment){ u16_t flags; void *payload; LWIP_ASSERT("p != NULL", p != NULL); if ((header_size_increment == 0) || (p == NULL)) return 0; flags = p->flags; /* remember current payload pointer */ payload = p->payload; /* pbuf types containing payloads? */ if (flags == PBUF_FLAG_RAM || flags == PBUF_FLAG_POOL) { /* set new payload pointer */ p->payload = (u8_t *)p->payload - header_size_increment; /* boundary check fails? */ if ((u8_t *)p->payload < (u8_t *)p + sizeof(struct pbuf)) { LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_header: failed as %p < %p (not enough space for new header size)\n", (void *)p->payload, (void *)(p + 1)));\ /* restore old payload pointer */ p->payload = payload; /* bail out unsuccesfully */ return 1; } /* pbuf types refering to external payloads? */ } else if (flags == PBUF_FLAG_REF || flags == PBUF_FLAG_ROM) { /* hide a header in the payload? */ if ((header_size_increment < 0) && (header_size_increment - p->len <= 0)) { /* increase payload pointer */ p->payload = (u8_t *)p->payload - header_size_increment; } else { /* cannot expand payload to front (yet!) * bail out unsuccesfully */ return 1; } } /* modify pbuf length fields */ p->len += header_size_increment; p->tot_len += header_size_increment; LWIP_DEBUGF( PBUF_DEBUG, ("pbuf_header: old %p new %p (%"S16_F")\n", (void *)payload, (void *)p->payload, header_size_increment)); return 0;}/** * 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_tpbuf_free(struct pbuf *p){ u16_t flags; 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)); flags = p->flags; /* is this a pbuf from the pool? */ if (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 (flags == PBUF_FLAG_ROM || flags == PBUF_FLAG_REF) { memp_free(MEMP_PBUF, 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 %"U16_F", ending here.\n", (void *)p, (u16_t)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;}/** * Count number of pbufs in a chain * * @param p first pbuf of chain * @return the number of pbufs in a chain */u8_tpbuf_clen(struct pbuf *p){ u8_t len; len = 0; while (p != NULL) { ++len; p = p->next; } return len;}/** * Increment the reference count of the pbuf. * * @param p pbuf to increase reference counter of * */voidpbuf_ref(struct pbuf *p)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -