V15.2.0 #33

Merged
rayaman merged 75 commits from v15.2.0 into master 2022-04-19 18:45:52 -04:00
5 changed files with 176 additions and 103 deletions
Showing only changes of commit 4877f64ca1 - Show all commits

View File

@ -66,7 +66,7 @@ Changed:
- Connection Objects no longer Fire with syntax sugar when attached to an object: - Connection Objects no longer Fire with syntax sugar when attached to an object:
`multiobj:OnSomeEvent(arg1,arg2.arg3)` No longer triggers the Fire event. As part of the update to make all objects use connections internally this little used feature had to be scrapped! `multiobj:OnSomeEvent(...)` No longer triggers the Fire event. As part of the update to make all objects use connections internally this little used feature had to be scrapped!
- multi:newTStep now derives it's functionality from multi:newStep (Cut's down on code length a bit) - multi:newTStep now derives it's functionality from multi:newStep (Cut's down on code length a bit)
@ -76,14 +76,16 @@ Removed:
--- ---
- `multi:newFunction(func)` - `multi:newFunction(func)`
- `thread:newFunction(func)` Has many more features and replaces what multi:newFunction did - `thread:newFunction(func)` Has many more features and replaces what multi:newFunction did
- `multi.holdFor()` Now that multi.hold takes the option table that thread.hold has this feature can be emulated using that.
- Calling Fire on a connection no longer returns anything! Now that internal features use connections, I noticed how slow connections are and have increased their speed quite a bit. From 50,000 Steps per seconds to almost 7 Million. All other features should work just fine. Only returning values has been removed - Calling Fire on a connection no longer returns anything! Now that internal features use connections, I noticed how slow connections are and have increased their speed quite a bit. From 50,000 Steps per seconds to almost 7 Million. All other features should work just fine. Only returning values has been removed
Fixed: Fixed:
--- ---
- [Issue](https://github.com/rayaman/multi/issues/30) with Lanes crashing the lua state. Issue seems to be related to my filesystem - [Issue](https://github.com/rayaman/multi/issues/30) with Lanes crashing the lua state. Issue seems to be related to my filesystem
- [Issue](https://github.com/rayaman/multi/issues/29) where System threaded functions not up to date with threaded functions - [Issue](https://github.com/rayaman/multi/issues/29) where System threaded functions not being up to date with threaded functions
- Issue where gettasksdetails would try to process a destroyed object causing it to crash - Issue where gettasksdetails() would try to process a destroyed object causing it to crash
- Issue with multi.hold() not pumping the mainloop and only the scheduler
ToDo: ToDo:

View File

@ -137,7 +137,7 @@ function multi:getTasksDetails(t)
{"Thread Name","Uptime","TID","Attached To"} {"Thread Name","Uptime","TID","Attached To"}
} }
local proc_tab = { local proc_tab = {
{"Process Name", "Uptime", "PID", "Load", "Cycles per Second per task"} {"Process Name", "Uptime", "PID", "Load", "CpS"}
} }
for th,process in pairs(globalThreads) do for th,process in pairs(globalThreads) do
if tostring(th.isProcessThread) == "destroyed" then if tostring(th.isProcessThread) == "destroyed" then
@ -372,7 +372,7 @@ function multi:newConnection(protect,func,kill)
end end
end end
function temp:Destroy() function temp:Destroy()
for i=1,#call_funcs do for i=#call_funcs,1,-1 do
if call_funcs[i]~=nil then if call_funcs[i]~=nil then
if call_funcs[i]==self.func then if call_funcs[i]==self.func then
table.remove(call_funcs,i) table.remove(call_funcs,i)
@ -742,8 +742,6 @@ function multi:newStep(start,reset,count,skip)
c.skip=skip or 0 c.skip=skip or 0
c.spos=0 c.spos=0
c.count=count or 1*think c.count=count or 1*think
c.funcE={}
c.funcS={}
c.start=start or 1 c.start=start or 1
if start~=nil and reset~=nil then if start~=nil and reset~=nil then
if start>reset then if start>reset then
@ -905,9 +903,13 @@ function multi:scheduleJob(time,func)
end end
local __CurrentProcess = multi local __CurrentProcess = multi
local __CurrentTask
function multi.getCurrentProcess() function multi.getCurrentProcess()
return __CurrentProcess return __CurrentProcess
end end
function multi.getCurrentTask()
return __CurrentTask
end
local sandcount = 1 local sandcount = 1
function multi:newProcessor(name) function multi:newProcessor(name)
@ -1087,14 +1089,17 @@ function multi.hold(func,opt)
return thread.sleep(func) return thread.sleep(func)
end end
local death = false local death = false
local proc = multi.getCurrentTask()
proc:Pause()
if type(func)=="number" then if type(func)=="number" then
self:newThread("Hold_func",function() self:newThread("Hold_func",function()
thread.sleep(func) thread.hold(func)
death = true death = true
end) end)
while not death do while not death do
multi.scheduler:Act() multi:uManager()
end end
proc:Resume()
else else
local rets local rets
self:newThread("Hold_func",function() self:newThread("Hold_func",function()
@ -1102,25 +1107,13 @@ function multi.hold(func,opt)
death = true death = true
end) end)
while not death do while not death do
multi.scheduler:Act() multi:uManager()
end end
proc:Resume()
return unpack(rets) return unpack(rets)
end end
end end
function multi.holdFor(n,func)
local temp
multi.getCurrentProcess():newThread(function()
thread.sleep(n)
temp = true
end)
return multi.getCurrentProcess().hold(function()
if func() then
return func()
elseif temp then
return multi.NIL, multi.TIMEOUT
end
end)
end
local function cleanReturns(...) local function cleanReturns(...)
local returns = {...} local returns = {...}
local rets = {} local rets = {}
@ -1133,10 +1126,12 @@ local function cleanReturns(...)
end end
return unpack(returns,1,ind) return unpack(returns,1,ind)
end end
function thread.pushStatus(...) function thread.pushStatus(...)
local t = thread.getRunningThread() local t = thread.getRunningThread()
t.statusconnector:Fire(...) t.statusconnector:Fire(...)
end end
function thread:newFunctionBase(generator,holdme) function thread:newFunctionBase(generator,holdme)
return function() return function()
local tfunc = {} local tfunc = {}
@ -1635,12 +1630,14 @@ function multi:lightloop(settings)
multi.OnPreLoad:Fire() multi.OnPreLoad:Fire()
if not isRunning then if not isRunning then
local Loop=self.Mainloop local Loop=self.Mainloop
local ctask
while true do while true do
for _D=#Loop,1,-1 do for _D=#Loop,1,-1 do
if Loop[_D].Active then __CurrentTask = Loop[_D]
self.CID=_D ctask = __CurrentTask
if ctask.Active then
if not protect then if not protect then
Loop[_D]:Act() ctask:Act()
end end
end end
end end
@ -1692,26 +1689,29 @@ function multi:mainloop(settings)
local autoP = 0 local autoP = 0
local solid,sRef local solid,sRef
local cc=0 local cc=0
local ctask
multi.OnLoad:Fire() multi.OnLoad:Fire()
while mainloopActive do while mainloopActive do
if priority == 1 then if priority == 1 then
for _D=#Loop,1,-1 do for _D=#Loop,1,-1 do
__CurrentTask = Loop[_D]
ctask = __CurrentTask
for P=1,7 do for P=1,7 do
if Loop[_D] then if ctask then
if (PS.PList[P])%Loop[_D].Priority==0 then if (PS.PList[P])%ctask.Priority == 0 then
if Loop[_D].Active then if ctask.Active then
self.CID=_D self.CID = _D
if not protect then if not protect then
Loop[_D]:Act() ctask:Act()
__CurrentProcess = self __CurrentProcess = self
else else
local status, err=pcall(Loop[_D].Act,Loop[_D]) local status, err = pcall(ctask.Act,ctask)
__CurrentProcess = self __CurrentProcess = self
if err then if err then
Loop[_D].error=err ctask.error=err
self.OnError:Fire(Loop[_D],err) self.OnError:Fire(ctask,err)
if stopOnError then if stopOnError then
Loop[_D]:Destroy() ctask:Destroy()
end end
end end
end end
@ -1722,21 +1722,22 @@ function multi:mainloop(settings)
end end
elseif priority == 2 then elseif priority == 2 then
for _D=#Loop,1,-1 do for _D=#Loop,1,-1 do
if Loop[_D] then __CurrentTask = Loop[_D]
if (PStep)%Loop[_D].Priority==0 then ctask = __CurrentTask
if Loop[_D].Active then if ctask then
self.CID=_D if (PStep)%ctask.Priority==0 then
if ctask.Active then
if not protect then if not protect then
Loop[_D]:Act() ctask:Act()
__CurrentProcess = self __CurrentProcess = self
else else
local status, err=pcall(Loop[_D].Act,Loop[_D]) local status, err=pcall(ctask.Act,ctask)
__CurrentProcess = self __CurrentProcess = self
if err then if err then
Loop[_D].error=err ctask.error=err
self.OnError:Fire(Loop[_D],err) self.OnError:Fire(ctask,err)
if stopOnError then if stopOnError then
Loop[_D]:Destroy() ctask:Destroy()
end end
end end
end end
@ -1756,21 +1757,22 @@ function multi:mainloop(settings)
cc=0 cc=0
end end
for _D=#Loop,1,-1 do for _D=#Loop,1,-1 do
if Loop[_D] then __CurrentTask = Loop[_D]
if Loop[_D].Priority == p_c or (Loop[_D].Priority == p_h and tt<.5) or (Loop[_D].Priority == p_an and tt<.125) or (Loop[_D].Priority == p_n and tt<.063) or (Loop[_D].Priority == p_bn and tt<.016) or (Loop[_D].Priority == p_l and tt<.003) or (Loop[_D].Priority == p_i and tt<.001) then ctask = __CurrentTask
if Loop[_D].Active then if ctask then
self.CID=_D if ctask.Priority == p_c or (ctask.Priority == p_h and tt<.5) or (ctask.Priority == p_an and tt<.125) or (ctask.Priority == p_n and tt<.063) or (ctask.Priority == p_bn and tt<.016) or (ctask.Priority == p_l and tt<.003) or (ctask.Priority == p_i and tt<.001) then
if ctask.Active then
if not protect then if not protect then
Loop[_D]:Act() ctask:Act()
__CurrentProcess = self __CurrentProcess = self
else else
local status, err=pcall(Loop[_D].Act,Loop[_D]) local status, err=pcall(ctask.Act,ctask)
__CurrentProcess = self __CurrentProcess = self
if err then if err then
Loop[_D].error=err ctask.error=err
self.OnError:Fire(Loop[_D],err) self.OnError:Fire(ctask,err)
if stopOnError then if stopOnError then
Loop[_D]:Destroy() ctask:Destroy()
end end
end end
end end
@ -1780,51 +1782,51 @@ function multi:mainloop(settings)
end end
elseif priority == -1 then elseif priority == -1 then
for _D=#Loop,1,-1 do for _D=#Loop,1,-1 do
sRef = Loop[_D] __CurrentTask = Loop[_D]
if Loop[_D] then ctask = __CurrentTask
if (sRef.Priority == p_c) or PStep==0 then if ctask then
if sRef.Active then if (ctask.Priority == p_c) or PStep==0 then
self.CID=_D if ctask.Active then
if not protect then if not protect then
if sRef.solid then if ctask.solid then
sRef:Act() ctask:Act()
__CurrentProcess = self __CurrentProcess = self
solid = true solid = true
else else
time = multi.timer(sRef.Act,sRef) time = multi.timer(ctask.Act,ctask)
sRef.solid = true ctask.solid = true
solid = false solid = false
end end
if Loop[_D] and not solid then if ctask and not solid then
if time == 0 then if time == 0 then
Loop[_D].Priority = p_c ctask.Priority = p_c
else else
Loop[_D].Priority = P_LB ctask.Priority = P_LB
end end
end end
else else
if Loop[_D].solid then if ctask.solid then
Loop[_D]:Act() ctask:Act()
__CurrentProcess = self __CurrentProcess = self
solid = true solid = true
else else
time, status, err=multi.timer(pcall,Loop[_D].Act,Loop[_D]) time, status, err=multi.timer(pcall,ctask.Act,ctask)
__CurrentProcess = self __CurrentProcess = self
Loop[_D].solid = true ctask.solid = true
solid = false solid = false
end end
if Loop[_D] and not solid then if ctask and not solid then
if time == 0 then if time == 0 then
Loop[_D].Priority = p_c ctask.Priority = p_c
else else
Loop[_D].Priority = P_LB ctask.Priority = P_LB
end end
end end
if err then if err then
Loop[_D].error=err ctask.error=err
self.OnError:Fire(Loop[_D],err) self.OnError:Fire(ctask,err)
if stopOnError then if stopOnError then
Loop[_D]:Destroy() ctask:Destroy()
end end
end end
end end
@ -1844,20 +1846,21 @@ function multi:mainloop(settings)
end end
else else
for _D=#Loop,1,-1 do for _D=#Loop,1,-1 do
if Loop[_D] then __CurrentTask = Loop[_D]
if Loop[_D].Active then ctask = __CurrentTask
self.CID=_D if ctask then
if ctask.Active then
if not protect then if not protect then
Loop[_D]:Act() ctask:Act()
__CurrentProcess = self __CurrentProcess = self
else else
local status, err=pcall(Loop[_D].Act,Loop[_D]) local status, err=pcall(ctask.Act,ctask)
__CurrentProcess = self __CurrentProcess = self
if err then if err then
Loop[_D].error=err ctask.error=err
self.OnError:Fire(Loop[_D],err) self.OnError:Fire(ctask,err)
if stopOnError then if stopOnError then
Loop[_D]:Destroy() ctask:Destroy()
end end
end end
end end
@ -2136,25 +2139,24 @@ function multi:enableLoadDetection()
multi.maxSpd = stop multi.maxSpd = stop
end end
local busy = false
local lastVal = 0 local lastVal = 0
local last_step = 0 local last_step = 0
local bb = 0
function multi:getLoad() function multi:getLoad()
if not multi.maxSpd then self:enableLoadDetection() end if not multi.maxSpd then multi:enableLoadDetection() end
if busy then return lastVal,last_step end
local val = nil local val = nil
local bench local bench
self:benchMark(.01):OnBench(function(time,steps) local bb
self:benchMark(.01).OnBench(function(time,steps)
bench = steps bench = steps
bb = steps bb = steps
end) end)
_,timeout = multi.hold(function() _,timeout = multi.hold(function()
return bench return bench
end,{sleep=.011}) end,{sleep=.012})
if timeout then if timeout then
bench = 150000 bench = 0
bb = 0
end end
bench = bench^1.5 bench = bench^1.5
val = math.ceil((1-(bench/(multi.maxSpd/2.2)))*100) val = math.ceil((1-(bench/(multi.maxSpd/2.2)))*100)

