mirror of
https://github.com/NeoFlock/neonucleus.git
synced 2025-09-24 09:03:32 +02:00
150 lines
3.5 KiB
Lua
150 lines
3.5 KiB
Lua
local process = require("process")
|
|
local unicode = require("unicode")
|
|
local event = require("event")
|
|
local event_mt = getmetatable(event.handlers)
|
|
|
|
-- WARNING this code does not use official kernel API and is likely to change
|
|
|
|
local data = {}
|
|
local widths = {}
|
|
local sorted = {}
|
|
local moved_indexes = {}
|
|
|
|
local elbow = unicode.char(0x2514)
|
|
|
|
local function thread_id(t,p)
|
|
if t then
|
|
return tostring(t):gsub("^thread: 0x", "")
|
|
end
|
|
-- find the parent thread
|
|
for k,v in pairs(process.list) do
|
|
if v == p then
|
|
return thread_id(k)
|
|
end
|
|
end
|
|
return "-"
|
|
end
|
|
|
|
local cols =
|
|
{
|
|
{"PID", thread_id},
|
|
{"EVENTS", function(_,p)
|
|
local handlers = {}
|
|
if event_mt.threaded then
|
|
handlers = rawget(p.data, "handlers") or {}
|
|
elseif not p.parent then
|
|
handlers = event.handlers
|
|
end
|
|
local count = 0
|
|
for _ in pairs(handlers) do
|
|
count = count + 1
|
|
end
|
|
return count == 0 and "-" or tostring(count)
|
|
end},
|
|
{"THREADS", function(_,p)
|
|
-- threads are handles with mt.close == thread.waitForAll
|
|
local count = 0
|
|
for _,h in ipairs(p.data.handles) do
|
|
local mt = getmetatable(h)
|
|
if mt and mt.__status then
|
|
count = count + 1
|
|
end
|
|
end
|
|
return count == 0 and "-" or tostring(count)
|
|
end},
|
|
{"PARENT", function(_,p)
|
|
for _,process_info in pairs(process.list) do
|
|
for i,handle in ipairs(process_info.data.handles) do
|
|
local mt = getmetatable(handle)
|
|
if mt and mt.__status then
|
|
if mt.process == p then
|
|
return thread_id(nil, process_info)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
return thread_id(nil, p.parent)
|
|
end},
|
|
{"HANDLES", function(_, p)
|
|
local count = #p.data.handles
|
|
return count == 0 and "-" or tostring(count)
|
|
end},
|
|
{"CMD", function(_,p) return p.command end},
|
|
}
|
|
|
|
local function add_field(key, value)
|
|
if not data[key] then data[key] = {} end
|
|
table.insert(data[key], value)
|
|
widths[key] = math.max(widths[key] or 0, #value)
|
|
end
|
|
|
|
for _,key in ipairs(cols) do
|
|
add_field(key[1], key[1])
|
|
end
|
|
|
|
for thread_handle, process_info in pairs(process.list) do
|
|
for _,key in ipairs(cols) do
|
|
add_field(key[1], key[2](thread_handle, process_info))
|
|
end
|
|
end
|
|
|
|
local parent_index
|
|
for index,set in ipairs(cols) do
|
|
if set[1] == "PARENT" then
|
|
parent_index = index
|
|
break
|
|
end
|
|
end
|
|
assert(parent_index, "did not find a parent column")
|
|
|
|
local function move_to_sorted(index)
|
|
if moved_indexes[index] then
|
|
return false
|
|
end
|
|
local entry = {}
|
|
for k,v in pairs(data) do
|
|
entry[k] = v[index]
|
|
end
|
|
sorted[#sorted + 1] = entry
|
|
moved_indexes[index] = true
|
|
return true
|
|
end
|
|
|
|
local function make_elbow(depth)
|
|
return (" "):rep(depth - 1) .. (depth > 0 and elbow or "")
|
|
end
|
|
|
|
-- remove COLUMN labels to simplify sort
|
|
move_to_sorted(1)
|
|
|
|
local function update_family(parent, depth)
|
|
depth = depth or 0
|
|
parent = parent or "-"
|
|
for index in ipairs(data.PID) do
|
|
local this_parent = data[cols[parent_index][1]][index]
|
|
if this_parent == parent then
|
|
local dash_cmd = make_elbow(depth) .. data.CMD[index]
|
|
data.CMD[index] = dash_cmd
|
|
widths.CMD = math.max(widths.CMD or 0, #dash_cmd)
|
|
if move_to_sorted(index) then
|
|
update_family(data.PID[index], depth + 1)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
update_family()
|
|
table.remove(cols, parent_index) -- don't show parent id
|
|
|
|
for _,set in ipairs(sorted) do
|
|
local split = ""
|
|
for _,key in ipairs(cols) do
|
|
local label = key[1]
|
|
local format = split .. "%-" .. tostring(widths[label]) .. "s"
|
|
io.write(string.format(format, set[label]))
|
|
split = " "
|
|
end
|
|
print()
|
|
end
|
|
|