diff --git a/AsyncDisplayKit/Details/ASThread.h b/AsyncDisplayKit/Details/ASThread.h index c88437d4..73c17163 100644 --- a/AsyncDisplayKit/Details/ASThread.h +++ b/AsyncDisplayKit/Details/ASThread.h @@ -34,6 +34,8 @@ static inline BOOL ASDisplayNodeThreadIsMain() #import #endif +#include + /** For use with ASDN::StaticMutex only. */ @@ -53,7 +55,7 @@ static inline BOOL ASDisplayNodeThreadIsMain() namespace ASDN { - + template class Locker { @@ -98,17 +100,72 @@ namespace ASDN { }; + template + class SharedLocker + { + std::shared_ptr _l; + +#if TIME_LOCKER + CFTimeInterval _ti; + const char *_name; +#endif + + public: +#if !TIME_LOCKER + + SharedLocker (std::shared_ptr const& l) ASDISPLAYNODE_NOTHROW : _l (l) { + assert(_l != nullptr); + _l->lock (); + } + + ~SharedLocker () { + _l->unlock (); + } + + // non-copyable. + SharedLocker(const SharedLocker&) = delete; + SharedLocker &operator=(const SharedLocker&) = delete; + +#else + + SharedLocker (std::shared_ptr const& l, const char *name = NULL) ASDISPLAYNODE_NOTHROW : _l (l), _name(name) { + _ti = CACurrentMediaTime(); + _l->lock (); + } + + ~SharedLocker () { + _l->unlock (); + if (_name) { + printf(_name, NULL); + printf(" dt:%f\n", CACurrentMediaTime() - _ti); + } + } + +#endif + + }; template class Unlocker { T &_l; public: - Unlocker (T &l) ASDISPLAYNODE_NOTHROW : _l (l) {_l.unlock ();} + Unlocker (T &l) ASDISPLAYNODE_NOTHROW : _l (l) { _l.unlock (); } ~Unlocker () {_l.lock ();} Unlocker(Unlocker&) = delete; Unlocker &operator=(Unlocker&) = delete; }; + + template + class SharedUnlocker + { + std::shared_ptr _l; + public: + SharedUnlocker (std::shared_ptr const& l) ASDISPLAYNODE_NOTHROW : _l (l) { _l->unlock (); } + ~SharedUnlocker () { _l->lock (); } + SharedUnlocker(SharedUnlocker&) = delete; + SharedUnlocker &operator=(SharedUnlocker&) = delete; + }; struct Mutex { @@ -164,7 +221,9 @@ namespace ASDN { }; typedef Locker MutexLocker; + typedef SharedLocker MutexSharedLocker; typedef Unlocker MutexUnlocker; + typedef SharedUnlocker MutexSharedUnlocker; /** If you are creating a static mutex, use StaticMutex and specify its default value as one of ASDISPLAYNODE_MUTEX_INITIALIZER diff --git a/AsyncDisplayKit/Private/ASLayoutTransition.mm b/AsyncDisplayKit/Private/ASLayoutTransition.mm index e169b6e1..52af19fa 100644 --- a/AsyncDisplayKit/Private/ASLayoutTransition.mm +++ b/AsyncDisplayKit/Private/ASLayoutTransition.mm @@ -16,6 +16,7 @@ #import "ASLayout.h" #import +#import #import "NSArray+Diffing.h" #import "ASEqualityHelpers.h" @@ -47,7 +48,8 @@ static inline BOOL ASLayoutCanTransitionAsynchronous(ASLayout *layout) { } @implementation ASLayoutTransition { - ASDN::RecursiveMutex __instanceLock__; + std::shared_ptr __instanceLock__; + BOOL _calculatedSubnodeOperations; NSArray *_insertedSubnodes; NSArray *_removedSubnodes; @@ -61,6 +63,8 @@ static inline BOOL ASLayoutCanTransitionAsynchronous(ASLayout *layout) { { self = [super init]; if (self) { + __instanceLock__ = std::make_shared(); + _node = node; _pendingLayout = pendingLayout; _previousLayout = previousLayout; @@ -70,7 +74,7 @@ static inline BOOL ASLayoutCanTransitionAsynchronous(ASLayout *layout) { - (BOOL)isSynchronous { - ASDN::MutexLocker l(__instanceLock__); + ASDN::MutexSharedLocker l(__instanceLock__); return !ASLayoutCanTransitionAsynchronous(_pendingLayout); } @@ -82,7 +86,7 @@ static inline BOOL ASLayoutCanTransitionAsynchronous(ASLayout *layout) { - (void)applySubnodeInsertions { - ASDN::MutexLocker l(__instanceLock__); + ASDN::MutexSharedLocker l(__instanceLock__); [self calculateSubnodeOperationsIfNeeded]; NSUInteger i = 0; @@ -95,7 +99,7 @@ static inline BOOL ASLayoutCanTransitionAsynchronous(ASLayout *layout) { - (void)applySubnodeRemovals { - ASDN::MutexLocker l(__instanceLock__); + ASDN::MutexSharedLocker l(__instanceLock__); [self calculateSubnodeOperationsIfNeeded]; for (ASDisplayNode *subnode in _removedSubnodes) { [subnode removeFromSupernode]; @@ -104,7 +108,7 @@ static inline BOOL ASLayoutCanTransitionAsynchronous(ASLayout *layout) { - (void)calculateSubnodeOperationsIfNeeded { - ASDN::MutexLocker l(__instanceLock__); + ASDN::MutexSharedLocker l(__instanceLock__); if (_calculatedSubnodeOperations) { return; } @@ -134,27 +138,27 @@ static inline BOOL ASLayoutCanTransitionAsynchronous(ASLayout *layout) { - (NSArray *)currentSubnodesWithTransitionContext:(_ASTransitionContext *)context { - ASDN::MutexLocker l(__instanceLock__); + ASDN::MutexSharedLocker l(__instanceLock__); return _node.subnodes; } - (NSArray *)insertedSubnodesWithTransitionContext:(_ASTransitionContext *)context { - ASDN::MutexLocker l(__instanceLock__); + ASDN::MutexSharedLocker l(__instanceLock__); [self calculateSubnodeOperationsIfNeeded]; return _insertedSubnodes; } - (NSArray *)removedSubnodesWithTransitionContext:(_ASTransitionContext *)context { - ASDN::MutexLocker l(__instanceLock__); + ASDN::MutexSharedLocker l(__instanceLock__); [self calculateSubnodeOperationsIfNeeded]; return _removedSubnodes; } - (ASLayout *)transitionContext:(_ASTransitionContext *)context layoutForKey:(NSString *)key { - ASDN::MutexLocker l(__instanceLock__); + ASDN::MutexSharedLocker l(__instanceLock__); if ([key isEqualToString:ASTransitionContextFromLayoutKey]) { return _previousLayout; } else if ([key isEqualToString:ASTransitionContextToLayoutKey]) { @@ -166,7 +170,7 @@ static inline BOOL ASLayoutCanTransitionAsynchronous(ASLayout *layout) { - (ASSizeRange)transitionContext:(_ASTransitionContext *)context constrainedSizeForKey:(NSString *)key { - ASDN::MutexLocker l(__instanceLock__); + ASDN::MutexSharedLocker l(__instanceLock__); if ([key isEqualToString:ASTransitionContextFromLayoutKey]) { return _previousLayout.constrainedSizeRange; } else if ([key isEqualToString:ASTransitionContextToLayoutKey]) { diff --git a/AsyncDisplayKit/TextKit/ASTextKitContext.mm b/AsyncDisplayKit/TextKit/ASTextKitContext.mm index e1f65a01..93958ce2 100755 --- a/AsyncDisplayKit/TextKit/ASTextKitContext.mm +++ b/AsyncDisplayKit/TextKit/ASTextKitContext.mm @@ -10,13 +10,14 @@ #import "ASTextKitContext.h" #import "ASLayoutManager.h" +#import "ASThread.h" -#import +#include @implementation ASTextKitContext { // All TextKit operations (even non-mutative ones) must be executed serially. - std::mutex _textKitMutex; + std::shared_ptr __instanceLock__; NSLayoutManager *_layoutManager; NSTextStorage *_textStorage; @@ -35,8 +36,11 @@ { if (self = [super init]) { // Concurrently initialising TextKit components crashes (rdar://18448377) so we use a global lock. - static std::mutex __static_mutex; - std::lock_guard l(__static_mutex); + static ASDN::Mutex __staticMutex; + ASDN::MutexLocker l(__staticMutex); + + __instanceLock__ = std::make_shared(); + // Create the TextKit component stack with our default configuration. if (textStorageCreationBlock) { _textStorage = textStorageCreationBlock(attributedString); @@ -60,13 +64,13 @@ - (CGSize)constrainedSize { - std::lock_guard l(_textKitMutex); + ASDN::MutexSharedLocker l(__instanceLock__); return _textContainer.size; } - (void)setConstrainedSize:(CGSize)constrainedSize { - std::lock_guard l(_textKitMutex); + ASDN::MutexSharedLocker l(__instanceLock__); _textContainer.size = constrainedSize; } @@ -74,7 +78,7 @@ NSTextStorage *, NSTextContainer *))block { - std::lock_guard l(_textKitMutex); + ASDN::MutexSharedLocker l(__instanceLock__); if (block) { block(_layoutManager, _textStorage, _textContainer); }