114 lines
2.5 KiB
Lua
114 lines
2.5 KiB
Lua
-- skynet module two-step initialize . When you require a skynet module :
|
|
-- 1. Run module main function as official lua module behavior.
|
|
-- 2. Run the functions register by skynet.init() during the step 1,
|
|
-- unless calling `require` in main thread .
|
|
-- If you call `require` in main thread ( service main function ), the functions
|
|
-- registered by skynet.init() do not execute immediately, they will be executed
|
|
-- by skynet.start() before start function.
|
|
|
|
local M = {}
|
|
|
|
local mainthread, ismain = coroutine.running()
|
|
assert(ismain, "skynet.require must initialize in main thread")
|
|
|
|
local context = {
|
|
[mainthread] = {},
|
|
}
|
|
|
|
do
|
|
local require = _G.require
|
|
local loaded = package.loaded
|
|
local loading = {}
|
|
|
|
function M.require(name)
|
|
local m = loaded[name]
|
|
if m ~= nil then
|
|
return m
|
|
end
|
|
|
|
local co, main = coroutine.running()
|
|
if main then
|
|
return require(name)
|
|
end
|
|
|
|
local filename = package.searchpath(name, package.path)
|
|
if not filename then
|
|
return require(name)
|
|
end
|
|
|
|
local modfunc = loadfile(filename)
|
|
if not modfunc then
|
|
return require(name)
|
|
end
|
|
|
|
local loading_queue = loading[name]
|
|
if loading_queue then
|
|
assert(loading_queue.co ~= co, "circular dependency")
|
|
-- Module is in the init process (require the same mod at the same time in different coroutines) , waiting.
|
|
local skynet = require "skynet"
|
|
loading_queue[#loading_queue+1] = co
|
|
skynet.wait(co)
|
|
local m = loaded[name]
|
|
if m == nil then
|
|
error(string.format("require %s failed", name))
|
|
end
|
|
return m
|
|
end
|
|
|
|
loading_queue = {co = co}
|
|
loading[name] = loading_queue
|
|
|
|
local old_init_list = context[co]
|
|
local init_list = {}
|
|
context[co] = init_list
|
|
|
|
-- We should call modfunc in lua, because modfunc may yield by calling M.require recursive.
|
|
local function execute_module()
|
|
local m = modfunc(name, filename)
|
|
|
|
for _, f in ipairs(init_list) do
|
|
f()
|
|
end
|
|
|
|
if m == nil then
|
|
m = true
|
|
end
|
|
|
|
loaded[name] = m
|
|
end
|
|
|
|
local ok, err = xpcall(execute_module, debug.traceback)
|
|
|
|
context[co] = old_init_list
|
|
|
|
local waiting = #loading_queue
|
|
if waiting > 0 then
|
|
local skynet = require "skynet"
|
|
for i = 1, waiting do
|
|
skynet.wakeup(loading_queue[i])
|
|
end
|
|
end
|
|
loading[name] = nil
|
|
|
|
if ok then
|
|
return loaded[name]
|
|
else
|
|
error(err)
|
|
end
|
|
end
|
|
end
|
|
|
|
function M.init_all()
|
|
for _, f in ipairs(context[mainthread]) do
|
|
f()
|
|
end
|
|
context[mainthread] = nil
|
|
end
|
|
|
|
function M.init(f)
|
|
assert(type(f) == "function")
|
|
local co = coroutine.running()
|
|
table.insert(context[co], f)
|
|
end
|
|
|
|
return M |