Skip to content

Commit

Permalink
Lazily create static mutexes
Browse files Browse the repository at this point in the history
  • Loading branch information
nguyenhuy committed Nov 26, 2018
1 parent be36e4b commit a62ac2e
Show file tree
Hide file tree
Showing 5 changed files with 30 additions and 40 deletions.
12 changes: 8 additions & 4 deletions Source/ASImageNode.mm
Original file line number Diff line number Diff line change
Expand Up @@ -433,13 +433,17 @@ + (UIImage *)displayWithParameters:(id<NSObject>)parameter isCancelled:(NS_NOESC
}

static ASWeakMap<ASImageNodeContentsKey *, UIImage *> *cache = nil;
// Allocate cacheLock on the heap to prevent destruction at app exit (https://github.com/TextureGroup/Texture/issues/136)
static auto *cacheLock = new ASDN::StaticMutex;

+ (ASWeakMapEntry *)contentsForkey:(ASImageNodeContentsKey *)key drawParameters:(id)drawParameters isCancelled:(asdisplaynode_iscancelled_block_t)isCancelled
{
static dispatch_once_t onceToken;
static ASDN::Mutex *cacheLock = nil;
dispatch_once(&onceToken, ^{
cacheLock = new ASDN::Mutex();
});

{
ASDN::StaticMutexLocker l(*cacheLock);
ASDN::MutexLocker l(*cacheLock);
if (!cache) {
cache = [[ASWeakMap alloc] init];
}
Expand All @@ -456,7 +460,7 @@ + (ASWeakMapEntry *)contentsForkey:(ASImageNodeContentsKey *)key drawParameters:
}

{
ASDN::StaticMutexLocker l(*cacheLock);
ASDN::MutexLocker l(*cacheLock);
return [cache setObject:contents forKey:key];
}
}
Expand Down
6 changes: 3 additions & 3 deletions Source/ASTextNode2.mm
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,11 @@ @implementation ASTextCacheValue
* NOTE: Be careful to copy `text` if needed.
*/
static NS_RETURNS_RETAINED ASTextLayout *ASTextNodeCompatibleLayoutWithContainerAndText(ASTextContainer *container, NSAttributedString *text) {
// Allocate layoutCacheLock on the heap to prevent destruction at app exit (https://github.com/TextureGroup/Texture/issues/136)
static auto *layoutCacheLock = new ASDN::StaticMutex;
static NSCache<NSAttributedString *, ASTextCacheValue *> *textLayoutCache;
static dispatch_once_t onceToken;
static ASDN::Mutex *layoutCacheLock;
static NSCache<NSAttributedString *, ASTextCacheValue *> *textLayoutCache;
dispatch_once(&onceToken, ^{
layoutCacheLock = new ASDN::Mutex();
textLayoutCache = [[NSCache alloc] init];
});

Expand Down
16 changes: 12 additions & 4 deletions Source/Details/ASBasicImageDownloader.mm
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,20 @@ @interface ASBasicImageDownloaderContext ()
@implementation ASBasicImageDownloaderContext

static NSMutableDictionary *currentRequests = nil;
// Allocate currentRequestsLock on the heap to prevent destruction at app exit (https://github.com/TextureGroup/Texture/issues/136)
static auto *currentRequestsLock = new ASDN::StaticMutex;

+ (ASDN::Mutex *)currentRequestLock
{
static dispatch_once_t onceToken;
static ASDN::Mutex *currentRequestsLock;
dispatch_once(&onceToken, ^{
currentRequestsLock = new ASDN::Mutex();
});
return currentRequestsLock;
}

+ (ASBasicImageDownloaderContext *)contextForURL:(NSURL *)URL
{
ASDN::StaticMutexLocker l(*currentRequestsLock);
ASDN::MutexLocker l(*self.currentRequestLock);
if (!currentRequests) {
currentRequests = [[NSMutableDictionary alloc] init];
}
Expand All @@ -57,7 +65,7 @@ + (ASBasicImageDownloaderContext *)contextForURL:(NSURL *)URL

+ (void)cancelContextWithURL:(NSURL *)URL
{
ASDN::StaticMutexLocker l(*currentRequestsLock);
ASDN::MutexLocker l(*self.currentRequestLock);
if (currentRequests) {
[currentRequests removeObjectForKey:URL];
}
Expand Down
26 changes: 0 additions & 26 deletions Source/Details/ASThread.h
Original file line number Diff line number Diff line change
Expand Up @@ -287,34 +287,8 @@ namespace ASDN {
RecursiveMutex () : Mutex (true) {}
};

/**
If you are creating a static mutex, use StaticMutex. This avoids expensive constructor overhead at startup (or worse, ordering
issues between different static objects). It also avoids running a destructor on app exit time (needless expense).
Note that you can, but should not, use StaticMutex for non-static objects. It will leak its mutex on destruction,
so avoid that!
TODO: Remove StaticMutex and use Mutex everywhere once the unfair lock experiment is shipped
*/
struct StaticMutex
{
StaticMutex () : _m (PTHREAD_MUTEX_INITIALIZER) {}
// non-copyable.
StaticMutex(const StaticMutex&) = delete;
StaticMutex &operator=(const StaticMutex&) = delete;
void lock () {
pthread_mutex_lock (this->mutex());
}
void unlock () {
pthread_mutex_unlock (this->mutex());
}
pthread_mutex_t *mutex () { return &_m; }
private:
pthread_mutex_t _m;
};

typedef std::lock_guard<Mutex> MutexLocker;
typedef std::unique_lock<Mutex> UniqueLock;
typedef std::lock_guard<StaticMutex> StaticMutexLocker;

} // namespace ASDN

Expand Down
10 changes: 7 additions & 3 deletions Source/TextKit/ASTextKitContext.mm
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,14 @@ - (instancetype)initWithAttributedString:(NSAttributedString *)attributedString

{
if (self = [super init]) {
static dispatch_once_t onceToken;
static ASDN::Mutex *mutex;
dispatch_once(&onceToken, ^{
mutex = new ASDN::Mutex();
});

// Concurrently initialising TextKit components crashes (rdar://18448377) so we use a global lock.
// Allocate mutex on the heap to prevent destruction at app exit (https://github.com/TextureGroup/Texture/issues/136)
static auto *mutex = new ASDN::StaticMutex;
ASDN::StaticMutexLocker l(*mutex);
ASDN::MutexLocker l(*mutex);

__instanceLock__ = std::make_shared<ASDN::Mutex>();

Expand Down

0 comments on commit a62ac2e

Please sign in to comment.