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