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

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.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:        // 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.9 ! root      161:        RWLockGuard_Write guard(driverlock);
1.1.1.8   root      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;
1.1.1.9 ! root      213:                        gMainApp.GetUIMessage()->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:        {
1.1.1.9 ! root      313:                RWLockGuard_Read guard(driverlock);
1.1.1.8   root      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.9 ! root      388:        RWLockGuard_Read 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.9 ! root      414:        RWLockGuard_Read 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: {
1.1.1.9 ! root      428:        RWLockGuard_Read guard(driverlock);
1.1.1.8   root      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:        {
1.1.1.9 ! root      441:                RWLockGuard_Read gurad(driverlock);
1.1.1.8   root      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.