美文网首页RunLoop
RunLoop的wakeup port

RunLoop的wakeup port

作者: tom555cat | 来源:发表于2018-12-04 00:41 被阅读4次

RunLoop的wakeup port起什么作用?

在查看RunLoop内容时,会显示wakeup port,如下所示:

(lldb) po [NSRunLoop currentRunLoop]
<CFRunLoop 0x6000001eed00 [0x10abbbc80]>{wakeup port = 0x2503, stopped = false, ignoreWakeUps = false, 
current mode = kCFRunLoopDefaultMode,
common modes = <CFBasicHash 0x60000024f990 [0x10abbbc80]>{type = mutable set, count = 2,
entries =>
    0 : <CFString 0x10bf2be88 [0x10abbbc80]>{contents = "UITrackingRunLoopMode"}
    2 : <CFString 0x10ab91818 [0x10abbbc80]>{contents = "kCFRunLoopDefaultMode"}
}

我们知道RunLoop中的Source 1是基于mach port的,但是RunLoop的wakeup port是做什么的?

由于RunLoop在睡眠状态下是通过mach port唤醒的,如CFRunLoop.c的__CFRunLoopRun方法中下面代码所示:

do {
    if (kCFUseCollectableAllocator) {
        // objc_clear_stack(0);
        // <rdar://problem/16393959>
        memset(msg_buffer, 0, sizeof(msg_buffer));
    }
    msg = (mach_msg_header_t *)msg_buffer;
    
    // 处理唤醒的mach消息
    __CFRunLoopServiceMachPort(waitSet, &msg, sizeof(msg_buffer), &livePort, poll ? 0 : TIMEOUT_INFINITY, &voucherState, &voucherCopy);
    
    if (modeQueuePort != MACH_PORT_NULL && livePort == modeQueuePort) {
        // Drain the internal queue. If one of the callout blocks sets the timerFired flag, break out and service the timer.
        while (_dispatch_runloop_root_queue_perform_4CF(rlm->_queue));
        if (rlm->_timerFired) {
            // Leave livePort as the queue port, and service timers below
            rlm->_timerFired = false;
            break;
        } else {
            if (msg && msg != (mach_msg_header_t *)msg_buffer) free(msg);
        }
    } else {
        // Go ahead and leave the inner loop.
        break;
    }
} while (1);

由于RunLoop的唤醒是通过mach port唤醒,而Source 0不是基于mach port的source,激活Source 0的操作需要如下两个步骤,缺一不可:

CFRunLoopSourceSignal(source0);
CFRunLoopWakeUp(runLoop);

那么是否是在CFRunLoopWakeUp(runLoop)中通过mach_msg发送了消息?查看CFRunLoopWakeUp的一部分汇编,在其中发现调用了mach_msg函数,发送(或接收)了消息:

0x1101a42d2 <+194>: mov    qword ptr [rbp - 0x120], rcx
0x1101a42d9 <+201>: mov    dword ptr [rbp - 0x118], eax
0x1101a42df <+207>: mov    dword ptr [rbp - 0x114], 0x0
0x1101a42e9 <+217>: mov    dword ptr [rbp - 0x10c], 0x0
0x1101a42f3 <+227>: mov    dword ptr [rsp], 0x0
0x1101a42fa <+234>: lea    r15, [rbp - 0x120]
0x1101a4301 <+241>: mov    esi, 0x11
0x1101a4306 <+246>: mov    edx, 0x18
0x1101a430b <+251>: xor    ecx, ecx
0x1101a430d <+253>: xor    r8d, r8d
0x1101a4310 <+256>: xor    r9d, r9d
0x1101a4313 <+259>: mov    rdi, r15
0x1101a4316 <+262>: call   0x1102f051e        ; symbol stub for: mach_msg

在执行完mach_msg之后,查看mach_msg的第一个参数mach_msg_header_t *msg来确认发送的内容,

(lldb) memory read -s8 -c3 -fx $r15
0x70000fa72ae0: 0x0000001800000013 0x0000000000002503
0x70000fa72af0: 0x000000000fa72b30

mach_msg_header_t的存储结构如下所示
typedef struct
{
mach_msg_bits_t msgh_bits; // unsigned int
mach_msg_size_t msgh_size; // unsigned int
mach_port_t msgh_remote_port; // unsigned int
mach_port_t msgh_local_port; // unsigned int
mach_port_name_t msgh_voucher_port; // mach_port_name_t
mach_msg_id_t msgh_id; // int
} mach_msg_header_t;

观察这一段“0x0000000000002503”,由于存储方式是小端存储,所以msgh_remote_port对应的内容为0x2503,正好是runLoop的wakeup port。

再查看mach_msg的第二个参数mach_msg_option_t option,第二个参数的值可以根据"0x1101a4301 <+241>: mov esi, 0x11"这条指令获得,所以option值为0x11,是由"define MACH_SEND_MSG 0x00000001"和"#define MACH_SEND_TIMEOUT 0x00000010"参数或运算的结果,意思是发送消息。

所以CFRunLoopWakeUp(runLoop)确实向runLoop的wakeup port发送了消息从而唤醒了runLoop,执行Source 0的回调函数。

相关文章

  • RunLoop的wakeup port

    RunLoop的wakeup port起什么作用? 在查看RunLoop内容时,会显示wakeup port,如下...

  • RunLoop 的坑

    由于项目中, 使用 runLoop.run()方法, 当执行 remove port 和CFRunLoopStop...

  • runloop中将一个任务放到第二次runloop中执行

    runloop中将一个任务放到第二次runloop中执行:利用socket/port做一些事情(封装一个sourc...

  • iOS 常驻线程

    1.创建子线程并开启线程2.给当前runloop添加port并运行runloop3.将新任务添加到已休眠的线程

  • Runloop--底层实现

    从上面代码可以看到,RunLoop 的核心是基于 mach port 的,其进入休眠时调用的函数是 mach_ms...

  • Runloop原理图

    RunLoop的底层是基于mach_port,可用于底层消息交换,包括进程,线程间的通信等,通过mach_msg(...

  • 响应链

    等待 我们都知道runloop在没有事件的时候会处于休眠状态。 这个函数等待接收mach port消息。 iOS中...

  • 反序列化中__wakeup()函数漏洞

    __wakeup()是用在反序列化操作中。unserialize()会检查存在一个__wakeup()方法。如果存...

  • xctf-unserialize3

    给了我一段代码,php,_wakeup(),反序列化过程中,会调用这个wakeup。 先上代码: 所以要有反序列化...

  • 2019-05-27

    人na 全世界都在催着你长大 你确以为自己还在童话里 都在不断敲打你 让你醒过来 wakeup wakeup NO...

网友评论

    本文标题:RunLoop的wakeup port

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