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

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.1.8 ! root       76: #include "uimessage.h"
1.1       root       77: 
                     78: // コンストラクタ
                     79: //
1.1.1.8 ! root       80: // n は 0 以上なら本体 COM のいずれか。-1 ならデバッガ。
        !            81: HostCOMDevice::HostCOMDevice(Device *parent_, int n,
        !            82:                const std::string& portname_)
        !            83:        : inherited(parent_, (n >= 0 ? OBJ_HOSTCOM(n) : OBJ_HOSTCOM_DBG), portname_)
1.1       root       84: {
1.1.1.8 ! root       85:        // SetName() で設定したオブジェクト名はスレッド名でも使う。
        !            86:        // また設定ファイルキーワードプレフィックスはこれを小文字にしたもの。
1.1.1.2   root       87: 
1.1       root       88:        // 親が hostcom* か debugger かによっていろいろ動作が違う。
1.1.1.8 ! root       89:        if (n < 0) {
        !            90:                SetName("Debugger");
        !            91: 
1.1       root       92:                // デバッガコンソールならログレベルは親に準じるため、こっちは不要。
                     93:                ClearAlias();
                     94: 
                     95:                // 送受信バイト数がメインのモニタはこっちにはなくていいだろう。
                     96:        } else {
1.1.1.8 ! root       97:                SetName(string_format("HostCOM%u", n));
        !            98: 
1.1       root       99:                // hostcom* なら親(mpscc などのシリアルデバイス)とこっち(HostCOM*)
                    100:                // のログレベルは独立。
                    101: 
                    102:                // モニタは hostcom* のみ必要。
1.1.1.8 ! root      103:                monitor = gMonitorManager->Regist(ID_MONITOR_HOSTCOM(n), this);
1.1.1.5   root      104:                monitor->func = ToMonitorCallback(&HostCOMDevice::MonitorUpdate);
1.1.1.8 ! root      105:                monitor->SetSize(33, 17);
1.1       root      106:        }
                    107: }
                    108: 
                    109: // デストラクタ
                    110: HostCOMDevice::~HostCOMDevice()
                    111: {
                    112: }
                    113: 
                    114: // ログレベル設定
                    115: void
                    116: HostCOMDevice::SetLogLevel(int loglevel_)
                    117: {
                    118:        inherited::SetLogLevel(loglevel_);
                    119: 
1.1.1.8 ! root      120:        std::lock_guard<std::mutex> guard(driverlock);
1.1       root      121:        if ((bool)driver) {
                    122:                driver->SetLogLevel(loglevel_);
                    123:        }
                    124: }
                    125: 
1.1.1.6   root      126: // 動的コンストラクションその2
1.1       root      127: bool
1.1.1.6   root      128: HostCOMDevice::Create2()
1.1       root      129: {
1.1.1.6   root      130:        if (inherited::Create2() == false) {
1.1       root      131:                return false;
                    132:        }
                    133: 
1.1.1.8 ! root      134:        // hostcom*-fallback は使わなくなったので、
        !           135:        // 初期値から変更されていれば警告だけ出す。
        !           136:        std::string key = GetConfigKey();
        !           137:        if (key != "debugger") {
        !           138:                const std::string fallback_key = key + "-fallback";
        !           139:                const ConfigItem& fallback_item = gConfig->Find(fallback_key);
        !           140:                if (fallback_item.GetFrom() != ConfigItem::FromInitial) {
        !           141:                        warnx("Warning: option '%s' has been obsoleted.",
        !           142:                                fallback_key.c_str());
        !           143:                }
        !           144:        }
        !           145: 
        !           146:        if (SelectDriver(true) == false) {
1.1       root      147:                return false;
                    148:        }
                    149: 
                    150:        return true;
                    151: }
                    152: 
1.1.1.8 ! root      153: // ドライバ(再)選択。
        !           154: // エラーが起きた場合、
        !           155: // 起動時なら、warn() 等で表示して false を返す(終了する)。
        !           156: // 実行中なら、warn() 等で表示してもいいが、必ず None にフォールバックして
        !           157: // true を返すこと。
