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:
WahPlus
2025-08-21 21:03:17 +03:00
parent 5276d2437b
commit ef0ffa1886
10 changed files with 208 additions and 73 deletions
+1
View File
@@ -0,0 +1 @@
.stfolder
+3 -3
View File
@@ -1,10 +1,10 @@
print("\27[44m".._VERSION.."\27[0m shell")
print('Type "exit" to exit.')
termlib.readHistory["lua"] = {""}
terminal.readHistory["lua"] = {""}
local fs = require("filesystem")
local loadedLibraries = ""
local libList = fs.list("halyde/lib")
local libList = fs.list("/lib/")
for _, lib in pairs(libList) do
if lib:match("(.+)%.lua") then
loadedLibraries = loadedLibraries .. "local " .. lib:match("(.+)%.lua") .. ' = require("' .. lib:match("(.+)%.lua") .. '")\n'
@@ -12,7 +12,7 @@ for _, lib in pairs(libList) do
end
while true do
local command = read("lua", "\27[44mlua>\27[0m ")
local command = terminal.read("lua", "\27[44mlua>\27[0m ")
if command == "exit" then
return
else
+1 -3
View File
@@ -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._OSLOGO = ""
_G._PUBLIC = {}
local ocelot = component.proxy(component.list("ocelot")())
local handle, tmpdata = filesystem.open("/halyde/config/oslogo.ans", "r"), nil
repeat
@@ -16,7 +15,6 @@ _G.package = {["preloaded"] = {}}
loadfile("/halyde/kernel/modules/datatools.lua")()
function _G.require(module, ...)
ocelot.log("Requiring " .. module)
local args = table.pack(...)
if package.preloaded[module] then
return package.preloaded[module]
@@ -50,7 +48,7 @@ function _G.package.preload(module)
_G[module] = nil
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")
package.preload("component")
+1 -1
View File
@@ -30,7 +30,7 @@ while true do
if print then
print("\n\27[91mCoroutine "..tostring(#tsched.tasks).." killed.")
end
tsched.tasks[#tsched.tasks] = nil
table.remove(tsched.tasks, #tsched.tasks)
end
elseif args[2] == "key_up" then
local keycode = args[5]
+3 -8
View File
@@ -1,19 +1,16 @@
local fs = require("filesystem")
local ocelot = require("component").ocelot
local modulePath = "/halyde/kernel/modules"
local modules = fs.list(modulePath)
local modules = assert(fs.list(modulePath))
local moduleTypes = {}
local function loadModule(modName)
ocelot.log("Checking module " .. modName)
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
table.remove(modules, table.find(modules, modName))
if not moduleData.check() then
return
end
ocelot.log("Loading module " .. modName)
if moduleData.dependencies then
for _, dependency in pairs(moduleData.dependencies) do
if table.find(modules, dependency) then
@@ -37,7 +34,7 @@ local function loadModule(modName)
end
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
--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
@@ -49,5 +46,3 @@ while modules[1] do
loadModule(modules[1])
end
end
ocelot.log("Finished loading modules!")
+112 -2
View File
@@ -1,15 +1,125 @@
local module = {}
function module.check()
return true -- This module should always be loaded
return true -- IPC should always be loaded
end
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
function module.exit()
_G.ipc = nil
_PUBLIC.ipc = nil
end
return module
+12 -6
View File
@@ -1,3 +1,5 @@
local idCounter = 1
_G._PUBLIC.tsched = {}
_G.tsched = {}
_G.tsched.tasks = {}
@@ -9,8 +11,6 @@ local computer = require("computer")
local filesystem = require("filesystem")
local json = require("json")
local gpu = component.gpu
local ocelot = component.ocelot
function _G._PUBLIC.tsched.runAsTask(path,...)
local args = {...}
local function taskFunction()
@@ -48,15 +48,21 @@ function _G._PUBLIC.tsched.runAsTask(path,...)
end
function _G._PUBLIC.tsched.addTask(func, name)
ocelot.log("Added task " .. name)
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
end
function _G._PUBLIC.tsched.removeTask(id)
-- 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
function handleError(errormsg)
@@ -76,7 +82,7 @@ local function runTasks()
handleError(errorMessage)
end
if coroutine.status(tsched.tasks[i].task) == "dead" then
_PUBLIC.tsched.removeTask(i)
_PUBLIC.tsched.removeTask(tsched.tasks[i].id)
--ocelot.log("Removed coroutine")
i = i - 1
end
+14 -4
View File
@@ -17,11 +17,21 @@ _G.shell.aliases = shellcfg["aliases"]
local function runAsTask(path, ...)
--ocelot.log("running " .. path .. " as coroutine")
tsched.runAsTask(path, ...)
local corIndex = #tsched.getTasks()
local task = tsched.getTasks()[#tsched.getTasks()]
repeat
local pid = tsched.getTasks()[#tsched.getTasks()].id
while true do
local foundTask = false
for _, task in pairs(tsched.getTasks()) do
if task.id == pid then
foundTask = true
break
end
end
if foundTask then
coroutine.yield()
until tsched.getTasks()[corIndex] ~= task
else
break
end
end
end
function _G.shell.run(command)
+6 -7
View File
@@ -1,7 +1,6 @@
local cor = coroutine.create(function()
print("Hello World!")
end)
print(coroutine.status(cor))
coroutine.resume(cor)
print(coroutine.status(cor))
local pid = tsched.getCurrentTask().id
local shareTable = ipc.shareWith(pid)
shareTable.gabbagool = "Pigeon Pizza! Wow!"
print(shareTable.gabbagool)
print(pid)
print(ipc.shared[pid].gabbagool)
+51 -35
View File
@@ -1,25 +1,6 @@
local gpu = component.proxy(component.list("gpu")())
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)
checkArg(1, file, "string")
local handle = component.invoke(computer.getBootAddress(), "open", file, "r")
@@ -37,6 +18,26 @@ local function handleError(errorMessage)
end
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)
end
@@ -45,28 +46,43 @@ gpu.fill(1, 1, resX, resY, " ")
-- Copying low-level functions in case of post-preload failure
local pullSignal = computer.pullSignal
local shutdown = computer.shutdown
local beep = computer.beep
local result, reason = xpcall(loadBoot, handleError)
if not result then
gpu.setBackground(0x000000)
local bgColor
if gpu.getDepth() == 1 then
bgColor = 0x000000
else
bgColor = 0x000080
end
gpu.setBackground(bgColor)
gpu.fill(1, 1, resX, resY, " ")
gpu.setBackground(0x800000)
local function render()
gpu.setForeground(0xFFFFFF)
gpu.set(2,2,"A critical error has occurred.")
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)
local i = 2
reason = "A fatal error has occurred.\nHalyde cannot continue.\n \n" .. tostring(reason or "unknown error"):gsub("\t", " ")
for line in string.gmatch(reason, "([^\n]*)\n?") do
gpu.set(2, i, line)
i = i + 1
end
gpu.set(2,i+1, "Press any key to restart.")
local evname
repeat
evname = pullSignal()
until evname == "key_down"
shutdown(true)
while true do
coroutine.yield()
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