| // Copyright 2019 The Marl Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #ifndef marl_thread_h |
| #define marl_thread_h |
| |
| #include "containers.h" |
| #include "export.h" |
| |
| #include <functional> |
| |
| namespace marl { |
| |
| // Thread provides an OS abstraction for threads of execution. |
| class Thread { |
| public: |
| using Func = std::function<void()>; |
| |
| // Core identifies a logical processor unit. |
| // How a core is identified varies by platform. |
| struct Core { |
| struct Windows { |
| uint8_t group; // Group number |
| uint8_t index; // Core within the processor group |
| }; |
| struct Pthread { |
| uint16_t index; // Core number |
| }; |
| union { |
| Windows windows; |
| Pthread pthread; |
| }; |
| |
| // Comparison functions |
| MARL_NO_EXPORT inline bool operator==(const Core&) const; |
| MARL_NO_EXPORT inline bool operator<(const Core&) const; |
| }; |
| |
| // Affinity holds the affinity mask for a thread - a description of what cores |
| // the thread is allowed to run on. |
| struct Affinity { |
| // supported is true if marl supports controlling thread affinity for this |
| // platform. |
| #if defined(_WIN32) || (defined(__linux__) && !defined(__ANDROID__)) || \ |
| defined(__FreeBSD__) |
| static constexpr bool supported = true; |
| #else |
| static constexpr bool supported = false; |
| #endif |
| |
| // Policy is an interface that provides a get() method for returning an |
| // Affinity for the given thread by id. |
| class Policy { |
| public: |
| virtual ~Policy() {} |
| |
| // anyOf() returns a Policy that returns an Affinity for a number of |
| // available cores in affinity. |
| // |
| // Windows requires that each thread is only associated with a |
| // single affinity group, so the Policy's returned affinity will contain |
| // cores all from the same group. |
| MARL_EXPORT static std::shared_ptr<Policy> anyOf( |
| Affinity&& affinity, |
| Allocator* allocator = Allocator::Default); |
| |
| // oneOf() returns a Policy that returns an affinity with a single enabled |
| // core from affinity. The single enabled core in the Policy's returned |
| // affinity is: |
| // affinity[threadId % affinity.count()] |
| MARL_EXPORT static std::shared_ptr<Policy> oneOf( |
| Affinity&& affinity, |
| Allocator* allocator = Allocator::Default); |
| |
| // get() returns the thread Affinity for the for the given thread by id. |
| MARL_EXPORT virtual Affinity get(uint32_t threadId, |
| Allocator* allocator) const = 0; |
| }; |
| |
| MARL_EXPORT Affinity(Allocator*); |
| |
| MARL_EXPORT Affinity(Affinity&&); |
| |
| MARL_EXPORT Affinity(const Affinity&, Allocator* allocator); |
| |
| // all() returns an Affinity with all the cores available to the process. |
| MARL_EXPORT static Affinity all(Allocator* allocator = Allocator::Default); |
| |
| MARL_EXPORT Affinity(std::initializer_list<Core>, Allocator* allocator); |
| |
| // count() returns the number of enabled cores in the affinity. |
| MARL_EXPORT size_t count() const; |
| |
| // operator[] returns the i'th enabled core from this affinity. |
| MARL_EXPORT Core operator[](size_t index) const; |
| |
| // add() adds the cores from the given affinity to this affinity. |
| // This affinity is returned to allow for fluent calls. |
| MARL_EXPORT Affinity& add(const Affinity&); |
| |
| // remove() removes the cores from the given affinity from this affinity. |
| // This affinity is returned to allow for fluent calls. |
| MARL_EXPORT Affinity& remove(const Affinity&); |
| |
| private: |
| Affinity(const Affinity&) = delete; |
| |
| containers::vector<Core, 32> cores; |
| }; |
| |
| MARL_EXPORT Thread() = default; |
| |
| MARL_EXPORT Thread(Thread&&); |
| |
| MARL_EXPORT Thread& operator=(Thread&&); |
| |
| // Start a new thread using the given affinity that calls func. |
| MARL_EXPORT Thread(Affinity&& affinity, Func&& func); |
| |
| MARL_EXPORT ~Thread(); |
| |
| // join() blocks until the thread completes. |
| MARL_EXPORT void join(); |
| |
| // setName() sets the name of the currently executing thread for displaying |
| // in a debugger. |
| MARL_EXPORT static void setName(const char* fmt, ...); |
| |
| // numLogicalCPUs() returns the number of available logical CPU cores for |
| // the system. |
| MARL_EXPORT static unsigned int numLogicalCPUs(); |
| |
| private: |
| Thread(const Thread&) = delete; |
| Thread& operator=(const Thread&) = delete; |
| |
| class Impl; |
| Impl* impl = nullptr; |
| }; |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // Thread::Core |
| //////////////////////////////////////////////////////////////////////////////// |
| // Comparison functions |
| bool Thread::Core::operator==(const Core& other) const { |
| return pthread.index == other.pthread.index; |
| } |
| |
| bool Thread::Core::operator<(const Core& other) const { |
| return pthread.index < other.pthread.index; |
| } |
| |
| } // namespace marl |
| |
| #endif // marl_thread_h |