1.1       root      158: bool
1.1.1.8 ! root      159: HostCOMDevice::SelectDriver(bool startup)
1.1       root      160: {
1.1.1.8 ! root      161:        std::lock_guard<std::mutex> guard(driverlock);
        !           162: 
        !           163:        driver.reset();
        !           164:        errmsg.clear();
        !           165: 
1.1       root      166:        // 設定のキー名は親デバイスによって異なる
                    167:        std::string key = GetConfigKey();
                    168:        const ConfigItem& item = gConfig->Find(key + "-driver");
                    169:        const std::string& type = item.AsString();
                    170: 
1.1.1.8 ! root      171:        enum {
        !           172:                ERR_CONFIG,             // 設定でのエラー
        !           173:                ERR_INVALID,    // 知らないドライバ
        !           174:        } reason = ERR_CONFIG;
        !           175: 
        !           176:        if (type == "none") {
        !           177:                CreateNone();
        !           178:        } else if (type == "stdio") {
        !           179:                CreateStdio(item, key);
        !           180:        } else if (type == "tcp") {
        !           181:                CreateTCP();
        !           182:        } else if (type == "console" || type == "cons") {
        !           183:                if (key == "debugger") {
        !           184:                        reason = ERR_INVALID;
        !           185:                } else {
        !           186:                        CreateConsole(item);
        !           187:                }
        !           188:        } else {
        !           189:                // 知らないドライバ種別
        !           190:                reason = ERR_INVALID;
        !           191:        }
1.1       root      192: 
1.1.1.8 ! root      193:        if ((bool)driver == false) {
        !           194:                // 指定のドライバが使えなかった場合、hostcom* でも debugger でも
        !           195:                // o 起動時ならエラー終了する。
        !           196:                // o 実行中なら none にフォールバックする。
        !           197:                if (startup) {
        !           198:                        switch (reason) {
        !           199:                         case ERR_INVALID:
        !           200:                                item.Err("Invalid driver name");
        !           201:                                break;
        !           202:                         case ERR_CONFIG:
        !           203:                                item.Err("Could not configure the driver");
        !           204:                                warnx("(See details with option -C -L%s=1)", key.c_str());
        !           205:                                break;
        !           206:                         default:
        !           207:                                assert(false);
1.1       root      208:                        }
1.1.1.8 ! root      209:                        return false;
        !           210:                } else {
        !           211:                        // UI に通知してフォールバック。
        !           212:                        int n = (key == "debugger") ? -1 : GetId() - OBJ_HOSTCOM0;
        !           213:                        UIMessage::Post(UIMessage::HOSTCOM_FAILED, n);
1.1       root      214: 
1.1.1.8 ! root      215:                        CreateNone();
        !           216:                }
        !           217:        }
        !           218:        assert((bool)driver);
1.1       root      219: 
1.1.1.8 ! root      220:        // ドライバ名は Capitalize だがログはほぼ小文字なので雰囲気を揃える…
        !           221:        putmsg(1, "selected host driver: %s",
        !           222:                string_tolower(driver->GetDriverName()).c_str());
1.1.1.5   root      223: 
1.1.1.8 ! root      224:        return true;
        !           225: }
1.1.1.5   root      226: 
1.1.1.8 ! root      227: // None ドライバを生成する。
        !           228: // 戻り値はなく、成否は (bool)driver で判断する。
        !           229: void
        !           230: HostCOMDevice::CreateNone()
        !           231: {
        !           232:        try {
        !           233:                driver.reset(new COMDriverNone(this));
        !           234:        } catch (...) { }
        !           235:        if ((bool)driver) {
        !           236:                if (driver->InitDriver()) {
        !           237:                        // 成功。
        !           238:                        return;
1.1       root      239:                }
1.1.1.8 ! root      240:                errmsg = driver->errmsg;
        !           241:                driver.reset();
        !           242:        }
        !           243: }
