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