MochiOS@仮想ファイルシステムの作成part10
前提知識無しで作るなんちゃって仮想ファイルシステムpart10。
開発日記です。独り言です。
これまでのあらすじ
part
内容
0
仮想ファイルシステムを作りたい宣言をする。
1
ざっくり仮想ファイルシステムの機能を決める。 が、機能呼出し先の仮想ファイルシステムのタスクIDをどう取得するかという問題に気付く。
2
カーネルにタスク名登録機能を実装した。 これでタスク名からタスクIDを取得する事が出来る様になるハズ、なので試したいが試す方法が無い事に気付き、ログ出力タスクの開発を宣言する。
3
ログ出力の為に使うvsnprintf()の仕様を調べる。
4
ログ出力タスクを開発してタスク名からタスクIDの取得機能が正しく動いている事が確認できた。
5
mount機能を実装した。たぶんできてる。
6
FDどうやって管理しようかー。メッセージのやり取り制御を状態遷移で制御しようかー。とか考えて、open機能を実装した。たぶんできてる。
7
openと同じようなシーケンスなので、メッセージとちょっとやる事変えて簡単にwrite機能を実装できちゃった。
8
writeと同じようなシーケンスなので、メッセージとちょっとやる事変えて簡単にread機能を実装できちゃった。
9
readと同じようなシーケンスなので、メッセージとちょっとやる事変えて簡単にclose機能を実装できちゃった。
応用
これまでmount、open~closeまでさくっと何も考えずに実装してきた。(そういえばunmount実装してないな。まいいか)
全てはドライバとアプリ間のインタフェースを作ることがひとまずの目的だったので、ドライバを作ってみなければ。
というわけでns16550ドライバを作った。
ns16550は所謂、RS-232C、COMポート、シリアルポート、UARTなどと呼ばれているハードウェアで、割りと制御が簡単。
それぞれ16byteの転送バッファと受信バッファがあって、書き込む(VfsWrite)時は転送バッファがフルでなければ1byteづつ書き込んでフルの時は転送バッファ空割り込みが来るまで待つ。読み込む時は受信割り込みが来たときに1byteづつ読み込んでいたデータを返すだけ。
mvfs メインスレッド 受信スレッド 転送スレッド NS16550 VfsReadReq VfsReadResp VfsWriteReq 転送バッファ書込 転送要求 VfsWriteResp 転送バッファ空割込み 割込み要求 転送バッファ読込 書込 転送バッファ読込 書込 受信割込み 読込 受信バッファ書込み 読込 受信バッファ書込み VfsReadReq 受信バッファ読込 VfsReadResp mvfs メインスレッド 受信スレッド 転送スレッド NS16550
MochiKernelのメッセージパッシングはキューがなく、即座にメッセージ受信をしないと仮想ファイルサーバがブロックされてシステムの性能が悪くなってしまうので、メインと受信と転送用に1プロセス3スレッド構成に。
(MochiKernelにスレッド機能なんて無かったので、作った。)
とまぁ、これだけでかなりのネタになるんだけれど、割愛。
⇂がコミットログ。
https://github.com/MasterMochi/drv-ns16550/commit/a09994d07188ec84b663b902f6dbc07509cc44de
本題はこれから。
ttyサーバを作りたいが…
tty「サーバ」って書くと???になるのだけれど、要はttyドライバです。MochiOSではサーバープロセスとしてttyファイルを提供するので「サーバ」にしているだけです。
そんで考えたのだけれど、次のシーケンスで悩みが出てくる。
ユーザアプリがttyサーバに行読込み(cockedモード)
ttyサーバがドライバからデータ読込み
受信データ無しのため、読込サイズ0で応答。
NS16550ドライバ ttyサーバ ユーザアプリ 1. VfsRead...Read 2. VfsRead...Read 3. 受信データ無し の為、サイズ0応答 どうやって 待ち合わせる…? NS16550ドライバ ttyサーバ ユーザアプリ
(シーケンス図では、仮想ファイルサーバは省略。それぞれのインタフェースは仮想ファイルサーバ上で行われる。そのためVfsRead…Readのような形式で記載。上位からはReadを起動し、それを受け取って仮想ファイルサーバから下位へVfsReadが起動される。)
ttyサーバは行データが揃うまでユーザアプリへRead要求を返さない。行データが揃うまで、ドライバから文字を読み続けなければいけないわけだけど、ドライバは受信データが無い(EOF)ので直ぐに読込サイズ0でReadを返す。
(ところが上のコミットではドライバがブロックする設計ミス。。。修正する。)
今、実装済みの機能でこれを実現するには、ttyサーバはドライバへのReadを繰り返すしかない。
NS16550ドライバ ttyサーバ ユーザアプリ VfsRead...Read VfsRead...Read VfsRead...Read VfsRead...Read VfsRead...Read VfsRead...Read VfsRead...Read NS16550ドライバ ttyサーバ ユーザアプリ
これは、もう、CPU100%一直線。
Select/VfsReady機能を追加する
説明しなくても大体わかると思うけど、selectです。指定したファイルディスクリプタの読み込みまたは書き込みが出来るまで待ち合わせます。
VfsReadyはファイルの読み込みまたは書き込み準備が出来た事を意味する通知。
NS16550 NS16550ドライバ 仮想ファイルサーバ ttyサーバ Select レディチェック。 読込・書込とも レディでないので 待ち合わせ 受信割り込み 読み込み VfsReady レディ設定 Read VfsRead データ & レディ状態 読込レディ設定 データ Write VfsWrite レディ状態 書込レディ設定 NS16550 NS16550ドライバ 仮想ファイルサーバ ttyサーバ
いちいちSelectで指定した全てのFDに対応するMountプロセスにレディ状態を問い合わせると、メッセージのやり取りが増えて待ち合わせ状態の管理や時間がかかるので、レディ状態は仮想ファイルシステムでも保持する仕様にした。その為、VfsRead応答に最新のレディ状態を含める様に修正する。
以下、メッセージ仕様。
■ Select要求メッセージ
offset
size
内容
値
意味
0x00
4
機能ID
0x0000_0009
Select
0x04
4
タイプ(要求/応答)
0x0000_0000
要求
0x08
4
読込監視グローバルFD数
0~1024
-
0x0C
4
書込監視グローバルFD数
0~1024
-
0x10
4
読込監視グローバルFD[0]
任意
-
…
…
読込監視グローバルFD[…]
…
…
可変
4
書込監視グローバルFD[0]
任意
-
…
…
書込監視グローバルFD[…]
…
…
■ Select応答メッセージ
offset
size
内容
値
意味
0x00
4
機能ID
0x0000_0009
Select
0x04
4
タイプ(要求/応答)
0x0000_0001
応答
0x08
4
処理結果
0x0000_0000 0x0000_0001
成功 失敗
0x0C
4
読込レディグローバルFD数
0~1024
-
0x10
4
書込レディグローバルFD数
0~1024
-
0x14
4
読込レディグローバルFD[0]
任意
-
…
…
読込レディグローバルFD[…]
…
…
可変
4
書込レディグローバルFD[0]
任意
-
…
…
書込レディグローバルFD[…]
…
…
■ VfsReady通知メッセージ
offset
size
内容
値
意味
0x00
4
機能ID
0x0000_0008
vfsClose
0x04
4
タイプ(要求/応答)
0x0000_0002
通知
0x08
4
グローバルFD
任意
-
0x0C
4
Ready対象
0bit目: read 1bit目: write
読込みレディ 書込みレディ
■ vfsRead応答メッセージ(改造)
offset
size
内容
値
意味
0x00
4
機能ID
0x0000_0006
vfsRead
0x04
4
タイプ(要求/応答)
0x0000_0001
応答
0x08
4
グローバルFD
任意
-
0x0C
4
処理結果
0x0000_0000 0x0000_0001
成功 失敗
0x10
4
読込レディ状態
0x0000_0000 0x0000_0001
非レディ レディ
0x14
4
読込み実施サイズ
0~24,064
-
0x18
0~24,064
データ
任意
-
■ vfsWrite応答メッセージ(改造)
offset
size
内容
値
意味
0x00
4
機能ID
0x0000_0004
vfsWrite
0x04
4
タイプ(要求/応答)
0x0000_0001
応答
0x08
4
グローバルFD
任意
-
0x0C
4
処理結果
0x0000_0000 0x0000_0001
成功 失敗
0x10
4
書込レディ状態
0x0000_0000 0x0000_0002
非レディ レディ
0x10
4
書込み実施サイズ
0~24,064
-
実装してみた
ttyプロセスが、select->read->writeを無限に繰り返す様にお試し。COM1で「1234567890Select!」を入力してみた。上のウィンドウは画面でデバッグログを、下のウィンドウはCOM1。端っこ切れてる。。
深く説明はしないけど、まぁCPU100%にならずに読込み待ちできたって感じです。
ここで問題発生
これまで、突貫で適当に作りすぎてて、機能毎に複数の要求を扱えない。
なので、ttyファイルをReadするとその先のドライバファイルのReadが行えない状況に。。。
driver 仮想ファイルサーバ ttyサーバ user 「/com1」をMount 「/ttyS0」をMount 「/ttyS0」に対してRead VfsRead 「/com1」に対してRead userからのReadを 実行中なので無理 VfsRead driver 仮想ファイルサーバ ttyサーバ user
直さねば。全体的に大改造なので、次回の更新はいつになるかな。