• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2021 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // EGLMultiContextTest.cpp:
7 //   Synchronization help for tests that use multiple threads.
8 
9 #include <atomic>
10 #include <condition_variable>
11 #include <mutex>
12 #include <thread>
13 
14 namespace
15 {
16 
17 // The following class is used by tests that need multiple threads that coordinate their actions
18 // via an enum of "steps".  This enum is the template type E.  The enum must have at least the
19 // following values:
20 //
21 // - Finish   This value indicates that one thread has finished its last step and is cleaning up.
22 //            The other thread waits for this before it does its last step and cleans up.
23 // - Abort    This value indicates that one thread encountered a GL error and has exited.  This
24 //            will cause the other thread (that is waiting for a different step) to also abort.
25 //
26 // This class is RAII.  It is declared at the top of a thread, and will be deconstructed at the end
27 // of the thread's outer block.  If the thread encounters a GL error, the deconstructor will abort
28 // the other thread using the E:Abort step.
29 template <typename E>
30 class ThreadSynchronization
31 {
32   public:
ThreadSynchronization(E * currentStep,std::mutex * mutex,std::condition_variable * condVar)33     ThreadSynchronization(E *currentStep, std::mutex *mutex, std::condition_variable *condVar)
34         : mCurrentStep(currentStep), mMutex(mutex), mCondVar(condVar)
35     {}
~ThreadSynchronization()36     ~ThreadSynchronization()
37     {
38         bool isAborting = false;
39         {
40             // If the other thread isn't finished, cause it to abort.
41             std::unique_lock<std::mutex> lock(*mMutex);
42             isAborting = *mCurrentStep != E::Finish;
43 
44             if (isAborting)
45             {
46                 *mCurrentStep = E::Abort;
47             }
48         }
49         mCondVar->notify_all();
50     }
51 
52     // Helper functions to synchronize the threads so that the operations are executed in the
53     // specific order the test is written for.
waitForStep(E waitStep)54     bool waitForStep(E waitStep)
55     {
56         std::unique_lock<std::mutex> lock(*mMutex);
57         while (*mCurrentStep != waitStep)
58         {
59             // If necessary, abort execution as the other thread has encountered a GL error.
60             if (*mCurrentStep == E::Abort)
61             {
62                 return false;
63             }
64             mCondVar->wait(lock);
65         }
66 
67         return true;
68     }
69 
nextStep(E newStep)70     void nextStep(E newStep)
71     {
72         {
73             std::unique_lock<std::mutex> lock(*mMutex);
74             *mCurrentStep = newStep;
75         }
76         mCondVar->notify_one();
77     }
78 
79   private:
80     E *mCurrentStep;
81     std::mutex *mMutex;
82     std::condition_variable *mCondVar;
83 };
84 }  // anonymous namespace
85