| /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying |
| file Copyright.txt or https://cmake.org/licensing for details. */ |
| #pragma once |
| |
| #include "cmConfigure.h" // IWYU pragma: keep |
| |
| #include <cstdint> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include <cm/memory> |
| |
| // -- Types |
| class cmWorkerPoolInternal; |
| |
| /** @class cmWorkerPool |
| * @brief Thread pool with job queue |
| */ |
| class cmWorkerPool |
| { |
| public: |
| /** |
| * Return value and output of an external process. |
| */ |
| struct ProcessResultT |
| { |
| void reset(); |
| bool error() const |
| { |
| return (this->ExitStatus != 0) || (this->TermSignal != 0) || |
| !this->ErrorMessage.empty(); |
| } |
| |
| std::int64_t ExitStatus = 0; |
| int TermSignal = 0; |
| std::string StdOut; |
| std::string StdErr; |
| std::string ErrorMessage; |
| }; |
| |
| /** |
| * Abstract job class for concurrent job processing. |
| */ |
| class JobT |
| { |
| public: |
| JobT(JobT const&) = delete; |
| JobT& operator=(JobT const&) = delete; |
| |
| /** |
| * Virtual destructor. |
| */ |
| virtual ~JobT(); |
| |
| /** |
| * Fence job flag |
| * |
| * Fence jobs require that: |
| * - all jobs before in the queue have been processed |
| * - no jobs later in the queue will be processed before this job was |
| * processed |
| */ |
| bool IsFence() const { return this->Fence_; } |
| |
| protected: |
| /** |
| * Protected default constructor |
| */ |
| JobT(bool fence = false) |
| : Fence_(fence) |
| { |
| } |
| |
| /** |
| * Abstract processing interface that must be implement in derived classes. |
| */ |
| virtual void Process() = 0; |
| |
| /** |
| * Get the worker pool. |
| * Only valid during the JobT::Process() call! |
| */ |
| cmWorkerPool* Pool() const { return this->Pool_; } |
| |
| /** |
| * Get the user data. |
| * Only valid during the JobT::Process() call! |
| */ |
| void* UserData() const { return this->Pool_->UserData(); }; |
| |
| /** |
| * Get the worker index. |
| * This is the index of the thread processing this job and is in the range |
| * [0..ThreadCount). |
| * Concurrently processing jobs will never have the same WorkerIndex(). |
| * Only valid during the JobT::Process() call! |
| */ |
| unsigned int WorkerIndex() const { return this->WorkerIndex_; } |
| |
| /** |
| * Run an external read only process. |
| * Use only during JobT::Process() call! |
| */ |
| bool RunProcess(ProcessResultT& result, |
| std::vector<std::string> const& command, |
| std::string const& workingDirectory); |
| |
| private: |
| //! Needs access to Work() |
| friend class cmWorkerPoolInternal; |
| //! Worker thread entry method. |
| void Work(cmWorkerPool* pool, unsigned int workerIndex) |
| { |
| this->Pool_ = pool; |
| this->WorkerIndex_ = workerIndex; |
| this->Process(); |
| } |
| |
| cmWorkerPool* Pool_ = nullptr; |
| unsigned int WorkerIndex_ = 0; |
| bool Fence_ = false; |
| }; |
| |
| /** |
| * Job handle type |
| */ |
| using JobHandleT = std::unique_ptr<JobT>; |
| |
| /** |
| * Fence job base class |
| */ |
| class JobFenceT : public JobT |
| { |
| public: |
| JobFenceT() |
| : JobT(true) |
| { |
| } |
| //! Does nothing |
| void Process() override{}; |
| }; |
| |
| /** |
| * Fence job that aborts the worker pool. |
| * |
| * Useful as the last job in the job queue. |
| */ |
| class JobEndT : JobFenceT |
| { |
| public: |
| //! Does nothing |
| void Process() override { this->Pool()->Abort(); } |
| }; |
| |
| // -- Methods |
| cmWorkerPool(); |
| ~cmWorkerPool(); |
| |
| /** |
| * Number of worker threads. |
| */ |
| unsigned int ThreadCount() const { return this->ThreadCount_; } |
| |
| /** |
| * Set the number of worker threads. |
| * |
| * Calling this method during Process() has no effect. |
| */ |
| void SetThreadCount(unsigned int threadCount); |
| |
| /** |
| * Blocking function that starts threads to process all Jobs in the queue. |
| * |
| * This method blocks until a job calls the Abort() method. |
| * @arg threadCount Number of threads to process jobs. |
| * @arg userData Common user data pointer available in all Jobs. |
| */ |
| bool Process(void* userData = nullptr); |
| |
| /** |
| * User data reference passed to Process(). |
| * |
| * Only valid during Process(). |
| */ |
| void* UserData() const { return this->UserData_; } |
| |
| // -- Job processing interface |
| |
| /** |
| * Clears the job queue and aborts all worker threads. |
| * |
| * This method is thread safe and can be called from inside a job. |
| */ |
| void Abort(); |
| |
| /** |
| * Push job to the queue. |
| * |
| * This method is thread safe and can be called from inside a job or before |
| * Process(). |
| */ |
| bool PushJob(JobHandleT&& jobHandle); |
| |
| /** |
| * Push job to the queue |
| * |
| * This method is thread safe and can be called from inside a job or before |
| * Process(). |
| */ |
| template <class T, typename... Args> |
| bool EmplaceJob(Args&&... args) |
| { |
| return this->PushJob(cm::make_unique<T>(std::forward<Args>(args)...)); |
| } |
| |
| private: |
| void* UserData_ = nullptr; |
| unsigned int ThreadCount_ = 1; |
| std::unique_ptr<cmWorkerPoolInternal> Int_; |
| }; |