Annotation of nono/host/hostdevice.cpp, revision 1.1.1.5

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.