openos 1.6.6

More memory savings, significant boot time savings

**Memory Savings**
The largest library in terms of cost in bytes in 1.6.5 was /lib/filesystem. Most of this library is not needed for boot, and in 1.6.6 the library is half loaded for boot with a delay load of the rest of the library when needed. There are also other minor memory improvements, see **Changes** for details

**Boot Time**
This update also introduces a newly written /bin/sh.lua that takes advantage of a common stdio system. This work was primary done to reduce memory needed to load the shell. However, during development of a simplified /bin/sh, I found that the /bin/source, /etc/profile, and /home/.shrc feature added to openos 1.6 had a significant boot time cost. I began optimizing /bin/source heavily and found that I could not make sufficient speed improvements due to the nature of how shell commands execute. Thus /etc/profile has been removed in favor of /etc/profile.lua, a script that sets up the environment the same but as a lua script. ~/.shrc is still honored if it exists on a system, and is sourced (/bin/source) as a set of shell commands. This change speeds up boot time from floppy by 3s, and on hdds by 1s.

**Possible Breaking Changes**
/etc/profile has been moved to /etc/profile.lua, but /home/.shrc is still sourced as shell script commands.

**Changes**
* /bin/sh.lua rewrite that takes advantage of standard io and uses the new /etc/profile.lua shaving 6s off boot time
* /bin/source.lua improve performance by reducing the number of processes created
* move /etc/profile to /etc/profile.lua and recode the actions in lua-form.
* move all ~/.shrc actions to /etc/profile.lua for performance reasons
* move motd to start of /etc/profile.lua to get the shell display as soon as possible
* update greetings that referenced /etc/profile to properly refer to /etc/profile.lua now
* update openos version to 1.6.6 to respect the impact of these changes
This commit is contained in:
payonel 2017-06-25 22:58:54 -07:00
parent 83a37af8cb
commit c988b44f66
12 changed files with 90 additions and 103 deletions

View File

@ -4,7 +4,7 @@ local args, options = shell.parse(...)
local ec, error_prefix = 0, "alias:" local ec, error_prefix = 0, "alias:"
if options.help then if options.help then
print(string.format("Usage: alias: [name[=value] ... ]", cmd_name)) print(string.format("Usage: alias: [name[=value] ... ]"))
return return
end end
@ -53,7 +53,7 @@ if not next(args) then -- no args
print(string.format("alias %s='%s'", k, v)) print(string.format("alias %s='%s'", k, v))
end end
else else
for k,v in pairs(args) do for _,v in ipairs(args) do
checkArg(1,v,"string") checkArg(1,v,"string")
handlePair(splitPair(v)) handlePair(splitPair(v))
end end

View File

@ -2,7 +2,6 @@ local keyboard = require("keyboard")
local shell = require("shell") local shell = require("shell")
local term = require("term") -- TODO use tty and cursor position instead of global area and gpu local term = require("term") -- TODO use tty and cursor position instead of global area and gpu
local text = require("text") local text = require("text")
local unicode = require("unicode")
if not io.output().tty then if not io.output().tty then
return loadfile(shell.resolve("cat", "lua"), "bt", _G)(...) return loadfile(shell.resolve("cat", "lua"), "bt", _G)(...)
@ -28,7 +27,7 @@ end
local line = nil local line = nil
local function readlines(num) local function readlines(num)
local x, y, w, h = term.getGlobalArea() local _, _, w, h = term.getGlobalArea()
num = num or (h - 1) num = num or (h - 1)
for _ = 1, num do for _ = 1, num do
if not line then if not line then
@ -52,7 +51,7 @@ while true do
return return
end end
while true do while true do
local event, address, char, code = term.pull("key_down") local _, _, _, code = term.pull("key_down")
if code == keyboard.keys.q then if code == keyboard.keys.q then
term.clearLine() term.clearLine()
return return

View File

