|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.