1 | // Copyright 2019 The Marl Authors. |
2 | // |
3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | // you may not use this file except in compliance with the License. |
5 | // You may obtain a copy of the License at |
6 | // |
7 | // https://www.apache.org/licenses/LICENSE-2.0 |
8 | // |
9 | // Unless required by applicable law or agreed to in writing, software |
10 | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | // See the License for the specific language governing permissions and |
13 | // limitations under the License. |
14 | |
15 | #ifndef marl_thread_h |
16 | #define marl_thread_h |
17 | |
18 | #include "containers.h" |
19 | #include "export.h" |
20 | |
21 | #include <functional> |
22 | |
23 | namespace marl { |
24 | |
25 | // Thread provides an OS abstraction for threads of execution. |
26 | class Thread { |
27 | public: |
28 | using Func = std::function<void()>; |
29 | |
30 | // Core identifies a logical processor unit. |
31 | // How a core is identified varies by platform. |
32 | struct Core { |
33 | struct Windows { |
34 | uint8_t group; // Group number |
35 | uint8_t index; // Core within the processor group |
36 | }; |
37 | struct Pthread { |
38 | uint16_t index; // Core number |
39 | }; |
40 | union { |
41 | Windows windows; |
42 | Pthread pthread; |
43 | }; |
44 | |
45 | // Comparison functions |
46 | MARL_NO_EXPORT inline bool operator==(const Core&) const; |
47 | MARL_NO_EXPORT inline bool operator<(const Core&) const; |
48 | }; |
49 | |
50 | // Affinity holds the affinity mask for a thread - a description of what cores |
51 | // the thread is allowed to run on. |
52 | struct Affinity { |
53 | // supported is true if marl supports controlling thread affinity for this |
54 | // platform. |
55 | #if defined(_WIN32) || (defined(__linux__) && !defined(__ANDROID__)) || \ |
56 | defined(__FreeBSD__) |
57 | static constexpr bool supported = true; |
58 | #else |
59 | static constexpr bool supported = false; |
60 | #endif |
61 | |
62 | // Policy is an interface that provides a get() method for returning an |
63 | // Affinity for the given thread by id. |
64 | class Policy { |
65 | public: |
66 | virtual ~Policy() {} |
67 | |
68 | // anyOf() returns a Policy that returns an Affinity for a number of |
69 | // available cores in affinity. |
70 | // |
71 | // Windows requires that each thread is only associated with a |
72 | // single affinity group, so the Policy's returned affinity will contain |
73 | // cores all from the same group. |
74 | MARL_EXPORT static std::shared_ptr<Policy> anyOf( |
75 | Affinity&& affinity, |
76 | Allocator* allocator = Allocator::Default); |
77 | |
78 | // oneOf() returns a Policy that returns an affinity with a single enabled |
79 | // core from affinity. The single enabled core in the Policy's returned |
80 | // affinity is: |
81 | // affinity[threadId % affinity.count()] |
82 | MARL_EXPORT static std::shared_ptr<Policy> oneOf( |
83 | Affinity&& affinity, |
84 | Allocator* allocator = Allocator::Default); |
85 | |
86 | // get() returns the thread Affinity for the given thread by id. |
87 | MARL_EXPORT virtual Affinity get(uint32_t threadId, |
88 | Allocator* allocator) const = 0; |
89 | }; |
90 | |
91 | MARL_EXPORT Affinity(Allocator*); |
92 | |
93 | MARL_EXPORT Affinity(Affinity&&); |
94 | |
95 | MARL_EXPORT Affinity(const Affinity&, Allocator* allocator); |
96 | |
97 | // all() returns an Affinity with all the cores available to the process. |
98 | MARL_EXPORT static Affinity all(Allocator* allocator = Allocator::Default); |
99 | |
100 | MARL_EXPORT Affinity(std::initializer_list<Core>, Allocator* allocator); |
101 | |
102 | MARL_EXPORT Affinity(const containers::vector<Core, 32>&, |
103 | Allocator* allocator); |
104 | |
105 | // count() returns the number of enabled cores in the affinity. |
106 | MARL_EXPORT size_t count() const; |
107 | |
108 | // operator[] returns the i'th enabled core from this affinity. |
109 | MARL_EXPORT Core operator[](size_t index) const; |
110 | |
111 | // add() adds the cores from the given affinity to this affinity. |
112 | // This affinity is returned to allow for fluent calls. |
113 | MARL_EXPORT Affinity& add(const Affinity&); |
114 | |
115 | // remove() removes the cores from the given affinity from this affinity. |
116 | // This affinity is returned to allow for fluent calls. |
117 | MARL_EXPORT Affinity& remove(const Affinity&); |
118 | |
119 | private: |
120 | Affinity(const Affinity&) = delete; |
121 | |
122 | containers::vector<Core, 32> cores; |
123 | }; |
124 | |
125 | MARL_EXPORT Thread() = default; |
126 | |
127 | MARL_EXPORT Thread(Thread&&); |
128 | |
129 | MARL_EXPORT Thread& operator=(Thread&&); |
130 | |
131 | // Start a new thread using the given affinity that calls func. |
132 | MARL_EXPORT Thread(Affinity&& affinity, Func&& func); |
133 | |
134 | MARL_EXPORT ~Thread(); |
135 | |
136 | // join() blocks until the thread completes. |
137 | MARL_EXPORT void join(); |
138 | |
139 | // setName() sets the name of the currently executing thread for displaying |
140 | // in a debugger. |
141 | MARL_EXPORT static void setName(const char* fmt, ...); |
142 | |
143 | // numLogicalCPUs() returns the number of available logical CPU cores for |
144 | // the system. |
145 | MARL_EXPORT static unsigned int numLogicalCPUs(); |
146 | |
147 | private: |
148 | Thread(const Thread&) = delete; |
149 | Thread& operator=(const Thread&) = delete; |
150 | |
151 | class Impl; |
152 | Impl* impl = nullptr; |
153 | }; |
154 | |
155 | //////////////////////////////////////////////////////////////////////////////// |
156 | // Thread::Core |
157 | //////////////////////////////////////////////////////////////////////////////// |
158 | // Comparison functions |
159 | bool Thread::Core::operator==(const Core& other) const { |
160 | return pthread.index == other.pthread.index; |
161 | } |
162 | |
163 | bool Thread::Core::operator<(const Core& other) const { |
164 | return pthread.index < other.pthread.index; |
165 | } |
166 | |
167 | } // namespace marl |
168 | |
169 | #endif // marl_thread_h |
170 | |