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