71
tests/connectionTest.lua Normal file
View File

@ -0,0 +1,71 @@
function connectionThreadTests(multi,thread)
print("Starting Connection and Thread tests!")
func = thread:newFunction(function(count)
local a = 0
while true do
a = a + 1
thread.sleep(.1)
thread.pushStatus(a,count)
if a == count then break end
end
return "Done"
end)
local ret = func(10)
local ret2 = func(15)
local ret3 = func(20)
local s1,s2,s3 = 0,0,0
ret.OnStatus(function(part,whole)
s1 = math.ceil((part/whole)*1000)/10
end)
ret2.OnStatus(function(part,whole)
s2 = math.ceil((part/whole)*1000)/10
end)
ret3.OnStatus(function(part,whole)
s3 = math.ceil((part/whole)*1000)/10
end)
local err, timeout = thread.hold(ret2.OnReturn + ret.OnReturn + ret3.OnReturn,{sleep=3})
if s1 == 100 and s2 == 100 and s3 == 100 then
print("Threads: Ok")
else
print("Threads on status error")
end
if timeout then
print("Threads or Connection error!")
else
print("Connection Test 1: Ok")
end
conn1 = multi:newConnection()
conn2 = multi:newConnection()
conn3 = multi:newConnection()
local c1,c2,c3,c4 = false,false,false,false
local a = conn1(function()
c1 = true
end)
local b = conn2(function()
c2 = true
end)
local c = conn3(function()
c3 = true
end)
local d = conn3(function()
c4 = true
end)
conn1:Fire()
conn2:Fire()
conn3:Fire()
if c1 and c2 and c3 and c4 then
print("Connection Test 2: Ok")
else
print("Connection Test 2: Error")
end
c3 = false
c4 = false
d:Destroy()
conn3:Fire()
if c3 and not(c4) then
print("Connection Test 3: Ok")
else
print("Connection Test 3: Error removing connection")
end
end
return connectionThreadTests

