Working on custom prioritySchemes
This commit is contained in:
parent
42149ffab2
commit
189552ac65
22
README.md
22
README.md
@ -1,6 +1,10 @@
|
||||
# Multi Version: 16.0.0 Connecting the dots
|
||||
# Multi Version: 16.0.0 - Getting the priorities straight
|
||||
**Key Changes**
|
||||
- Concat connections
|
||||
- Expanded connection logic
|
||||
- New integration priorityManager
|
||||
- Tests for threads
|
||||
- Consistent behavior between the threading integrations
|
||||
- Bug fixes
|
||||
|
||||
Found an issue? Please [submit it](https://github.com/rayaman/multi/issues) and someone will look into it!
|
||||
|
||||
@ -16,9 +20,19 @@ Progress is being made in [v16.0.0](https://github.com/rayaman/multi/tree/v16.0.
|
||||
INSTALLING
|
||||
----------
|
||||
Link to optional dependencies:
|
||||
- [lanes](https://github.com/LuaLanes/lanes)
|
||||
- [lanes](https://github.com/LuaLanes/lanes) `luarocks install lanes`
|
||||
|
||||
- [chronos](https://github.com/ldrumm/chronos) `luarocks install chronos`
|
||||
|
||||
- [love2d](https://love2d.org/)
|
||||
|
||||
When using love2d add multi:uManager() or any processor to love.update()
|
||||
|
||||
```lua
|
||||
function love.update(dt)
|
||||
multi:uManager()
|
||||
end
|
||||
```
|
||||
|
||||
To install copy the multi folder into your environment and you are good to go</br>
|
||||
If you want to use the system threads, then you'll need to install lanes or love2d game engine!
|
||||
@ -34,7 +48,7 @@ https://discord.gg/U8UspuA
|
||||
|
||||
Planned features/TODO
|
||||
---------------------
|
||||
- [x] Create test suite (In progress, mostly done)
|
||||
- [x] ~~Create test suite (In progress, mostly done)~~
|
||||
- [ ] Network Parallelism rework
|
||||
|
||||
Usage: [Check out the documentation for more info](https://github.com/rayaman/multi/blob/master/Documentation.md)
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
# Changelog
|
||||
Table of contents
|
||||
---
|
||||
[Update 16.0.0 - Connecting the dots](#update-1600---connecting-the-dots)</br>
|
||||
[Update 16.0.0 - Connecting the dots](#update-1600---getting-the-priorities-straight)</br>
|
||||
[Update 15.3.1 - Bug fix](#update-1531---bug-fix)</br>
|
||||
[Update 15.3.0 - A world of connections](#update-1530---a-world-of-connections)</br>
|
||||
[Update 15.2.1 - Bug fix](#update-1521---bug-fix)</br>
|
||||
@ -58,15 +58,30 @@ Table of contents
|
||||
[Update: EventManager 1.0.0 - Error checking](#update-eventmanager-100---error-checking)</br>
|
||||
[Version: EventManager 0.0.1 - In The Beginning things were very different](#version-eventmanager-001---in-the-beginning-things-were-very-different)
|
||||
|
||||
# Update 16.0.0 - Connecting the dots
|
||||
# Update 16.0.0 - Getting the priorities straight
|
||||
Added
|
||||
---
|
||||
### New Integration - priorityManager
|
||||
|
||||
Allows the user to have multi auto set priorities. Also adds the functionality to create your own runners (multi:mainloop(), multi:umanager()) that you can set using the priority manager. Even if you do not have `chronos` installed these features will still work!
|
||||
|
||||
- multi:setCurrentTask() -- Used to set the current processor. Used in custom processors.
|
||||
- multi:setCurrentProcess() -- Used to set the current processor. It should only be called on a processor object
|
||||
- multi.warn(...) -- Sends a warning.
|
||||
- multi.error(err) -- When called this function will gracefully kill multi, cleaning things up.
|
||||
- multi.warn(...) -- Sends a warning. Yellow `WARNING`
|
||||
- multi.error(err) -- When called this function will gracefully kill multi, cleaning things up. Red `ERROR`
|
||||
|
||||
**Note:** If you want to have multi.print, multi.warn and multi.error to work you need to enable them in settings
|
||||
```lua
|
||||
multi, thread = require("multi"):init {
|
||||
print=true,
|
||||
warn=true,
|
||||
error=true -- Errors will throw regardless. Setting to true will
|
||||
-- cause the library to force hard crash itself!
|
||||
}
|
||||
```
|
||||
- THREAD.setENV(table) -- Set a simple table that will be merged into the global namespace
|
||||
|
||||
**Note:** To maintain compatibility between each integration use simple tables. No self references, and string indices only
|
||||
**Note:** To maintain compatibility between each integration use simple tables. No self references, and string indices only.
|
||||
```lua
|
||||
THREAD.setENV({
|
||||
shared_function = function()
|
||||
@ -204,8 +219,18 @@ Added
|
||||
|
||||
Changed
|
||||
---
|
||||
- multi errors now internally call `multi.error` instead of `multi.print`
|
||||
- Actors Act() method now returns true when the main event is fired. Steps/Loops always return true. Nil is returned otherwise.
|
||||
- Connection:Connect(func, name) Now you can supply a name and name the connection.
|
||||
- Connection:getConnection(name) This will return the connection function which you can do what you will with it.
|
||||
- Fast connections are the only connections. Legacy connections have been removed completely. Not much should change on the users end. Perhaps some minor changes.
|
||||
- conn:Lock(conn) When supplied with a connection reference (What is returned by Connect(func)) it will only lock that connection Reference and not the entire connection. Calling without any arguments will lock the entire connection.
|
||||
- connUnlock(conn) When supplied with a connection reference it restores that reference and it can be fired again. When no arguments are supplied it unlocks the entire connection.
|
||||
|
||||
**Note:** Lock and Unlock when supplied with arguments and not supplied with arguments operate on different objects. If you unlock an entire connection. Individual connection refs will not unlock. The same applies with locking. The entire connection and references are treated differently.
|
||||
|
||||
- multi.OnObjectCreated is only called when an object is created in a particular process. Proc.OnObjectCreated is needed to detect when an object is created within a process.
|
||||
- multi.print shows "INFO" before it's message.
|
||||
- multi.print shows "INFO" before it's message. Blue `INFO`
|
||||
- Connections internals changed, not too much changed on the surface.
|
||||
- newConnection(protect, func, kill)
|
||||
- `protect` disables fastmode, but protects the connection
|
||||
@ -221,8 +246,9 @@ Removed
|
||||
|
||||
Fixed
|
||||
---
|
||||
- multi:reallocate(processor, index) has been fixed to work with the current changes of the library.
|
||||
- Issue with lanes not handling errors properly. This is now resolved
|
||||
- Oversight with how pushStatus worked with nesting threaded functions, connections and forwarding events
|
||||
- Oversight with how pushStatus worked with nesting threaded functions, connections and forwarding events. Changes made and this works now!
|
||||
```lua
|
||||
func = thread:newFunction(function()
|
||||
for i=1,10 do
|
||||
|
||||
299
init.lua
299
init.lua
@ -142,25 +142,34 @@ function multi.ForEach(tab,func)
|
||||
for i=1,#tab do func(tab[i]) end
|
||||
end
|
||||
|
||||
function multi.randomString(n)
|
||||
local str = ''
|
||||
local strings = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','1','2','3','4','5','6','7','8','9','0','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'}
|
||||
for i=1,n do
|
||||
str = str..''..strings[math.random(1,#strings)]
|
||||
end
|
||||
return str
|
||||
end
|
||||
|
||||
local optimization_stats = {}
|
||||
local ignoreconn = true
|
||||
function multi:newConnection(protect, func, kill)
|
||||
local empty_func = function() end
|
||||
function multi:newConnection(protect,func,kill)
|
||||
local c={}
|
||||
local call_funcs = {}
|
||||
local lock = false
|
||||
c.__connectionAdded = function() end
|
||||
c.rawadd = false
|
||||
c.Parent = self
|
||||
local locked = {}
|
||||
local fast = {}
|
||||
c.Parent=self
|
||||
|
||||
setmetatable(c,{
|
||||
__call=function(self, ...) -- ()
|
||||
setmetatable(c,{__call=function(self,...)
|
||||
local t = ...
|
||||
if type(t)=="table" then
|
||||
for i,v in pairs(t) do
|
||||
if v == self then
|
||||
local ref = self:Connect(select(2, ...))
|
||||
if v==self then
|
||||
local ref = self:Connect(select(2,...))
|
||||
if ref then
|
||||
ref.root_link = select(1, ...)
|
||||
ref.root_link = select(1,...)
|
||||
return ref
|
||||
end
|
||||
return self
|
||||
@ -171,49 +180,6 @@ function multi:newConnection(protect, func, kill)
|
||||
return self:Connect(...)
|
||||
end
|
||||
end,
|
||||
__mod = function(obj1, obj2) -- %
|
||||
local cn = multi:newConnection()
|
||||
if type(obj1) == "function" and type(obj2) == "table" then
|
||||
obj2(function(...)
|
||||
cn:Fire(obj1(...))
|
||||
end)
|
||||
else
|
||||
multi.error("Invalid mod!", type(obj1), type(obj2),"Expected function, connection(table)")
|
||||
end
|
||||
return cn
|
||||
end,
|
||||
__concat = function(obj1, obj2) -- ..
|
||||
local cn = multi:newConnection()
|
||||
local ref
|
||||
if type(obj1) == "function" and type(obj2) == "table" then
|
||||
cn(function(...)
|
||||
if obj1(...) then
|
||||
obj2:Fire(...)
|
||||
end
|
||||
end)
|
||||
cn.__connectionAdded = function(conn, func)
|
||||
cn:Unconnect(conn)
|
||||
obj2:Connect(func)
|
||||
end
|
||||
elseif type(obj1) == "table" and type(obj2) == "function" then
|
||||
ref = cn(function(...)
|
||||
obj1:Fire(...)
|
||||
obj2(...)
|
||||
end)
|
||||
cn.__connectionAdded = function()
|
||||
cn.rawadd = true
|
||||
cn:Unconnect(ref)
|
||||
ref = cn(function(...)
|
||||
if obj2(...) then
|
||||
obj1:Fire(...)
|
||||
end
|
||||
end)
|
||||
end
|
||||
else
|
||||
multi.error("Invalid concat!", type(obj1), type(obj2),"Expected function/connection(table), connection(table)/function")
|
||||
end
|
||||
return cn
|
||||
end,
|
||||
__add = function(c1,c2) -- Or
|
||||
local cn = multi:newConnection()
|
||||
c1(function(...)
|
||||
@ -270,63 +236,106 @@ function multi:newConnection(protect, func, kill)
|
||||
return #call_funcs~=0
|
||||
end
|
||||
|
||||
function c:getConnection(name,ignore)
|
||||
if ignore then
|
||||
return connections[name] or CRef
|
||||
else
|
||||
return connections[name] or self
|
||||
function c:Lock(conn)
|
||||
if conn and not conn.lock then
|
||||
conn.lock = function() end
|
||||
for i = 1, #fast do
|
||||
if conn.ref == fast[i] then
|
||||
fast[i] = conn.lock
|
||||
return self
|
||||
end
|
||||
end
|
||||
return self
|
||||
end
|
||||
end
|
||||
|
||||
function c:Lock()
|
||||
lock = self.Fire
|
||||
self.Fire = function() end
|
||||
lock = true
|
||||
return self
|
||||
end
|
||||
|
||||
function c:Unlock()
|
||||
self.Fire = lock
|
||||
function c:Unlock(conn)
|
||||
if conn and conn.lock then
|
||||
for i = 1, #fast do
|
||||
if conn.lock == fast[i] then
|
||||
fast[i] = conn.ref
|
||||
return self
|
||||
end
|
||||
end
|
||||
return self
|
||||
end
|
||||
lock = false
|
||||
return self
|
||||
end
|
||||
|
||||
if protect then
|
||||
function c:Fire(...)
|
||||
if lock then return end
|
||||
local kills = {}
|
||||
for i=1,#fast do
|
||||
local suc, err = pcall(fast[i], ...)
|
||||
if not suc then
|
||||
print(err)
|
||||
end
|
||||
if kill then
|
||||
table.remove(kills,i)
|
||||
multi:newTask(function()
|
||||
for _,k in pairs(kills) do
|
||||
table.remove(fast, k)
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function c:getConnections()
|
||||
return call_funcs
|
||||
end
|
||||
|
||||
function c:getConnection(name, ignore)
|
||||
return fast[name] or function() multi:warning("") end
|
||||
end
|
||||
|
||||
function c:Unconnect(conn)
|
||||
if conn.fast then
|
||||
for i = 1, #call_funcs do
|
||||
if conn.ref == call_funcs[i] then
|
||||
table.remove(call_funcs, i)
|
||||
for i = 1, #fast do
|
||||
if conn.ref == fast[i] then
|
||||
return table.remove(fast, i), i
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function c:fastMode() return self end
|
||||
if kill then
|
||||
local kills = {}
|
||||
function c:Fire(...)
|
||||
if lock then return end
|
||||
for i=1,#fast do
|
||||
fast[i](...)
|
||||
if kill then
|
||||
table.insert(kills,i)
|
||||
multi:newTask(function()
|
||||
for k = #kills, 1, -1 do
|
||||
table.remove(fast, k)
|
||||
table.remove(kills,i)
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
elseif conn.Destroy then
|
||||
conn:Destroy()
|
||||
end
|
||||
end
|
||||
|
||||
function c:Fire(...)
|
||||
for i=1, #call_funcs do
|
||||
call_funcs[i](...)
|
||||
end
|
||||
end
|
||||
|
||||
-- Not needed anymore, since it's so light, I'll leave it in forever
|
||||
function c:fastMode() return self end
|
||||
|
||||
function c:Connect(func)
|
||||
local th
|
||||
if thread.getRunningThread then
|
||||
th = thread.getRunningThread()
|
||||
end
|
||||
if th then
|
||||
local fref = func
|
||||
func = function(...)
|
||||
__CurrentConnectionThread = th
|
||||
fref(...)
|
||||
else
|
||||
function c:Fire(...)
|
||||
if lock then return end
|
||||
for i=1,#fast do
|
||||
fast[i](...)
|
||||
end
|
||||
end
|
||||
table.insert(call_funcs, func)
|
||||
end
|
||||
|
||||
function c:Connect(func, name)
|
||||
table.insert(fast, func)
|
||||
if name then
|
||||
fast[name] = func
|
||||
else
|
||||
fast["Conn_"..multi.randomString(12)] = func
|
||||
end
|
||||
local temp = {fast = true}
|
||||
setmetatable(temp,{
|
||||
__call=function(s,...)
|
||||
@ -346,11 +355,7 @@ function multi:newConnection(protect, func, kill)
|
||||
end,
|
||||
})
|
||||
temp.ref = func
|
||||
if self.rawadd then
|
||||
self.rawadd = false
|
||||
else
|
||||
self.__connectionAdded(temp, func)
|
||||
end
|
||||
temp.name = name
|
||||
return temp
|
||||
end
|
||||
|
||||
@ -366,41 +371,11 @@ function multi:newConnection(protect, func, kill)
|
||||
return temp
|
||||
end
|
||||
|
||||
if find_optimization then
|
||||
--
|
||||
end
|
||||
|
||||
c.connect=c.Connect
|
||||
c.GetConnection=c.getConnection
|
||||
c.HasConnections = c.hasConnections
|
||||
c.GetConnection = c.getConnection
|
||||
|
||||
if protect then -- Do some tests and override the fastmode if you want to do something differently
|
||||
function c:Fire(...)
|
||||
for i=#call_funcs,1,-1 do
|
||||
if not call_funcs[i] then return end
|
||||
local suc, err = pcall(call_funcs[i],...)
|
||||
if not suc then
|
||||
multi.print(err)
|
||||
end
|
||||
if kill then
|
||||
table.remove(call_funcs,i)
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif kill then
|
||||
function c:Fire(...)
|
||||
for i=#call_funcs,1,-1 do
|
||||
call_funcs[i](...)
|
||||
table.remove(call_funcs,i)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if func then
|
||||
c = c .. func
|
||||
end
|
||||
|
||||
if not(ignoreconn) then
|
||||
self:create(c)
|
||||
end
|
||||
@ -474,6 +449,7 @@ function multi:SetTime(n)
|
||||
self.link:Pause()
|
||||
self.OnTimedOut:Fire(self.link)
|
||||
self:Destroy()
|
||||
return true
|
||||
end
|
||||
end
|
||||
return self
|
||||
@ -564,7 +540,7 @@ function multi:isDone()
|
||||
end
|
||||
|
||||
function multi:create(ref)
|
||||
self.OnObjectCreated:Fire(ref,self)
|
||||
self.OnObjectCreated:Fire(ref, self)
|
||||
return self
|
||||
end
|
||||
|
||||
@ -653,6 +629,7 @@ function multi:newEvent(task)
|
||||
self:Pause()
|
||||
self.returns = t
|
||||
c.OnEvent:Fire(self)
|
||||
return true
|
||||
end
|
||||
end
|
||||
function c:SetTask(func)
|
||||
@ -675,6 +652,7 @@ function multi:newUpdater(skip)
|
||||
if pos >= skip then
|
||||
pos = 0
|
||||
self.OnUpdate:Fire(self)
|
||||
return true
|
||||
end
|
||||
pos = pos+1
|
||||
end
|
||||
@ -701,6 +679,7 @@ function multi:newAlarm(set)
|
||||
self.Active=false
|
||||
self.OnRing:Fire(self)
|
||||
t = clock()
|
||||
return true
|
||||
end
|
||||
end
|
||||
function c:Resume()
|
||||
@ -732,10 +711,12 @@ function multi:newLoop(func,notime)
|
||||
if notime then
|
||||
function c:Act()
|
||||
self.OnLoop:Fire(self)
|
||||
return true
|
||||
end
|
||||
else
|
||||
function c:Act()
|
||||
self.OnLoop:Fire(self,clock()-start)
|
||||
return true
|
||||
end
|
||||
end
|
||||
c.OnLoop = self:newConnection():fastMode()
|
||||
@ -783,6 +764,7 @@ function multi:newStep(start,reset,count,skip)
|
||||
if self.spos>=self.skip then
|
||||
self.spos=0
|
||||
end
|
||||
return true
|
||||
end
|
||||
c.Reset=c.Resume
|
||||
c.OnStart = self:newConnection():fastMode()
|
||||
@ -820,6 +802,7 @@ function multi:newTLoop(func,set)
|
||||
self.life=self.life+1
|
||||
self.timer:Reset()
|
||||
self.OnLoop:Fire(self,self.life)
|
||||
return true
|
||||
end
|
||||
end
|
||||
function c:Set(set)
|
||||
@ -878,6 +861,7 @@ function multi:newTStep(start,reset,count,set)
|
||||
self.OnEnd:Fire(self)
|
||||
self.pos=self.start
|
||||
end
|
||||
return true
|
||||
end
|
||||
end
|
||||
function c:Set(set)
|
||||
@ -957,6 +941,14 @@ function multi.getCurrentTask()
|
||||
return __CurrentTask
|
||||
end
|
||||
|
||||
function multi:setCurrentProcess()
|
||||
__CurrentProcess = self
|
||||
end
|
||||
|
||||
function multi:setCurrentTask()
|
||||
__CurrentTask = self
|
||||
end
|
||||
|
||||
function multi:getName()
|
||||
return self.Name
|
||||
end
|
||||
@ -998,7 +990,7 @@ function multi:newProcessor(name, nothread)
|
||||
c.OnError = multi:newConnection()
|
||||
end
|
||||
|
||||
c.OnError(multi.print)
|
||||
c.OnError(multi.error)
|
||||
|
||||
function c:getThreads()
|
||||
return c.threads
|
||||
@ -1379,7 +1371,7 @@ function thread:newThread(name, func, ...)
|
||||
c.isError = false
|
||||
c.OnError = multi:newConnection(true,nil,true)
|
||||
c.OnDeath = multi:newConnection(true,nil,true)
|
||||
c.OnError(multi.print)
|
||||
c.OnError(multi.error)
|
||||
|
||||
function c:getName()
|
||||
return c.Name
|
||||
@ -1450,7 +1442,7 @@ function thread:newThread(name, func, ...)
|
||||
|
||||
globalThreads[c] = multi
|
||||
threadid = threadid + 1
|
||||
self:create(c)
|
||||
multi:getCurrentProcess():create(c)
|
||||
c.creationTime = os.clock()
|
||||
return c
|
||||
end
|
||||
@ -1865,10 +1857,6 @@ local function doOpt()
|
||||
end
|
||||
end
|
||||
|
||||
function multi:setCurrentProcess()
|
||||
__CurrentProcess = self
|
||||
end
|
||||
|
||||
local init = false
|
||||
function multi.init(settings, realsettings)
|
||||
if settings == multi then settings = realsettings end
|
||||
@ -2076,15 +2064,6 @@ else
|
||||
end
|
||||
end
|
||||
|
||||
function multi.randomString(n)
|
||||
local str = ''
|
||||
local strings = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','1','2','3','4','5','6','7','8','9','0','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'}
|
||||
for i=1,n do
|
||||
str = str..''..strings[math.random(1,#strings)]
|
||||
end
|
||||
return str
|
||||
end
|
||||
|
||||
function multi:getChildren()
|
||||
return self.Mainloop
|
||||
end
|
||||
@ -2173,12 +2152,16 @@ function multi:IsAnActor()
|
||||
return self.Act~=nil
|
||||
end
|
||||
|
||||
function multi:reallocate(o, n)
|
||||
n=n or #o.Mainloop+1
|
||||
function multi:reallocate(processor, index)
|
||||
index=index or #processor.Mainloop+1
|
||||
local int=self.Parent
|
||||
self:Destroy()
|
||||
self.Parent=o
|
||||
table.insert(o.Mainloop,n,self)
|
||||
self.Parent=processor
|
||||
print("Moving task to new processor!")
|
||||
if index then
|
||||
table.insert(processor.Mainloop, index, self)
|
||||
else
|
||||
table.insert(processor.Mainloop, self)
|
||||
end
|
||||
self.Active=true
|
||||
return self
|
||||
end
|
||||
@ -2200,18 +2183,28 @@ end
|
||||
|
||||
function multi.print(...)
|
||||
if multi.defaultSettings.print then
|
||||
print("INFO:", table.concat({...}, " "))
|
||||
local t = {}
|
||||
for i,v in pairs({...}) do t[#t+1] = tostring(v) end
|
||||
io.write("\x1b[94mINFO:\x1b[0m " .. table.concat(t," ") .. "\n")
|
||||
end
|
||||
end
|
||||
|
||||
function multi.warn(...)
|
||||
if multi.defaultSettings.warn then
|
||||
print("WARNING:", table.concat({...}, " "))
|
||||
local t = {}
|
||||
for i,v in pairs({...}) do t[#t+1] = tostring(v) end
|
||||
io.write("\x1b[93mWARNING:\x1b[0m " .. table.concat(t," ") .. "\n")
|
||||
end
|
||||
end
|
||||
|
||||
function multi.error(err)
|
||||
error("ERROR: " .. err)
|
||||
function multi.error(self, err)
|
||||
if type(err) == "bool" then crash = err end
|
||||
if type(self) == "string" then err = self end
|
||||
io.write("\x1b[91mERROR:\x1b[0m " .. err .. "\n")
|
||||
error("^^^")
|
||||
if multi.defaultSettings.error then
|
||||
os.exit(1)
|
||||
end
|
||||
end
|
||||
|
||||
multi.GetType = multi.getType
|
||||
|
||||
@ -25,57 +25,193 @@ local mainloop_p = multi.mainloop_p
|
||||
local uManagerRef = multi.uManagerRef
|
||||
local uManagerRefP = multi.uManagerRefP1
|
||||
|
||||
local PROFILE_COUNT = 5
|
||||
|
||||
-- self:setCurrentProcess() a bit slower than using the local var, but there isn't another option
|
||||
|
||||
local priorityManager = multi:newProcessor("Priority Manager", true)
|
||||
priorityManager.newThread = function() multi.warn("You cannot spawn threads on the priority manager!") end
|
||||
|
||||
priorityManager.setPriorityScheme = function() multi.warn("You cannot set priority on the priorityManager!") end
|
||||
|
||||
local function average(t)
|
||||
local sum = 0
|
||||
for _,v in pairs(t) do
|
||||
sum = sum + v
|
||||
end
|
||||
return sum / #t
|
||||
end
|
||||
|
||||
local function getPriority(obj)
|
||||
local avg = average(obj.__profiling)
|
||||
if avg < 0.0002 then
|
||||
multi.print("Setting priority to: core")
|
||||
return PList[1]
|
||||
elseif avg < 0.0004 then
|
||||
multi.print("Setting priority to: very high")
|
||||
return PList[2]
|
||||
elseif avg < 0.0008 then
|
||||
multi.print("Setting priority to: high")
|
||||
return PList[3]
|
||||
elseif avg < 0.001 then
|
||||
multi.print("Setting priority to: above normal")
|
||||
return PList[4]
|
||||
elseif avg < 0.0025 then
|
||||
multi.print("Setting priority to: normal")
|
||||
return PList[5]
|
||||
elseif avg < 0.005 then
|
||||
multi.print("Setting priority to: below normal")
|
||||
return PList[6]
|
||||
elseif avg < 0.008 then
|
||||
multi.print("Setting priority to: low")
|
||||
return PList[7]
|
||||
elseif avg < 0.01 then
|
||||
multi.print("Setting priority to: very low")
|
||||
return PList[8]
|
||||
else
|
||||
multi.print("Setting priority to: idle")
|
||||
return PList[9]
|
||||
end
|
||||
end
|
||||
|
||||
local start, stop
|
||||
|
||||
priorityManager.uManager = function(self)
|
||||
-- proc.run already checks if the processor is active
|
||||
self:setCurrentProcess()
|
||||
local Loop=self.Mainloop
|
||||
local ctask
|
||||
for _D=#Loop,1,-1 do
|
||||
ctask = Loop[_D]
|
||||
ctask:setCurrentTask()
|
||||
start = chronos.nanotime()
|
||||
if ctask:Act() then
|
||||
stop = chronos.nanotime()
|
||||
if ctask.__profiling then
|
||||
table.insert(ctask.__profiling, stop - start)
|
||||
end
|
||||
if ctask.__profiling and #ctask.__profiling == PROFILE_COUNT then
|
||||
ctask:setPriority(getPriority(ctask))
|
||||
ctask:reallocate(ctask.__restoreProc)
|
||||
ctask.__restoreProc = nil
|
||||
ctask.__profiling = nil
|
||||
end
|
||||
end
|
||||
self:setCurrentProcess()
|
||||
end
|
||||
end
|
||||
|
||||
local function processHook(obj, proc)
|
||||
if obj.Type == multi.PROCESS or not(obj.IsAnActor) then return end
|
||||
obj.__restoreProc = proc
|
||||
obj.__profiling = {}
|
||||
obj:reallocate(priorityManager)
|
||||
end
|
||||
|
||||
local function init()
|
||||
local RR, PB, TB = 0, 1, 2
|
||||
local registry = {}
|
||||
|
||||
multi.priorityScheme = {
|
||||
RoundRobin = 0,
|
||||
PriorityBased = 1,
|
||||
TimedBased = 2
|
||||
RoundRobin = "RoundRobin",
|
||||
PriorityBased = "PriorityBased",
|
||||
TimeBased = "TimeBased"
|
||||
}
|
||||
|
||||
function multi:setProfilerCount(count)
|
||||
PROFILE_COUNT = count
|
||||
end
|
||||
|
||||
function multi:recalibrate()
|
||||
if self.__processConn then
|
||||
local items = self.Mainloop
|
||||
for i,v in pairs(items) do
|
||||
processHook(v, self)
|
||||
end
|
||||
else
|
||||
multi.error("Cannot recalibrate the priority if not using Time based mangement!")
|
||||
end
|
||||
end
|
||||
|
||||
function multi:isRegistredScheme(scheme)
|
||||
--
|
||||
end
|
||||
|
||||
function multi:getRegisteredScheme(scheme)
|
||||
--
|
||||
end
|
||||
|
||||
local empty_func = function() return true end
|
||||
function multi:registerScheme(name,options)
|
||||
local mainloop = options.mainloop or multi.error("You must provide a mainloop option when registring a scheme!")
|
||||
local umanager = options.umanager or multi.error("You must provide a umanager option when registring a scheme!")
|
||||
|
||||
if not options.condition then
|
||||
multi.warn("You might want to use condition when registring a scheme! A function that returns true has been auto generated for you!")
|
||||
end
|
||||
|
||||
local condition = options.condition or empty_func
|
||||
|
||||
if registry[name] and not registry[name].static then
|
||||
multi.warn("A scheme named: \"" .. name .. "\" has already been registred, overriting!")
|
||||
else
|
||||
multi.error("A scheme named: \"" .. name .. "\" has already been registred!")
|
||||
end
|
||||
|
||||
registry[name] = {
|
||||
mainloop = mainloop,
|
||||
umanager = umanger,
|
||||
condition = condition,
|
||||
static = options.static or false
|
||||
}
|
||||
return true
|
||||
end
|
||||
|
||||
function multi:setPriorityScheme(scheme)
|
||||
|
||||
if not self.Type == multi.PROCESS or not self.Type == multi.ROOTPROCESS then
|
||||
multi.warn("You should only invoke setPriorityScheme on a processor object!")
|
||||
end
|
||||
if scheme == RR then
|
||||
multi.mainloop = mainloop
|
||||
multi.uManager = uManagerRef
|
||||
elseif scheme == PB then
|
||||
multi.mainloop = mainloop_p
|
||||
multi.uManager = uManagerRefP
|
||||
elseif scheme == TB then
|
||||
--
|
||||
|
||||
if scheme == multi.priorityScheme.RoundRobin then
|
||||
if self.__processConn then self.OnObjectCreated:Unconnect(self.__processConn) self.__processConn = nil end
|
||||
self.mainloop = mainloop
|
||||
self.uManager = uManagerRef
|
||||
elseif scheme == multi.priorityScheme.PriorityBased then
|
||||
if self.__processConn then self.OnObjectCreated:Unconnect(self.__processConn) self.__processConn = nil end
|
||||
self.mainloop = mainloop_p
|
||||
self.uManager = uManagerRefP
|
||||
elseif scheme == multi.priorityScheme.TimeBased then
|
||||
if not chronos then return multi.warn("Unable to use TimeBased Priority without the chronos library!") end
|
||||
if self.__processConn then multi.warn("Already enabled TimeBased Priority!") end
|
||||
self.__processConn = self.OnObjectCreated(processHook)
|
||||
self.mainloop = mainloop_p
|
||||
self.uManager = uManagerRefP
|
||||
elseif self:isRegistredScheme(scheme) then
|
||||
local mainloop, umanager, condition = self:getRegisteredScheme(scheme)
|
||||
if condition() then
|
||||
self.mainloop = mainloop
|
||||
self.uManager = umanager
|
||||
end
|
||||
else
|
||||
multi.error("Invalid priority scheme passed!")
|
||||
self.error("Invalid priority scheme selected!")
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
local function init_chronos()
|
||||
multi:newThread("Priority Manager", function()
|
||||
thread:newThread("System Priority Manager", function()
|
||||
while true do
|
||||
thread.yield()
|
||||
priorityManager.run()
|
||||
end
|
||||
end)
|
||||
end).OnError(multi.error)
|
||||
end
|
||||
|
||||
if chronos then
|
||||
init_chronos()
|
||||
else
|
||||
multi.print("In order to have time based priority management, you need to install the chronos library!")
|
||||
multi.warn("In order to have time based priority management, you need to install the chronos library!")
|
||||
end
|
||||
|
||||
init()
|
||||
|
||||
--chronos.nanotime()
|
||||
init()
|
||||
150
tests/test.lua
150
tests/test.lua
@ -1,5 +1,151 @@
|
||||
package.path = "../?/init.lua;../?.lua;"..package.path
|
||||
multi, thread = require("multi"):init{print=true,findopt=true}
|
||||
multi, thread = require("multi"):init{print=true,warn=true,error=true}
|
||||
require("multi.integration.priorityManager")
|
||||
|
||||
multi:mainloop()
|
||||
test = multi:newProcessor("Test")
|
||||
test:setPriorityScheme(multi.priorityScheme.TimeBased)
|
||||
multi.OnObjectCreated(function(proc, obj)
|
||||
print("MULTI",proc.Type,obj.Type)
|
||||
end)
|
||||
local a = 0
|
||||
test:newUpdater(100000):OnUpdate(function()
|
||||
print("Print is slowish")
|
||||
end)
|
||||
|
||||
print("Running...")
|
||||
|
||||
multi:mainloop()
|
||||
|
||||
|
||||
-- local conn1, conn2, conn3 = multi:newConnection(nil,nil,true), multi:newConnection(), multi:newConnection()
|
||||
|
||||
-- local link = conn1(function()
|
||||
-- print("Conn1, first")
|
||||
-- end)
|
||||
|
||||
-- local link2 = conn1(function()
|
||||
-- print("Conn1, second")
|
||||
-- end)
|
||||
|
||||
-- local link3 = conn1(function()
|
||||
-- print("Conn1, third")
|
||||
-- end)
|
||||
|
||||
-- local link4 = conn2(function()
|
||||
-- print("Conn2, first")
|
||||
-- end)
|
||||
|
||||
-- local link5 = conn2(function()
|
||||
-- print("Conn2, second")
|
||||
-- end)
|
||||
|
||||
-- local link6 = conn2(function()
|
||||
-- print("Conn2, third")
|
||||
-- end)
|
||||
|
||||
-- print("Links 1-6",link,link2,link3,link4,link5,link6)
|
||||
-- conn1:Lock(link)
|
||||
-- print("All conns\n-------------")
|
||||
-- conn1:Fire()
|
||||
-- conn2:Fire()
|
||||
|
||||
-- conn1:Unlock(link)
|
||||
|
||||
-- conn1:Unconnect(link3)
|
||||
-- conn2:Unconnect(link6)
|
||||
-- print("All conns Edit\n---------------------")
|
||||
-- conn1:Fire()
|
||||
-- conn2:Fire()
|
||||
|
||||
-- thread:newThread(function()
|
||||
-- print("Awaiting status")
|
||||
-- thread.hold(conn1 + (conn2 * conn3))
|
||||
-- print("Conn or Conn2 and Conn3")
|
||||
-- end)
|
||||
|
||||
-- multi:newAlarm(1):OnRing(function()
|
||||
-- print("Conn")
|
||||
-- conn1:Fire()
|
||||
-- end)
|
||||
-- multi:newAlarm(2):OnRing(function()
|
||||
-- print("Conn2")
|
||||
-- conn2:Fire()
|
||||
-- end)
|
||||
-- multi:newAlarm(3):OnRing(function()
|
||||
-- print("Conn3")
|
||||
-- conn3:Fire()
|
||||
-- os.exit()
|
||||
-- end)
|
||||
|
||||
|
||||
-- local conn = multi:newSystemThreadedConnection("conn"):init()
|
||||
|
||||
-- multi:newSystemThread("Thread_Test_1", function()
|
||||
-- local multi, thread = require("multi"):init()
|
||||
-- local conn = GLOBAL["conn"]:init()
|
||||
-- local console = THREAD.getConsole()
|
||||
-- conn(function(a,b,c)
|
||||
-- console.print(THREAD:getName().." was triggered!",a,b,c)
|
||||
-- end)
|
||||
-- multi:mainloop()
|
||||
-- end)
|
||||
|
||||
-- multi:newSystemThread("Thread_Test_2", function()
|
||||
-- local multi, thread = require("multi"):init()
|
||||
-- local conn = GLOBAL["conn"]:init()
|
||||
-- local console = THREAD.getConsole()
|
||||
-- conn(function(a,b,c)
|
||||
-- console.print(THREAD:getName().." was triggered!",a,b,c)
|
||||
-- end)
|
||||
-- multi:newAlarm(2):OnRing(function()
|
||||
-- console.print("Fire 2!!!")
|
||||
-- conn:Fire(4,5,6)
|
||||
-- THREAD.kill()
|
||||
-- end)
|
||||
|
||||
-- multi:mainloop()
|
||||
-- end)
|
||||
-- local console = THREAD.getConsole()
|
||||
-- conn(function(a,b,c)
|
||||
-- console.print("Mainloop conn got triggered!",a,b,c)
|
||||
-- end)
|
||||
|
||||
-- alarm = multi:newAlarm(1)
|
||||
-- alarm:OnRing(function()
|
||||
-- console.print("Fire 1!!!")
|
||||
-- conn:Fire(1,2,3)
|
||||
-- end)
|
||||
|
||||
-- alarm = multi:newAlarm(3):OnRing(function()
|
||||
-- multi:newSystemThread("Thread_Test_3",function()
|
||||
-- local multi, thread = require("multi"):init()
|
||||
-- local conn = GLOBAL["conn"]:init()
|
||||
-- local console = THREAD.getConsole()
|
||||
-- conn(function(a,b,c)
|
||||
-- console.print(THREAD:getName().." was triggered!",a,b,c)
|
||||
-- end)
|
||||
-- multi:newAlarm(4):OnRing(function()
|
||||
-- console.print("Fire 3!!!")
|
||||
-- conn:Fire(7,8,9)
|
||||
-- end)
|
||||
-- multi:mainloop()
|
||||
-- end)
|
||||
-- end)
|
||||
|
||||
-- multi:newSystemThread("Thread_Test_4",function()
|
||||
-- local multi, thread = require("multi"):init()
|
||||
-- local conn = GLOBAL["conn"]:init()
|
||||
-- local conn2 = multi:newConnection()
|
||||
-- local console = THREAD.getConsole()
|
||||
-- multi:newAlarm(2):OnRing(function()
|
||||
-- conn2:Fire()
|
||||
-- end)
|
||||
-- multi:newThread(function()
|
||||
-- console.print("Conn Test!")
|
||||
-- thread.hold(conn + conn2)
|
||||
-- console.print("It held!")
|
||||
-- end)
|
||||
-- multi:mainloop()
|
||||
-- end)
|
||||
|
||||
-- multi:mainloop()
|
||||
Loading…
x
Reference in New Issue
Block a user