From a6f36ef73ca4d217a9f1f0d39ce015030528253c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Sat, 12 Apr 2014 20:58:39 +0200 Subject: [PATCH] Experimenting with moving all of the OS out of the kernel, i.e. including stuff like the fileystem library. The bad: had to increase minimum memory module size quite a bit to make that work. The good: allows ultimate freedom to modify the OS without "external" changes. Added an 'install' script to allow copying OpenOS to attached drives where it can then be edited. Made cp.lua capable of recursive copying. Added computer API entry to get and set the address of the preferred boot device (where kernel looks for init.lua before falling back to ROM). Fixed NPE in sound cleanup. Moved process module out of kernel into ROM. Removed debug method i forgot to remove way back in io... Removed deprecated methods. Making active GC run only every so often, not on every resume. --- .../assets/opencomputers/lua/kernel.lua | 197 ++++-------------- .../assets/opencomputers/lua/rom/bin/cp.lua | 42 +++- .../opencomputers/lua/rom/bin/install.lua | 60 ++++++ .../assets/opencomputers/lua/rom/bin/lua.lua | 4 +- .../assets/opencomputers/lua/rom/bin/sh.lua | 7 +- .../assets/opencomputers/lua/rom/init.lua | 148 ++++++++++++- .../assets/opencomputers/lua/rom/lib/io.lua | 2 +- .../opencomputers/lua/rom/lib/process.lua | 85 ++++++++ .../opencomputers/lua/rom/lib/shell.lua | 6 - .../assets/opencomputers/lua/rom/lib/text.lua | 10 - src/main/resources/reference.conf | 6 +- src/main/scala/li/cil/oc/Settings.scala | 8 +- src/main/scala/li/cil/oc/client/Sound.scala | 6 +- .../machine/NativeLuaArchitecture.scala | 7 +- .../component/machine/luac/ComputerAPI.scala | 17 ++ 15 files changed, 406 insertions(+), 199 deletions(-) create mode 100644 src/main/resources/assets/opencomputers/lua/rom/bin/install.lua create mode 100644 src/main/resources/assets/opencomputers/lua/rom/lib/process.lua diff --git a/src/main/resources/assets/opencomputers/lua/kernel.lua b/src/main/resources/assets/opencomputers/lua/kernel.lua index 32eb82351..ceb789397 100644 --- a/src/main/resources/assets/opencomputers/lua/kernel.lua +++ b/src/main/resources/assets/opencomputers/lua/kernel.lua @@ -27,21 +27,6 @@ end ------------------------------------------------------------------------------- -local running = setmetatable({}, {__mode="k"}) - -local function findProcess(co) - co = co or coroutine.running() - for _, process in pairs(running) do - for _, instance in pairs(process.instances) do - if instance == co then - return process - end - end - end -end - -------------------------------------------------------------------------------- - local function spcall(...) local result = table.pack(pcall(...)) if not result[1] then @@ -71,7 +56,6 @@ sandbox = { if not system.allowBytecode() then mode = "t" end - env = env or select(2, libprocess.running()) return load(ld, source, mode, env or sandbox) end, loadfile = nil, -- in boot/*_base.lua @@ -100,11 +84,7 @@ sandbox = { end, coroutine = { - create = function(f) - local co = coroutine.create(f) - table.insert(findProcess().instances, co) - return co - end, + create = coroutine.create, resume = function(co, ...) -- custom resume part for bubbling sysyields checkArg(1, co, "thread") local args = table.pack(...) @@ -194,8 +174,8 @@ sandbox = { pi = math.pi, pow = math.pow, rad = math.rad, - random = function(low, high) - return spcall(math.random, low, high) + random = function(...) + return spcall(math.random, ...) end, randomseed = function(seed) spcall(math.randomseed, seed) @@ -288,7 +268,7 @@ libcomponent = { doc = function(address, method) checkArg(1, address, "string") checkArg(2, method, "string") - local result, reason = component.doc(address, method) + local result, reason = spcall(component.doc, address, method) if not result and reason then error(reason, 2) end @@ -297,7 +277,7 @@ libcomponent = { invoke = function(address, method, ...) checkArg(1, address, "string") checkArg(2, method, "string") - local methods, reason = component.methods(address) + local methods, reason = spcall(component.methods, address) if not methods then return nil, reason end @@ -310,7 +290,7 @@ libcomponent = { end, list = function(filter) checkArg(1, filter, "string", "nil") - local list = component.list(filter) + local list = spcall(component.list, filter) local key = nil return function() key = next(list, key) @@ -321,12 +301,12 @@ libcomponent = { end, proxy = function(address) checkArg(1, address, "string") - local type, reason = component.type(address) + local type, reason = spcall(component.type, address) if not type then return nil, reason end local proxy = {address = address, type = type} - local methods, reason = component.methods(address) + local methods, reason = spcall(component.methods, address) if not methods then return nil, reason end @@ -340,6 +320,7 @@ libcomponent = { return component.type(address) end } +sandbox.component = libcomponent local libcomputer = { isRobot = computer.isRobot, @@ -352,6 +333,11 @@ local libcomputer = { energy = computer.energy, maxEnergy = computer.maxEnergy, + getBootAddress = computer.getBootAddress, + setBootAddress = function(address) + return spcall(computer.setBootAddress, address) + end, + users = computer.users, addUser = function(name) return spcall(computer.addUser, name) @@ -377,51 +363,7 @@ local libcomputer = { until computer.uptime() >= deadline end } - -libprocess = { - load = function(path, env, init, name) - checkArg(1, path, "string") - checkArg(2, env, "table", "nil") - checkArg(3, init, "function", "nil") - checkArg(4, name, "string", "nil") - - local process = findProcess() - if process then - env = env or process.env - end - env = setmetatable({}, {__index=env or sandbox}) - local code, reason = sandbox.loadfile(path, "t", env) - if not code then - return nil, reason - end - - local thread = coroutine.create(function(...) - if init then - init() - end - return code(...) - end) - running[thread] = { - path = path, - command = name, - env = env, - parent = process, - instances = setmetatable({thread}, {__mode="v"}) - } - return thread - end, - running = function(level) - level = level or 1 - local process = findProcess() - while level > 1 and process do - process = process.parent - level = level - 1 - end - if process then - return process.path, process.env, process.command - end - end -} +sandbox.computer = libcomputer local libunicode = { char = function(...) @@ -446,91 +388,48 @@ local libunicode = { return spcall(unicode.upper, s) end } +sandbox.unicode = libunicode ------------------------------------------------------------------------------- local function bootstrap() - -- Minimalistic hard-coded pure async proxy for our ROM. - local rom = {} - function rom.invoke(method, ...) - return invoke(true, computer.romAddress(), method, ...) - end - function rom.open(file) return rom.invoke("open", file) end - function rom.read(handle) return rom.invoke("read", handle, math.huge) end - function rom.close(handle) return rom.invoke("close", handle) end - function rom.inits(file) return ipairs(rom.invoke("list", "boot")) end - function rom.isDirectory(path) return rom.invoke("isDirectory", path) end - - -- Custom low-level loadfile/dofile implementation reading from our ROM. - local function loadfile(file) - local handle, reason = rom.open(file) + local function tryLoadFrom(address) + function boot_invoke(method, ...) + local result = table.pack(pcall(invoke, true, address, method, ...)) + if not result[1] then + return nil, result[2] + else + return table.unpack(result, 2, result.n) + end + end + local handle, reason = boot_invoke("open", "/init.lua") if not handle then - error(reason) + return nil, reason end local buffer = "" repeat - local data, reason = rom.read(handle) + local data, reason = boot_invoke("read", handle, math.huge) if not data and reason then - error(reason) + return nil, reason end buffer = buffer .. (data or "") until not data - rom.close(handle) - return load(buffer, "=" .. file, "t", sandbox) + boot_invoke("close", handle) + return load(buffer, "=init", "t", sandbox) end - local function dofile(file) - local program, reason = loadfile(file) - if program then - local result = table.pack(pcall(program)) - if result[1] then - return table.unpack(result, 2, result.n) - else - error(result[2]) - end - else - error(reason) - end + local init, reason + if computer.getBootAddress() then + init, reason = tryLoadFrom(computer.getBootAddress()) + end + if not init then + computer.setBootAddress() + init, reason = tryLoadFrom(computer.romAddress()) + end + if not init then + error(reason) end - -- Load file system related libraries we need to load other stuff moree - -- comfortably. This is basically wrapper stuff for the file streams - -- provided by the filesystem components. - local package = dofile("/lib/package.lua") - - -- Initialize the package module with some of our own APIs. - package.preload["buffer"] = loadfile("/lib/buffer.lua") - package.preload["component"] = function() return libcomponent end - package.preload["computer"] = function() return libcomputer end - package.preload["filesystem"] = loadfile("/lib/filesystem.lua") - package.preload["io"] = loadfile("/lib/io.lua") - package.preload["process"] = function() return libprocess end - package.preload["unicode"] = function() return libunicode end - - -- Inject the package and io modules into the global namespace, as in Lua. - sandbox.package = package - sandbox.io = sandbox.require("io") - - -- Mount the ROM and temporary file systems to allow working on the file - -- system module from this point on. - sandbox.require("filesystem").mount(computer.romAddress(), "/") - if computer.tmpAddress() then - sandbox.require("filesystem").mount(computer.tmpAddress(), "/tmp") - end - - -- Run library startup scripts. These mostly initialize event handlers. - local scripts = {} - for _, file in rom.inits() do - local path = "boot/" .. file - if not rom.isDirectory(path) then - table.insert(scripts, path) - end - end - table.sort(scripts) - for i = 1, #scripts do - dofile(scripts[i]) - end - - return coroutine.create(function() dofile("/init.lua") end), {n=0} + return coroutine.create(init), {n=0} end local function wrapUserdata(values) @@ -582,18 +481,12 @@ end ------------------------------------------------------------------------------- local function main() - -- Make all calls in the bootstrapper direct to speed up booting. - local realInvoke = invoke - invoke = function(_, ...) return realInvoke(true, ...) end - - local co, args = bootstrap() - - -- Step out of the fast lane, all the basic stuff should now be loaded. - invoke = realInvoke - -- Yield once to get a memory baseline. coroutine.yield() + -- After memory footprint to avoid init.lua bumping the baseline. + local co, args = bootstrap() + while true do deadline = computer.realTime() + system.timeout() debug.sethook(co, checkDeadline, "", hookInterval) diff --git a/src/main/resources/assets/opencomputers/lua/rom/bin/cp.lua b/src/main/resources/assets/opencomputers/lua/rom/bin/cp.lua index 232ca1795..9351e81ee 100644 --- a/src/main/resources/assets/opencomputers/lua/rom/bin/cp.lua +++ b/src/main/resources/assets/opencomputers/lua/rom/bin/cp.lua @@ -13,11 +13,43 @@ local to = shell.resolve(args[2]) if fs.isDirectory(to) then to = to .. "/" .. fs.name(from) end -if fs.exists(to) and not options.f then - io.stderr:write("target file exists") - return + +local function status(from, to) + if options.v then + print(from .. " -> " .. to) + end end -local result, reason = fs.copy(from, to) + +local result, reason + +local function recurse(fromPath, toPath) + status(fromPath, toPath) + if fs.isDirectory(fromPath) then + if fs.exists(toPath) and not fs.isDirectory(toPath) then + if not options.f then + return nil, "target file exists" + end + fs.remove(toPath) + end + fs.makeDirectory(toPath) + for file in fs.list(fromPath) do + local result, reason = recurse(fs.concat(fromPath, file), fs.concat(toPath, file)) + if not result then + return nil, reason + end + end + return true + else + if fs.exists(toPath) then + if fs.isDirectory(toPath) or not options.f then + return nil, "target file exists" + end + fs.remove(toPath) + end + return fs.copy(fromPath, toPath) + end +end +result, reason = recurse(from, to) if not result then - io.stderr:write(reason) + error(reason) end \ No newline at end of file diff --git a/src/main/resources/assets/opencomputers/lua/rom/bin/install.lua b/src/main/resources/assets/opencomputers/lua/rom/bin/install.lua new file mode 100644 index 000000000..14bd4ef1f --- /dev/null +++ b/src/main/resources/assets/opencomputers/lua/rom/bin/install.lua @@ -0,0 +1,60 @@ +local component = require("component") +local computer = require("computer") +local event = require("event") +local unicode = require("unicode") + +local candidates = {} +for address in component.list("filesystem") do + local dev = component.proxy(address) + if not dev.isReadOnly() and dev.address ~= computer.tmpAddress() then + table.insert(candidates, dev) + end +end + +if #candidates == 0 then + print("No writable disks found, aborting.") + return +end + +for i = 1, #candidates do + print(i .. ") " .. candidates[i].address) +end + +print("To select the device to install to, please enter a number between 1 and " .. #candidates .. ".") +print("Press 'q' to cancel the installation.") +local choice +repeat + local _, address, char, code = event.pull("key") + if component.isPrimary(address) then + local value = unicode.char(char) + if value == "q" then + return + end + local number = tonumber(value) + if number and number > 0 and number <= #candidates then + choice = number + else + end + end +until choice +choice = candidates[choice] + +print("Installing OpenOS to device " .. choice.address) +local rom = "/mnt/" .. computer.romAddress():sub(1, 3) .. "/" +local mnt = "/mnt/" .. choice.address:sub(1, 3) .. "/" +local function install(what, path) + print("Installing " .. what .. "...") + local result, reason = os.execute("cp -vf " .. rom .. path .. " " .. mnt) + if not result then + error(reason, 0) + end +end +install("programs", "bin") +install("boot scripts", "boot") +install("libraries", "lib") +install("additional files", "usr") +install("startup script", "init.lua") +computer.setBootAddress(choice.address) + +print("All done! Rebooting from device now...") +computer.shutdown(true) \ No newline at end of file diff --git a/src/main/resources/assets/opencomputers/lua/rom/bin/lua.lua b/src/main/resources/assets/opencomputers/lua/rom/bin/lua.lua index 2dbb77ba1..bf84eb772 100644 --- a/src/main/resources/assets/opencomputers/lua/rom/bin/lua.lua +++ b/src/main/resources/assets/opencomputers/lua/rom/bin/lua.lua @@ -1,7 +1,7 @@ local component = require("component") local package = require("package") local term = require("term") -local text = require("text") +local serialization = require("serialization") local function optrequire(...) local success, module = pcall(require, ...) @@ -49,7 +49,7 @@ while term.isAvailable() do io.stderr:write(tostring(result[2]) .. "\n") else for i = 2, result.n do - term.write(text.serialize(result[i], true) .. "\t", true) + term.write(serialization.serialize(result[i], true) .. "\t", true) end if term.getCursor() > 1 then term.write("\n") diff --git a/src/main/resources/assets/opencomputers/lua/rom/bin/sh.lua b/src/main/resources/assets/opencomputers/lua/rom/bin/sh.lua index 342f9f04b..ae48cb646 100644 --- a/src/main/resources/assets/opencomputers/lua/rom/bin/sh.lua +++ b/src/main/resources/assets/opencomputers/lua/rom/bin/sh.lua @@ -120,10 +120,11 @@ if #args == 0 and (io.input() == io.stdin or options.i) and not options.c then return elseif command ~= "" then local result, reason = execute(command) + if term.getCursor() > 1 then + term.write("\n") + end if not result then io.stderr:write((tostring(reason) or "unknown error").. "\n") - elseif term.getCursor() > 1 then - term.write("\n") end end end @@ -132,7 +133,7 @@ else -- execute command. local result = table.pack(execute(table.unpack(args))) if not result[1] then - error(result[2]) + error(result[2], 0) end return table.unpack(result, 2) end \ No newline at end of file diff --git a/src/main/resources/assets/opencomputers/lua/rom/init.lua b/src/main/resources/assets/opencomputers/lua/rom/init.lua index 99afa57f3..525532436 100644 --- a/src/main/resources/assets/opencomputers/lua/rom/init.lua +++ b/src/main/resources/assets/opencomputers/lua/rom/init.lua @@ -1,13 +1,147 @@ -local component = require("component") +do + local component = component + local computer = computer + local unicode = unicode + + -- Low level dofile implementation to read filesystem libraries. + local rom = {} + function rom.invoke(method, ...) + return component.invoke(computer.romAddress(), method, ...) + end + function rom.open(file) return rom.invoke("open", file) end + function rom.read(handle) return rom.invoke("read", handle, math.huge) end + function rom.close(handle) return rom.invoke("close", handle) end + function rom.inits(file) return ipairs(rom.invoke("list", "boot")) end + function rom.isDirectory(path) return rom.invoke("isDirectory", path) end + + -- Report boot progress if possible. + local gpu, screen = component.list("gpu")(), component.list("screen")() + local w, h + if gpu and screen then + component.invoke(gpu, "bind", screen) + w, h = component.invoke(gpu, "getResolution") + component.invoke(gpu, "setResolution", w, h) + component.invoke(gpu, "setBackground", 0x000000) + component.invoke(gpu, "setForeground", 0xFFFFFF) + component.invoke(gpu, "fill", 1, 1, w, h, " ") + end + local y = 1 + local function status(msg) + if gpu and screen then + component.invoke(gpu, "set", 1, y, msg) + if y == h then + component.invoke(gpu, "copy", 1, 2, w, h - 1, 0, -1) + component.invoke(gpu, "fill", 1, h, w, 1, " ") + else + y = y + 1 + end + end + end + + status("Booting " .. _OSVERSION .. "...") + + -- Custom low-level loadfile/dofile implementation reading from our ROM. + local function loadfile(file) + status("> " .. file) + local handle, reason = rom.open(file) + if not handle then + error(reason) + end + local buffer = "" + repeat + local data, reason = rom.read(handle) + if not data and reason then + error(reason) + end + buffer = buffer .. (data or "") + until not data + rom.close(handle) + return load(buffer, "=" .. file) + end + + local function dofile(file) + local program, reason = loadfile(file) + if program then + local result = table.pack(pcall(program)) + if result[1] then + return table.unpack(result, 2, result.n) + else + error(result[2]) + end + else + error(reason) + end + end + + status("Initializing package management...") + + -- Load file system related libraries we need to load other stuff moree + -- comfortably. This is basically wrapper stuff for the file streams + -- provided by the filesystem components. + local package = dofile("/lib/package.lua") + + do + -- Unclutter global namespace now that we have the package module. + _G.component = nil + _G.computer = nil + _G.process = nil + _G.unicode = nil + + -- Initialize the package module with some of our own APIs. + package.preload["buffer"] = loadfile("/lib/buffer.lua") + package.preload["component"] = function() return component end + package.preload["computer"] = function() return computer end + package.preload["filesystem"] = loadfile("/lib/filesystem.lua") + package.preload["io"] = loadfile("/lib/io.lua") + package.preload["unicode"] = function() return unicode end + + -- Inject the package and io modules into the global namespace, as in Lua. + _G.package = package + _G.io = require("io") + end + + status("Initializing file system...") + + -- Mount the ROM and temporary file systems to allow working on the file + -- system module from this point on. + local filesystem = require("filesystem") + filesystem.mount(computer.getBootAddress() or computer.romAddress(), "/") + if computer.tmpAddress() then + filesystem.mount(computer.tmpAddress(), "/tmp") + end + + status("Running boot scripts...") + + -- Run library startup scripts. These mostly initialize event handlers. + local scripts = {} + for _, file in rom.inits() do + local path = "boot/" .. file + if not rom.isDirectory(path) then + table.insert(scripts, path) + end + end + table.sort(scripts) + for i = 1, #scripts do + dofile(scripts[i]) + end + + -- Initialize process module. + require("process").install("/init.lua", "init") + + status("Initializing components...") + + for c, t in component.list() do + computer.pushSignal("component_added", c, t) + end + os.sleep(0.5) -- Allow signal processing by libraries. + computer.pushSignal("init") -- so libs know components are initialized. + + status("Starting shell...") +end + local computer = require("computer") local event = require("event") -for c, t in component.list() do - computer.pushSignal("component_added", c, t) -end -os.sleep(0.5) -- Allow signal processing by libraries. -computer.pushSignal("init") -- so libs know components are initialized. - while true do require("term").clear() io.write(_OSVERSION .. " (" .. math.floor(computer.totalMemory() / 1024) .. "k RAM)\n") diff --git a/src/main/resources/assets/opencomputers/lua/rom/lib/io.lua b/src/main/resources/assets/opencomputers/lua/rom/lib/io.lua index ea2e4f115..17949be11 100644 --- a/src/main/resources/assets/opencomputers/lua/rom/lib/io.lua +++ b/src/main/resources/assets/opencomputers/lua/rom/lib/io.lua @@ -2,7 +2,7 @@ local io, file = {}, {} local input, output local programs = setmetatable({}, {__mode="k"}) -- maps program envs to i/o -function io.progs() return programs end + local function findOverride(filter) local override pcall(function() diff --git a/src/main/resources/assets/opencomputers/lua/rom/lib/process.lua b/src/main/resources/assets/opencomputers/lua/rom/lib/process.lua new file mode 100644 index 000000000..cc53a6fb5 --- /dev/null +++ b/src/main/resources/assets/opencomputers/lua/rom/lib/process.lua @@ -0,0 +1,85 @@ +local process = {} + +------------------------------------------------------------------------------- + +local running = setmetatable({}, {__mode="k"}) + +local function findProcess(co) + co = co or coroutine.running() + for _, process in pairs(running) do + for _, instance in pairs(process.instances) do + if instance == co then + return process + end + end + end +end + +------------------------------------------------------------------------------- + +function process.load(path, env, init, name) + checkArg(1, path, "string") + checkArg(2, env, "table", "nil") + checkArg(3, init, "function", "nil") + checkArg(4, name, "string", "nil") + + local process = findProcess() + if process then + env = env or process.env + end + env = setmetatable({}, {__index=env or _G}) + local code, reason = loadfile(path, "t", env) + if not code then + return nil, reason + end + + local thread = coroutine.create(function(...) + if init then + init() + end + return code(...) + end) + running[thread] = { + path = path, + command = name, + env = env, + parent = process, + instances = setmetatable({thread}, {__mode="v"}) + } + return thread +end + +function process.running(level) + level = level or 1 + local process = findProcess() + while level > 1 and process do + process = process.parent + level = level - 1 + end + if process then + return process.path, process.env, process.command + end +end + +function process.install(path, name) + local coroutine_create = coroutine.create + _G.coroutine.create = function(f) + local co = coroutine_create(f) + table.insert(findProcess().instances, co) + return co + end + local load = load + _G.load = function(ld, source, mode, env) + env = env or select(2, process.running()) + return load(ld, source, mode, env) + end + local thread = coroutine.running() + running[thread] = { + path = path, + command = name, + env = _ENV, + instances = setmetatable({thread}, {__mode="v"}) + } +end + +return process \ No newline at end of file diff --git a/src/main/resources/assets/opencomputers/lua/rom/lib/shell.lua b/src/main/resources/assets/opencomputers/lua/rom/lib/shell.lua index a8b0c20d6..7c15bf721 100644 --- a/src/main/resources/assets/opencomputers/lua/rom/lib/shell.lua +++ b/src/main/resources/assets/opencomputers/lua/rom/lib/shell.lua @@ -1,6 +1,4 @@ -local event = require("event") local fs = require("filesystem") -local process = require("process") local text = require("text") local unicode = require("unicode") @@ -165,10 +163,6 @@ function shell.parse(...) return args, options end -function shell.running(level) -- deprecated - return require("process").running(level) -end - ------------------------------------------------------------------------------- return shell diff --git a/src/main/resources/assets/opencomputers/lua/rom/lib/text.lua b/src/main/resources/assets/opencomputers/lua/rom/lib/text.lua index c8d4c2510..0eae2c924 100644 --- a/src/main/resources/assets/opencomputers/lua/rom/lib/text.lua +++ b/src/main/resources/assets/opencomputers/lua/rom/lib/text.lua @@ -17,7 +17,6 @@ end function text.padRight(value, length) checkArg(1, value, "string", "nil") checkArg(2, length, "number") - local unicode = require("unicode") if not value or unicode.len(value) == 0 then return string.rep(" ", length) else @@ -28,7 +27,6 @@ end function text.padLeft(value, length) checkArg(1, value, "string", "nil") checkArg(2, length, "number") - local unicode = require("unicode") if not value or unicode.len(value) == 0 then return string.rep(" ", length) else @@ -99,14 +97,6 @@ function text.tokenize(value) return tokens end -function text.serialize(value, pretty) -- deprecated, use serialization module - return require("serialization").serialize(value, pretty) -end - -function text.unserialize(data) -- deprecated, use serialization module - return require("serialization").unserialize(data) -end - ------------------------------------------------------------------------------- return text diff --git a/src/main/resources/reference.conf b/src/main/resources/reference.conf index 73a382d79..ad5667068 100644 --- a/src/main/resources/reference.conf +++ b/src/main/resources/reference.conf @@ -110,11 +110,11 @@ opencomputers { # there are six levels of RAM, they still fall into the three tiers of # items (level 1, 2 = tier 1, level 3, 4 = tier 2, level 5, 6 = tier 3). ramSizes: [ - 64 - 96 - 128 + 192 256 + 384 512 + 768 1024 ] diff --git a/src/main/scala/li/cil/oc/Settings.scala b/src/main/scala/li/cil/oc/Settings.scala index 69eb7a133..aede14b72 100644 --- a/src/main/scala/li/cil/oc/Settings.scala +++ b/src/main/scala/li/cil/oc/Settings.scala @@ -38,17 +38,11 @@ class Settings(config: Config) { val startupDelay = config.getDouble("computer.startupDelay") max 0.05 val activeGC = config.getBoolean("computer.activeGC") val ramSizes = Array(config.getIntList("computer.ramSizes"): _*) match { - case Array(tier1, tier2, tier3) => - // For compatibility with older config files. - Array(tier1: Int, (tier1: Int) * 3 / 2, tier2: Int, tier3: Int, tier3 * 2: Int, tier3 * 4: Int) - case Array(tier1, tier3, tier4, tier5, tier6) => - // For compatibility with older config files. - Array(tier1: Int, (tier1: Int) * 3 / 2, tier3: Int, tier4: Int, tier5: Int, tier6: Int) case Array(tier1, tier2, tier3, tier4, tier5, tier6) => Array(tier1: Int, tier2: Int, tier3: Int, tier4: Int, tier5: Int, tier6: Int) case _ => OpenComputers.log.warning("Bad number of RAM sizes, ignoring.") - Array(64, 96, 128, 256, 512, 1024) + Array(192, 256, 384, 512, 768, 1024) } val ramScaleFor64Bit = config.getDouble("computer.ramScaleFor64Bit") max 1 val cpuComponentSupport = Array(config.getIntList("computer.cpuComponentCount"): _*) match { diff --git a/src/main/scala/li/cil/oc/client/Sound.scala b/src/main/scala/li/cil/oc/client/Sound.scala index 356724ea7..e67213960 100644 --- a/src/main/scala/li/cil/oc/client/Sound.scala +++ b/src/main/scala/li/cil/oc/client/Sound.scala @@ -167,8 +167,10 @@ object Sound { } def stop() { - soundSystem.stop(source) - soundSystem.removeSource(source) + if (soundSystem != null) { + soundSystem.stop(source) + soundSystem.removeSource(source) + } } } diff --git a/src/main/scala/li/cil/oc/server/component/machine/NativeLuaArchitecture.scala b/src/main/scala/li/cil/oc/server/component/machine/NativeLuaArchitecture.scala index 9140c649a..8cad81bf4 100644 --- a/src/main/scala/li/cil/oc/server/component/machine/NativeLuaArchitecture.scala +++ b/src/main/scala/li/cil/oc/server/component/machine/NativeLuaArchitecture.scala @@ -17,6 +17,8 @@ class NativeLuaArchitecture(val machine: api.machine.Machine) extends Architectu private[machine] val ramScale = if (LuaStateFactory.is64Bit) Settings.get.ramScaleFor64Bit else 1.0 + private[machine] var bootAddress = "" + private val persistence = new PersistenceAPI(this) private val apis = Array( @@ -28,6 +30,8 @@ class NativeLuaArchitecture(val machine: api.machine.Machine) extends Architectu new UnicodeAPI(this), new UserdataAPI(this)) + private var lastCollection = 0L + // ----------------------------------------------------------------------- // override def name() = "Lua" @@ -73,9 +77,10 @@ class NativeLuaArchitecture(val machine: api.machine.Machine) extends Architectu // The kernel thread will always be at stack index one. assert(lua.isThread(1)) - if (Settings.get.activeGC) { + if (Settings.get.activeGC && (machine.worldTime - lastCollection) > 20) { // Help out the GC a little. The emergency GC has a few limitations // that will make it free less memory than doing a full step manually. + lastCollection = machine.worldTime lua.gc(LuaState.GcAction.COLLECT, 0) } diff --git a/src/main/scala/li/cil/oc/server/component/machine/luac/ComputerAPI.scala b/src/main/scala/li/cil/oc/server/component/machine/luac/ComputerAPI.scala index ea1b948b1..41ea0e3d9 100644 --- a/src/main/scala/li/cil/oc/server/component/machine/luac/ComputerAPI.scala +++ b/src/main/scala/li/cil/oc/server/component/machine/luac/ComputerAPI.scala @@ -38,6 +38,23 @@ class ComputerAPI(owner: NativeLuaArchitecture) extends NativeLuaAPI(owner) { }) lua.setField(-2, "address") + // Get/set address of boot device. + lua.pushScalaFunction(lua => { + owner.bootAddress match { + case "" => lua.pushNil() + case address => lua.pushString(address) + } + 1 + }) + lua.setField(-2, "getBootAddress") + + lua.pushScalaFunction(lua => { + if (lua.isNoneOrNil(1)) owner.bootAddress = "" + else owner.bootAddress = lua.checkString(1) + 0 + }) + lua.setField(-2, "setBootAddress") + lua.pushScalaFunction(lua => { // This is *very* unlikely, but still: avoid this getting larger than // what we report as the total memory.