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

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

unix.superglobalmegacorp.com

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