summaryrefslogtreecommitdiffstats
path: root/Tests/CMakeLib/testUVJobServerClient.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'Tests/CMakeLib/testUVJobServerClient.cxx')
-rw-r--r--Tests/CMakeLib/testUVJobServerClient.cxx179
1 files changed, 179 insertions, 0 deletions
diff --git a/Tests/CMakeLib/testUVJobServerClient.cxx b/Tests/CMakeLib/testUVJobServerClient.cxx
new file mode 100644
index 0000000..13f0f40
--- /dev/null
+++ b/Tests/CMakeLib/testUVJobServerClient.cxx
@@ -0,0 +1,179 @@
+#include <cassert>
+#include <cstddef>
+#include <deque>
+#include <iostream>
+#include <vector>
+
+#include <cm/optional>
+
+#include <cm3p/uv.h>
+
+#ifndef _WIN32
+# include <unistd.h>
+#endif
+
+#include "cmGetPipes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmUVHandlePtr.h"
+#include "cmUVJobServerClient.h"
+
+namespace {
+
+const std::size_t kTOTAL_JOBS = 10;
+const std::size_t kTOTAL_TOKENS = 3;
+
+struct Job
+{
+ cm::uv_timer_ptr Timer;
+};
+
+struct JobRunner
+{
+ cm::uv_loop_ptr Loop;
+ cm::optional<cmUVJobServerClient> JSC;
+ std::vector<Job> Jobs;
+ std::size_t NextJobIndex = 0;
+
+ std::size_t ActiveJobs = 0;
+
+ std::deque<std::size_t> Queue;
+
+ bool Okay = true;
+
+ JobRunner()
+ : Jobs(kTOTAL_JOBS)
+ {
+ this->Loop.init(nullptr);
+ this->JSC = cmUVJobServerClient::Connect(
+ *this->Loop, [this]() { this->StartQueuedJob(); }, nullptr);
+ if (!this->JSC) {
+ std::cerr << "Failed to connect to job server.\n";
+ this->Okay = false;
+ }
+ }
+
+ ~JobRunner() {}
+
+ bool Run()
+ {
+ if (this->Okay) {
+ this->QueueNextJobs();
+ uv_run(this->Loop, UV_RUN_DEFAULT);
+ std::cerr << "HeldTokens: " << this->JSC->GetHeldTokens() << '\n';
+ std::cerr << "NeedTokens: " << this->JSC->GetNeedTokens() << '\n';
+ }
+#ifdef _WIN32
+ // FIXME: Windows job server client not yet implemented.
+ return true;
+#else
+ return this->Okay;
+#endif
+ }
+
+ void QueueNextJobs()
+ {
+ std::cerr << "QueueNextJobs()\n";
+ std::size_t queued = 0;
+ while (queued < 2 && this->NextJobIndex < this->Jobs.size()) {
+ this->QueueJob(this->NextJobIndex);
+ ++this->NextJobIndex;
+ ++queued;
+ }
+ std::cerr << "QueueNextJobs done\n";
+ }
+
+ void StartQueuedJob()
+ {
+ std::cerr << "StartQueuedJob()\n";
+ assert(!this->Queue.empty());
+
+ std::size_t index = this->Queue.front();
+ this->Queue.pop_front();
+ this->StartJob(index);
+
+ std::cerr << "StartQueuedJob done\n";
+ }
+
+ void StartJob(std::size_t index)
+ {
+ cm::uv_timer_ptr& job = this->Jobs[index].Timer;
+ job.init(*this->Loop, this);
+ uv_timer_start(
+ job,
+ [](uv_timer_t* handle) {
+ uv_timer_stop(handle);
+ auto self = static_cast<JobRunner*>(handle->data);
+ self->FinishJob();
+ },
+ /*timeout_ms=*/10 * (1 + (index % 3)), /*repeat_ms=*/0);
+ ++this->ActiveJobs;
+ std::cerr << " StartJob(" << index
+ << "): Active jobs: " << this->ActiveJobs << '\n';
+
+ if (this->ActiveJobs > kTOTAL_TOKENS) {
+ std::cerr << "Started more than " << kTOTAL_TOKENS << " jobs at once!\n";
+ this->Okay = false;
+ return;
+ }
+ }
+
+ void QueueJob(std::size_t index)
+ {
+ this->JSC->RequestToken();
+ this->Queue.push_back(index);
+ std::cerr << " QueueJob(" << index
+ << "): Queue length: " << this->Queue.size() << '\n';
+ }
+
+ void FinishJob()
+ {
+ --this->ActiveJobs;
+ std::cerr << "FinishJob: Active jobs: " << this->ActiveJobs << '\n';
+
+ this->JSC->ReleaseToken();
+ this->QueueNextJobs();
+ }
+};
+
+bool testJobServer()
+{
+#ifdef _WIN32
+ // FIXME: Windows job server client not yet implemented.
+#else
+ // Create a job server pipe.
+ int jobServerPipe[2];
+ if (cmGetPipes(jobServerPipe) < 0) {
+ std::cerr << "Failed to create job server pipe\n";
+ return false;
+ }
+
+ // Write N-1 tokens to the pipe.
+ std::vector<char> jobServerInit(kTOTAL_TOKENS - 1, '.');
+ if (write(jobServerPipe[1], jobServerInit.data(), jobServerInit.size()) !=
+ kTOTAL_TOKENS - 1) {
+ std::cerr << "Failed to initialize job server pipe\n";
+ return false;
+ }
+
+ // Establish the job server client context.
+ // Add a bogus server spec to verify we use the last spec.
+ cmSystemTools::PutEnv(cmStrCat("MAKEFLAGS=--flags-before"
+ " --jobserver-auth=bogus"
+ " --flags-between"
+ " --jobserver-fds=",
+ jobServerPipe[0], ',', jobServerPipe[1],
+ " --flags-after"));
+#endif
+
+ JobRunner jobRunner;
+ return jobRunner.Run();
+}
+}
+
+int testUVJobServerClient(int, char** const)
+{
+ bool passed = true;
+ passed = testJobServer() && passed;
+ return passed ? 0 : -1;
+}