1.1       root      244: 
1.1.1.8 ! root      245: // stdio ドライバを生成する。
        !           246: // 戻り値はなく、成否は (bool)driver で判断する。
        !           247: void
        !           248: HostCOMDevice::CreateStdio(const ConfigItem& item, const std::string& key)
        !           249: {
        !           250:        // セマフォの処理は InitDriver() 内で行ってある。
1.1       root      251: 
1.1.1.8 ! root      252:        try {
        !           253:                driver.reset(new COMDriverStdio(this));
        !           254:        } catch (...) { }
        !           255:        if ((bool)driver) {
        !           256:                if (driver->InitDriver()) {
        !           257:                        // 成功。
        !           258:                        return;
1.1       root      259:                }
1.1.1.8 ! root      260:                errmsg = driver->errmsg;
        !           261:                driver.reset();
1.1       root      262:        }
1.1.1.8 ! root      263: }
1.1       root      264: 
1.1.1.8 ! root      265: // TCP ドライバを生成する。
        !           266: // 戻り値はなく、成否は (bool)driver で判断する。
        !           267: void
        !           268: HostCOMDevice::CreateTCP()
        !           269: {
        !           270:        try {
        !           271:                driver.reset(new COMDriverTCP(this));
        !           272:        } catch (...) { }
        !           273:        if ((bool)driver) {
        !           274:                if (driver->InitDriver()) {
        !           275:                        // 成功。
        !           276:                        return;
1.1       root      277:                }
1.1.1.8 ! root      278:                errmsg = driver->errmsg;
        !           279:                driver.reset();
1.1       root      280:        }
1.1.1.8 ! root      281: }
1.1       root      282: 
1.1.1.8 ! root      283: // Console ドライバを生成する。
        !           284: // 戻り値はなく、成否は (bool)driver で判断する。
        !           285: void
        !           286: HostCOMDevice::CreateConsole(const ConfigItem& item)
        !           287: {
        !           288:        // console デバイスのいない機種では指定出来ない。
        !           289:        if (gMainApp.FindObject(OBJ_CONSOLE) == NULL) {
        !           290:                item.Err("cannot be specified on vmtype=%s",
        !           291:                        gMainApp.GetVMTypeStr().c_str());
        !           292:                return;
        !           293:        }
1.1       root      294: 
1.1.1.8 ! root      295:        try {
        !           296:                driver.reset(new COMDriverConsole(this));
        !           297:        } catch (...) { }
        !           298:        if ((bool)driver) {
        !           299:                if (driver->InitDriver()) {
        !           300:                        // 成功。
        !           301:                        return;
        !           302:                }
        !           303:                errmsg = driver->errmsg;
        !           304:                driver.reset();
        !           305:        }
1.1       root      306: }
                    307: 
                    308: void
                    309: HostCOMDevice::Dispatch(int udata)
                    310: {
                    311:        // driver の Dispatch は処理し終わったら DONE を返す
1.1.1.8 ! root      312:        {
        !           313:                std::lock_guard<std::mutex> guard(driverlock);
        !           314:                udata = driver->Dispatch(udata);
        !           315:        }
1.1       root      316: 
                    317:        // ...のだが、Dispatch(LISTEN_SOCKET) は着信を受け付けた時には
                    318:        // LISTEN_SOCKET を返し、それを受けてここで通知処理を行う。
                    319:        if (udata == LISTEN_SOCKET) {
1.1.1.3   root      320:                if (accept_func) {
1.1.1.8 ! root      321:                        (parent->*accept_func)(0);
1.1       root      322:                }
                    323:                udata = DONE;
                    324:        }
                    325: 
                    326:        inherited::Dispatch(udata);
                    327: }
                    328: 
                    329: // VM からの送信 (VM スレッドで呼ばれる)
                    330: bool
                    331: HostCOMDevice::Tx(uint32 data)
                    332: {
                    333:        if (loglevel >= 2) {
                    334:                char buf[8];
                    335: 
                    336:                buf[0] = '\0';
                    337:                if (0x20 <= data && data < 0x7f) {
                    338:                        snprintf(buf, sizeof(buf), " '%c'", data);
                    339:                }
                    340:                putlog(2, "Send $%02x%s", data, buf);
                    341:        }
                    342: 
                    343:        // 送信キューに入れて..
                    344:        if (txq.Enqueue(data) == false) {
                    345:                putlog(2, "txq exhausted");
                    346:                stat.txqfull_bytes++;
                    347:                return false;
                    348:        }
                    349:        stat.tx_bytes++;
                    350: 
                    351:        // ざっくりピーク値
1.1.1.4   root      352:        stat.txq_peak = std::max((uint)txq.Length(), stat.txq_peak);
1.1       root      353: 
1.1.1.8 ! root      354:        // パイプで通知。
        !           355:        return WritePipe(PIPE_TX);
1.1       root      356: }
                    357: 
                    358: // キューから取り出す (VM スレッドで呼ばれる)
                    359: uint32
                    360: HostCOMDevice::Rx()
                    361: {
                    362:        uint8 data;
                    363: 
                    364:        if (rxq.Dequeue(&data) == false) {
                    365:                // キューが空
                    366:                return -1;
                    367:        }
                    368:        stat.rx_bytes++;
                    369: 
                    370:        if (loglevel >= 2) {
                    371:                char buf[8];
                    372: 
                    373:                buf[0] = '\0';
                    374:                if (0x20 <= data && data < 0x7f) {
                    375:                        snprintf(buf, sizeof(buf), " '%c'", data);
                    376:                }
                    377:                putlog(2, "Recv $%02x%s", data, buf);
                    378:        }
                    379: 
                    380:        return data;
                    381: }
                    382: 
                    383: // ドライバから読み込む。
                    384: // 戻り値はキューに投入したデータ数。
                    385: int
                    386: HostCOMDevice::Read()
                    387: {
1.1.1.8 ! root      388:        std::lock_guard<std::mutex> guard(driverlock);
1.1       root      389:        assert((bool)driver);
                    390: 
                    391:        int data = driver->Read();
                    392:        if (data < 0) {
                    393:                return 0;
                    394:        }
                    395:        stat.read_bytes++;
                    396: 
                    397:        if (rxq.Enqueue(data) == false) {
                    398:                stat.rxqfull_bytes++;
                    399:                return 0;
                    400:        }
                    401: 
                    402:        // ざっくりピーク値
1.1.1.4   root      403:        stat.rxq_peak = std::max((uint)rxq.Length(), stat.rxq_peak);
1.1       root      404: 
                    405:        return 1;
                    406: }
                    407: 
                    408: // 外部への書き出し (ホストスレッドで呼ばれる)
                    409: void
