|
|
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:
1.1.1.4 ! root 53: try {
! 54: thread.reset(new std::thread(func));
! 55: } catch (...) { }
1.1 root 56: if ((bool)thread == false) {
1.1.1.4 ! root 57: warnx("Failed to initialize thread(%s) at %s", threadname, __method__);
1.1 root 58: return false;
59: }
60: return true;
61: }
62:
63: // スレッドに終了を要求し、その終了を待つ。
64: // スレッド外から呼ぶこと。
65: void
66: ThreadDevice::TerminateThread()
67: {
68: if ((bool)thread) {
69: Terminate();
70:
71: if (thread->joinable()) {
72: thread->join();
73: }
74:
75: thread.reset();
76: }
77: }
1.1.1.3 root 78:
79: // このスレッドアフィニティを設定する。
80: void
81: ThreadDevice::SetThreadAffinityHint(AffinityClass hint)
82: {
83: #if defined(HAVE_PTHREAD_SETAFFINITY_NP) && defined(HAVE_MICPUSET)
84: auto aff = gMainApp.cpu_affinity;
85: if (aff == MainApp::CPUAffinity::None) {
86: return;
87: }
88:
89: // hint, aff, cpu_list から cset を作成する。
90: //
91: // aff hint list
92: // ----- ---- ----
93: // Low Heavy 0 -
94: // Low Heavy 1 -
95: // High Light 0 -
96: // High Light 1 -
97: // ↑このケースは CPU を固定しないので cset の収集自体不要。
98: //
99: // Low Light 0 -
100: // Low Light 1 set
101: // High Heavy 0 -
102: // High Heavy 1 set
103: // ↑このケースは list[] が true なところを固定。
104: //
105: // Perf Light 0 set
106: // Perf Light 1 -
107: // Perf Heavy 0 -
108: // Perf Heavy 1 set
109: // ↑このケースは (bool)hint と list[] が一致したところを固定。
110:
111: // このスレッドは CPU を固定しない。
112: if ((hint == AffinityClass::Heavy && aff == MainApp::CPUAffinity::Low ) ||
113: (hint == AffinityClass::Light && aff == MainApp::CPUAffinity::High))
114: {
115: return;
116: }
117:
118: const std::vector<bool>& cpu_list = gMainApp.cpu_list;
119: MICPUSet cset;
120: for (int i = 0, end = cpu_list.size(); i < end; i++) {
121: if (aff == MainApp::CPUAffinity::Perf) {
122: // Light,Heavy と list が一致していたらセット。
123: bool hintb = (hint == AffinityClass::Heavy);
124: if (hintb == cpu_list[i]) {
125: cset.Set(i);
126: }
127: } else {
128: // Low,High と Light,Heavy が一致しているので立ってるほうをセット。
129: if (cpu_list[i]) {
130: cset.Set(i);
131: }
132: }
133: }
134:
135: int r = PTHREAD_SETAFFINITY(pthread_self(), cset);
136:
137: if (gMainApp.hostcpu->loglevel >= 1) {
138: std::string csetstr;
139: for (int i = 0, end = cpu_list.size(); i < end; i++) {
140: csetstr += '0' + (uint)cset.Get(i);
141: }
142: gMainApp.hostcpu->putmsgn("SetAffinity:%-12s(%s) %s%s%s",
143: PTHREAD_GETNAME().c_str(),
144: (hint == AffinityClass::Light ? "Light" : "Heavy"),
145: csetstr.c_str(),
146: (r == 0 ? "" : " = "),
147: (r == 0 ? "" : strerror(r)));
148: }
149:
150: // エラーなら errno ではなく戻り値にエラー番号が返ってくる。
151: // NetBSD では sysctl で許可しないと一般ユーザはこの機能を使えないため
152: // EPERM で失敗したら以降はもう何もしない。
153: if (r == EPERM) {
154: gMainApp.cpu_affinity = MainApp::CPUAffinity::None;
155: }
156: #else
157: // なければ無視する。
158: #endif
159: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.