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

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: 
1.1.1.6 ! root       60: // 初期化
        !            61: bool
        !            62: HostDevice::Init()
        !            63: {
        !            64:        // Create2() と Config::Fix が終わったところで fallback をオンにする。
        !            65:        // これ以降の動的変更でエラー終了するのは困るので。
        !            66:        std::string line = GetConfigKey() + "-fallback=1";
        !            67:        gConfig->UpdateRunning(line);
        !            68: 
        !            69:        return true;
        !            70: }
        !            71: 
1.1       root       72: // 設定ファイルキーのプレフィックス ("hostcomX" とか) を返す
                     73: std::string
                     74: HostDevice::GetConfigKey() const
                     75: {
                     76:        return string_tolower(GetName());
                     77: }
                     78: 
                     79: // 外部からの読み込みディスクリプタを登録
                     80: int
                     81: HostDevice::AddOuter(int fd)
                     82: {
                     83:        return kevent_add(kq, fd, EVFILT_READ, EV_ADD, DATA_FROM_OUTER);
                     84: }
                     85: 
                     86: // 外部からの読み込みディスクリプタを登録解除。
                     87: //
                     88: // *BSD では kqueue(2) に登録したディスクリプタがクローズされると自動的に
                     89: // 削除されるので本来この操作は不要だが、libkqueue などユーザランドで実装
                     90: // してある互換ライブラリでは実現方法がなく自動的に削除されない。
                     91: // そのためディスクリプタをクローズする前にこれを呼ぶこと。
                     92: // see https://github.com/mheily/libkqueue/blob/master/BUGS.md
                     93: int
                     94: HostDevice::DelOuter(int fd)
                     95: {
                     96:        return kevent_add(kq, fd, EVFILT_READ, EV_DELETE, DATA_FROM_OUTER);
                     97: }
                     98: 
                     99: // Listen ソケットを登録
                    100: int
                    101: HostDevice::AddListen(int ls, int action)
                    102: {
                    103:        return kevent_add(kq, ls, EVFILT_READ, action, LISTEN_SOCKET);
                    104: }
                    105: 
1.1.1.6 ! root      106: // Listen ソケットを登録解除。
        !           107: int
        !           108: HostDevice::DelListen(int ls)
        !           109: {
        !           110:        return kevent_add(kq, ls, EVFILT_READ, EV_DELETE, LISTEN_SOCKET);
        !           111: }
        !           112: 
        !           113: // 受信通知コールバックを解除
        !           114: void
        !           115: HostDevice::ResetRxCallback()
        !           116: {
        !           117:        rx_func = NULL;
        !           118: }
        !           119: 
1.1       root      120: // 受信通知コールバックを設定
                    121: void
1.1.1.6 ! root      122: HostDevice::SetRxCallback(DeviceCallback_t func, uint32 arg)
1.1       root      123: {
                    124:        rx_func = func;
1.1.1.6 ! root      125:        rx_arg  = arg;
1.1       root      126: }
                    127: 
                    128: // 着信通知コールバックを設定
                    129: void
                    130: HostDevice::SetAcceptCallback(DeviceCallback_t func)
                    131: {
                    132:        accept_func = func;
                    133: }
                    134: 
                    135: // スレッド実行
                    136: void
                    137: HostDevice::ThreadRun()
                    138: {
1.1.1.4   root      139:        SetThreadAffinityHint(AffinityClass::Light);
                    140: 
1.1       root      141:        for (; exit_requested == false; ) {
                    142:                struct kevent kev;
                    143:                int r;
                    144: 
                    145:                putlog(3, "polling");
                    146: 
                    147:                r = kevent_poll(kq, &kev, 1, NULL);
                    148:                if (r < 0) {
                    149:                        if (errno == EINTR) {
                    150:                                continue;
                    151:                        }
                    152:                        // XXX どうする?
                    153:                        putlog(0, "ThreadRun: kevent_poll: %s", strerror(errno));
                    154:                        return;
                    155:                }
                    156:                assert(r > 0);
                    157:                int udata = EV_UDATA2INT(kev.udata);
                    158:                putlog(3, "polled: udata=%d", udata);
                    159: 
                    160:                Dispatch(udata);
                    161:        }
                    162: }
                    163: 
                    164: void
                    165: HostDevice::Dispatch(int udata)
                    166: {
                    167:        int n;
                    168: 
                    169:        if (udata == DATA_FROM_VM) {
                    170:                // VM からの送信パイプに着信があった
                    171:                char buf[1];
                    172: 
                    173:                n = read(rpipe, buf, sizeof(buf));
                    174:                if (n < 0) {
                    175:                        // XXX どうする?
                    176:                        putlog(0, "Dispatch: read: %s", strerror(errno));
                    177:                        exit_requested = true;
                    178:                        return;
                    179:                }
                    180:                if (n == 0) {
                    181:                        // EOF なら終了要求
                    182:                        exit_requested = true;
                    183:                        return;
                    184:                }
                    185: 
1.1.1.6 ! root      186:                if (__predict_false(buf[0] != PIPE_TX)) {
        !           187:                        SelectDriver(false);
        !           188:                } else {
        !           189:                        // 外部に送信 (継承クラスによる)
        !           190:                        Write();
        !           191:                }
1.1       root      192: 
                    193:        } else if (udata == DATA_FROM_OUTER) {
                    194:                // 外部から着信があった
                    195: 
                    196:                // キューに1個以上データが投入されたら VM に通知
                    197:                n = Read();
                    198:                if (n > 0) {
1.1.1.3   root      199:                        if (rx_func) {
1.1.1.6 ! root      200:                                (parent->*rx_func)(rx_arg);
1.1       root      201:                        }
                    202:                }
                    203:        }
                    204: }
                    205: 
                    206: // data (のうち下位8bit) をパイプに書き込む。(VM スレッドで呼ばれる)
                    207: bool
                    208: HostDevice::WritePipe(uint32 data)
                    209: {
                    210:        uint8 buf[1];
                    211: 
                    212:        buf[0] = data;
                    213:        if (write(wpipe, buf, sizeof(buf)) < 1) {
                    214:                return false;
                    215:        }
                    216:        return true;
                    217: }
                    218: 
                    219: // スレッド終了指示
                    220: void
                    221: HostDevice::Terminate()
                    222: {
                    223:        // wpipe を閉じると rpipe が EOF になって最終的にスレッドが終了する。
                    224:        wpipe.Close();
                    225: }
                    226: 
                    227: // ログ表示。
                    228: // ホストデバイスでは、仮想時間とオブジェクト名を表示する。PC は表示しない。
                    229: void
                    230: HostDevice::putlogn(const char *fmt, ...) const
                    231: {
                    232:        char buf[1024];
                    233:        va_list ap;
                    234:        int len;
                    235: 
1.1.1.2   root      236:        uint64 vt = scheduler->GetVirtTime();
1.1.1.4   root      237:        len = snprintf(buf, sizeof(buf), "%4u.%03u'%03u'%03u %s ",
                    238:                (uint)(vt / 1000 / 1000 / 1000),
                    239:                (uint)((vt / 1000 / 1000) % 1000),
                    240:                (uint)((vt / 1000) % 1000),
                    241:                (uint)(vt % 1000),
1.1       root      242:                GetName().c_str());
                    243: 
                    244:        va_start(ap, fmt);
                    245:        vsnprintf(buf + len, sizeof(buf) - len, fmt, ap);
                    246:        va_end(ap);
                    247: 
                    248:        WriteLog(buf);
                    249: }

unix.superglobalmegacorp.com

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