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

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

unix.superglobalmegacorp.com

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