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

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

unix.superglobalmegacorp.com

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