이 시스템 호출이 끝나면 무슨 일이 일어나고 왜 일어나는지 개념적으로 이해할 수 없습니다. 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 */
왜 fit + nbytes - sizeof(uint32)를 반환합니까? fit(구조체)을 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
이 코드에서 사용되는 것은 다음과 같습니다.하지만 발신자는 아닙니다. 따라서 공개 API의 일부 getstk()
가 아닌 공개 API 호출을 생각할 수 있습니다. struct memblk
이는 단지 내부 메커니즘의 일부일 뿐입니다.
반환 값은 메모리 영역의 맨 위(가장 높은 지점)를 가리키는 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()를 통해 반올림되지만 아마도 이 시스템은 재활용에도 사용됩니다).