|
|
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.2 ! root 15: HostDevice::HostDevice(int objid_)
! 16: : inherited(objid_)
1.1 root 17: {
18: }
19:
20: // デストラクタ
21: HostDevice::~HostDevice()
22: {
23: TerminateThread();
24: }
25:
26: // 初期化
27: bool
28: HostDevice::Init()
29: {
30: int fds[2];
31: int r;
32:
1.1.1.2 ! root 33: if (inherited::Init() == false) {
! 34: return false;
! 35: }
! 36:
1.1 root 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:
94: // コールバック先デバイスを設定。
95: //
96: // コールバックはデバイスと関数が両方設定されている時だけ呼び出すので、
97: // 設定時は、コールバック関数設定後に SetCallbackDevice() でデバイスを設定、
98: // 解除時は、まず SetCallbackDevice(NULL) でデバイスを解除、
99: // の順にすること。
100: void
101: HostDevice::SetCallbackDevice(Device *dev_)
102: {
103: dev = dev_;
104: }
105:
106: // 受信通知コールバックを設定
107: void
108: HostDevice::SetRxCallback(DeviceCallback_t func)
109: {
110: rx_func = func;
111: }
112:
113: // 着信通知コールバックを設定
114: void
115: HostDevice::SetAcceptCallback(DeviceCallback_t func)
116: {
117: accept_func = func;
118: }
119:
120: // スレッド実行
121: void
122: HostDevice::ThreadRun()
123: {
124: for (; exit_requested == false; ) {
125: struct kevent kev;
126: int r;
127:
128: putlog(3, "polling");
129:
130: r = kevent_poll(kq, &kev, 1, NULL);
131: if (r < 0) {
132: if (errno == EINTR) {
133: continue;
134: }
135: // XXX どうする?
136: putlog(0, "ThreadRun: kevent_poll: %s", strerror(errno));
137: return;
138: }
139: assert(r > 0);
140: int udata = EV_UDATA2INT(kev.udata);
141: putlog(3, "polled: udata=%d", udata);
142:
143: Dispatch(udata);
144: }
145: }
146:
147: void
148: HostDevice::Dispatch(int udata)
149: {
150: int n;
151:
152: if (udata == DATA_FROM_VM) {
153: // VM からの送信パイプに着信があった
154: char buf[1];
155:
156: n = read(rpipe, buf, sizeof(buf));
157: if (n < 0) {
158: // XXX どうする?
159: putlog(0, "Dispatch: read: %s", strerror(errno));
160: exit_requested = true;
161: return;
162: }
163: if (n == 0) {
164: // EOF なら終了要求
165: exit_requested = true;
166: return;
167: }
168:
169: // 外部に送信 (継承クラスによる)
170: Write(buf[0]);
171:
172: } else if (udata == DATA_FROM_OUTER) {
173: // 外部から着信があった
174:
175: // キューに1個以上データが投入されたら VM に通知
176: n = Read();
177: if (n > 0) {
178: if (dev && rx_func) {
179: (dev->*rx_func)();
180: }
181: }
182: }
183: }
184:
185: // data (のうち下位8bit) をパイプに書き込む。(VM スレッドで呼ばれる)
186: bool
187: HostDevice::WritePipe(uint32 data)
188: {
189: uint8 buf[1];
190:
191: buf[0] = data;
192: if (write(wpipe, buf, sizeof(buf)) < 1) {
193: return false;
194: }
195: return true;
196: }
197:
198: // スレッド終了指示
199: void
200: HostDevice::Terminate()
201: {
202: // wpipe を閉じると rpipe が EOF になって最終的にスレッドが終了する。
203: wpipe.Close();
204: }
205:
206: // ログ表示。
207: // ホストデバイスでは、仮想時間とオブジェクト名を表示する。PC は表示しない。
208: void
209: HostDevice::putlogn(const char *fmt, ...) const
210: {
211: char buf[1024];
212: va_list ap;
213: int len;
214:
1.1.1.2 ! root 215: uint64 vt = scheduler->GetVirtTime();
1.1 root 216: len = snprintf(buf, sizeof(buf), "%4d.%03d'%03d'%03d %s ",
217: (int)(vt / 1000 / 1000 / 1000),
218: (int)((vt / 1000 / 1000) % 1000),
219: (int)((vt / 1000) % 1000),
220: (int)(vt % 1000),
221: GetName().c_str());
222:
223: va_start(ap, fmt);
224: vsnprintf(buf + len, sizeof(buf) - len, fmt, ap);
225: va_end(ap);
226:
227: WriteLog(buf);
228: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.