view paper/cbc_interface.tex @ 44:ee0ea632634b

fig add syntax
author tobaru
date Thu, 05 Mar 2020 15:35:10 +0900
parents 8ab113a99ea3
children
line wrap: on
line source

\chapter{CbC インターフェース}

 Gears OS では Meta Code Gear で Context から値を取り出し、ノーマルレベルの Code Gear に値を渡す。
しかし、Code Gaer がどの Data Gear の番号に対応するかを指定する必要があったり、 % ぱるすさんコード必要?
ノーマルレベルとメタレベルで見え方が異なる Data Gear を Meta Code Gear によって 調整する必要があったりと、 % みつきさん
メタレベルからノーマルレベルの継続の記述が煩雑になるため、Interface 化をしている。
Interface は Data Gear に対しての操作を行う Code Gear であり、実装は別で定義する。
% Interface で定義した Code Gear に


%  Xv6 の書き換えは Interface を用いてモジュール化する。
Interface を使って記述することで Gears OS の機能を置き換えることできるようになる。



\section{インターフェースの定義}
 インターフェースはある Data Gear の定義と、
それに対する操作を行う Code Gear の集合を表現する Meta Data Gear である。
Context では全ての Code Gaer と Data Gear の集合を表現していることに対し、
インターフェースは一部の Code Gear と一部の Data Gear の集合を表現する。


インターフェースを記述することによってノーマルレベルとメタレベルの分離が可能となる。

Paging のインターフェースを記述したコードを ソースコード \ref{interface} に示す。

\lstinputlisting[label=interface, caption={\footnotesize vm のインターフェースの定義(vm.h)}]{./src/fix_vm.h}

1行目で実装名を定義している。
typedef struct の直後に実装名(vm)を書く。


% 2行目から19行目で引数の Data Gear 郡を定義している。
% 初期化された Data Gear がそれぞれの Code Gear の引数として扱われる。
% 例として、2行目で定義された vm が21行目から32行目までの引数と対応している。


% インターフェースの Code Gear の goto による継続先は基本的に不定となっており、継続元から渡される。
Code Gear は\_\_code CodeGearName () で記述する。
第一引数である Impl* vm が Code Gear の型になる。


\_\_code next(...) の引数 ... は複数の Input Data Gear を持つという意味である。
後述する実装によって条件分岐によって複数の継続先が設定されることがある。
それぞれの Code Gear の引数の1つに設定する。引数の最後に設定しているが遷移先で引数を受け取る順番が正しければよい。
 

 Code Gaer は 2行目から15行目のように "\_\_code [Code Gear名]([引数])"で定義する。
この引数が input Data Gear になる。


% 実装側に書く
% 引数の Data Gear はその Code Gear の Input Data Gear になり、引数の Code Gear の中の引 数が Output Data Gear になる。Code Gear の第一引数には Interface を実装した Data Gear を渡す。これは、Code Gear の操作の対象となる Data Gear を設定し ており、後述する継続構文では引数として記述を行わない。


 インターフェースは Data Gear に対しての Code Gear とその Code Gear で扱われている Data Gear の集合を抽象化した Meta Data Gear で、vm.c に対応する実装は別で定義する。

\section{インターフェースの実装の初期化}
インターフェースの定義が終わったので次にインターフェースの使うための初期化についてソースコード \ref{create_impl} で示す。


\lstinputlisting[frame=lrbt,label=create_impl,caption={\footnotesize vm インターフェースの初期化(vm\_impl.cbc)}]{./src/vm_impl_createimpl.cbc}

2行目のようにインターフェースのヘッダーファイルは \#include ではなく \#interface で呼び出す。


create\_impl で、インターフェースを vm で定義する。
5行目で new vm() することでメモリ上にインターフェースの置き場所を確保。vm\_impl も同じようにすることで実装の置き場所を確保し、7行目でインターフェースと実装を紐付ける。


23行目の vm-$>$void\_ret のようにそれぞれの Code Gear 名を enum の番号で代入していく。
enum の番号を使う事で、ポインタによる誤ったアクセスを防ぐことができる。



\section{インターフェース の実装}
初期化したインターフェースの実装の例を説明する。
ソースコード \ref{create_impl} の24行目 C\_init\_vmmvm\_impl が \ref{impl_vm}
 の 6行目の init\_vmmvm\_impl に対応する。

\lstinputlisting[frame=lrbt,label=impl_vm,caption={\footnotesize vm インターフェースの使用(vm\_impl.cbc)}]{./src/vm_impl.cbc}


\section{インターフェース実装内の明示的な遷移の処理}
CbCは状態遷移ベースで記述するため、for文やif文がある場合はさらに実装を分ける。

vm と同じように vm\_impl を定義し、遷移する関数名に対応させていく。分けた実装はさらに別で実装する(vm\_impl\_private.cbc)。

インターフェースの定義、実装、明示的な遷移の流れを図\ref{fig:interface} に示す。
 \begin{figure}[ht]
 \begin{center}
  \includegraphics[width=160mm]{./fig/interface_color}
 \end{center}
 \caption{インターフェースの実装の流れ}
 \label{fig:interface}
\end{figure}

% インターフェースを呼び出す場合は、struct vm* vm = createvm_impl(cbc_context); 


インターフェースで定義した Code Gear 以外の Code Gaer も記述することができる。
この Code Gear は基本的にインターフェースで指定された Code Gear 内からのみ継続されるため、
Java の private メソッドのように扱われる。

インターフェースと同じようにヘッダーファイルをソースコード \ref{impl_vm_privateh} で定義する。


\lstinputlisting[frame=lrbt,label=impl_vm_privateh,caption={\footnotesize vm private のヘッダーファイル}]{./src/vm_impl_private.h}


