-- You should use this module (skynet.coroutine) instead of origin lua coroutine in skynet framework local coroutine = coroutine -- origin lua coroutine module local coroutine_resume = coroutine.resume local coroutine_yield = coroutine.yield local coroutine_status = coroutine.status local coroutine_running = coroutine.running local select = select local skynetco = {} skynetco.isyieldable = coroutine.isyieldable skynetco.running = coroutine.running skynetco.status = coroutine.status local skynet_coroutines = setmetatable({}, { __mode = "kv" }) function skynetco.create(f) local co = coroutine.create(f) -- mark co as a skynet coroutine skynet_coroutines[co] = true return co end do -- begin skynetco.resume local profile = require "skynet.profile" -- skynet use profile.resume_co/yield_co instead of coroutine.resume/yield local skynet_resume = profile.resume_co local skynet_yield = profile.yield_co local function unlock(co, ...) skynet_coroutines[co] = true return ... end local function skynet_yielding(co, from, ...) skynet_coroutines[co] = false return unlock(co, skynet_resume(co, from, skynet_yield(from, ...))) end local function resume(co, from, ok, ...) if not ok then return ok, ... elseif coroutine_status(co) == "dead" then -- the main function exit skynet_coroutines[co] = nil return true, ... elseif (...) == "USER" then return true, select(2, ...) else -- blocked in skynet framework, so raise the yielding message return resume(co, from, skynet_yielding(co, from, ...)) end end -- record the root of coroutine caller (It should be a skynet thread) local coroutine_caller = setmetatable({} , { __mode = "kv" }) function skynetco.resume(co, ...) local co_status = skynet_coroutines[co] if not co_status then if co_status == false then -- is running return false, "cannot resume a skynet coroutine suspend by skynet framework" end if coroutine_status(co) == "dead" then -- always return false, "cannot resume dead coroutine" return coroutine_resume(co, ...) else return false, "cannot resume none skynet coroutine" end end local from = coroutine_running() local caller = coroutine_caller[from] or from coroutine_caller[co] = caller return resume(co, caller, coroutine_resume(co, ...)) end function skynetco.thread(co) co = co or coroutine_running() if skynet_coroutines[co] ~= nil then return coroutine_caller[co] , false else return co, true end end end -- end of skynetco.resume function skynetco.status(co) local status = coroutine.status(co) if status == "suspended" then if skynet_coroutines[co] == false then return "blocked" else return "suspended" end else return status end end function skynetco.yield(...) return coroutine_yield("USER", ...) end do -- begin skynetco.wrap local function wrap_co(ok, ...) if ok then return ... else error(...) end end function skynetco.wrap(f) local co = skynetco.create(function(...) return f(...) end) return function(...) return wrap_co(skynetco.resume(co, ...)) end end end -- end of skynetco.wrap return skynetco