Merge pull request #3128 from dreampiggy/feature_replace_semaphore_with_os_unfair_lock_and_spinlock

Replace all current dispatch_semaphore usage into the os_unfair_lock, use OSSpinLock for lower firmware
This commit is contained in:
DreamPiggy 2020-11-20 15:28:43 +08:00 committed by GitHub
commit af96d0b825
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 148 additions and 123 deletions

View File

@ -13,6 +13,7 @@
#import "SDInternalMacros.h"
@interface SDAnimatedImagePlayer () {
SD_LOCK_DECLARE(_lock);
NSRunLoopMode _runLoopMode;
}
@ -26,7 +27,6 @@
@property (nonatomic, assign) BOOL needsDisplayWhenImageBecomesAvailable;
@property (nonatomic, assign) NSUInteger maxBufferCount;
@property (nonatomic, strong) NSOperationQueue *fetchQueue;
@property (nonatomic, strong) dispatch_semaphore_t lock;
@property (nonatomic, strong) SDDisplayLink *displayLink;
@end
@ -46,6 +46,7 @@
self.totalLoopCount = provider.animatedImageLoopCount;
self.animatedProvider = provider;
self.playbackRate = 1.0;
SD_LOCK_INIT(_lock);
#if SD_UIKIT
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveMemoryWarning:) name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
#endif
@ -70,7 +71,7 @@
[_fetchQueue cancelAllOperations];
[_fetchQueue addOperationWithBlock:^{
NSNumber *currentFrameIndex = @(self.currentFrameIndex);
SD_LOCK(self.lock);
SD_LOCK(self->_lock);
NSArray *keys = self.frameBuffer.allKeys;
// only keep the next frame for later rendering
for (NSNumber * key in keys) {
@ -78,7 +79,7 @@
[self.frameBuffer removeObjectForKey:key];
}
}
SD_UNLOCK(self.lock);
SD_UNLOCK(self->_lock);
}];
}
@ -98,13 +99,6 @@
return _frameBuffer;
}
- (dispatch_semaphore_t)lock {
if (!_lock) {
_lock = dispatch_semaphore_create(1);
}
return _lock;
}
- (SDDisplayLink *)displayLink {
if (!_displayLink) {
_displayLink = [SDDisplayLink displayLinkWithTarget:self selector:@selector(displayDidRefresh:)];
@ -152,9 +146,9 @@
#endif
if (posterFrame) {
self.currentFrame = posterFrame;
SD_LOCK(self.lock);
SD_LOCK(self->_lock);
self.frameBuffer[@(self.currentFrameIndex)] = self.currentFrame;
SD_UNLOCK(self.lock);
SD_UNLOCK(self->_lock);
[self handleFrameChange];
}
}
@ -171,9 +165,9 @@
}
- (void)clearFrameBuffer {
SD_LOCK(self.lock);
SD_LOCK(_lock);
[_frameBuffer removeAllObjects];
SD_UNLOCK(self.lock);
SD_UNLOCK(_lock);
}
#pragma mark - Animation Control
@ -246,13 +240,13 @@
BOOL bufferFull = NO;
if (self.needsDisplayWhenImageBecomesAvailable) {
UIImage *currentFrame;
SD_LOCK(self.lock);
SD_LOCK(_lock);
currentFrame = self.frameBuffer[@(currentFrameIndex)];
SD_UNLOCK(self.lock);
SD_UNLOCK(_lock);
// Update the current frame
if (currentFrame) {
SD_LOCK(self.lock);
SD_LOCK(_lock);
// Remove the frame buffer if need
if (self.frameBuffer.count > self.maxBufferCount) {
self.frameBuffer[@(currentFrameIndex)] = nil;
@ -261,7 +255,7 @@
if (self.frameBuffer.count == totalFrameCount) {
bufferFull = YES;
}
SD_UNLOCK(self.lock);
SD_UNLOCK(_lock);
// Update the current frame immediately
self.currentFrame = currentFrame;
@ -322,9 +316,9 @@
// Or, most cases, the decode speed is faster than render speed, we fetch next frame
NSUInteger fetchFrameIndex = self.bufferMiss? currentFrameIndex : nextFrameIndex;
UIImage *fetchFrame;
SD_LOCK(self.lock);
SD_LOCK(_lock);
fetchFrame = self.bufferMiss? nil : self.frameBuffer[@(nextFrameIndex)];
SD_UNLOCK(self.lock);
SD_UNLOCK(_lock);
if (!fetchFrame && !bufferFull && self.fetchQueue.operationCount == 0) {
// Prefetch next frame in background queue
@ -339,9 +333,9 @@
BOOL isAnimating = self.displayLink.isRunning;
if (isAnimating) {
SD_LOCK(self.lock);
SD_LOCK(self->_lock);
self.frameBuffer[@(fetchFrameIndex)] = frame;
SD_UNLOCK(self.lock);
SD_UNLOCK(self->_lock);
}
}];
[self.fetchQueue addOperation:operation];

View File

@ -13,13 +13,12 @@
@interface SDImageCachesManager ()
@property (nonatomic, strong, nonnull) dispatch_semaphore_t cachesLock;
@property (nonatomic, strong, nonnull) NSMutableArray<id<SDImageCache>> *imageCaches;
@end
@implementation SDImageCachesManager
{
NSMutableArray<id<SDImageCache>> *_imageCaches;
@implementation SDImageCachesManager {
SD_LOCK_DECLARE(_cachesLock);
}
+ (SDImageCachesManager *)sharedManager {
@ -41,25 +40,25 @@
self.clearOperationPolicy = SDImageCachesManagerOperationPolicyConcurrent;
// initialize with default image caches
_imageCaches = [NSMutableArray arrayWithObject:[SDImageCache sharedImageCache]];
_cachesLock = dispatch_semaphore_create(1);
SD_LOCK_INIT(_cachesLock);
}
return self;
}
- (NSArray<id<SDImageCache>> *)caches {
SD_LOCK(self.cachesLock);
SD_LOCK(_cachesLock);
NSArray<id<SDImageCache>> *caches = [_imageCaches copy];
SD_UNLOCK(self.cachesLock);
SD_UNLOCK(_cachesLock);
return caches;
}
- (void)setCaches:(NSArray<id<SDImageCache>> *)caches {
SD_LOCK(self.cachesLock);
SD_LOCK(_cachesLock);
[_imageCaches removeAllObjects];
if (caches.count) {
[_imageCaches addObjectsFromArray:caches];
}
SD_UNLOCK(self.cachesLock);
SD_UNLOCK(_cachesLock);
}
#pragma mark - Cache IO operations
@ -68,18 +67,18 @@
if (![cache conformsToProtocol:@protocol(SDImageCache)]) {
return;
}
SD_LOCK(self.cachesLock);
SD_LOCK(_cachesLock);
[_imageCaches addObject:cache];
SD_UNLOCK(self.cachesLock);
SD_UNLOCK(_cachesLock);
}
- (void)removeCache:(id<SDImageCache>)cache {
if (![cache conformsToProtocol:@protocol(SDImageCache)]) {
return;
}
SD_LOCK(self.cachesLock);
SD_LOCK(_cachesLock);
[_imageCaches removeObject:cache];
SD_UNLOCK(self.cachesLock);
SD_UNLOCK(_cachesLock);
}
#pragma mark - SDImageCache

View File

@ -15,13 +15,12 @@
@interface SDImageCodersManager ()
@property (nonatomic, strong, nonnull) dispatch_semaphore_t codersLock;
@property (nonatomic, strong, nonnull) NSMutableArray<id<SDImageCoder>> *imageCoders;
@end
@implementation SDImageCodersManager
{
NSMutableArray<id<SDImageCoder>> *_imageCoders;
@implementation SDImageCodersManager {
SD_LOCK_DECLARE(_codersLock);
}
+ (nonnull instancetype)sharedManager {
@ -37,27 +36,27 @@
if (self = [super init]) {
// initialize with default coders
_imageCoders = [NSMutableArray arrayWithArray:@[[SDImageIOCoder sharedCoder], [SDImageGIFCoder sharedCoder], [SDImageAPNGCoder sharedCoder]]];
_codersLock = dispatch_semaphore_create(1);
SD_LOCK_INIT(_codersLock);
}
return self;
}
- (NSArray<id<SDImageCoder>> *)coders
{
SD_LOCK(self.codersLock);
SD_LOCK(_codersLock);
NSArray<id<SDImageCoder>> *coders = [_imageCoders copy];
SD_UNLOCK(self.codersLock);
SD_UNLOCK(_codersLock);
return coders;
}
- (void)setCoders:(NSArray<id<SDImageCoder>> *)coders
{
SD_LOCK(self.codersLock);
SD_LOCK(_codersLock);
[_imageCoders removeAllObjects];
if (coders.count) {
[_imageCoders addObjectsFromArray:coders];
}
SD_UNLOCK(self.codersLock);
SD_UNLOCK(_codersLock);
}
#pragma mark - Coder IO operations
@ -66,18 +65,18 @@
if (![coder conformsToProtocol:@protocol(SDImageCoder)]) {
return;
}
SD_LOCK(self.codersLock);
SD_LOCK(_codersLock);
[_imageCoders addObject:coder];
SD_UNLOCK(self.codersLock);
SD_UNLOCK(_codersLock);
}
- (void)removeCoder:(nonnull id<SDImageCoder>)coder {
if (![coder conformsToProtocol:@protocol(SDImageCoder)]) {
return;
}
SD_LOCK(self.codersLock);
SD_LOCK(_codersLock);
[_imageCoders removeObject:coder];
SD_UNLOCK(self.codersLock);
SD_UNLOCK(_codersLock);
}
#pragma mark - SDImageCoder

View File

@ -12,13 +12,12 @@
@interface SDImageLoadersManager ()
@property (nonatomic, strong, nonnull) dispatch_semaphore_t loadersLock;
@property (nonatomic, strong, nonnull) NSMutableArray<id<SDImageLoader>> *imageLoaders;
@end
@implementation SDImageLoadersManager
{
NSMutableArray<id<SDImageLoader>>* _imageLoaders;
@implementation SDImageLoadersManager {
SD_LOCK_DECLARE(_loadersLock);
}
+ (SDImageLoadersManager *)sharedManager {
@ -35,25 +34,25 @@
if (self) {
// initialize with default image loaders
_imageLoaders = [NSMutableArray arrayWithObject:[SDWebImageDownloader sharedDownloader]];
_loadersLock = dispatch_semaphore_create(1);
SD_LOCK_INIT(_loadersLock);
}
return self;
}
- (NSArray<id<SDImageLoader>> *)loaders {
SD_LOCK(self.loadersLock);
SD_LOCK(_loadersLock);
NSArray<id<SDImageLoader>>* loaders = [_imageLoaders copy];
SD_UNLOCK(self.loadersLock);
SD_UNLOCK(_loadersLock);
return loaders;
}
- (void)setLoaders:(NSArray<id<SDImageLoader>> *)loaders {
SD_LOCK(self.loadersLock);
SD_LOCK(_loadersLock);
[_imageLoaders removeAllObjects];
if (loaders.count) {
[_imageLoaders addObjectsFromArray:loaders];
}
SD_UNLOCK(self.loadersLock);
SD_UNLOCK(_loadersLock);
}
#pragma mark - Loader Property
@ -62,18 +61,18 @@
if (![loader conformsToProtocol:@protocol(SDImageLoader)]) {
return;
}
SD_LOCK(self.loadersLock);
SD_LOCK(_loadersLock);
[_imageLoaders addObject:loader];
SD_UNLOCK(self.loadersLock);
SD_UNLOCK(_loadersLock);
}
- (void)removeLoader:(id<SDImageLoader>)loader {
if (![loader conformsToProtocol:@protocol(SDImageLoader)]) {
return;
}
SD_LOCK(self.loadersLock);
SD_LOCK(_loadersLock);
[_imageLoaders removeObject:loader];
SD_UNLOCK(self.loadersLock);
SD_UNLOCK(_loadersLock);
}
#pragma mark - SDImageLoader

View File

@ -13,12 +13,15 @@
static void * SDMemoryCacheContext = &SDMemoryCacheContext;
@interface SDMemoryCache <KeyType, ObjectType> ()
@interface SDMemoryCache <KeyType, ObjectType> () {
#if SD_UIKIT
SD_LOCK_DECLARE(_weakCacheLock); // a lock to keep the access to `weakCache` thread-safe
#endif
}
@property (nonatomic, strong, nullable) SDImageCacheConfig *config;
#if SD_UIKIT
@property (nonatomic, strong, nonnull) NSMapTable<KeyType, ObjectType> *weakCache; // strong-weak cache
@property (nonatomic, strong, nonnull) dispatch_semaphore_t weakCacheLock; // a lock to keep the access to `weakCache` thread-safe
#endif
@end
@ -61,7 +64,7 @@ static void * SDMemoryCacheContext = &SDMemoryCacheContext;
#if SD_UIKIT
self.weakCache = [[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsStrongMemory valueOptions:NSPointerFunctionsWeakMemory capacity:0];
self.weakCacheLock = dispatch_semaphore_create(1);
SD_LOCK_INIT(_weakCacheLock);
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(didReceiveMemoryWarning:)
@ -85,9 +88,9 @@ static void * SDMemoryCacheContext = &SDMemoryCacheContext;
}
if (key && obj) {
// Store weak cache
SD_LOCK(self.weakCacheLock);
SD_LOCK(_weakCacheLock);
[self.weakCache setObject:obj forKey:key];
SD_UNLOCK(self.weakCacheLock);
SD_UNLOCK(_weakCacheLock);
}
}
@ -98,9 +101,9 @@ static void * SDMemoryCacheContext = &SDMemoryCacheContext;
}
if (key && !obj) {
// Check weak cache
SD_LOCK(self.weakCacheLock);
SD_LOCK(_weakCacheLock);
obj = [self.weakCache objectForKey:key];
SD_UNLOCK(self.weakCacheLock);
SD_UNLOCK(_weakCacheLock);
if (obj) {
// Sync cache
NSUInteger cost = 0;
@ -120,9 +123,9 @@ static void * SDMemoryCacheContext = &SDMemoryCacheContext;
}
if (key) {
// Remove weak cache
SD_LOCK(self.weakCacheLock);
SD_LOCK(_weakCacheLock);
[self.weakCache removeObjectForKey:key];
SD_UNLOCK(self.weakCacheLock);
SD_UNLOCK(_weakCacheLock);
}
}
@ -132,9 +135,9 @@ static void * SDMemoryCacheContext = &SDMemoryCacheContext;
return;
}
// Manually remove should also remove weak cache
SD_LOCK(self.weakCacheLock);
SD_LOCK(_weakCacheLock);
[self.weakCache removeAllObjects];
SD_UNLOCK(self.weakCacheLock);
SD_UNLOCK(_weakCacheLock);
}
#endif

