xref: /aosp_15_r20/external/angle/src/tests/test_utils/MultiThreadSteps.h (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1*8975f5c5SAndroid Build Coastguard Worker //
2*8975f5c5SAndroid Build Coastguard Worker // Copyright 2021 The ANGLE Project Authors. All rights reserved.
3*8975f5c5SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
4*8975f5c5SAndroid Build Coastguard Worker // found in the LICENSE file.
5*8975f5c5SAndroid Build Coastguard Worker //
6*8975f5c5SAndroid Build Coastguard Worker // MultiThreadSteps.h:
7*8975f5c5SAndroid Build Coastguard Worker //   Synchronization help for tests that use multiple threads.
8*8975f5c5SAndroid Build Coastguard Worker 
9*8975f5c5SAndroid Build Coastguard Worker #include "gl_raii.h"
10*8975f5c5SAndroid Build Coastguard Worker 
11*8975f5c5SAndroid Build Coastguard Worker #include <atomic>
12*8975f5c5SAndroid Build Coastguard Worker #include <condition_variable>
13*8975f5c5SAndroid Build Coastguard Worker #include <functional>
14*8975f5c5SAndroid Build Coastguard Worker #include <mutex>
15*8975f5c5SAndroid Build Coastguard Worker #include <thread>
16*8975f5c5SAndroid Build Coastguard Worker 
17*8975f5c5SAndroid Build Coastguard Worker class EGLWindow;
18*8975f5c5SAndroid Build Coastguard Worker 
19*8975f5c5SAndroid Build Coastguard Worker namespace angle
20*8975f5c5SAndroid Build Coastguard Worker {
21*8975f5c5SAndroid Build Coastguard Worker namespace
22*8975f5c5SAndroid Build Coastguard Worker {
23*8975f5c5SAndroid Build Coastguard Worker // The following class is used by tests that need multiple threads that coordinate their actions
24*8975f5c5SAndroid Build Coastguard Worker // via an enum of "steps".  This enum is the template type E.  The enum must have at least the
25*8975f5c5SAndroid Build Coastguard Worker // following values:
26*8975f5c5SAndroid Build Coastguard Worker //
27*8975f5c5SAndroid Build Coastguard Worker // - Finish   This value indicates that one thread has finished its last step and is cleaning up.
28*8975f5c5SAndroid Build Coastguard Worker //            The other thread waits for this before it does its last step and cleans up.
29*8975f5c5SAndroid Build Coastguard Worker // - Abort    This value indicates that one thread encountered a GL error and has exited.  This
30*8975f5c5SAndroid Build Coastguard Worker //            will cause the other thread (that is waiting for a different step) to also abort.
31*8975f5c5SAndroid Build Coastguard Worker //
32*8975f5c5SAndroid Build Coastguard Worker // This class is RAII.  It is declared at the top of a thread, and will be deconstructed at the end
33*8975f5c5SAndroid Build Coastguard Worker // of the thread's outer block.  If the thread encounters a GL error, the deconstructor will abort
34*8975f5c5SAndroid Build Coastguard Worker // the other thread using the E:Abort step.
35*8975f5c5SAndroid Build Coastguard Worker template <typename E>
36*8975f5c5SAndroid Build Coastguard Worker class ThreadSynchronization
37*8975f5c5SAndroid Build Coastguard Worker {
38*8975f5c5SAndroid Build Coastguard Worker   public:
ThreadSynchronization(E * currentStep,std::mutex * mutex,std::condition_variable * condVar)39*8975f5c5SAndroid Build Coastguard Worker     ThreadSynchronization(E *currentStep, std::mutex *mutex, std::condition_variable *condVar)
40*8975f5c5SAndroid Build Coastguard Worker         : mCurrentStep(currentStep), mMutex(mutex), mCondVar(condVar)
41*8975f5c5SAndroid Build Coastguard Worker     {}
~ThreadSynchronization()42*8975f5c5SAndroid Build Coastguard Worker     ~ThreadSynchronization()
43*8975f5c5SAndroid Build Coastguard Worker     {
44*8975f5c5SAndroid Build Coastguard Worker         bool isAborting = false;
45*8975f5c5SAndroid Build Coastguard Worker         {
46*8975f5c5SAndroid Build Coastguard Worker             // If the other thread isn't finished, cause it to abort.
47*8975f5c5SAndroid Build Coastguard Worker             std::unique_lock<std::mutex> lock(*mMutex);
48*8975f5c5SAndroid Build Coastguard Worker             isAborting = *mCurrentStep != E::Finish;
49*8975f5c5SAndroid Build Coastguard Worker 
50*8975f5c5SAndroid Build Coastguard Worker             if (isAborting)
51*8975f5c5SAndroid Build Coastguard Worker             {
52*8975f5c5SAndroid Build Coastguard Worker                 *mCurrentStep = E::Abort;
53*8975f5c5SAndroid Build Coastguard Worker             }
54*8975f5c5SAndroid Build Coastguard Worker         }
55*8975f5c5SAndroid Build Coastguard Worker         mCondVar->notify_all();
56*8975f5c5SAndroid Build Coastguard Worker     }
57*8975f5c5SAndroid Build Coastguard Worker 
58*8975f5c5SAndroid Build Coastguard Worker     // Helper functions to synchronize the threads so that the operations are executed in the
59*8975f5c5SAndroid Build Coastguard Worker     // specific order the test is written for.
waitForStep(E waitStep)60*8975f5c5SAndroid Build Coastguard Worker     bool waitForStep(E waitStep)
61*8975f5c5SAndroid Build Coastguard Worker     {
62*8975f5c5SAndroid Build Coastguard Worker         std::unique_lock<std::mutex> lock(*mMutex);
63*8975f5c5SAndroid Build Coastguard Worker         while (*mCurrentStep != waitStep)
64*8975f5c5SAndroid Build Coastguard Worker         {
65*8975f5c5SAndroid Build Coastguard Worker             // If necessary, abort execution as the other thread has encountered a GL error.
66*8975f5c5SAndroid Build Coastguard Worker             if (*mCurrentStep == E::Abort)
67*8975f5c5SAndroid Build Coastguard Worker             {
68*8975f5c5SAndroid Build Coastguard Worker                 return false;
69*8975f5c5SAndroid Build Coastguard Worker             }
70*8975f5c5SAndroid Build Coastguard Worker             // Expect increasing order to reduce risk of race conditions / deadlocks.
71*8975f5c5SAndroid Build Coastguard Worker             if (*mCurrentStep > waitStep)
72*8975f5c5SAndroid Build Coastguard Worker             {
73*8975f5c5SAndroid Build Coastguard Worker                 FATAL() << "waitForStep requires increasing order. mCurrentStep="
74*8975f5c5SAndroid Build Coastguard Worker                         << (int)*mCurrentStep << ", waitStep=" << (int)waitStep;
75*8975f5c5SAndroid Build Coastguard Worker             }
76*8975f5c5SAndroid Build Coastguard Worker             mCondVar->wait(lock);
77*8975f5c5SAndroid Build Coastguard Worker         }
78*8975f5c5SAndroid Build Coastguard Worker 
79*8975f5c5SAndroid Build Coastguard Worker         return true;
80*8975f5c5SAndroid Build Coastguard Worker     }
81*8975f5c5SAndroid Build Coastguard Worker 
nextStep(E newStep)82*8975f5c5SAndroid Build Coastguard Worker     void nextStep(E newStep)
83*8975f5c5SAndroid Build Coastguard Worker     {
84*8975f5c5SAndroid Build Coastguard Worker         {
85*8975f5c5SAndroid Build Coastguard Worker             std::unique_lock<std::mutex> lock(*mMutex);
86*8975f5c5SAndroid Build Coastguard Worker             *mCurrentStep = newStep;
87*8975f5c5SAndroid Build Coastguard Worker         }
88*8975f5c5SAndroid Build Coastguard Worker         mCondVar->notify_all();
89*8975f5c5SAndroid Build Coastguard Worker     }
90*8975f5c5SAndroid Build Coastguard Worker 
91*8975f5c5SAndroid Build Coastguard Worker   private:
92*8975f5c5SAndroid Build Coastguard Worker     E *mCurrentStep;
93*8975f5c5SAndroid Build Coastguard Worker     std::mutex *mMutex;
94*8975f5c5SAndroid Build Coastguard Worker     std::condition_variable *mCondVar;
95*8975f5c5SAndroid Build Coastguard Worker };
96*8975f5c5SAndroid Build Coastguard Worker }  // anonymous namespace
97*8975f5c5SAndroid Build Coastguard Worker 
98*8975f5c5SAndroid Build Coastguard Worker using LockStepThreadFunc = std::function<void(EGLDisplay, EGLSurface, EGLContext)>;
99*8975f5c5SAndroid Build Coastguard Worker void RunLockStepThreads(EGLWindow *window, size_t threadCount, LockStepThreadFunc threadFuncs[]);
100*8975f5c5SAndroid Build Coastguard Worker void RunLockStepThreadsWithSize(EGLWindow *window,
101*8975f5c5SAndroid Build Coastguard Worker                                 EGLint width,
102*8975f5c5SAndroid Build Coastguard Worker                                 EGLint height,
103*8975f5c5SAndroid Build Coastguard Worker                                 size_t threadCount,
104*8975f5c5SAndroid Build Coastguard Worker                                 LockStepThreadFunc threadFuncs[]);
105*8975f5c5SAndroid Build Coastguard Worker }  // namespace angle
106