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