6.828: Operating System Engineering (34)

page_alloc とか page_free とかの検討。
とりあえず page_alloc のコメントの以下の部分を

// Hint: use LIST_FIRST, LIST_REMOVE, and page_initpp

参考に、というか先頭のソレを使って初期化したソレを引数にセットすりゃ良いのかなぁ。あら? 基本的に struct Page な配列の空いてる要素をセットすれば良いだけ、ってことにしようかな。

struct Page のリンクリスト云々

下記を展開してみます。

LIST_HEAD(Page_list, Page);
typedef LIST_ENTRY(Page) Page_LIST_entry_t;

LIST_HEAD マクロの定義は inc/queue.h で以下。

#define	LIST_HEAD(name, type)						\
struct name {								\
    struct type *lh_first;	/* first element */			\
}

これをアレすると以下かいな。

struct Page_list {
    struct Page *lh_first; /* first element */
};
struct {
    struct Page *le_next;  /* next element */
    struct Page **le_prev; /* ptr to ptr to this element */
};

手順としては

  • LIST_FIRST マクロを使って先頭要素を引数の pp_store に設定
    • LIST_FIRST が NULL だったら -E_NO_MEM 戻せば良いのかな
  • 先頭要素を LIST_REMOVE で削除
  • pp_store なソレを page_initpp で初期化

あるいは page_free は単純に

  • LIST_INSERT_HEAD すれば良い?

とりあえず実装してみるか。

LIST_REMOVE マクロ

定義が以下。

/*
 * Remove the element "elm" from the list.
 * The "field" name is the link element as above.
 */
#define	LIST_REMOVE(elm, field) do {					\
	if (LIST_NEXT((elm), field) != NULL)				\
		LIST_NEXT((elm), field)->field.le_prev = 		\
		    (elm)->field.le_prev;				\
	*(elm)->field.le_prev = LIST_NEXT((elm), field);		\
} while (0)

LIST_NEXT って何だ、と言いつつ定義が以下。

/*
 * Return the element after "elm" in the list.
 * The "field" name is the link element as above.
 */
#define	LIST_NEXT(elm, field)	((elm)->field.le_next)

ええと、基本的に field なナニは pp_link を指定すれば良いはず。以下でどうか。

int
page_alloc(struct Page **pp_store)
{
    // Fill this function in
    if ((*pp_store = LIST_FIRST(page_list_first)) == NULL)
        return -E_NO_MEM;

    LIST_REMOVE(LIST_FIRST(page_list_first), pp_link);
    page_initpp(*pp_store);

    return 0;
}

//
// Return a page to the free list.
// (This function should only be called when pp->pp_ref reaches 0.)
//
void
page_free(struct Page *pp)
{
    // Fill this function in
    LIST_INSERT_HEAD(&page_free_list, pp, pp_link);
}

もの凄くヤッツケ感満点。で、make qemu してみたらコンパイルエラーがナニ。page_list_first って何だよ、とか型をカン違いしてたりとか、結構恥ずいレベル。

make qemu してみたらなんとなく check_page_alloc 手続きの assert はパスしてる模様です。本当かなぁ。一応確認したところでは、page_check 手続きの assert (679 行) で panic してるみたいです。以下。

	// there is no free memory, so we can't allocate a page table 
	assert(page_insert(boot_pgdir, pp1, 0x0, 0) < 0);

あ、よく見てみたら check_page_alloc() succeeded! ってメセジが出てますね。一応これで Lab2 の Part 1 はなんとかなってる、ということで良いのかどうか。
とりあえず今日は Part 2 に目を通します。