ALPHA 3.0.0 - Added Inter-Process Communication and fixed the bug where the shell would continue taking in input when a command was still running.
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
.stfolder
|
||||||
+3
-3
@@ -1,10 +1,10 @@
|
|||||||
print("\27[44m".._VERSION.."\27[0m shell")
|
print("\27[44m".._VERSION.."\27[0m shell")
|
||||||
print('Type "exit" to exit.')
|
print('Type "exit" to exit.')
|
||||||
termlib.readHistory["lua"] = {""}
|
terminal.readHistory["lua"] = {""}
|
||||||
local fs = require("filesystem")
|
local fs = require("filesystem")
|
||||||
|
|
||||||
local loadedLibraries = ""
|
local loadedLibraries = ""
|
||||||
local libList = fs.list("halyde/lib")
|
local libList = fs.list("/lib/")
|
||||||
for _, lib in pairs(libList) do
|
for _, lib in pairs(libList) do
|
||||||
if lib:match("(.+)%.lua") then
|
if lib:match("(.+)%.lua") then
|
||||||
loadedLibraries = loadedLibraries .. "local " .. lib:match("(.+)%.lua") .. ' = require("' .. lib:match("(.+)%.lua") .. '")\n'
|
loadedLibraries = loadedLibraries .. "local " .. lib:match("(.+)%.lua") .. ' = require("' .. lib:match("(.+)%.lua") .. '")\n'
|
||||||
@@ -12,7 +12,7 @@ for _, lib in pairs(libList) do
|
|||||||
end
|
end
|
||||||
|
|
||||||
while true do
|
while true do
|
||||||
local command = read("lua", "\27[44mlua>\27[0m ")
|
local command = terminal.read("lua", "\27[44mlua>\27[0m ")
|
||||||
if command == "exit" then
|
if command == "exit" then
|
||||||
return
|
return
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ local filesystem = assert(loadfile("/lib/filesystem.lua")(loadfile))
|
|||||||
_G._OSVERSION = "HALYDE VERSION" -- TODO: Put this in a separate config file
|
_G._OSVERSION = "HALYDE VERSION" -- TODO: Put this in a separate config file
|
||||||
_G._OSLOGO = ""
|
_G._OSLOGO = ""
|
||||||
_G._PUBLIC = {}
|
_G._PUBLIC = {}
|
||||||
local ocelot = component.proxy(component.list("ocelot")())
|
|
||||||
|
|
||||||
local handle, tmpdata = filesystem.open("/halyde/config/oslogo.ans", "r"), nil
|
local handle, tmpdata = filesystem.open("/halyde/config/oslogo.ans", "r"), nil
|
||||||
repeat
|
repeat
|
||||||
@@ -16,7 +15,6 @@ _G.package = {["preloaded"] = {}}
|
|||||||
loadfile("/halyde/kernel/modules/datatools.lua")()
|
loadfile("/halyde/kernel/modules/datatools.lua")()
|
||||||
|
|
||||||
function _G.require(module, ...)
|
function _G.require(module, ...)
|
||||||
ocelot.log("Requiring " .. module)
|
|
||||||
local args = table.pack(...)
|
local args = table.pack(...)
|
||||||
if package.preloaded[module] then
|
if package.preloaded[module] then
|
||||||
return package.preloaded[module]
|
return package.preloaded[module]
|
||||||
@@ -50,7 +48,7 @@ function _G.package.preload(module)
|
|||||||
_G[module] = nil
|
_G[module] = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
require("/halyde/kernel/datatools.lua") -- If this is not imported BEFORE modload gets run, modload requires filesystem which requires computer which requires datatools.
|
require("/halyde/kernel/datatools.lua") -- If this is not imported BEFORE modload gets run, modload requires filesystem which requires computer which requires datatools. TODO: When VFS is implemented, make the pre-VFS loading of filesystem load a more basic version. And remove this.
|
||||||
require("/halyde/kernel/modload.lua")
|
require("/halyde/kernel/modload.lua")
|
||||||
|
|
||||||
package.preload("component")
|
package.preload("component")
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ while true do
|
|||||||
if print then
|
if print then
|
||||||
print("\n\27[91mCoroutine "..tostring(#tsched.tasks).." killed.")
|
print("\n\27[91mCoroutine "..tostring(#tsched.tasks).." killed.")
|
||||||
end
|
end
|
||||||
tsched.tasks[#tsched.tasks] = nil
|
table.remove(tsched.tasks, #tsched.tasks)
|
||||||
end
|
end
|
||||||
elseif args[2] == "key_up" then
|
elseif args[2] == "key_up" then
|
||||||
local keycode = args[5]
|
local keycode = args[5]
|
||||||
|
|||||||
@@ -1,19 +1,16 @@
|
|||||||
local fs = require("filesystem")
|
local fs = require("filesystem")
|
||||||
local ocelot = require("component").ocelot
|
|
||||||
|
|
||||||
local modulePath = "/halyde/kernel/modules"
|
local modulePath = "/halyde/kernel/modules"
|
||||||
|
|
||||||
local modules = fs.list(modulePath)
|
local modules = assert(fs.list(modulePath))
|
||||||
local moduleTypes = {}
|
local moduleTypes = {}
|
||||||
|
|
||||||
local function loadModule(modName)
|
local function loadModule(modName)
|
||||||
ocelot.log("Checking module " .. modName)
|
local moduleData = assert(require(fs.concat(modulePath, modName)), "Module did not return anything!") -- TODO: Make this not actually throw an error, rather put something in the log and move on
|
||||||
local moduleData = require(fs.concat(modulePath, modName))
|
|
||||||
table.remove(modules, table.find(modules, modName))
|
table.remove(modules, table.find(modules, modName))
|
||||||
if not moduleData.check() then
|
if not moduleData.check() then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
ocelot.log("Loading module " .. modName)
|
|
||||||
if moduleData.dependencies then
|
if moduleData.dependencies then
|
||||||
for _, dependency in pairs(moduleData.dependencies) do
|
for _, dependency in pairs(moduleData.dependencies) do
|
||||||
if table.find(modules, dependency) then
|
if table.find(modules, dependency) then
|
||||||
@@ -37,7 +34,7 @@ local function loadModule(modName)
|
|||||||
end
|
end
|
||||||
|
|
||||||
for _, modName in pairs(modules) do -- Get all the module types
|
for _, modName in pairs(modules) do -- Get all the module types
|
||||||
local moduleData = require(fs.concat(modulePath, modName))
|
local moduleData = assert(require(fs.concat(modulePath, modName)), "Module did not return anything!") -- TODO: Make this not actually throw an error, rather put something in the log and move on
|
||||||
if moduleData.type then
|
if moduleData.type then
|
||||||
--print(moduleData.type)
|
--print(moduleData.type)
|
||||||
moduleTypes[modName] = moduleData.type -- Not the other way around because there can be multiple modules of the same type, but there can't be multiple entries with the same key
|
moduleTypes[modName] = moduleData.type -- Not the other way around because there can be multiple modules of the same type, but there can't be multiple entries with the same key
|
||||||
@@ -49,5 +46,3 @@ while modules[1] do
|
|||||||
loadModule(modules[1])
|
loadModule(modules[1])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
ocelot.log("Finished loading modules!")
|
|
||||||
|
|||||||
@@ -1,15 +1,125 @@
|
|||||||
local module = {}
|
local module = {}
|
||||||
|
|
||||||
function module.check()
|
function module.check()
|
||||||
return true -- This module should always be loaded
|
return true -- IPC should always be loaded
|
||||||
end
|
end
|
||||||
|
|
||||||
function module.init()
|
function module.init()
|
||||||
|
_G.ipc = {}
|
||||||
|
_G.ipc.shared = {}
|
||||||
|
_PUBLIC.ipc = {}
|
||||||
|
|
||||||
|
function _PUBLIC.ipc.shareWithAll()
|
||||||
|
local shareTable = {}
|
||||||
|
setmetatable(shareTable, {["__newindex"] = function(_, key, value)
|
||||||
|
local currentPID = _PUBLIC.tsched.getCurrentTask().id
|
||||||
|
if not _G.ipc.shared[currentPID] then
|
||||||
|
_G.ipc.shared[currentPID] = {} -- TODO: Add some kind of cleanup routine since these IPC shares can just keep piling up
|
||||||
|
end
|
||||||
|
local globalTable
|
||||||
|
for _, tab in pairs(_G.ipc.shared[currentPID]) do
|
||||||
|
if tab.sharedWith == "all" then
|
||||||
|
globalTable = tab
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if not globalTable then
|
||||||
|
globalTable = {["sharedWith"] = "all"}
|
||||||
|
table.insert(_G.ipc.shared[currentPID], globalTable)
|
||||||
|
end
|
||||||
|
if not globalTable.vars then
|
||||||
|
globalTable.vars = {}
|
||||||
|
end
|
||||||
|
globalTable.vars[key] = value
|
||||||
|
end, ["__index"] = function(_, key)
|
||||||
|
local currentPID = _PUBLIC.tsched.getCurrentTask().id
|
||||||
|
if not _G.ipc.shared[currentPID] then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
local globalTable
|
||||||
|
for _, tab in pairs(_G.ipc.shared[currentPID]) do
|
||||||
|
if tab.sharedWith == "all" then
|
||||||
|
globalTable = tab
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if not globalTable then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
if not globalTable.vars then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
return globalTable.vars[key]
|
||||||
|
end})
|
||||||
|
return shareTable
|
||||||
|
end
|
||||||
|
|
||||||
|
function _PUBLIC.ipc.shareWith(pid)
|
||||||
|
checkArg(1, pid, "number")
|
||||||
|
local shareTable = {}
|
||||||
|
setmetatable(shareTable, {["__newindex"] = function(_, key, value)
|
||||||
|
local currentPID = _PUBLIC.tsched.getCurrentTask().id
|
||||||
|
if not _G.ipc.shared[currentPID] then
|
||||||
|
_G.ipc.shared[currentPID] = {} -- TODO: Add some kind of cleanup routine since these IPC shares can just keep piling up
|
||||||
|
end
|
||||||
|
local globalTable
|
||||||
|
for _, tab in pairs(_G.ipc.shared[currentPID]) do
|
||||||
|
if tab.sharedWith == "all" then
|
||||||
|
globalTable = tab
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if not globalTable then
|
||||||
|
globalTable = {["sharedWith"] = pid}
|
||||||
|
table.insert(_G.ipc.shared[currentPID], globalTable)
|
||||||
|
end
|
||||||
|
if not globalTable.vars then
|
||||||
|
globalTable.vars = {}
|
||||||
|
end
|
||||||
|
globalTable.vars[key] = value
|
||||||
|
end, ["__index"] = function(_, key)
|
||||||
|
local currentPID = _PUBLIC.tsched.getCurrentTask().id
|
||||||
|
if not _G.ipc.shared[currentPID] then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
local globalTable
|
||||||
|
for _, tab in pairs(_G.ipc.shared[currentPID]) do
|
||||||
|
if tab.sharedWith == pid then
|
||||||
|
globalTable = tab
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if not globalTable then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
if not globalTable.vars then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
return globalTable.vars[key]
|
||||||
|
end})
|
||||||
|
return shareTable
|
||||||
|
end
|
||||||
|
|
||||||
|
_PUBLIC.ipc.shared = {}
|
||||||
|
setmetatable(_PUBLIC.ipc.shared, {["__index"] = function(_, pid)
|
||||||
|
local currentPID = _PUBLIC.tsched.getCurrentTask().id
|
||||||
|
local returnTable = {}
|
||||||
|
for _, shareTable in pairs(ipc.shared[pid] or {}) do
|
||||||
|
if shareTable.sharedWith == currentPID then
|
||||||
|
for key, value in pairs(shareTable.vars) do
|
||||||
|
returnTable[key] = table.copy(value)
|
||||||
|
end
|
||||||
|
elseif shareTable.sharedWith == "all" then
|
||||||
|
for key, value in pairs(shareTable.vars) do
|
||||||
|
if not returnTable[key] then
|
||||||
|
returnTable[key] = table.copy(value)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return returnTable
|
||||||
|
end})
|
||||||
end
|
end
|
||||||
|
|
||||||
function module.exit()
|
function module.exit()
|
||||||
|
_G.ipc = nil
|
||||||
|
_PUBLIC.ipc = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
return module
|
return module
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
local idCounter = 1
|
||||||
|
|
||||||
_G._PUBLIC.tsched = {}
|
_G._PUBLIC.tsched = {}
|
||||||
_G.tsched = {}
|
_G.tsched = {}
|
||||||
_G.tsched.tasks = {}
|
_G.tsched.tasks = {}
|
||||||
@@ -9,8 +11,6 @@ local computer = require("computer")
|
|||||||
local filesystem = require("filesystem")
|
local filesystem = require("filesystem")
|
||||||
local json = require("json")
|
local json = require("json")
|
||||||
local gpu = component.gpu
|
local gpu = component.gpu
|
||||||
local ocelot = component.ocelot
|
|
||||||
|
|
||||||
function _G._PUBLIC.tsched.runAsTask(path,...)
|
function _G._PUBLIC.tsched.runAsTask(path,...)
|
||||||
local args = {...}
|
local args = {...}
|
||||||
local function taskFunction()
|
local function taskFunction()
|
||||||
@@ -48,15 +48,21 @@ function _G._PUBLIC.tsched.runAsTask(path,...)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function _G._PUBLIC.tsched.addTask(func, name)
|
function _G._PUBLIC.tsched.addTask(func, name)
|
||||||
ocelot.log("Added task " .. name)
|
|
||||||
local task = coroutine.create(func)
|
local task = coroutine.create(func)
|
||||||
table.insert(tsched.tasks, {["task"] = task, ["name"] = name})
|
table.insert(tsched.tasks, {["task"] = task, ["name"] = name, ["id"] = idCounter})
|
||||||
|
idCounter = idCounter + 1
|
||||||
return task
|
return task
|
||||||
end
|
end
|
||||||
|
|
||||||
function _G._PUBLIC.tsched.removeTask(id)
|
function _G._PUBLIC.tsched.removeTask(id)
|
||||||
-- TODO: Check for user permissions before running
|
-- TODO: Check for user permissions before running
|
||||||
table.remove(_G.tsched.tasks, id)
|
for index, task in pairs(tsched.tasks) do
|
||||||
|
if task.id == id then
|
||||||
|
table.remove(tsched.tasks, index)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
function handleError(errormsg)
|
function handleError(errormsg)
|
||||||
@@ -76,7 +82,7 @@ local function runTasks()
|
|||||||
handleError(errorMessage)
|
handleError(errorMessage)
|
||||||
end
|
end
|
||||||
if coroutine.status(tsched.tasks[i].task) == "dead" then
|
if coroutine.status(tsched.tasks[i].task) == "dead" then
|
||||||
_PUBLIC.tsched.removeTask(i)
|
_PUBLIC.tsched.removeTask(tsched.tasks[i].id)
|
||||||
--ocelot.log("Removed coroutine")
|
--ocelot.log("Removed coroutine")
|
||||||
i = i - 1
|
i = i - 1
|
||||||
end
|
end
|
||||||
|
|||||||
+15
-5
@@ -17,11 +17,21 @@ _G.shell.aliases = shellcfg["aliases"]
|
|||||||
local function runAsTask(path, ...)
|
local function runAsTask(path, ...)
|
||||||
--ocelot.log("running " .. path .. " as coroutine")
|
--ocelot.log("running " .. path .. " as coroutine")
|
||||||
tsched.runAsTask(path, ...)
|
tsched.runAsTask(path, ...)
|
||||||
local corIndex = #tsched.getTasks()
|
local pid = tsched.getTasks()[#tsched.getTasks()].id
|
||||||
local task = tsched.getTasks()[#tsched.getTasks()]
|
while true do
|
||||||
repeat
|
local foundTask = false
|
||||||
coroutine.yield()
|
for _, task in pairs(tsched.getTasks()) do
|
||||||
until tsched.getTasks()[corIndex] ~= task
|
if task.id == pid then
|
||||||
|
foundTask = true
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if foundTask then
|
||||||
|
coroutine.yield()
|
||||||
|
else
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function _G.shell.run(command)
|
function _G.shell.run(command)
|
||||||
|
|||||||
+6
-7
@@ -1,7 +1,6 @@
|
|||||||
local cor = coroutine.create(function()
|
local pid = tsched.getCurrentTask().id
|
||||||
print("Hello World!")
|
local shareTable = ipc.shareWith(pid)
|
||||||
end)
|
shareTable.gabbagool = "Pigeon Pizza! Wow!"
|
||||||
|
print(shareTable.gabbagool)
|
||||||
print(coroutine.status(cor))
|
print(pid)
|
||||||
coroutine.resume(cor)
|
print(ipc.shared[pid].gabbagool)
|
||||||
print(coroutine.status(cor))
|
|
||||||
|
|||||||
@@ -1,25 +1,6 @@
|
|||||||
local gpu = component.proxy(component.list("gpu")())
|
local gpu = component.proxy(component.list("gpu")())
|
||||||
local resX, resY = gpu.getResolution()
|
local resX, resY = gpu.getResolution()
|
||||||
|
|
||||||
-- Architecture check
|
|
||||||
local foundArchitecture = false
|
|
||||||
for _, arch in pairs(computer.getArchitectures()) do
|
|
||||||
if arch == "Lua 5.3" then
|
|
||||||
foundArchitecture = true
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if foundArchitecture then
|
|
||||||
computer.setArchitecture("Lua 5.3")
|
|
||||||
else
|
|
||||||
gpu.set(1, 1, "Required architecture (Lua 5.3) is not supported.")
|
|
||||||
gpu.set(1, 2, "Halting.")
|
|
||||||
while true do
|
|
||||||
computer.pullSignal()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function loadfile(file)
|
local function loadfile(file)
|
||||||
checkArg(1, file, "string")
|
checkArg(1, file, "string")
|
||||||
local handle = component.invoke(computer.getBootAddress(), "open", file, "r")
|
local handle = component.invoke(computer.getBootAddress(), "open", file, "r")
|
||||||
@@ -37,6 +18,26 @@ local function handleError(errorMessage)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function loadBoot()
|
function loadBoot()
|
||||||
|
local foundArchitecture = false
|
||||||
|
for _, arch in pairs(computer.getArchitectures()) do
|
||||||
|
if arch == "Lua 5.3" then
|
||||||
|
foundArchitecture = true
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if foundArchitecture then
|
||||||
|
local _, errorMesage = computer.setArchitecture("Lua 5.3")
|
||||||
|
if errorMessage then
|
||||||
|
error(errorMessage)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
gpu.set(1, 1, "Required architecture (Lua 5.3) is not supported.")
|
||||||
|
gpu.set(1, 2, "Halting.")
|
||||||
|
while true do
|
||||||
|
computer.pullSignal()
|
||||||
|
end
|
||||||
|
end
|
||||||
loadfile("/halyde/kernel/boot.lua")(loadfile)
|
loadfile("/halyde/kernel/boot.lua")(loadfile)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -45,28 +46,43 @@ gpu.fill(1, 1, resX, resY, " ")
|
|||||||
|
|
||||||
-- Copying low-level functions in case of post-preload failure
|
-- Copying low-level functions in case of post-preload failure
|
||||||
local pullSignal = computer.pullSignal
|
local pullSignal = computer.pullSignal
|
||||||
local shutdown = computer.shutdown
|
local beep = computer.beep
|
||||||
|
|
||||||
local result, reason = xpcall(loadBoot, handleError)
|
local result, reason = xpcall(loadBoot, handleError)
|
||||||
if not result then
|
if not result then
|
||||||
gpu.setBackground(0x000000)
|
local bgColor
|
||||||
gpu.fill(1, 1, resX, resY, " ")
|
if gpu.getDepth() == 1 then
|
||||||
gpu.setBackground(0x800000)
|
bgColor = 0x000000
|
||||||
gpu.setForeground(0xFFFFFF)
|
else
|
||||||
gpu.set(2,2,"A critical error has occurred.")
|
bgColor = 0x000080
|
||||||
local i = 4
|
|
||||||
reason = tostring(reason):gsub("\t", " ")
|
|
||||||
for line in string.gmatch(reason or "unknown error", "([^\n]*)\n?") do
|
|
||||||
gpu.set(2,i,line)
|
|
||||||
i = i + 1
|
|
||||||
end
|
end
|
||||||
gpu.set(2,i+1, "Press any key to restart.")
|
gpu.setBackground(bgColor)
|
||||||
local evname
|
gpu.fill(1, 1, resX, resY, " ")
|
||||||
repeat
|
local function render()
|
||||||
evname = pullSignal()
|
gpu.setForeground(0xFFFFFF)
|
||||||
until evname == "key_down"
|
local i = 2
|
||||||
shutdown(true)
|
reason = "A fatal error has occurred.\nHalyde cannot continue.\n \n" .. tostring(reason or "unknown error"):gsub("\t", " ")
|
||||||
while true do
|
for line in string.gmatch(reason, "([^\n]*)\n?") do
|
||||||
coroutine.yield()
|
gpu.set(2, i, line)
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
|
gpu.set(1, resY - 1, string.rep("─", resX))
|
||||||
|
gpu.setForeground(bgColor)
|
||||||
|
gpu.setBackground(0xFFFFFF)
|
||||||
|
gpu.set(2, resY, "🠅 🠄 🠇 🠆")
|
||||||
|
gpu.setForeground(0xFFFFFF)
|
||||||
|
gpu.setBackground(bgColor)
|
||||||
|
gpu.set(4, resY, " / ")
|
||||||
|
gpu.set(9, resY, " / ")
|
||||||
|
gpu.set(14, resY, " / ")
|
||||||
|
gpu.set(20, resY, "Scroll" .. string.rep(" ", resX - 21))
|
||||||
|
end
|
||||||
|
render()
|
||||||
|
beep(440, 0.2)
|
||||||
|
beep(465, 0.2)
|
||||||
|
beep(440, 0.2)
|
||||||
|
beep(370, 0.5)
|
||||||
|
while true do -- TODO: Make this scrollable
|
||||||
|
pullSignal()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user