Annotation of nono/host/hostcom.cpp, revision 1.1.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.