Somewhat smaller & less RAM-hungry kernel so the system is more usable.

This commit is contained in:
20kdc 2018-03-30 01:53:00 +01:00
parent 89d8c7fd82
commit fcabf5b853
2 changed files with 116 additions and 92 deletions

View File

@ -6,6 +6,32 @@ The first commit is after I got the installer working again after the new compre
That's what the "SYSTEM HEROES" thing is about. That's what the "SYSTEM HEROES" thing is about.
## Known Issues (That Aren't KittenOS NEO's Fault)
Touch calibration is off because OC's setPrecise seems to offset coordinates down and right by a character. OCEmu's does not. I consider this an OC bug. This is known to occur on at least `OpenComputers-MC1.12.2-1.7.2.67.jar`. If you want to check my routines, see sys-everest, search for the lowest instance of `"touch"`. Or just use OCEmu, which doesn't change anything when precise is set, and thus can't be doing anything different than the setPrecise(false) behavior.
Wide character support *may* encounter issues due to performance-saving tricks in some old OC versions. The 1.12.2 version being used at LimboCon doesn't have the issue, so it's been dealt with. Point is, not a KittenOS NEO bug if it happens.
## Known Issues (That Are KittenOS NEO's Fault But Aren't Really Fixable)
If you move a window over another window, that window has to rerender. The alternative is buffering the window. Since memory is a concern, that is not going to happen. Some windows are more expensive to render than others (`klogo` tries to use less RAM if the system is 192K, at the expense of disk access) - move the most expensive window out of the way, since once a window is top-most, moving it around is usually "free".
If the system runs out of memory, the kernel could crash, or alternatively the system goes into a limbo state. You're more or less doomed. Given that almost everything in Lua causes a memory allocation, I'm not exactly sure how I'd be supposed to fix this properly.
Any situation where the system fails to boot *may* be fixable with Safe Mode.
This includes if you copied a sufficiently large bit of text into the persistent clipboard, and now Icecap or Everest won't start.
The catch is, it wipes your settings. As the settings are always in RAM, and contain just about every *fixable* thing that can break your boot,
nuking them should bring you to defaults.
It seems to take just under a second for a key event to get through, yet drags are fine.
I don't know why this is, but I suspect the answer involves the timing of a `computer.pullSignal()` with no timeout.
If you particularly find performance important, and don't mind the energy costs, you can modify the `init.lua` to make it so that the kernel wakes up every tick.
And finally, just because a system can multitask somewhat on 192K doesn't mean it can do the impossible regarding memory usage.
Lesson learned: Cleaner design -> Higher memory usage.
So anyone who wants the design to be made even cleaner should probably reread this paragraph.
(In R0, editing the kernel causes 192K systems to fail to open filedialogs. I've fixed this in R1.)
## Description ## Description
At least in theory: "efficient. multi-tasking. clean. security-oriented". At least in theory: "efficient. multi-tasking. clean. security-oriented".

View File

@ -106,12 +106,12 @@ function wrapMeta(t)
local t2 = {} local t2 = {}
setmetatable(t2, { setmetatable(t2, {
__index = function (a, k) return wrapMeta(t[k]) end, __index = function (a, k) return wrapMeta(t[k]) end,
__newindex = function (a, k, v) end, __newindex = error,
__pairs = function (a) __pairs = function (a)
return function (x, key) return function (x, key)
local k, v = next(t, k) local k, v = next(t, k)
if k then return k, wrapMeta(v) end if k then return k, wrapMeta(v) end
end, {}, nil end, 9, nil
end, end,
__ipairs = function (a) __ipairs = function (a)
return function (x, key) return function (x, key)
@ -119,7 +119,7 @@ function wrapMeta(t)
if t[key] then if t[key] then
return key, wrapMeta(t[key]) return key, wrapMeta(t[key])
end end
end, {}, 0 end, 9, 0
end, end,
__metatable = uniqueNEOProtectionObject __metatable = uniqueNEOProtectionObject
-- Don't protect this table - it'll make things worse -- Don't protect this table - it'll make things worse
@ -138,36 +138,17 @@ function ensureType(a, t)
end end
function ensurePathComponent(s) function ensurePathComponent(s)
if not s:match("^[a-zA-Z0-9_%-%+%,%#%~%@%'%;%[%]%(%)%&%%%$%! %=%{%}%^]+") then error("chars disallowed") end if not string.match(s, "^[a-zA-Z0-9_%-%+%,%#%~%@%'%;%[%]%(%)%&%%%$%! %=%{%}%^]+") then error("chars disallowed") end
if s == "." then error("single dot disallowed") end if s == "." then error("single dot disallowed") end
if s == ".." then error("double dot disallowed") end if s == ".." then error("double dot disallowed") end
end end
function ensurePath(s, r) function ensurePath(s, r)
-- Filter filename for anything "worrying". Note / is allowed, see further filters string.gsub(s, "[^/]+", ensurePathComponent)
if not s:match("^[a-zA-Z0-9_%-%+%,%#%~%@%'%;%[%]%(%)%&%%%$%! %=%{%}%^%/]+") then error("chars disallowed") end
if s:sub(1, r:len()) ~= r then error("base disallowed") end if s:sub(1, r:len()) ~= r then error("base disallowed") end
if s:match("//") then error("// disallowed") end if s:match("//") then error("// disallowed") end
if s:match("^%.%./") then error("../ disallowed") end
if s:match("/%.%./") then error("/../ disallowed") end
if s:match("/%.%.$") then error("/.. disallowed") end
if s:match("^%./") then error("./ disallowed") end
if s:match("/%./") then error("/./ disallowed") end
if s:match("/%.$") then error("/. disallowed") end
end end
wrapMath = wrapMeta(math)
wrapTable = wrapMeta(table)
wrapString = wrapMeta(string)
wrapUnicode = wrapMeta(unicode)
wrapCoroutine = wrapMeta(coroutine)
wrapOs = wrapMeta({
totalMemory = computer.totalMemory, freeMemory = computer.freeMemory,
energy = computer.energy, maxEnergy = computer.maxEnergy,
clock = os.clock, date = os.date, difftime = os.difftime,
time = os.time, uptime = computer.uptime
})
-- Use with extreme care. -- Use with extreme care.
-- (A process killing itself will actually survive until the next yield... before any of the death events have run.) -- (A process killing itself will actually survive until the next yield... before any of the death events have run.)
function termProc(pid, reason) function termProc(pid, reason)
@ -218,7 +199,7 @@ function distEvent(pid, s, ...)
if not v then if not v then
return return
end end
if not (v.access["s." .. s] or v.access["k.root"]) then if not (s:sub(1, 2) == "k." or v.access["s." .. s] or v.access["k.root"]) then
return return
end end
-- Schedule the timer to carry the event. -- Schedule the timer to carry the event.
@ -243,57 +224,6 @@ function lister(pfx)
end end
end end
function baseProcEnv()
local pe = {
_VERSION = _VERSION,
math = wrapMath,
table = wrapTable,
string = wrapString,
unicode = wrapUnicode,
coroutine = wrapCoroutine,
os = wrapOs,
-- Note raw-methods are gone - these can interfere with the metatable safeties.
require = loadLibraryInner,
assert = assert, ipairs = ipairs,
load = load, next = next,
pairs = pairs, pcall = pcall,
xpcall = xpcall, select = select,
type = type, error = error,
tonumber = tonumber, tostring = tostring,
setmetatable = setmetatable, getmetatable = function (n)
local mt = getmetatable(n)
if mt == uniqueNEOProtectionObject then return "NEO-Protected Object" end
return mt
end,
rawset = function (t, i, v)
local mt = getmetatable(n)
if mt == uniqueNEOProtectionObject then error("NEO-Protected Object") end
return rawset(t, i, v)
end, rawget = rawget, rawlen = rawlen, rawequal = rawequal,
neo = {
emergency = emergencyFunction,
readBufSize = readBufSize,
wrapMeta = wrapMeta,
listProcs = function ()
local n = {}
for k, v in pairs(processes) do
table.insert(n, {k, v.pkg, v.cpuUsage})
end
return n
end,
listApps = lister("apps/"),
listLibs = lister("libs/"),
totalIdleTime = function () return idleTime end,
ensurePath = ensurePath,
ensurePathComponent = ensurePathComponent,
ensureType = ensureType
}
}
pe._G = pe
pe._ENV = pe
return pe
end
function loadLibraryInner(library) function loadLibraryInner(library)
ensureType(library, "string") ensureType(library, "string")
library = "libs/" .. library .. ".lua" library = "libs/" .. library .. ".lua"
@ -313,6 +243,87 @@ function loadLibraryInner(library)
return nil, r return nil, r
end end
wrapMath = wrapMeta(math)
wrapTable = wrapMeta(table)
wrapString = wrapMeta(string)
wrapUnicode = wrapMeta(unicode)
wrapCoroutine = wrapMeta(coroutine)
wrapOs = wrapMeta({
totalMemory = computer.totalMemory, freeMemory = computer.freeMemory,
energy = computer.energy, maxEnergy = computer.maxEnergy,
clock = os.clock, date = os.date, difftime = os.difftime,
time = os.time, uptime = computer.uptime
})
wrapDebug = wrapMeta(debug)
baseProcEnvCore = {
_VERSION = _VERSION,
math = wrapMath,
table = wrapTable,
string = wrapString,
unicode = wrapUnicode,
coroutine = wrapCoroutine,
os = wrapOs,
debug = wrapDebug,
require = loadLibraryInner,
assert = assert, ipairs = ipairs,
load = load,
next = function (t, k)
local mt = getmetatable(t)
if mt == uniqueNEOProtectionObject then error("NEO-Protected Object") end
return next(t, k)
end,
pairs = pairs, pcall = pcall,
xpcall = xpcall, select = select,
type = type, error = error,
tonumber = tonumber, tostring = tostring,
setmetatable = setmetatable, getmetatable = function (n)
local mt = getmetatable(n)
if mt == uniqueNEOProtectionObject then return "NEO-Protected Object" end
return mt
end,
rawset = function (t, i, v)
local mt = getmetatable(t)
if mt == uniqueNEOProtectionObject then error("NEO-Protected Object") end
return rawset(t, i, v)
end, rawget = rawget, rawlen = rawlen, rawequal = rawequal,
}
baseProcNeo = {
emergency = emergencyFunction,
readBufSize = readBufSize,
wrapMeta = wrapMeta,
listProcs = function ()
local n = {}
for k, v in pairs(processes) do
table.insert(n, {k, v.pkg, v.cpuUsage})
end
return n
end,
listApps = lister("apps/"),
listLibs = lister("libs/"),
totalIdleTime = function () return idleTime end,
ensurePath = ensurePath,
ensurePathComponent = ensurePathComponent,
ensureType = ensureType
}
baseProcEnvMT = {
__index = baseProcEnvCore,
__metatable = uniqueNEOProtectionObject
}
baseProcNeoMT = {
__index = baseProcNeo,
__metatable = uniqueNEOProtectionObject
}
function baseProcEnv()
local pe = setmetatable({}, baseProcEnvMT)
pe.neo = setmetatable({}, baseProcNeoMT)
pe._G = pe
pe._ENV = pe
return pe
end
-- These two are hooks for k.root level applications to change policy. -- These two are hooks for k.root level applications to change policy.
-- Only a k.root application is allowed to do this for obvious reasons. -- Only a k.root application is allowed to do this for obvious reasons.
function securityPolicy(pid, proc, perm, req) function securityPolicy(pid, proc, perm, req)
@ -500,7 +511,6 @@ function start(pkg, ...)
end end
local env = baseProcEnv() local env = baseProcEnv()
env.neo.pid = pid env.neo.pid = pid
env.neo.dead = false
env.neo.executeAsync = startFromUser env.neo.executeAsync = startFromUser
env.neo.execute = function (...) env.neo.execute = function (...)
return osExecuteCore(function () end, ...) return osExecuteCore(function () end, ...)
@ -538,16 +548,7 @@ function start(pkg, ...)
end end
proc.co = coroutine.create(function (...) local r = {xpcall(appfunc, debug.traceback, ...)} if not r[1] then error(table.unpack(r, 2)) end return table.unpack(r, 2) end) proc.co = coroutine.create(function (...) local r = {xpcall(appfunc, debug.traceback, ...)} if not r[1] then error(table.unpack(r, 2)) end return table.unpack(r, 2) end)
proc.pkg = pkg proc.pkg = pkg
proc.access = { proc.access = {}
-- These permissions are the "critical set".
["s.k.securityresponse"] = true,
["s.k.timer"] = true,
["s.k.procnew"] = true,
["s.k.procdie"] = true,
-- Used when a registration is updated, in particular, as this signifies "readiness"
["s.k.registration"] = true,
["s.k.deregistration"] = true
}
proc.denied = {} proc.denied = {}
-- You are dead. Not big surprise. -- You are dead. Not big surprise.
proc.deathCBs = {function () pcall(function () env.neo.dead = true end) end} proc.deathCBs = {function () pcall(function () env.neo.dead = true end) end}
@ -571,15 +572,14 @@ while true do
for i = 1, 16 do for i = 1, 16 do
tmr = nil tmr = nil
local now = computer.uptime() local now = computer.uptime()
local breaking = false -- Used when a process dies - in this case it's assumed OC just did something drastic local didAnything = false -- for early exit
local didAnything = false
local k = 1 local k = 1
while timers[k] do while timers[k] do
local v = timers[k] local v = timers[k]
if v[1] <= now then if v[1] <= now then
table.remove(timers, k) table.remove(timers, k)
if v[2](table.unpack(v, 3)) then if v[2](table.unpack(v, 3)) then
breaking = true didAnything = false -- to break
tmr = 0.05 tmr = 0.05
break break
end end
@ -593,8 +593,6 @@ while true do
k = k + 1 k = k + 1
end end
end end
if breaking then break end
-- If the system didn't make any progress, then we're waiting for a signal (this includes timers)
if not didAnything then break end if not didAnything then break end
end end
now = computer.uptime() -- the above probably took a while now = computer.uptime() -- the above probably took a while