summaryrefslogtreecommitdiff
path: root/src/buildtool/multithreading/task_system.cpp
diff options
context:
space:
mode:
authorKlaus Aehlig <klaus.aehlig@huawei.com>2022-02-22 17:03:21 +0100
committerKlaus Aehlig <klaus.aehlig@huawei.com>2022-02-22 17:03:21 +0100
commit619def44c1cca9f3cdf63544d5f24f2c7a7d9b77 (patch)
tree01868de723cb82c86842f33743fa7b14e24c1fa3 /src/buildtool/multithreading/task_system.cpp
downloadjustbuild-619def44c1cca9f3cdf63544d5f24f2c7a7d9b77.tar.gz
Initial self-hosting commit
This is the initial version of our tool that is able to build itself. In can be bootstrapped by ./bin/bootstrap.py Co-authored-by: Oliver Reiche <oliver.reiche@huawei.com> Co-authored-by: Victor Moreno <victor.moreno1@huawei.com>
Diffstat (limited to 'src/buildtool/multithreading/task_system.cpp')
-rw-r--r--src/buildtool/multithreading/task_system.cpp56
1 files changed, 56 insertions, 0 deletions
diff --git a/src/buildtool/multithreading/task_system.cpp b/src/buildtool/multithreading/task_system.cpp
new file mode 100644
index 00000000..8c976a2f
--- /dev/null
+++ b/src/buildtool/multithreading/task_system.cpp
@@ -0,0 +1,56 @@
+#include "src/buildtool/multithreading/task_system.hpp"
+
+#include "gsl-lite/gsl-lite.hpp"
+#include "src/buildtool/multithreading/task.hpp"
+
+TaskSystem::TaskSystem() : TaskSystem(std::thread::hardware_concurrency()) {}
+
+TaskSystem::TaskSystem(std::size_t number_of_threads)
+ : thread_count_{std::max(1UL, number_of_threads)},
+ num_threads_running_{thread_count_} {
+ for (std::size_t index = 0; index < thread_count_; ++index) {
+ queues_.emplace_back(&queues_read_, &num_threads_running_);
+ }
+ for (std::size_t index = 0; index < thread_count_; ++index) {
+ threads_.emplace_back([&, index]() { Run(index); });
+ }
+}
+
+TaskSystem::~TaskSystem() {
+ // When starting a new task system all spawned threads will immediately go
+ // to sleep and wait for tasks. Even after adding some tasks, it can take a
+ // while until the first thread wakes up. Therefore, we first need to wait
+ // for the queues being read, before we can wait for all threads to become
+ // idle.
+ queues_read_.WaitForSet();
+ num_threads_running_.WaitForZero();
+ for (auto& q : queues_) {
+ q.done();
+ }
+ for (auto& t : threads_) {
+ t.join();
+ }
+}
+
+void TaskSystem::Run(std::size_t idx) {
+ gsl_Expects(thread_count_ > 0);
+
+ while (true) {
+ std::optional<Task> t{};
+ for (std::size_t i = 0; i < thread_count_; ++i) {
+ t = queues_[(idx + i) % thread_count_].try_pop();
+ if (t) {
+ break;
+ }
+ }
+
+ // NOLINTNEXTLINE(clang-analyzer-core.DivideZero)
+ t = t ? t : queues_[idx % thread_count_].pop();
+
+ if (!t) {
+ break;
+ }
+
+ (*t)();
+ }
+}