mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-17 03:05:30 -04:00
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.
This commit is contained in:
parent
ceae60bfae
commit
a6f36ef73c
@ -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)
|
||||
|
@ -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
|
@ -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)
|
@ -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")
|
||||
|
@ -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
|
@ -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")
|
||||
|
@ -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()
|
||||
|
@ -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
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
]
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -167,8 +167,10 @@ object Sound {
|
||||
}
|
||||
|
||||
def stop() {
|
||||
soundSystem.stop(source)
|
||||
soundSystem.removeSource(source)
|
||||
if (soundSystem != null) {
|
||||
soundSystem.stop(source)
|
||||
soundSystem.removeSource(source)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
Loading…
x
Reference in New Issue
Block a user