硬汉嵌入式论坛

 找回密码
 立即注册
查看: 900|回复: 4
收起左侧

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

[复制链接]

4

主题

6

回帖

18

积分

新手上路

积分
18
发表于 2022-6-20 15:52:45 | 显示全部楼层 |阅读模式
本帖最后由 村头柯师傅 于 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结果示意图:
image.png
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;
}

回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106738
QQ
发表于 2022-6-21 01:48:17 | 显示全部楼层
帮顶。
回复

使用道具 举报

3

主题

336

回帖

345

积分

高级会员

积分
345
发表于 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文件中:
[C] 纯文本查看 复制代码
#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 */

你的红色文字中,
[C] 纯文本查看 复制代码
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观察,结果如预期的正确。
回复

使用道具 举报

4

主题

6

回帖

18

积分

新手上路

积分
18
 楼主| 发表于 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)的内存就没有了或者保存在其他地方
回复

使用道具 举报

4

主题

6

回帖

18

积分

新手上路

积分
18
 楼主| 发表于 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的内存哪里去了!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-3 01:29 , Processed in 0.172138 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表