この文書は「なかのひと」、特にプログラミングをする人のための文書、 あるいはクラス間インターフェイスの設計メモです。 カーネルプログラミングをする人にはカーネルリソースの扱い方なんかの説明になると思います。 たぶん。
この章ではタスクの生成から終了までを説明します。 主に参照されるソースは「include/task.h」です。
タスクを生成するにはTASKクラスをnewします。 変数としてインスタンスを生成(変数タスク)することもできますが、 これはシステムサービスのための方法ですのであまりお薦めしません。 引数は生成するタスクの種類によって違いますが、カーネルタスクの場合、 エントリポイント、優先度、パラメタの3つ。 ユーザタスクの場合これにさらにプロセスを加えた4つが引数です。
エントリポイントは「void (*)(void*)」の関数ポインタです。 所属クラスはありませんのでメンバ関数を指定する場合はstaticにする必要があります。 もしstaticでないメンバ関数をエントリポイントにする必要があるのなら 「パラメタ」にインスタンスのポインタを渡してstaticなメンバ関数から呼んでもらうなどの 方法を採る必要があります。
優先度はドライバ、カーネル、ユーザ、バックグラウンドの4段階となります。 優先度間は単純なプリエンプティブ関係となります。 また、ドライバ、カーネル優先度同士は単純なFCFSでスケジューリングされ、 ユーザ、バックグラウンド優先度はFCFSに加えてタイムスライス毎にラウンドロビンされます。 なお、ラウンドロビンではチケットなどの配分メカニズムは採用していません。 単純な実時間タイムスライスです。
何かを待たせる時は待たせる対象をGetします。 待ち時間を指定すると時間切れの時は戻ってきます。 また、単なる時間待ちの時はTASK::Sleepします。
なお、実行可能状態から待ち状態に移行できるのはカレントタスクだけです。 他のタスクを待ち状態にする方法はありませんし、 他のタスクを特定する操作自体が制限されています。 もしそれが必要だと思ったら代わりにMUTEXかLOCKで解決する必要があります。
何かを待っているタスクを直接起床させる方法はありません。 そんなものはバグの元にしかなりません。 わざわざバグの種を蒔くことはありませんので「待ち」と同様にMUTEXやLOCKを使ってください。
タスクを終了するには生成時にエントリポイントとして指定した関数を抜けます。 また、変数タスクの場合はTASKインスタンスが消滅した時点で自動的に終了します。 !なお、絶対にカレントタスクをdeleteしてはいけません!
talosはデバイスドライバが簡単に書けるよう特に注意して設計されています。 この章ではデバイスドライバの書き方について説明します。 主に参照されるソースは「include/driver.h」です。 他にいくつかデバイスドライバを参照するとよいでしょう。
デバイスドライバを書くにはDRIVERの子クラスとDEVICEの子クラスを用意し、 DRIVERの子クラスのインスタンスを生成します。 このインスタンスは外から参照される必要がないのでstaticにしてしまってOKです。 ドライバはコンパイラやリンカによってではなくグローバルコンストラクタによって 実行時に登録されます。
DRIVERは、検出されたデバイスが当該ドライバのものであるかどうか確認し、 最適であるとシステムに判断された場合にDEVICEをnewするのが役目です。 なのでDRIVERはMatchとInitのメソッドを持ちます。 Matchは検出されたデバイスの情報を受け取り、 そのデバイスがどの程度マッチしているかを返します。
要は「デバイスの素性を調べて一致度を返す」Matchメソッドを書けばよいです。
で、次に全てのDRIVERのMatchが返した値が比較され、 最適であると判断されたDRIVERのInitが呼ばれます。 引数はMatchで渡されるものと同じです。 Initでは単にDEVICEの子クラスをnewしてその結果を返します。
DEVICEがドライバ本体です。 インターフェイスはread、write、io(POSIXでいうIOCTL)です。 排他制御のためにopenやcloseも必要でしょうが準備中です。