skynet.sleep分析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/gneveek/article/details/78944807

官方文档

skynet.sleep(ti) 将当前 coroutine 挂起 ti 个单位时间。一个单位是 1/100 秒。它是向框架注册一个定时器实现的。框架会在 ti 时间后,发送一个定时器消息来唤醒这个 coroutine 。这是一个阻塞 API 。它的返回值会告诉你是时间到了(返回nil),还是被 skynet.wakeup 唤醒 (返回 “BREAK”)。

Code

function skynet.sleep(ti)
    local session = c.intcommand("TIMEOUT",ti)
    assert(session)
    local succ, ret = coroutine_yield("SLEEP", session)
    sleep_session[coroutine.running()] = nil
    if succ then
        return
    end
    if ret == "BREAK" then
        return "BREAK"
    else
        error(ret)
    end
end

c.intcommand(“TIMEOUT”,ti)会调到C里面的这个函数。

static const char *
cmd_timeout(struct skynet_context * context, const char * param) {
    char * session_ptr = NULL;
    int ti = strtol(param, &session_ptr, 10);
    int session = skynet_context_newsession(context);
    skynet_timeout(context->handle, ti, session);
    sprintf(context->result, "%d", session);
    return context->result;
}

这里会调用skynet_timeout注册一个定时器,当时间到后,就会给context->handle这个服务发送一个类型为PTYPE_RESPONSE的消息来唤醒它。代码如下:

int
skynet_timeout(uint32_t handle, int time, int session) {
    if (time <= 0) {//如果时间<=0,直接发消息
        struct skynet_message message;
        message.source = 0;
        message.session = session;
        message.data = NULL;
        message.sz = (size_t)PTYPE_RESPONSE << MESSAGE_TYPE_SHIFT;

        if (skynet_context_push(handle, &message)) {
            return -1;
        }
    } else {//添加定时器
        struct timer_event event;
        event.handle = handle;
        event.session = session;
        timer_add(TI, &event, sizeof(event), time);
    }

    return session;
}

时间到后会调到下面这个C函数:

static inline void
dispatch_list(struct timer_node *current) {
    do {
        struct timer_event * event = (struct timer_event *)(current+1);
        struct skynet_message message;
        message.source = 0;
        message.session = event->session;
        message.data = NULL;
        message.sz = (size_t)PTYPE_RESPONSE << MESSAGE_TYPE_SHIFT;

        skynet_context_push(event->handle, &message);

        struct timer_node * temp = current;
        current=current->next;
        skynet_free(temp);  
    } while (current);
}

可以看到,给注册这个定时器的服务发了个PTYPE_RESPONSE的消息。

之后就跟skynet.call + skynet.ret的流程一样了:

local function raw_dispatch_message(prototype, msg, sz, session, source)
    -- skynet.PTYPE_RESPONSE = 1, read skynet.h
    if prototype == 1 then
        local co = session_id_coroutine[session]
        if co == "BREAK" then
            session_id_coroutine[session] = nil
        elseif co == nil then
            unknown_response(session, source, msg, sz)
        else
            session_id_coroutine[session] = nil
            suspend(co, coroutine_resume(co, true, msg, sz))
        end
    else
    ...

消息回调这边特殊处理PTYPE_RESPONSE的消息,调用coroutine.resume唤醒协程。


可以看到上面那段代码里面有个 if co == "BREAK" 的判断,这是干嘛的呢?
其实云风文档里已经说了,是skynet.wakeup搞的鬼。

详细分析请看:skynet.wakeup分析

猜你喜欢

转载自blog.csdn.net/gneveek/article/details/78944807