worked on taskmanager almost done with that

This commit is contained in:
Ryan Ward 2019-07-28 22:39:44 -04:00
parent 2e19a444da
commit 8782fa4538
7 changed files with 366 additions and 148 deletions

View File

@ -0,0 +1,5 @@
function gui:asRef()
self.isRef = true
self.Visible = false
return self
end

View File

@ -0,0 +1,22 @@
local copy
function copy(obj, seen)
if type(obj) ~= 'table' then return obj end
if seen and seen[obj] then return seen[obj] end
local s = seen or {}
local res = setmetatable({}, getmetatable(obj))
s[obj] = res
for k, v in pairs(obj) do res[copy(k, s)] = copy(v, s) end
return res
end
function gui:clone(par,isRef)
local temp = copy(self)
temp.isACopy = true
if par then
temp:SetParent(par)
end
if isRef or self.isRef then
self.Visible = false
temp.Visible = true
end
return temp
end

View File

@ -11,31 +11,27 @@ function gui:newScrollMenu(name,SC,MC)
temp.scroll = ScrollY temp.scroll = ScrollY
local cc = self.Color local cc = self.Color
local c1,c2=Color.new(cc[1]*255,cc[2]*255,cc[3]*255),Color.new(cc[1]*255+20,cc[2]*255+20,cc[3]*255+20) local c1,c2=Color.new(cc[1]*255,cc[2]*255,cc[3]*255),Color.new(cc[1]*255+20,cc[2]*255+20,cc[3]*255+20)
print(cc[1]-20,cc[2]-20,cc[3]-20)
ScrollY.Color=SC or c1 ScrollY.Color=SC or c1
ScrollY.allowOverlapping = true ScrollY.allowOverlapping = true
ScrollY.Mover = ScrollY:newFrame(name.."MoverY",5,5,10,80) ScrollY.Mover = ScrollY:newFrame(name.."MoverY",5,5,10,80)
ScrollY.Mover.Color = MC or c2 ScrollY.Mover.Color = MC or c2
local func = function(b,self,x,y,nn) local func = function(b,self,x,y,nn)
temp.symbolicY = y
if y>45 and y<self.height-45 then if y>45 and y<self.height-45 then
self.Mover:SetDualDim(nil,y-40) self.Mover:SetDualDim(nil,y-40)
temp.first:setDualDim(nil,nil,nil,nil,nil,-((y-46)/(self.height-92))*((temp.max-temp.height+60)/temp.height)) temp.first:setDualDim(nil,nil,nil,nil,nil,-((y-46)/(self.height-92))*((temp.max-temp.height+60)/temp.height))
if not nn then if not nn then
self:setMouseXY(10) self:setMouseXY(10)
end end
elseif y<5 then
self.Mover:SetDualDim(nil,5)
temp.first:setDualDim(nil,nil,nil,nil,nil,0)
end end
end end
ScrollY:OnClicked(func) ScrollY:OnClicked(func)
temp.symbolicY = 45 temp.symbolicY = 45
temp.scrollM = 2 temp.scrollM = 2
temp:OnMouseWheelMoved(function(self,x,y) temp:OnMouseWheelMoved(function(self,x,y)
temp.symbolicY=temp.symbolicY-(y*temp.scrollM) temp.symbolicY=temp.symbolicY-(y*#temp.list)
if temp.symbolicY<45 then
temp.symbolicY = 45
elseif temp.symbolicY>ScrollY.height-40 then
temp.symbolicY = ScrollY.height-40
end
func("l",ScrollY,x,temp.symbolicY,true) func("l",ScrollY,x,temp.symbolicY,true)
end) end)
temp.ClipDescendants=true temp.ClipDescendants=true

View File

@ -0,0 +1,47 @@
local TM_Count = 0
function gui:newTabMenu(x,y,w,h,sx,sy,sw,sh)
TM_Count = TM_Count + 1
local c = self:newFrame("TabMenu_"..TM_Count,x,y,w,h,sx,sy,sw,sh)
c.Id = TM_Count
c.tabs = {}
c.frames = {}
c.tabheight = 30
function c:setTabHeight(n)
self.tabheight = n or 30
end
function c:updateTabs()
local n = #self.tabs
for i = 1,#self.tabs do
self.tabs[i]:SetDualDim(0,0,0,self.tabheight,(i-1)/n,0,1/n)
multi.nextStep(function()
self.tabs[i]:fitFont()
end)
end
end
function c:addTab(name,c1,c2)
local bnt = self:newTextLabel(name,name,0,0,0,self.tabheight)
local frame = self:newFrame(name,0,self.tabheight,0,-self.tabheight,0,0,1,1)
bnt.Frame = frame
if c1 then
bnt.Color = c1
frame.Color = c1
end
if c2 then
frame.Color = c2
end
table.insert(self.tabs,bnt)
table.insert(self.frames,frame)
self:updateTabs()
bnt:OnReleased(function(b,self)
for i = 1,#c.frames do
c.frames[i].Visible = false
end
self.Frame.Visible = true
end)
return frame,bnt
end
function c:removeTab(name)
end
return c
end

View File

@ -0,0 +1,34 @@
local wincount = 0
function gui:newWindow(name,win_width,win_height)
local win=self:newFrame(0+(wincount*25),0+(wincount*25),win_width or 400,win_height or 20)
wincount=wincount+1
win:enableDragging(true)
win.dragbut="l"
if name then
local font=love.graphics.getFont()
win.title=win:newTextLabel(name,0,0,font:getWidth(name),20)
win.title.TextFormat="left"
win.title.Visibility=0
win.title.XTween=3
win.title.Tween=3
end
win:ApplyGradient({Color.new(70,70,70),Color.Darken(Color.new(70,70,70),.25),trans=200})
win.close=win:newImageButton("GuiManager/icons/cancel.png",-(win_height or 20),2,(win_height or 20)-4,(win_height or 20)-4,1)
local click = false
win:OnClicked(function(b,self)
if not click then
self:TopStack()
click = true
end
end)
win:OnReleased(function(b,self)
click = false
end)
win.close:OnReleased(function(b,self)
self.Parent:Destroy()
love.mouse.setCursor()
end)
win.holder=win:newFrame(0,0,0,280,0,1,1)
win.holder.Color = Color.new(25,25,25)
return win.holder,win
end

View File

@ -6,112 +6,130 @@ require("GuiManager")
require("parseManager") require("parseManager")
--VNCore = require("VNCore").init(gui:newFullFrame("Main"), parseManager, multi) --VNCore = require("VNCore").init(gui:newFullFrame("Main"), parseManager, multi)
--debug = require("VNCore.debug") --debug = require("VNCore.debug")
local TM_Count = 0
function gui:newTabMenu(x,y,w,h,sx,sy,sw,sh)
TM_Count = TM_Count + 1
local c = self:newFrame("TabMenu_"..TM_Count,x,y,w,h,sx,sy,sw,sh)
c.Id = TM_Count
c.tabs = {}
c.frames = {}
c.tabheight = 30
function c:setTabHeight(n)
self.tabheight = n or 30
end
function c:updateTabs()
local n = #self.tabs
for i = 1,#self.tabs do
self.tabs[i]:SetDualDim(0,0,0,self.tabheight,(i-1)/n,0,1/n)
multi.nextStep(function()
self.tabs[i]:fitFont()
end)
end
end
function c:addTab(name,c1,c2)
local bnt = self:newTextLabel(name,name,0,0,0,self.tabheight)
local frame = self:newFrame(name,0,self.tabheight,0,-self.tabheight,0,0,1,1)
bnt.Frame = frame
if c1 then
bnt.Color = c1
frame.Color = c1
end
if c2 then
frame.Color = c2
end
table.insert(self.tabs,bnt)
table.insert(self.frames,frame)
self:updateTabs()
bnt:OnReleased(function(b,self)
for i = 1,#c.frames do
c.frames[i].Visible = false
end
self.Frame.Visible = true
end)
return frame,bnt
end
function c:removeTab(name)
end win = gui:newWindow("Taskmanager",500,20)
return c test = win:newTabMenu(0,0,500,600)
end
local wincount = 0
function gui:newWindow(name)
local win=self:newFrame(0+(wincount*25),0+(wincount*25),400,20)
wincount=wincount+1
win:enableDragging(true)
win.dragbut="l"
if name then
local font=love.graphics.getFont()
win.title=win:newTextLabel(name,0,0,font:getWidth(name),20)
win.title.TextFormat="left"
win.title.Visibility=0
win.title.XTween=3
win.title.Tween=3
end
win:ApplyGradient({Color.new(70,70,70),Color.Darken(Color.new(70,70,70),.25),trans=200})
win.close=win:newImageButton("GuiManager/icons/cancel.png",-20,2,16,16,1)
local click = false
win:OnClicked(function(b,self)
if not click then
self:TopStack()
click = true
end
end)
win:OnReleased(function(b,self)
click = false
end)
win.close:OnReleased(function(b,self)
self.Parent:Destroy()
love.mouse.setCursor()
end)
win.holder=win:newFrame(0,0,0,280,0,1,1)
win.holder.Color = Color.new(25,25,25)
return win.holder,win
end
win = gui:newWindow("Taskmanager")
test = win:newTabMenu(0,0,400,500)
test:setTabHeight(30) test:setTabHeight(30)
f,b = test:addTab("Tasks",Color.new(60,60,60), Color.new(80,80,80)) local tasks, tasks_b = test:addTab("Tasks",Color.new(60,60,60), Color.new(80,80,80))
f,b = test:addTab("Threads",Color.new(60,60,60), Color.new(80,80,80)) threads,threads_b = test:addTab("Threads",Color.new(60,60,60), Color.new(80,80,80))
f,b = test:addTab("SThreads",Color.new(60,60,60), Color.new(80,80,80)) sthreads,sthreads_b = test:addTab("SThreads",Color.new(60,60,60), Color.new(80,80,80))
f,b = test:addTab("Details",Color.new(60,60,60), Color.new(80,80,80)) details,details_b = test:addTab("Details",Color.new(60,60,60), Color.new(80,80,80))
local temp = f:newScrollMenu("System Threads") local ST_Menu = sthreads:newScrollMenu("System Threads")
temp:setRef{ local T_Menu = threads:newScrollMenu("Threads")
[[fitFont()]], local TASKS_Menu = tasks:newScrollMenu("Tasks")
} --local DETAILS_Menu -- We need to manage this one a bit differently
local f refFrame = gui:newFrame("Reference Object"):asRef() -- Makes cloning an object seamless, since we set this as an object we expect to be cloned
for i=1,20 do refFrame.ItemName = refFrame:newTextLabel("Item Name","Item Name",5,3,0,19)
hmm=temp:addItem("Item "..i, math.random(30,60), 5) refFrame.ItemName:widthToTextSize()
hmm:OnReleased(function(b,self) refFrame.ItemPR = refFrame.ItemName:newTextLabel("Running","Running",5,0,0,0,1,0,0,1) -- Doubles as Resume thread as well
print(self.text) refFrame.ItemPR:widthToTextSize()
end) refFrame.ItemKill = refFrame.ItemPR:newTextLabel("Kill","Kill",5,0,0,0,1,0,0,1) -- Doubles as Resume thread as well
if i == 1 then refFrame.ItemKill:widthToTextSize()
f = hmm refFrame.ItemUpTime = refFrame.ItemKill:newTextLabel("Uptime","Uptime",5,0,0,0,1,0,0,1) -- Doubles as Resume thread as well
refFrame.ItemUpTime:widthToTextSize()
local function pr(b,self)
if self.GLink:isPaused() then
self.text = "Running"
self:widthToTextSize()
self.GLink:Resume()
else
self.text = "Paused"
self:widthToTextSize()
self.GLink:Pause()
end end
end end
temp:removeItem(f) local function kill(b,self)
function love.update() self.GLink:Destroy()
multi:uManager()
end end
--temp:setRef{
-- [[fitFont()]],
--}
--ST_Menu:addItem("System Threads "..i, 25, 1,refFrame:clone())
--T_Menu:addItem("Threads "..i, 25, 1,refFrame:clone())
--
local listref = {
["ProcessName"] = true,
["CyclesPerSecondPerTask"] = true,
["MemoryUsage"] = true,
["ThreadCount"] = true,
["SystemLoad"] = true,
["PriorityScheme"] = true,
["SystemThreadCount"] = true,
_Tasks = {},
_Threads = {},
_SystemThreads = {},
}
function table.sync(a,b)
for i,v in pairs(b) do
if a[i] then
a[i] = v
end
end
end
multi:newThread("Updater",function()
while true do
local taskslist = multi:getTasksDetails("t")
table.sync(listref,taskslist) -- Managing details
thread.sleep(.1)
for i=1,#taskslist.Tasks do
if not listref._Tasks[taskslist.Tasks[i].TID] then
local ref = TASKS_Menu:addItem("Tasks "..i, 25, 1,refFrame:clone())
ref.GLink = taskslist.Tasks[i].Link
ref.ItemKill:OnReleased(kill)
ref.ItemKill.GLink = ref.GLink
ref.ItemPR:OnReleased(pr)
ref.ItemPR.GLink = ref.GLink
listref._Tasks[taskslist.Tasks[i].TID] = {ref,taskslist.Tasks[i].Link}
ref.ItemName.text = taskslist.Tasks[i].Name
ref.ItemName:widthToTextSize()
ref.ItemUpTime.text = "Uptime: "..taskslist.Tasks[i].Uptime
ref.ItemUpTime:widthToTextSize()
elseif listref._Tasks[taskslist.Tasks[i].TID] then
-- Update whats already there
listref._Tasks[taskslist.Tasks[i].TID][1].ItemUpTime.text = taskslist.Tasks[i].Priority.." | "..taskslist.Tasks[i].Type.." | "..taskslist.Tasks[i].Uptime
listref._Tasks[taskslist.Tasks[i].TID][1].ItemUpTime:widthToTextSize()
end
end
for i,v in pairs(listref._Tasks) do
if v[2].Destroyed then
TASKS_Menu:removeItem(v[1])
listref._Tasks[i] = nil
end
end
for i=1,#taskslist.Threads do
if not listref._Threads[taskslist.Threads[i].TID] then
local ref = T_Menu:addItem("Tasks "..i, 25, 1,refFrame:clone())
ref.GLink = taskslist.Threads[i].Link
ref.ItemKill:OnReleased(kill)
ref.ItemKill.GLink = ref.GLink
ref.ItemPR:OnReleased(pr)
ref.ItemPR.GLink = ref.GLink
listref._Threads[taskslist.Threads[i].TID] = {ref,taskslist.Threads[i].Link}
ref.ItemName.text = taskslist.Threads[i].Name
ref.ItemName:widthToTextSize()
ref.ItemUpTime.text = "Uptime: "..taskslist.Threads[i].Uptime
ref.ItemUpTime:widthToTextSize()
elseif listref._Threads[taskslist.Threads[i].TID] then
if taskslist.Tasks[i] then
listref._Threads[taskslist.Threads[i].TID][1].ItemUpTime.text = "Uptime: "..taskslist.Tasks[i].Uptime
listref._Threads[taskslist.Threads[i].TID][1].ItemUpTime:widthToTextSize()
end
end
end
for i,v in pairs(listref._Tasks) do
if v[2].Destroyed then
TASKS_Menu:removeItem(v[1])
listref._Tasks[i] = nil
end
end
end
end)
settings = {protect = true,priority = 2}
function love.update()
multi:uManager(settings)
end
multi.OnError(function(...) multi.OnError(function(...)
print(...) print(...)
end) end)

View File

@ -24,8 +24,8 @@ SOFTWARE.
local bin = pcall(require,"bin") local bin = pcall(require,"bin")
local multi = {} local multi = {}
local clock = os.clock local clock = os.clock
multi.Version = "13.0.0" multi.Version = "13.1.0"
multi._VERSION = "13.0.0" multi._VERSION = "13.1.0"
multi.stage = "stable" multi.stage = "stable"
multi.__index = multi multi.__index = multi
multi.Name = "multi.root" multi.Name = "multi.root"
@ -158,7 +158,7 @@ function multi:getLoad()
bench = steps bench = steps
bb = steps bb = steps
end) end)
while not bench do while not bench do
multi:uManager() multi:uManager()
end end
bench = bench^1.5 bench = bench^1.5
@ -342,7 +342,17 @@ function multi:getTasksDetails(t)
name = " <"..name..">" name = " <"..name..">"
end end
count = count + 1 count = count + 1
table.insert(str,{v.Type:sub(1,1):upper()..v.Type:sub(2,-1)..name,multi.Round(os.clock()-v.creationTime,3),self.PriorityResolve[v.Priority],i}) table.insert(str,{v.Type:sub(1,1):upper()..v.Type:sub(2,-1)..name,multi.Round(os.clock()-v.creationTime,3),self.PriorityResolve[v.Priority],v.TID})
end
for v,i in pairs(multi.PausedObjects) do
if v.Type~="event" then
local name = v.Name or ""
if name~="" then
name = " <"..name..">"
end
count = count + 1
table.insert(str,{v.Type:sub(1,1):upper()..v.Type:sub(2,-1)..name,multi.Round(os.clock()-v.creationTime,3),self.PriorityResolve[v.Priority],v.TID})
end
end end
if count == 0 then if count == 0 then
table.insert(str,{"Currently no processes running!","","",""}) table.insert(str,{"Currently no processes running!","","",""})
@ -355,7 +365,7 @@ function multi:getTasksDetails(t)
dat2 = dat2.."<SystemThread: "..multi.SystemThreads[i].Name.." | "..os.clock()-multi.SystemThreads[i].creationTime..">\n" dat2 = dat2.."<SystemThread: "..multi.SystemThreads[i].Name.." | "..os.clock()-multi.SystemThreads[i].creationTime..">\n"
end end
end end
local load,steps = multi:getLoad() local load, steps = multi:getLoad()
if multi.scheduler then if multi.scheduler then
for i=1,#multi.scheduler.Threads do for i=1,#multi.scheduler.Threads do
dat = dat .. "<THREAD: "..multi.scheduler.Threads[i].Name.." | "..os.clock()-multi.scheduler.Threads[i].creationTime..">\n" dat = dat .. "<THREAD: "..multi.scheduler.Threads[i].Name.." | "..os.clock()-multi.scheduler.Threads[i].creationTime..">\n"
@ -369,22 +379,30 @@ function multi:getTasksDetails(t)
str = { str = {
ProcessName = (self.Name or "Unnamed"), ProcessName = (self.Name or "Unnamed"),
ThreadCount = #multi.scheduler.Threads, ThreadCount = #multi.scheduler.Threads,
MemoryUsage = math.ceil(collectgarbage("count")).." KB", MemoryUsage = math.ceil(collectgarbage("count")),
PriorityScheme = priorityTable[multi.defaultSettings.priority or 0], PriorityScheme = priorityTable[multi.defaultSettings.priority or 0],
SystemLoad = multi.Round(load,2), SystemLoad = multi.Round(load,2),
CyclesPerSecondPerTask = steps, CyclesPerSecondPerTask = steps,
SystemThreadCount = multi.SystemThreads and #multi.SystemThreads or 0
} }
str.threads = {} str.Tasks = {}
str.systemthreads = {} str.PausedTasks = {}
str.Threads = {}
str.Systemthreads = {}
for i,v in pairs(self.Mainloop) do for i,v in pairs(self.Mainloop) do
str[#str+1]={Type=v.Type,Name=v.Name,Uptime=os.clock()-v.creationTime,Priority=self.PriorityResolve[v.Priority],TID = i} table.insert(str.Tasks,{Link = v, Type=v.Type,Name=v.Name,Uptime=os.clock()-v.creationTime,Priority=self.PriorityResolve[v.Priority],TID = v.TID})
end
for v,i in pairs(multi.PausedObjects) do
if v.Type~="event" then
table.insert(str.Tasks,{Link = v, Type=v.Type,Name=v.Name,Uptime=os.clock()-v.creationTime,Priority=self.PriorityResolve[v.Priority],TID = v.TID})
end
end end
for i=1,#multi.scheduler.Threads do for i=1,#multi.scheduler.Threads do
str.threads[multi.scheduler.Threads[i].Name]={Uptime = os.clock()-multi.scheduler.Threads[i].creationTime} table.insert(str.Threads,{Uptime = os.clock()-multi.scheduler.Threads[i].creationTime,Name = multi.scheduler.Threads[i].Name,Link = multi.scheduler.Threads[i],TID = multi.scheduler.Threads[i].TID})
end end
if multi.canSystemThread then if multi.SystemThreads then
for i=1,#multi.SystemThreads do for i=1,#multi.SystemThreads do
str.systemthreads[multi.SystemThreads[i].Name]={Uptime = os.clock()-multi.SystemThreads[i].creationTime} table.insert(str.Systemthreads,{Uptime = os.clock()-multi.SystemThreads[i].creationTime,Name = multi.SystemThreads[i].Name,Link = multi.SystemThreads[i],TID = multi.SystemThreads[i].count})
end end
end end
return str return str
@ -528,6 +546,7 @@ function multi:OnTimerResolved(func)
return self return self
end end
-- Timer stuff done -- Timer stuff done
multi.PausedObjects = {}
function multi:Pause() function multi:Pause()
if self.Type=='mainprocess' then if self.Type=='mainprocess' then
multi.print("You cannot pause the main process. Doing so will stop all methods and freeze your program! However if you still want to use multi:_Pause()") multi.print("You cannot pause the main process. Doing so will stop all methods and freeze your program! However if you still want to use multi:_Pause()")
@ -536,6 +555,7 @@ function multi:Pause()
local loop = self.Parent.Mainloop local loop = self.Parent.Mainloop
for i=1,#loop do for i=1,#loop do
if loop[i] == self then if loop[i] == self then
multi.PausedObjects[self] = true
table.remove(loop,i) table.remove(loop,i)
break break
end end
@ -553,6 +573,7 @@ function multi:Resume()
else else
if self.Active==false then if self.Active==false then
table.insert(self.Parent.Mainloop,self) table.insert(self.Parent.Mainloop,self)
multi.PausedObjects[self] = nil
self.Active=true self.Active=true
end end
end end
@ -570,6 +591,7 @@ function multi:Destroy()
if self.Parent.Mainloop[i]==self then if self.Parent.Mainloop[i]==self then
self.Parent.OnObjectDestroyed:Fire(self) self.Parent.OnObjectDestroyed:Fire(self)
table.remove(self.Parent.Mainloop,i) table.remove(self.Parent.Mainloop,i)
self.Destroyed = true
break break
end end
end end
@ -594,6 +616,7 @@ function multi:setName(name)
end end
multi.SetName = multi.setName multi.SetName = multi.setName
--Constructors [CORE] --Constructors [CORE]
local _tid = 0
function multi:newBase(ins) function multi:newBase(ins)
if not(self.Type=='mainprocess' or self.Type=='process' or self.Type=='queue') then error('Can only create an object on multi or an interface obj') return false end if not(self.Type=='mainprocess' or self.Type=='process' or self.Type=='queue') then error('Can only create an object on multi or an interface obj') return false end
local c = {} local c = {}
@ -607,6 +630,7 @@ function multi:newBase(ins)
c.funcTM={} c.funcTM={}
c.funcTMR={} c.funcTMR={}
c.ender={} c.ender={}
c.TID = _tid
c.important={} c.important={}
c.Act=function() end c.Act=function() end
c.Parent=self c.Parent=self
@ -617,6 +641,7 @@ function multi:newBase(ins)
else else
table.insert(self.Mainloop,c) table.insert(self.Mainloop,c)
end end
_tid = _tid + 1
return c return c
end end
function multi:newProcessor(file) function multi:newProcessor(file)
@ -635,7 +660,7 @@ function multi:newProcessor(file)
c.Jobs={} c.Jobs={}
c.queue={} c.queue={}
c.jobUS=2 c.jobUS=2
c.l=self:newLoop(function(self,dt) c.l=self:newLoop(function(self,dt)
if self.link.Active then if self.link.Active then
c:uManager() c:uManager()
end end
@ -740,6 +765,7 @@ function multi:newConnection(protect,func)
local c={} local c={}
c.callback = func c.callback = func
c.Parent=self c.Parent=self
c.lock = false
setmetatable(c,{__call=function(self,...) setmetatable(c,{__call=function(self,...)
local t = ... local t = ...
if type(t)=="table" and t.Type ~= nil then if type(t)=="table" and t.Type ~= nil then
@ -788,8 +814,15 @@ function multi:newConnection(protect,func)
return self.connections[name] or self return self.connections[name] or self
end end
end end
function c:Lock()
c.lock = true
end
function c:Unlock()
c.lock = false
end
function c:Fire(...) function c:Fire(...)
local ret={} local ret={}
if self.lock then return end
for i=#self.func,1,-1 do for i=#self.func,1,-1 do
if self.protect then if self.protect then
local temp={pcall(self.func[i][1],...)} local temp={pcall(self.func[i][1],...)}
@ -822,6 +855,7 @@ function multi:newConnection(protect,func)
ID=self.ID, ID=self.ID,
Parent=self, Parent=self,
Fire=function(self,...) Fire=function(self,...)
if self.Parent.lock then return end
--~ if self.Parent.FC>0 then --~ if self.Parent.FC>0 then
--~ for i=1,#self.Parent.FC do --~ for i=1,#self.Parent.FC do
--~ self.Parent.FC[i]:Fire(...) --~ self.Parent.FC[i]:Fire(...)
@ -1046,9 +1080,9 @@ function multi:newFunction(func)
c.func=func c.func=func
mt={ mt={
__index=multi, __index=multi,
__call=function(self,...) __call=function(self,...)
if self.Active then if self.Active then
return self:func(...) return self:func(...)
end end
return nil,true return nil,true
end end
@ -1436,19 +1470,38 @@ if os.getOS()=="windows" then
else else
thread.__CORES=tonumber(io.popen("nproc --all"):read("*n")) thread.__CORES=tonumber(io.popen("nproc --all"):read("*n"))
end end
thread.requests = {}
function thread.request(t,cmd,...)
thread.requests[t.thread] = {cmd,{...}}
end
function thread._Requests()
local t = thread.requests[coroutine.running()]
thread.requests[coroutine.running()] = nil
if t then
local cmd,args = t[1],t[2]
thread[cmd](unpack(args))
end
end
function thread.exec(func)
func()
end
function thread.sleep(n) function thread.sleep(n)
thread._Requests()
coroutine.yield({"_sleep_",n or 0}) coroutine.yield({"_sleep_",n or 0})
end end
function thread.hold(n) function thread.hold(n)
thread._Requests()
return coroutine.yield({"_hold_",n or function() return true end}) return coroutine.yield({"_hold_",n or function() return true end})
end end
function thread.skip(n) function thread.skip(n)
thread._Requests()
coroutine.yield({"_skip_",n or 0}) coroutine.yield({"_skip_",n or 0})
end end
function thread.kill() function thread.kill()
coroutine.yield({"_kill_",":)"}) coroutine.yield({"_kill_",":)"})
end end
function thread.yeild() function thread.yeild()
thread._Requests()
coroutine.yield({"_sleep_",0}) coroutine.yield({"_sleep_",0})
end end
function thread.isThread() function thread.isThread()
@ -1469,8 +1522,8 @@ function thread.waitFor(name)
return thread.get(name) return thread.get(name)
end end
function thread.testFor(name,_val,sym) function thread.testFor(name,_val,sym)
thread.hold(function() thread.hold(function()
local val = thread.get(name)~=nil local val = thread.get(name)~=nil
if val then if val then
if sym == "==" or sym == "=" then if sym == "==" or sym == "=" then
return _val==val return _val==val
@ -1496,21 +1549,52 @@ multi:setDomainName("Threads")
multi:setDomainName("Globals") multi:setDomainName("Globals")
local initT = false local initT = false
local threadCount = 0 local threadCount = 0
local threadid = 0
function multi:newThread(name,func) function multi:newThread(name,func)
local func = func local func = func or name
if type(name) == "function" then if type(name) == "function" then
func = name
name = "Thread#"..threadCount name = "Thread#"..threadCount
end end
local g=string.dump(func)
if g:find("K") and not g:find(" thread") then
print("Warning! The thread created: <"..name.."> contains a while loop which may not be confugured properly with thread.* If your code seems to hang this may be the reason!")
else
multi.print("Should be safe")
end
local c={} local c={}
c.ref={} c.ref={}
c.Name=name c.Name=name
c.thread=coroutine.create(func) c.thread=coroutine.create(func)
c.sleep=1 c.sleep=1
c.Type="thread" c.Type="thread"
c.TID = threadid
c.firstRunDone=false c.firstRunDone=false
c.timer=multi:newTimer() c.timer=multi:newTimer()
c.ref.Globals=self:linkDomain("Globals") c.ref.Globals=self:linkDomain("Globals")
c._isPaused = false
function c:isPaused()
return self._isPaused
end
local resumed = false
function c:Pause()
if not self._isPaused then
thread.request(self,"exec",function()
thread.hold(function()
return resumed
end)
resumed = false
self._isPaused = false
end)
self._isPaused = true
end
end
function c:Resume()
resumed = true
end
function c:Kill()
thread.request(self,"kill")
end
c.Destroy = c.Kill
function c.ref:send(name,val) function c.ref:send(name,val)
ret=coroutine.yield({Name=name,Value=val}) ret=coroutine.yield({Name=name,Value=val})
self:syncGlobals(ret) self:syncGlobals(ret)
@ -1544,6 +1628,8 @@ function multi:newThread(name,func)
multi.initThreads() multi.initThreads()
end end
c.creationTime = os.clock() c.creationTime = os.clock()
threadid = threadid + 1
return c
end end
function multi.initThreads() function multi.initThreads()
initT = true initT = true
@ -1553,11 +1639,29 @@ function multi.initThreads()
self.skip=tonumber(n) or 24 self.skip=tonumber(n) or 24
end end
multi.scheduler.skip=0 multi.scheduler.skip=0
multi.scheduler.counter=0
multi.scheduler.Threads=multi:linkDomain("Threads") multi.scheduler.Threads=multi:linkDomain("Threads")
multi.scheduler.Globals=multi:linkDomain("Globals") multi.scheduler.Globals=multi:linkDomain("Globals")
local holds = {}
local skips = {}
local t0,t1,t2,t3,t4,t5,t6
multi.scheduler:OnLoop(function(self) multi.scheduler:OnLoop(function(self)
self.counter=self.counter+1 for i=#skips,1,-1 do
skips[i].pos = skips[i].pos + 1
if skips[i].count==skips[i].pos then
skips[i].Link.sleep=0
skips[i]=nil
end
end
for i=#holds,1,-1 do
if holds[i] then
t0,t1,t2,t3,t4,t5,t6 = holds[i].func()
if t0 then
holds[i].Link.sleep = 0
holds[i].Link.returns = {t0,t1,t2,t3,t4,t5,t6}
holds[i]=nil
end
end
end
for i=#self.Threads,1,-1 do for i=#self.Threads,1,-1 do
ret={} ret={}
if coroutine.status(self.Threads[i].thread)=="dead" then if coroutine.status(self.Threads[i].thread)=="dead" then
@ -1596,26 +1700,18 @@ function multi.initThreads()
elseif ret[1]=="_skip_" then elseif ret[1]=="_skip_" then
self.Threads[i].timer:Reset() self.Threads[i].timer:Reset()
self.Threads[i].sleep=math.huge self.Threads[i].sleep=math.huge
local event=multi:newEvent(function(evnt) return multi.scheduler.counter>=evnt.counter end) table.insert(skips,{
event.link=self.Threads[i] Link = self.Threads[i],
event.counter=self.counter+ret[2] count = ret[2],
event:OnEvent(function(evnt) pos = 0,
evnt.link.sleep=0 })
evnt:Destroy()
end):setName("multi.thread.skip")
elseif ret[1]=="_hold_" then elseif ret[1]=="_hold_" then
self.Threads[i].timer:Reset() self.Threads[i].timer:Reset()
self.Threads[i].sleep=math.huge self.Threads[i].sleep=math.huge
local event=multi:newEvent(ret[2]) table.insert(holds,{
event.returns = nil Link = self.Threads[i],
event.link=self.Threads[i] func = ret[2]
event:OnEvent(function(evnt) })
evnt.link.sleep=0
evnt.link.returns = evnt.returns
multi.nextStep(function()
evnt:Destroy()
end)
end):setName("multi.thread.hold")
elseif ret.Name then elseif ret.Name then
self.Globals[ret.Name]=ret.Value self.Globals[ret.Name]=ret.Value
end end