Push root node ref down the tree

This commit is contained in:
Adlai Holler
2018-11-07 15:08:01 -08:00
parent 4cfc333d81
commit c98ed5ee16
3 changed files with 49 additions and 8 deletions
+27 -6
View File
@@ -2108,16 +2108,23 @@ ASDISPLAYNODE_INLINE BOOL subtreeIsRasterized(ASDisplayNode *node) {
// NOTE: This method must be dealloc-safe (should not retain self).
- (ASDisplayNode *)supernode
{
#if CHECK_LOCKING_SAFETY
if (__instanceLock__.locked()) {
NSLog(@"WARNING: Accessing supernode while holding recursive instance lock of this node is worrisome. It's likely that you will soon try to acquire the supernode's lock, and this can easily cause deadlocks.");
}
#endif
ASDN::MutexLocker l(__instanceLock__);
return _supernode;
}
- (ASDN::UniqueLock)acquireRootLock __unused {
for (;; std::this_thread::yield()) {
if (!__instanceLock__.try_lock()) {
continue;
}
ASDN::UniqueLock rootLock(_rootNode->__instanceLock__, std::try_to_lock);
if (!rootLock.owns_lock()) {
continue;
}
return rootLock;
}
}
- (void)_setSupernode:(ASDisplayNode *)newSupernode
{
BOOL supernodeDidChange = NO;
@@ -2129,6 +2136,20 @@ ASDISPLAYNODE_INLINE BOOL subtreeIsRasterized(ASDisplayNode *node) {
// in case supernode implementation must access one of our properties.
_supernode = newSupernode;
supernodeDidChange = YES;
unowned ASDisplayNode *newRoot = newSupernode ? newSupernode->_rootNode : self;
if (newRoot != self) {
_rootNode = newRoot;
} else {
_rootNode = nil;
}
// Push new root node ref down while holding self.
// In the future, tree modifications could require the root node to be locked and thus
// we could guarantee a stable view of a tree on-demand.
ASDisplayNodePerformBlockOnEverySubnode(self, NO, ^(ASDisplayNode *node) {
ASDN::MutexLocker l(node->__instanceLock__);
node->_rootNode = newRoot;
});
}
}
+4 -2
View File
@@ -78,7 +78,9 @@ AS_EXTERN NSString * const ASRenderingEngineDidDisplayNodesScheduledBeforeTimest
@interface ASDisplayNode () <_ASTransitionContextCompletionDelegate>
{
@package
@public
// Note: These ivars are declared public only for testing. Don't access them from outside please!
ASDN::RecursiveMutex __instanceLock__;
_ASPendingState *_pendingViewState;
@@ -126,7 +128,7 @@ AS_EXTERN NSString * const ASRenderingEngineDidDisplayNodesScheduledBeforeTimest
unsigned isDeallocating:1;
} _flags;
@protected
unowned ASDisplayNode *_rootNode;
ASDisplayNode * __weak _supernode;
NSMutableArray<ASDisplayNode *> *_subnodes;
+18
View File
@@ -2698,4 +2698,22 @@ static bool stringContainsPointer(NSString *description, id p) {
}
}
- (void)testRootNodePropagation
{
// [A [B [C, D]]
ASDisplayNode *a = [ASDisplayNode new];
XCTAssertNil(a->_rootNode);
ASDisplayNode *b = [ASDisplayNode new];
[a addSubnode:b];
XCTAssertEqual(b->_rootNode, a);
ASDisplayNode *c = [ASDisplayNode new];
[b addSubnode:c];
ASDisplayNode *d = [ASDisplayNode new];
[b addSubnode:d];
XCTAssertEqual(d->_rootNode, a);
[b removeFromSupernode];
XCTAssertNil(b->_rootNode);
XCTAssertEqual(c->_rootNode, b);
}
@end