123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239 |
- //
- // YYDispatchQueueManager.m
- // YYKit <https://github.com/ibireme/YYKit>
- //
- // Created by ibireme on 15/7/18.
- // Copyright (c) 2015 ibireme.
- //
- // This source code is licensed under the MIT-style license found in the
- // LICENSE file in the root directory of this source tree.
- //
- #import "YYDispatchQueuePool.h"
- #import <UIKit/UIKit.h>
- #import <libkern/OSAtomic.h>
- #define MAX_QUEUE_COUNT 32
- static inline dispatch_queue_priority_t NSQualityOfServiceToDispatchPriority(NSQualityOfService qos) {
- switch (qos) {
- case NSQualityOfServiceUserInteractive: return DISPATCH_QUEUE_PRIORITY_HIGH;
- case NSQualityOfServiceUserInitiated: return DISPATCH_QUEUE_PRIORITY_HIGH;
- case NSQualityOfServiceUtility: return DISPATCH_QUEUE_PRIORITY_LOW;
- case NSQualityOfServiceBackground: return DISPATCH_QUEUE_PRIORITY_BACKGROUND;
- case NSQualityOfServiceDefault: return DISPATCH_QUEUE_PRIORITY_DEFAULT;
- default: return DISPATCH_QUEUE_PRIORITY_DEFAULT;
- }
- }
- static inline qos_class_t NSQualityOfServiceToQOSClass(NSQualityOfService qos) {
- switch (qos) {
- case NSQualityOfServiceUserInteractive: return QOS_CLASS_USER_INTERACTIVE;
- case NSQualityOfServiceUserInitiated: return QOS_CLASS_USER_INITIATED;
- case NSQualityOfServiceUtility: return QOS_CLASS_UTILITY;
- case NSQualityOfServiceBackground: return QOS_CLASS_BACKGROUND;
- case NSQualityOfServiceDefault: return QOS_CLASS_DEFAULT;
- default: return QOS_CLASS_UNSPECIFIED;
- }
- }
- typedef struct {
- const char *name;
- void **queues;
- uint32_t queueCount;
- int32_t counter;
- } YYDispatchContext;
- static YYDispatchContext *YYDispatchContextCreate(const char *name,
- uint32_t queueCount,
- NSQualityOfService qos) {
- YYDispatchContext *context = calloc(1, sizeof(YYDispatchContext));
- if (!context) return NULL;
- context->queues = calloc(queueCount, sizeof(void *));
- if (!context->queues) {
- free(context);
- return NULL;
- }
- if ([UIDevice currentDevice].systemVersion.floatValue >= 8.0) {
- dispatch_qos_class_t qosClass = NSQualityOfServiceToQOSClass(qos);
- for (NSUInteger i = 0; i < queueCount; i++) {
- dispatch_queue_attr_t attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, qosClass, 0);
- dispatch_queue_t queue = dispatch_queue_create(name, attr);
- context->queues[i] = (__bridge_retained void *)(queue);
- }
- } else {
- long identifier = NSQualityOfServiceToDispatchPriority(qos);
- for (NSUInteger i = 0; i < queueCount; i++) {
- dispatch_queue_t queue = dispatch_queue_create(name, DISPATCH_QUEUE_SERIAL);
- dispatch_set_target_queue(queue, dispatch_get_global_queue(identifier, 0));
- context->queues[i] = (__bridge_retained void *)(queue);
- }
- }
- context->queueCount = queueCount;
- if (name) {
- context->name = strdup(name);
- }
- return context;
- }
- static void YYDispatchContextRelease(YYDispatchContext *context) {
- if (!context) return;
- if (context->queues) {
- for (NSUInteger i = 0; i < context->queueCount; i++) {
- void *queuePointer = context->queues[i];
- dispatch_queue_t queue = (__bridge_transfer dispatch_queue_t)(queuePointer);
- const char *name = dispatch_queue_get_label(queue);
- if (name) strlen(name); // avoid compiler warning
- queue = nil;
- }
- free(context->queues);
- context->queues = NULL;
- }
- if (context->name) free((void *)context->name);
- }
- static dispatch_queue_t YYDispatchContextGetQueue(YYDispatchContext *context) {
- uint32_t counter = (uint32_t)OSAtomicIncrement32(&context->counter);
- void *queue = context->queues[counter % context->queueCount];
- return (__bridge dispatch_queue_t)(queue);
- }
- static YYDispatchContext *YYDispatchContextGetForQOS(NSQualityOfService qos) {
- static YYDispatchContext *context[5] = {0};
- switch (qos) {
- case NSQualityOfServiceUserInteractive: {
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- int count = (int)[NSProcessInfo processInfo].activeProcessorCount;
- count = count < 1 ? 1 : count > MAX_QUEUE_COUNT ? MAX_QUEUE_COUNT : count;
- context[0] = YYDispatchContextCreate("com.ibireme.yykit.user-interactive", count, qos);
- });
- return context[0];
- } break;
- case NSQualityOfServiceUserInitiated: {
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- int count = (int)[NSProcessInfo processInfo].activeProcessorCount;
- count = count < 1 ? 1 : count > MAX_QUEUE_COUNT ? MAX_QUEUE_COUNT : count;
- context[1] = YYDispatchContextCreate("com.ibireme.yykit.user-initiated", count, qos);
- });
- return context[1];
- } break;
- case NSQualityOfServiceUtility: {
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- int count = (int)[NSProcessInfo processInfo].activeProcessorCount;
- count = count < 1 ? 1 : count > MAX_QUEUE_COUNT ? MAX_QUEUE_COUNT : count;
- context[2] = YYDispatchContextCreate("com.ibireme.yykit.utility", count, qos);
- });
- return context[2];
- } break;
- case NSQualityOfServiceBackground: {
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- int count = (int)[NSProcessInfo processInfo].activeProcessorCount;
- count = count < 1 ? 1 : count > MAX_QUEUE_COUNT ? MAX_QUEUE_COUNT : count;
- context[3] = YYDispatchContextCreate("com.ibireme.yykit.background", count, qos);
- });
- return context[3];
- } break;
- case NSQualityOfServiceDefault:
- default: {
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- int count = (int)[NSProcessInfo processInfo].activeProcessorCount;
- count = count < 1 ? 1 : count > MAX_QUEUE_COUNT ? MAX_QUEUE_COUNT : count;
- context[4] = YYDispatchContextCreate("com.ibireme.yykit.default", count, qos);
- });
- return context[4];
- } break;
- }
- }
- @implementation YYDispatchQueuePool {
- @public
- YYDispatchContext *_context;
- }
- - (void)dealloc {
- if (_context) {
- YYDispatchContextRelease(_context);
- _context = NULL;
- }
- }
- - (instancetype)initWithContext:(YYDispatchContext *)context {
- self = [super init];
- if (!context) return nil;
- self->_context = context;
- _name = context->name ? [NSString stringWithUTF8String:context->name] : nil;
- return self;
- }
- - (instancetype)initWithName:(NSString *)name queueCount:(NSUInteger)queueCount qos:(NSQualityOfService)qos {
- if (queueCount == 0 || queueCount > MAX_QUEUE_COUNT) return nil;
- self = [super init];
- _context = YYDispatchContextCreate(name.UTF8String, (uint32_t)queueCount, qos);
- if (!_context) return nil;
- _name = name;
- return self;
- }
- - (dispatch_queue_t)queue {
- return YYDispatchContextGetQueue(_context);
- }
- + (instancetype)defaultPoolForQOS:(NSQualityOfService)qos {
- switch (qos) {
- case NSQualityOfServiceUserInteractive: {
- static YYDispatchQueuePool *pool;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- pool = [[YYDispatchQueuePool alloc] initWithContext:YYDispatchContextGetForQOS(qos)];
- });
- return pool;
- } break;
- case NSQualityOfServiceUserInitiated: {
- static YYDispatchQueuePool *pool;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- pool = [[YYDispatchQueuePool alloc] initWithContext:YYDispatchContextGetForQOS(qos)];
- });
- return pool;
- } break;
- case NSQualityOfServiceUtility: {
- static YYDispatchQueuePool *pool;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- pool = [[YYDispatchQueuePool alloc] initWithContext:YYDispatchContextGetForQOS(qos)];
- });
- return pool;
- } break;
- case NSQualityOfServiceBackground: {
- static YYDispatchQueuePool *pool;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- pool = [[YYDispatchQueuePool alloc] initWithContext:YYDispatchContextGetForQOS(qos)];
- });
- return pool;
- } break;
- case NSQualityOfServiceDefault:
- default: {
- static YYDispatchQueuePool *pool;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- pool = [[YYDispatchQueuePool alloc] initWithContext:YYDispatchContextGetForQOS(NSQualityOfServiceDefault)];
- });
- return pool;
- } break;
- }
- }
- @end
- dispatch_queue_t YYDispatchQueueGetForQOS(NSQualityOfService qos) {
- return YYDispatchContextGetQueue(YYDispatchContextGetForQOS(qos));
- }
|