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

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: 
1.1.1.7 ! root      165:                        try {
        !           166:                                driver.reset(new COMDriverStdio(this));
        !           167:                        } catch (...) { }
1.1       root      168:                        if ((bool)driver && driver->InitDriver() == false) {
                    169:                                driver.reset();
                    170:                        }
                    171: 
                    172:                } else if (type == "tcp") {
1.1.1.7 ! root      173:                        try {
        !           174:                                driver.reset(new COMDriverTCP(this));
        !           175:                        } catch (...) { }
1.1       root      176:                        if ((bool)driver && driver->InitDriver() == false) {
                    177:                                driver.reset();
                    178:                        }
                    179: 
1.1.1.5   root      180:                } else if (type == "cons") {
                    181:                        // console デバイスのいない機種では指定出来ない。
                    182:                        if (gMainApp.FindObject(OBJ_CONSOLE) == NULL) {
                    183:                                item.Err("cannot be specified on vmtype=%s",
                    184:                                        gMainApp.GetVMTypeStr().c_str());
                    185:                                return false;
                    186:                        }
                    187: 
1.1.1.7 ! root      188:                        try {
        !           189:                                driver.reset(new COMDriverCons(this));
        !           190:                        } catch (...) { }
1.1.1.5   root      191:                        if ((bool)driver && driver->InitDriver() == false) {
                    192:                                driver.reset();
                    193:                        }
                    194: 
1.1       root      195:                } else {
                    196:                        // 知らないドライバ種別
                    197:                        item.Err();
                    198:                        return false;
                    199:                }
                    200: 
                    201:                if ((bool)driver == false) {
                    202:                        bool fallback = false;
                    203: 
                    204:                        // 指定のドライバが使えなかった場合、
                    205:                        // hostcom*-driver なら fallback するかどうかは設定による。
                    206:                        // debugger-driver なら常に fallback せず終了する。
                    207:                        //
                    208:                        // 元々 hostnet が tap, bpf のように順に試してという流れだったので
                    209:                        // fallback の選択肢が用意されていたが、hostcom は今の所どれか1つ
                    210:                        // (stdio か tcp) か、そうでなければ none しかないので、fallback
                    211:                        // するかどうかを選ばせる意味があまりような気もするけど、
                    212:                        // とりあえず形式だけ真似してみる…。
                    213:                        // 一方、debugger-driver なら常に fallback せず、設定自体も用意
                    214:                        // しない。デバッガを使いたいと言ってる時点でデバッガがなくても
                    215:                        // とりあえず起動してほしいとはならないだろうと思うので。
                    216:                        if (key != "debugger") {
                    217:                                fallback = gConfig->Find(key + "-fallback").AsInt();
                    218:                                putmsg(1, "%s-fallback=%d", key.c_str(), fallback ? 1 : 0);
                    219:                        }
                    220: 
                    221:                        if (fallback == false) {
                    222:                                // フォールバックしないならエラー終了
                    223:                                std::string errmsg;
                    224:                                errmsg = string_format("No %s driver found", key.c_str());
                    225:                                putmsg(1, "%s", errmsg.c_str());
                    226:                                warnx("%s (See details with option -C -L%s=1)",
                    227:                                        errmsg.c_str(), key.c_str());
                    228:                                return false;
                    229:                        }
                    230:                }
                    231:        }
                    232: 
                    233:        if ((bool)driver == false) {
1.1.1.7 ! root      234:                try {
        !           235:                        driver.reset(new COMDriverNone(this));
        !           236:                } catch (...) { }
1.1       root      237:                if ((bool)driver && driver->InitDriver() == false) {
                    238:                        // 失敗したら出来ることはあまりなさげ
                    239:                        assert(false);
                    240:                }
                    241:        }
                    242:        assert((bool)driver);
                    243: 
                    244:        // ドライバ名は Capitalize だがログはほぼ小文字なので雰囲気を揃える…
                    245:        putmsg(1, "selected host driver: %s",
                    246:                string_tolower(driver->GetDriverName()).c_str());
                    247: 
                    248:        return true;
                    249: }
                    250: 
                    251: void
                    252: HostCOMDevice::Dispatch(int udata)
                    253: {
                    254:        // driver の Dispatch は処理し終わったら DONE を返す
                    255:        udata = driver->Dispatch(udata);
                    256: 
                    257:        // ...のだが、Dispatch(LISTEN_SOCKET) は着信を受け付けた時には
                    258:        // LISTEN_SOCKET を返し、それを受けてここで通知処理を行う。
                    259:        if (udata == LISTEN_SOCKET) {
1.1.1.3   root      260:                if (accept_func) {
                    261:                        (parent->*accept_func)();
1.1       root      262:                }
                    263:                udata = DONE;
                    264:        }
                    265: 
                    266:        inherited::Dispatch(udata);
                    267: }
                    268: 
                    269: // VM からの送信 (VM スレッドで呼ばれる)
                    270: bool
                    271: HostCOMDevice::Tx(uint32 data)
                    272: {
                    273:        if (loglevel >= 2) {
                    274:                char buf[8];
                    275: 
                    276:                buf[0] = '\0';
                    277:                if (0x20 <= data && data < 0x7f) {
                    278:                        snprintf(buf, sizeof(buf), " '%c'", data);
                    279:                }
                    280:                putlog(2, "Send $%02x%s", data, buf);
                    281:        }
                    282: 
                    283:        // 送信キューに入れて..
                    284:        if (txq.Enqueue(data) == false) {
                    285:                putlog(2, "txq exhausted");
                    286:                stat.txqfull_bytes++;
                    287:                return false;
                    288:        }
                    289:        stat.tx_bytes++;
                    290: 
                    291:        // ざっくりピーク値
1.1.1.4   root      292:        stat.txq_peak = std::max((uint)txq.Length(), stat.txq_peak);
1.1       root      293: 
                    294:        // パイプに通知 (値はダミー)
                    295:        return WritePipe(0);
                    296: }
                    297: 
                    298: // キューから取り出す (VM スレッドで呼ばれる)
                    299: uint32
                    300: HostCOMDevice::Rx()
                    301: {
                    302:        uint8 data;
                    303: 
                    304:        if (rxq.Dequeue(&data) == false) {
                    305:                // キューが空
                    306:                return -1;
                    307:        }
                    308:        stat.rx_bytes++;
                    309: 
                    310:        if (loglevel >= 2) {
                    311:                char buf[8];
                    312: 
                    313:                buf[0] = '\0';
                    314:                if (0x20 <= data && data < 0x7f) {
                    315:                        snprintf(buf, sizeof(buf), " '%c'", data);
                    316:                }
                    317:                putlog(2, "Recv $%02x%s", data, buf);
                    318:        }
                    319: 
                    320:        return data;
                    321: }
                    322: 
                    323: // ドライバから読み込む。
                    324: // 戻り値はキューに投入したデータ数。
                    325: int
                    326: HostCOMDevice::Read()
                    327: {
                    328:        assert((bool)driver);
                    329: 
                    330:        int data = driver->Read();
                    331:        if (data < 0) {
                    332:                return 0;
                    333:        }
                    334:        stat.read_bytes++;
                    335: 
                    336:        if (rxq.Enqueue(data) == false) {
                    337:                stat.rxqfull_bytes++;
                    338:                return 0;
                    339:        }
                    340: 
                    341:        // ざっくりピーク値
1.1.1.4   root      342:        stat.rxq_peak = std::max((uint)rxq.Length(), stat.rxq_peak);
1.1       root      343: 
                    344:        return 1;
                    345: }
                    346: 
                    347: // 外部への書き出し (ホストスレッドで呼ばれる)
                    348: void
                    349: HostCOMDevice::Write(uint32 dummy)
                    350: {
                    351:        uint8 data;
                    352: 
                    353:        assert(driver);
                    354: 
                    355:        // 送信キューを全部吐き出す
                    356:        while (txq.Dequeue(&data)) {
                    357:                driver->Write(data);
                    358:                stat.write_bytes++;
                    359:        }
                    360: }
                    361: 
                    362: // モニタ
                    363: void
                    364: HostCOMDevice::MonitorUpdate(Monitor *, TextScreen& screen)
                    365: {
                    366:        screen.Clear();
                    367: 
1.1.1.3   root      368:        screen.Print(0, 0, "Parent Device : %s", parent->GetName().c_str());
                    369:        screen.Print(0, 1, "HostCOM Driver: %s", driver->GetDriverName());
1.1       root      370:        // 次の1行はドライバ依存情報
1.1.1.3   root      371:        driver->MonitorUpdateMD(screen, 2);
1.1       root      372: 
1.1.1.3   root      373:        int y = 4;
1.1       root      374:        screen.Print(0, y++, "%-17s%13s", "<Tx>", "Bytes");
                    375:        screen.Print(0, y++, "%-17s%13s", "VM sends",
                    376:                format_number(stat.tx_bytes).c_str());
                    377:        screen.Print(0, y++, "%-17s%13s", "Write to host",
                    378:                format_number(stat.write_bytes).c_str());
                    379:        screen.Print(0, y++, "%-17s%13s", "Drop:TxQ Full",
                    380:                format_number(stat.txqfull_bytes).c_str());
                    381:        y++;
                    382: 
                    383:        screen.Print(0, y++, "%-17s%13s", "<Rx>", "Bytes");
                    384:        screen.Print(0, y++, "%-17s%13s", "Read from host",
                    385:                format_number(stat.read_bytes).c_str());
                    386:        screen.Print(0, y++, "%-17s%13s", "VM receives",
                    387:                format_number(stat.rx_bytes).c_str());
                    388:        screen.Print(0, y++, "%-17s%13s", "Drop:RxQ Full",
                    389:                format_number(stat.rxqfull_bytes).c_str());
                    390:        y++;
                    391: 
                    392:        screen.Print(5, y++, "Capacity Peak");
1.1.1.4   root      393:        screen.Print(0, y++, "TxQ %4u/%4u %4u",
                    394:                (uint)txq.Length(), (uint)txq.Capacity(), stat.txq_peak);
                    395:        screen.Print(0, y++, "RxQ %4u/%4u %4u",
                    396:                (uint)rxq.Length(), (uint)rxq.Capacity(), stat.rxq_peak);
1.1       root      397: }

unix.superglobalmegacorp.com

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