annotate code-mangement.ind @ 7:319a58e580e4

...
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Mon, 17 Apr 2023 18:29:04 +0900
parents c6bea5a028fd
children 36b34f6e906a
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
977222ed78ab first commit
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
1 -title: Gears OSの CodeGear Management
977222ed78ab first commit
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
2
6
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
3 -author: 仲吉菜々子 and 河野真治
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
4
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
5 --abstract:
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
6
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
7 GearsOSではすべてのプログラムはKernelやdriverを含めて CodeGear
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
8 で書かれている。これらは、CodeGear のSystem DBに格納される
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
9 べきである。Microwre OS9でもmoduleという形でメモリに展開さ
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
10 れていた。CodeGearの集合で一つのアプリやサービスが作られる。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
11 このCodeGearnの組み合わせを指定する仕組みが必要である。また、
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
12 CodeGear を実行時にloadする機構を作ることにより、現在、clnag
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
13 のlinkerで行っている作業抜きでGearsOSを構成できる。これによ
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
14 り、GearsOSのbuildを簡単にすることができる。高速化が必要な
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
15 場合は、複数のCodeGearをまとめて最適化して、一つのCodeGearn
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
16 にする。しかし、実行時のメタ計算がが必要な場合は、それよう
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
17 のhookを用意する必要がある。これの仕組みについて考察する。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
18
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
19 --abstract-e:
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
20
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
21 In GearsOS, all programs, including kernels and drivers, are
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
22 written in CodeGear. These should be stored in the System DB
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
23 of CodeGear. In Microwre OS9, they were deployed in memory
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
24 as modules. An application or service is created using a set
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
25 of CodeGear. A mechanism is needed to specify the combination
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
26 of CodeGear. Additionally, by creating a mechanism to load
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
27 CodeGear at runtime, GearsOS can be built without the work
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
28 currently done by the clnag linker. This simplifies the process
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
29 of building GearsOS. When optimization is necessary, multiple
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
30 CodeGear can be combined and optimized to create a single CodeGear.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
31 However, if runtime metacalculation is necessary, a hook must
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
32 be provided for it.
0
977222ed78ab first commit
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
33
1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
34 --Gears OSによる信頼できるサービス
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
35
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
36 サービスやアプリケーションの信頼性は、OSとユーザプログラムのように分離することはできない。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
37 プログラムの正しさは基本的にはコードの正しさであり、今のOSのようにコードの管理をユーザ空間の
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
38 問題として放り出す方法には限界がある。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
39
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
40 Gears OSでは実行単位として codeGear、データ単位として dataGear を使う。さらに、これらは
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
41 Monad のようにメタ codeGeearやメタdataGearを持っている。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
42
6
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
43 Gears OSでの検証は、Agda\cite{Agda,AgdaWiki}を使った GearsAgdaを用いる。これらの実行と並列実行は、
1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
44 GearsAgdaに対して定義される。当然、すべてのGearsAgdaのcodeGearは、Gears OSに
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
45 登録されることになる。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
46
6
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
47 OSでの証明よる検証はいろいろ行なわれているが、Haskellに近い形式に変換することが多い
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
48 \cite{Klein:2014:CFV:2584468.2560537,Chen:2015:UCH:2815400.2815402,Yang:2010:SLI:1806596.1806610}。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
49 Gears OSでは、GearsAgda で直接に記述できる点が新しい。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
50
1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
51 この論文では、Gears OSのcodeGearの管理方法について考察する。
0
977222ed78ab first commit
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
52
977222ed78ab first commit
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
53 --Normal and Meta computation
977222ed78ab first commit
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
54
6
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
55 Gears OSの基本は、CbC (Continuation based C)\cite{cbc-github}であり、input interfaceとoutput interfaceを有限な処理で
1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
56 結ぶものになっている。これは、コンパイラの基本ブロックに大体相当する。これはさらに、GearsAgdaの
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
57 Agdaで記述された invariant あるいは、表示的意味論と直結している。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
58
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
59 CbCの記述は以下のようなものである。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
60
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
61 __code startTimer(struct TimerImpl* timer, __code next(...)) {
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
62 struct timeval tv;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
63 gettimeofday(&tv, NULL);
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
64 timer->time = tv.tv_sec + (double)tv.tv_usec*1e-6;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
65 goto next(...);
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
66 }
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
67
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
68 nextが軽量継続を表している。このcodeGearの実行は論理的に割り込まれない。つまり、並行実行は
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
69 この単位で行われ定義される。ハードウェアでの並行実行、割り込み処理などは、それにそって
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
70 実装される必要がある。これらは、GearsAgdaでは、外部環境へのアクセスがある。この場合は
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
71 時刻に対するアクセスである。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
72
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
73 OS側からみると、これは詳細のない単なるコードに見える。実行の詳細、つまり、実行に関係する
6
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
74 すべての dataGear 、すべてのcodeGearは、プロセスに相当する Context metaDataGear(図\ref{Gears OS})に格納される。
1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
75
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
76 つまり、OSからみた codeGearの実行は、
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
77
6
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
78 meta codeGearの番号から、codeGearを選ぶ
1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
79   それを実行し、continuation としてshcedulerを指定する
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
80   これを CPU worker 毎に実行する
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
81
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
82 ということになる。CPU worker毎に Contextは一つなので、Contextはsingle threadで実行される。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
83 これにより、並行実行の単位はcodeGearとなる。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
84 ただし、Context関の共有データがある場合は意味的なずれがでる場合がある。それは、
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
85 Contextの実行をそうなるように実装することになる。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
86
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
87 その実装の正しさは、実装を GearsAgdaで記述することより可能になるが、その実装が物理的に一致するかどうかの
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
88 保証はハードウェアの性質に依存する。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
89
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
90 外界との対応もメタ計算になるが、それはGearsAgdaによるシミュレーションに対する正しさということになる。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
91
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
92 scheduler から codeGearへの移行は、以下のmeta codeGear で実装される。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
93
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
94 __code meta(struct Context* context, enum Code next) {
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
95 goto (context->code[next])(context);
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
96 }
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
97
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
98
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
99 \verb+context->code[next]+が codeGearのtableの呼び出しになるが、
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
100 これは表がコンパイル時に確定し、直接の呼び出しでは、コンパイラが最適化するので、overhead とはならない。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
101 meta が書き換えられている場合は、ここで Context switchが起きることになる。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
102
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
103 このContext switchでメモリ空間の切り替えが必要かどうかは application に依存する。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
104 もし、codeGearの実行の正しさが証明されているなら、メモリ空間を切り替える必然性はない。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
105 実際、Kernel 内や Realtime Monitor では切り替えない方が普通である。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
106
6
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
107 <center><img src="fig/gears_structure.pdf" alt="Gears OS"></center>
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
108
1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
109 --証明付きのコード
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
110
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
111 GearsAgdaで記述されていれば、codeGearやdataGearは証明を持つ。これらは単なる型なので実行時には
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
112 実態を持たない。ただし、それを実行時にチェックすることもできる。assertなどと同じ扱いである。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
113
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
114 GearsAgdaの証明に閉じていれば、その範囲内での信頼性がある。しかし、動的にcodeが読み込まれる場合は
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
115 そうはならない。その時には、証明しなおす、簡易あるいは詳細なモデル検査を実施するなどが可能だが、
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
116 それらが実用的とは限らない。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
117
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
118 codeはContextの表に登録されるが、システム全体のcodeは Database で管理される。その管理は
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
119 ファイルシステム上でも良い。codeは証明が付属している場合もあるが、それは何らかの形で
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
120 codeGear Databseに格納される。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
121
2
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
122 現状では、証明はAgdaで記述されたデータ構造でしかない。それをcodeGear DBに入れても利用する方法は
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
123 ないがいくつかの利用法は考えられる。
1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
124
2
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
125 証明とcodeGearの一致を確認する
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
126 型整合に使う
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
127 codeの認証に使う
1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
128
2
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
129 この大域のcodeGear DBは、kernelを含めたすべてのcodeGearに対するもので全部で共有される。つまり、
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
130 あらゆるversionを含む共有ライブラリとなる。これは全世界でuniqueなDBとしても良い。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
131
4
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
132 --CbCのcodeGear と GearsAgdaの違い
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
133
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
134 CbCのcodeGearとdataGearは、普通のCの関数と構造体であり、その意味で不思議なところはない。しかし、
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
135 normal levelではpointerが出てこないのが望ましい。なぜなら、メモリ配置は meta levelの問題で
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
136 プログラムの正しさとは直接関係しないからである。つまり、normal levelでの構造体は List や 木
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
137 など以外の再帰的構造でも直接的なポインタ操作は行わない。meta levelでは、メモリの直接操作
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
138 例えば mallocやfree、あるいは共有データの扱いなどをポインタを通して行う。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
139
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
140 meta levelでのポインタ操作は、データ構造に対する操作であり、そのlevelに閉じる限り、
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
141 プログラムの正しさはポインタの実装に依存しない。その意味で、meta codeGear も単なる
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
142 noraml level のcodeGear に過ぎない。meta codeGearの証明あるいは、実装をさらにmeta level
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
143 で行うこともできる。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
144
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
145 GearsAgda では、すべてはAgdaの構造体で表現される。これらは変数と項であり、基本的に複製可能
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
146 な項である。その意味で、ポインタを持たないと言ってよい。Listや木の実装を配列と番号で行う
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
147 ことはまったく実用的ではないので、普通に再帰的なデータ構造を使ってよい。ただし、それを
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
148 自分自身の codeGear の再帰呼び出しで行うと、codeGearの実行が有界な時間に閉じなくなる。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
149 なので、loop は軽量継続を用いて、一旦、外にでることになる。これは、この段階でmeta level的に処理が
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
150 割り込まれることも意味している。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
151
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
152 GearsAgda で処理された項は、ContextのdataGearに格納される。また、GearsAgdaのcodeGearは、
6
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
153 Contextのcode table(図\ref{code table})に格納される。どちらも、メモリ的には番号で管理されることになる。
4
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
154 GearsAgda の Context は、その意味で、プロセスのメモリ空間そのものを抽象化したものになっている。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
155
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
156
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
157 つまり、CbCのcodeGearと GearsAgdaは、normal level ではポインタを使わないのだが、
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
158 その意味は、CbCと GearsAgda で若干異なる。CbCでの実装は、GearsAgdaでの実装の持つ
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
159 性質を保存する必要がある。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
160
6
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
161 <center><img src="fig/codetable.pdf" alt="code table"></center>
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
162
4
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
163 --Contextを通した dataGearとcodeGearの連携
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
164
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
165 Gears OSでは、Context はCの構造体であり、一つのContextで使用するdataGearとcodeGearは、そこに格納される。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
166 複数のContextから、dataGearもcodeGearも共有されることがある。その排他制御は、Gears OSのmeta codeGearに
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
167 よって行われる。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
168
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
169 Gears OSは、interfaceという構造体でオブジェクト表現していて、これらには、メソッドを格納する配列がある。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
170 この配列の添字を他のinterfaceが使用する。なので、interface間の呼び出しは、interfaceを表すdataGearと
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
171 そのメソッドの番号で決定される。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
172
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
173 引数は、interface毎に Contextに決まった場所が確保される。これは、通常ではstack上に場所を確保する。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
174 しかし、CbCでは関数呼び出しはstackを使わないので、このようにする必要がある。これは、もちろん、
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
175 マルチスレッドな実行では破壊されるおそれがあるが、Contextはシングルスレッドで実行することになっている
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
176 ので問題ない。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
177
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
178 Contextの切り替えは、codeGearの境目で行われるので、Contextと実行しているcodeGearのcode tableの番号で
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
179 状態が決定する。つまり、Gears OSでは、Task Switchにはレジスタは関係しない。割り込みなどは、codeGearの
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
180 境界と独立に起きるが、それをmeta codeGearが境界で Context switchが起きたのと同じようにすることを
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
181 保証する。これは一種の遅延処理となる。もちろん、影響がないなら、割り込み中にmetaな処理を行ってもよい。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
182 これは、本来はCPUなどのハードウェアでサポートされるべきかもしれない。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
183
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
184 dataGearは、metaな情報として、dataGearの構造定義を番号として持っている。これを使うことにより
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
185 任意のdataGearの表示を正しく行うことができる。この情報を取り扱うことは meta level からでしか
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
186 許されないが、CbC的には特に制限はない。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
187
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
188 引数として呼び出される dataGearは、Context上に前もって確保されているが、実行時にallocateされる
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
189 dataGearもContextから参照される pool に確保される。これの管理は meta dataGear (Gears OSのkernel)
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
190 が行う。GearsAgda は、この部分はAgdaが管理するので meta的な管理は行われない。しかし、
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
191 Context を用いた並行実行の場合は、Context上での管理の問題が生じる。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
192
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
193
6
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
194 --code table
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
195
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
196 contextの初期化の中で、code table に実際の codeGear stub へのポインタが初期化される。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
197
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
198 context->code[C_add] = add_stub;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
199 context->code[C_checkAndSetAtomicReference]
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
200 = checkAndSetAtomicReference_stub;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
201 context->code[C_clearSingleLinkedQueue] = clearSingleLinkedQueue_stub;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
202 context->code[C_clearSynchronizedQueue] = clearSynchronizedQueue_stub;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
203 context->code[C_code1] = code1_stub;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
204 context->code[C_createTask1] = createTask1_stub;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
205 context->code[C_createTask2] = createTask2_stub;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
206 context->code[C_decrementTaskCountTaskManagerImpl]
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
207 = decrementTaskCountTaskManagerImpl_stub;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
208 context->code[C_exit_code] = exit_code_stub;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
209 context->code[C_getTaskCPUWorker] = getTaskCPUWorker_stub;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
210 context->code[C_incrementTaskCountTaskManagerImpl]
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
211 = incrementTaskCountTaskManagerImpl_stub;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
212
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
213 interfaceの初期化の中で、この番号が interfaceを表す dataGearに格納される。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
214
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
215 Tree* createRedBlackTree(struct Context* context) {
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
216 struct Tree* tree = &ALLOCATE(context, Tree)->Tree;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
217 struct RedBlackTree* redBlackTree
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
218 = &ALLOCATE(context, RedBlackTree)->RedBlackTree;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
219 tree->tree = (union Data*)redBlackTree;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
220 redBlackTree->root = NULL;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
221 redBlackTree->nodeStack = createSingleLinkedStack(context);
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
222 tree->put = C_putRedBlackTree;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
223 tree->get = C_getRedBlackTree;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
224 tree->remove = C_removeRedBlackTree;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
225 return tree;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
226 }
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
227
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
228 この辺の構造は、GearsAgda 側では簡素化されている。実際、pointer を直接操作しないとかも、厳密に守る必要はなく、
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
229 GearsAgda と CbC での実装が平行していれば問題はない。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
230
2
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
231 --codeGearのlinkage
1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
232
2
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
233 Gears OSのあらゆるコードは、codeGear DBのコードの組み合わせになる。しかし、そのためには、
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
234 Contextから詳細なデータを取り出して、実行し、次のcodeGearを呼び出す時にContextの正しい場所にdataGearを格納する
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
235 必要がある。これは codeGear 全体に対して必要になる。
1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
236
2
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
237 現状では、これは stubとしてコンパイル時に生成される。
1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 0
diff changeset
238
6
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
239 __code checkAndSetAtomicReference(struct AtomicReference* atomic,
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
240 union Data** ptr, union Data* oldData, union Data* newData, __code next(...),
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
241 __code fail(...)) {
2
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
242 if (__sync_bool_compare_and_swap(ptr, oldData, newData)) {
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
243 goto next(...);
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
244 }
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
245 goto fail(...);
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
246 }
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
247
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
248 では、Context 上には以下の構造と、それを呼び出す stub がある。
0
977222ed78ab first commit
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
249
2
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
250 struct Atomic {
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
251 union Data* atomic;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
252 union Data** ptr;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
253 union Data* oldData;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
254 union Data* newData;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
255 enum Code checkAndSet;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
256 enum Code next;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
257 enum Code fail;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
258 } Atomic;
0
977222ed78ab first commit
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
259
2
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
260 __code checkAndSetAtomicReference_stub(struct Context* context) {
6
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
261 AtomicReference* atomic = (AtomicReference*)
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
262 GearImpl(context, Atomic, atomic);
2
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
263 Data** ptr = Gearef(context, Atomic)->ptr;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
264 Data* oldData = Gearef(context, Atomic)->oldData;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
265 Data* newData = Gearef(context, Atomic)->newData;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
266 enum Code next = Gearef(context, Atomic)->next;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
267 enum Code fail = Gearef(context, Atomic)->fail;
6
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
268 goto checkAndSetAtomicReference(context, atomic,
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
269 ptr, oldData, newData, next, fail);
2
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
270 }
0
977222ed78ab first commit
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
271
2
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
272 これらは単一のGears OS内で整合する必要がある。実際には、これらは、stubが参照する Context内のoffsetにすぎない。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
273 Atomic は dataGear の巨大な Union になっている。これは、GearsAgda でも状況は同じで、巨大な Sum type になっている。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
274
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
275 このContext内での offsetと呼び出すcodeGearの番号が一致すれば、Kernel側で整合性の問題はない。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
276
4
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
277 --codeGearのコンパイル方法
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
278
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
279 現在の Gears OSのcodeGearは、interfaceを含む記述を .cbc に書き、それを CbC に変換している。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
280 この時に、meta codeGear として stub そして、meta dataGearとして Context の定義が生成される。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
281
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
282 Context の定義は Application 毎に異なっているが、全部をそろえることも可能である。この変換は
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
283 Perl script で記述されていて、煩雑になっている。これを codeGear / interface 単位で .o と
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
284 meta dataGearにできれば、全体の構成と、interfaceのコンパイルが簡単になると期待される。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
285
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
286 ただし、この場合は、Context の中での引数領域のoffset管理、code tableの初期化、code間の
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
287 遷移を扱う codeGearの番号の指定の書き換えなどが必要となる。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
288
2
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
289 --static linkage
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
290
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
291 コンパイル時に codeGearの結合が明らかならば、それは一つのcodeGearとしてまとめてよい。Contextへの書き込みもさぼることが
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
292 可能になる。ただし、時分割実行される場合は、codeGearの切れ目で分割するのと同じ実行が要求される。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
293 つまり、割り込み処理などで途中で実行が中断するならば、それはその単位まで実行してから、Contextを切り替える必要がある。
0
977222ed78ab first commit
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
294
2
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
295 これを実現する手法はflagを参照する方法や、コードを書き換える方法あるいは、polingを埋め込むなどの方法が考えられる。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
296 整合性が不要であれば途中で止めても問題ないが、その場合は register などの状態を従来のOSのように保持する必要がある。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
297
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
298 codeGear単位で正直に分割コンパイルすると最適化の余地がない。しかし、その場合でもJITなどは可能である。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
299
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
300 --boot codeGear
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
301
6
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 4
diff changeset
302 今の実装では、UEFIから Gears OSが読み出される。Gears OS自体は、x.v6\cite{xv6rpi}と同じで、ファイルシステムを
2
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
303 含む一体の binary になっている。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
304
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 1
diff changeset
305 codeGear DBを実装すれば、かなりの部分を後からロードすることが可能になる。
0
977222ed78ab first commit
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
306
4
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
307
0
977222ed78ab first commit
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
308 --まとめ
4
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
309
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
310 Gears OS と GearsAgda における codeGear の管理方法について考察した。将来的には GearsAgda で記述された
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
311 証明付きinterfaceのコードを CbC に変換し、それを Gears OSで正しさを確認しながら組み合わせて、meta計算の
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
312 変更を可能にしながら実行するシステムを作りたい。
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
313
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
314
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
315
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
316
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 2
diff changeset
317