private での CbC の記述を vm.c と比べて説明する。
全体の記述量が多いため、if文とfor文のある loaduvm という関数で説明を行う。


\begin{lstlisting}[frame=lrbt,label=vm_loaduvm,caption={\footnotesize vm.c のloaduvm}]
// Return the address of the PTE in page directory that corresponds to
// virtual address va.  If alloc!=0, create any required page table pages.
static pte_t* walkpgdir (pde_t *pgdir, const void *va, int alloc)
{
    pde_t *pde;
    pte_t *pgtab;

    // pgdir points to the page directory, get the page direcotry entry (pde)
    pde = &pgdir[PDE_IDX(va)];

    if (*pde & PE_TYPES) {
        pgtab = (pte_t*) p2v(PT_ADDR(*pde));

    } else {
        if (!alloc || (pgtab = (pte_t*) kpt_alloc()) == 0) {
            return 0;
        }

        // Make sure all those PTE_P bits are zero.
        memset(pgtab, 0, PT_SZ);

        // The permissions here are overly generous, but they can
        // be further restricted by the permissions in the page table
        // entries, if necessary.
        *pde = v2p(pgtab) | UPDE_TYPE;
    }

    return &pgtab[PTE_IDX(va)];
}

// Load a program segment into pgdir.  addr must be page-aligned
// and the pages from addr to addr+sz must already be mapped.
int loaduvm (pde_t *pgdir, char *addr, struct inode *ip, uint offset, uint sz)
{
    uint i, pa, n;
    pte_t *pte;

    if ((uint) addr % PTE_SZ != 0) {
        panic("loaduvm: addr must be page aligned");
    }

    for (i = 0; i < sz; i += PTE_SZ) {
        if ((pte = walkpgdir(pgdir, addr + i, 0)) == 0) {
            panic("loaduvm: address should exist");
        }

        pa = PTE_ADDR(*pte);

        if (sz - i < PTE_SZ) {
            n = sz - i;
        } else {
            n = PTE_SZ;
        }

        if (readi(ip, p2v(pa), offset + i, n) != n) {
            return -1;
        }
    }

    return 0;
}

\end{lstlisting}

vm\_impl.cbc の Code Gear であるloaduvmvm\_impl から goto で loaduvm\_ptesize\_checkvm\_impl に遷移する。
vm.c での最初の if 文までの処理を 1つの Code Gear として loaduvm\_ptesize\_checkvm\_impl に記述する。(3行目~11行目)


\section{vm の Context}
メモリ変換の処理で生成される Context の説明をする。
code は全ての Code Gear を列挙した enum と関数ポインタの組みで表現される。(ソースコード \ref{contexth} 55行目~68行目)
Code Gear の名前は enum で定義され、コンパイル後には整数で変換される。
Code Gear に接続する際は enum で定義された番号を指定する。
これによってメタ計算時に接続する Code Gear を切り替えることができる。


Data Gear のメモリ空間は事前に領域を確保した後、必要に応じて領域を割り当てることで実現する。
実際に Allocation する際は ソースコード \ref{contexth} の9行目で定義した heap を Data Gear のサイズ分増やすことで実現する。


\lstinputlisting[label=contexth, caption={\footnotesize 生成された Context}]{./src/context.h}


\section{CbC のループ処理}
 
CbC では goto での状態遷移によって実装するので loop は if 文を使って実装する。
遷移図を 図 \ref{fig:cbc_for_private} で示す。

 \begin{figure}[ht]
 \begin{center}
  \includegraphics[width=160mm]{./fig/cbc_for_private}
 \end{center}
 \caption{CbC によるループの実装}
 \label{fig:cbc_for_private}
\end{figure}


\lstinputlisting[frame=lrbt,label=impl_vm_loaduvm,caption={\footnotesize loaduvm の実装の記述}]{./src/vm_impl_private.cbc}

for文から末尾再起の変換について
図 \ref{fig:cbc_for_private} のように loaduvm\_loopvm\_impl のif 文で ループの条件を書いて goto させ、loaduvm\_check\_PTE\_SZ で満たしてなければ loaduvm\_loopvm\_impl に goto することでループを実装している。


static なものはまだ書き直していないが後々実装する

\section{Meta Code Gear の記述}
cmake によって生成されたメタ部分の記述について説明する。
ファイルはビルドディレクトリ以下の /CMakeFiles/kernel.dir/c/ に生成される。


ノーマルレベルの Code Gear と ノーマルレベルの Code Gear 名 の後ろに \_stub が付いた Meta Code Gearが対応する。
例として loaduvm の生成された Code Gear と Meta Code Gear をソースコード \ref{loaduvm_stub} に示す。

\lstinputlisting[frame=lrbt,label=loaduvm_stub,caption={\footnotesize loaduvm のメタ部分の記述}]{./src/stub_loaduvm}



\section{インターフェースの呼び出し}
定義したインターフェースの呼び出し方について説明する。
 CbC の場合 goto による遷移を行うので、関数呼び出しのように goto 以降のコードを実行できない。

\lstinputlisting[frame=lrbt,label=cbc_goto,caption={\footnotesize cbc インターフェースのgoto}]{./src/failure_example_userinit}

例として、ソースコード \ref{cbc_goto} の15行目のように goto によってインターフェースで定義した命令を行うと、戻ってこれないため16行目以降が実行されなくなる。


\lstinputlisting[frame=lrbt,label=dummy,caption={\footnotesize dummy を使った呼び出し}]{./src/dummy}
7行目から11行目の引数の設定に Gearef を使っているが、本来は CMake で生成しその部分には何も書かない。
11行目の C\_vm\_void\_ret は return するための enum コードであり、これを使って関数呼び出しのように振る舞う。