|
|
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: 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
423: HostCOMDevice::MonitorUpdate(Monitor *, TextScreen& screen)
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行はドライバ依存情報
433: driver->MonitorUpdateMD(screen, 2);
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.