美文网首页
GCD源码分析

GCD源码分析

作者: Cwwng | 来源:发表于2020-11-16 00:02 被阅读0次

    1、源码版本

    libdispatch-1173.40.5
    地址:https://opensource.apple.com/tarballs/libdispatch/

    2、dispatch_get_global_queue

    init.c

    dispatch_queue_global_t
    dispatch_get_global_queue(long priority, unsigned long flags)
    {
        dispatch_assert(countof(_dispatch_root_queues) ==
                DISPATCH_ROOT_QUEUE_COUNT);
    
        if (flags & ~(unsigned long)DISPATCH_QUEUE_OVERCOMMIT) {
            return DISPATCH_BAD_INPUT;
        }
        // 获取队列优先级
        dispatch_qos_t qos = _dispatch_qos_from_queue_priority(priority);
    #if !HAVE_PTHREAD_WORKQUEUE_QOS
        if (qos == QOS_CLASS_MAINTENANCE) {
            qos = DISPATCH_QOS_BACKGROUND;
        } else if (qos == QOS_CLASS_USER_INTERACTIVE) {
            qos = DISPATCH_QOS_USER_INITIATED;
        }
    #endif
        if (qos == DISPATCH_QOS_UNSPECIFIED) {
            return DISPATCH_BAD_INPUT;
        }
        // 从系统默认的root队列数组中取对应qos的队列
        return _dispatch_get_root_queue(qos, flags & DISPATCH_QUEUE_OVERCOMMIT);
    }
    

    priority.h

    static inline dispatch_qos_t
    _dispatch_qos_from_queue_priority(long priority)
    {
        switch (priority) {
        case DISPATCH_QUEUE_PRIORITY_BACKGROUND:      return DISPATCH_QOS_BACKGROUND;
        case DISPATCH_QUEUE_PRIORITY_NON_INTERACTIVE: return DISPATCH_QOS_UTILITY;
        case DISPATCH_QUEUE_PRIORITY_LOW:             return DISPATCH_QOS_UTILITY;
        case DISPATCH_QUEUE_PRIORITY_DEFAULT:         return DISPATCH_QOS_DEFAULT;
        case DISPATCH_QUEUE_PRIORITY_HIGH:            return DISPATCH_QOS_USER_INITIATED;
        default: return _dispatch_qos_from_qos_class((qos_class_t)priority);
        }
    }
    

    inline_internal.h

    struct dispatch_queue_global_s _dispatch_root_queues[] = {
    #define _DISPATCH_ROOT_QUEUE_IDX(n, flags) \
            ((flags & DISPATCH_PRIORITY_FLAG_OVERCOMMIT) ? \
            DISPATCH_ROOT_QUEUE_IDX_##n##_QOS_OVERCOMMIT : \
            DISPATCH_ROOT_QUEUE_IDX_##n##_QOS)
    #define _DISPATCH_ROOT_QUEUE_ENTRY(n, flags, ...) \
        [_DISPATCH_ROOT_QUEUE_IDX(n, flags)] = { \
            DISPATCH_GLOBAL_OBJECT_HEADER(queue_global), \
            .dq_state = DISPATCH_ROOT_QUEUE_STATE_INIT_VALUE, \
            .do_ctxt = _dispatch_root_queue_ctxt(_DISPATCH_ROOT_QUEUE_IDX(n, flags)), \
            .dq_atomic_flags = DQF_WIDTH(DISPATCH_QUEUE_WIDTH_POOL), \
            .dq_priority = flags | ((flags & DISPATCH_PRIORITY_FLAG_FALLBACK) ? \
                    _dispatch_priority_make_fallback(DISPATCH_QOS_##n) : \
                    _dispatch_priority_make(DISPATCH_QOS_##n, 0)), \
            __VA_ARGS__ \
        }
        _DISPATCH_ROOT_QUEUE_ENTRY(MAINTENANCE, 0,
            .dq_label = "com.apple.root.maintenance-qos",
            .dq_serialnum = 4,
        ),
        _DISPATCH_ROOT_QUEUE_ENTRY(MAINTENANCE, DISPATCH_PRIORITY_FLAG_OVERCOMMIT,
            .dq_label = "com.apple.root.maintenance-qos.overcommit",
            .dq_serialnum = 5,
        ),
        _DISPATCH_ROOT_QUEUE_ENTRY(BACKGROUND, 0,
            .dq_label = "com.apple.root.background-qos",
            .dq_serialnum = 6,
        ),
        _DISPATCH_ROOT_QUEUE_ENTRY(BACKGROUND, DISPATCH_PRIORITY_FLAG_OVERCOMMIT,
            .dq_label = "com.apple.root.background-qos.overcommit",
            .dq_serialnum = 7,
        ),
        _DISPATCH_ROOT_QUEUE_ENTRY(UTILITY, 0,
            .dq_label = "com.apple.root.utility-qos",
            .dq_serialnum = 8,
        ),
        _DISPATCH_ROOT_QUEUE_ENTRY(UTILITY, DISPATCH_PRIORITY_FLAG_OVERCOMMIT,
            .dq_label = "com.apple.root.utility-qos.overcommit",
            .dq_serialnum = 9,
        ),
        _DISPATCH_ROOT_QUEUE_ENTRY(DEFAULT, DISPATCH_PRIORITY_FLAG_FALLBACK,
            .dq_label = "com.apple.root.default-qos",
            .dq_serialnum = 10,
        ),
        _DISPATCH_ROOT_QUEUE_ENTRY(DEFAULT,
                DISPATCH_PRIORITY_FLAG_FALLBACK | DISPATCH_PRIORITY_FLAG_OVERCOMMIT,
            .dq_label = "com.apple.root.default-qos.overcommit",
            .dq_serialnum = 11,
        ),
        _DISPATCH_ROOT_QUEUE_ENTRY(USER_INITIATED, 0,
            .dq_label = "com.apple.root.user-initiated-qos",
            .dq_serialnum = 12,
        ),
        _DISPATCH_ROOT_QUEUE_ENTRY(USER_INITIATED, DISPATCH_PRIORITY_FLAG_OVERCOMMIT,
            .dq_label = "com.apple.root.user-initiated-qos.overcommit",
            .dq_serialnum = 13,
        ),
        _DISPATCH_ROOT_QUEUE_ENTRY(USER_INTERACTIVE, 0,
            .dq_label = "com.apple.root.user-interactive-qos",
            .dq_serialnum = 14,
        ),
        _DISPATCH_ROOT_QUEUE_ENTRY(USER_INTERACTIVE, DISPATCH_PRIORITY_FLAG_OVERCOMMIT,
            .dq_label = "com.apple.root.user-interactive-qos.overcommit",
            .dq_serialnum = 15,
        ),
    };
    

    3、dispatch_queue_create

    queue.c

    dispatch_queue_t
    dispatch_queue_create_with_target(const char *label, dispatch_queue_attr_t dqa,
            dispatch_queue_t tq)
    {
        return _dispatch_lane_create_with_target(label, dqa, tq, false);
    }
    
    DISPATCH_NOINLINE
    static dispatch_queue_t
    _dispatch_lane_create_with_target(const char *label, dispatch_queue_attr_t dqa,
            dispatch_queue_t tq, bool legacy)
    {
        dispatch_queue_attr_info_t dqai = _dispatch_queue_attr_to_info(dqa);
    
        //
        // Step 1: Normalize arguments (qos, overcommit, tq)
        //
    
        // 取出优先级
        dispatch_qos_t qos = dqai.dqai_qos;
    #if !HAVE_PTHREAD_WORKQUEUE_QOS
        if (qos == DISPATCH_QOS_USER_INTERACTIVE) {
            dqai.dqai_qos = qos = DISPATCH_QOS_USER_INITIATED;
        }
        if (qos == DISPATCH_QOS_MAINTENANCE) {
            dqai.dqai_qos = qos = DISPATCH_QOS_BACKGROUND;
        }
    #endif // !HAVE_PTHREAD_WORKQUEUE_QOS
    
        _dispatch_queue_attr_overcommit_t overcommit = dqai.dqai_overcommit;
        if (overcommit != _dispatch_queue_attr_overcommit_unspecified && tq) {
            if (tq->do_targetq) {
                DISPATCH_CLIENT_CRASH(tq, "Cannot specify both overcommit and "
                        "a non-global target queue");
            }
        }
    
        if (tq && dx_type(tq) == DISPATCH_QUEUE_GLOBAL_ROOT_TYPE) {
            // Handle discrepancies between attr and target queue, attributes win
            if (overcommit == _dispatch_queue_attr_overcommit_unspecified) {
                if (tq->dq_priority & DISPATCH_PRIORITY_FLAG_OVERCOMMIT) {
                    overcommit = _dispatch_queue_attr_overcommit_enabled;
                } else {
                    overcommit = _dispatch_queue_attr_overcommit_disabled;
                }
            }
            if (qos == DISPATCH_QOS_UNSPECIFIED) {
                qos = _dispatch_priority_qos(tq->dq_priority);
            }
            tq = NULL;
        } else if (tq && !tq->do_targetq) {
            // target is a pthread or runloop root queue, setting QoS or overcommit
            // is disallowed
            if (overcommit != _dispatch_queue_attr_overcommit_unspecified) {
                DISPATCH_CLIENT_CRASH(tq, "Cannot specify an overcommit attribute "
                        "and use this kind of target queue");
            }
        } else {
            if (overcommit == _dispatch_queue_attr_overcommit_unspecified) {
                // Serial queues default to overcommit!
                overcommit = dqai.dqai_concurrent ?
                        _dispatch_queue_attr_overcommit_disabled :
                        _dispatch_queue_attr_overcommit_enabled;
            }
        }
        
        // 初始化队列默认传了DISPATCH_TARGET_QUEUE_DEFAULT,也就是null,所以进入if语句。
        if (!tq) {
            // 获取一个管理自己队列的root队列
            tq = _dispatch_get_root_queue(
                    qos == DISPATCH_QOS_UNSPECIFIED ? DISPATCH_QOS_DEFAULT : qos,
                    overcommit == _dispatch_queue_attr_overcommit_enabled)->_as_dq;
            if (unlikely(!tq)) {
                DISPATCH_CLIENT_CRASH(qos, "Invalid queue attribute");
            }
        }
    
        //
        // Step 2: Initialize the queue
        //
    
        if (legacy) {
            // if any of these attributes is specified, use non legacy classes
            if (dqai.dqai_inactive || dqai.dqai_autorelease_frequency) {
                legacy = false;
            }
        }
    
        const void *vtable;
        dispatch_queue_flags_t dqf = legacy ? DQF_MUTABLE : 0;
        if (dqai.dqai_concurrent) {
            vtable = DISPATCH_VTABLE(queue_concurrent);
        } else {
            vtable = DISPATCH_VTABLE(queue_serial);
        }
        switch (dqai.dqai_autorelease_frequency) {
        case DISPATCH_AUTORELEASE_FREQUENCY_NEVER:
            dqf |= DQF_AUTORELEASE_NEVER;
            break;
        case DISPATCH_AUTORELEASE_FREQUENCY_WORK_ITEM:
            dqf |= DQF_AUTORELEASE_ALWAYS;
            break;
        }
        if (label) {
            const char *tmp = _dispatch_strdup_if_mutable(label);
            if (tmp != label) {
                dqf |= DQF_LABEL_NEEDS_FREE;
                label = tmp;
            }
        }
    
        dispatch_lane_t dq = _dispatch_object_alloc(vtable,
                sizeof(struct dispatch_lane_s));
        _dispatch_queue_init(dq, dqf, dqai.dqai_concurrent ?
                DISPATCH_QUEUE_WIDTH_MAX : 1, DISPATCH_QUEUE_ROLE_INNER |
                (dqai.dqai_inactive ? DISPATCH_QUEUE_INACTIVE : 0));
    
        dq->dq_label = label;
        dq->dq_priority = _dispatch_priority_make((dispatch_qos_t)dqai.dqai_qos,
                dqai.dqai_relpri);
        if (overcommit == _dispatch_queue_attr_overcommit_enabled) {
            dq->dq_priority |= DISPATCH_PRIORITY_FLAG_OVERCOMMIT;
        }
        if (!dqai.dqai_inactive) {
            _dispatch_queue_priority_inherit_from_target(dq, tq);
            _dispatch_lane_inherit_wlh_from_target(dq, tq);
        }
        _dispatch_retain(tq);
        dq->do_targetq = tq;
        _dispatch_object_debug(dq, "%s", __func__);
        return _dispatch_trace_queue_create(dq)._dq;
    }
    
    static inline dispatch_queue_global_t
    _dispatch_get_root_queue(dispatch_qos_t qos, bool overcommit)
    {
        if (unlikely(qos < DISPATCH_QOS_MIN || qos > DISPATCH_QOS_MAX)) {
            DISPATCH_CLIENT_CRASH(qos, "Corrupted priority");
        }
        return &_dispatch_root_queues[2 * (qos - 1) + overcommit];
    }
    

    相关文章

      网友评论

          本文标题:GCD源码分析

          本文链接:https://www.haomeiwen.com/subject/ycgobktx.html