このシステムコールが終了すると、何が起こり、なぜ起こるのかを概念的に理解することはできません。 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
これは、十分なサイズのブロックが見つかる2つのケースです。最初のケースでは、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);
}**
今強調した2番目のケースで見つかったブロックは次のとおりです。十分に大きい。超過した内容は無駄になるため、内容全体を返さないことが重要です。また、戻り値の特性(以下を参照)は、受信者がレコードの実際のサイズを持っていないことを意味するため、次のようにブロックがリサイクルされると後で検索されます。必要なサイズ(パラメータの元の値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()で丸められますが、おそらくこのシステムはリサイクルにも使用されます)。