村头柯师傅 发表于 2022-6-20 15:52:45

LWIP 协议栈pbuf_alloc函数是不是有问题?

本帖最后由 村头柯师傅 于 2022-6-20 16:10 编辑

LWIP版本1.4.1(2.1.2)也是一样,内存申请函数:
红色部分:p->len = LWIP_MIN(length, PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset));这句感觉有问题,不是应该去掉SIZEOF_STRUCT_PBUF结构体本省的长度吗?
第一个应该是:p->len = LWIP_MIN(length, PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset) - SIZEOF_STRUCT_PBUF);
如果是多个PBUF,第二个开始是:p->len = LWIP_MIN(length, PBUF_POOL_BUFSIZE_ALIGNED - SIZEOF_STRUCT_PBUF);
下图为POOL类型的pbuf结果示意图:

struct pbuf * pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
{
struct pbuf *p, *q, *r;
u16_t offset;
s32_t rem_len; /* remaining length */
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F")\n", length));
/*省略*/
switch (type) {
case PBUF_POOL:
    /* allocate head of pbuf chain into p */
    p = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL);
    LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc: allocated pbuf %p\n", (void *)p));
    if (p == NULL) {
      PBUF_POOL_IS_EMPTY();
      return NULL;
    }
    p->type = type;
    p->next = NULL;

    /* make the payload pointer point 'offset' bytes into pbuf data memory */
    p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + (SIZEOF_STRUCT_PBUF + offset)));
    LWIP_ASSERT("pbuf_alloc: pbuf p->payload properly aligned",
            ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0);
    /* the total length of the pbuf chain is the requested size */
    p->tot_len = length;
    /* set the length of the first pbuf in the chain */
    p->len = LWIP_MIN(length, PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset));
    LWIP_ASSERT("check p->payload + p->len does not overflow pbuf",
                ((u8_t*)p->payload + p->len <=
               (u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED));
    LWIP_ASSERT("PBUF_POOL_BUFSIZE must be bigger than MEM_ALIGNMENT",
      (PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset)) > 0 );
    /* set reference count (needed here in case we fail) */
    p->ref = 1;

    /* now allocate the tail of the pbuf chain */

    /* remember first pbuf for linkage in next iteration */
    r = p;
    /* remaining length to be allocated */
    rem_len = length - p->len;
    /* any remaining pbufs to be allocated? */
    while (rem_len > 0) {
      q = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL);
      if (q == NULL) {
      PBUF_POOL_IS_EMPTY();
      /* free chain so far allocated */
      pbuf_free(p);
      /* bail out unsuccesfully */
      return NULL;
      }
      q->type = type;
      q->flags = 0;
      q->next = NULL;
      /* make previous pbuf point to this pbuf */
      r->next = q;
      /* set total length of this pbuf and next in chain */
      LWIP_ASSERT("rem_len < max_u16_t", rem_len < 0xffff);
      q->tot_len = (u16_t)rem_len;
      /* this pbuf length is pool size, unless smaller sized tail */
    q->len = LWIP_MIN((u16_t)rem_len, PBUF_POOL_BUFSIZE_ALIGNED);
      q->payload = (void *)((u8_t *)q + SIZEOF_STRUCT_PBUF);
      LWIP_ASSERT("pbuf_alloc: pbuf q->payload properly aligned",
            ((mem_ptr_t)q->payload % MEM_ALIGNMENT) == 0);
      LWIP_ASSERT("check p->payload + p->len does not overflow pbuf",
                  ((u8_t*)p->payload + p->len <=
                   (u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED));
      q->ref = 1;
      /* calculate remaining length to be allocated */
      rem_len -= q->len;
      /* remember this pbuf for linkage in next iteration */
      r = q;
    }
    /* end of chain */
    /*r->next = NULL;*/

    break;
