--- nono/host/netdriver.h 2026/04/29 17:04:51 1.1.1.7 +++ nono/host/netdriver.h 2026/04/29 17:04:54 1.1.1.8 @@ -6,31 +6,35 @@ #pragma once -#include "object.h" +#include "device.h" #include "ethernet.h" +#include "monitor.h" #include #include -class NetDriver : public Object +class NetDriver : public Device { - public: + using inherited = Device; + protected: // コンストラクタ - NetDriver(const char *name, EthernetDevice *parent, - std::mutex *mtx, std::condition_variable *cv); + NetDriver(const char *name, EthernetDevice *parent, int loglevel_); + public: // デストラクタ。 - ~NetDriver() override; + virtual ~NetDriver() override; - // 初期化 & オープン。 - // EthernetDevice::Init() から呼ばれる。諸制約については device.h 参照。 - // まずどれが呼ばれたかを putmsg(1) でログ表示し、 - // 必要なオープン処理や、必要なら受信スレッドの作成を行う。 + // デバイス初期化 & オープン。 + // NetDriverSelector::InitDriver() から呼ばれる。 + // この中ではログ出力が可能。まずどれが呼ばれたかを putmsg(1) で表示し + // 必要なオープン処理を行う。 // 成功すれば true、失敗すれば warn()/warnx() でメッセージを出力して // false を返すこと。 - // また、クローズ相当の動作はなくデストラクタで行う。 - virtual bool Init() = 0; + // また、これに対応するクローズ相当の動作はなくデストラクタで行う。 + virtual bool InitDriver() = 0; - void MonitorUpdate(TextScreen&) override; + // こっちは Device クラス由来の Init()。VM::Init() から呼ばれる。 + // ここで受信スレッドを起動する。 + bool Init() override; // パケットを送信する。正常に送信できれば true を返す。 // EthernetDevice::SendPacket() が呼ばれると常に呼び出される。 @@ -44,20 +48,41 @@ class NetDriver : public Object // 受信スレッド。 // VM に引き渡せたパケットについて rx_pkts, rx_bytes を更新すること。 - virtual void ThreadRun() = 0; + void ThreadRun(); // オープンされていれば true を返す。 bool IsOpen() const { return fd != -1; } + // ドライバ名を返す。 + const char *GetDriverName() const { return drivername; } + + // InitDriver() 中の(主に最後の)エラーメッセージ。 + // NetDriver は複数を順番に試す場合もあるし、全部エラーになっても終了する + // かどうかは設定によるので、各ドライバはエラーが発生しても各自で warnx に + // よる表示はせず、ここにエラーメッセージをセットする。必要になった時点で + // NetDriverSelector が最後の一つを warnx() で表示する。 + // なお、おそらくそれだけでは大抵何も分からないのでこれとは別に + // ログレベル 1 で putmsg() は充実させておくこと。 + std::string errmsg {}; + protected: - // 受信スレッドを起動する (必要なら継承クラス側が呼ぶ) - bool InitRecvThread(); + // 受信パケットキューにパケットを一つ追加する + void RecvEnqueue(uint8 *buf, size_t len); + + // パケットを受信する。read(2) と同じように値を返す。 + virtual ssize_t RecvPacket() = 0; + + // モニタのうちドライバ依存部分の情報を書き出す。 + // screen のうち (0から数えて) 1行目と2行目のみがドライバ依存部分なので + // ここだけ書き出すこと。不要なら書き出さなくてよい。Clear() しないこと。 + virtual void MonitorUpdateMD(TextScreen& screen) = 0; + + DECLARE_MONITOR_CALLBACK(MonitorUpdate); const char *drivername {}; // ドライバ名 EthernetDevice *parent {}; // 親 - std::string devpath {}; // デバイスファイルパス - std::string ifname {}; // 作成したインタフェース名 + std::string ifname {}; // (あれば)作成したインタフェース名 // デバイスディスクリプタ。 // ディスクリプタを持つというのは共通なのでディスクリプタはここに置くが @@ -65,10 +90,6 @@ class NetDriver : public Object // 初期化と IsOpen() だけ受け持つ。ちょっと責任分解点が気持ち悪いけど。 int fd {}; - // 親(Ethernet)デバイスの mutex と condvar - std::mutex *mtx {}; - std::condition_variable *cv {}; - // 統計情報 uint64 tx_pkts = 0; uint64 rx_pkts = 0; @@ -81,6 +102,8 @@ class NetDriver : public Object private: bool RunScript(const char *filename); + + Monitor monitor { this }; }; extern std::unique_ptr gNetDriver;