mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-16 18:55:03 -04:00
Disabling Lua GC while persisting and unpersisting, might help with native crash.
This commit is contained in:
parent
891efc924e
commit
2c87f6059a
@ -41,6 +41,25 @@ local function spcall(...)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function sgc(self)
|
||||||
|
local oldDeadline, oldHitDeadline = deadline, hitDeadline
|
||||||
|
local mt = debug.getmetatable(self)
|
||||||
|
mt = rawget(mt, "mt")
|
||||||
|
local gc = rawget(mt, "__gc")
|
||||||
|
if type(gc) ~= "function" then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local co = coroutine.create(gc)
|
||||||
|
debug.sethook(co, checkDeadline, "", hookInterval)
|
||||||
|
deadline, hitDeadline = math.min(oldDeadline, computer.realTime() + 0.5), true
|
||||||
|
local result, reason = coroutine.resume(co, self)
|
||||||
|
debug.sethook(co)
|
||||||
|
deadline, hitDeadline = oldDeadline, oldHitDeadline
|
||||||
|
if not result then
|
||||||
|
error(reason, 0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
--[[ This is the global environment we make available to userland programs. ]]
|
--[[ This is the global environment we make available to userland programs. ]]
|
||||||
-- You'll notice that we do a lot of wrapping of native functions and adding
|
-- You'll notice that we do a lot of wrapping of native functions and adding
|
||||||
-- parameter checks in those wrappers. This is to avoid errors from the host
|
-- parameter checks in those wrappers. This is to avoid errors from the host
|
||||||
@ -53,8 +72,15 @@ sandbox = {
|
|||||||
error = error,
|
error = error,
|
||||||
_G = nil, -- see below
|
_G = nil, -- see below
|
||||||
getmetatable = function(t)
|
getmetatable = function(t)
|
||||||
if type(t) == "string" then return nil end
|
if type(t) == "string" then -- don't allow messing with the string mt
|
||||||
return getmetatable(t)
|
return nil
|
||||||
|
end
|
||||||
|
local result = getmetatable(t)
|
||||||
|
-- check if we have a wrapped __gc using mt
|
||||||
|
if type(result) == "table" and rawget(result, "__gc") == sgc then
|
||||||
|
result = rawget(result, "mt")
|
||||||
|
end
|
||||||
|
return result
|
||||||
end,
|
end,
|
||||||
ipairs = ipairs,
|
ipairs = ipairs,
|
||||||
load = function(ld, source, mode, env)
|
load = function(ld, source, mode, env)
|
||||||
@ -81,29 +107,21 @@ sandbox = {
|
|||||||
if type(mt) ~= "table" then
|
if type(mt) ~= "table" then
|
||||||
return setmetatable(t, mt)
|
return setmetatable(t, mt)
|
||||||
end
|
end
|
||||||
local gc = rawget(mt, "__gc")
|
if type(rawget(mt, "__gc")) == "function" then
|
||||||
if type(gc) == "function" then
|
|
||||||
-- For all user __gc functions we enforce a much tighter deadline.
|
-- For all user __gc functions we enforce a much tighter deadline.
|
||||||
-- This is because these functions may be called from the main
|
-- This is because these functions may be called from the main
|
||||||
-- thread under certain circumstanced (such as when saving the world),
|
-- thread under certain circumstanced (such as when saving the world),
|
||||||
-- which can lead to noticeable lag if the __gc function behaves badly.
|
-- which can lead to noticeable lag if the __gc function behaves badly.
|
||||||
rawset(mt, "__gc", function(self)
|
local sbmt = {} -- sandboxed metatable. only for __gc stuff, so it's
|
||||||
local oldDeadline, oldHitDeadline = deadline, hitDeadline
|
-- kinda ok to have a shallow copy instead... meh.
|
||||||
local co = coroutine.create(gc)
|
for k, v in pairs(mt) do
|
||||||
debug.sethook(co, checkDeadline, "", hookInterval)
|
sbmt[k] = v
|
||||||
deadline, hitDeadline = math.min(oldDeadline, computer.realTime() + 0.5), true
|
|
||||||
local result, reason = coroutine.resume(co, self)
|
|
||||||
debug.sethook(co)
|
|
||||||
checkDeadline()
|
|
||||||
deadline, hitDeadline = oldDeadline, oldHitDeadline
|
|
||||||
if not result then
|
|
||||||
error(reason, 0)
|
|
||||||
end
|
end
|
||||||
end)
|
sbmt.mt = mt
|
||||||
|
sbmt.__gc = sgc
|
||||||
|
mt = sbmt
|
||||||
end
|
end
|
||||||
local result = setmetatable(t, mt)
|
return setmetatable(t, mt)
|
||||||
rawset(mt, "__gc", gc)
|
|
||||||
return result
|
|
||||||
end,
|
end,
|
||||||
tonumber = tonumber,
|
tonumber = tonumber,
|
||||||
tostring = tostring,
|
tostring = tostring,
|
||||||
|
@ -347,9 +347,15 @@ class NativeLuaArchitecture(val machine: api.machine.Machine) extends Architectu
|
|||||||
for (api <- apis) {
|
for (api <- apis) {
|
||||||
api.load(nbt)
|
api.load(nbt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try lua.gc(LuaState.GcAction.COLLECT, 0) catch {
|
||||||
|
case t: Throwable =>
|
||||||
|
OpenComputers.log.warning(s"Error cleaning up loaded computer @ (${machine.owner.x}, ${machine.owner.y}, ${machine.owner.z}). This either means the server is badly overloaded or a user created an evil __gc method, accidentally or not.")
|
||||||
|
machine.crash("error in garbage collector, most likely __gc method timed out")
|
||||||
|
}
|
||||||
} catch {
|
} catch {
|
||||||
case e: LuaRuntimeException =>
|
case e: LuaRuntimeException =>
|
||||||
OpenComputers.log.warning("Could not unpersist computer.\n" + e.toString + (if (e.getLuaStackTrace.isEmpty) "" else "\tat " + e.getLuaStackTrace.mkString("\n\tat ")))
|
OpenComputers.log.warning(s"Could not unpersist computer @ (${machine.owner.x}, ${machine.owner.y}, ${machine.owner.z}).\n${e.toString}" + (if (e.getLuaStackTrace.isEmpty) "" else "\tat " + e.getLuaStackTrace.mkString("\n\tat ")))
|
||||||
machine.stop()
|
machine.stop()
|
||||||
machine.start()
|
machine.start()
|
||||||
}
|
}
|
||||||
@ -386,6 +392,12 @@ class NativeLuaArchitecture(val machine: api.machine.Machine) extends Architectu
|
|||||||
for (api <- apis) {
|
for (api <- apis) {
|
||||||
api.save(nbt)
|
api.save(nbt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try lua.gc(LuaState.GcAction.COLLECT, 0) catch {
|
||||||
|
case t: Throwable =>
|
||||||
|
OpenComputers.log.warning(s"Error cleaning up loaded computer @ (${machine.owner.x}, ${machine.owner.y}, ${machine.owner.z}). This either means the server is badly overloaded or a user created an evil __gc method, accidentally or not.")
|
||||||
|
machine.crash("error in garbage collector, most likely __gc method timed out")
|
||||||
|
}
|
||||||
} catch {
|
} catch {
|
||||||
case e: LuaRuntimeException =>
|
case e: LuaRuntimeException =>
|
||||||
OpenComputers.log.warning(s"Could not persist computer @ (${machine.owner.x}, ${machine.owner.y}, ${machine.owner.z}).\n${e.toString}" + (if (e.getLuaStackTrace.isEmpty) "" else "\tat " + e.getLuaStackTrace.mkString("\n\tat ")))
|
OpenComputers.log.warning(s"Could not persist computer @ (${machine.owner.x}, ${machine.owner.y}, ${machine.owner.z}).\n${e.toString}" + (if (e.getLuaStackTrace.isEmpty) "" else "\tat " + e.getLuaStackTrace.mkString("\n\tat ")))
|
||||||
|
@ -122,6 +122,8 @@ class PersistenceAPI(owner: NativeLuaArchitecture) extends NativeLuaAPI(owner) {
|
|||||||
def persist(index: Int): Array[Byte] = {
|
def persist(index: Int): Array[Byte] = {
|
||||||
if (Settings.get.allowPersistence) {
|
if (Settings.get.allowPersistence) {
|
||||||
configure()
|
configure()
|
||||||
|
try {
|
||||||
|
lua.gc(LuaState.GcAction.STOP, 0)
|
||||||
lua.getGlobal("eris") // ... eris
|
lua.getGlobal("eris") // ... eris
|
||||||
lua.getField(-1, "persist") // ... eris persist
|
lua.getField(-1, "persist") // ... eris persist
|
||||||
if (lua.isFunction(-1)) {
|
if (lua.isFunction(-1)) {
|
||||||
@ -143,12 +145,18 @@ class PersistenceAPI(owner: NativeLuaArchitecture) extends NativeLuaAPI(owner) {
|
|||||||
} // ... eris :(
|
} // ... eris :(
|
||||||
lua.pop(2) // ...
|
lua.pop(2) // ...
|
||||||
}
|
}
|
||||||
|
finally {
|
||||||
|
lua.gc(LuaState.GcAction.RESTART, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
Array[Byte]()
|
Array[Byte]()
|
||||||
}
|
}
|
||||||
|
|
||||||
def unpersist(value: Array[Byte]): Boolean = {
|
def unpersist(value: Array[Byte]): Boolean = {
|
||||||
if (Settings.get.allowPersistence) {
|
if (Settings.get.allowPersistence) {
|
||||||
configure()
|
configure()
|
||||||
|
try {
|
||||||
|
lua.gc(LuaState.GcAction.STOP, 0)
|
||||||
lua.getGlobal("eris") // ... eris
|
lua.getGlobal("eris") // ... eris
|
||||||
lua.getField(-1, "unpersist") // ... eris unpersist
|
lua.getField(-1, "unpersist") // ... eris unpersist
|
||||||
if (lua.isFunction(-1)) {
|
if (lua.isFunction(-1)) {
|
||||||
@ -161,6 +169,10 @@ class PersistenceAPI(owner: NativeLuaArchitecture) extends NativeLuaAPI(owner) {
|
|||||||
} // ... :(
|
} // ... :(
|
||||||
lua.pop(1)
|
lua.pop(1)
|
||||||
}
|
}
|
||||||
|
finally {
|
||||||
|
lua.gc(LuaState.GcAction.RESTART, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user