mirror of
https://github.com/20kdc/OC-KittenOS.git
synced 2024-12-25 02:18:07 +11:00
Somewhat smaller & less RAM-hungry kernel so the system is more usable.
This commit is contained in:
parent
89d8c7fd82
commit
fcabf5b853
26
README.md
26
README.md
@ -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.
|
||||
|
||||
## 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
|
||||
|
||||
At least in theory: "efficient. multi-tasking. clean. security-oriented".
|
||||
|
182
code/init.lua
182
code/init.lua
@ -106,12 +106,12 @@ function wrapMeta(t)
|
||||
local t2 = {}
|
||||
setmetatable(t2, {
|
||||
__index = function (a, k) return wrapMeta(t[k]) end,
|
||||
__newindex = function (a, k, v) end,
|
||||
__newindex = error,
|
||||
__pairs = function (a)
|
||||
return function (x, key)
|
||||
local k, v = next(t, k)
|
||||
if k then return k, wrapMeta(v) end
|
||||
end, {}, nil
|
||||
end, 9, nil
|
||||
end,
|
||||
__ipairs = function (a)
|
||||
return function (x, key)
|
||||
@ -119,7 +119,7 @@ function wrapMeta(t)
|
||||
if t[key] then
|
||||
return key, wrapMeta(t[key])
|
||||
end
|
||||
end, {}, 0
|
||||
end, 9, 0
|
||||
end,
|
||||
__metatable = uniqueNEOProtectionObject
|
||||
-- Don't protect this table - it'll make things worse
|
||||
@ -138,36 +138,17 @@ function ensureType(a, t)
|
||||
end
|
||||
|
||||
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("double dot disallowed") end
|
||||
end
|
||||
|
||||
function ensurePath(s, r)
|
||||
-- Filter filename for anything "worrying". Note / is allowed, see further filters
|
||||
if not s:match("^[a-zA-Z0-9_%-%+%,%#%~%@%'%;%[%]%(%)%&%%%$%! %=%{%}%^%/]+") then error("chars disallowed") end
|
||||
string.gsub(s, "[^/]+", ensurePathComponent)
|
||||
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
|
||||
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.
|
||||
-- (A process killing itself will actually survive until the next yield... before any of the death events have run.)
|
||||
function termProc(pid, reason)
|
||||
@ -218,7 +199,7 @@ function distEvent(pid, s, ...)
|
||||
if not v then
|
||||
return
|
||||
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
|
||||
end
|
||||
-- Schedule the timer to carry the event.
|
||||
@ -243,57 +224,6 @@ function lister(pfx)
|
||||
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)
|
||||
ensureType(library, "string")
|
||||
library = "libs/" .. library .. ".lua"
|
||||
@ -313,6 +243,87 @@ function loadLibraryInner(library)
|
||||
return nil, r
|
||||
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.
|
||||
-- Only a k.root application is allowed to do this for obvious reasons.
|
||||
function securityPolicy(pid, proc, perm, req)
|
||||
@ -500,7 +511,6 @@ function start(pkg, ...)
|
||||
end
|
||||
local env = baseProcEnv()
|
||||
env.neo.pid = pid
|
||||
env.neo.dead = false
|
||||
env.neo.executeAsync = startFromUser
|
||||
env.neo.execute = function (...)
|
||||
return osExecuteCore(function () end, ...)
|
||||
@ -538,16 +548,7 @@ function start(pkg, ...)
|
||||
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.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.access = {}
|
||||
proc.denied = {}
|
||||
-- You are dead. Not big surprise.
|
||||
proc.deathCBs = {function () pcall(function () env.neo.dead = true end) end}
|
||||
@ -571,15 +572,14 @@ while true do
|
||||
for i = 1, 16 do
|
||||
tmr = nil
|
||||
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
|
||||
local didAnything = false -- for early exit
|
||||
local k = 1
|
||||
while timers[k] do
|
||||
local v = timers[k]
|
||||
if v[1] <= now then
|
||||
table.remove(timers, k)
|
||||
if v[2](table.unpack(v, 3)) then
|
||||
breaking = true
|
||||
didAnything = false -- to break
|
||||
tmr = 0.05
|
||||
break
|
||||
end
|
||||
@ -593,8 +593,6 @@ while true do
|
||||
k = k + 1
|
||||
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
|
||||
end
|
||||
now = computer.uptime() -- the above probably took a while
|
||||
|
Loading…
Reference in New Issue
Block a user