mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-16 02:39:48 -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
|
||||
|
||||
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. ]]
|
||||
-- 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
|
||||
@ -53,8 +72,15 @@ sandbox = {
|
||||
error = error,
|
||||
_G = nil, -- see below
|
||||
getmetatable = function(t)
|
||||
if type(t) == "string" then return nil end
|
||||
return getmetatable(t)
|
||||
if type(t) == "string" then -- don't allow messing with the string mt
|
||||
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,
|
||||
ipairs = ipairs,
|
||||
load = function(ld, source, mode, env)
|
||||
@ -81,29 +107,21 @@ sandbox = {
|
||||
if type(mt) ~= "table" then
|
||||
return setmetatable(t, mt)
|
||||
end
|
||||
local gc = rawget(mt, "__gc")
|
||||
if type(gc) == "function" then
|
||||
if type(rawget(mt, "__gc")) == "function" then
|
||||
-- For all user __gc functions we enforce a much tighter deadline.
|
||||
-- This is because these functions may be called from the main
|
||||
-- thread under certain circumstanced (such as when saving the world),
|
||||
-- which can lead to noticeable lag if the __gc function behaves badly.
|
||||
rawset(mt, "__gc", function(self)
|
||||
local oldDeadline, oldHitDeadline = deadline, hitDeadline
|
||||
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)
|
||||
checkDeadline()
|
||||
deadline, hitDeadline = oldDeadline, oldHitDeadline
|
||||
if not result then
|
||||
error(reason, 0)
|
||||
end
|
||||
end)
|
||||
local sbmt = {} -- sandboxed metatable. only for __gc stuff, so it's
|
||||
-- kinda ok to have a shallow copy instead... meh.
|
||||
for k, v in pairs(mt) do
|
||||
sbmt[k] = v
|
||||
end
|
||||
sbmt.mt = mt
|
||||
sbmt.__gc = sgc
|
||||
mt = sbmt
|
||||
end
|
||||
local result = setmetatable(t, mt)
|
||||
rawset(mt, "__gc", gc)
|
||||
return result
|
||||
return setmetatable(t, mt)
|
||||
end,
|
||||
tonumber = tonumber,
|
||||
tostring = tostring,
|
||||
|
@ -258,7 +258,7 @@ class NativeLuaArchitecture(val machine: api.machine.Machine) extends Architectu
|
||||
}
|
||||
catch {
|
||||
case e: LuaRuntimeException =>
|
||||
OpenComputers.log.warning("Kernel crashed. This is a bug!\n" + e.toString + "\tat " + e.getLuaStackTrace.mkString("\n\tat "))
|
||||
OpenComputers.log.warning("Kernel crashed. This is a bug!\n" + e.toString + "\tat " + e.getLuaStackTrace.mkString("\n\tat "))
|
||||
new ExecutionResult.Error("kernel panic: this is a bug, check your log file and report it")
|
||||
case e: LuaGcMetamethodException =>
|
||||
if (e.getMessage != null) new ExecutionResult.Error("kernel panic:\n" + e.getMessage)
|
||||
@ -347,9 +347,15 @@ class NativeLuaArchitecture(val machine: api.machine.Machine) extends Architectu
|
||||
for (api <- apis) {
|
||||
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 {
|
||||
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.start()
|
||||
}
|
||||
@ -386,6 +392,12 @@ class NativeLuaArchitecture(val machine: api.machine.Machine) extends Architectu
|
||||
for (api <- apis) {
|
||||
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 {
|
||||
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 ")))
|
||||
|
@ -122,26 +122,32 @@ class PersistenceAPI(owner: NativeLuaArchitecture) extends NativeLuaAPI(owner) {
|
||||
def persist(index: Int): Array[Byte] = {
|
||||
if (Settings.get.allowPersistence) {
|
||||
configure()
|
||||
lua.getGlobal("eris") // ... eris
|
||||
lua.getField(-1, "persist") // ... eris persist
|
||||
if (lua.isFunction(-1)) {
|
||||
lua.getField(LuaState.REGISTRYINDEX, "perms") // ... eris persist perms
|
||||
lua.pushValue(index) // ... eris persist perms obj
|
||||
try {
|
||||
lua.call(2, 1) // ... eris str?
|
||||
} catch {
|
||||
case e: Throwable =>
|
||||
lua.pop(1)
|
||||
throw e
|
||||
}
|
||||
if (lua.isString(-1)) {
|
||||
// ... eris str
|
||||
val result = lua.toByteArray(-1)
|
||||
lua.pop(2) // ...
|
||||
return result
|
||||
try {
|
||||
lua.gc(LuaState.GcAction.STOP, 0)
|
||||
lua.getGlobal("eris") // ... eris
|
||||
lua.getField(-1, "persist") // ... eris persist
|
||||
if (lua.isFunction(-1)) {
|
||||
lua.getField(LuaState.REGISTRYINDEX, "perms") // ... eris persist perms
|
||||
lua.pushValue(index) // ... eris persist perms obj
|
||||
try {
|
||||
lua.call(2, 1) // ... eris str?
|
||||
} catch {
|
||||
case e: Throwable =>
|
||||
lua.pop(1)
|
||||
throw e
|
||||
}
|
||||
if (lua.isString(-1)) {
|
||||
// ... eris str
|
||||
val result = lua.toByteArray(-1)
|
||||
lua.pop(2) // ...
|
||||
return result
|
||||
} // ... eris :(
|
||||
} // ... eris :(
|
||||
} // ... eris :(
|
||||
lua.pop(2) // ...
|
||||
lua.pop(2) // ...
|
||||
}
|
||||
finally {
|
||||
lua.gc(LuaState.GcAction.RESTART, 0)
|
||||
}
|
||||
}
|
||||
Array[Byte]()
|
||||
}
|
||||
@ -149,17 +155,23 @@ class PersistenceAPI(owner: NativeLuaArchitecture) extends NativeLuaAPI(owner) {
|
||||
def unpersist(value: Array[Byte]): Boolean = {
|
||||
if (Settings.get.allowPersistence) {
|
||||
configure()
|
||||
lua.getGlobal("eris") // ... eris
|
||||
lua.getField(-1, "unpersist") // ... eris unpersist
|
||||
if (lua.isFunction(-1)) {
|
||||
lua.getField(LuaState.REGISTRYINDEX, "uperms") // ... eris persist uperms
|
||||
lua.pushByteArray(value) // ... eris unpersist uperms str
|
||||
lua.call(2, 1) // ... eris obj
|
||||
lua.insert(-2) // ... obj eris
|
||||
try {
|
||||
lua.gc(LuaState.GcAction.STOP, 0)
|
||||
lua.getGlobal("eris") // ... eris
|
||||
lua.getField(-1, "unpersist") // ... eris unpersist
|
||||
if (lua.isFunction(-1)) {
|
||||
lua.getField(LuaState.REGISTRYINDEX, "uperms") // ... eris persist uperms
|
||||
lua.pushByteArray(value) // ... eris unpersist uperms str
|
||||
lua.call(2, 1) // ... eris obj
|
||||
lua.insert(-2) // ... obj eris
|
||||
lua.pop(1)
|
||||
return true
|
||||
} // ... :(
|
||||
lua.pop(1)
|
||||
return true
|
||||
} // ... :(
|
||||
lua.pop(1)
|
||||
}
|
||||
finally {
|
||||
lua.gc(LuaState.GcAction.RESTART, 0)
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user