From 8782fa453867d1757d651a2aa39c9bb2cf89a5bf Mon Sep 17 00:00:00 2001 From: Ryan Ward Date: Sun, 28 Jul 2019 22:39:44 -0400 Subject: [PATCH] worked on taskmanager almost done with that --- Visual Novel/GuiManager/Core/asRef.lua | 5 + Visual Novel/GuiManager/Core/clone.lua | 22 ++ .../GuiManager/Misc/newScrollMenu.lua | 12 +- Visual Novel/GuiManager/Misc/newTabMenu.lua | 47 ++++ Visual Novel/GuiManager/Misc/newWindow.lua | 34 +++ Visual Novel/main.lua | 220 ++++++++++-------- Visual Novel/multi/init.lua | 174 ++++++++++---- 7 files changed, 366 insertions(+), 148 deletions(-) create mode 100644 Visual Novel/GuiManager/Core/asRef.lua create mode 100644 Visual Novel/GuiManager/Core/clone.lua create mode 100644 Visual Novel/GuiManager/Misc/newTabMenu.lua create mode 100644 Visual Novel/GuiManager/Misc/newWindow.lua diff --git a/Visual Novel/GuiManager/Core/asRef.lua b/Visual Novel/GuiManager/Core/asRef.lua new file mode 100644 index 0000000..d5e3fe8 --- /dev/null +++ b/Visual Novel/GuiManager/Core/asRef.lua @@ -0,0 +1,5 @@ +function gui:asRef() + self.isRef = true + self.Visible = false + return self +end \ No newline at end of file diff --git a/Visual Novel/GuiManager/Core/clone.lua b/Visual Novel/GuiManager/Core/clone.lua new file mode 100644 index 0000000..bdfade3 --- /dev/null +++ b/Visual Novel/GuiManager/Core/clone.lua @@ -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 \ No newline at end of file diff --git a/Visual Novel/GuiManager/Misc/newScrollMenu.lua b/Visual Novel/GuiManager/Misc/newScrollMenu.lua index 5afc923..3b30833 100644 --- a/Visual Novel/GuiManager/Misc/newScrollMenu.lua +++ b/Visual Novel/GuiManager/Misc/newScrollMenu.lua @@ -11,31 +11,27 @@ function gui:newScrollMenu(name,SC,MC) temp.scroll = ScrollY 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) - print(cc[1]-20,cc[2]-20,cc[3]-20) ScrollY.Color=SC or c1 ScrollY.allowOverlapping = true ScrollY.Mover = ScrollY:newFrame(name.."MoverY",5,5,10,80) ScrollY.Mover.Color = MC or c2 local func = function(b,self,x,y,nn) - temp.symbolicY = y if y>45 and yScrollY.height-40 then - temp.symbolicY = ScrollY.height-40 - end + temp.symbolicY=temp.symbolicY-(y*#temp.list) func("l",ScrollY,x,temp.symbolicY,true) end) temp.ClipDescendants=true diff --git a/Visual Novel/GuiManager/Misc/newTabMenu.lua b/Visual Novel/GuiManager/Misc/newTabMenu.lua new file mode 100644 index 0000000..c962afa --- /dev/null +++ b/Visual Novel/GuiManager/Misc/newTabMenu.lua @@ -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 \ No newline at end of file diff --git a/Visual Novel/GuiManager/Misc/newWindow.lua b/Visual Novel/GuiManager/Misc/newWindow.lua new file mode 100644 index 0000000..51cfb8f --- /dev/null +++ b/Visual Novel/GuiManager/Misc/newWindow.lua @@ -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 \ No newline at end of file diff --git a/Visual Novel/main.lua b/Visual Novel/main.lua index 6acab55..0445af6 100644 --- a/Visual Novel/main.lua +++ b/Visual Novel/main.lua @@ -6,112 +6,130 @@ require("GuiManager") require("parseManager") --VNCore = require("VNCore").init(gui:newFullFrame("Main"), parseManager, multi) --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 - return c -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) +win = gui:newWindow("Taskmanager",500,20) +test = win:newTabMenu(0,0,500,600) test:setTabHeight(30) -f,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)) -f,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)) -local temp = f:newScrollMenu("System Threads") -temp:setRef{ - [[fitFont()]], -} -local f -for i=1,20 do - hmm=temp:addItem("Item "..i, math.random(30,60), 5) - hmm:OnReleased(function(b,self) - print(self.text) - end) - if i == 1 then - f = hmm +local tasks, tasks_b = test:addTab("Tasks",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)) +sthreads,sthreads_b = test:addTab("SThreads",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 ST_Menu = sthreads:newScrollMenu("System Threads") +local T_Menu = threads:newScrollMenu("Threads") +local TASKS_Menu = tasks:newScrollMenu("Tasks") +--local DETAILS_Menu -- We need to manage this one a bit differently +refFrame = gui:newFrame("Reference Object"):asRef() -- Makes cloning an object seamless, since we set this as an object we expect to be cloned +refFrame.ItemName = refFrame:newTextLabel("Item Name","Item Name",5,3,0,19) +refFrame.ItemName:widthToTextSize() +refFrame.ItemPR = refFrame.ItemName:newTextLabel("Running","Running",5,0,0,0,1,0,0,1) -- Doubles as Resume thread as well +refFrame.ItemPR:widthToTextSize() +refFrame.ItemKill = refFrame.ItemPR:newTextLabel("Kill","Kill",5,0,0,0,1,0,0,1) -- Doubles as Resume thread as well +refFrame.ItemKill:widthToTextSize() +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 -temp:removeItem(f) -function love.update() - multi:uManager() +local function kill(b,self) + self.GLink:Destroy() 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(...) print(...) end) diff --git a/Visual Novel/multi/init.lua b/Visual Novel/multi/init.lua index 418bc26..33302b5 100644 --- a/Visual Novel/multi/init.lua +++ b/Visual Novel/multi/init.lua @@ -24,8 +24,8 @@ SOFTWARE. local bin = pcall(require,"bin") local multi = {} local clock = os.clock -multi.Version = "13.0.0" -multi._VERSION = "13.0.0" +multi.Version = "13.1.0" +multi._VERSION = "13.1.0" multi.stage = "stable" multi.__index = multi multi.Name = "multi.root" @@ -158,7 +158,7 @@ function multi:getLoad() bench = steps bb = steps end) - while not bench do + while not bench do multi:uManager() end bench = bench^1.5 @@ -342,7 +342,17 @@ function multi:getTasksDetails(t) 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],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 if count == 0 then table.insert(str,{"Currently no processes running!","","",""}) @@ -355,7 +365,7 @@ function multi:getTasksDetails(t) dat2 = dat2.."\n" end end - local load,steps = multi:getLoad() + local load, steps = multi:getLoad() if multi.scheduler then for i=1,#multi.scheduler.Threads do dat = dat .. "\n" @@ -369,22 +379,30 @@ function multi:getTasksDetails(t) str = { ProcessName = (self.Name or "Unnamed"), ThreadCount = #multi.scheduler.Threads, - MemoryUsage = math.ceil(collectgarbage("count")).." KB", + MemoryUsage = math.ceil(collectgarbage("count")), PriorityScheme = priorityTable[multi.defaultSettings.priority or 0], SystemLoad = multi.Round(load,2), CyclesPerSecondPerTask = steps, + SystemThreadCount = multi.SystemThreads and #multi.SystemThreads or 0 } - str.threads = {} - str.systemthreads = {} + str.Tasks = {} + str.PausedTasks = {} + str.Threads = {} + str.Systemthreads = {} 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 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 - if multi.canSystemThread then + if multi.SystemThreads then 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 return str @@ -528,6 +546,7 @@ function multi:OnTimerResolved(func) return self end -- Timer stuff done +multi.PausedObjects = {} function multi:Pause() 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()") @@ -536,6 +555,7 @@ function multi:Pause() local loop = self.Parent.Mainloop for i=1,#loop do if loop[i] == self then + multi.PausedObjects[self] = true table.remove(loop,i) break end @@ -553,6 +573,7 @@ function multi:Resume() else if self.Active==false then table.insert(self.Parent.Mainloop,self) + multi.PausedObjects[self] = nil self.Active=true end end @@ -570,6 +591,7 @@ function multi:Destroy() if self.Parent.Mainloop[i]==self then self.Parent.OnObjectDestroyed:Fire(self) table.remove(self.Parent.Mainloop,i) + self.Destroyed = true break end end @@ -594,6 +616,7 @@ function multi:setName(name) end multi.SetName = multi.setName --Constructors [CORE] +local _tid = 0 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 local c = {} @@ -607,6 +630,7 @@ function multi:newBase(ins) c.funcTM={} c.funcTMR={} c.ender={} + c.TID = _tid c.important={} c.Act=function() end c.Parent=self @@ -617,6 +641,7 @@ function multi:newBase(ins) else table.insert(self.Mainloop,c) end + _tid = _tid + 1 return c end function multi:newProcessor(file) @@ -635,7 +660,7 @@ function multi:newProcessor(file) c.Jobs={} c.queue={} c.jobUS=2 - c.l=self:newLoop(function(self,dt) + c.l=self:newLoop(function(self,dt) if self.link.Active then c:uManager() end @@ -740,6 +765,7 @@ function multi:newConnection(protect,func) local c={} c.callback = func c.Parent=self + c.lock = false setmetatable(c,{__call=function(self,...) local t = ... if type(t)=="table" and t.Type ~= nil then @@ -788,8 +814,15 @@ function multi:newConnection(protect,func) return self.connections[name] or self end end + function c:Lock() + c.lock = true + end + function c:Unlock() + c.lock = false + end function c:Fire(...) local ret={} + if self.lock then return end for i=#self.func,1,-1 do if self.protect then local temp={pcall(self.func[i][1],...)} @@ -822,6 +855,7 @@ function multi:newConnection(protect,func) ID=self.ID, Parent=self, Fire=function(self,...) + if self.Parent.lock then return end --~ if self.Parent.FC>0 then --~ for i=1,#self.Parent.FC do --~ self.Parent.FC[i]:Fire(...) @@ -1046,9 +1080,9 @@ function multi:newFunction(func) c.func=func mt={ __index=multi, - __call=function(self,...) - if self.Active then - return self:func(...) + __call=function(self,...) + if self.Active then + return self:func(...) end return nil,true end @@ -1436,19 +1470,38 @@ if os.getOS()=="windows" then else thread.__CORES=tonumber(io.popen("nproc --all"):read("*n")) 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) + thread._Requests() coroutine.yield({"_sleep_",n or 0}) end function thread.hold(n) + thread._Requests() return coroutine.yield({"_hold_",n or function() return true end}) end function thread.skip(n) + thread._Requests() coroutine.yield({"_skip_",n or 0}) end function thread.kill() coroutine.yield({"_kill_",":)"}) end function thread.yeild() + thread._Requests() coroutine.yield({"_sleep_",0}) end function thread.isThread() @@ -1469,8 +1522,8 @@ function thread.waitFor(name) return thread.get(name) end function thread.testFor(name,_val,sym) - thread.hold(function() - local val = thread.get(name)~=nil + thread.hold(function() + local val = thread.get(name)~=nil if val then if sym == "==" or sym == "=" then return _val==val @@ -1496,21 +1549,52 @@ multi:setDomainName("Threads") multi:setDomainName("Globals") local initT = false local threadCount = 0 +local threadid = 0 function multi:newThread(name,func) - local func = func + local func = func or name if type(name) == "function" then - func = name name = "Thread#"..threadCount 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={} c.ref={} c.Name=name c.thread=coroutine.create(func) c.sleep=1 c.Type="thread" + c.TID = threadid c.firstRunDone=false c.timer=multi:newTimer() 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) ret=coroutine.yield({Name=name,Value=val}) self:syncGlobals(ret) @@ -1544,6 +1628,8 @@ function multi:newThread(name,func) multi.initThreads() end c.creationTime = os.clock() + threadid = threadid + 1 + return c end function multi.initThreads() initT = true @@ -1553,11 +1639,29 @@ function multi.initThreads() self.skip=tonumber(n) or 24 end multi.scheduler.skip=0 - multi.scheduler.counter=0 multi.scheduler.Threads=multi:linkDomain("Threads") multi.scheduler.Globals=multi:linkDomain("Globals") + local holds = {} + local skips = {} + local t0,t1,t2,t3,t4,t5,t6 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 ret={} if coroutine.status(self.Threads[i].thread)=="dead" then @@ -1596,26 +1700,18 @@ function multi.initThreads() elseif ret[1]=="_skip_" then self.Threads[i].timer:Reset() self.Threads[i].sleep=math.huge - local event=multi:newEvent(function(evnt) return multi.scheduler.counter>=evnt.counter end) - event.link=self.Threads[i] - event.counter=self.counter+ret[2] - event:OnEvent(function(evnt) - evnt.link.sleep=0 - evnt:Destroy() - end):setName("multi.thread.skip") + table.insert(skips,{ + Link = self.Threads[i], + count = ret[2], + pos = 0, + }) elseif ret[1]=="_hold_" then self.Threads[i].timer:Reset() self.Threads[i].sleep=math.huge - local event=multi:newEvent(ret[2]) - event.returns = nil - event.link=self.Threads[i] - event:OnEvent(function(evnt) - evnt.link.sleep=0 - evnt.link.returns = evnt.returns - multi.nextStep(function() - evnt:Destroy() - end) - end):setName("multi.thread.hold") + table.insert(holds,{ + Link = self.Threads[i], + func = ret[2] + }) elseif ret.Name then self.Globals[ret.Name]=ret.Value end