Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ ShadowNode::ShadowNode(
std::shared_ptr<ShadowNode> ShadowNode::clone(
const ShadowNodeFragment& fragment) const {
const auto& family = *family_;
std::lock_guard<std::recursive_mutex> npGuard(family.nativePropsMutex);
const auto& componentDescriptor = family.componentDescriptor_;
if (family.nativeProps_DEPRECATED != nullptr) {
auto propsParserContext = PropsParserContext{family_->getSurfaceId(), {}};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include <memory>
#include <shared_mutex>
#include <mutex>

#include <react/renderer/core/EventEmitter.h>
#include <react/renderer/core/InstanceHandle.h>
Expand Down Expand Up @@ -118,6 +119,7 @@ class ShadowNodeFamily final : public jsi::NativeState {
* architecture and will be removed in the future.
*/
mutable std::unique_ptr<folly::dynamic> nativeProps_DEPRECATED;
mutable std::recursive_mutex nativePropsMutex;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason this needs to be a recursive mutex instead of a plain one?

Does this need to be ShadowNodeFamily scoped, or would a single global mutex on UIManager be sufficient?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know enough about the internals of react native, so took the safe approach of using a recursive one to prevent deadlocks in the case the critical path ends up trying to acquire the lock again recursively. That said, if that can't happen, it could be replaced with a regular mutex.

As for scoping, I'm not sure (again due to lack of internals knowledge). The main issue this tries to address is concurrent writes / reads to the nativeProps_DEPRECATED field, which is why I added it there, trying to keep the locking exactly to where it's needed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's stick with a normal mutex here - I don't see any way this could be re-entrant.


/**
* @return tag for the ShadowNodeFamily.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ std::shared_ptr<ShadowNode> UIManager::cloneNode(
auto props = ShadowNodeFragment::propsPlaceholder();

if (!rawProps.isEmpty()) {
std::lock_guard<std::recursive_mutex> npGuard(family.nativePropsMutex);
if (family.nativeProps_DEPRECATED != nullptr) {
// 1. update the nativeProps_DEPRECATED props.
//
Expand Down Expand Up @@ -426,6 +427,7 @@ void UIManager::setNativeProps_DEPRECATED(
const std::shared_ptr<const ShadowNode>& shadowNode,
RawProps rawProps) const {
auto& family = shadowNode->getFamily();
family.nativePropsMutex.lock();
if (family.nativeProps_DEPRECATED) {
// Values in `rawProps` patch (take precedence over)
// `nativeProps_DEPRECATED`. For example, if both `nativeProps_DEPRECATED`
Expand All @@ -440,6 +442,7 @@ void UIManager::setNativeProps_DEPRECATED(
family.nativeProps_DEPRECATED =
std::make_unique<folly::dynamic>((folly::dynamic)rawProps);
}
family.nativePropsMutex.unlock();

shadowTreeRegistry_.visit(
family.getSurfaceId(), [&](const ShadowTree& shadowTree) {
Expand Down