Fix skynet.require recursion issue, See
@@ -17,21 +17,76 @@ local context = {
do
local require = _G.require
- function M.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(...)
- else
+ 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
+ -- 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
+ print ("Waiting " .. name)
+ skynet.wait(co)
+ local m = loaded[name]
+ print ("Waiting OK : " .. tostring(m))
+ if m == nil then
+ error(string.format("require %s failed", name))
+ end
+ return m
+ end
+
+ loading_queue = {}
+ loading[name] = loading_queue
+
local old_init_list = context[co]
local init_list = {}
context[co] = init_list
- local ret = require(...)
+
+ -- We should call modfunc in lua, because modfunc may yield by calling M.require recursive.
+ local m = modfunc(name, filename)
+
for _, f in ipairs(init_list) do
f()
end
context[co] = old_init_list
- return ret
+
+ if m == nil then
+ m = true
end
+
+ package.loaded[name] = m
+
+ 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
+
+ return m
end
end
