fhandler tutorial
fhandler のチュートリアル
本文書は /dev/zero を例に取って、新しい「fhandler」を Cygwin に追加する方法を示すものです。
注意すべきファイル:
fhandler.h- 新しい派生クラスと FH_* が定義される必要があるファイルpath.cc- 「/dev/zero」を通知しマークするファイルfhandler_zero.cc- 新しいファイルdtable.cc- fhandler のインスタンスを作成するためのファイル
まず、新しい fhandler がどのように振舞うのかを決定する必要があります。
この例では、以下のような特徴を持つ UNIX の「/dev/zero」デバイスを実装することとします。
/dev/zeroに対する書き込みは黙って処分される。/dev/zeroからの読み込みに対しては全て 0 バイトを返す。/dev/zeroに対する mmap() は 0 の塊としてマップされるようにする。
Windows はこのように振舞うデバイスを持っていませんので、全てをシミュレートする必要があります。従って、
- 書き込みは単純に成功を返す。
- 読み込みはバッファを
memset()し、成功を返す。 -
CreateFileMapping()は -1 のハンドルを受け取ることが出来、それによって (1) スワップメモリをマップし、(2) それに 0 を設定する(少なくとも NT では)という事実を利用する。
それでは、fhandler.h から始めましょう。
最初に、ファイルがどこにあるのかについてのコメントを更新します。
FH_DEV_ZERO として fhandler_dev_zero を追加します(訳注: Cygwin 1.1.7
のコードを見る限り、FH_DEV_ZERO ではなく FH_ZERO のようです)。
このデバイスは「高速な」デバイス(決してブロックされないデバイス)
として追加されるので、FH_NDEV もまた修正する必要があります。
正しく行えたなら、fhandler_dev_null をコピーし fhandler_dev_zero
となるように編集します。小さいのでこれを選んだわけですが、作業を進めるためには更なるメンバを加えることになるでしょう(全てをシミュレートしようとしているのですから)。実のところ、後から完全なリストを纏めることは出来るとはいえ、とにかく全ての入出力メソッドが必要なのですから、fhandler_windows からそれらをコピーしましょう。
続いて、ユーザが「/dev/zero」をオープンしようとしたときにそれを認識出来るよう、
path.cc を編集する必要があります。get_device_number
の中を参照して下さい。長い場合分けがありますが、単に追加するだけです(「null」
の次に追加してみました)。windows_device_names
のリストの正しい場所にエントリを追加することも忘れないで下さい。
これらの変更に追従するために dtable.cc も変更する必要があります。
FH_NULL を探して、更に FH_ZERO の場合分けも追加して下さい。
今や、fhandler_zero.cc それ自身にまで到達しました。空のファイルを作成し、
他の fhandler_*.cc ファイルから「通常の」ヘッダ / コピーライト /
インクルード文をコピーします。新しいファイルをビルドするように
Makefile.in を修正することもまた必要です。DLL_OFILES に新しいエントリを追加し、
新しい winsup.h 依存行を追加します(訳注: 現在の Makefile.in
には必要ないようです)。
fhandler.h を修正したので、「make」をタイプすれば全てがリビルドされます。
これ以上ヘッダを変更しないので、それを実行する機会には前進してそれを行って下さい。まだ新しい fhandler クラスに全てのメソッドを追加していないので、新しい DLL はリンク出来ませんが、しかし少なくとも多くの寄せ集めを邪魔にならないところへと取り出します。
続いて、fhandler メソッドそれ自身を追加し始めましょう。
コンストラクタ: 名前を受け取ります。行うことは FH_ZERO という値と共に、
その名前をベースクラスに戻すことだけです。全ての fhandler は set_cb
を呼び出しますので、ここでも set_cb を呼びます(これによってファイルディスクリプタのコピーが行われます)。
open: /dev/zero のような実際の Windows デバイスは存在しませんので、
名前を取るようにオーバーライドしていますが、この名前は無視しています。
フラグを保存するために set_flags を呼び出します。
write: 書き込みは無視され、成功が返されます。
read: 読み込みは NUL バイトを読み込みます。従ってバッファは NUL
で埋められ、成功が返されます。
lseek/close: 成功を返すだけです。
dump: デバッギング用であり、何かをただプリントするだけです。
select_*: これはまだサポートされていません。例として、select.cc 中の
myriad の例を参照して下さい。ベースとなる fhandler のメソッドは、今の
ところこうなっています。