View File

@ -40,15 +40,16 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext;
@property (strong, nonatomic, nonnull) NSOperationQueue *downloadQueue;
@property (strong, nonatomic, nonnull) NSMutableDictionary<NSURL *, NSOperation<SDWebImageDownloaderOperation> *> *URLOperations;
@property (strong, nonatomic, nullable) NSMutableDictionary<NSString *, NSString *> *HTTPHeaders;
@property (strong, nonatomic, nonnull) dispatch_semaphore_t HTTPHeadersLock; // A lock to keep the access to `HTTPHeaders` thread-safe
@property (strong, nonatomic, nonnull) dispatch_semaphore_t operationsLock; // A lock to keep the access to `URLOperations` thread-safe
// The session in which data tasks will run
@property (strong, nonatomic) NSURLSession *session;
@end
@implementation SDWebImageDownloader
@implementation SDWebImageDownloader {
SD_LOCK_DECLARE(_HTTPHeadersLock); // A lock to keep the access to `HTTPHeaders` thread-safe
SD_LOCK_DECLARE(_operationsLock); // A lock to keep the access to `URLOperations` thread-safe
}
+ (void)initialize {
// Bind SDNetworkActivityIndicator if available (download it here: http://github.com/rs/SDNetworkActivityIndicator )
@ -120,8 +121,8 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext;
}
headerDictionary[@"Accept"] = @"image/*,*/*;q=0.8";
_HTTPHeaders = headerDictionary;
_HTTPHeadersLock = dispatch_semaphore_create(1);
_operationsLock = dispatch_semaphore_create(1);
SD_LOCK_INIT(_HTTPHeadersLock);
SD_LOCK_INIT(_operationsLock);
NSURLSessionConfiguration *sessionConfiguration = _config.sessionConfiguration;
if (!sessionConfiguration) {
sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
@ -161,18 +162,18 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext;
if (!field) {
return;
}
SD_LOCK(self.HTTPHeadersLock);
SD_LOCK(_HTTPHeadersLock);
[self.HTTPHeaders setValue:value forKey:field];
SD_UNLOCK(self.HTTPHeadersLock);
SD_UNLOCK(_HTTPHeadersLock);
}
- (nullable NSString *)valueForHTTPHeaderField:(nullable NSString *)field {
if (!field) {
return nil;
}
SD_LOCK(self.HTTPHeadersLock);
SD_LOCK(_HTTPHeadersLock);
NSString *value = [self.HTTPHeaders objectForKey:field];
SD_UNLOCK(self.HTTPHeadersLock);
SD_UNLOCK(_HTTPHeadersLock);
return value;
}
@ -202,14 +203,14 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext;
return nil;
}
SD_LOCK(self.operationsLock);
SD_LOCK(_operationsLock);
id downloadOperationCancelToken;
NSOperation<SDWebImageDownloaderOperation> *operation = [self.URLOperations objectForKey:url];
// There is a case that the operation may be marked as finished or cancelled, but not been removed from `self.URLOperations`.
if (!operation || operation.isFinished || operation.isCancelled) {
operation = [self createDownloaderOperationWithUrl:url options:options context:context];
if (!operation) {
SD_UNLOCK(self.operationsLock);
SD_UNLOCK(_operationsLock);
if (completedBlock) {
NSError *error = [NSError errorWithDomain:SDWebImageErrorDomain code:SDWebImageErrorInvalidDownloadOperation userInfo:@{NSLocalizedDescriptionKey : @"Downloader operation is nil"}];
completedBlock(nil, nil, error, YES);
@ -222,9 +223,9 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext;
if (!self) {
return;
}
SD_LOCK(self.operationsLock);
SD_LOCK(self->_operationsLock);
[self.URLOperations removeObjectForKey:url];
SD_UNLOCK(self.operationsLock);
SD_UNLOCK(self->_operationsLock);
};
self.URLOperations[url] = operation;
// Add the handlers before submitting to operation queue, avoid the race condition that operation finished before setting handlers.
@ -248,7 +249,7 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext;
}
}
}
SD_UNLOCK(self.operationsLock);
SD_UNLOCK(_operationsLock);
SDWebImageDownloadToken *token = [[SDWebImageDownloadToken alloc] initWithDownloadOperation:operation];
token.url = url;
@ -271,9 +272,9 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext;
NSMutableURLRequest *mutableRequest = [[NSMutableURLRequest alloc] initWithURL:url cachePolicy:cachePolicy timeoutInterval:timeoutInterval];
mutableRequest.HTTPShouldHandleCookies = SD_OPTIONS_CONTAINS(options, SDWebImageDownloaderHandleCookies);
mutableRequest.HTTPShouldUsePipelining = YES;
SD_LOCK(self.HTTPHeadersLock);
SD_LOCK(_HTTPHeadersLock);
mutableRequest.allHTTPHeaderFields = self.HTTPHeaders;
SD_UNLOCK(self.HTTPHeadersLock);
SD_UNLOCK(_HTTPHeadersLock);
// Context Option
SDWebImageMutableContext *mutableContext;

