ロード トップ 参照元 逆検索 検索 ヘルプ

[logo] 組み込みTiki/の構造


組み込みTiki

ここでは、Ruby から下の部分について整理。

  -----------------------     <<<<< VOS API(その1)
     ライブラリ(Minix + BSD)
          stdio
          math
          ansi
          net
          ohters
  ------------------------    <<<<< VOS API(その2)
     Virtual OS 
          FileSystem (V7)
          Host OS wrapper

  ------------------------    <<<<< Host OS API
       Host OS

ここでは、API について整理したい。

__vos_ プレフィックスが付く VOS API には 2 つの種類がある。

それ以外に API は、

この4種類がある。整理されてなかったり、変だったりするが、これが現状(005c)

---

以下特に 気をくばった(or くばるべき(未完))ポイント

API と データ構造


@ ディレクトリ -- その API と データ構造

API は、struct dirent を使った API

これは、新規につくらなければならない。

MINIX の dirent.h では、

struct dirent {         /* Largest entry (8 slots) */
        ino_t           d_ino;          /* I-node number */
        unsigned char   d_extent;       /* Extended with this many slots */
        char            d_name[61];     /* Null terminated name */
};

という定義になっている。これは本来 ディレクトリ の物理構造 とは 関係なく、opnedir などのライブラリが提供する 構造体である。

もともと ファイルシステムがサポートする ファイル名の長さを 長くしたかった という事情があったので、V7FS のディレクトリ自体を 上記の構造にする。

ファイルシステム内の構造は、struct direct 。これが一致する。

      dirent == direct

である。

opendir 等の API は、other/dir.c で作成。

readdir は、

という構造になっている。

なお、DIR という 型があるが みていない、FILE だとして扱っている。

問題点(TODO)


@ ファイルディスクリプタ -- API と データ構造

ファイルディスクリプタは、VOS のファイルシステムが提供する。

ファイルシステム内の ファイルディスクリプタはそれで良いわけだが、 stdin/out , socket 等のリソースを どう扱うか 決めなければならない。

   
   hfd : HOST OS のファイルディスクリプタ
   vfd : Virtual OS のファイルディスクリプタ

と表現する

これだけでは説明しにくいので、
     hfd == 15
     vfd == 7
であったとして 表記する。


   vfd(7) は、/dev/fd/15 を open したときの ファイルディスクリプタ

と定義する。

たとえば、

   hfd = socket();

で HOS の ファイルディスクリプタ 15 が得られたとする。

この場合

    vfd = open(/dev/fd/15) 

として、vfd を返す。

vfd に対する read/write は、ファイルシステムを通して、/dev/fd/15 に対する
read/write になるわけだ。

で、ファイルシステムには、/dev/fd のドライバを仕込んでおいて、
minor(dev) に対する ファイルに対し read/write する。

それ以外 たとえば send/recv といった ものは、ファイルシステムを通さない。

これは、socket で生成するときに、
       __vos_fdconv_tab[]

というテーブルを作っておいて、

       hfd = __vos_fdconv_tab[vfd]

で hfd に変換し、HOST OS に対して send/recv する。


dup/dup2 はかなり面倒。


ファイルシステムに閉じている場合は良いのだが、... そうでないとき

   -- HOST OS の dup を呼び出し、新たにファイルディスクリプタを得る。
   -- 上の socket の 例のように して vfd を作成。

という手順になる。


普通は、

   vfd1 ---\ 
              inode
   vfd2 ---/

おなじ inode を使うが、socket や stdin/stdout の 場合

                                          HOST OS

   vfd1 ---  /dev/fd  ---   hfd1 ------- | ---- \
                                         |         inode
   vfd2 ---  /dev/fd ----   hfd2 ------  | ---- /


HOST OS にまで いくわけだ。

なぜ こんな構造をしているかというと、select サポートのため。

いまの select の id 変換で 
vfd と hfd は、1:1 にしたいという 事情がある


dup の概念は、UNIX 独自だから、HOS 側に それを期待するのは、
ちょっとまずい。

しかし、本来このようなことをせずとも良いので、select 側を 対応して
HOS の dup を使わないように したい。(TODO)

ちょっと話がずれるかもしれないですが、ruby/io.c は、dup, dup2つかってます。 特に$stdin, $stdout への代入のフックではdupを使っているのでdupまたはその代替は必須かな。
cygwinはどうやってるんだろう?
CGI (cgi.rb)まわりで、ファイルディスクリプタの番号0, 1でなくて、$stdin, $stdout を使ってるなら ごまかす余地はあるかもしれないけれど。

HOST の dup を使わないしくみは以下のとおり

         
    dup では、ローカルに dup するだけでなく、

    __vos_fdconv_tab[vfd]

    にも登録してしまう。__vos_fdconv_tab[vfd] が いくつ重複しているか
    わかるように __vos_hfd_refcnt[] も 作成 。

    で、__vos_fdconv_tab[vfd] に登録されているものは、

    __vos_sockclose を呼びだすが、実際に close するのは、
    リファレンスカウントが 0 になったとき。

    select で hfd がどの vfd なのか判断する必要がある。
    どの vfd に対して bit を立てたはわかるので、その vfd を選ぶ。
    ようにした。

    dup2 は、入れ忘れた

    __v7_dup2() が 成功した後

#ifndef USE_HOST_DUP
        if (__vos_issock(fdes))
                __vos_sockdup2(fdes,ret);
#endif

    とすれば OK 。
    


@ エラー番号 マッピングの仕組み


@ シグナルと API

シグナルは、VOS では まじめにサポートする必要はないはずだ。

なぜなら、1つの プロセスしかなく、外のプロセスのことを関知しない というのが VOS のポリシーだから。

signal に関する API は提供する、しかし どこからも シグナルはやって来ない という考えで作る。

コードは、minlib/other/sigfake.c

ところが、例外があった、タイマーである。タイマーは時間がたてば やってくる。

タイマーを登録する API は、UNIX では、alarm か setitimer しかない。 いちおう、タイマーなしでも Ruby のスレッドは動くようなので、 OFF にしてあるが、setitimer は サポートできる。

ただし、VIRTUAL TIMER を指定でき あがるシグナルは、ALRM と VTALRM を ただしく選択できるものの 時間の管理は、REAL である。 理由は、HOST に 負担をかけたくないため。

HOST 側で、

     __hos_timer_block
     __hos_timer_unblock
     __hos_timer_set
の関数を用意すれば、タイマーはサポートできるが、

UNIX API で これを作るのに

         setitimer
         sigaction
         sigaddset
         sigdelset
         sigemptyset
         sigismember
         sigprocmask
が結局必要になった。別の OS ではまた違った実装になるかも知れない ということで、できるだけ プリミティブなものを使うという ことにしている。


@ struct sockaddr 変換

実は NetBSD で動かすとき はまった。

Linux とか古いものは、

     unsigned short sa_family;
     char sa_data[14];

BSD 系は、

     unsigned char sa_len;
     unsigned char sa_family;
     char sa_data[14];

という感じになっている。


@ bopy の移植上の注意。

ndbm の移植ではまったのだが、BSD の bcopy と memcpy はおなじではない。 オーバラップするときちゃんとコピーされるかどうかが違う。

で、Linux の memcpy は定義どおり オーバラップするケースを考慮しない。 しかし、NetBSD とかは、memcpy は、オーバラップするケースを考慮してくれる。 NetBSD とかで動くからといって、Linux でも動くとは限らない。



(最終更新 Thu Mar 30 19:06:52 2006)