case PBUF_RAM:
    /* If pbuf is to be allocated in RAM, allocate memory for it. */
    p = (struct pbuf*)mem_malloc(LWIP_MEM_ALIGN_SIZE(SIZEOF_STRUCT_PBUF + offset) + LWIP_MEM_ALIGN_SIZE(length));
    if (p == NULL) {
      return NULL;
    }
    /* Set up internal structure of the pbuf. */
    p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + SIZEOF_STRUCT_PBUF + offset));
    p->len = p->tot_len = length;
    p->next = NULL;
    p->type = type;

    LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned",
         ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0);
    break;
/* pbuf references existing (non-volatile static constant) ROM payload? */
case PBUF_ROM:
/* pbuf references existing (externally allocated) RAM payload? */
case PBUF_REF:
    /* only allocate memory for the pbuf structure */
    p = (struct pbuf *)memp_malloc(MEMP_PBUF);
    if (p == NULL) {
      LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
                  ("pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_%s.\n",
                  (type == 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->type = type;
    break;
default:
    LWIP_ASSERT("pbuf_alloc: erroneous type", 0);
    return NULL;
}
/* set reference count */
p->ref = 1;
/* set flags */
p->flags = 0;
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F") == %p\n", length, (void *)p));
return p;
}

eric2013 发表于 2022-6-21 01:48:17

帮顶。

glory 发表于 2022-6-21 10:37:53

本帖最后由 glory 于 2022-6-21 10:39 编辑

源码是没有问题的:
q = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL);
上面函数的返回值q指针,指向了包含payload空间的整个struct pbuf内存块,其大小是:
LWIP_MEM_ALIGN_SIZE(sizeof(struct pbuf)) + LWIP_MEM_ALIGN_SIZE(payloadsize)
其中payloadsize就是PBUF_POOL_BUFSIZE宏决定的。
参见memp_std.h文件中:
#ifndef LWIP_PBUF_MEMPOOL
/* This treats "pbuf pools" just like any other pool.
* Allocates buffers for a pbuf struct AND a payload size */
#define LWIP_PBUF_MEMPOOL(name, num, payload, desc) LWIP_MEMPOOL(name, num, (LWIP_MEM_ALIGN_SIZE(sizeof(struct pbuf)) + LWIP_MEM_ALIGN_SIZE(payload)), desc)
#endif /* LWIP_PBUF_MEMPOOL */
你的红色文字中,
qlen = LWIP_MIN(rem_len, (u16_t)(PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset)));
此时qlen就是正确的净负荷字节数,因为PBUF_POOL_BUFSIZE_ALIGNED并不包含sizeof(struct pbuf)大小,而是净负荷大小。
你可以通过printf打印出q指针,q->payload指针,q->len观察,结果如预期的正确。

村头柯师傅 发表于 2022-6-21 17:40:13

glory 发表于 2022-6-21 10:37
源码是没有问题的:
q = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL);
上面函数的返回值q指针,指向了包 ...

这个地方q = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL);申请一个POOL类型的内存池,一个内存池的固定大小就是PBUF_POOL_BUFSIZE。那sizeof(struct pbuf),LWIP_MEM_ALIGN_SIZE(offset),和paylaod三个应该连续保存在一个内存池上面吧。如果按照源码那样的话sizeof(struct pbuf)的内存就没有了或者保存在其他地方

村头柯师傅 发表于 2022-6-21 17:59:50

glory 发表于 2022-6-21 10:37
源码是没有问题的:
q = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL);
上面函数的返回值q指针,指向了包 ...

知道了,pbuf_pool类型的内存池初始化是这个:#define LWIP_PBUF_MEMPOOL(name, num, payload, desc) LWIP_MEMPOOL(name, num, (LWIP_MEM_ALIGN_SIZE(sizeof(struct pbuf)) + LWIP_MEM_ALIGN_SIZE(payload)), desc)
加了一个这个 (LWIP_MEM_ALIGN_SIZE(sizeof(struct pbuf)),我说那个struct pbuf的内存哪里去了!
页: [1]
查看完整版本: LWIP 协议栈pbuf_alloc函数是不是有问题?