Ver código fonte

Stop using spinlocks

Apple engineers have pointed out that OSSpinLocks are vulnerable to live locking
on iOS in cases of priority inversion:

. http://mjtsai.com/blog/2015/12/16/osspinlock-is-unsafe/
. https://lists.swift.org/pipermail/swift-dev/Week-of-Mon-20151214/000372.html
ibireme 9 anos atrás
pai
commit
e6b0a5133f

+ 1 - 1
Demo/YYImageDemo/YYImageBenchmark.m

@@ -572,7 +572,7 @@ static inline void YYBenchmark(void (^block)(void), void (^complete)(double ms))
     CoverDecodeBlock yyCoverDecoder = ^(NSData *data) {
     CoverDecodeBlock yyCoverDecoder = ^(NSData *data) {
         @autoreleasepool {
         @autoreleasepool {
             YYImageDecoder *decoder = [YYImageDecoder decoderWithData:data scale:1];
             YYImageDecoder *decoder = [YYImageDecoder decoderWithData:data scale:1];
-            [decoder frameAtIndex:0 decodeForDisplay:YES];;
+            [decoder frameAtIndex:0 decodeForDisplay:YES];
         }
         }
     };
     };
     
     

+ 6 - 7
YYImage/YYAnimatedImageView.m

@@ -12,19 +12,18 @@
 #import "YYAnimatedImageView.h"
 #import "YYAnimatedImageView.h"
 #import "YYImageCoder.h"
 #import "YYImageCoder.h"
 #import <pthread.h>
 #import <pthread.h>
-#import <libkern/OSAtomic.h>
 #import <mach/mach.h>
 #import <mach/mach.h>
 
 
 
 
 #define BUFFER_SIZE (10 * 1024 * 1024) // 10MB (minimum memory buffer size)
 #define BUFFER_SIZE (10 * 1024 * 1024) // 10MB (minimum memory buffer size)
 
 
-#define LOCK(...) OSSpinLockLock(&self->_lock); \
+#define LOCK(...) dispatch_semaphore_wait(self->_lock, DISPATCH_TIME_FOREVER); \
 __VA_ARGS__; \
 __VA_ARGS__; \
-OSSpinLockUnlock(&self->_lock);
+dispatch_semaphore_signal(self->_lock);
 
 
-#define LOCK_VIEW(...) OSSpinLockLock(&view->_lock); \
+#define LOCK_VIEW(...) dispatch_semaphore_wait(view->_lock, DISPATCH_TIME_FOREVER); \
 __VA_ARGS__; \
 __VA_ARGS__; \