@ -5,70 +5,50 @@ local text = require("text")
local sh = require("sh") local sh = require("sh")
local input = table.pack(...) local input = table.pack(...)
local args, options = shell.parse(select(3,table.unpack(input))) local args = shell.parse(select(3,table.unpack(input)))
if input[2] then if input[2] then
table.insert(args, 1, input[2]) table.insert(args, 1, input[2])
end end
local history = {hint = sh.hintHandler} local history = {hint = sh.hintHandler}
shell.prime() shell.prime()
local update_gpu = io.output().tty
local interactive = io.input().tty
local foreground
if #args == 0 and (io.stdin.tty or options.i) and not options.c then if #args == 0 then
-- interactive shell.
-- source profile
if not tty.isAvailable() then event.pull("term_available") end
loadfile(shell.resolve("source","lua"))("/etc/profile")
while true do while true do
if not tty.isAvailable() then -- don't clear unless we lost the term if update_gpu then
while not tty.isAvailable() do while not tty.isAvailable() do
event.pull("term_available") event.pull("term_available")
end end
tty.clear() if not foreground and interactive then -- first time run AND interactive
end dofile("/etc/profile.lua")
local gpu = tty.gpu()
while tty.isAvailable() do
local foreground = gpu.setForeground(0xFF0000)
io.write(sh.expand(os.getenv("PS1") or "$ "))
gpu.setForeground(foreground)
tty.setCursorBlink(true)
local command = tty.read(history)
if not command then
if command == false then
break -- soft interrupt
end
io.write("exit\n") -- pipe closed
return -- eof
end end
foreground = tty.gpu().setForeground(0xFF0000)
io.write(sh.expand(os.getenv("PS1") or "$ "))
tty.gpu().setForeground(foreground)
tty.setCursorBlink(true)
end
local command = tty.read(history)
if command then
command = text.trim(command) command = text.trim(command)
if command == "exit" then if command == "exit" then
return return
elseif command ~= "" then elseif command ~= "" then
local result, reason = sh.execute(_ENV, command) local result, reason = sh.execute(_ENV, command)
if tty.getCursor() > 1 then if update_gpu and tty.getCursor() > 1 then
print() io.write("\n")
end end
if not result then if not result then
io.stderr:write((reason and tostring(reason) or "unknown error") .. "\n") io.stderr:write((reason and tostring(reason) or "unknown error") .. "\n")
end end
end end
end elseif command == nil then -- command==false is a soft interrupt, ignore it
end if interactive then
elseif #args == 0 and not io.stdin.tty then io.write("exit\n") -- pipe closed
while true do
io.write(sh.expand(os.getenv("PS1") or "$ "))
local command = io.read("*l")
if not command then
command = "exit"
io.write(command,"\n")
end
command = text.trim(command)
if command == "exit" then
return
elseif command ~= "" then
local result, reason = os.execute(command)
if not result then
io.stderr:write((reason and tostring(reason) or "unknown error") .. "\n")
end end
return -- eof
end end
end end
else else

View File

@ -1,6 +1,5 @@
local shell = require("shell") local shell = require("shell")
local fs = require("filesystem") local process = require("process")
local sh = require("sh")
local args, options = shell.parse(...) local args, options = shell.parse(...)
@ -9,23 +8,25 @@ if #args ~= 1 then
return 1 return 1
end end
local file, reason = io.open(args[1], "r") local file, open_reason = io.open(args[1], "r")
if not file then if not file then
if not options.q then if not options.q then
io.stderr:write(string.format("could not source %s because: %s\n", args[1], reason)); io.stderr:write(string.format("could not source %s because: %s\n", args[1], open_reason));
end end
return 1 return 1
else
local status, reason = xpcall(function()
repeat
local line = file:read()
if line then
sh.execute(nil, line)
end
until not line
end, function(msg) return {msg, debug.traceback()} end)
file:close()
if not status and reason then assert(false, tostring(reason[1]) .."\n".. tostring(reason[2])) end
end end
local current_data = process.info().data
local source_proc = process.load((assert(os.getenv("SHELL"), "no $SHELL set")))
local source_data = process.list[source_proc].data
source_data.aliases = current_data.aliases -- hacks to propogate sub shell env changes
source_data.vars = current_data.vars
source_data.io[0] = file -- set stdin to the file
if options.q then
source_data.io[1] = {tty=false,write=function()end} -- set stdin to the file
end
process.internal.continue(source_proc)
file:close() -- should have closed when the process closed, but just to be sure

View File

@ -2,9 +2,9 @@ function loadfile(filename, ...)
if filename:sub(1,1) ~= "/" then if filename:sub(1,1) ~= "/" then
filename = (os.getenv("PWD") or "/") .. "/" .. filename filename = (os.getenv("PWD") or "/") .. "/" .. filename
end end
local handle, reason = require("filesystem").open(filename) local handle, open_reason = require("filesystem").open(filename)
if not handle then if not handle then
return nil, reason return nil, open_reason
end end
local buffer = {} local buffer = {}
while true do while true do

View File

@ -1,26 +0,0 @@
alias dir=ls
alias move=mv
alias rename=mv
alias copy=cp
alias del=rm
alias md=mkdir
alias cls=clear
alias rs=redstone
alias view=edit\ -r
alias help=man
alias cp=cp\ -i
set EDITOR=/bin/edit
set HISTSIZE=10
set HOME=/home
set IFS=\
set MANPATH=/usr/man:.
set PAGER=/bin/more
set PS1='$HOSTNAME$HOSTNAME_SEPARATOR$PWD # '
set PWD=/
set LS_COLORS="{FILE=0xFFFFFF,DIR=0x66CCFF,LINK=0xFFAA00,['*.lua']=0x00FF00}"
cd $HOME
clear
/etc/motd
source $HOME/.shrc -q

View File