View File

@ -37,6 +37,6 @@ function objectTests(multi,thread)
if tloops > 10 then print("TLoops: Ok") else print("TLoops: Bad!") end if tloops > 10 then print("TLoops: Ok") else print("TLoops: Bad!") end
if updaters > 100 then print("Updaters: Ok") else print("Updaters: Bad!") end if updaters > 100 then print("Updaters: Ok") else print("Updaters: Bad!") end
end) end)
return event thread.hold(event.OnEvent)
end end
return objectTests return objectTests

View File

@ -16,20 +16,18 @@ package.path="./?.lua;../?.lua;../?/init.lua;../?.lua;../?/?/init.lua;"..package
This will be pushed directly to the master as tests start existing. This will be pushed directly to the master as tests start existing.
]] ]]
local multi, thread = require("multi"):init() local multi, thread = require("multi"):init()
local good = false local good = false
runTest = thread:newFunction(function() runTest = thread:newFunction(function()
local objects = multi:newProcessor("Basic Object Tests") local objects = multi:newProcessor("Basic Object Tests")
objects.Start() objects.Start()
otest = require("tests/objectTests")(objects,thread) require("tests/objectTests")(objects,thread)
thread.hold(otest.OnEvent) objects.Stop()
print("Timers: Ok") local conn_thread = multi:newProcessor("Connection/Thread Tests")
print("Connections: Ok") conn_thread.Start()
print("Threads: Ok") require("tests/connectionTest")(conn_thread,thread)
print(objects:getTasksDetails()) conn_thread.Stop()
good = true print(multi:getTasksDetails())
print("\nTests done")
os.exit() os.exit()
end,true) end)
print(runTest()) runTest()
multi:mainloop() multi:mainloop()