Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d39f9d46 authored by Leon Scroggins's avatar Leon Scroggins Committed by Automerger Merge Worker
Browse files

Merge "Avoid deadlock in EventThread::onNewVsyncSchedule" into udc-dev am: e6cfeaad

parents b22eaaa6 e6cfeaad
Loading
Loading
Loading
Loading
+41 −14
Original line number Diff line number Diff line
@@ -109,7 +109,6 @@ void Scheduler::startTimers() {
void Scheduler::setPacesetterDisplay(std::optional<PhysicalDisplayId> pacesetterIdOpt) {
    demotePacesetterDisplay();

    std::scoped_lock lock(mDisplayLock);
    promotePacesetterDisplay(pacesetterIdOpt);
}

@@ -123,16 +122,22 @@ void Scheduler::registerDisplayInternal(PhysicalDisplayId displayId,
                                        std::shared_ptr<VsyncSchedule> vsyncSchedule) {
    demotePacesetterDisplay();

    std::shared_ptr<VsyncSchedule> pacesetterVsyncSchedule;
    {
        std::scoped_lock lock(mDisplayLock);
        mRefreshRateSelectors.emplace_or_replace(displayId, std::move(selectorPtr));
        mVsyncSchedules.emplace_or_replace(displayId, std::move(vsyncSchedule));

    promotePacesetterDisplay();
        pacesetterVsyncSchedule = promotePacesetterDisplayLocked();
    }
    applyNewVsyncSchedule(std::move(pacesetterVsyncSchedule));
}

void Scheduler::unregisterDisplay(PhysicalDisplayId displayId) {
    demotePacesetterDisplay();

    std::shared_ptr<VsyncSchedule> pacesetterVsyncSchedule;
    {
        std::scoped_lock lock(mDisplayLock);
        mRefreshRateSelectors.erase(displayId);
        mVsyncSchedules.erase(displayId);
@@ -142,7 +147,9 @@ void Scheduler::unregisterDisplay(PhysicalDisplayId displayId) {
        // headless virtual display.)
        LOG_ALWAYS_FATAL_IF(mRefreshRateSelectors.empty(), "Cannot unregister all displays!");

    promotePacesetterDisplay();
        pacesetterVsyncSchedule = promotePacesetterDisplayLocked();
    }
    applyNewVsyncSchedule(std::move(pacesetterVsyncSchedule));
}

void Scheduler::run() {
@@ -678,6 +685,18 @@ bool Scheduler::updateFrameRateOverrides(GlobalSignals consideredSignals, Fps di
}

void Scheduler::promotePacesetterDisplay(std::optional<PhysicalDisplayId> pacesetterIdOpt) {
    std::shared_ptr<VsyncSchedule> pacesetterVsyncSchedule;

    {
        std::scoped_lock lock(mDisplayLock);
        pacesetterVsyncSchedule = promotePacesetterDisplayLocked(pacesetterIdOpt);
    }

    applyNewVsyncSchedule(std::move(pacesetterVsyncSchedule));
}

std::shared_ptr<VsyncSchedule> Scheduler::promotePacesetterDisplayLocked(
        std::optional<PhysicalDisplayId> pacesetterIdOpt) {
    // TODO(b/241286431): Choose the pacesetter display.
    mPacesetterDisplayId = pacesetterIdOpt.value_or(mRefreshRateSelectors.begin()->first);
    ALOGI("Display %s is the pacesetter", to_string(*mPacesetterDisplayId).c_str());
@@ -697,13 +716,21 @@ void Scheduler::promotePacesetterDisplay(std::optional<PhysicalDisplayId> pacese
        vsyncSchedule->startPeriodTransition(mSchedulerCallback, refreshRate.getPeriod(),
                                             true /* force */);
    }
    return vsyncSchedule;
}

void Scheduler::applyNewVsyncSchedule(std::shared_ptr<VsyncSchedule> vsyncSchedule) {
    onNewVsyncSchedule(vsyncSchedule->getDispatch());
    std::vector<android::EventThread*> threads;
    {
        std::lock_guard<std::mutex> lock(mConnectionsLock);
        threads.reserve(mConnections.size());
        for (auto& [_, connection] : mConnections) {
            connection.thread->onNewVsyncSchedule(vsyncSchedule);
            threads.push_back(connection.thread.get());
        }
    }
    for (auto* thread : threads) {
        thread->onNewVsyncSchedule(vsyncSchedule);
    }
}

+11 −0
Original line number Diff line number Diff line
@@ -321,7 +321,18 @@ private:
    // Chooses a pacesetter among the registered displays, unless `pacesetterIdOpt` is specified.
    // The new `mPacesetterDisplayId` is never `std::nullopt`.
    void promotePacesetterDisplay(std::optional<PhysicalDisplayId> pacesetterIdOpt = std::nullopt)
            REQUIRES(kMainThreadContext) EXCLUDES(mDisplayLock);

    // Changes to the displays (e.g. registering and unregistering) must be made
    // while mDisplayLock is locked, and the new pacesetter then must be promoted while
    // mDisplayLock is still locked. However, a new pacesetter means that
    // MessageQueue and EventThread need to use the new pacesetter's
    // VsyncSchedule, and this must happen while mDisplayLock is *not* locked,
    // or else we may deadlock with EventThread.
    std::shared_ptr<VsyncSchedule> promotePacesetterDisplayLocked(
            std::optional<PhysicalDisplayId> pacesetterIdOpt = std::nullopt)
            REQUIRES(kMainThreadContext, mDisplayLock);
    void applyNewVsyncSchedule(std::shared_ptr<VsyncSchedule>) EXCLUDES(mDisplayLock);

    // Blocks until the pacesetter's idle timer thread exits. `mDisplayLock` must not be locked by
    // the caller on the main thread to avoid deadlock, since the timer thread locks it before exit.