f5fcc84903
when the user kernel module creates a task, it used to count the amount of processes in the system, which can lead to some processes having the same IDs as another, which causes havoc. this has been fixed by using the ID counter in the tsched kernel module.
127 lines
3.7 KiB
Lua
127 lines
3.7 KiB
Lua
local module = {}
|
|
|
|
module.dependencies = {}
|
|
|
|
function module.check()
|
|
return true
|
|
end
|
|
|
|
function module.init()
|
|
_G._PUBLIC.tsched = {}
|
|
_G.tsched = {}
|
|
_G.tsched.tasks = {}
|
|
|
|
local component = require("component")
|
|
local filesystem = require("filesystem")
|
|
local gpu = component.gpu
|
|
local log = require("log")
|
|
|
|
tsched.idCounter = 1
|
|
|
|
function _G._PUBLIC.tsched.runAsTask(path, ...)
|
|
checkArg(1, path, "string")
|
|
local args = { ... }
|
|
local function taskFunction()
|
|
local result, errorMessage = xpcall(function(...)
|
|
local args = table.pack(...)
|
|
if not filesystem.exists(path) then
|
|
error("No such file: " .. path)
|
|
end
|
|
local handle, data, tmpdata = filesystem.open(path), "", nil
|
|
repeat
|
|
tmpdata = handle:read(math.huge or math.maxinteger)
|
|
data = data .. (tmpdata or "")
|
|
until not tmpdata
|
|
handle:close()
|
|
|
|
-- Userland environment definition
|
|
local userland = table.copy(_PUBLIC)
|
|
userland._G = userland
|
|
userland.load = function(chunk, chunkname, mode, env)
|
|
if not env or env == _G then
|
|
env = userland
|
|
end -- if they SOMEHOW get the kernel environment they're not running jack shit
|
|
return load(chunk, chunkname, mode, env)
|
|
end
|
|
userland.require = reqgen(userland.load)
|
|
|
|
assert(load(data, "=" .. path, "t", userland))(table.unpack(args))
|
|
end, function(errorMessage)
|
|
return errorMessage .. "\n \n" .. debug.traceback()
|
|
end, --[[ path,]] table.unpack(args))
|
|
if not result then
|
|
if print then
|
|
gpu.freeAllBuffers()
|
|
print("\n\27[91m" .. errorMessage)
|
|
else
|
|
error(errorMessage)
|
|
end
|
|
end
|
|
--require(path, table.unpack(args))
|
|
end
|
|
local _, taskInfo = _PUBLIC.tsched.addTask(taskFunction, string.match(tostring(path), "([^/]+)%.lua$"))
|
|
taskInfo.path = path
|
|
taskInfo.args = table.copy(args)
|
|
end
|
|
|
|
function _G._PUBLIC.tsched.addTask(func, name)
|
|
checkArg(1, func, "function")
|
|
checkArg(2, name, "string")
|
|
local task = coroutine.create(func)
|
|
local taskInfo = { ["task"] = task, ["name"] = name, ["id"] = tsched.idCounter }
|
|
if type(tsched.currentTask) == "table" and type(tsched.currentTask.id) == "number" then
|
|
taskInfo.parent = tsched.currentTask.id
|
|
taskInfo.user = tsched.currentTask.user
|
|
end
|
|
table.insert(tsched.tasks, taskInfo)
|
|
tsched.idCounter = tsched.idCounter + 1
|
|
if taskInfo.parent then
|
|
log.kernel.info(
|
|
("[tsched] Created task %s (PID %d) by parent PID %d as UID %d"):format(
|
|
name,
|
|
tsched.idCounter - 1,
|
|
taskInfo.parent,
|
|
taskInfo.user
|
|
)
|
|
)
|
|
else
|
|
taskInfo.user = 1 -- It's probably being run from kernel level
|
|
log.kernel.info(
|
|
string.format("[tsched] Created task %s (PID %d) as UID 1 (no parent found)", name, tsched.idCounter - 1)
|
|
)
|
|
end
|
|
return task, taskInfo
|
|
end
|
|
|
|
function _G._PUBLIC.tsched.removeTask(id)
|
|
checkArg(1, id, "number")
|
|
-- TODO: Check for user permissions before running
|
|
for index, task in pairs(tsched.tasks) do
|
|
if task.id == id then
|
|
table.remove(tsched.tasks, index)
|
|
log.kernel.info(string.format("[tsched] Removed task with PID %d", id))
|
|
return true
|
|
end
|
|
end
|
|
log.kernel.warn(string.format("[tsched] Tried to remove task that doesn't exist - PID %d", id))
|
|
return false
|
|
end
|
|
|
|
function _G._PUBLIC.tsched.getCurrentTask()
|
|
return table.copy(tsched.currentTask)
|
|
end
|
|
|
|
function _G._PUBLIC.tsched.getTasks()
|
|
return table.copy(tsched.tasks)
|
|
end
|
|
end
|
|
|
|
function module.exit()
|
|
-- why would you even want to
|
|
_G._PUBLIC.tsched = nil
|
|
_G.tsched = nil
|
|
_G.tsched.tasks = nil
|
|
end
|
|
|
|
return module
|