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