Annotation of OpenXM/src/kxx/openintro.tex, Revision 1.1.1.1
1.1 maekawa 1: %#!platex
2: %% 数式処理に投稿する場合はこちらを使用する.
3: % \documentclass{jarticle}
4: % \usepackage{jssac}
5:
6: % \title{Open asir 入門}
7: % \author{
8: % 小原 功任
9: % \affil{神戸大学大学院自然科学研究科}
10: % \mail{ohara@math.kobe-u.ac.jp}
11: % \and
12: % 高山 信毅
13: % \affil{神戸大学理学部数学教室}
14: % \mail{taka@math.kobe-u.ac.jp}
15: % \and
16: % 野呂 正行
17: % \affil{富士通研究所 HPC 研究センター}
18: % \mail{noro@para.flab.fujitsu.co.jp}
19: % }
20: %\art{}
21:
22: %% 古い LaTeX でコンパイルする場合はこちら
23: \documentstyle{jarticle}
24: \title{Open asir 入門}
25: \author{小原功任\thanks{神戸大学大学院自然科学研究科},
26: 高山信毅\thanks{神戸大学理学部数学教室},
27: 野呂正行\thanks{富士通研究所 HPC 研究センター}}
28: \date{1998, 11月27日}
29:
30: %% 以下は共通
31: \begin{document}
32: \maketitle
33:
34: \section{Open asir とは}
35:
36: Open xxx は, 同じタイプまたは異なるタイプの数学プロセス間の
37: メッセージのやりとりの規約である.
38: 開発の動機は, 手作り(または研究的な)数学ソフトの相互乗り入れの実現
39: および分散計算の実装が第一であったが,
40: もちろん数学ソフト間だけでなく, ワープロソフトや,
41: インタラクティブな数学本,
42: さらには数学デジタル博物館用のソフトがこの規約に従い,
43: 数学ソフトを呼び出すことなどにも利用できる.
44: さらに, だれでもこのプロジェクトに参加できるように
45: 規約を拡張していくための規約も定めるものとする.
46:
47: 設計の方針として, (1) 単純 (2) 拡張性 (3) 実装の簡便さ (4) 実用性,
48: に重きをおいている.
49: Open xxx はなにも考えずに簡単に接続できるシステムを作ろう,
50: というまで野心的ではない.
51: 数学的なオブジェクトは一筋縄ではいかないし,
52: 完全な統一規格をつくるというのは
53: 気が遠くなる仕事である.
54: そのかわり, 今よりすこしだけこのようなデータ交換や分散システム構築の仕事を楽に
55: したいというのがささやかな第1目標である.
56:
57: 数学的なオブジェクトをどのように表現するのか,
58: どう伝えるのかを考えることは決してつまらない問題ではない.
59: このような問題は, 新しい数学記号を創造する問題と似ているかもしれない.
60: 我々は, 数字を $0$ を含んだ10進数で表記し,
61: 微分を $dx$ と書き, 写像を $\longrightarrow$ であらわす.
62: これらの記号法からどれだけ多くの利益を得ているか, 思いをはせて欲しい.
63: また, Mathematica や Maple といった統合ソフトを, 我々自身の
64: 手でつくっていくための基礎でもある.
65:
66: さて, Open asir は Open xxx 規約を実装した asir サーバである.
67: Open xxx 規約にしたがったメッセージを Open asir サーバに送ることにより,
68: asir の全機能を利用することができる.
69: 現在, Open xxx 規約に基づく計算サーバとしては, Linux 上で動作する
70: Open asir と Open sm1 (kan/sm1) がバイナリで提供されている.
71: ユーザは自分でクライアントを C, Java, Lisp (さらに asir, sm1) などの
72: 言語で作成して, Open asir を利用することができる.
73: また, MathLink との変換ソフトを書けば, Mathematica のサーバになることも
74: 可能である.
75:
76: Open asir の基本的な計算のモデルはメッセージの交換である.
77: Open asir サーバに計算させたいものをメッセージとして送り,
78: 次いで計算結果をメッセージとして受け取るという形で計算は進行する.
79: 通常, メッセージのやりとりには大きく分けて,
80: 同期的なやりとりと非同期的なやりとりが考えられる.
81: ここで同期的なやりとりとは, 双方のプロセスがあらかじめタイミングを決めて
82: メッセージのやりとりをすることをいう.
83: このとき, それぞれのプロセスは相手からのメッセージが届くまでの間は
84: ブロックされる.
85: 非同期的なやりとりとは, それぞれのプロセスがメッセージを送った後,
86: 相手の状態にかかわらず, すぐに復帰するようなやりとりのことである.
87: 現在のサーバは, 非同期的なメッセージのやりとりのみ実装している.
88:
89: このモデルを現在は, TCP/IP とソケットを用いて実装しているが,
90: Open xxx 規約自身は TCP/IP に縛られているわけではないので,
91: もちろん, MPI や PVM などの上にこのモデルを実装してもいいし,
92: ファイルよりメッセージを読み込み結果をファイルへ書き出してもよい.
93: この Open xxx 規約は文献 \cite{Openxxx-1998} で定義されている.
94: \cite{Openxxx-1998}の \TeX ソースは
95: \begin{center}
96: {\tt http://www.math.kobe-u.ac.jp/openxxx/}
97: \end{center}
98: から入手することが出来る.
99:
100: なお, Open xxx 規約は現在研究中のプロトコルであり,
101: 規約, 実装の変更が随時おこなわれている.
102: また, 同様の試みとして, openmath
103: \begin{center}
104: {\tt http://www.openmath.org/}
105: \end{center}
106: がある.
107: こちらとの関係も考慮して行きたい.
108:
109: この文書は Open asir クライアントの作成を通じて,
110: Open xxx 規約(プロトコル)の考え方を説明することをその目的とするため,
111: 必要に応じて C 言語によるプログラムのソースを例示する.
112: この文書で, 引用されているクライアントの完全なソース(このソースは,
113: Redhat Linux 4.2 または FreeBSD 2.2.6でコンパイル可能である)
114: は,
115: \cite{Openxxx-1998} と同じページより入手することが出来る.
116: open sm1 サーバも同じページより入手できる.
117: また, Linux 版の Open asir サーバ実験版も同じページにおくよう
118: 努力したい.
119: 問題点などの指摘は, {\tt openxxx@math.kobe-u.ac.jp} へメールを
120: おくってほしい.
121: %% 小原君, 田村君: この openxxx ホーム, メールの運用も宜しくね...
122:
123: \section{Open asir で扱われるデータ}
124:
125: Open asir とやりとりするメッセージは, データあるいは命令(コマンド)である.
126: これについてはあとでまた説明することにして,
127: この節ではこのデータの形式(フォーマット)を説明しよう.
128: Open asir で扱われるデータは Common Math Object (CMO) と呼ばれる形式の
129: データである.
130: CMO はデータ型を示すタグとデータ本体より構成されている.
131: 例えば32bit整数値 1234 は, (CMO\_INT32, 1234) なる CMO として表現される.
132: この表記方法は CMO expression と呼ばれている.
133: CMO expression は, CMO の実体の構造を人間が読みやすいような形式で表現し
134: たものであり, マシン語(バイト列)に対応するアセンブリ言語または高級言語のよ
135: うなものだと思ってもよい.
136: ここで CMO\_INT32 がデータ型を表すタグである.
137: おなじように, 長さが $6$ の文字列 {\tt "abcdef"} は
138: (CMO\_STRING, 6, "abcdef")
139: という CMO で表現する.
140:
141: これらのデータ型を表すタグ CMO\_INT32, CMO\_STRING などは 32bit 整数値
142: であり, Open xxx 規約で
143: \begin{verbatim}
144: #define CMO_NULL 1
145: #define CMO_INT32 2
146: #define CMO_DATUM 3
147: #define CMO_STRING 4
148:
149: #define CMO_LIST 17
150: #define CMO_MONOMIAL32 19
151: #define CMO_ZZ 20
152: #define CMO_QQ 21
153: #define CMO_ZERO 22
154: #define CMO_DMS 23
155: \end{verbatim}
156: などと定義されている.
157: 現在の TCP/IP での実装では, たとえば
158: (CMO\_INT32, 1234)
159: は
160: \[
161: \mbox{\tt 00 00 00 02 00 00 04 d2}
162: \]
163: という16進バイト列に変換される.
164: さっきのマシン語のたとえをつかうとこちらがマシン語(バイト列)に対応する.
165:
166: その他のデータ型としては, リスト, 多重精度整数(bignum),
167: 分散表現多項式などが現在用意されている.
168: 主要なデータ型の非形式的な定義をあげておく.
169:
170: \noindent
171: いま述べた 32bit整数 $n$ は CMObject としては Integer32 と呼ばれ, \\
172: \begin{tabular}{|c|c|}
173: \hline
174: {\tt int32 CMO\_INT32}& {\tt int32 $n$} \\
175: \hline
176: \end{tabular} \\
177: なる形で表現する.
178: ここで, 表の各項目は,
179: \begin{tabular}{|c|c|}
180: \hline
181: データ型 & データ\\
182: \hline
183: \end{tabular}
184: なる形で表現している.
185:
186: \noindent
187: 長さ $n$ の 文字列 s は, CMObject としては, Cstring 型とよばれ \\
188: \begin{tabular}{|c|c|c|c|c|c|}
189: \hline
190: {\tt int32 CMO\_STRING}& {\tt int32 $n$} & {\tt byte} s[0]
191: & {\tt byte} s[1] &
192: $\cdots$ & {\tt byte} s[$n-1$] \\
193: \hline
194: \end{tabular} \\
195: と表現する. C 言語で普通用いられる, 文字列の終端の {\tt 0} は文字列
196: には含めない.
197:
198: \noindent
199: 長さ $m$ のリストは \\
200: \begin{tabular}{|c|c|c|c|c|}
201: \hline
202: {\tt int32 CMO\_LIST}& {\tt int32 $m$} & {\tt CMObject}\, ob[0] & $\cdots$ &
203: {\tt CMObject}\, ob[$m-1$] \\
204: \hline
205: \end{tabular}\\
206: で表現する.
207:
208: 各データ型のさらに詳しい定義, および形式的記述法は,
209: \cite{Openxxx-1998} を参照してほしい.
210: CMO の定義を正確かつ簡単に行うには形式的記述法が不可欠であることを
211: 注意しておく.
212:
213: \section{Open asir サーバとの通信}
214:
215: 現在のサーバの実装では, サーバ・クライアント間の通信は
216: ソケットを用いて, ストリーム型で行う.
217: 現在実装されているサーバは, ふたつのプロセスに別れていて,
218: 実際の計算を行うプロセスと制御命令を受け取るプロセスからなる.
219: 計算の中断, サーバの終了などの制御命令はコントロールプロセスに
220: 送ることになる.
221: この文書では, 特に断らない場合には「サーバへの送信」は実際の計算を行う
222: プロセスへの送信のことを指す.
223:
224: 現在実装されているサーバがふたつのプロセスに分れているのは以下の理由によ
225: る.
226: 我々は, クライアントがサーバに任意のタイミングで計算の中断を指示できる
227: 機能が必要であると考える.
228: この機能は, 現在の実装では, コントロールプロセスが計算プロセスにUNIXの
229: シグナルを送ることで実現している.
230: Open xxx規約はネットワーク透過性を目指しているが, サーバとクライアントが
231: 異なるマシンで動作している場合には, クライアントが直接シグナルを送ること
232: は困難である.
233: しかしながら, 計算プロセスと同じマシン上にコントロールプロセスがあってク
234: ライアントと別の通信路で結ばれていれば, クライアントからのメッセージをコ
235: ントロールプロセスが受取り, かわりに計算プロセスへのシグナルを送ることは
236: できる.
237: 我々は, このような構成で信頼性の高いメッセージのやりとりを実現しているの
238: である.
239: 実際にどのような手順で計算の中断を実現しているかについては
240: Section~\ref{section:reset}で詳しく説明する.
241:
242: さて, 最初にクライアントは両方のプロセスとの通信路を確保する必要がある.
243: これは, コントロールプロセス, 計算プロセスの順に通信路を確保しなければな
244: らない.
245: % また単なる時間稼ぎとして, usleep を挟むことが, 現在のサーバの実装では必
246: % 要である.
247: % この理由がいまいちよく分かりません. 特定のサーバの実装によることなら,
248: % その旨, 理由とともに述べたほうがいいのではないでしょうか.
249: 例えば以下のような関数を実行することになる.
250:
251: \begin{verbatim}
252: #define PORT_CONTROL 1200
253: #define PORT_STREAM 1300
254:
255: int fdControl, fdStream;
256:
257: int mysocketOpen(const char* hostname, int portnum)
258: {
259: struct sockaddr_in serv;
260: struct hostent *host;
261: int s;
262:
263: bzero(&serv, sizeof(serv));
264: serv.sin_family = AF_INET;
265: serv.sin_port = htons(portnum);
266: host = gethostbyname(hostname);
267: bcopy(host->h_addr, (char *)&serv.sin_addr, host->h_length);
268:
269: s = socket(AF_INET, SOCK_STREAM, 0);
270: connect(s, (struct sockaddr *)&serv, sizeof(serv));
271: return s;
272: }
273:
274: void ox_start(char* servername)
275: {
276: fdControl = mysocketOpen(servername, PORT_CONTROL);
277: fdStream = mysocketOpen(servername, PORT_STREAM);
278: }
279:
280: int main()
281: {
282: ...
283: ox_start("localhost");
284: ...
285: }
286: \end{verbatim}
287:
288: 通信路が確保されたら, メッセージの交換が開始できるわけであるが,
289: ここで, Open xxx 規約における32bit整数の扱い(CMO\_INT32ではない)について
290: 注意しておこう.
291: 一般的に注意しなければならない点は, 負数の扱いとバイトオーダであると
292: 思われる.
293: 現在実装されているサーバは負数は 2 の補数表現されているものと
294: 見做して動作する.
295: ただしこれは旧版の\cite{Openxxx-1998} には明記されていない.
296: 次にサーバとの通信において, 用いるべきバイトオーダに関してであるが,
297: Open xxx 規約では通信時にはネットワークバイトオーダを用いることと
298: 定められている.
299: よって, C 言語でプログラムを作成する場合には, 適時, 変換する必要がある.
300: 例えば 32bit 整数を送信する場合には以下のような関数を用いればよい.
301: \begin{verbatim}
302: int send_int32(int fd, int integer32)
303: {
304: integer32 = htonl(integer32);
305: return write(fd, &integer32, sizeof(int));
306: }
307: \end{verbatim}
308:
309: \section{メッセージ}
310:
311: Open asir はサーバとクライアントの間でメッセージを交換するという形で
312: 計算を進行させる.
313: Open xxx 規約では, 数学プロセスはスタックマシンであると定義されている.
314: サーバはクライアントから受け取ったメッセージがデータであれば
315: スタックに積み, 命令であればスタックマシンとしてその命令を実行して
316: 結果をスタックに積む.
317: Open asir における全てのメッセージにはメッセージの種類を表す
318: 情報(32bit整数値で表されるタグ)と, シリアル番号が与えられる.
319: Open xxx 規約では, 以下の形式のメッセージが定義されている.
320: \begin{center}
321: \begin{tabular}{ll}
322: (OX\_COMMAND, {\sl serial number}, {\sl SMObject}) & \qquad 命令\\
323: (OX\_DATA, {\sl serial number}, {\sl CMObject}) & \qquad データ \\
324: (OX\_SYNC\_BALL, {\sl serial number}) & \qquad 同期用メッセージ
325: \end{tabular}
326: \end{center}
327: サーバ・クライアント間で交換されるメッセージは全て上のいずれかの形式をと
328: らなければならない.
329: これらのメッセージの種類を表すタグは次のように定義されている.
330: \begin{verbatim}
331: #define OX_COMMAND 513
332: #define OX_DATA 514
333: #define OX_SYNC_BALL 515
334: \end{verbatim}
335: メッセージのシリアル番号も 32bit 整数で与えられる.
336: これはクライアントまたはサーバが自由につけてよい.
337: シリアル番号はエラー処理に主に利用される.
338: サーバはエラーを発生したメッセージのシリアル番号をエラーメッセージに含めて
339: もどす.
340: 上のメッセージの定義で,
341: SMObject は, スタックマシンへの命令であり,
342: CMObject は, CMO に属するデータである.
343: スタックマシンへの命令は32bit整数値で与えられる.
344: \cite{Openxxx-1998} では例えば以下のような命令を定義している.
345: \begin{verbatim}
346: #define SM_popCMO 262
347: #define SM_popString 263
348: #define SM_mathcap 264
349: #define SM_pops 265
350: #define SM_setName 266
351: #define SM_evalName 267
352: #define SM_executeStringByLocalParser 268
353: #define SM_executeFunction 269
354:
355: #define SM_control_kill 1024
356: #define SM_control_reset_connection 1030
357: \end{verbatim}
358:
359: Open xxx のスタックマシンは二種類の異なる機能をもつと言える.
360: これはマシン語のたとえを使うと, いくつかの異なるマシン語の
361: エミュレーションモードをもつ CPU のようなものである.
362: モード (1) では, ローカル言語(Open asir の場合は asir)の文法に
363: したがった文字列を受け取り,
364: 計算した結果をローカル言語で記述された文字列でもどす.
365: この計算は命令
366: SM\_executeStringByLocalParser を用いて行われる.
367: モード (2) では, Open xxx で定められたスタックマシンとして動作する.
368: 基本的に, CMO をスタックに積み, 命令を受け取ると演算を行う.
369:
370: この節ではモード (1) を用いた計算の例をあげる.
371: ユーザが, Open asir に ``diff((x+2*y)\^{ }2,x);'' を評価させたいときは,
372: サーバにメッセージ
373: \begin{eqnarray*}
374: && \mbox{(OX\_DATA, {\sl serial number}, (CMO\_STRING, 18, "diff((x+2*y)\^{ }2,x);"))} \\
375: && \mbox{(OX\_COMMAND, {\sl serial number}, SM\_executeStringByLocalParser)}
376: \end{eqnarray*}
377: を順に送る.
378: 最初のメッセージで文字列``diff((x+2*y)\^{ }2,x);''がスタックに積まれ,
379: 次のメッセージでスタックの最上位の``diff((x+2*y)\^{ }2,x);''が
380: Open asir サーバによって実行される.
381: 結果は再びスタックに積まれる.
382:
383: これを実行するクライアントのプログラムは C 言語で表すと次のようになる.
384: \begin{verbatim}
385: /* (OX_tag, serial number) を送信する */
386: int send_ox_tag(int fd, int tag)
387: {
388: static int serial_number = 0;
389: send_int32(fd, tag);
390: return send_int32(fd, serial_number++);
391: }
392:
393: void send_ox_cmo_string(int fd, const char* str)
394: {
395: int len;
396: send_ox_tag(fd, OX_DATA); /* OXタグとシリアル番号を送信 */
397: send_int32(fd, CMO_STRING); /* CMO_STRING 形式の文字列を送る */
398: len = strlen(str);
399: send_int32(fd, len);
400: write(fd, str, len);
401: }
402:
403: void send_ox_command(int fd, int sm_command)
404: {
405: send_ox_tag(fd, OX_COMMAND); /* OXタグとシリアル番号を送信 */
406: send_int32(fd, sm_command);
407: }
408:
409: int executeStringByLocalParser(const char* str)
410: {
411: send_ox_cmo_string(fdStream, str);
412: send_ox_command(fdStream, SM_executeStringByLocalParser);
413: }
414:
415: int main()
416: {
417: ...
418: executeStringByLocalParser("diff((x+2*y)^2,x);");
419: ...
420: }
421: \end{verbatim}
422:
423: スタックに積まれた結果を文字列として取り出すときは,
424: SM\_popString 命令を用いる.
425: すなわち, サーバへメッセージ
426: \[
427: \mbox{(OX\_COMMAND, {\sl serial number}, SM\_popString)}
428: \]
429: を送る. その後, Open asir サーバから計算結果を表すメッセージ
430: \[
431: \mbox{(OX\_DATA, {\sl serial number}, (CMO\_STRING, 7, "2*x+4*y"))}
432: \]
433: が送られてくるので, それを読めばよい.
434:
435: \begin{verbatim}
436: typedef struct cmo_t {
437: int tag;
438: union {
439: int integer;
440: char *string;
441: } u;
442: } cmo_t;
443:
444: char *receive_cmo_string(int fd)
445: {
446: int len = receive_int32(fd);
447: char* str = malloc(len+1);
448: bzero(str, len+1);
449: read(fd, str, len);
450: return str;
451: }
452:
453: cmo_t receive_cmo(int fd)
454: {
455: cmo_t m;
456: m.tag = receive_int32(fd);
457: switch(m.tag) {
458: case CMO_STRING:
459: m.u.string = receive_cmo_string(fd);
460: break;
461: case CMO_INT32:
462: m.u.integer = receive_int32(fd);
463: break;
464: default:
465: }
466: return m;
467: }
468:
469: /* (OX_tag, serial number) を受信する */
470: int receive_ox_tag(int fd)
471: {
472: int tag = receive_int32(fd);
473: receive_serial_number(fd);
474: return tag;
475: }
476:
477: char* popString()
478: {
479: cmo_t m;
480:
481: send_ox_command(fdStream, SM_popString);
482: receive_ox_tag(fdStream); /* OXタグとシリアル番号を受信 */
483: m = receive_cmo(fdStream);
484:
485: return m.u.str;
486: }
487:
488: int main()
489: {
490: char *result;
491: ...
492: result = popString();
493: puts(result);
494: ...
495: }
496: \end{verbatim}
497:
498: \section{計算の中断}\label{section:reset}
499: 計算の中断は, Open xxx の設計でいちばん苦労した部分である.
500: このアイデアは asir が本来もっていた分散計算の機能に由来する.
501: まず基本として全てのメッセージ (OX\_ ではじまるデータまたは命令の
502: ひとかたまり)をいわゆる synchronized object として扱っている.
503: したがって,メッセージを転送しているときは転送が終了するまで
504: 割り込みは保留される.
505:
506: 計算の中断についてはサーバがコントロールプロセスと
507: 計算プロセスに別れて実装されていることが大きな意味をもつ.
508: 以下, このことに留意して説明を行う.
509:
510: まず, 計算の中断の依頼が行われる前には, クライアントおよびコントロールプ
511: ロセスは待機状態, 計算プロセスは計算中の状態にある.
512: 計算の中断の必要があると認められたとき, クライアントは,
513: 待機状態にあるコントロールプロセスにメッセージ
514: \[
515: \mbox{(OX\_COMMAND, {\sl serial number}, SM\_control\_reset\_connection)}
516: \]
517: を送信する.
518: このメッセージの送信後, クライアントはコントロールプロセスからの
519: 通信路のみを監視し待機状態に入る.
520: クライアントは計算プロセスからのメッセージは読まないようにする.
521:
522: このメッセージを受け取ったコントロールプロセスは活動を再開し,
523: クライアントに対しメッセージ
524: \[
525: \mbox{(OX\_DATA, {\sl serial number}, (CMO\_INT32, 0))}
526: \]
527: を投げ返し, さらに計算プロセスには中断処理を開始せよとのシグナルをおくる.
528: この時点では,
529: クライアントはコントロールプロセスとの通信路を監視している状態,
530: コントロールプロセスはシグナルを送った後, 待機状態に入り,
531: 計算プロセスは計算中にシグナルを受け取った状態である.
532: 計算プロセスはシグナルをうけとったときクリティカル区間にいれば
533: この区間がおわるまで計算の中断をしない.
534: とくに(Open xxx規約の意味での)メッセージの送受信中は,
535: クリティカル区間であると見做される.
536:
537: クライアントはコントロールプロセスとの通信路のみを最初監視しているが,
538: 上のコントロールプロセスからのメッセージを受信した後は
539: コントロールプロセスとの通信路を監視するのは止めて,
540: 計算プロセスからの{\tt OX\_SYNC\_BALL}を待つ状態に遷移する.
541: ある通信路において{\tt OX\_SYNC\_BALL}を待つ状態とは,
542: その通信路を通してメッセージ
543: \[
544: \mbox{(OX\_SYNC\_BALL, {\sl serial number})}
545: \]
546: を受け取るまで, その通信路からの全てのメッセージを読み飛ばす
547: 状態のことである.
548: 計算プロセスは中断処理が終了した後に{\tt OX\_SYNC\_BALL}をクライアントに
549: 送信してクライアントからの{\tt OX\_SYNC\_BALL}を待つ状態に入る.
550: 計算プロセスは{\tt OX\_SYNC\_BALL}以前のメッセージをすべて読みとばす.
551:
552: クライアントは計算プロセスから{\tt OX\_SYNC\_BALL}を受け取ると,
553: すぐさま, メッセージ
554: \[
555: \mbox{(OX\_SYNC\_BALL, {\sl serial number})}
556: \]
557: を計算プロセスに送信し, 通常の状態に復帰する.
558: サーバもこのメッセージを受信後, 通常の状態に復帰する.
559: これで, 手続きは全て終了する.
560:
561: 我々の中断手続きの設計において注意すべきことは, この手順でクライアントが
562: OX\_SYNC\_BALLを送った時点で, クライアント側からはサーバが待ち状態になっ
563: ていて, かつ次のストリーム(クライアント, 計算プロセス間の通信路)に対する
564: 読み出しは, これから送るコマンドのうちサーバが最初にストリームに書き出し
565: た結果であることが保証されていると思ってよい, ということである.
566: これには,
567: \begin{enumerate}
568: \item
569: サーバの中断処理は, クライアントからの依頼(シグナル)によって開始し,
570: クライアントからのOX\_SYNC\_BALL受領により終了する.
571: \item
572: サーバの中断処理が開始してから, クライアントからのOX\_SYNC\_BALLが
573: 送られてくる.
574: \end{enumerate}
575: という順序がなりたつことが本質的に重要である.
576: 例えば, サーバからのOX\_SYNC\_BALLを待たずにクライアントがOX\_SYNC\_BALL
577: を送ってしまった場合, シグナルに先着することもありえる.
578:
579: サーバでの中断処理の読み出し中に, さらに中断依頼が来た場合などのクライア
580: ントからのOX\_SYNC\_BALLが複数来る場合に対応するために, OX\_SYNC\_BALLは,
581: 通常状態では無視する必要があるので, 実際, 通常状態ではOX\_SYNC\_BALLは
582: サーバで無視されることには留意しなければならない.
583: サーバはクライアントにOX\_SYNC\_BALLを送るが, クライアントがもう
584: OX\_SYNC\_BALLを送った気でいると, 自分が送ったOX\_SYNC\_BALLの返事をずっ
585: と待ち続けることになる.
586:
587: なお, クライアントにおける中断処理のための関数は以下のようになる.
588: \begin{verbatim}
589: void ox_reset()
590: {
591: send_ox_command(fdControl, SM_control_reset_connection);
592:
593: receive_ox_tag(fdControl); /* OXタグとシリアル番号を受信 */
594: receive_cmo(fdControl); /* メッセージの本体を受信 */
595:
596: while(receive_ox_tag(fdStream) != OX_SYNC_BALL) {
597: receive_cmo(fdStream); /* メッセージを読み飛ばす. */
598: }
599: send_ox_tag(fdStream, OX_SYNC_BALL);
600: }
601:
602: int main()
603: {
604: ...
605: ox_reset();
606: ...
607: }
608: \end{verbatim}
609:
610:
611: \section{クライアントの終了}
612: クライアントを終了するときには, コントロールプロセスにメッセージ
613: \[
614: \mbox{(OX\_COMMAND, {\sl serial number}, SM\_control\_kill)}
615: \]
616: を送る.
617: このメッセージを受け取るとただちにサーバは終了するので,
618: それを待ってクライアントも終了する.
619: 現在実装されているサーバは
620: クライアントが突然終了するなどのために通信路が閉じられると,
621: サーバも自動的に終了するように設計されてはいるが,
622: 明示的にコントロールプロセスにメッセージを送るべきである.
623: \begin{verbatim}
624: void ox_close()
625: {
626: send_ox_command(fdControl, SM_control_kill);
627: }
628: \end{verbatim}
629:
630: \section{サーバにローカルに定義された関数の実行}
631: 先にあげた計算の例では, 計算の対象を文字列として送信し,
632: スタックマシンの命令\\ SM\_executeStringByLocalParser を利用していた.
633: 次にモード(2)を用いた計算の例をあげよう.
634: モード(2)では CMO\_STRING 型のオブジェクトだけでなく,
635: 一般の CMO が直接スタックにプッシュされ, 計算処理の対象となる.
636:
637: Open xxx 規約は以下のような意味でサーバの自由な拡張を許す.
638: Open xxx 規約に従う数学プロセスでは, その数学プロセス独自の関数が
639: 存在してもよい.
640: 例えば, asir における ``igcd'' などである.
641: これを\cite{Openxxx-1998}では「サーバのローカル関数」と呼んでいる.
642: Open asir では, asir マニュアルに説明されているすべての関数を
643: モード(2)のサーバのローカル関数として実行できる.
644: もちろん, asir などで用意されている「関数定義」を利用して新しく関数を
645: 追加してもよい.
646:
647: Open xxx 規約にはスタック上のCMOデータに対してサーバのローカル関数を
648: 実行するための命令 SM\_executeFunction が定義されている.
649: この節ではこの命令の使い方について説明しよう.
650:
651: まず, 実行したい関数の引数となるオブジェクトを「右から」順にサーバに
652: 送信すると, サーバは順にそれらのオブジェクトをスタックに積む.
653: 次いで, 引数の個数を CMO\_INT32 型のオブジェクトでサーバに送信すると,
654: サーバはスタックに積む.
655: 次に, 実行したいと思っている関数の名前を CMO\_STRING 型で送信すると,
656: サーバは再びスタックに積む. 最後に命令 SM\_executeFunction を送信すると,
657: サーバはスタックの最上位に積まれている「関数」を実行する. 関数は引数を
658: スタックからポップして実行し, サーバはその実行結果をスタックに積む.
659:
660: 例をあげよう. SM\_executeFunction を用いて, asir の文
661: \[
662: \mbox{print("Hello World.");}
663: \]
664: を実行するには次の手順をとる.
665:
666: まず, 次の順にメッセージを送信する.
667: \begin{eqnarray*}
668: && \mbox{(OX\_DATA, {\sl serial number}, (CMO\_STRING, 12, "Hello World."))} \\
669: && \mbox{(OX\_DATA, {\sl serial number}, (CMO\_INT32, 1))} \\
670: && \mbox{(OX\_DATA, {\sl serial number}, (CMO\_STRING, 5, "print"))}
671: \end{eqnarray*}
672: これらはサーバによって順にスタックに積まれる.
673: 次いで命令
674: \[
675: \mbox{(OX\_COMMAND, {\sl serial number}, SM\_executeFunction)}
676: \]
677: を送信すると関数 ``print'' が実行され,
678: サーバは ``Hello World.'' を画面に出力する.
679: 実行結果として (CMO\_NULL) がスタックに積まれる.
680:
681: \section{CMO ZZ}
682:
683: この節ではOpen xxx 規約における任意の大きさの整数(bignum)の扱いについて
684: 説明する.
685: 多重精度整数についての一般論については Knuth~\cite{Knuth-1986} に詳しい.
686: Open xxx 規約における多重精度整数を表すデータ型 CMO\_ZZ は GNU MPライブ
687: ラリなどを参考にして設計されていて, 符号付き絶対値表現を用いている.
688: CMO\_ZZ は次の形式をとると\cite{Openxxx-1998}で定義されている.\\
689: \begin{tabular}{|c|c|c|c|c|}
690: \hline
691: {\tt int32 CMO\_ZZ} & {\tt int32 $f$} & {\tt byte $b_1$} & $\cdots$ &
692: {\tt byte $b_n$} \\
693: \hline
694: \end{tabular} \\
695: $f$ は32bit整数であるが, 正数とは限らない.
696: $b_1, \ldots, b_n$ は 1バイト符号なし整数である.
697: このバイト列の長さ $n$ は絶対値 $|f|$ と一致しなければならない.
698: この CMO の符号は $f$ の符号で定める.
699: 前述したように, 32bit整数の負数は 2 の補数表現で表される.
700:
701: Open xxx 規約では上の CMO は以下の整数を意味する.
702: \[
703: \mbox{sgn}(f)\times (b_1 R^{n-1}+ b_2 R^{n-2} + \cdots + b_{n-1}R + b_n).
704: \]
705: ここで $R = 2^8$ である.
706: 例えば, 整数 $14$ は CMO\_ZZ で表わすと,
707: \[
708: \mbox{(CMO\_ZZ, 1, e)}
709: \]
710: となり, これをバイト列で表すと以下のようになる.
711: \[
712: \mbox{\tt 00 00 00 14 00 00 00 01 0e}
713: \]
714: あるいはゲタをはかせて CMO\_ZZ で
715: \[
716: \mbox{(CMO\_ZZ, 4, 0, 0, 0, e)},
717: \]
718: と表してもよい.
719: これはバイト列では
720: \[
721: \mbox{\tt 00 00 00 14 00 00 00 04 00 00 00 0e}
722: \]
723: となる.
724: 後者の表現の方が C 言語でクライアントを作成するのには, 簡単であろう.
725:
726: さて, 前節で説明した命令 SM\_executeFunction を利用して, 整数 $14$ と
727: $22$ の最大公約数を求めることを考えよう.
728: これには asir の関数 igcd が利用できる.
729:
730: まず, CMO\_ZZ で表した二つの整数, 引数の数(ここでは2)と関数名``igcd''を
731: 順にサーバに送信する.
732: \begin{eqnarray*}
733: && \mbox{(OX\_DATA, {\sl serial number}, (CMO\_ZZ, 4, 0, 0, 0, e))} \\
734: && \mbox{(OX\_DATA, {\sl serial number}, (CMO\_ZZ, 4, 0, 0, 0, 16))} \\
735: && \mbox{(OX\_DATA, {\sl serial number}, (CMO\_INT32, 1))} \\
736: && \mbox{(OX\_DATA, {\sl serial number}, (CMO\_STRING, 4, "igcd"))}
737: \end{eqnarray*}
738: 最後に命令 SM\_executeFunction をサーバに送信する.
739: \[
740: \mbox{(OX\_COMMAND, {\sl serial number}, SM\_executeFunction)}
741: \]
742: スタックの最上位には計算結果が積まれるが, 命令 SM\_popString をサーバに
743: 送ると, それが文字列に変換されてクライアントに返される.
744: なお CMO 形式でデータを受け取るには, 命令 SM\_popCMO をサーバに送る.
745:
746: 一連の操作を C 言語で実装すれば以下のようになるだろう.
747: \begin{verbatim}
748: typedef struct {
749: int size;
750: unsigned char *mp_d;
751: } cmo_zz_t;
752:
753: cmo_zz_t cmo_zz_set_si(int integer)
754: {
755: cmo_zz_t zz;
756: zz.size = (integer < 0)? -sizeof(int): sizeof(int);
757: integer = htonl(integer);
758: zz.mp_d = malloc(sizeof(int));
759: bcopy(&integer, zz.mp_d, sizeof(int));
760: return zz;
761: }
762:
763: void send_ox_cmo_zz(int fd, cmo_zz_t zz)
764: {
765: int len = (zz.size < 0)? -zz.size: zz.size;
766: send_ox_tag(fd, OX_DATA); /* OXタグとシリアル番号を送信 */
767: send_int32(fd, CMO_ZZ);
768: send_int32(fd, zz.size);
769: write(fd, zz.mp_d, len);
770: }
771:
772: int main()
773: {
774:
775: ...
776: send_ox_cmo_zz(fdStream, cmo_zz_set_si(14));
777: send_ox_cmo_zz(fdStream, cmo_zz_set_si(22));
778: send_ox_cmo_integer(fdStream, 2); /* number of arguments */
779: send_ox_cmo_string(fdStream, "igcd");
780:
781: send_ox_command(fdStream, SM_executeFunction);
782:
783: fprintf(stderr, "igcd(%d, %d) == %s.\n", 14, 22, ox_popString(fdStream));
784: ...
785:
786: }
787: \end{verbatim}
788:
789: \section{エラー処理}
790: この節ではエラー処理について説明する.
791: Open xxx 規約ではエラーを検出したとき,
792: サーバは CMO\_ERROR2型のオブジェクトをスタックに積むと定めている.
793: CMO\_ERROR2型のオブジェクトはエラーを表すために用意されたオブジェクトで
794: あり, どのようなエラーであるか, どのメッセージで発生したのかの情報を含む.
795: CMO\_ERROR2 という名称は歴史的な理由によるものである.
796: このオブジェクトは次のように定義されている.\\
797: \begin{tabular}{|c|c|}
798: \hline
799: {\tt int32 CMO\_ERROR2} & {\tt CMO\_LIST} error \\
800: \hline
801: \end{tabular}\\
802: error は CMO\_LIST 型のオブジェクトで, リストの各要素がエラーについての
803: 情報になっている. 特にリストの先頭の要素はInteger32 型の CMObject で,
804: その値はエラーが発生したメッセージのシリアル番号を Integer32 で表現した
805: ものでなければならない.
806: このリスト error の各要素についての詳細は \cite{Openxxx-1998} を参照して
807: ほしい.
808:
809: さてクライアントはエラーが起こったことを知らないわけであるが,
810: それは次のようにして検出できる.
811: まず, 命令 SM\_popCMO をサーバに送る.
812: すると, サーバはスタックの最上位をクライアントに送信する.
813: そこでクライアントはその CMO のデータ型を見て, エラーが起こったことを
814: 確認できる.
815:
816: \section{補足}
817: この解説を執筆中に, Mathematical Sciences Research Institute (Berkeley)
818: で, Parallel Symbolic Computation なるワークショップがあった.
819: 関係する興味深い発表が沢山あったので, 発表に関係ある URL
820: とキーワードをメモとして加えておく.
821: \def\til{$\tilde{\ }$}
822: \begin{enumerate}
823: \item {\tt www.openmath.org} (open math)
824: \item {\tt www.w3.org} (math web)
825: \item {\tt posso.lip6.fr/\til jcf} (Faugere $F_4$, parallel GB algorithm)
826: \item {\tt www.cs.berkeley.edu/\til yelick} (multipol)
827: \item {\tt www.mupad.de} (parallel muPAD)
828: \item {\tt www.math.ncsu.edu/\til kaltofen} (open math virtual machine)
829: \item {\tt norma.nkkhef.nl/\til t68/summer} (integral)
830: \item {\tt www.inf.ethz.ch/personal/mannhart} ($\Pi^{it}$)
831: \item {\tt www.nag.co.uk} (useful links to computer algebra projects including Frisco project)
832: \item {\tt www.can.nl} (useful links to computer algebra projects)
833: \item {\tt www.cecm.sfu.ca} (useful links to computer algebra projects)
834: \item {\tt www.icot.or.jp} (KLIC, Fujise-Murao's project)
835: \item Parallel mathematica.
836: \end{enumerate}
837:
838:
839: \begin{thebibliography}{99}
840: \bibitem{Openxxx-1998}
841: 野呂正行, 高山信毅.
842: {Open xxx の設計と実装, xxx = asir,kan}, 1998/06/16
843: \bibitem{Knuth-1986}
844: D. E. Knuth.
845: 準数値算法/算術演算,
846: サイエンス社, 1986.
847: \end{thebibliography}
848:
849: \end{document}
850:
851:
852: % 小原君:
853: % 可能なら
854: % socket 関係の余計なエラー処理をぬいてできるだけ短く簡略化した残りの
855: % ソースリスト
856: % (たとえば mysocket などの定義がない)
857: % をいれるといいと思う.
858: % それから タグの define 文もいれておくと便利と思う.
859: % 長くて不可能なら, mysocket などにかんする説明を加えるべき.
860:
861: % カタカナ英語, そのたスタイルが変な部分はどんどん書き直して下さい.
862: % 表現, 説明が変とおもったらどんどんかきなおして下さい.
863:
864: % あと, 関係する project としては,
865: % CMO expression $\Leftrightarrow$ バイト列
866: % の変換コンパイラ,
867: % C や Java の open xxx 用ライブラリ. MathLink (Mathematica).
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>