|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.