@ -0,0 +1,38 @@
local shell = require("shell")
local tty = require("tty")
local fs = require("filesystem")
tty.clear()
dofile("/etc/motd")
shell.setAlias("dir", "ls")
shell.setAlias("move", "mv")
shell.setAlias("rename", "mv")
shell.setAlias("copy", "cp")
shell.setAlias("del", "rm")
shell.setAlias("md", "mkdir")
shell.setAlias("cls", "clear")
shell.setAlias("rs", "redstone")
shell.setAlias("view", "edit -r")
shell.setAlias("help", "man")
shell.setAlias("cp", "cp -i")
shell.setAlias("l", "ls -lhp")
shell.setAlias("..", "cd ..")
shell.setAlias("df", "df -h")
shell.setAlias("grep", "grep --color")
os.setenv("EDITOR", "/bin/edit")
os.setenv("HISTSIZE", "10")
os.setenv("HOME", "/home")
os.setenv("IFS", " ")
os.setenv("MANPATH", "/usr/man:.")
os.setenv("PAGER", "/bin/more")
os.setenv("PS1", "$HOSTNAME$HOSTNAME_SEPARATOR$PWD # ")
os.setenv("LS_COLORS", "{FILE=0xFFFFFF,DIR=0x66CCFF,LINK=0xFFAA00,['*.lua']=0x00FF00}")
shell.setWorkingDirectory(os.getenv("HOME"))
local home_shrc = shell.resolve(".shrc")
if fs.exists(home_shrc) then
loadfile(shell.resolve("source", "lua"))(home_shrc, "-q")
end

View File

@ -1,5 +0,0 @@
alias l="ls -lhp"
alias ..="cd .."
alias df="df -h"
alias grep="grep --color"

View File

@ -1,7 +1,7 @@
-- called from /init.lua -- called from /init.lua
local raw_loadfile = ... local raw_loadfile = ...
_G._OSVERSION = "OpenOS 1.6.5" _G._OSVERSION = "OpenOS 1.6.6"
local component = component local component = component
local computer = computer local computer = computer

View File

@ -253,7 +253,7 @@ local function display(names)
max_size_width = math.max(max_size_width, formatSize(info.size):len()) max_size_width = math.max(max_size_width, formatSize(info.size):len())
max_date_width = math.max(max_date_width, formatDate(info.time):len()) max_date_width = math.max(max_date_width, formatDate(info.time):len())
end end
mt.__index = function(tbl, index) mt.__index = function(_, index)
local info = stat(names, index) local info = stat(names, index)
local file_type = info.isLink and 'l' or info.isDir and 'd' or 'f' local file_type = info.isLink and 'l' or info.isDir and 'd' or 'f'
local link_target = info.isLink and string.format(" -> %s", info.link:gsub("/+$", "") .. (info.isDir and "/" or "")) or "" local link_target = info.isLink and string.format(" -> %s", info.link:gsub("/+$", "") .. (info.isDir and "/" or "")) or ""
@ -267,7 +267,7 @@ local function display(names)
end end
elseif ops["1"] or not fOut then elseif ops["1"] or not fOut then
lines.n = #names lines.n = #names
mt.__index = function(tbl, index) mt.__index = function(_, index)
local info = stat(names, index) local info = stat(names, index)
return {{color = colorize(info), name = info.name}} return {{color = colorize(info), name = info.name}}
end end
@ -302,10 +302,10 @@ local function display(names)
end end
end end
lines.n = items_per_column lines.n = items_per_column
mt.__index=function(tbl, line_index) mt.__index=function(_, line_index)
return setmetatable({},{ return setmetatable({},{
__len=function()return num_columns end, __len=function()return num_columns end,
__index=function(tbl, column_index) __index=function(_, column_index)
local ri = real(column_index, line_index) local ri = real(column_index, line_index)
if not ri then return end if not ri then return end
local info = stat(names, ri) local info = stat(names, ri)

View File

@ -18,11 +18,11 @@ function shell.getShell()
if shells[shellName] then if shells[shellName] then
return shells[shellName] return shells[shellName]
end end
local sh, reason = loadfile(shellName) local sh, load_reason = loadfile(shellName)
if sh then if sh then
shells[shellName] = sh shells[shellName] = sh
end end
return sh, reason return sh, load_reason
end end
------------------------------------------------------------------------------- -------------------------------------------------------------------------------

View File

@ -22,7 +22,7 @@ Many component methods have a short documentation - use `=component.componentNam
You can get a list of all attached components using the `components` program. You can get a list of all attached components using the `components` program.
If you encounter out of memory errors, throw more RAM at your computer. If you encounter out of memory errors, throw more RAM at your computer.
Have you tried turning it off and on again? Have you tried turning it off and on again?
To disable this greeting, install OpenOS to a writeable medium and remove the `/etc/motd` line from `/etc/profile`. To disable this greeting, install OpenOS to a writeable medium and remove the `/etc/motd` line from `/etc/profile.lua`.
Did you know OpenComputers has a forum? No? Well, it's at https://oc.cil.li/. Did you know OpenComputers has a forum? No? Well, it's at https://oc.cil.li/.
Please report bugs on the Github issue tracker, thank you! Please report bugs on the Github issue tracker, thank you!
Beware of cycles when building networks, or you may get duplicate messages! Beware of cycles when building networks, or you may get duplicate messages!