|
|
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: #include "hostdevice.h"
1.1.1.6 ! root 12: #include "config.h"
1.1 root 13: #include "scheduler.h"
14:
15: // コンストラクタ
1.1.1.6 ! root 16: HostDevice::HostDevice(Device *parent_, uint objid_,
! 17: const std::string& portname_)
1.1.1.2 root 18: : inherited(objid_)
1.1 root 19: {
1.1.1.3 root 20: parent = parent_;
1.1.1.6 ! root 21: SetPortName(portname_);
1.1 root 22: }
23:
24: // デストラクタ
25: HostDevice::~HostDevice()
26: {
27: TerminateThread();
28: }
29:
1.1.1.5 root 30: // 動的コンストラクションその2
1.1 root 31: bool
1.1.1.5 root 32: HostDevice::Create2()
1.1 root 33: {
34: int fds[2];
35: int r;
36:
37: kq = kqueue();
38: if (kq < 0) {
39: putmsg(0, "kqueue: %s", strerror(errno));
40: return false;
41: }
42:
43: // VM スレッドからの連絡用パイプ
44: r = pipe(fds);
45: if (r < 0) {
46: putmsg(0, "pipe: %s", strerror(errno));
47: return false;
48: }
49: rpipe = fds[0];
50: wpipe = fds[1];
51:
52: if (kevent_add(kq, rpipe, EVFILT_READ, EV_ADD, DATA_FROM_VM) < 0) {
53: putmsg(0, "kevent_add: %s", strerror(errno));
54: return false;
55: }
56:
57: return true;
58: }
59:
1.1.1.6 ! root 60: // 初期化
! 61: bool
! 62: HostDevice::Init()
! 63: {
! 64: // Create2() と Config::Fix が終わったところで fallback をオンにする。
! 65: // これ以降の動的変更でエラー終了するのは困るので。
! 66: std::string line = GetConfigKey() + "-fallback=1";
! 67: gConfig->UpdateRunning(line);
! 68:
! 69: return true;
! 70: }
! 71:
1.1 root 72: // 設定ファイルキーのプレフィックス ("hostcomX" とか) を返す
73: std::string
74: HostDevice::GetConfigKey() const
75: {
76: return string_tolower(GetName());
77: }
78:
79: // 外部からの読み込みディスクリプタを登録
80: int
81: HostDevice::AddOuter(int fd)
82: {
83: return kevent_add(kq, fd, EVFILT_READ, EV_ADD, DATA_FROM_OUTER);
84: }
85:
86: // 外部からの読み込みディスクリプタを登録解除。
87: //
88: // *BSD では kqueue(2) に登録したディスクリプタがクローズされると自動的に
89: // 削除されるので本来この操作は不要だが、libkqueue などユーザランドで実装
90: // してある互換ライブラリでは実現方法がなく自動的に削除されない。
91: // そのためディスクリプタをクローズする前にこれを呼ぶこと。
92: // see https://github.com/mheily/libkqueue/blob/master/BUGS.md
93: int
94: HostDevice::DelOuter(int fd)
95: {
96: return kevent_add(kq, fd, EVFILT_READ, EV_DELETE, DATA_FROM_OUTER);
97: }
98:
99: // Listen ソケットを登録
100: int
101: HostDevice::AddListen(int ls, int action)
102: {
103: return kevent_add(kq, ls, EVFILT_READ, action, LISTEN_SOCKET);
104: }
105:
1.1.1.6 ! root 106: // Listen ソケットを登録解除。
! 107: int
! 108: HostDevice::DelListen(int ls)
! 109: {
! 110: return kevent_add(kq, ls, EVFILT_READ, EV_DELETE, LISTEN_SOCKET);
! 111: }
! 112:
! 113: // 受信通知コールバックを解除
! 114: void
! 115: HostDevice::ResetRxCallback()
! 116: {
! 117: rx_func = NULL;
! 118: }
! 119:
1.1 root 120: // 受信通知コールバックを設定
121: void
1.1.1.6 ! root 122: HostDevice::SetRxCallback(DeviceCallback_t func, uint32 arg)
1.1 root 123: {
124: rx_func = func;
1.1.1.6 ! root 125: rx_arg = arg;
1.1 root 126: }
127:
128: // 着信通知コールバックを設定
129: void
130: HostDevice::SetAcceptCallback(DeviceCallback_t func)
131: {
132: accept_func = func;
133: }
134:
135: // スレッド実行
136: void
137: HostDevice::ThreadRun()
138: {
1.1.1.4 root 139: SetThreadAffinityHint(AffinityClass::Light);
140:
1.1 root 141: for (; exit_requested == false; ) {
142: struct kevent kev;
143: int r;
144:
145: putlog(3, "polling");
146:
147: r = kevent_poll(kq, &kev, 1, NULL);
148: if (r < 0) {
149: if (errno == EINTR) {
150: continue;
151: }
152: // XXX どうする?
153: putlog(0, "ThreadRun: kevent_poll: %s", strerror(errno));
154: return;
155: }
156: assert(r > 0);
157: int udata = EV_UDATA2INT(kev.udata);
158: putlog(3, "polled: udata=%d", udata);
159:
160: Dispatch(udata);
161: }
162: }
163:
164: void
165: HostDevice::Dispatch(int udata)
166: {
167: int n;
168:
169: if (udata == DATA_FROM_VM) {
170: // VM からの送信パイプに着信があった
171: char buf[1];
172:
173: n = read(rpipe, buf, sizeof(buf));
174: if (n < 0) {
175: // XXX どうする?
176: putlog(0, "Dispatch: read: %s", strerror(errno));
177: exit_requested = true;
178: return;
179: }
180: if (n == 0) {
181: // EOF なら終了要求
182: exit_requested = true;
183: return;
184: }
185:
1.1.1.6 ! root 186: if (__predict_false(buf[0] != PIPE_TX)) {
! 187: SelectDriver(false);
! 188: } else {
! 189: // 外部に送信 (継承クラスによる)
! 190: Write();
! 191: }
1.1 root 192:
193: } else if (udata == DATA_FROM_OUTER) {
194: // 外部から着信があった
195:
196: // キューに1個以上データが投入されたら VM に通知
197: n = Read();
198: if (n > 0) {
1.1.1.3 root 199: if (rx_func) {
1.1.1.6 ! root 200: (parent->*rx_func)(rx_arg);
1.1 root 201: }
202: }
203: }
204: }
205:
206: // data (のうち下位8bit) をパイプに書き込む。(VM スレッドで呼ばれる)
207: bool
208: HostDevice::WritePipe(uint32 data)
209: {
210: uint8 buf[1];
211:
212: buf[0] = data;
213: if (write(wpipe, buf, sizeof(buf)) < 1) {
214: return false;
215: }
216: return true;
217: }
218:
219: // スレッド終了指示
220: void
221: HostDevice::Terminate()
222: {
223: // wpipe を閉じると rpipe が EOF になって最終的にスレッドが終了する。
224: wpipe.Close();
225: }
226:
227: // ログ表示。
228: // ホストデバイスでは、仮想時間とオブジェクト名を表示する。PC は表示しない。
229: void
230: HostDevice::putlogn(const char *fmt, ...) const
231: {
232: char buf[1024];
233: va_list ap;
234: int len;
235:
1.1.1.2 root 236: uint64 vt = scheduler->GetVirtTime();
1.1.1.4 root 237: len = snprintf(buf, sizeof(buf), "%4u.%03u'%03u'%03u %s ",
238: (uint)(vt / 1000 / 1000 / 1000),
239: (uint)((vt / 1000 / 1000) % 1000),
240: (uint)((vt / 1000) % 1000),
241: (uint)(vt % 1000),
1.1 root 242: GetName().c_str());
243:
244: va_start(ap, fmt);
245: vsnprintf(buf + len, sizeof(buf) - len, fmt, ap);
246: va_end(ap);
247:
248: WriteLog(buf);
249: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.