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

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.3 ! root       15: HostDevice::HostDevice(Device *parent_, int 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: {
                    113:        for (; exit_requested == false; ) {
                    114:                struct kevent kev;
                    115:                int r;
                    116: 
                    117:                putlog(3, "polling");
                    118: 
                    119:                r = kevent_poll(kq, &kev, 1, NULL);
                    120:                if (r < 0) {
                    121:                        if (errno == EINTR) {
                    122:                                continue;
                    123:                        }
                    124:                        // XXX どうする?
                    125:                        putlog(0, "ThreadRun: kevent_poll: %s", strerror(errno));
                    126:                        return;
                    127:                }
                    128:                assert(r > 0);
                    129:                int udata = EV_UDATA2INT(kev.udata);
                    130:                putlog(3, "polled: udata=%d", udata);
                    131: 
                    132:                Dispatch(udata);
                    133:        }
                    134: }
                    135: 
                    136: void
                    137: HostDevice::Dispatch(int udata)
                    138: {
                    139:        int n;
                    140: 
                    141:        if (udata == DATA_FROM_VM) {
                    142:                // VM からの送信パイプに着信があった
                    143:                char buf[1];
                    144: 
                    145:                n = read(rpipe, buf, sizeof(buf));
                    146:                if (n < 0) {
                    147:                        // XXX どうする?
                    148:                        putlog(0, "Dispatch: read: %s", strerror(errno));
                    149:                        exit_requested = true;
                    150:                        return;
                    151:                }
                    152:                if (n == 0) {
                    153:                        // EOF なら終了要求
                    154:                        exit_requested = true;
                    155:                        return;
                    156:                }
                    157: 
                    158:                // 外部に送信 (継承クラスによる)
                    159:                Write(buf[0]);
                    160: 
                    161:        } else if (udata == DATA_FROM_OUTER) {
                    162:                // 外部から着信があった
                    163: 
                    164:                // キューに1個以上データが投入されたら VM に通知
                    165:                n = Read();
                    166:                if (n > 0) {
1.1.1.3 ! root      167:                        if (rx_func) {
        !           168:                                (parent->*rx_func)();
1.1       root      169:                        }
                    170:                }
                    171:        }
                    172: }
                    173: 
                    174: // data (のうち下位8bit) をパイプに書き込む。(VM スレッドで呼ばれる)
                    175: bool
                    176: HostDevice::WritePipe(uint32 data)
                    177: {
                    178:        uint8 buf[1];
                    179: 
                    180:        buf[0] = data;
                    181:        if (write(wpipe, buf, sizeof(buf)) < 1) {
                    182:                return false;
                    183:        }
                    184:        return true;
                    185: }
                    186: 
                    187: // スレッド終了指示
                    188: void
                    189: HostDevice::Terminate()
                    190: {
                    191:        // wpipe を閉じると rpipe が EOF になって最終的にスレッドが終了する。
                    192:        wpipe.Close();
                    193: }
                    194: 
                    195: // ログ表示。
                    196: // ホストデバイスでは、仮想時間とオブジェクト名を表示する。PC は表示しない。
                    197: void
                    198: HostDevice::putlogn(const char *fmt, ...) const
                    199: {
                    200:        char buf[1024];
                    201:        va_list ap;
                    202:        int len;
                    203: 
1.1.1.2   root      204:        uint64 vt = scheduler->GetVirtTime();
1.1       root      205:        len = snprintf(buf, sizeof(buf), "%4d.%03d'%03d'%03d %s ",
                    206:                (int)(vt / 1000 / 1000 / 1000),
                    207:                (int)((vt / 1000 / 1000) % 1000),
                    208:                (int)((vt / 1000) % 1000),
                    209:                (int)(vt % 1000),
                    210:                GetName().c_str());
                    211: 
                    212:        va_start(ap, fmt);
                    213:        vsnprintf(buf + len, sizeof(buf) - len, fmt, ap);
                    214:        va_end(ap);
                    215: 
                    216:        WriteLog(buf);
                    217: }

unix.superglobalmegacorp.com

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