DevOps 实例解析Runloop

iamapc · March 23, 2020 · 10 hits

前文

你是否厌倦了阅读枯燥的源码?本文试图通过运行 App 实例来分析 Runloop 的内在构成。

首先,我们需要拷贝部分源码过来,可以粘贴到你的.m 文件上面:


typedef struct __CFRuntimeBase {
    uintptr_t _cfisa;
    uint8_t _cfinfo[4];
#if __LP64__
    uint32_t _rc;
#endif
} CFRuntimeBase;

typedef struct ___CFPortSet {
    uint16_t    used;
    uint16_t    size;
    mach_port_t *handles;
    uint32_t lock;        // insert and remove must be thread safe, like the Mach calls
} *__CFPortSet;

struct _CFRunLoopTimer {
    CFRuntimeBase _base;
    uint16_t _bits;
    pthread_mutex_t _lock;
    CFRunLoopRef _runLoop;
    CFMutableSetRef _rlModes;
    CFAbsoluteTime _nextFireDate;
    CFTimeInterval _interval;        /* immutable */
    CFTimeInterval _tolerance;          /* mutable */
    uint64_t _fireTSR;            /* TSR units */
    CFIndex _order;            /* immutable */
    CFRunLoopTimerCallBack _callout;    /* immutable */
    CFRunLoopTimerContext _context;    /* immutable, except invalidation */
};

struct _CFRunLoopMode {
    CFRuntimeBase _base;
    pthread_mutex_t _lock;    /* must have the run loop locked before locking this */
    CFStringRef _name;
    Boolean _stopped;
    char _padding[3];
    CFMutableSetRef _sources0;
    CFMutableSetRef _sources1;
    CFMutableArrayRef _observers;
    CFMutableArrayRef _timers;
    CFMutableDictionaryRef _portToV1SourceMap;
    __CFPortSet _portSet;
    CFIndex _observerMask;
#if USE_DISPATCH_SOURCE_FOR_TIMERS
    dispatch_source_t _timerSource;
    dispatch_queue_t _queue;
    Boolean _timerFired; // set to true by the source when a timer has fired
    Boolean _dispatchTimerArmed;
#endif
#if USE_MK_TIMER_TOO
    mach_port_t _timerPort;
    Boolean _mkTimerArmed;
#endif
#if DEPLOYMENT_TARGET_WINDOWS
    DWORD _msgQMask;
    void (*_msgPump)(void);
#endif
    uint64_t _timerSoftDeadline; /* TSR */
    uint64_t _timerHardDeadline; /* TSR */
};



struct _CFRunLoop {
    CFRuntimeBase _base;
    pthread_mutex_t _lock;            /* locked for accessing mode list */
    mach_port_t _wakeUpPort;            // used for CFRunLoopWakeUp
    Boolean _unused;
    volatile uint32_t *_perRunData;              // reset for runs of the run loop
    pthread_t _pthread;
    uint32_t _winthread;
    CFMutableSetRef _commonModes;
    CFMutableSetRef _commonModeItems;
    struct _CFRunLoopMode *_currentMode;
    CFMutableSetRef _modes;
    struct _block_item *_blocks_head;
    struct _block_item *_blocks_tail;
    CFAbsoluteTime _runTime;
    CFAbsoluteTime _sleepTime;
    CFTypeRef _counterpart;
};


struct __CFRunLoopSource {
    CFRuntimeBase _base;
    uint32_t _bits;
    pthread_mutex_t _lock;
    CFIndex _order;            /* immutable */
    CFMutableBagRef _runLoops;
    union {
        CFRunLoopSourceContext version0;    /* immutable, except invalidation */
        CFRunLoopSourceContext1 version1;    /* immutable, except invalidation */
    } _context;
};


通过这些数据结构,你大致了解或重温了 Runloop 的内存结构,下面开始运行分析。

1 主线程的 Runloop 分析

1.1 commonModes 的组成

通过打印 lp->_commonModes,输出如下:

_lp->_commonModes:
{(
    UITrackingRunLoopMode,
    kCFRunLoopDefaultMode
)}

新建的 Runloop 的 commonModes set 里默认添加了 kCFRunLoopDefaultMode, 现在我们看到主线程的 Runloop 还添加了 UITrackingRunLoopMode。

1.2 commonModeItems

我们知道 source,timer,observer 在 kCFRunLoopCommonModes 下添加到 Runloop 会被添加 commonModeItems 里,那么在主线程下,这里面有啥呢?

_lp->_commonModeItems:
{(
    <CFRunLoopSource 0x1c01798c0 [0x1b42c2538]>{signalled = No, valid = Yes, order = -1, context = <CFRunLoopSource context>{version = 0, info = 0x0, callout = <redacted> (0x183f5daec)}},
    <CFRunLoopSource 0x1c4179140 [0x1b42c2538]>{signalled = No, valid = Yes, order = -1, context = <CFRunLoopSource context>{version = 0, info = 0x1c414c290, callout = <redacted> (0x18c63a1b8)}},
    <CFRunLoopSource 0x1c4179380 [0x1b42c2538]>{signalled = No, valid = Yes, order = -2, context = <CFRunLoopSource context>{version = 0, info = 0x1c4259cb0, callout = <redacted> (0x18c63a1c0)}},
    <CFRunLoopSource 0x1c41792c0 [0x1b42c2538]>{signalled = No, valid = Yes, order = 0, context = <CFRunLoopSource MIG Server> {port = 13063, subsystem = 0x1ad95d5d0, context = 0x0}},
    <CFRunLoopSource 0x1c0179e00 [0x1b42c2538]>{signalled = No, valid = Yes, order = 0, context = <CFRunLoopSource MIG Server> {port = 42251, subsystem = 0x1ad977c68, context = 0x1c002aa80}},
    <CFRunLoopObserver 0x1c41350e0 [0x1b42c2538]>{valid = Yes, activities = 0x20, repeats = Yes, order = 0, callout = <redacted> (0x18bf494c4), context = <CFRunLoopObserver context 0x1c40c2a00>},
    <CFRunLoopSource 0x1c0179980 [0x1b42c2538]>{signalled = No, valid = Yes, order = -1, context = <CFRunLoopSource context>{version = 1, info = 0x4e03, callout = <redacted> (0x183f60238)}},
    <CFRunLoopSource 0x1c0179740 [0x1b42c2538]>{signalled = No, valid = Yes, order = 0, context = <CFRunLoopSource MIG Server> {port = 24595, subsystem = 0x1acc62ef0, context = 0x1c00a81c0}},
    <CFRunLoopSource 0x1c4179500 [0x1b42c2538]>{signalled = No, valid = Yes, order = 0, context = <CFRunLoopSource context>{version = 0, info = 0x1c40a8580, callout = <redacted> (0x1848e7bf0)}},
    <CFRunLoopObserver 0x1c4135720 [0x1b42c2538]>{valid = Yes, activities = 0xa0, repeats = Yes, order = 2000000, callout = <redacted> (0x1861c63f4), context = <CFRunLoopObserver context 0x0>},
    <CFRunLoopObserver 0x1c4135680 [0x1b42c2538]>{valid = Yes, activities = 0xa0, repeats = Yes, order = 2147483647, callout = <redacted> (0x18bf49650), context = <CFArray 0x1c425ab50 [0x1b42c2538]>{type = mutable-small, count = 1, values = (
    0 : <0x104854048>
)}},
    <CFRunLoopObserver 0x1c41355e0 [0x1b42c2538]>{valid = Yes, activities = 0x1, repeats = Yes, order = -2147483647, callout = <redacted> (0x18bf49650), context = <CFArray 0x1c425ab50 [0x1b42c2538]>{type = mutable-small, count = 1, values = (
    0 : <0x104854048>
)}},
    <CFRunLoopObserver 0x1c4135540 [0x1b42c2538]>{valid = Yes, activities = 0xa0, repeats = Yes, order = 2001000, callout = <redacted> (0x18bf494cc), context = <CFRunLoopObserver context 0x104c02ba0>},
    <CFRunLoopObserver 0x1c41354a0 [0x1b42c2538]>{valid = Yes, activities = 0xa0, repeats = Yes, order = 1999000, callout = <redacted> (0x18c07c9fc), context = <CFRunLoopObserver context 0x104c02ba0>}
)}

