官方文檔
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分析