View File

@ -26,14 +26,15 @@ static id<SDImageLoader> _defaultImageLoader;
@end
@interface SDWebImageManager ()
@interface SDWebImageManager () {
SD_LOCK_DECLARE(_failedURLsLock); // a lock to keep the access to `failedURLs` thread-safe
SD_LOCK_DECLARE(_runningOperationsLock); // a lock to keep the access to `runningOperations` thread-safe
}
@property (strong, nonatomic, readwrite, nonnull) SDImageCache *imageCache;
@property (strong, nonatomic, readwrite, nonnull) id<SDImageLoader> imageLoader;
@property (strong, nonatomic, nonnull) NSMutableSet<NSURL *> *failedURLs;
@property (strong, nonatomic, nonnull) dispatch_semaphore_t failedURLsLock; // a lock to keep the access to `failedURLs` thread-safe
@property (strong, nonatomic, nonnull) NSMutableSet<SDWebImageCombinedOperation *> *runningOperations;
@property (strong, nonatomic, nonnull) dispatch_semaphore_t runningOperationsLock; // a lock to keep the access to `runningOperations` thread-safe
@end
@ -87,9 +88,9 @@ static id<SDImageLoader> _defaultImageLoader;
_imageCache = cache;
_imageLoader = loader;
_failedURLs = [NSMutableSet new];
_failedURLsLock = dispatch_semaphore_create(1);
SD_LOCK_INIT(_failedURLsLock);
_runningOperations = [NSMutableSet new];
_runningOperationsLock = dispatch_semaphore_create(1);
SD_LOCK_INIT(_runningOperationsLock);
}
return self;
}
@ -188,9 +189,9 @@ static id<SDImageLoader> _defaultImageLoader;
BOOL isFailedUrl = NO;
if (url) {
SD_LOCK(self.failedURLsLock);
SD_LOCK(_failedURLsLock);
isFailedUrl = [self.failedURLs containsObject:url];
SD_UNLOCK(self.failedURLsLock);
SD_UNLOCK(_failedURLsLock);
}
if (url.absoluteString.length == 0 || (!(options & SDWebImageRetryFailed) && isFailedUrl)) {
@ -200,9 +201,9 @@ static id<SDImageLoader> _defaultImageLoader;
return operation;
}
SD_LOCK(self.runningOperationsLock);
SD_LOCK(_runningOperationsLock);
[self.runningOperations addObject:operation];
SD_UNLOCK(self.runningOperationsLock);
SD_UNLOCK(_runningOperationsLock);
// Preprocess the options and context arg to decide the final the result for manager
SDWebImageOptionsResult *result = [self processedResultForURL:url options:options context:context];
@ -214,17 +215,17 @@ static id<SDImageLoader> _defaultImageLoader;
}
- (void)cancelAll {
SD_LOCK(self.runningOperationsLock);
SD_LOCK(_runningOperationsLock);
NSSet<SDWebImageCombinedOperation *> *copiedOperations = [self.runningOperations copy];
SD_UNLOCK(self.runningOperationsLock);
SD_UNLOCK(_runningOperationsLock);
[copiedOperations makeObjectsPerformSelector:@selector(cancel)]; // This will call `safelyRemoveOperationFromRunning:` and remove from the array
}
- (BOOL)isRunning {
BOOL isRunning = NO;
SD_LOCK(self.runningOperationsLock);
SD_LOCK(_runningOperationsLock);
isRunning = (self.runningOperations.count > 0);
SD_UNLOCK(self.runningOperationsLock);
SD_UNLOCK(_runningOperationsLock);
return isRunning;
}
@ -232,15 +233,15 @@ static id<SDImageLoader> _defaultImageLoader;
if (!url) {
return;
}
SD_LOCK(self.failedURLsLock);
SD_LOCK(_failedURLsLock);
[self.failedURLs removeObject:url];
SD_UNLOCK(self.failedURLsLock);
SD_UNLOCK(_failedURLsLock);
}
- (void)removeAllFailedURLs {
SD_LOCK(self.failedURLsLock);
SD_LOCK(_failedURLsLock);
[self.failedURLs removeAllObjects];
SD_UNLOCK(self.failedURLsLock);
SD_UNLOCK(_failedURLsLock);
}
#pragma mark - Private
@ -415,15 +416,15 @@ static id<SDImageLoader> _defaultImageLoader;
BOOL shouldBlockFailedURL = [self shouldBlockFailedURLWithURL:url error:error options:options context:context];
if (shouldBlockFailedURL) {
SD_LOCK(self.failedURLsLock);
SD_LOCK(self->_failedURLsLock);
[self.failedURLs addObject:url];
SD_UNLOCK(self.failedURLsLock);
SD_UNLOCK(self->_failedURLsLock);
}
} else {
if ((options & SDWebImageRetryFailed)) {
SD_LOCK(self.failedURLsLock);
SD_LOCK(self->_failedURLsLock);
[self.failedURLs removeObject:url];
SD_UNLOCK(self.failedURLsLock);
SD_UNLOCK(self->_failedURLsLock);
}
// Continue store cache process
[self callStoreCacheProcessForOperation:operation url:url options:options context:context downloadedImage:downloadedImage downloadedData:downloadedData finished:finished progress:progressBlock completed:completedBlock];
@ -564,9 +565,9 @@ static id<SDImageLoader> _defaultImageLoader;
if (!operation) {
return;
}
SD_LOCK(self.runningOperationsLock);
SD_LOCK(_runningOperationsLock);
[self.runningOperations removeObject:operation];
SD_UNLOCK(self.runningOperationsLock);
SD_UNLOCK(_runningOperationsLock);
}
- (void)storeImage:(nullable UIImage *)image

