Annotation of nono/vm/thread.cpp, revision 1.1.1.5

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 "thread.h"
1.1.1.3   root       12: #include "mainapp.h"
1.1       root       13: #include "mythread.h"
                     14: 
                     15: // コンストラクタ
1.1.1.3   root       16: ThreadDevice::ThreadDevice(uint objid_)
1.1.1.2   root       17:        : inherited(objid_)
1.1       root       18: {
1.1.1.5 ! root       19:        // SetName() はこのクラスでオーバーライドしているので
        !            20:        // ここで(改めて)実行する必要がある。
        !            21:        SetName(GetName());
1.1       root       22: }
                     23: 
                     24: // デストラクタ
                     25: ThreadDevice::~ThreadDevice()
                     26: {
                     27:        // ここで virtual の Terminate() は呼べないので、
                     28:        // 継承側のデストラクタで TerminateThread() をそれぞれ呼ぶこと。
                     29: }
                     30: 
1.1.1.5 ! root       31: // オブジェクト名を設定(更新)するとともにスレッド名も更新する。
        !            32: // Object::SetName() のオーバーロード。
1.1       root       33: void
1.1.1.5 ! root       34: ThreadDevice::SetName(const std::string& newname)
        !            35: {
        !            36:        inherited::SetName(newname);
        !            37:        SetThreadName(newname);
        !            38: }
        !            39: 
        !            40: // スレッドにつけるスレッド名を覚えておく
        !            41: // (このスレッドにスレッド名を設定する、ではない)。
        !            42: void
        !            43: ThreadDevice::SetThreadName(const std::string& threadname_)
1.1       root       44: {
                     45:        threadname = threadname_;
                     46: }
                     47: 
                     48: // スレッド開始
                     49: bool
                     50: ThreadDevice::StartThread()
                     51: {
1.1.1.5 ! root       52:        // ここまでに名前はセットしておくこと。
        !            53:        assert(threadname.empty() == false);
        !            54: 
1.1       root       55:        auto func = [this]() {
1.1.1.5 ! root       56:                PTHREAD_SETNAME(threadname.c_str());
1.1       root       57:                std::lock_guard<std::mutex> lock_sub(this->thread_starter);
                     58:                this->ThreadRun();
                     59:        };
                     60: 
                     61:        // スレッド起動
                     62:        std::lock_guard<std::mutex> lock(thread_starter);
                     63: 
1.1.1.4   root       64:        try {
                     65:                thread.reset(new std::thread(func));
                     66:        } catch (...) { }
1.1       root       67:        if ((bool)thread == false) {
1.1.1.5 ! root       68:                warnx("Failed to initialize thread(%s) at %s",
        !            69:                        threadname.c_str(), __method__);
1.1       root       70:                return false;
                     71:        }
                     72:        return true;
                     73: }
                     74: 
                     75: // スレッドに終了を要求し、その終了を待つ。
                     76: // スレッド外から呼ぶこと。
                     77: void
                     78: ThreadDevice::TerminateThread()
                     79: {
                     80:        if ((bool)thread) {
                     81:                Terminate();
                     82: 
                     83:                if (thread->joinable()) {
                     84:                        thread->join();
                     85:                }
                     86: 
                     87:                thread.reset();
                     88:        }
                     89: }
1.1.1.3   root       90: 
                     91: // このスレッドアフィニティを設定する。
1.1.1.5 ! root       92: /*static*/ void
        !            93: ThreadBase::SetThreadAffinityHint(AffinityClass hint)
1.1.1.3   root       94: {
                     95: #if defined(HAVE_PTHREAD_SETAFFINITY_NP) && defined(HAVE_MICPUSET)
                     96:        auto aff = gMainApp.cpu_affinity;
                     97:        if (aff == MainApp::CPUAffinity::None) {
                     98:                return;
                     99:        }
                    100: 
                    101:        // hint, aff, cpu_list から cset を作成する。
                    102:        //
                    103:        // aff  hint  list
                    104:        // ----- ---- ----
                    105:        // Low  Heavy 0         -
                    106:        // Low  Heavy 1         -
                    107:        // High Light 0         -
                    108:        // High Light 1         -
                    109:        // ↑このケースは CPU を固定しないので cset の収集自体不要。
                    110:        //
                    111:        // Low  Light 0         -
                    112:        // Low  Light 1         set
                    113:        // High Heavy 0         -
                    114:        // High Heavy 1         set
                    115:        // ↑このケースは list[] が true なところを固定。
                    116:        //
                    117:        // Perf Light 0         set
                    118:        // Perf Light 1         -
                    119:        // Perf Heavy 0         -
                    120:        // Perf Heavy 1         set
                    121:        // ↑このケースは (bool)hint と list[] が一致したところを固定。
                    122: 
                    123:        // このスレッドは CPU を固定しない。
                    124:        if ((hint == AffinityClass::Heavy && aff == MainApp::CPUAffinity::Low ) ||
                    125:                (hint == AffinityClass::Light && aff == MainApp::CPUAffinity::High))
                    126:        {
                    127:                return;
                    128:        }
                    129: 
                    130:        const std::vector<bool>& cpu_list = gMainApp.cpu_list;
                    131:        MICPUSet cset;
                    132:        for (int i = 0, end = cpu_list.size(); i < end; i++) {
                    133:                if (aff == MainApp::CPUAffinity::Perf) {
                    134:                        // Light,Heavy と list が一致していたらセット。
                    135:                        bool hintb = (hint == AffinityClass::Heavy);
                    136:                        if (hintb == cpu_list[i]) {
                    137:                                cset.Set(i);
                    138:                        }
                    139:                } else {
                    140:                        // Low,High と Light,Heavy が一致しているので立ってるほうをセット。
                    141:                        if (cpu_list[i]) {
                    142:                                cset.Set(i);
                    143:                        }
                    144:                }
                    145:        }
                    146: 
                    147:        int r = PTHREAD_SETAFFINITY(pthread_self(), cset);
                    148: 
                    149:        if (gMainApp.hostcpu->loglevel >= 1) {
                    150:                std::string csetstr;
                    151:                for (int i = 0, end = cpu_list.size(); i < end; i++) {
                    152:                        csetstr += '0' + (uint)cset.Get(i);
                    153:                }
                    154:                gMainApp.hostcpu->putmsgn("SetAffinity:%-12s(%s) %s%s%s",
                    155:                        PTHREAD_GETNAME().c_str(),
                    156:                        (hint == AffinityClass::Light ? "Light" : "Heavy"),
                    157:                        csetstr.c_str(),
                    158:                        (r == 0 ? "" : " = "),
                    159:                        (r == 0 ? "" : strerror(r)));
                    160:        }
                    161: 
                    162:        // エラーなら errno ではなく戻り値にエラー番号が返ってくる。
                    163:        // NetBSD では sysctl で許可しないと一般ユーザはこの機能を使えないため
                    164:        // EPERM で失敗したら以降はもう何もしない。
                    165:        if (r == EPERM) {
                    166:                gMainApp.cpu_affinity = MainApp::CPUAffinity::None;
                    167:        }
                    168: #else
                    169:        // なければ無視する。
                    170: #endif
                    171: }

unix.superglobalmegacorp.com

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