skynet.sleep分析

官方文檔

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分析

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章