xref: /aosp_15_r20/external/swiftshader/third_party/marl/include/marl/thread.h (revision 03ce13f70fcc45d86ee91b7ee4cab1936a95046e)
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==(Core) const;
47     MARL_NO_EXPORT inline bool operator<(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) ||                                                       \
56     (defined(__linux__) && !defined(__ANDROID__) && !defined(__BIONIC__)) || \
57     defined(__FreeBSD__)
58     static constexpr bool supported = true;
59 #else
60     static constexpr bool supported = false;
61 #endif
62 
63     // Policy is an interface that provides a get() method for returning an
64     // Affinity for the given thread by id.
65     class Policy {
66      public:
~PolicyAffinity67       virtual ~Policy() {}
68 
69       // anyOf() returns a Policy that returns an Affinity for a number of
70       // available cores in affinity.
71       //
72       // Windows requires that each thread is only associated with a
73       // single affinity group, so the Policy's returned affinity will contain
74       // cores all from the same group.
75       MARL_EXPORT static std::shared_ptr<Policy> anyOf(
76           Affinity&& affinity,
77           Allocator* allocator = Allocator::Default);
78 
79       // oneOf() returns a Policy that returns an affinity with a single enabled
80       // core from affinity. The single enabled core in the Policy's returned
81       // affinity is:
82       //      affinity[threadId % affinity.count()]
83       MARL_EXPORT static std::shared_ptr<Policy> oneOf(
84           Affinity&& affinity,
85           Allocator* allocator = Allocator::Default);
86 
87       // get() returns the thread Affinity for the given thread by id.
88       MARL_EXPORT virtual Affinity get(uint32_t threadId,
89                                        Allocator* allocator) const = 0;
90     };
91 
92     MARL_EXPORT Affinity(Allocator*);
93 
94     MARL_EXPORT Affinity(Affinity&&);
95 
96     MARL_EXPORT Affinity& operator=(Affinity&&);
97 
98     MARL_EXPORT Affinity(const Affinity&, Allocator* allocator);
99 
100     // all() returns an Affinity with all the cores available to the process.
101     MARL_EXPORT static Affinity all(Allocator* allocator = Allocator::Default);
102 
103     MARL_EXPORT Affinity(std::initializer_list<Core>, Allocator* allocator);
104 
105     MARL_EXPORT Affinity(const containers::vector<Core, 32>&,
106                          Allocator* allocator);
107 
108     // count() returns the number of enabled cores in the affinity.
109     MARL_EXPORT size_t count() const;
110 
111     // operator[] returns the i'th enabled core from this affinity.
112     MARL_EXPORT Core operator[](size_t index) const;
113 
114     // add() adds the cores from the given affinity to this affinity.
115     // This affinity is returned to allow for fluent calls.
116     MARL_EXPORT Affinity& add(const Affinity&);
117 
118     // remove() removes the cores from the given affinity from this affinity.
119     // This affinity is returned to allow for fluent calls.
120     MARL_EXPORT Affinity& remove(const Affinity&);
121 
122    private:
123     Affinity(const Affinity&) = delete;
124 
125     containers::vector<Core, 32> cores;
126   };
127 
128   MARL_EXPORT Thread() = default;
129 
130   MARL_EXPORT Thread(Thread&&);
131 
132   MARL_EXPORT Thread& operator=(Thread&&);
133 
134   // Start a new thread using the given affinity that calls func.
135   MARL_EXPORT Thread(Affinity&& affinity, Func&& func);
136 
137   MARL_EXPORT ~Thread();
138 
139   // join() blocks until the thread completes.
140   MARL_EXPORT void join();
141 
142   // setName() sets the name of the currently executing thread for displaying
143   // in a debugger.
144   MARL_EXPORT static void setName(const char* fmt, ...);
145 
146   // numLogicalCPUs() returns the number of available logical CPU cores for
147   // the system.
148   MARL_EXPORT static unsigned int numLogicalCPUs();
149 
150  private:
151   Thread(const Thread&) = delete;
152   Thread& operator=(const Thread&) = delete;
153 
154   class Impl;
155   Impl* impl = nullptr;
156 };
157 
158 ////////////////////////////////////////////////////////////////////////////////
159 // Thread::Core
160 ////////////////////////////////////////////////////////////////////////////////
161 // Comparison functions
162 bool Thread::Core::operator==(Core other) const {
163   return pthread.index == other.pthread.index;
164 }
165 
166 bool Thread::Core::operator<(Core other) const {
167   return pthread.index < other.pthread.index;
168 }
169 
170 }  // namespace marl
171 
172 #endif  // marl_thread_h
173