xref: /aosp_15_r20/external/deqp/framework/common/tcuThreadUtil.hpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 #ifndef _TCUTHREADUTIL_HPP
2 #define _TCUTHREADUTIL_HPP
3 /*-------------------------------------------------------------------------
4  * drawElements Quality Program Tester Core
5  * ----------------------------------------
6  *
7  * Copyright 2014 The Android Open Source Project
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  *//*!
22  * \file
23  * \brief Thread test utilities
24  *//*--------------------------------------------------------------------*/
25 
26 #include "tcuDefs.hpp"
27 #include "deSharedPtr.hpp"
28 #include "deMutex.hpp"
29 #include "deSemaphore.hpp"
30 #include "deThread.hpp"
31 #include "deRandom.hpp"
32 
33 #include <vector>
34 #include <sstream>
35 
36 namespace tcu
37 {
38 namespace ThreadUtil
39 {
40 // Event object for synchronizing threads
41 class Event
42 {
43 public:
44     enum Result
45     {
46         RESULT_NOT_READY = 0,
47         RESULT_OK,
48         RESULT_FAILED
49     };
50 
51     Event(void);
52     ~Event(void);
53     void setResult(Result result);
54     Result waitReady(void);
getResult(void) const55     Result getResult(void) const
56     {
57         return m_result;
58     }
59 
60 private:
61     volatile Result m_result;
62     volatile int m_waiterCount;
63     de::Semaphore m_waiters;
64     de::Mutex m_lock;
65 
66     // Disabled
67     Event(const Event &);
68     Event &operator=(const Event &);
69 };
70 
71 // Base class for objects which modifications should be tracked between threads
72 class Object
73 {
74 public:
75     Object(const char *type, de::SharedPtr<Event> createEvent);
76     virtual ~Object(void);
getType(void) const77     const char *getType(void) const
78     {
79         return m_type;
80     }
81 
82     // Used by class Operation only
83     void read(de::SharedPtr<Event> event, std::vector<de::SharedPtr<Event>> &deps);
84     void modify(de::SharedPtr<Event> event, std::vector<de::SharedPtr<Event>> &deps);
85 
86 private:
87     const char *m_type;
88     de::SharedPtr<Event> m_modify;
89     std::vector<de::SharedPtr<Event>> m_reads;
90 
91     // Disabled
92     Object(const Object &);
93     Object &operator=(const Object &);
94 };
95 
96 class Thread;
97 
98 class MessageBuilder
99 {
100 public:
MessageBuilder(Thread & thread)101     MessageBuilder(Thread &thread) : m_thread(thread)
102     {
103     }
MessageBuilder(const MessageBuilder & other)104     MessageBuilder(const MessageBuilder &other) : m_thread(other.m_thread), m_stream(other.m_stream.str())
105     {
106     }
107     template <class T>
operator <<(const T & t)108     MessageBuilder &operator<<(const T &t)
109     {
110         m_stream << t;
111         return *this;
112     }
113 
114     class EndToken
115     {
116     public:
EndToken(void)117         EndToken(void)
118         {
119         }
120     };
121 
122     void operator<<(const EndToken &);
123 
124 private:
125     Thread &m_thread;
126     std::stringstream m_stream;
127 };
128 
129 class Message
130 {
131 public:
Message(uint64_t time,const char * message)132     Message(uint64_t time, const char *message) : m_time(time), m_message(message)
133     {
134     }
135 
getTime(void) const136     uint64_t getTime(void) const
137     {
138         return m_time;
139     }
getMessage(void) const140     const std::string &getMessage(void) const
141     {
142         return m_message;
143     }
144 
145     static const MessageBuilder::EndToken End;
146 
147 private:
148     uint64_t m_time;
149     std::string m_message;
150 };
151 
152 // Base class for operations executed by threads
153 class Operation
154 {
155 public:
156     Operation(const char *name);
157     virtual ~Operation(void);
158 
getName(void) const159     const char *getName(void) const
160     {
161         return m_name;
162     }
getEvent(void)163     de::SharedPtr<Event> getEvent(void)
164     {
165         return m_event;
166     }
167 
readObject(de::SharedPtr<Object> object)168     void readObject(de::SharedPtr<Object> object)
169     {
170         object->read(m_event, m_deps);
171     }
modifyObject(de::SharedPtr<Object> object)172     void modifyObject(de::SharedPtr<Object> object)
173     {
174         object->modify(m_event, m_deps);
175     }
176 
177     virtual void exec(Thread &thread) = 0; //!< Overwritten by inherited class to perform actual operation
178     virtual void execute(
179         Thread &thread); //!< May Be overwritten by inherited class to change how syncronization is done
180 
181 protected:
182     const char *m_name;
183     std::vector<de::SharedPtr<Event>> m_deps;
184     de::SharedPtr<Event> m_event;
185 
186     Operation(const Operation &);
187     Operation &operator=(const Operation &);
188 };
189 
190 class Thread : public de::Thread
191 {
192 public:
193     enum ThreadStatus
194     {
195         THREADSTATUS_NOT_STARTED = 0,
196         THREADSTATUS_INIT_FAILED,
197         THREADSTATUS_RUNNING,
198         THREADSTATUS_READY,
199         THREADSTATUS_FAILED,
200         THREADSTATUS_NOT_SUPPORTED
201     };
202     Thread(uint32_t seed);
203     ~Thread(void);
204 
init(void)205     virtual void init(void)
206     {
207     } //!< Called first before any Operation
208 
209     // \todo [mika] Should the result of execution be passed to deinit?
deinit(void)210     virtual void deinit(void)
211     {
212     } //!< Called after after operation
213 
214     void addOperation(Operation *operation);
215 
216     void exec(void);
217 
218     uint8_t *getUnusedData(
219         size_t size); //!< Return data pointer that contains at least size bytes. Valid until next call
220 
getStatus(void) const221     ThreadStatus getStatus(void) const
222     {
223         de::ScopedLock lock(m_statusLock);
224         return m_status;
225     }
setStatus(ThreadStatus status)226     void setStatus(ThreadStatus status)
227     {
228         de::ScopedLock lock(m_statusLock);
229         m_status = status;
230     }
231 
newMessage(void)232     MessageBuilder newMessage(void)
233     {
234         return MessageBuilder(*this);
235     }
getRandom(void)236     de::Random &getRandom(void)
237     {
238         return m_random;
239     }
240 
241     // Used to by test case to read log messages
242     int getMessageCount(void) const;
243     Message getMessage(int index) const;
244 
245     // Used by message builder
246     void pushMessage(const std::string &str);
247 
248 private:
249     virtual void run(void);
250 
251     std::vector<Operation *> m_operations;
252     de::Random m_random;
253 
254     mutable de::Mutex m_messageLock;
255     std::vector<Message> m_messages;
256     mutable de::Mutex m_statusLock;
257     ThreadStatus m_status;
258     std::vector<uint8_t> m_unusedData;
259 
260     // Disabled
261     Thread(const Thread &);
262     Thread operator=(const Thread &);
263 };
264 
265 class DataBlock : public Object
266 {
267 public:
268     DataBlock(de::SharedPtr<Event> event);
269 
270     void setData(size_t size, const void *data);
getData(void) const271     const uint8_t *getData(void) const
272     {
273         return &(m_data[0]);
274     }
getSize(void) const275     size_t getSize(void) const
276     {
277         return m_data.size();
278     }
279 
280 private:
281     std::vector<uint8_t> m_data;
282 };
283 
284 class CompareData : public Operation
285 {
286 public:
287     CompareData(de::SharedPtr<DataBlock> a, de::SharedPtr<DataBlock> b);
288     void exec(Thread &thread);
289 
290 private:
291     de::SharedPtr<DataBlock> m_a;
292     de::SharedPtr<DataBlock> m_b;
293 };
294 
295 } // namespace ThreadUtil
296 } // namespace tcu
297 
298 #endif // _TCUTHREADUTIL_HPP
299