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