From 8cf9505bd27c5dade33b17cc177fa5ef1613dbcd Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 8 Oct 2019 21:48:15 -0700 Subject: [PATCH] Fabric: MountingCoordinator::waitForTransaction(...) Summary: `MountingCoordinator::waitForTransaction()` allows waiting for a new coming transaction synchronously, as efficient as waiting for a mutex. This feature can be used to implement more high-level synchronous rendering APIs. Reviewed By: mdvacca Differential Revision: D17629425 fbshipit-source-id: acd91b941e4d6d43bc4518f332a1604e14506be9 --- .../fabric/mounting/MountingCoordinator.cpp | 33 +++++++++++++------ .../fabric/mounting/MountingCoordinator.h | 15 ++++++++- 2 files changed, 37 insertions(+), 11 deletions(-) diff --git a/ReactCommon/fabric/mounting/MountingCoordinator.cpp b/ReactCommon/fabric/mounting/MountingCoordinator.cpp index 9cb77d049cebb1..7b45c28a31dfb0 100644 --- a/ReactCommon/fabric/mounting/MountingCoordinator.cpp +++ b/ReactCommon/fabric/mounting/MountingCoordinator.cpp @@ -11,6 +11,8 @@ #include #endif +#include + #include #include #include @@ -31,17 +33,21 @@ SurfaceId MountingCoordinator::getSurfaceId() const { } void MountingCoordinator::push(ShadowTreeRevision &&revision) const { - std::lock_guard lock(mutex_); - - assert(revision.getNumber() > baseRevision_.getNumber()); - assert( - !lastRevision_.has_value() || - revision.getNumber() != lastRevision_->getNumber()); - - if (!lastRevision_.has_value() || - lastRevision_->getNumber() < revision.getNumber()) { - lastRevision_ = std::move(revision); + { + std::lock_guard lock(mutex_); + + assert(revision.getNumber() > baseRevision_.getNumber()); + assert( + !lastRevision_.has_value() || + revision.getNumber() != lastRevision_->getNumber()); + + if (!lastRevision_.has_value() || + lastRevision_->getNumber() < revision.getNumber()) { + lastRevision_ = std::move(revision); + } } + + signal_.notify_all(); } void MountingCoordinator::revoke() const { @@ -49,6 +55,13 @@ void MountingCoordinator::revoke() const { lastRevision_.reset(); } +bool MountingCoordinator::waitForTransaction( + std::chrono::duration timeout) const { + std::unique_lock lock(mutex_); + return signal_.wait_for( + lock, timeout, [this]() { return lastRevision_.has_value(); }); +} + better::optional MountingCoordinator::pullTransaction() const { std::lock_guard lock(mutex_); diff --git a/ReactCommon/fabric/mounting/MountingCoordinator.h b/ReactCommon/fabric/mounting/MountingCoordinator.h index 9bbdda13532156..d25dc8590e2989 100644 --- a/ReactCommon/fabric/mounting/MountingCoordinator.h +++ b/ReactCommon/fabric/mounting/MountingCoordinator.h @@ -8,6 +8,7 @@ #pragma once #include +#include #include #include @@ -48,10 +49,21 @@ class MountingCoordinator final { * mount. * The method is thread-safe and can be called from any thread. * However, a consumer should always call it on the same thread (e.g. on the - * main thread) or ensure sequentiality of mount transaction separately. + * main thread) or ensure sequentiality of mount transactions separately. */ better::optional pullTransaction() const; + /* + * Blocks the current thread until a new mounting transaction is available or + * after the specified `timeout` duration. + * Returns `false` if a timeout occurred before a new transaction available. + * Call `pullTransaction` right after the method to retrieve the transaction. + * Similarly to `pullTransaction` this method is thread-safe but the consumer + * should call it on the same thread (e.g. on the main thread) or ensure + * sequentiality of mount transactions separately. + */ + bool waitForTransaction(std::chrono::duration timeout) const; + private: friend class ShadowTree; @@ -76,6 +88,7 @@ class MountingCoordinator final { mutable ShadowTreeRevision baseRevision_; mutable better::optional lastRevision_{}; mutable MountingTransaction::Number number_{0}; + mutable std::condition_variable signal_; #ifdef RN_SHADOW_TREE_INTROSPECTION mutable StubViewTree stubViewTree_; // Protected by `mutex_`.