View File

@ -22,8 +22,8 @@
unsigned long _totalCount;
// Used to ensure NSPointerArray thread safe
dispatch_semaphore_t _prefetchOperationsLock;
dispatch_semaphore_t _loadOperationsLock;
SD_LOCK_DECLARE(_prefetchOperationsLock)
SD_LOCK_DECLARE(_loadOperationsLock);
}
@property (nonatomic, copy, readwrite) NSArray<NSURL *> *urls;
@ -268,8 +268,8 @@
- (instancetype)init {
self = [super init];
if (self) {
_prefetchOperationsLock = dispatch_semaphore_create(1);
_loadOperationsLock = dispatch_semaphore_create(1);
SD_LOCK_INIT(_prefetchOperationsLock);
SD_LOCK_INIT(_loadOperationsLock);
}
return self;
}

View File

@ -32,7 +32,7 @@ static NSArray *SDBundlePreferredScales() {
}
@implementation SDImageAssetManager {
dispatch_semaphore_t _lock;
SD_LOCK_DECLARE(_lock);
}
+ (instancetype)sharedAssetManager {
@ -56,7 +56,7 @@ static NSArray *SDBundlePreferredScales() {
valueOptions = NSPointerFunctionsStrongMemory;
#endif
_imageTable = [NSMapTable mapTableWithKeyOptions:NSPointerFunctionsCopyIn valueOptions:valueOptions];
_lock = dispatch_semaphore_create(1);
SD_LOCK_INIT(_lock);
#if SD_UIKIT
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveMemoryWarning:) name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
#endif

View File

@ -9,9 +9,8 @@
#import "SDImageCachesManagerOperation.h"
#import "SDInternalMacros.h"
@implementation SDImageCachesManagerOperation
{
dispatch_semaphore_t _pendingCountLock;
@implementation SDImageCachesManagerOperation {
SD_LOCK_DECLARE(_pendingCountLock);
}
@synthesize executing = _executing;
@ -21,7 +20,7 @@
- (instancetype)init {
if (self = [super init]) {
_pendingCountLock = dispatch_semaphore_create(1);
SD_LOCK_INIT(_pendingCountLock);
_pendingCount = 0;
}
return self;

View File

@ -7,14 +7,44 @@
*/
#import <Foundation/Foundation.h>
#import <os/lock.h>
#import <libkern/OSAtomic.h>
#import "SDmetamacros.h"
#ifndef SD_LOCK_DECLARE
#if TARGET_OS_MACCATALYST
#define SD_LOCK_DECLARE(lock) os_unfair_lock lock;
#else
#define SD_LOCK_DECLARE(lock) os_unfair_lock lock API_AVAILABLE(ios(10.0), tvos(10), watchos(3), macos(10.12)); \
OSSpinLock lock##_deprecated;
#endif
#endif
#ifndef SD_LOCK_INIT
#if TARGET_OS_MACCATALYST
#define SD_LOCK_INIT(lock) lock = OS_UNFAIR_LOCK_INIT;
#else
#define SD_LOCK_INIT(lock) if (@available(iOS 10, tvOS 10, watchOS 3, macOS 10.12, *)) lock = OS_UNFAIR_LOCK_INIT; \
else lock##_deprecated = OS_SPINLOCK_INIT;
#endif
#endif
#ifndef SD_LOCK
#define SD_LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
#if TARGET_OS_MACCATALYST
#define SD_LOCK(lock) os_unfair_lock_lock(&lock);
#else
#define SD_LOCK(lock) if (@available(iOS 10, tvOS 10, watchOS 3, macOS 10.12, *)) os_unfair_lock_lock(&lock); \
else OSSpinLockLock(&lock##_deprecated);
#endif
#endif
#ifndef SD_UNLOCK
#define SD_UNLOCK(lock) dispatch_semaphore_signal(lock);
#if TARGET_OS_MACCATALYST
#define SD_UNLOCK(lock) os_unfair_lock_unlock(&lock);
#else
#define SD_UNLOCK(lock) if (@available(iOS 10, tvOS 10, watchOS 3, macOS 10.12, *)) os_unfair_lock_unlock(&lock); \
else OSSpinLockUnlock(&lock##_deprecated);
#endif
#endif
#ifndef SD_OPTIONS_CONTAINS