Mercurial > hg > Papers > 2020 > tobaru-master
view paper/cbc_interface.tex @ 20:ff1f2c66a84d
rm tex file
author | tobaru |
---|---|
date | Sat, 08 Feb 2020 17:22:55 +0900 |
parents | 98cee2f6c919 |
children | ee9435951c31 |
line wrap: on
line source
\chapter{CbC インターフェース} 構造図書く(今のcbcxv6と同じか確認してから) 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 を用いてモジュール化する。 そうすることで 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 は 20行目から33行目のように "\_\_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 を設定し ており、後述する継続構文では引数として記述を行わない。 \section{インターフェースの実装} インターフェースは Data Gear に対しての Code Gear とその Code Gear で扱われている Data Gear の集合を抽象化した Meta Data Gear で、vm.c に対応する実装は別で定義する。 インターフェースの実装についてソースコード \ref{impl_vm} で示す。 \lstinputlisting[frame=lrbt,label=impl_vm,caption={\footnotesize vm インターフェースの実装}]{./src/vm_impl.cbc} 2行目のようにインターフェースのヘッダーファイルは \#include ではなく \#interface で呼び出す。 create\_impl の関数内で、インターフェースを vm で定義し、23行目の vm-$>$void\_ret のようにそれぞれの Code Gear 名に対応させていく。 CbCは1つ1つの Code Gear の信頼性を保障させるために細かくする必要があるので、for文やif文がある場合はさらに実装を分ける。vm と同じように vm\_impl を定義し、遷移する関数名に対応させていく。分けた実装はさらに別で実装する(vm\_impl\_private.cbc)。 % インターフェースを呼び出す場合は、struct vm* vm = createvm_impl(cbc_context); \section{インターフェース内の private メソッド} インターフェースで定義した 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行目) 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} \begin{lstlisting}[frame=lrbt,label=impl_vm_loaduvm,caption={\footnotesize privateでの loaduvm の実装}] #interface "vm_impl.h" __code loaduvm_ptesize_checkvm_impl(struct vm_impl* vm_impl, __code next(int ret, ...)) { char* addr = vm_impl->addr; if ((uint) addr %PTE_SZ != 0) { // goto panic } goto loaduvm_loopvm_impl(vm_impl, next(ret, ...)); } __code loaduvm_loopvm_impl(struct vm_impl* vm_impl, __code next(int ret, ...)) { uint i = vm_impl->i; uint sz = vm_impl->sz; if (i < sz) { goto loaduvm_check_pgdir(vm_impl, next(ret, ...)); } goto loaduvm_exit(vm_impl, next(ret, ...)); } 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)]; } __code loaduvm_check_pgdir(struct vm_impl* vm_impl, __code next(int ret, ...)) { pte_t* pte = vm_impl->pte; pde_t* pgdir = vm_impl->pgdir; uint i = vm_impl->i; char* addr = vm_impl->addr; uint pa = vm_impl->pa; if ((pte = walkpgdir(pgdir, addr + i, 0)) == 0) { // goto panic } pa = PTE_ADDR(*pte); vm_impl->pte = pte; vm_impl->pgdir = pgdir; vm_impl->addr = addr; vm_impl->pa = pa; goto loaduvm_check_PTE_SZ(vm_impl, next(ret, ...)); } __code loaduvm_check_PTE_SZ(struct vm_impl* vm_impl, __code next(int ret, ...)) { uint sz = vm_impl->sz; uint i = vm_impl->i; uint n = vm_impl->n; struct inode* ip = vm_impl->ip; uint pa = vm_impl->pa; uint offset = vm_impl->offset; if (sz - i < PTE_SZ) { n = sz - i; } else { n = PTE_SZ; } if (readi(ip, p2v(pa), offset + i, n) != n) { ret = -1; goto next(ret, ...); } vm_impl->n = n; goto loaduvm_loopvm_impl(vm_impl, next(ret, ...)); } __code loaduvm_exit(struct vm_impl* vm_impl, __code next(int ret, ...)) { ret = 0; goto next(ret, ...); } \end{lstlisting} for文から末尾再起の変換について static なものに関しては後々実装する \section{インターフェースの呼び出し} 定義したインターフェースの呼び出し方について説明する。 CbC の場合 goto による遷移を行うので、関数呼び出しのように goto 以降のコードを実行できない。 例として、ソースコード \ref{cbc_goto} の16行目のように goto によってインターフェースで定義した命令を行うと、戻ってこれないため17行目以降が実行されなくなる。 \lstinputlisting[frame=lrbt,label=cbc_goto,caption={\footnotesize cbc インターフェースのgoto}]{./src/failure_example_userinit} \lstinputlisting[frame=lrbt,label=dummy,caption={\footnotesize dummy を使った呼び出し}]{./src/dummy} ソースコードの説明 - dummy を使って解決する