Annotation of nono/host/hostcom.cpp, revision 1.1

1.1     ! root        1: //
        !             2: // nono
        !             3: // Copyright (C) 2021 nono project
        !             4: // Licensed under nono-license.txt
        !             5: //
        !             6: 
        !             7: //
        !             8: // シリアルポートのホストデバイス
        !             9: //
        !            10: 
        !            11: // 送信のフロー
        !            12: //
        !            13: // VM thread                :     Host thread
        !            14: //
        !            15: // 各シリアルデバイス::Tx() :
        !            16: //     |
        !            17: // SerialDevice::Tx()       :
        !            18: //     |
        !            19: // HostCOMDevice::Tx()      :   HostDevice::ThreadRun
        !            20: //     |
        !            21: //     +-------------->| queue |----+
        !            22: //     +-------------->| pipe  |----+
        !            23: //     |                            |
        !            24: //   <-+                    :       v
        !            25: //                                 --- kevent
        !            26: //                          :       |
        !            27: //                              HostCOMDevice::Write()
        !            28: //                          :       |
        !            29: //                              COMDriver*::Write()
        !            30: //                          :       |
        !            31: //                                  +-----> Send to the real world
        !            32: 
        !            33: // 受信のフロー
        !            34: //
        !            35: // VM thread                :     Host thread
        !            36: //
        !            37: //                          :   HostDevice::ThreadRun
        !            38: //
        !            39: //                          :       +-----< Recv from the real world
        !            40: //                                  |
        !            41: //                          :       v
        !            42: //                                 --- kevent
        !            43: //                          :       |
        !            44: //                              HostCOMDevice::Read()
        !            45: //                                  |
        !            46: //     +---------------| queue |<---+
        !            47: //     +---------------| event |<---+
        !            48: //     v
        !            49: // SerialDevice::Callback()
        !            50: //     |
        !            51: // 各シリアルデバイス::Rx()
        !            52: 
        !            53: // ログ名
        !            54: //        MPSCC        HostDevice       COMDriver
        !            55: //         |            |                |
        !            56: //         v            v                v
        !            57: //        SIODevice -> HostCOMDevice -> COMDriver***
        !            58: // 表示名 (sio)        (HostCOMx)      (HostCOMx.***)
        !            59: // 識別名 "sio"        "hostcomx"      "hostcomx"
        !            60: //
        !            61: // HostCOM は 1VM あたり 1個とは限らないので、親デバイスがそれぞれ対応する
        !            62: // HostCOM に名前を付ける。
        !            63: 
        !            64: 
        !            65: #include "hostcom.h"
        !            66: #include "comdriver_none.h"
        !            67: #include "comdriver_stdio.h"
        !            68: #include "comdriver_tcp.h"
        !            69: #include "config.h"
        !            70: #include "mainapp.h"
        !            71: 
        !            72: // コンストラクタ
        !            73: //
        !            74: // objname_ は "HostCOM" とか (スレッド名も同じになる)。
        !            75: // 設定ファイルキーワードプレフィックスはこれを小文字にしたもの("hostcom")。
        !            76: HostCOMDevice::HostCOMDevice(const std::string& objname_)
        !            77:        : inherited(objname_)
        !            78: {
        !            79:        // 親が hostcom* か debugger かによっていろいろ動作が違う。
        !            80:        if (GetName() == "Debugger") {
        !            81:                // デバッガコンソールならログレベルは親に準じるため、こっちは不要。
        !            82:                ClearAlias();
        !            83: 
        !            84:                // 送受信バイト数がメインのモニタはこっちにはなくていいだろう。
        !            85:        } else {
        !            86:                // hostcom* なら親(mpscc などのシリアルデバイス)とこっち(HostCOM*)
        !            87:                // のログレベルは独立。
        !            88: 
        !            89:                // モニタは hostcom* のみ必要。
        !            90:                monitor.func = ToMonitorCallback(&HostCOMDevice::MonitorUpdate);
        !            91:                monitor.SetSize(30, 16);
        !            92:                monitor.Regist(ID_MONITOR_HOSTCOM);
        !            93:        }
        !            94: }
        !            95: 
        !            96: // デストラクタ
        !            97: HostCOMDevice::~HostCOMDevice()
        !            98: {
        !            99: }
        !           100: 
        !           101: // ログレベル設定
        !           102: void
        !           103: HostCOMDevice::SetLogLevel(int loglevel_)
        !           104: {
        !           105:        inherited::SetLogLevel(loglevel_);
        !           106: 
        !           107:        if ((bool)driver) {
        !           108:                driver->SetLogLevel(loglevel_);
        !           109:        }
        !           110: }
        !           111: 
        !           112: // 初期化
        !           113: bool
        !           114: HostCOMDevice::Init()
        !           115: {
        !           116:        if (inherited::Init() == false) {
        !           117:                return false;
        !           118:        }
        !           119: 
        !           120:        if (SelectDriver() == false) {
        !           121:                return false;
        !           122:        }
        !           123: 
        !           124:        return true;
        !           125: }
        !           126: 
        !           127: // ドライバ(再)選択
        !           128: bool
        !           129: HostCOMDevice::SelectDriver()
        !           130: {
        !           131:        // 設定のキー名は親デバイスによって異なる
        !           132:        std::string key = GetConfigKey();
        !           133:        const ConfigItem& item = gConfig->Find(key + "-driver");
        !           134:        const std::string& type = item.AsString();
        !           135: 
        !           136:        driver.reset();
        !           137: 
        !           138:        if (type != "none") {
        !           139:                if (type == "stdio") {
        !           140:                        // debugger-driver=stdio (または -D オプション) と
        !           141:                        // hostcom*-driver=stdio とは共存できない。
        !           142:                        // 歴史的経緯でとりあえず debugger-driver=stdio 側を優先とする。
        !           143:                        // XXX これも後指定優先にするかどうか
        !           144:                        // XXX hostcom が増えたらたぶんこうじゃなくなる
        !           145:                        if (key != "debugger") {
        !           146:                                const ConfigItem& dditem = gConfig->Find("debugger-driver");
        !           147:                                const std::string& ddtype = dditem.AsString();
        !           148:                                if (ddtype == "stdio") {
        !           149:                                        const char *opt;
        !           150:                                        if (gMainApp.opt_D) {
        !           151:                                                opt = "-D";
        !           152:                                        } else {
        !           153:                                                opt = "'-V debugger-driver=stdio'";
        !           154:                                        }
        !           155:                                        item.Err("cannot be used with %s option", opt);
        !           156:                                        return false;
        !           157:                                }
        !           158:                        }
        !           159: 
        !           160:                        driver.reset(new COMDriverStdio(this));
        !           161:                        if ((bool)driver && driver->InitDriver() == false) {
        !           162:                                driver.reset();
        !           163:                        }
        !           164: 
        !           165:                } else if (type == "tcp") {
        !           166:                        driver.reset(new COMDriverTCP(this));
        !           167:                        if ((bool)driver && driver->InitDriver() == false) {
        !           168:                                driver.reset();
        !           169:                        }
        !           170: 
        !           171:                } else {
        !           172:                        // 知らないドライバ種別
        !           173:                        item.Err();
        !           174:                        return false;
        !           175:                }
        !           176: 
        !           177:                if ((bool)driver == false) {
        !           178:                        bool fallback = false;
        !           179: 
        !           180:                        // 指定のドライバが使えなかった場合、
        !           181:                        // hostcom*-driver なら fallback するかどうかは設定による。
        !           182:                        // debugger-driver なら常に fallback せず終了する。
        !           183:                        //
        !           184:                        // 元々 hostnet が tap, bpf のように順に試してという流れだったので
        !           185:                        // fallback の選択肢が用意されていたが、hostcom は今の所どれか1つ
        !           186:                        // (stdio か tcp) か、そうでなければ none しかないので、fallback
        !           187:                        // するかどうかを選ばせる意味があまりような気もするけど、
        !           188:                        // とりあえず形式だけ真似してみる…。
        !           189:                        // 一方、debugger-driver なら常に fallback せず、設定自体も用意
        !           190:                        // しない。デバッガを使いたいと言ってる時点でデバッガがなくても
        !           191:                        // とりあえず起動してほしいとはならないだろうと思うので。
        !           192:                        if (key != "debugger") {
        !           193:                                fallback = gConfig->Find(key + "-fallback").AsInt();
        !           194:                                putmsg(1, "%s-fallback=%d", key.c_str(), fallback ? 1 : 0);
        !           195:                        }
        !           196: 
        !           197:                        if (fallback == false) {
        !           198:                                // フォールバックしないならエラー終了
        !           199:                                std::string errmsg;
        !           200:                                errmsg = string_format("No %s driver found", key.c_str());
        !           201:                                putmsg(1, "%s", errmsg.c_str());
        !           202:                                warnx("%s (See details with option -C -L%s=1)",
        !           203:                                        errmsg.c_str(), key.c_str());
        !           204:                                return false;
        !           205:                        }
        !           206:                }
        !           207:        }
        !           208: 
        !           209:        if ((bool)driver == false) {
        !           210:                driver.reset(new COMDriverNone(this));
        !           211:                if ((bool)driver && driver->InitDriver() == false) {
        !           212:                        // 失敗したら出来ることはあまりなさげ
        !           213:                        assert(false);
        !           214:                }
        !           215:        }
        !           216:        assert((bool)driver);
        !           217: 
        !           218:        // ドライバ名は Capitalize だがログはほぼ小文字なので雰囲気を揃える…
        !           219:        putmsg(1, "selected host driver: %s",
        !           220:                string_tolower(driver->GetDriverName()).c_str());
        !           221: 
        !           222:        return true;
        !           223: }
        !           224: 
        !           225: void
        !           226: HostCOMDevice::Dispatch(int udata)
        !           227: {
        !           228:        // driver の Dispatch は処理し終わったら DONE を返す
        !           229:        udata = driver->Dispatch(udata);
        !           230: 
        !           231:        // ...のだが、Dispatch(LISTEN_SOCKET) は着信を受け付けた時には
        !           232:        // LISTEN_SOCKET を返し、それを受けてここで通知処理を行う。
        !           233:        if (udata == LISTEN_SOCKET) {
        !           234:                if (dev && accept_func) {
        !           235:                        (dev->*accept_func)();
        !           236:                }
        !           237:                udata = DONE;
        !           238:        }
        !           239: 
        !           240:        inherited::Dispatch(udata);
        !           241: }
        !           242: 
        !           243: // VM からの送信 (VM スレッドで呼ばれる)
        !           244: bool
        !           245: HostCOMDevice::Tx(uint32 data)
        !           246: {
        !           247:        if (loglevel >= 2) {
        !           248:                char buf[8];
        !           249: 
        !           250:                buf[0] = '\0';
        !           251:                if (0x20 <= data && data < 0x7f) {
        !           252:                        snprintf(buf, sizeof(buf), " '%c'", data);
        !           253:                }
        !           254:                putlog(2, "Send $%02x%s", data, buf);
        !           255:        }
        !           256: 
        !           257:        // 送信キューに入れて..
        !           258:        if (txq.Enqueue(data) == false) {
        !           259:                putlog(2, "txq exhausted");
        !           260:                stat.txqfull_bytes++;
        !           261:                return false;
        !           262:        }
        !           263:        stat.tx_bytes++;
        !           264: 
        !           265:        // ざっくりピーク値
        !           266:        stat.txq_peak = std::max((int)txq.Length(), stat.txq_peak);
        !           267: 
        !           268:        // パイプに通知 (値はダミー)
        !           269:        return WritePipe(0);
        !           270: }
        !           271: 
        !           272: // キューから取り出す (VM スレッドで呼ばれる)
        !           273: uint32
        !           274: HostCOMDevice::Rx()
        !           275: {
        !           276:        uint8 data;
        !           277: 
        !           278:        if (rxq.Dequeue(&data) == false) {
        !           279:                // キューが空
        !           280:                return -1;
        !           281:        }
        !           282:        stat.rx_bytes++;
        !           283: 
        !           284:        if (loglevel >= 2) {
        !           285:                char buf[8];
        !           286: 
        !           287:                buf[0] = '\0';
        !           288:                if (0x20 <= data && data < 0x7f) {
        !           289:                        snprintf(buf, sizeof(buf), " '%c'", data);
        !           290:                }
        !           291:                putlog(2, "Recv $%02x%s", data, buf);
        !           292:        }
        !           293: 
        !           294:        return data;
        !           295: }
        !           296: 
        !           297: // ドライバから読み込む。
        !           298: // 戻り値はキューに投入したデータ数。
        !           299: int
        !           300: HostCOMDevice::Read()
        !           301: {
        !           302:        assert((bool)driver);
        !           303: 
        !           304:        int data = driver->Read();
        !           305:        if (data < 0) {
        !           306:                return 0;
        !           307:        }
        !           308:        stat.read_bytes++;
        !           309: 
        !           310:        if (rxq.Enqueue(data) == false) {
        !           311:                stat.rxqfull_bytes++;
        !           312:                return 0;
        !           313:        }
        !           314: 
        !           315:        // ざっくりピーク値
        !           316:        stat.rxq_peak = std::max((int)rxq.Length(), stat.rxq_peak);
        !           317: 
        !           318:        return 1;
        !           319: }
        !           320: 
        !           321: // 外部への書き出し (ホストスレッドで呼ばれる)
        !           322: void
        !           323: HostCOMDevice::Write(uint32 dummy)
        !           324: {
        !           325:        uint8 data;
        !           326: 
        !           327:        assert(driver);
        !           328: 
        !           329:        // 送信キューを全部吐き出す
        !           330:        while (txq.Dequeue(&data)) {
        !           331:                driver->Write(data);
        !           332:                stat.write_bytes++;
        !           333:        }
        !           334: }
        !           335: 
        !           336: // モニタ
        !           337: void
        !           338: HostCOMDevice::MonitorUpdate(Monitor *, TextScreen& screen)
        !           339: {
        !           340:        screen.Clear();
        !           341: 
        !           342:        screen.Print(0, 0, "HostCOM Driver: %s", driver->GetDriverName());
        !           343:        // 次の1行はドライバ依存情報
        !           344:        driver->MonitorUpdateMD(screen);
        !           345: 
        !           346:        int y = 3;
        !           347:        screen.Print(0, y++, "%-17s%13s", "<Tx>", "Bytes");
        !           348:        screen.Print(0, y++, "%-17s%13s", "VM sends",
        !           349:                format_number(stat.tx_bytes).c_str());
        !           350:        screen.Print(0, y++, "%-17s%13s", "Write to host",
        !           351:                format_number(stat.write_bytes).c_str());
        !           352:        screen.Print(0, y++, "%-17s%13s", "Drop:TxQ Full",
        !           353:                format_number(stat.txqfull_bytes).c_str());
        !           354:        y++;
        !           355: 
        !           356:        screen.Print(0, y++, "%-17s%13s", "<Rx>", "Bytes");
        !           357:        screen.Print(0, y++, "%-17s%13s", "Read from host",
        !           358:                format_number(stat.read_bytes).c_str());
        !           359:        screen.Print(0, y++, "%-17s%13s", "VM receives",
        !           360:                format_number(stat.rx_bytes).c_str());
        !           361:        screen.Print(0, y++, "%-17s%13s", "Drop:RxQ Full",
        !           362:                format_number(stat.rxqfull_bytes).c_str());
        !           363:        y++;
        !           364: 
        !           365:        screen.Print(5, y++, "Capacity Peak");
        !           366:        screen.Print(0, y++, "TxQ %4d/%4d %4d",
        !           367:                (int)txq.Length(), (int)txq.Capacity(), stat.txq_peak);
        !           368:        screen.Print(0, y++, "RxQ %4d/%4d %4d",
        !           369:                (int)rxq.Length(), (int)rxq.Capacity(), stat.rxq_peak);
        !           370: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.