skynet.send
function skynet.send(addr, typename, ...)
local p = proto[typename]
return c.send(addr, p.id, 0 , p.pack(...))
end
skynet.call
function skynet.call(addr, typename, ...)
local p = proto[typename]
local session = c.send(addr, p.id , nil , p.pack(...)) -- 这里的第三个参数如果是nil就会ALLOCSESSION
if session == nil then
error("call to invalid address " .. skynet.address(addr))
end
return p.unpack(yield_call(addr, session))
end
lualib-src/lua-skynet.c
int type = luaL_checkinteger(L, idx_type+0); // idx_type =2
int session = 0;
if (lua_isnil(L,idx_type+1)) {
type |= PTYPE_TAG_ALLOCSESSION;
} else {
session = luaL_checkinteger(L,idx_type+1);
}
下面是yield_call,他在watching_session里面加了一个映射
local function yield_call(service, session)
watching_session[session] = service
session_id_coroutine[session] = running_thread
local succ, msg, sz = coroutine_yield "SUSPEND" --挂起在这里
watching_session[session] = nil
if not succ then
error "call failed"
end
return msg,sz
end
下面看下怎么把如上的挂起给唤醒,以使skynet.call流程继续
function skynet.ret(msg, sz)
msg = msg or ""
local co_session = session_coroutine_id[running_thread]
if co_session == nil then
error "No session"
end
session_coroutine_id[running_thread] = nil
if co_session == 0 then
if sz ~= nil then
c.trash(msg, sz)
end
return false
-- send dont need ret
end
local co_address = session_coroutine_address[running_thread]
local ret = c.send(co_address, skynet.PTYPE_RESPONSE, co_session, msg, sz)
if ret then
return true
elseif ret == false then
-- If the package is too large, returns false. so we should report error back
c.send(co_address, skynet.PTYPE_ERROR, co_session, "")
end
return false
end
可以看到最后是在raw_dispatch_message的第一层判断做处理
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
local tag = session_coroutine_tracetag[co]
if tag then c.trace(tag, "resume") end
session_id_coroutine[session] = nil
suspend(co, coroutine_resume(co, true, msg, sz, session))
end
else
...