Skip to content
This repository was archived by the owner on Feb 2, 2023. It is now read-only.

Commit 0e32802

Browse files
maickigarrettmoon
authored andcommitted
[ASThread] Add SharedLocker and SharedUnlocker that uses a shared pointer for the mutex (#2047)
* Add SharedLocker and SharedUnlocker that uses a shared pointer for the mutex * Move ASTextKitContext to use Shared Locker
1 parent 824c934 commit 0e32802

File tree

3 files changed

+86
-19
lines changed

3 files changed

+86
-19
lines changed

AsyncDisplayKit/Details/ASThread.h

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ static inline BOOL ASDisplayNodeThreadIsMain()
3434
#import <QuartzCore/QuartzCore.h>
3535
#endif
3636

37+
#include <memory>
38+
3739
/**
3840
For use with ASDN::StaticMutex only.
3941
*/
@@ -53,7 +55,7 @@ static inline BOOL ASDisplayNodeThreadIsMain()
5355

5456

5557
namespace ASDN {
56-
58+
5759
template<class T>
5860
class Locker
5961
{
@@ -98,17 +100,72 @@ namespace ASDN {
98100

99101
};
100102

103+
template<class T>
104+
class SharedLocker
105+
{
106+
std::shared_ptr<T> _l;
107+
108+
#if TIME_LOCKER
109+
CFTimeInterval _ti;
110+
const char *_name;
111+
#endif
112+
113+
public:
114+
#if !TIME_LOCKER
115+
116+
SharedLocker (std::shared_ptr<T> const& l) ASDISPLAYNODE_NOTHROW : _l (l) {
117+
assert(_l != nullptr);
118+
_l->lock ();
119+
}
120+
121+
~SharedLocker () {
122+
_l->unlock ();
123+
}
124+
125+
// non-copyable.
126+
SharedLocker(const SharedLocker<T>&) = delete;
127+
SharedLocker &operator=(const SharedLocker<T>&) = delete;
128+
129+
#else
130+
131+
SharedLocker (std::shared_ptr<T> const& l, const char *name = NULL) ASDISPLAYNODE_NOTHROW : _l (l), _name(name) {
132+
_ti = CACurrentMediaTime();
133+
_l->lock ();
134+
}
135+
136+
~SharedLocker () {
137+
_l->unlock ();
138+
if (_name) {
139+
printf(_name, NULL);
140+
printf(" dt:%f\n", CACurrentMediaTime() - _ti);
141+
}
142+
}
143+
144+
#endif
145+
146+
};
101147

102148
template<class T>
103149
class Unlocker
104150
{
105151
T &_l;
106152
public:
107-
Unlocker (T &l) ASDISPLAYNODE_NOTHROW : _l (l) {_l.unlock ();}
153+
Unlocker (T &l) ASDISPLAYNODE_NOTHROW : _l (l) { _l.unlock (); }
108154
~Unlocker () {_l.lock ();}
109155
Unlocker(Unlocker<T>&) = delete;
110156
Unlocker &operator=(Unlocker<T>&) = delete;
111157
};
158+
159+
template<class T>
160+
class SharedUnlocker
161+
{
162+
std::shared_ptr<T> _l;
163+
public:
164+
SharedUnlocker (std::shared_ptr<T> const& l) ASDISPLAYNODE_NOTHROW : _l (l) { _l->unlock (); }
165+
~SharedUnlocker () { _l->lock (); }
166+
SharedUnlocker(SharedUnlocker<T>&) = delete;
167+
SharedUnlocker &operator=(SharedUnlocker<T>&) = delete;
168+
};
112169

113170
struct Mutex
114171
{
@@ -164,7 +221,9 @@ namespace ASDN {
164221
};
165222

166223
typedef Locker<Mutex> MutexLocker;
224+
typedef SharedLocker<Mutex> MutexSharedLocker;
167225
typedef Unlocker<Mutex> MutexUnlocker;
226+
typedef SharedUnlocker<Mutex> MutexSharedUnlocker;
168227

169228
/**
170229
If you are creating a static mutex, use StaticMutex and specify its default value as one of ASDISPLAYNODE_MUTEX_INITIALIZER

AsyncDisplayKit/Private/ASLayoutTransition.mm

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#import "ASLayout.h"
1717

1818
#import <queue>
19+
#import <memory>
1920

2021
#import "NSArray+Diffing.h"
2122
#import "ASEqualityHelpers.h"
@@ -47,7 +48,8 @@ static inline BOOL ASLayoutCanTransitionAsynchronous(ASLayout *layout) {
4748
}
4849

4950
@implementation ASLayoutTransition {
50-
ASDN::RecursiveMutex __instanceLock__;
51+
std::shared_ptr<ASDN::RecursiveMutex> __instanceLock__;
52+
5153
BOOL _calculatedSubnodeOperations;
5254
NSArray<ASDisplayNode *> *_insertedSubnodes;
5355
NSArray<ASDisplayNode *> *_removedSubnodes;
@@ -61,6 +63,8 @@ - (instancetype)initWithNode:(ASDisplayNode *)node
6163
{
6264
self = [super init];
6365
if (self) {
66+
__instanceLock__ = std::make_shared<ASDN::RecursiveMutex>();
67+
6468
_node = node;
6569
_pendingLayout = pendingLayout;
6670
_previousLayout = previousLayout;
@@ -70,7 +74,7 @@ - (instancetype)initWithNode:(ASDisplayNode *)node
7074

7175
- (BOOL)isSynchronous
7276
{
73-
ASDN::MutexLocker l(__instanceLock__);
77+
ASDN::MutexSharedLocker l(__instanceLock__);
7478
return ASLayoutCanTransitionAsynchronous(_pendingLayout);
7579
}
7680

@@ -82,7 +86,7 @@ - (void)startTransition
8286

8387
- (void)applySubnodeInsertions
8488
{
85-
ASDN::MutexLocker l(__instanceLock__);
89+
ASDN::MutexSharedLocker l(__instanceLock__);
8690
[self calculateSubnodeOperationsIfNeeded];
8791

8892
NSUInteger i = 0;
@@ -95,7 +99,7 @@ - (void)applySubnodeInsertions
9599

96100
- (void)applySubnodeRemovals
97101
{
98-
ASDN::MutexLocker l(__instanceLock__);
102+
ASDN::MutexSharedLocker l(__instanceLock__);
99103
[self calculateSubnodeOperationsIfNeeded];
100104
for (ASDisplayNode *subnode in _removedSubnodes) {
101105
[subnode removeFromSupernode];
@@ -104,7 +108,7 @@ - (void)applySubnodeRemovals
104108

105109
- (void)calculateSubnodeOperationsIfNeeded
106110
{
107-
ASDN::MutexLocker l(__instanceLock__);
111+
ASDN::MutexSharedLocker l(__instanceLock__);
108112
if (_calculatedSubnodeOperations) {
109113
return;
110114
}
@@ -134,27 +138,27 @@ - (void)calculateSubnodeOperationsIfNeeded
134138

135139
- (NSArray<ASDisplayNode *> *)currentSubnodesWithTransitionContext:(_ASTransitionContext *)context
136140
{
137-
ASDN::MutexLocker l(__instanceLock__);
141+
ASDN::MutexSharedLocker l(__instanceLock__);
138142
return _node.subnodes;
139143
}
140144

141145
- (NSArray<ASDisplayNode *> *)insertedSubnodesWithTransitionContext:(_ASTransitionContext *)context
142146
{
143-
ASDN::MutexLocker l(__instanceLock__);
147+
ASDN::MutexSharedLocker l(__instanceLock__);
144148
[self calculateSubnodeOperationsIfNeeded];
145149
return _insertedSubnodes;
146150
}
147151

148152
- (NSArray<ASDisplayNode *> *)removedSubnodesWithTransitionContext:(_ASTransitionContext *)context
149153
{
150-
ASDN::MutexLocker l(__instanceLock__);
154+
ASDN::MutexSharedLocker l(__instanceLock__);
151155
[self calculateSubnodeOperationsIfNeeded];
152156
return _removedSubnodes;
153157
}
154158

155159
- (ASLayout *)transitionContext:(_ASTransitionContext *)context layoutForKey:(NSString *)key
156160
{
157-
ASDN::MutexLocker l(__instanceLock__);
161+
ASDN::MutexSharedLocker l(__instanceLock__);
158162
if ([key isEqualToString:ASTransitionContextFromLayoutKey]) {
159163
return _previousLayout;
160164
} else if ([key isEqualToString:ASTransitionContextToLayoutKey]) {
@@ -166,7 +170,7 @@ - (ASLayout *)transitionContext:(_ASTransitionContext *)context layoutForKey:(NS
166170

167171
- (ASSizeRange)transitionContext:(_ASTransitionContext *)context constrainedSizeForKey:(NSString *)key
168172
{
169-
ASDN::MutexLocker l(__instanceLock__);
173+
ASDN::MutexSharedLocker l(__instanceLock__);
170174
if ([key isEqualToString:ASTransitionContextFromLayoutKey]) {
171175
return _previousLayout.constrainedSizeRange;
172176
} else if ([key isEqualToString:ASTransitionContextToLayoutKey]) {

AsyncDisplayKit/TextKit/ASTextKitContext.mm

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,14 @@
1010

1111
#import "ASTextKitContext.h"
1212
#import "ASLayoutManager.h"
13+
#import "ASThread.h"
1314

14-
#import <mutex>
15+
#include <memory>
1516

1617
@implementation ASTextKitContext
1718
{
1819
// All TextKit operations (even non-mutative ones) must be executed serially.
19-
std::mutex _textKitMutex;
20+
std::shared_ptr<ASDN::Mutex> __instanceLock__;
2021

2122
NSLayoutManager *_layoutManager;
2223
NSTextStorage *_textStorage;
@@ -35,8 +36,11 @@ - (instancetype)initWithAttributedString:(NSAttributedString *)attributedString
3536
{
3637
if (self = [super init]) {
3738
// Concurrently initialising TextKit components crashes (rdar://18448377) so we use a global lock.
38-
static std::mutex __static_mutex;
39-
std::lock_guard<std::mutex> l(__static_mutex);
39+
static ASDN::Mutex __staticMutex;
40+
ASDN::MutexLocker l(__staticMutex);
41+
42+
__instanceLock__ = std::make_shared<ASDN::Mutex>();
43+
4044
// Create the TextKit component stack with our default configuration.
4145
if (textStorageCreationBlock) {
4246
_textStorage = textStorageCreationBlock(attributedString);
@@ -60,21 +64,21 @@ - (instancetype)initWithAttributedString:(NSAttributedString *)attributedString
6064

6165
- (CGSize)constrainedSize
6266
{
63-
std::lock_guard<std::mutex> l(_textKitMutex);
67+
ASDN::MutexSharedLocker l(__instanceLock__);
6468
return _textContainer.size;
6569
}
6670

6771
- (void)setConstrainedSize:(CGSize)constrainedSize
6872
{
69-
std::lock_guard<std::mutex> l(_textKitMutex);
73+
ASDN::MutexSharedLocker l(__instanceLock__);
7074
_textContainer.size = constrainedSize;
7175
}
7276

7377
- (void)performBlockWithLockedTextKitComponents:(void (^)(NSLayoutManager *,
7478
NSTextStorage *,
7579
NSTextContainer *))block
7680
{
77-
std::lock_guard<std::mutex> l(_textKitMutex);
81+
ASDN::MutexSharedLocker l(__instanceLock__);
7882
if (block) {
7983
block(_layoutManager, _textStorage, _textContainer);
8084
}

0 commit comments

Comments
 (0)