1.1.1.8 ! root      410: HostCOMDevice::Write()
1.1       root      411: {
                    412:        uint8 data;
                    413: 
1.1.1.8 ! root      414:        std::lock_guard<std::mutex> guard(driverlock);
1.1       root      415:        assert(driver);
                    416: 
                    417:        // 送信キューを全部吐き出す
                    418:        while (txq.Dequeue(&data)) {
                    419:                driver->Write(data);
                    420:                stat.write_bytes++;
                    421:        }
                    422: }
                    423: 
1.1.1.8 ! root      424: // ドライバ名を返す
        !           425: const std::string
        !           426: HostCOMDevice::GetDriverName()
        !           427: {
        !           428:        std::lock_guard<std::mutex> guard(driverlock);
        !           429:        assert((bool)driver);
        !           430:        return driver->GetDriverName();
        !           431: }
        !           432: 
1.1       root      433: // モニタ
                    434: void
                    435: HostCOMDevice::MonitorUpdate(Monitor *, TextScreen& screen)
                    436: {
                    437:        screen.Clear();
                    438: 
1.1.1.8 ! root      439:        screen.Print(0, 0, "Device(Port)  : %s", GetPortName().c_str());
        !           440:        {
        !           441:                std::lock_guard<std::mutex> guard(driverlock);
        !           442:                screen.Print(0, 1, "HostCOM Driver: %s", driver->GetDriverName());
        !           443:                // 次の1行はドライバ依存情報
        !           444:                driver->MonitorUpdateMD(screen, 2);
        !           445:        }
1.1       root      446: 
1.1.1.3   root      447:        int y = 4;
1.1.1.8 ! root      448:        screen.Print(0, y++, "%-20s%13s", "<Tx>", "Bytes");
        !           449:        screen.Print(0, y++, "%-20s%13s", "VM sends",
1.1       root      450:                format_number(stat.tx_bytes).c_str());
1.1.1.8 ! root      451:        screen.Print(0, y++, "%-20s%13s", "Write to host",
1.1       root      452:                format_number(stat.write_bytes).c_str());
1.1.1.8 ! root      453:        screen.Print(0, y++, "%-20s%13s", "Drop:TxQ Full",
1.1       root      454:                format_number(stat.txqfull_bytes).c_str());
                    455:        y++;
                    456: 
1.1.1.8 ! root      457:        screen.Print(0, y++, "%-20s%13s", "<Rx>", "Bytes");
        !           458:        screen.Print(0, y++, "%-20s%13s", "Read from host",
1.1       root      459:                format_number(stat.read_bytes).c_str());
1.1.1.8 ! root      460:        screen.Print(0, y++, "%-20s%13s", "VM receives",
1.1       root      461:                format_number(stat.rx_bytes).c_str());
1.1.1.8 ! root      462:        screen.Print(0, y++, "%-20s%13s", "Drop:RxQ Full",
1.1       root      463:                format_number(stat.rxqfull_bytes).c_str());
                    464:        y++;
                    465: 
                    466:        screen.Print(5, y++, "Capacity Peak");
1.1.1.4   root      467:        screen.Print(0, y++, "TxQ %4u/%4u %4u",
                    468:                (uint)txq.Length(), (uint)txq.Capacity(), stat.txq_peak);
                    469:        screen.Print(0, y++, "RxQ %4u/%4u %4u",
                    470:                (uint)rxq.Length(), (uint)rxq.Capacity(), stat.rxq_peak);
1.1       root      471: }

unix.superglobalmegacorp.com

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