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