-OSSpinLockUnlock(&view->_lock);
+dispatch_semaphore_signal(view->_lock);
 
 
 
 
 static int64_t _YYDeviceMemoryTotal() {
 static int64_t _YYDeviceMemoryTotal() {
@@ -126,7 +125,7 @@ typedef NS_ENUM(NSUInteger, YYAnimatedImageType) {
     UIImage <YYAnimatedImage> *_curAnimatedImage;
     UIImage <YYAnimatedImage> *_curAnimatedImage;
     
     
     dispatch_once_t _onceToken;
     dispatch_once_t _onceToken;
-    OSSpinLock _lock; ///< lock for _buffer
+    dispatch_semaphore_t _lock; ///< lock for _buffer
     NSOperationQueue *_requestQueue; ///< image request queue, serial
     NSOperationQueue *_requestQueue; ///< image request queue, serial
     
     
     CADisplayLink *_link; ///< ticker for change frame
     CADisplayLink *_link; ///< ticker for change frame
@@ -227,7 +226,7 @@ typedef NS_ENUM(NSUInteger, YYAnimatedImageType) {
 // init the animated params.
 // init the animated params.
 - (void)resetAnimated {
 - (void)resetAnimated {
     dispatch_once(&_onceToken, ^{
     dispatch_once(&_onceToken, ^{
-        _lock = OS_SPINLOCK_INIT;
+        _lock = dispatch_semaphore_create(1);
         _buffer = [NSMutableDictionary new];
         _buffer = [NSMutableDictionary new];
         _requestQueue = [[NSOperationQueue alloc] init];
         _requestQueue = [[NSOperationQueue alloc] init];
         _requestQueue.maxConcurrentOperationCount = 1;
         _requestQueue.maxConcurrentOperationCount = 1;

+ 8 - 9
YYImage/YYImage.m

@@ -10,7 +10,6 @@
 //
 //
 
 
 #import "YYImage.h"
 #import "YYImage.h"
-#import <libkern/OSAtomic.h>
 
 
 /**
 /**
  An array of NSNumber objects, shows the best order for path scale search.
  An array of NSNumber objects, shows the best order for path scale search.
@@ -88,7 +87,7 @@ static CGFloat _NSStringPathScale(NSString *string) {
 @implementation YYImage {
 @implementation YYImage {
     YYImageDecoder *_decoder;
     YYImageDecoder *_decoder;
     NSArray *_preloadedFrames;
     NSArray *_preloadedFrames;
-    OSSpinLock _preloadedLock;
+    dispatch_semaphore_t _preloadedLock;
     NSUInteger _bytesPerFrame;
     NSUInteger _bytesPerFrame;
 }
 }
 
 
@@ -145,7 +144,7 @@ static CGFloat _NSStringPathScale(NSString *string) {
 - (instancetype)initWithData:(NSData *)data scale:(CGFloat)scale {
 - (instancetype)initWithData:(NSData *)data scale:(CGFloat)scale {
     if (data.length == 0) return nil;
     if (data.length == 0) return nil;
     if (scale <= 0) scale = [UIScreen mainScreen].scale;
     if (scale <= 0) scale = [UIScreen mainScreen].scale;
-    _preloadedLock = OS_SPINLOCK_INIT;
+    _preloadedLock = dispatch_semaphore_create(1);
     @autoreleasepool {
     @autoreleasepool {
         YYImageDecoder *decoder = [YYImageDecoder decoderWithData:data scale:scale];
         YYImageDecoder *decoder = [YYImageDecoder decoderWithData:data scale:scale];
         YYImageFrame *frame = [decoder frameAtIndex:0 decodeForDisplay:YES];
         YYImageFrame *frame = [decoder frameAtIndex:0 decodeForDisplay:YES];
@@ -180,13 +179,13 @@ static CGFloat _NSStringPathScale(NSString *string) {
                     [frames addObject:[NSNull null]];
                     [frames addObject:[NSNull null]];
                 }
                 }
             }
             }
-            OSSpinLockLock(&_preloadedLock);
+            dispatch_semaphore_wait(_preloadedLock, DISPATCH_TIME_FOREVER);
             _preloadedFrames = frames;
             _preloadedFrames = frames;
-            OSSpinLockUnlock(&_preloadedLock);
+            dispatch_semaphore_signal(_preloadedLock);
         } else {
         } else {
-            OSSpinLockLock(&_preloadedLock);
+            dispatch_semaphore_wait(_preloadedLock, DISPATCH_TIME_FOREVER);
             _preloadedFrames = nil;
             _preloadedFrames = nil;
-            OSSpinLockUnlock(&_preloadedLock);
+            dispatch_semaphore_signal(_preloadedLock);
         }
         }
     }
     }
 }
 }
@@ -229,9 +228,9 @@ static CGFloat _NSStringPathScale(NSString *string) {
 
 
 - (UIImage *)animatedImageFrameAtIndex:(NSUInteger)index {
 - (UIImage *)animatedImageFrameAtIndex:(NSUInteger)index {
     if (index >= _decoder.frameCount) return nil;
     if (index >= _decoder.frameCount) return nil;
-    OSSpinLockLock(&_preloadedLock);
+    dispatch_semaphore_wait(_preloadedLock, DISPATCH_TIME_FOREVER);
     UIImage *image = _preloadedFrames[index];
     UIImage *image = _preloadedFrames[index];
-    OSSpinLockUnlock(&_preloadedLock);
+    dispatch_semaphore_signal(_preloadedLock);
     if (image) return image == (id)[NSNull null] ? nil : image;
     if (image) return image == (id)[NSNull null] ? nil : image;
     return [_decoder frameAtIndex:index decodeForDisplay:YES].image;
     return [_decoder frameAtIndex:index decodeForDisplay:YES].image;
 }
 }

+ 16 - 17
YYImage/YYImageCoder.m

@@ -19,7 +19,6 @@
 #import <AssetsLibrary/AssetsLibrary.h>
 #import <AssetsLibrary/AssetsLibrary.h>
 #import <objc/runtime.h>
 #import <objc/runtime.h>
 #import <pthread.h>
 #import <pthread.h>
-#import <libkern/OSAtomic.h>
 #import <zlib.h>
 #import <zlib.h>
 
 
 
 
@@ -924,7 +923,7 @@ CGImageRef YYCGImageCreateAffineTransformCopy(CGImageRef imageRef, CGAffineTrans
     if (srcWidth == 0 || srcHeight == 0 || destWidth == 0 || destHeight == 0) return NULL;
     if (srcWidth == 0 || srcHeight == 0 || destWidth == 0 || destHeight == 0) return NULL;
     
     
     CGDataProviderRef tmpProvider = NULL, destProvider = NULL;
     CGDataProviderRef tmpProvider = NULL, destProvider = NULL;
-    CGImageRef tmpImage = NULL, destImage = NULL;;
+    CGImageRef tmpImage = NULL, destImage = NULL;
     vImage_Buffer src = {0}, tmp = {0}, dest = {0};
     vImage_Buffer src = {0}, tmp = {0}, dest = {0};
     if(!YYCGImageDecodeToBitmapBufferWith32BitFormat(imageRef, &src, kCGImageAlphaFirst | kCGBitmapByteOrderDefault)) return NULL;
     if(!YYCGImageDecodeToBitmapBufferWith32BitFormat(imageRef, &src, kCGImageAlphaFirst | kCGBitmapByteOrderDefault)) return NULL;
     
     
@@ -1506,7 +1505,7 @@ CGImageRef YYCGImageCreateWithWebPData(CFDataRef webpData,
 
 
 
 
 @implementation YYImageDecoder {
 @implementation YYImageDecoder {
-    pthread_mutex_t _lock;
+    pthread_mutex_t _lock; // recursive lock
     
     
     BOOL _sourceTypeDetected;
     BOOL _sourceTypeDetected;
     CGImageSourceRef _source;
     CGImageSourceRef _source;
@@ -1516,7 +1515,7 @@ CGImageRef YYCGImageCreateWithWebPData(CFDataRef webpData,
 #endif
 #endif
     
     
     UIImageOrientation _orientation;
     UIImageOrientation _orientation;
-    OSSpinLock _framesLock;
+    dispatch_semaphore_t _framesLock;
     NSArray *_frames; ///< Array<GGImageDecoderFrame>, without image
     NSArray *_frames; ///< Array<GGImageDecoderFrame>, without image
     BOOL _needBlend;
     BOOL _needBlend;
     NSUInteger _blendFrameIndex;
     NSUInteger _blendFrameIndex;
@@ -1548,7 +1547,7 @@ CGImageRef YYCGImageCreateWithWebPData(CFDataRef webpData,
     self = [super init];
     self = [super init];
     if (scale <= 0) scale = 1;
     if (scale <= 0) scale = 1;
     _scale = scale;
     _scale = scale;
-    _framesLock = OS_SPINLOCK_INIT;
+    _framesLock = dispatch_semaphore_create(1);
     
     
     pthread_mutexattr_t attr;
     pthread_mutexattr_t attr;
     pthread_mutexattr_init (&attr);
     pthread_mutexattr_init (&attr);
@@ -1577,11 +1576,11 @@ CGImageRef YYCGImageCreateWithWebPData(CFDataRef webpData,
 
 
 - (NSTimeInterval)frameDurationAtIndex:(NSUInteger)index {
 - (NSTimeInterval)frameDurationAtIndex:(NSUInteger)index {
     NSTimeInterval result = 0;
     NSTimeInterval result = 0;
-    OSSpinLockLock(&_framesLock); // for better performance when play animation...
+    dispatch_semaphore_wait(_framesLock, DISPATCH_TIME_FOREVER);
     if (index < _frames.count) {
     if (index < _frames.count) {
         result = ((_YYImageDecoderFrame *)_frames[index]).duration;
         result = ((_YYImageDecoderFrame *)_frames[index]).duration;
     }
     }
-    OSSpinLockUnlock(&_framesLock);
+    dispatch_semaphore_signal(_framesLock);
     return result;
     return result;
 }
 }
 
 
@@ -1746,9 +1745,9 @@ CGImageRef YYCGImageCreateWithWebPData(CFDataRef webpData,
     _loopCount = 0;
     _loopCount = 0;
     if (_webpSource) WebPDemuxDelete(_webpSource);
     if (_webpSource) WebPDemuxDelete(_webpSource);
     _webpSource = NULL;
     _webpSource = NULL;
-    OSSpinLockLock(&_framesLock);
+    dispatch_semaphore_wait(_framesLock, DISPATCH_TIME_FOREVER);
     _frames = nil;
     _frames = nil;
-    OSSpinLockUnlock(&_framesLock);
+    dispatch_semaphore_signal(_framesLock);
     
     
     /*
     /*
      https://developers.google.com/speed/webp/docs/api
      https://developers.google.com/speed/webp/docs/api
@@ -1832,9 +1831,9 @@ CGImageRef YYCGImageCreateWithWebPData(CFDataRef webpData,
     _loopCount = webpLoopCount;
     _loopCount = webpLoopCount;
     _needBlend = needBlend;
     _needBlend = needBlend;
     _webpSource = demuxer;
     _webpSource = demuxer;
-    OSSpinLockLock(&_framesLock);
+    dispatch_semaphore_wait(_framesLock, DISPATCH_TIME_FOREVER);
     _frames = frames;
     _frames = frames;
-    OSSpinLockUnlock(&_framesLock);
+    dispatch_semaphore_signal(_framesLock);
 #endif
 #endif
 }
 }
 
 
@@ -1930,9 +1929,9 @@ CGImageRef YYCGImageCreateWithWebPData(CFDataRef webpData,
     _loopCount = apng->apng_loop_num;
     _loopCount = apng->apng_loop_num;
     _needBlend = needBlend;
     _needBlend = needBlend;
     _apngSource = apng;
     _apngSource = apng;
-    OSSpinLockLock(&_framesLock);
+    dispatch_semaphore_wait(_framesLock, DISPATCH_TIME_FOREVER);
     _frames = frames;
     _frames = frames;
-    OSSpinLockUnlock(&_framesLock);
+    dispatch_semaphore_signal(_framesLock);
 }
 }
 
 
 - (void)_updateSourceImageIO {
 - (void)_updateSourceImageIO {
@@ -1940,9 +1939,9 @@ CGImageRef YYCGImageCreateWithWebPData(CFDataRef webpData,
     _height = 0;
     _height = 0;
     _orientation = UIImageOrientationUp;
     _orientation = UIImageOrientationUp;
     _loopCount = 0;
     _loopCount = 0;
-    OSSpinLockLock(&_framesLock);
+    dispatch_semaphore_wait(_framesLock, DISPATCH_TIME_FOREVER);
     _frames = nil;
     _frames = nil;
-    OSSpinLockUnlock(&_framesLock);
+    dispatch_semaphore_signal(_framesLock);
     
     
     if (!_source) {
     if (!_source) {
         if (_finalized) {
         if (_finalized) {
@@ -2026,9 +2025,9 @@ CGImageRef YYCGImageCreateWithWebPData(CFDataRef webpData,
             CFRelease(properties);
             CFRelease(properties);
         }
         }
     }
     }
-    OSSpinLockLock(&_framesLock);
+    dispatch_semaphore_wait(_framesLock, DISPATCH_TIME_FOREVER);
     _frames = frames;
     _frames = frames;
-    OSSpinLockUnlock(&_framesLock);
+    dispatch_semaphore_signal(_framesLock);
 }
 }
 
 
 - (CGImageRef)_newUnblendedImageAtIndex:(NSUInteger)index
 - (CGImageRef)_newUnblendedImageAtIndex:(NSUInteger)index