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

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

unix.superglobalmegacorp.com

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