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

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

unix.superglobalmegacorp.com

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