我无法从概念上理解此系统调用结束时发生的情况及其原因。我了解 getstk.c 方法返回可用空间的最高内存地址,但不明白某些代码在做什么。如果能澄清这一点就太好了。我不完全理解的代码区域用星号强调。
/* getstk.c - getstk */
#include <xinu.h>
/*------------------------------------------------------------------------
* getstk - Allocate stack memory, returning highest word address
*------------------------------------------------------------------------
*/
char *getstk(
uint32 nbytes /* size of memory requested */
)
{
intmask mask; /* saved interrupt mask */
struct memblk *prev, *curr; /* walk through memory list */
struct memblk *fits, *fitsprev; /* record block that fits */
mask = disable();
if (nbytes == 0) {
restore(mask);
return (char *)SYSERR;
}
nbytes = (uint32) roundmb(nbytes); /* use mblock multiples */
prev = &memlist;
curr = memlist.mnext;
fits = NULL;
fitsprev = NULL; /* to avoid a compiler warning */
while (curr != NULL) { /* scan entire list */
if (curr->mlength >= nbytes) { /* record block address */
fits = curr; /* when request fits */
fitsprev = prev;
}
prev = curr;
curr = curr->mnext;
}
if (fits == NULL) { /* no block was found */
restore(mask);
return (char *)SYSERR;
}
if (nbytes == fits->mlength) { /* block is exact match */
fitsprev->mnext = fits->mnext;
**} else { /* remove top section */
fits->mlength -= nbytes;
fits = (struct memblk *)((uint32)fits + fits->mlength);
}**
memlist.mlength -= nbytes;
restore(mask);
**return (char *)((uint32) fits + nbytes - sizeof(uint32));**
}
struct memblk 可以在这里找到:
struct memblk { /* see roundmb & truncmb */
struct memblk *mnext; /* ptr to next free memory blk */
uint32 mlength; /* size of blk (includes memblk)*/
};
extern struct memblk memlist; /* head of free memory list */
为什么他们返回fits + nbytes - sizeof(uint32)?为什么他们将 fits(a struct) 转换为 uint32 类型?
答案1
这是找到足够大小的块的两种情况。请注意,在第一种情况下,我们通过将前一个节点的下一个指针链接到该节点的下一个指针来删除整个节点 ( fits
) 。memlist
然后,该块将在返回值中使用,因此我从该块和注释等推测,此处的目的是在池中找到一些空闲内存并将其从空闲池中删除以供使用。
if (nbytes == fits->mlength) { /* block is exact match */
fitsprev->mnext = fits->mnext;
**} else { /* remove top section */
fits->mlength -= nbytes;
fits = (struct memblk *)((uint32)fits + fits->mlength);
}**
现在,在您突出显示的第二种情况下,找到的块是足够大。重要的是,不要返回整个内容,因为多余的部分将被浪费,而且,返回值的性质(见下文)意味着接收者将没有实际大小的记录,这可能意味着如果该块被回收后来只能根据要求的尺寸(参数 的原始值nbytes
),将浪费的多余部分永久隔离在内存池中。
为了解决这个问题,fits
块被缩短了到余数的长度。那是,不是请求块的长度,但是从找到的(大于足够大的)块的长度中减去请求的量时剩下的量。与 if/else 的第一个子句不同,这里的 Fits 块是没有删除从游泳池。只是缩短了:
fits->mlength -= nbytes;
然后,将在返回值中使用的指针向前移动到新缩短的块的末尾。这指向将从池中删除的区域:
fits = (struct memblk *)((uint32)fits + fits->mlength);
请注意,虽然fits
指针已移动,但代码不会纠正现在指向的fits->mlength
区域的大小fits
(这与上一行中的位置不同)。这是因为返回的内容不是一个结构体。我猜这个函数是从struct memblk
根本不使用的地方调用的。换句话说,struct memblk
在这段代码中使用的是,但不在调用者中。因此,您可以考虑getstk()
公共 API 调用,其中struct memblk
不是公共 API 的一部分——它只是内部机制的一部分。
返回值只是一个指向内存区域顶部(最高点)的 char 指针。
getstk - Allocate stack memory, returning highest word address
据推测,调用者将假设返回的指针指向顶端一个区域的nbytes
大小。这与 malloc() 的作用非常相似,例如:
char *dataA = malloc(4096);
char *dataB = getstk(4096);
除了malloc返回一个地址在底部4096 字节块,因此地址范围从dataA
到dataA + 4095
。由于 getstk() 返回高地址,因此范围将从 到dataB - 4095
(dataB
实际上,不完全是,因为正在使用“字大小”,请继续阅读)。
因此:
return (char *)((uint32) fits + nbytes - sizeof(uint32));
这是目前指向底部的区域(我们nbytes
通常认为fits
起始地址,与 malloc 一样)。但 getstk() 应该返回高地址——更准确地说是最高字地址。一个“字”通常是4字节/32位;这里是明确的sizeof(uint32)
。所以返回的地址指向一个块nbytes
大小的最后 4 个字节(实际上,nbytes 是通过 roundmb() 进行舍入的,但大概这个系统也用于回收)。