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

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: #include "signalthread.h"
                     14: 
                     15: // コンストラクタ
                     16: HostDevice::HostDevice(const std::string& objname_)
                     17:        : inherited(objname_)
                     18: {
                     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: 
                     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: // シグナルスレッドからのパイプを登録
                     85: int
                     86: HostDevice::AddSignal(int rfd, int wfd)
                     87: {
                     88:        int r;
                     89: 
                     90:        r = kevent_add(kq, rfd, EVFILT_READ, EV_ADD, DATA_FROM_SIGNAL);
                     91:        if (r < 0) {
                     92:                return r;
                     93:        }
                     94:        // シグナルスレッドに登録。
                     95:        gSignalThread->AddPipe(wfd);
                     96: 
                     97:        return 0;
                     98: }
                     99: 
                    100: // Listen ソケットを登録
                    101: int
                    102: HostDevice::AddListen(int ls, int action)
                    103: {
                    104:        return kevent_add(kq, ls, EVFILT_READ, action, LISTEN_SOCKET);
                    105: }
                    106: 
                    107: // コールバック先デバイスを設定。
                    108: //
                    109: // コールバックはデバイスと関数が両方設定されている時だけ呼び出すので、
                    110: // 設定時は、コールバック関数設定後に SetCallbackDevice() でデバイスを設定、
                    111: // 解除時は、まず SetCallbackDevice(NULL) でデバイスを解除、
                    112: // の順にすること。
                    113: void
                    114: HostDevice::SetCallbackDevice(Device *dev_)
                    115: {
                    116:        dev = dev_;
                    117: }
                    118: 
                    119: // 受信通知コールバックを設定
                    120: void
                    121: HostDevice::SetRxCallback(DeviceCallback_t func)
                    122: {
                    123:        rx_func = func;
                    124: }
                    125: 
                    126: // 着信通知コールバックを設定
                    127: void
                    128: HostDevice::SetAcceptCallback(DeviceCallback_t func)
                    129: {
                    130:        accept_func = func;
                    131: }
                    132: 
                    133: // スレッド実行
                    134: void
                    135: HostDevice::ThreadRun()
                    136: {
                    137:        for (; exit_requested == false; ) {
                    138:                struct kevent kev;
                    139:                int r;
                    140: 
                    141:                putlog(3, "polling");
                    142: 
                    143:                r = kevent_poll(kq, &kev, 1, NULL);
                    144:                if (r < 0) {
                    145:                        if (errno == EINTR) {
                    146:                                continue;
                    147:                        }
                    148:                        // XXX どうする?
                    149:                        putlog(0, "ThreadRun: kevent_poll: %s", strerror(errno));
                    150:                        return;
                    151:                }
                    152:                assert(r > 0);
                    153:                int udata = EV_UDATA2INT(kev.udata);
                    154:                putlog(3, "polled: udata=%d", udata);
                    155: 
                    156:                Dispatch(udata);
                    157:        }
                    158: }
                    159: 
                    160: void
                    161: HostDevice::Dispatch(int udata)
                    162: {
                    163:        int n;
                    164: 
                    165:        if (udata == DATA_FROM_VM) {
                    166:                // VM からの送信パイプに着信があった
                    167:                char buf[1];
                    168: 
                    169:                n = read(rpipe, buf, sizeof(buf));
                    170:                if (n < 0) {
                    171:                        // XXX どうする?
                    172:                        putlog(0, "Dispatch: read: %s", strerror(errno));
                    173:                        exit_requested = true;
                    174:                        return;
                    175:                }
                    176:                if (n == 0) {
                    177:                        // EOF なら終了要求
                    178:                        exit_requested = true;
                    179:                        return;
                    180:                }
                    181: 
                    182:                // 外部に送信 (継承クラスによる)
                    183:                Write(buf[0]);
                    184: 
                    185:        } else if (udata == DATA_FROM_OUTER) {
                    186:                // 外部から着信があった
                    187: 
                    188:                // キューに1個以上データが投入されたら VM に通知
                    189:                n = Read();
                    190:                if (n > 0) {
                    191:                        if (dev && rx_func) {
                    192:                                (dev->*rx_func)();
                    193:                        }
                    194:                }
                    195:        }
                    196: }
                    197: 
                    198: // data (のうち下位8bit) をパイプに書き込む。(VM スレッドで呼ばれる)
                    199: bool
                    200: HostDevice::WritePipe(uint32 data)
                    201: {
                    202:        uint8 buf[1];
                    203: 
                    204:        buf[0] = data;
                    205:        if (write(wpipe, buf, sizeof(buf)) < 1) {
                    206:                return false;
                    207:        }
                    208:        return true;
                    209: }
                    210: 
                    211: // スレッド終了指示
                    212: void
                    213: HostDevice::Terminate()
                    214: {
                    215:        // wpipe を閉じると rpipe が EOF になって最終的にスレッドが終了する。
                    216:        wpipe.Close();
                    217: }
                    218: 
                    219: // ログ表示。
                    220: // ホストデバイスでは、仮想時間とオブジェクト名を表示する。PC は表示しない。
                    221: void
                    222: HostDevice::putlogn(const char *fmt, ...) const
                    223: {
                    224:        char buf[1024];
                    225:        va_list ap;
                    226:        int len;
                    227: 
                    228:        uint64 vt = gScheduler->GetVirtTime();
                    229:        len = snprintf(buf, sizeof(buf), "%4d.%03d'%03d'%03d %s ",
                    230:                (int)(vt / 1000 / 1000 / 1000),
                    231:                (int)((vt / 1000 / 1000) % 1000),
                    232:                (int)((vt / 1000) % 1000),
                    233:                (int)(vt % 1000),
                    234:                GetName().c_str());
                    235: 
                    236:        va_start(ap, fmt);
                    237:        vsnprintf(buf + len, sizeof(buf) - len, fmt, ap);
                    238:        va_end(ap);
                    239: 
                    240:        WriteLog(buf);
                    241: }

unix.superglobalmegacorp.com

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