里面有 8 个 sources 和 6 个 observers,

1.3 modes

_lp->_modes:
{(
    <CFRunLoopMode 0x1c0188a20 [0x1b42c2538]>{name = UITrackingRunLoopMode, port set = 0x2b03, queue = 0x1c014c080, source = 0x1c0188af0 (not fired), timer port = 0x2d03, 
    sources0 = <CFBasicHash 0x1c024ed00 [0x1b42c2538]>{type = mutable set, count = 4,
entries =>
    0 : <CFRunLoopSource 0x1c01798c0 [0x1b42c2538]>{signalled = No, valid = Yes, order = -1, context = <CFRunLoopSource context>{version = 0, info = 0x0, callout = <redacted> (0x183f5daec)}}
    3 : <CFRunLoopSource 0x1c4179380 [0x1b42c2538]>{signalled = No, valid = Yes, order = -2, context = <CFRunLoopSource context>{version = 0, info = 0x1c4259cb0, callout = <redacted> (0x18c63a1c0)}}
    5 : <CFRunLoopSource 0x1c4179500 [0x1b42c2538]>{signalled = No, valid = Yes, order = 0, context = <CFRunLoopSource context>{version = 0, info = 0x1c40a8580, callout = <redacted> (0x1848e7bf0)}}
    6 : <CFRunLoopSource 0x1c4179140 [0x1b42c2538]>{signalled = No, valid = Yes, order = -1, context = <CFRunLoopSource context>{version = 0, info = 0x1c414c290, callout = <redacted> (0x18c63a1b8)}}
}
,
    sources1 = <CFBasicHash 0x1c024edc0 [0x1b42c2538]>{type = mutable set, count = 4,
entries =>
    0 : <CFRunLoopSource 0x1c0179980 [0x1b42c2538]>{signalled = No, valid = Yes, order = -1, context = <CFRunLoopSource context>{version = 1, info = 0x4e03, callout = <redacted> (0x183f60238)}}
    1 : <CFRunLoopSource 0x1c41792c0 [0x1b42c2538]>{signalled = No, valid = Yes, order = 0, context = <CFRunLoopSource MIG Server> {port = 13063, subsystem = 0x1ad95d5d0, context = 0x0}}
    4 : <CFRunLoopSource 0x1c0179740 [0x1b42c2538]>{signalled = No, valid = Yes, order = 0, context = <CFRunLoopSource MIG Server> {port = 24595, subsystem = 0x1acc62ef0, context = 0x1c00a81c0}}
    6 : <CFRunLoopSource 0x1c0179e00 [0x1b42c2538]>{signalled = No, valid = Yes, order = 0, context = <CFRunLoopSource MIG Server> {port = 42251, subsystem = 0x1ad977c68, context = 0x1c002aa80}}
}
,
    observers = (
    "<CFRunLoopObserver 0x1c41355e0 [0x1b42c2538]>{valid = Yes, activities = 0x1, repeats = Yes, order = -2147483647, callout = <redacted> (0x18bf49650), context = <CFArray 0x1c425ab50 [0x1b42c2538]>{type = mutable-small, count = 1, values = (nt0 : <0x104854048>n)}}",
    "<CFRunLoopObserver 0x1c41350e0 [0x1b42c2538]>{valid = Yes, activities = 0x20, repeats = Yes, order = 0, callout = <redacted> (0x18bf494c4), context = <CFRunLoopObserver context 0x1c40c2a00>}",
    "<CFRunLoopObserver 0x1c41354a0 [0x1b42c2538]>{valid = Yes, activities = 0xa0, repeats = Yes, order = 1999000, callout = <redacted> (0x18c07c9fc), context = <CFRunLoopObserver context 0x104c02ba0>}",
    "<CFRunLoopObserver 0x1c4135720 [0x1b42c2538]>{valid = Yes, activities = 0xa0, repeats = Yes, order = 2000000, callout = <redacted> (0x1861c63f4), context = <CFRunLoopObserver context 0x0>}",
    "<CFRunLoopObserver 0x1c4135540 [0x1b42c2538]>{valid = Yes, activities = 0xa0, repeats = Yes, order = 2001000, callout = <redacted> (0x18bf494cc), context = <CFRunLoopObserver context 0x104c02ba0>}",
    "<CFRunLoopObserver 0x1c4135680 [0x1b42c2538]>{valid = Yes, activities = 0xa0, repeats = Yes, order = 2147483647, callout = <redacted> (0x18bf49650), context = <CFArray 0x1c425ab50 [0x1b42c2538]>{type = mutable-small, count = 1, values = (nt0 : <0x104854048>n)}}"
),
    timers = (null),
    currently 545921038 (8000932696234) / soft deadline in: 7.68614003e+11 sec (@ -1) / hard deadline in: 7.68614003e+11 sec (@ -1)
},
,
    <CFRunLoopMode 0x1c0188bc0 [0x1b42c2538]>{name = GSEventReceiveRunLoopMode, port set = 0x5003, queue = 0x1c014c600, source = 0x1c0188c90 (not fired), timer port = 0x2e03, 
    sources0 = <CFBasicHash 0x1c024ee50 [0x1b42c2538]>{type = mutable set, count = 1,
entries =>
    0 : <CFRunLoopSource 0x1c01798c0 [0x1b42c2538]>{signalled = No, valid = Yes, order = -1, context = <CFRunLoopSource context>{version = 0, info = 0x0, callout = <redacted> (0x183f5daec)}}
}
,
    sources1 = <CFBasicHash 0x1c024edf0 [0x1b42c2538]>{type = mutable set, count = 1,
entries =>
    0 : <CFRunLoopSource 0x1c0179a40 [0x1b42c2538]>{signalled = No, valid = Yes, order = -1, context = <CFRunLoopSource context>{version = 1, info = 0x4e03, callout = <redacted> (0x183f60238)}}
}
,
    observers = (null),
    timers = (null),
    currently 545921038 (8000932859869) / soft deadline in: 7.68614003e+11 sec (@ -1) / hard deadline in: 7.68614003e+11 sec (@ -1)
},
,
    <CFRunLoopMode 0x1c0188540 [0x1b42c2538]>{name = kCFRunLoopDefaultMode, port set = 0x1803, queue = 0x1c014c3f0, source = 0x1c0188610 (not fired), timer port = 0x1903, 
    sources0 = <CFBasicHash 0x1c024ed60 [0x1b42c2538]>{type = mutable set, count = 4,
entries =>
    0 : <CFRunLoopSource 0x1c01798c0 [0x1b42c2538]>{signalled = No, valid = Yes, order = -1, context = <CFRunLoopSource context>{version = 0, info = 0x0, callout = <redacted> (0x183f5daec)}}
    3 : <CFRunLoopSource 0x1c4179380 [0x1b42c2538]>{signalled = No, valid = Yes, order = -2, context = <CFRunLoopSource context>{version = 0, info = 0x1c4259cb0, callout = <redacted> (0x18c63a1c0)}}
    5 : <CFRunLoopSource 0x1c4179500 [0x1b42c2538]>{signalled = No, valid = Yes, order = 0, context = <CFRunLoopSource context>{version = 0, info = 0x1c40a8580, callout = <redacted> (0x1848e7bf0)}}
    6 : <CFRunLoopSource 0x1c4179140 [0x1b42c2538]>{signalled = No, valid = Yes, order = -1, context = <CFRunLoopSource context>{version = 0, info = 0x1c414c290, callout = <redacted> (0x18c63a1b8)}}
}
,
    sources1 = <CFBasicHash 0x1c024ed90 [0x1b42c2538]>{type = mutable set, count = 4,
entries =>
    0 : <CFRunLoopSource 0x1c0179980 [0x1b42c2538]>{signalled = No, valid = Yes, order = -1, context = <CFRunLoopSource context>{version = 1, info = 0x4e03, callout = <redacted> (0x183f60238)}}
    1 : <CFRunLoopSource 0x1c41792c0 [0x1b42c2538]>{signalled = No, valid = Yes, order = 0, context = <CFRunLoopSource MIG Server> {port = 13063, subsystem = 0x1ad95d5d0, context = 0x0}}
    4 : <CFRunLoopSource 0x1c0179740 [0x1b42c2538]>{signalled = No, valid = Yes, order = 0, context = <CFRunLoopSource MIG Server> {port = 24595, subsystem = 0x1acc62ef0, context = 0x1c00a81c0}}
    6 : <CFRunLoopSource 0x1c0179e00 [0x1b42c2538]>{signalled = No, valid = Yes, order = 0, context = <CFRunLoopSource MIG Server> {port = 42251, subsystem = 0x1ad977c68, context = 0x1c002aa80}}
}
,
    observers = (
    "<CFRunLoopObserver 0x1c41355e0 [0x1b42c2538]>{valid = Yes, activities = 0x1, repeats = Yes, order = -2147483647, callout = <redacted> (0x18bf49650), context = <CFArray 0x1c425ab50 [0x1b42c2538]>{type = mutable-small, count = 1, values = (nt0 : <0x104854048>n)}}",
    "<CFRunLoopObserver 0x1c41350e0 [0x1b42c2538]>{valid = Yes, activities = 0x20, repeats = Yes, order = 0, callout = <redacted> (0x18bf494c4), context = <CFRunLoopObserver context 0x1c40c2a00>}",
    "<CFRunLoopObserver 0x1c41354a0 [0x1b42c2538]>{valid = Yes, activities = 0xa0, repeats = Yes, order = 1999000, callout = <redacted> (0x18c07c9fc), context = <CFRunLoopObserver context 0x104c02ba0>}",
    "<CFRunLoopObserver 0x1c4135720 [0x1b42c2538]>{valid = Yes, activities = 0xa0, repeats = Yes, order = 2000000, callout = <redacted> (0x1861c63f4), context = <CFRunLoopObserver context 0x0>}",
    "<CFRunLoopObserver 0x1c4135540 [0x1b42c2538]>{valid = Yes, activities = 0xa0, repeats = Yes, order = 2001000, callout = <redacted> (0x18bf494cc), context = <CFRunLoopObserver context 0x104c02ba0>}",
    "<CFRunLoopObserver 0x1c4135680 [0x1b42c2538]>{valid = Yes, activities = 0xa0, repeats = Yes, order = 2147483647, callout = <redacted> (0x18bf49650), context = <CFArray 0x1c425ab50 [0x1b42c2538]>{type = mutable-small, count = 1, values = (nt0 : <0x104854048>n)}}"
),
    timers = <CFArray 0x1c40a8760 [0x1b42c2538]>{type = mutable-small, count = 1, values = (
    0 : <CFRunLoopTimer 0x1c017c740 [0x1b42c2538]>{valid = Yes, firing = No, interval = 0, tolerance = 0, next fire date = 545920896 (-141.531507 @ 7997537050952), callout = (NSTimer) [_UISystemGestureGateGestureRecognizer _timeOut] (0x182b0337c / 0x18bf41d7c) (/System/Library/Frameworks/UIKit.framework/UIKit), context = <CFRunLoopTimer context 0x1c00317e0>}
)},
    currently 545921038 (8000932867535) / soft deadline in: 7.68614336e+11 sec (@ 7997537050952) / hard deadline in: 7.68614336e+11 sec (@ 7997537050952)
},
,
    <CFRunLoopMode 0x1c0189240 [0x1b42c2538]>{name = kCFRunLoopCommonModes, port set = 0xa907, queue = 0x1c014cb80, source = 0x1c0189310 (not fired), timer port = 0x5703, 
    sources0 = (null),
    sources1 = (null),
    observers = (null),
    timers = (null),
    currently 545921038 (8000933166060) / soft deadline in: 7.68614003e+11 sec (@ -1) / hard deadline in: 7.68614003e+11 sec (@ -1)
},

)}

归类分析我们发现 4 种 mode:

  1. UITrackingRunLoopMode。source0 有 4 个,source1 也有 4 个,observers 有 6 个,times 为空
  2. GSEventReceiveRunLoopMode。 source0 有 1 个,source1 也有 1 个,observers 为空,times 为空
  3. kCFRunLoopDefaultMode。 source0 有 4 个,source1 也有 4 个,observers 有 6 个,times 有 1 个,调用方法为[_UISystemGestureGateGestureRecognizer _timeOut]
  4. kCFRunLoopCommonModes。 数据基本为空。

仔细比较后我们发现:

  1. 同一个 source0<CFRunLoopSource 0x1c01798c0 [0x1b42c2538]>{signalled = No, valid = Yes, order = -1, context = <CFRunLoopSource context>{version = 0, info = 0x0, callout = <redacted> (0x183f5daec)}}被添加到了 3 个 mode 里,也就是所有 mode 里。
  2. commonModeItems 里的 sources 和 timers 就是 kCFRunLoopDefaultMode 里的 sources 和 timers。
  3. UITrackingRunLoopMode 和 kCFRunLoopDefaultMode 的 source0、source1 和 observers 都是一样的,那这两个有啥区别呢?难道只是名字不同?
<CFRunLoopMode 0x1c0188a20 [0x1b42c2538]>{name = UITrackingRunLoopMode, port set = 0x2b03, queue = 0x1c014c080, source = 0x1c0188af0 (not fired), timer port = 0x2d03, 
 <CFRunLoopMode 0x1c0188540 [0x1b42c2538]>{name = kCFRunLoopDefaultMode, port set = 0x1803, queue = 0x1c014c3f0, source = 0x1c0188610 (not fired), timer port = 0x1903,  

这两个 mode 所在队列和 timerSource 是不同的。

1.4 currentMode

<CFRunLoopMode 0x1c0188540 [0x1b42c2538]>{name = kCFRunLoopDefaultMode, port set = 0x1803, queue = 0x1c014c3f0, source = 0x1c0188610 (not fired), timer port = 0x1903, 

通常为默认的 kCFRunLoopDefaultMode。

2. 子线程的 Runloop 分析以 Timer 驱动

新建一个子线程如下:

- (void)main{
    
    NSTimer *timer = [NSTimer timerWithTimeInterval:6 target:self selector:@selector(say) userInfo:nil repeats:YES];
    timer.tolerance = 1;
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
    
    struct _CFRunLoop *lp  = CFRunLoopGetCurrent();
    _lp2 = lp;
    
    [[NSRunLoop currentRunLoop] runUntilDate:[NSDate distantFuture]];
    
}

2.1 commonModes 的组成

_lp2->_commonModes:
{(
    kCFRunLoopDefaultMode
)}

2.2 commonModeItems

为空,因为我们没有在 commonMode 下运行

2.3 modes

lp2->_modes:
{(
    <CFRunLoopMode 0x1c4187f90 [0x1b42c2538]>{name = kCFRunLoopDefaultMode, port set = 0xa203, queue = 0x1c41455f0, source = 0x1c4188060 (not fired), timer port = 0xa103, 
    sources0 = (null),
    sources1 = (null),
    observers = (null),
    timers = <CFArray 0x1c40a4b00 [0x1b42c2538]>{type = mutable-small, count = 1, values = (
    0 : <CFRunLoopTimer 0x1c41747c0 [0x1b42c2538]>{valid = Yes, firing = Yes, interval = 6, tolerance = 1, next fire date = 545924825 (-345.269891 @ 8091831849828), callout = (NSTimer) [ViewController say] (0x182b0337c / 0x10416a3e8) (/var/containers/Bundle/Application/97D498CA-C786-46B3-A8AB-0B3841AAE115/runloopDemo.app/runloopDemo), context = <CFRunLoopTimer context 0x1c4035ca0>}
)},
    currently 545925171 (8100117929266) / soft deadline in: 7.68613999e+11 sec (@ -1) / hard deadline in: 7.68613999e+11 sec (@ -1)
},

)}

果然只有一个我们当前运行的 kCFRunLoopDefaultMode,并且其 sources 为空,只有一个我们的 timer。

2.4 currentMode

<CFRunLoopMode 0x1c4187f90 [0x1b42c2538]>{name = kCFRunLoopDefaultMode, port set = 0xa203, queue = 0x1c41455f0, source = 0x1c4188060 (not fired), timer port = 0xa103, 

无需多讲,如上。

如果把 NSTimer 添加到 NSRunLoopCommonModes,上面的数据除了_commonModeItems 里多了这个 NSTimer,其他的都没变。

3. 子线程的 Runloop 分析以 Port 驱动

- (void)main{
    
    [[NSRunLoop currentRunLoop] addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
    struct _CFRunLoop *lp  = CFRunLoopGetCurrent();
    _lp2 = lp;
    [[NSRunLoop currentRunLoop] runUntilDate:[NSDate distantFuture]];
    
}

3.1 commonModes 的组成

_lp2->_commonModes:
{(
    kCFRunLoopDefaultMode
)}

3.2 commonModeItems

lp2->_commonModeItems:
{(
    <CFRunLoopSource 0x1c016c6c0 [0x1b42c2538]>{signalled = No, valid = Yes, order = 0, context = <CFRunLoopSource context>{version = 0, info = 0x1c000ef70, callout = <redacted> (0x182b01f98)}}
)}

这里有个 source0,在哪里添加进来的呢?读者可以想一想

3.3 modes

lp2->_modes:
{(
    <CFRunLoopMode 0x1c41893e0 [0x1b42c2538]>{name = kCFRunLoopDefaultMode, port set = 0x5d03, queue = 0x1c4146d50, source = 0x1c41894b0 (not fired), timer port = 0x5f03, 
    sources0 = <CFBasicHash 0x1c4457880 [0x1b42c2538]>{type = mutable set, count = 1,
entries =>
    1 : <CFRunLoopSource 0x1c016c6c0 [0x1b42c2538]>{signalled = No, valid = Yes, order = 0, context = <CFRunLoopSource context>{version = 0, info = 0x1c000ef70, callout = <redacted> (0x182b01f98)}}
}
,
    sources1 = <CFBasicHash 0x1c4457520 [0x1b42c2538]>{type = mutable set, count = 1,
entries =>
    0 : <CFRunLoopSource 0x1c416e7c0 [0x1b42c2538]>{signalled = No, valid = Yes, order = 200, context = <CFMachPort 0x1c4146e00 [0x1b42c2538]>{valid = Yes, port = 6003, source = 0x1c416e7c0, callout = __NSFireMachPort (0x182ae5a58), context = <CFMachPort context 0x1c44573d0>}}
}
,
    observers = (null),
    timers = (null),
    currently 545926298 (8127170276617) / soft deadline in: 7.68613998e+11 sec (@ -1) / hard deadline in: 7.68613998e+11 sec (@ -1)
},

)}

  1. 添加 NSMachPort 到 runloop,那么这个 mode 里不仅有 source0,还有 source1
  2. 说明 NSMachPort 是 source0 和 source1 的组合
  3. addPort 不是简单的 addSource, addPort 不在 runloop 的头文件里,说明 addPort 做了额外的处理

3.4 currentMode

<CFRunLoopMode 0x1c41893e0 [0x1b42c2538]>{name = kCFRunLoopDefaultMode, port set = 0x5d03, queue = 0x1c4146d50, source = 0x1c41894b0 (not fired), timer port = 0x5f03


No Reply at the moment.
You need to Sign in before reply, if you don't have an account, please Sign up first.