mirror of
https://github.com/rayaman/multi.git
synced 2026-09-05 07:27:35 -04:00
Compare commits
19
Commits
action_update
...
v16.3.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8b5d10cbb6 | ||
|
|
0796788fcb | ||
|
|
ee5e3bde7f | ||
|
|
c86413351c | ||
|
|
4a52cd5e14 | ||
|
|
14beeb686a | ||
|
|
60783fdb16 | ||
|
|
b1a7e61c03 | ||
|
|
9fa0e7c2cb | ||
|
|
ef243f87d4 | ||
|
|
178283e0b4 | ||
|
|
7f35265a8e | ||
|
|
0501f068e4 | ||
|
|
ffd7ac15f6 | ||
|
|
869368af56 | ||
|
|
eeb75490dc | ||
|
|
2fec5b39b8 | ||
|
|
0a92890290 | ||
|
|
40de9a8d22 |
@@ -1,25 +0,0 @@
|
|||||||
name: Build & Run tests Love2d
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ master ]
|
|
||||||
pull_request:
|
|
||||||
branches: [ master ]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
runs-on: "ubuntu-latest"
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
submodules: recursive
|
|
||||||
- name: Install love2d
|
|
||||||
run: |
|
|
||||||
sudo apt install fuse
|
|
||||||
wget https://github.com/love2d/love/releases/download/11.4/love-11.4-x86_64.AppImage -O love.AppImage
|
|
||||||
sudo chmod +x love.AppImage
|
|
||||||
- name: Run Tests
|
|
||||||
run: |
|
|
||||||
./love.AppImage tests
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
name: Build & Run tests Ubuntu
|
name: Lua Unit Tests (Matrix)
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
@@ -7,35 +7,26 @@ on:
|
|||||||
branches: [ master ]
|
branches: [ master ]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
matrix:
|
||||||
build-type: [Release] # Debug
|
luaVersion: ["5.1", "5.2", "5.3", "5.4"]
|
||||||
lua: ["lua 5.1", "lua 5.2", "lua 5.3", "lua 5.4", "luajit 2.1.0-beta3"]
|
|
||||||
os: ["ubuntu-latest"]
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Lua
|
||||||
|
uses: leafo/gh-actions-lua@v10
|
||||||
with:
|
with:
|
||||||
submodules: recursive
|
luaVersion: ${{ matrix.luaVersion }}
|
||||||
|
|
||||||
- uses: actions/setup-python@v2
|
- name: Verify Lua version
|
||||||
with:
|
run: lua -v
|
||||||
python-version: '3.10'
|
|
||||||
|
|
||||||
- name: Setup env
|
- name: Run unit tests
|
||||||
run: |
|
run: |
|
||||||
pip install hererocks
|
# Replace with your actual test file
|
||||||
hererocks lua-pkg --${{ matrix.lua }} -rlatest
|
lua tests/multi_test.lua
|
||||||
|
|
||||||
- name: Install lanes and multi
|
|
||||||
run: |
|
|
||||||
source ${{github.workspace}}/lua-pkg/bin/activate
|
|
||||||
luarocks install lanes
|
|
||||||
luarocks install rockspecs/multi-16.0-0.rockspec
|
|
||||||
|
|
||||||
- name: Run Tests
|
|
||||||
run: |
|
|
||||||
source ${{github.workspace}}/lua-pkg/bin/activate
|
|
||||||
lua tests/runtests.lua
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
# Multi Version: 16.1.0 - The Flow State
|
# Multi Version: 16.3.0 -
|
||||||
**Key Changes**
|
**Key Changes**
|
||||||
- Updated Processors to have more controlled over scheduled processes
|
- Fixed connection multiplying
|
||||||
- Forwarding connections
|
- Optimizing the library
|
||||||
- New Timeout handling
|
- Updated task management support
|
||||||
|
|
||||||
Refer to the [Change Log](https://github.com/rayaman/multi/blob/master/docs/changes.md) for more infromation
|
Refer to the [Change Log](https://github.com/rayaman/multi/blob/master/docs/changes.md) for more infromation
|
||||||
|
|
||||||
@@ -12,7 +12,7 @@ My multitasking library for lua. It is a pure lua binding, with exceptions of th
|
|||||||
|
|
||||||
</br>
|
</br>
|
||||||
|
|
||||||
Progress is being made in [v16.2.0](https://github.com/rayaman/multi/tree/v16.2.0)
|
Progress is being made in [v16.3.0](https://github.com/rayaman/multi/tree/v16.3.0)
|
||||||
---
|
---
|
||||||
|
|
||||||
</br>
|
</br>
|
||||||
|
|||||||
+28
-5
@@ -1,7 +1,8 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
Table of contents
|
Table of contents
|
||||||
---
|
---
|
||||||
[Update 16.2.0 - TimeStamps and UUIDs](#update-1620---timestamps-and-uuids-and-bugfixes)</br>
|
[Update 16.3.0 - Proper Priorities](#update-1620---proper-priorities)</br>
|
||||||
|
[Update 16.2.0 - TimeStamps and UUIDs](#update-1620---timestamps-and-uuids)</br>
|
||||||
[Update 16.1.0 - The Flow State](#update-1610---the-flow-state)</br>
|
[Update 16.1.0 - The Flow State](#update-1610---the-flow-state)</br>
|
||||||
[Update 16.0.1 - Bug fix](#update-1601---bug-fix)</br>
|
[Update 16.0.1 - Bug fix](#update-1601---bug-fix)</br>
|
||||||
[Update 16.0.0 - Connecting the dots](#update-1600---getting-the-priorities-straight)</br>
|
[Update 16.0.0 - Connecting the dots](#update-1600---getting-the-priorities-straight)</br>
|
||||||
@@ -61,6 +62,30 @@ Table of contents
|
|||||||
[Update: EventManager 1.0.0 - Error checking](#update-eventmanager-100---error-checking)</br>
|
[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)
|
[Version: EventManager 0.0.1 - In The Beginning things were very different](#version-eventmanager-001---in-the-beginning-things-were-very-different)
|
||||||
|
|
||||||
|
# Update 16.3.0 - Proper Priorities
|
||||||
|
|
||||||
|
Added
|
||||||
|
---
|
||||||
|
- New processor scoped to track connections that exist
|
||||||
|
- Better Destroy logic for connections
|
||||||
|
- Added UPTIME to all objects in the library via the create hook
|
||||||
|
- added `proc:isPaused()` to processors
|
||||||
|
- `multi.setClock(c)` allows you to set the internal clock used by the multi core. For example on linux os.clock doesn't give time elapsed since the program started like it does on windows. This method allows one to swap that out.
|
||||||
|
|
||||||
|
Changed
|
||||||
|
---
|
||||||
|
- `thread.kill(msg)` now accepts a message. If omitted will use default `thread killed!`
|
||||||
|
- Modified multiple locations to not create a function during a thread.hold() and reuse. Only functions containing an upvalue currently have functions being created during hold. This will eventually be fixed
|
||||||
|
- Updated `multi:getStats()` with more information
|
||||||
|
- `multi.forwardConnection()` now returns the link to the source connection so you can do cleanup
|
||||||
|
- When connecting to a connection you can unconnect using ref:Unconnect() it has an internal reference to the root connection
|
||||||
|
- Unnamed threads have a shorter postfix of only 4 random characters
|
||||||
|
|
||||||
|
Fixed
|
||||||
|
---
|
||||||
|
- [Issue](https://github.com/rayaman/multi/issues/77) with concat of connections where conn .. func did not work properly
|
||||||
|
- [Issue](https://github.com/rayaman/multi/issues/67) with connection multiplying
|
||||||
|
|
||||||
# Update 16.2.0 - TimeStamps and UUIDs and bugfixes
|
# Update 16.2.0 - TimeStamps and UUIDs and bugfixes
|
||||||
Added
|
Added
|
||||||
---
|
---
|
||||||
@@ -629,15 +654,13 @@ Added
|
|||||||
|
|
||||||
Output:
|
Output:
|
||||||
```
|
```
|
||||||
I run before all and control if execution should continue!
|
I run before all and control if things go!
|
||||||
Hi 3
|
Hi 3
|
||||||
Hi 1
|
Hi 1
|
||||||
I run before all and control if execution should continue!
|
|
||||||
Hi 3
|
|
||||||
Hi 2
|
|
||||||
Test 1
|
Test 1
|
||||||
Test 2
|
Test 2
|
||||||
Test 3
|
Test 3
|
||||||
|
I run after it all!
|
||||||
```
|
```
|
||||||
|
|
||||||
**Note:** Concat of connections does modify internal events on both connections depending on the direction func .. conn or conn .. func See implemention below:
|
**Note:** Concat of connections does modify internal events on both connections depending on the direction func .. conn or conn .. func See implemention below:
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -92,7 +92,7 @@ function multi.getTypes()
|
|||||||
return types
|
return types
|
||||||
end
|
end
|
||||||
|
|
||||||
multi.Version = "16.2.0"
|
multi.Version = "16.3.0-testing"
|
||||||
multi.Name = "root"
|
multi.Name = "root"
|
||||||
multi.NIL = {Type="NIL"}
|
multi.NIL = {Type="NIL"}
|
||||||
local NIL = multi.NIL
|
local NIL = multi.NIL
|
||||||
@@ -154,11 +154,18 @@ function multi:isType(type)
|
|||||||
return self.Type == type
|
return self.Type == type
|
||||||
end
|
end
|
||||||
|
|
||||||
|
multi.connection_count = 0
|
||||||
|
multi.connection_subscriptions = 0
|
||||||
|
|
||||||
function multi:getStats()
|
function multi:getStats()
|
||||||
local stats = {
|
local stats = {
|
||||||
[multi.Name] = {
|
[multi.Name] = {
|
||||||
threads = multi:getThreads(),
|
threads = multi:getThreads(),
|
||||||
tasks = multi:getTasks()
|
tasks = multi.Mainloop,
|
||||||
|
name = "root",
|
||||||
|
fullName = "root",
|
||||||
|
connections = self.connection_count,
|
||||||
|
subscriptions = self.connection_subscriptions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
local procs = multi:getProcessors()
|
local procs = multi:getProcessors()
|
||||||
@@ -166,7 +173,11 @@ function multi:getStats()
|
|||||||
local proc = procs[i]
|
local proc = procs[i]
|
||||||
stats[proc:getFullName()] = {
|
stats[proc:getFullName()] = {
|
||||||
threads = proc:getThreads(),
|
threads = proc:getThreads(),
|
||||||
tasks = proc:getTasks()
|
tasks = proc.Mainloop,
|
||||||
|
name = proc:getName(),
|
||||||
|
fullName = proc:getFullName(),
|
||||||
|
connections = proc.connection_count,
|
||||||
|
subscriptions = proc.connection_subscriptions
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
return stats
|
return stats
|
||||||
@@ -202,7 +213,7 @@ end
|
|||||||
|
|
||||||
function multi.forwardConnection(src, dest)
|
function multi.forwardConnection(src, dest)
|
||||||
if multi.isMulitObj(src) and multi.isMulitObj(dest) then
|
if multi.isMulitObj(src) and multi.isMulitObj(dest) then
|
||||||
src(function(...)
|
return src(function(...)
|
||||||
dest:Fire(...)
|
dest:Fire(...)
|
||||||
end)
|
end)
|
||||||
else
|
else
|
||||||
@@ -215,23 +226,32 @@ local ignoreconn = true
|
|||||||
local empty_func = function() end
|
local empty_func = function() end
|
||||||
|
|
||||||
function multi:newConnection(protect,func,kill)
|
function multi:newConnection(protect,func,kill)
|
||||||
|
self.connection_count = self.connection_count + 1
|
||||||
local processor = self
|
local processor = self
|
||||||
local c={}
|
local c = {}
|
||||||
local lock = false
|
local lock = false
|
||||||
local fast = {}
|
local fast = {}
|
||||||
c.__connectionAdded = function() end
|
c.__connectionAdded = function() end
|
||||||
c.rawadd = false
|
c.rawadd = false
|
||||||
c.Parent = self
|
c.Parent = self
|
||||||
|
c._child_conns = {} -- tracks connections spawned by operators
|
||||||
|
c.destroyed = false
|
||||||
|
|
||||||
setmetatable(c,{
|
-- Helper: register a child connection for cleanup
|
||||||
__call=function(self,...)
|
local function trackChild(cn)
|
||||||
|
c._child_conns[#c._child_conns + 1] = cn
|
||||||
|
return cn
|
||||||
|
end
|
||||||
|
|
||||||
|
setmetatable(c, {
|
||||||
|
__call = function(self, ...)
|
||||||
local t = ...
|
local t = ...
|
||||||
if type(t)=="table" then
|
if type(t) == "table" then
|
||||||
for i,v in pairs(t) do
|
for i, v in pairs(t) do
|
||||||
if v==self then
|
if v == self then
|
||||||
local ref = self:Connect(select(2,...))
|
local ref = self:Connect(select(2, ...))
|
||||||
if ref then
|
if ref then
|
||||||
ref.root_link = select(1,...)
|
ref.root_link = select(1, ...)
|
||||||
return ref
|
return ref
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
@@ -242,7 +262,8 @@ function multi:newConnection(protect,func,kill)
|
|||||||
return self:Connect(...)
|
return self:Connect(...)
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
__unm = function(obj) -- -obj Reverses the order of connected events
|
|
||||||
|
__unm = function(obj)
|
||||||
local conns = obj:Bind({})
|
local conns = obj:Bind({})
|
||||||
for i = #conns, 1, -1 do
|
for i = #conns, 1, -1 do
|
||||||
obj.rawadd = true
|
obj.rawadd = true
|
||||||
@@ -251,15 +272,16 @@ function multi:newConnection(protect,func,kill)
|
|||||||
end
|
end
|
||||||
return obj
|
return obj
|
||||||
end,
|
end,
|
||||||
__mod = function(obj1, obj2) -- %
|
|
||||||
local cn = self:newConnection()
|
__mod = function(obj1, obj2)
|
||||||
if type(obj1) == "function" and type(obj2) == "table" then
|
local cn = trackChild(self:newConnection())
|
||||||
|
if (type(obj1) == "function" or type(obj1) == "table" and obj1.Type == multi.registerType("function", "functions")) and type(obj2) == "table" then
|
||||||
obj2(function(...)
|
obj2(function(...)
|
||||||
cn:Fire(obj1(...))
|
cn:Fire(obj1(...))
|
||||||
end)
|
end)
|
||||||
elseif type(obj1) == "table" and type(obj2) == "function" then
|
elseif type(obj1) == "table" and (type(obj2) == "function" or type(obj2) == "table" and obj2.Type == multi.registerType("function", "functions")) then
|
||||||
local conns = obj1:Bind({})
|
local conns = obj1:Bind({})
|
||||||
for i = 1,#conns do
|
for i = 1, #conns do
|
||||||
obj1(function(...)
|
obj1(function(...)
|
||||||
conns[i](obj2(...))
|
conns[i](obj2(...))
|
||||||
end)
|
end)
|
||||||
@@ -274,31 +296,33 @@ function multi:newConnection(protect,func,kill)
|
|||||||
end
|
end
|
||||||
return obj1
|
return obj1
|
||||||
else
|
else
|
||||||
error("Invalid mod!", type(obj1), type(obj2),"Expected function, connection(table)")
|
multi.error("Invalid mod!", type(obj1), type(obj2), "Expected function, connection(table)")
|
||||||
end
|
end
|
||||||
return cn
|
return cn
|
||||||
end,
|
end,
|
||||||
__div = function(obj1, obj2) -- /
|
|
||||||
local cn = self:newConnection()
|
__div = function(obj1, obj2)
|
||||||
local ref
|
local cn = trackChild(self:newConnection())
|
||||||
if type(obj1) == "function" and type(obj2) == "table" then
|
if type(obj1) == "function" and type(obj2) == "table" then
|
||||||
obj2(function(...)
|
obj2(function(...)
|
||||||
local args = {obj1(...)}
|
local args = { obj1(...) }
|
||||||
if args[1] then
|
if args[1] then
|
||||||
|
table.remove(args, 1)
|
||||||
cn:Fire(multi.unpack(args))
|
cn:Fire(multi.unpack(args))
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
else
|
else
|
||||||
multi.error("Invalid divide!", type(obj1), type(obj2),"Expected function/connection(table)")
|
multi.error("Invalid divide!", type(obj1), type(obj2), "Expected function/connection(table)")
|
||||||
end
|
end
|
||||||
return cn
|
return cn
|
||||||
end,
|
end,
|
||||||
__concat = function(obj1, obj2) -- ..
|
|
||||||
local cn = self:newConnection()
|
__concat = function(obj1, obj2)
|
||||||
|
local cn = trackChild(self:newConnection())
|
||||||
local ref
|
local ref
|
||||||
if type(obj1) == "function" and type(obj2) == "table" then
|
if type(obj1) == "function" and type(obj2) == "table" then
|
||||||
cn(function(...)
|
cn(function(...)
|
||||||
if obj1(...) then
|
if obj1(...) == true then
|
||||||
obj2:Fire(...)
|
obj2:Fire(...)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
@@ -320,26 +344,24 @@ function multi:newConnection(protect,func,kill)
|
|||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
return obj1
|
return cn
|
||||||
elseif type(obj1) == "table" and type(obj2) == "table" then
|
elseif type(obj1) == "table" and type(obj2) == "table" then
|
||||||
--
|
-- reserved
|
||||||
else
|
else
|
||||||
error("Invalid concat!", type(obj1), type(obj2),"Expected function/connection(table), connection(table)/function")
|
error("Invalid concat!", type(obj1), type(obj2), "Expected function/connection(table), connection(table)/function")
|
||||||
end
|
end
|
||||||
return cn
|
return cn
|
||||||
end,
|
end,
|
||||||
__add = function(c1,c2) -- Or
|
|
||||||
local cn = self:newConnection()
|
__add = function(c1, c2) -- Or
|
||||||
c1(function(...)
|
local cn = trackChild(self:newConnection())
|
||||||
cn:Fire(...)
|
c1(function(...) cn:Fire(...) end)
|
||||||
end)
|
c2(function(...) cn:Fire(...) end)
|
||||||
c2(function(...)
|
|
||||||
cn:Fire(...)
|
|
||||||
end)
|
|
||||||
return cn
|
return cn
|
||||||
end,
|
end,
|
||||||
__mul = function(c1,c2) -- And
|
|
||||||
local cn = self:newConnection()
|
__mul = function(c1, c2) -- And
|
||||||
|
local cn = trackChild(self:newConnection())
|
||||||
local ref1, ref2
|
local ref1, ref2
|
||||||
if c1.__hasInstances == nil then
|
if c1.__hasInstances == nil then
|
||||||
cn.__hasInstances = {2}
|
cn.__hasInstances = {2}
|
||||||
@@ -367,12 +389,80 @@ function multi:newConnection(protect,func,kill)
|
|||||||
if cn.__count[1] == cn.__hasInstances[1] then
|
if cn.__count[1] == cn.__hasInstances[1] then
|
||||||
cn:Fire(...)
|
cn:Fire(...)
|
||||||
cn.__count[1] = 0
|
cn.__count[1] = 0
|
||||||
c1:Unlock(ref1)
|
|
||||||
c2:Unlock(ref2)
|
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
return cn
|
return cn
|
||||||
end})
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
-- ... (Type, ID, FC setup, Lock/Unlock, Fire, Connect, Bind, etc. unchanged) ...
|
||||||
|
|
||||||
|
--- Destroy this connection and all resources it owns.
|
||||||
|
-- Recursively destroys any connections created by operator overloads (+, *, %, /, ..).
|
||||||
|
-- Safe to call multiple times.
|
||||||
|
function c:Destroy()
|
||||||
|
if self.destroyed then return end
|
||||||
|
self.destroyed = true
|
||||||
|
|
||||||
|
-- Unlock first so any in-progress Fire() calls drain cleanly
|
||||||
|
lock = false
|
||||||
|
|
||||||
|
-- Destroy operator-spawned child connections recursively
|
||||||
|
for i = 1, #self._child_conns do
|
||||||
|
local child = self._child_conns[i]
|
||||||
|
if child and type(child.Destroy) == "function" and not child.destroyed then
|
||||||
|
child:Destroy()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self._child_conns = {}
|
||||||
|
|
||||||
|
-- Null out root_link back-references on all connection handles
|
||||||
|
for key, _ in pairs(fast) do
|
||||||
|
if type(key) == "string" then
|
||||||
|
local handle = fast[key]
|
||||||
|
if type(handle) == "table" and rawget(handle, "root_link") then
|
||||||
|
handle.root_link = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Adjust subscription count on parent before wiping fast[]
|
||||||
|
if self.Parent and self.Parent.connection_subscriptions then
|
||||||
|
self.Parent.connection_subscriptions =
|
||||||
|
math.max(0, self.Parent.connection_subscriptions - #fast)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Clear all stored callbacks
|
||||||
|
fast = {}
|
||||||
|
|
||||||
|
-- Remove from parent's object list
|
||||||
|
if self.Parent then
|
||||||
|
for i = 1, #self.Parent do
|
||||||
|
if self.Parent[i] == self then
|
||||||
|
table.remove(self.Parent, i)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Detach hooks so stale references can't re-fire into dead state
|
||||||
|
self.__connectionAdded = function() end
|
||||||
|
self.Connect = function() multi:warning("Connect called on destroyed connection") end
|
||||||
|
self.Fire = function() end
|
||||||
|
self.Bind = function() return {} end
|
||||||
|
self.Unconnect = function() end
|
||||||
|
self.Lock = function() return self end
|
||||||
|
self.Unlock = function() return self end
|
||||||
|
|
||||||
|
if self.Parent and self.Parent.connection_count then
|
||||||
|
self.Parent.connection_count = math.max(0, self.Parent.connection_count - 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
self.Parent = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Alias
|
||||||
|
c.destroy = c.Destroy
|
||||||
|
|
||||||
c.Type=multi.registerType("connector", "connections")
|
c.Type=multi.registerType("connector", "connections")
|
||||||
c.func={}
|
c.func={}
|
||||||
@@ -402,7 +492,8 @@ function multi:newConnection(protect,func,kill)
|
|||||||
|
|
||||||
function c:Unlock(conn)
|
function c:Unlock(conn)
|
||||||
if conn and conn.lock then
|
if conn and conn.lock then
|
||||||
for i = 1, #fast do
|
local n = #fast
|
||||||
|
for i = 1, n do
|
||||||
if conn.lock == fast[i] then
|
if conn.lock == fast[i] then
|
||||||
fast[i] = fast[conn.ref]
|
fast[i] = fast[conn.ref]
|
||||||
return self
|
return self
|
||||||
@@ -418,12 +509,13 @@ function multi:newConnection(protect,func,kill)
|
|||||||
function c:Fire(...)
|
function c:Fire(...)
|
||||||
if lock then return end
|
if lock then return end
|
||||||
local kills = {}
|
local kills = {}
|
||||||
for i=1,#fast do
|
local n = #fast
|
||||||
|
for i=1, n do
|
||||||
local suc, err = pcall(fast[i], ...)
|
local suc, err = pcall(fast[i], ...)
|
||||||
if not suc then
|
if not suc then
|
||||||
multi.error(err)
|
multi.error(err)
|
||||||
end
|
end
|
||||||
if kill then
|
if kill and n > 0 then
|
||||||
table.insert(kills,i)
|
table.insert(kills,i)
|
||||||
processor:newTask(function()
|
processor:newTask(function()
|
||||||
for _, k in pairs(kills) do
|
for _, k in pairs(kills) do
|
||||||
@@ -448,6 +540,7 @@ function multi:newConnection(protect,func,kill)
|
|||||||
for i = 1, #fast do
|
for i = 1, #fast do
|
||||||
if fast[conn.ref] == fast[i] then
|
if fast[conn.ref] == fast[i] then
|
||||||
table.remove(self)
|
table.remove(self)
|
||||||
|
self.Parent.connection_subscriptions = self.Parent.connection_subscriptions - 1
|
||||||
return table.remove(fast, i), i
|
return table.remove(fast, i), i
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -476,12 +569,18 @@ function multi:newConnection(protect,func,kill)
|
|||||||
function c:Fire(...)
|
function c:Fire(...)
|
||||||
if lock then return end
|
if lock then return end
|
||||||
for i=1,#fast do
|
for i=1,#fast do
|
||||||
|
if fast[i] then
|
||||||
fast[i](...)
|
fast[i](...)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function c:Connect(func, name)
|
function c:Connect(func, name)
|
||||||
|
if func == nil then
|
||||||
|
multi.error("You must provide a valid function when calling a connection")
|
||||||
|
end
|
||||||
|
self.Parent.connection_subscriptions = self.Parent.connection_subscriptions + 1
|
||||||
local th
|
local th
|
||||||
if thread.getRunningThread then
|
if thread.getRunningThread then
|
||||||
th = thread.getRunningThread()
|
th = thread.getRunningThread()
|
||||||
@@ -494,11 +593,12 @@ function multi:newConnection(protect,func,kill)
|
|||||||
__CurrentConnectionThread = nil
|
__CurrentConnectionThread = nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
local ref = multi.randomString(24)
|
||||||
table.insert(fast, func)
|
table.insert(fast, func)
|
||||||
if name then
|
if name then
|
||||||
fast[name] = func
|
fast[name] = func
|
||||||
else
|
else
|
||||||
fast["Conn_"..multi.randomString(12)] = func
|
fast["Conn_"..ref:sub(1, 12)] = func
|
||||||
end
|
end
|
||||||
local temp = {fast = true}
|
local temp = {fast = true}
|
||||||
setmetatable(temp,{
|
setmetatable(temp,{
|
||||||
@@ -518,9 +618,13 @@ function multi:newConnection(protect,func,kill)
|
|||||||
rawset(t,k,v)
|
rawset(t,k,v)
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
temp.ref = multi.randomString(24)
|
temp.ref = ref
|
||||||
fast[temp.ref] = func
|
fast[temp.ref] = func
|
||||||
temp.name = name
|
temp.name = name
|
||||||
|
temp.link = self
|
||||||
|
function temp:Unconnect()
|
||||||
|
self.link:Unconnect(self)
|
||||||
|
end
|
||||||
if self.rawadd then
|
if self.rawadd then
|
||||||
self.rawadd = false
|
self.rawadd = false
|
||||||
else
|
else
|
||||||
@@ -532,7 +636,9 @@ function multi:newConnection(protect,func,kill)
|
|||||||
|
|
||||||
function c:Bind(t)
|
function c:Bind(t)
|
||||||
local temp = fast
|
local temp = fast
|
||||||
|
self.Parent.connection_subscriptions = self.Parent.connection_subscriptions - #fast
|
||||||
fast=t
|
fast=t
|
||||||
|
self.Parent.connection_subscriptions = self.Parent.connection_subscriptions + #t
|
||||||
return temp
|
return temp
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -542,6 +648,7 @@ function multi:newConnection(protect,func,kill)
|
|||||||
|
|
||||||
function c:Remove()
|
function c:Remove()
|
||||||
local temp = fast
|
local temp = fast
|
||||||
|
self.Parent.connection_subscriptions = self.Parent.connection_subscriptions - #fast
|
||||||
fast={}
|
fast={}
|
||||||
return temp
|
return temp
|
||||||
end
|
end
|
||||||
@@ -610,10 +717,10 @@ function multi:SetTime(n)
|
|||||||
c.OnTimedOut = self:newConnection()
|
c.OnTimedOut = self:newConnection()
|
||||||
c.OnTimerResolved = self:newConnection()
|
c.OnTimerResolved = self:newConnection()
|
||||||
self._timer=c.timer
|
self._timer=c.timer
|
||||||
function c:Act()
|
function c:Act(dt)
|
||||||
if self.timer:Get()>=self.set then
|
if self.timer:Get()>=self.set then
|
||||||
self.link:Pause()
|
self.link:Pause()
|
||||||
self.OnTimedOut:Fire(self.link)
|
self.OnTimedOut:Fire(self.link,dt)
|
||||||
self:Destroy()
|
self:Destroy()
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
@@ -698,17 +805,12 @@ function multi:isDone()
|
|||||||
return self.Active~=true
|
return self.Active~=true
|
||||||
end
|
end
|
||||||
|
|
||||||
local time = os.time
|
|
||||||
local ok, chronos = pcall(require, "chronos") -- hpc
|
|
||||||
|
|
||||||
if ok then
|
|
||||||
math.randomseed(chronos.nanotime()*100000000)
|
|
||||||
else
|
|
||||||
math.randomseed(time())
|
|
||||||
end
|
|
||||||
|
|
||||||
function multi:create(ref)
|
function multi:create(ref)
|
||||||
ref.UID = multi.generate_uuid7()
|
ref.UID = multi.generate_uuid7()
|
||||||
|
ref.UPTIME = clock()
|
||||||
|
if ref.setPriority then
|
||||||
|
ref:setPriority("normal")
|
||||||
|
end
|
||||||
self.OnObjectCreated:Fire(ref, self)
|
self.OnObjectCreated:Fire(ref, self)
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -813,12 +915,12 @@ end
|
|||||||
function multi:newEvent(task, func)
|
function multi:newEvent(task, func)
|
||||||
local c,err=self:newBase(multi.registerType("event", "events"))
|
local c,err=self:newBase(multi.registerType("event", "events"))
|
||||||
local task = task or function() end
|
local task = task or function() end
|
||||||
function c:Act()
|
function c:Act(dt)
|
||||||
local t = task(self)
|
local t = task(self)
|
||||||
if t then
|
if t then
|
||||||
self:Pause()
|
self:Pause()
|
||||||
self.returns = t
|
self.returns = t
|
||||||
self.OnEvent:Fire(self)
|
self.OnEvent:Fire(self,dt)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -840,10 +942,10 @@ function multi:newUpdater(skip, func)
|
|||||||
local c,err=self:newBase(multi.registerType("updater", "updaters"))
|
local c,err=self:newBase(multi.registerType("updater", "updaters"))
|
||||||
local pos = 1
|
local pos = 1
|
||||||
local skip = skip or 1
|
local skip = skip or 1
|
||||||
function c:Act()
|
function c:Act(dt)
|
||||||
if pos >= skip then
|
if pos >= skip then
|
||||||
pos = 0
|
pos = 0
|
||||||
self.OnUpdate:Fire(self)
|
self.OnUpdate:Fire(self,dt)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
pos = pos+1
|
pos = pos+1
|
||||||
@@ -867,11 +969,11 @@ function multi:newAlarm(set, func)
|
|||||||
c.set=set or 0
|
c.set=set or 0
|
||||||
local count = 0
|
local count = 0
|
||||||
local t = clock()
|
local t = clock()
|
||||||
function c:Act()
|
function c:Act(dt)
|
||||||
if clock()-t>=self.set then
|
if clock()-t>=self.set then
|
||||||
self:Pause()
|
self:Pause()
|
||||||
self.Active=false
|
self.Active=false
|
||||||
self.OnRing:Fire(self)
|
self.OnRing:Fire(self,dt)
|
||||||
t = clock()
|
t = clock()
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
@@ -905,13 +1007,13 @@ function multi:newLoop(func, notime)
|
|||||||
local c,err=self:newBase(multi.registerType("loop", "loops"))
|
local c,err=self:newBase(multi.registerType("loop", "loops"))
|
||||||
local start=clock()
|
local start=clock()
|
||||||
if notime then
|
if notime then
|
||||||
function c:Act()
|
function c:Act(dt)
|
||||||
self.OnLoop:Fire(self)
|
self.OnLoop:Fire(self,nil,dt)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
function c:Act()
|
function c:Act(dt)
|
||||||
self.OnLoop:Fire(self,clock()-start)
|
self.OnLoop:Fire(self,clock()-start,dt)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -941,13 +1043,13 @@ function multi:newStep(start,reset,count,skip)
|
|||||||
think=-1
|
think=-1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
function c:Act()
|
function c:Act(dt)
|
||||||
if self~=nil then
|
if self~=nil then
|
||||||
if self.spos==0 then
|
if self.spos==0 then
|
||||||
if self.pos==self.start then
|
if self.pos==self.start then
|
||||||
self.OnStart:Fire(self)
|
self.OnStart:Fire(self)
|
||||||
end
|
end
|
||||||
self.OnStep:Fire(self,self.pos)
|
self.OnStep:Fire(self,self.pos,dt)
|
||||||
self.pos=self.pos+self.count
|
self.pos=self.pos+self.count
|
||||||
if self.pos-self.count==self.endAt then
|
if self.pos-self.count==self.endAt then
|
||||||
self:Pause()
|
self:Pause()
|
||||||
@@ -993,11 +1095,11 @@ function multi:newTLoop(func, set)
|
|||||||
c.life=0
|
c.life=0
|
||||||
c:setPriority("Low")
|
c:setPriority("Low")
|
||||||
|
|
||||||
function c:Act()
|
function c:Act(dt)
|
||||||
if self.timer:Get() >= self.set then
|
if self.timer:Get() >= self.set then
|
||||||
self.life=self.life+1
|
self.life=self.life+1
|
||||||
self.timer:Reset()
|
self.timer:Reset()
|
||||||
self.OnLoop:Fire(self, self.life)
|
self.OnLoop:Fire(self, self.life,dt)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1052,13 +1154,13 @@ function multi:newTStep(start,reset,count,set)
|
|||||||
self:Resume()
|
self:Resume()
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
function c:Act()
|
function c:Act(dt)
|
||||||
if clock()-self.timer>=self.set then
|
if clock()-self.timer>=self.set then
|
||||||
self:Reset()
|
self:Reset()
|
||||||
if self.pos==self.start then
|
if self.pos==self.start then
|
||||||
self.OnStart:Fire(self)
|
self.OnStart:Fire(self)
|
||||||
end
|
end
|
||||||
self.OnStep:Fire(self,self.pos)
|
self.OnStep:Fire(self,self.pos,dt)
|
||||||
self.pos=self.pos+self.count
|
self.pos=self.pos+self.count
|
||||||
if self.pos-self.count==self.endAt then
|
if self.pos-self.count==self.endAt then
|
||||||
self:Pause()
|
self:Pause()
|
||||||
@@ -1181,6 +1283,8 @@ function multi:newProcessor(name, opts, priority)
|
|||||||
end
|
end
|
||||||
|
|
||||||
sandcount = sandcount + 1
|
sandcount = sandcount + 1
|
||||||
|
c.connection_count = 0
|
||||||
|
c.connection_subscriptions = 0
|
||||||
c.Mainloop = {}
|
c.Mainloop = {}
|
||||||
c.Type = multi.registerType("process", "processes")
|
c.Type = multi.registerType("process", "processes")
|
||||||
local Active = nothread or false
|
local Active = nothread or false
|
||||||
@@ -1196,7 +1300,7 @@ function multi:newProcessor(name, opts, priority)
|
|||||||
local handler
|
local handler
|
||||||
|
|
||||||
if type(opts) == "table" then
|
if type(opts) == "table" then
|
||||||
priority = opts.Priority or false
|
priority = opts.Priority
|
||||||
Active = opts.Start or false
|
Active = opts.Start or false
|
||||||
maxThreads = opts.MaxThreads or -1
|
maxThreads = opts.MaxThreads or -1
|
||||||
maxObjects = opts.MaxObjects or -1
|
maxObjects = opts.MaxObjects or -1
|
||||||
@@ -1207,7 +1311,7 @@ function multi:newProcessor(name, opts, priority)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if priority then
|
if priority or multi.defaultSettings.priority then
|
||||||
handler = c:createPriorityHandler(c)
|
handler = c:createPriorityHandler(c)
|
||||||
else
|
else
|
||||||
handler = c:createHandler(c)
|
handler = c:createHandler(c)
|
||||||
@@ -1280,27 +1384,27 @@ function multi:newProcessor(name, opts, priority)
|
|||||||
function c:boost(count)
|
function c:boost(count)
|
||||||
boost = count or 1
|
boost = count or 1
|
||||||
if boost > 1 then
|
if boost > 1 then
|
||||||
self.run = function()
|
self.run = function(dt)
|
||||||
if not Active then return end
|
if not Active then return end
|
||||||
for i=1,boost do
|
for i=1,boost do
|
||||||
c:uManager(true)
|
c:uManager(dt)
|
||||||
handler()
|
handler()
|
||||||
end
|
end
|
||||||
return c
|
return c
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
self.run = function()
|
self.run = function(dt)
|
||||||
if not Active then return end
|
if not Active then return end
|
||||||
c:uManager(true)
|
c:uManager(dt)
|
||||||
handler()
|
handler()
|
||||||
return c
|
return c
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function c.run()
|
function c.run(dt)
|
||||||
if not Active then return end
|
if not Active then return end
|
||||||
c:uManager(true)
|
c:uManager(dt)
|
||||||
handler()
|
handler()
|
||||||
return c
|
return c
|
||||||
end
|
end
|
||||||
@@ -1309,6 +1413,10 @@ function multi:newProcessor(name, opts, priority)
|
|||||||
return Active
|
return Active
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function c:isPaused()
|
||||||
|
return not(Active)
|
||||||
|
end
|
||||||
|
|
||||||
function c.Start()
|
function c.Start()
|
||||||
Active = true
|
Active = true
|
||||||
return c
|
return c
|
||||||
@@ -1321,8 +1429,10 @@ function multi:newProcessor(name, opts, priority)
|
|||||||
|
|
||||||
function c:Destroy()
|
function c:Destroy()
|
||||||
Active = false
|
Active = false
|
||||||
|
if c.process then
|
||||||
c.process:Destroy()
|
c.process:Destroy()
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function c:setTaskDelay(delay)
|
function c:setTaskDelay(delay)
|
||||||
if type(delay) == "function" then
|
if type(delay) == "function" then
|
||||||
@@ -1517,8 +1627,9 @@ function thread.skip(n)
|
|||||||
return yield(CMD, t_skip, n or 1)
|
return yield(CMD, t_skip, n or 1)
|
||||||
end
|
end
|
||||||
|
|
||||||
function thread.kill()
|
function thread.kill(msg)
|
||||||
multi.error("thread killed!")
|
msg = msg or "thread killed!"
|
||||||
|
multi.error(msg)
|
||||||
end
|
end
|
||||||
|
|
||||||
function thread.yield()
|
function thread.yield()
|
||||||
@@ -1550,7 +1661,8 @@ function thread.get(name)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function thread.waitFor(name)
|
function thread.waitFor(name)
|
||||||
thread.hold(function() return thread.get(name)~=nil end)
|
local check = function() return thread.get(name)~=nil end
|
||||||
|
thread.hold(check)
|
||||||
return thread.get(name)
|
return thread.get(name)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1578,6 +1690,7 @@ function thread:newFunctionBase(generator, holdme, TYPE)
|
|||||||
local tfunc = {
|
local tfunc = {
|
||||||
GetCreationTimestamp = function() return multi.extract_uuid7_timestamp(UID).iso8601 end,
|
GetCreationTimestamp = function() return multi.extract_uuid7_timestamp(UID).iso8601 end,
|
||||||
}
|
}
|
||||||
|
tfunc.UPTIME = clock()
|
||||||
tfunc.Active = true
|
tfunc.Active = true
|
||||||
function tfunc:Pause()
|
function tfunc:Pause()
|
||||||
self.Active = false
|
self.Active = false
|
||||||
@@ -1592,9 +1705,7 @@ function thread:newFunctionBase(generator, holdme, TYPE)
|
|||||||
return nil, "Function is paused"
|
return nil, "Function is paused"
|
||||||
end
|
end
|
||||||
local rets, err
|
local rets, err
|
||||||
local function wait()
|
local check = function()
|
||||||
if thread.isThread() then
|
|
||||||
return thread.hold(function()
|
|
||||||
if err then
|
if err then
|
||||||
return multi.NIL, err
|
return multi.NIL, err
|
||||||
elseif rets then
|
elseif rets then
|
||||||
@@ -1602,7 +1713,10 @@ function thread:newFunctionBase(generator, holdme, TYPE)
|
|||||||
rets = nil
|
rets = nil
|
||||||
return cleanReturns((g[1] or multi.NIL),g[2],g[3],g[4],g[5],g[6],g[7],g[8],g[9],g[10],g[11],g[12],g[13],g[14],g[15],g[16])
|
return cleanReturns((g[1] or multi.NIL),g[2],g[3],g[4],g[5],g[6],g[7],g[8],g[9],g[10],g[11],g[12],g[13],g[14],g[15],g[16])
|
||||||
end
|
end
|
||||||
end)
|
end
|
||||||
|
local function wait()
|
||||||
|
if thread.isThread() then
|
||||||
|
return thread.hold(check)
|
||||||
else
|
else
|
||||||
while not rets and not err do
|
while not rets and not err do
|
||||||
multi:uManager()
|
multi:uManager()
|
||||||
@@ -1751,7 +1865,7 @@ function thread:newThread(name, func, ...)
|
|||||||
multi.OnLoad:Fire() -- This was done incase a threaded function was called before mainloop/uManager was called
|
multi.OnLoad:Fire() -- This was done incase a threaded function was called before mainloop/uManager was called
|
||||||
if type(name) == "function" then
|
if type(name) == "function" then
|
||||||
func = name
|
func = name
|
||||||
name = "UnnamedThread_"..multi.randomString(16)
|
name = "UnnamedThread_"..multi.randomString(4)
|
||||||
end
|
end
|
||||||
local c={nil,nil,nil,nil,nil,nil,nil}
|
local c={nil,nil,nil,nil,nil,nil,nil}
|
||||||
c.TempRets = {nil,nil,nil,nil,nil,nil,nil,nil,nil,nil}
|
c.TempRets = {nil,nil,nil,nil,nil,nil,nil,nil,nil,nil}
|
||||||
@@ -2326,7 +2440,7 @@ function multi.init(settings, realsettings)
|
|||||||
return _G["$multi"].multi,_G["$multi"].thread
|
return _G["$multi"].multi,_G["$multi"].thread
|
||||||
end
|
end
|
||||||
|
|
||||||
function multi:uManager()
|
function multi:uManager(dt)
|
||||||
if self.Active then
|
if self.Active then
|
||||||
__CurrentProcess = self
|
__CurrentProcess = self
|
||||||
multi.OnPreLoad:Fire()
|
multi.OnPreLoad:Fire()
|
||||||
@@ -2335,7 +2449,7 @@ function multi:uManager()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function multi:uManagerRefP1()
|
function multi:uManagerRefP1(dt)
|
||||||
if self.Active then
|
if self.Active then
|
||||||
__CurrentProcess = self
|
__CurrentProcess = self
|
||||||
local Loop=self.Mainloop
|
local Loop=self.Mainloop
|
||||||
@@ -2343,7 +2457,7 @@ function multi:uManagerRefP1()
|
|||||||
__CurrentTask = Loop[_D]
|
__CurrentTask = Loop[_D]
|
||||||
for P=1,9 do
|
for P=1,9 do
|
||||||
if PList[P]%__CurrentTask.Priority==0 then
|
if PList[P]%__CurrentTask.Priority==0 then
|
||||||
__CurrentTask:Act()
|
__CurrentTask:Act(dt)
|
||||||
__CurrentProcess = self
|
__CurrentProcess = self
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -2351,13 +2465,13 @@ function multi:uManagerRefP1()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function multi:uManagerRef()
|
function multi:uManagerRef(dt)
|
||||||
if self.Active then
|
if self.Active then
|
||||||
__CurrentProcess = self
|
__CurrentProcess = self
|
||||||
local Loop=self.Mainloop
|
local Loop=self.Mainloop
|
||||||
for _D=#Loop,1,-1 do
|
for _D=#Loop,1,-1 do
|
||||||
__CurrentTask = Loop[_D]
|
__CurrentTask = Loop[_D]
|
||||||
__CurrentTask:Act()
|
__CurrentTask:Act(dt)
|
||||||
__CurrentProcess = self
|
__CurrentProcess = self
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -2389,7 +2503,7 @@ function table.merge(t1, t2)
|
|||||||
return t1
|
return t1
|
||||||
end
|
end
|
||||||
|
|
||||||
math.randomseed(os.time())
|
math.randomseed(math.floor(os.time()))
|
||||||
|
|
||||||
function multi:enableLoadDetection()
|
function multi:enableLoadDetection()
|
||||||
if multi.maxSpd then return end
|
if multi.maxSpd then return end
|
||||||
@@ -2397,7 +2511,7 @@ function multi:enableLoadDetection()
|
|||||||
local temp = self:newProcessor()
|
local temp = self:newProcessor()
|
||||||
local t = clock()
|
local t = clock()
|
||||||
local stop = false
|
local stop = false
|
||||||
temp:benchMark(.01):OnBench(function(time,steps)
|
temp:benchMark(.1):OnBench(function(time,steps)
|
||||||
stop = steps
|
stop = steps
|
||||||
end)
|
end)
|
||||||
while not stop do
|
while not stop do
|
||||||
@@ -2410,28 +2524,39 @@ end
|
|||||||
local lastVal = 0
|
local lastVal = 0
|
||||||
local last_step = 0
|
local last_step = 0
|
||||||
|
|
||||||
function multi:getLoad()
|
function multi:getLoad(loops)
|
||||||
if not multi.maxSpd then multi:enableLoadDetection() end
|
local proc = proc or multi
|
||||||
|
if not proc.maxSpd then proc:enableLoadDetection() end
|
||||||
local val = nil
|
local val = nil
|
||||||
local bench
|
local bench
|
||||||
local bb
|
local bb
|
||||||
self:benchMark(.01).OnBench(function(time,steps)
|
local avg = 0
|
||||||
|
local loops = loops or 5
|
||||||
|
for i=1,loops do
|
||||||
|
self:benchMark(1).OnBench(function(time,steps)
|
||||||
bench = steps
|
bench = steps
|
||||||
bb = steps
|
bb = steps
|
||||||
|
avg = avg + steps
|
||||||
|
if steps > proc.maxSpd then
|
||||||
|
proc.maxSpd = steps
|
||||||
|
end
|
||||||
end)
|
end)
|
||||||
_,timeout = multi.hold(function()
|
_,timeout = multi.hold(function()
|
||||||
return bench
|
return bench
|
||||||
end,{sleep=.012})
|
end,{sleep=1.1})
|
||||||
|
end
|
||||||
|
avg = avg/loops
|
||||||
if timeout or not bench then
|
if timeout or not bench then
|
||||||
bench = 0
|
bench = 0
|
||||||
bb = 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/(proc.maxSpd/2.2)))*100)
|
||||||
if val<0 then val = 0 end
|
if val<0 then val = 0 end
|
||||||
if val > 100 then val = 100 end
|
if val > 100 then val = 100 end
|
||||||
lastVal = val
|
lastVal = val
|
||||||
last_step = bb*100
|
last_step = bb*100
|
||||||
|
print(proc.maxSpd, bench, bench/proc.maxSpd/2.2,val)
|
||||||
return val,last_step
|
return val,last_step
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -2532,8 +2657,8 @@ function multi:benchMark(sec,p,pt)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function multi.Round(num, numDecimalPlaces)
|
function multi.Round(num, numDecimalPlaces)
|
||||||
local mult = 10^(numDecimalPlaces or 0)
|
local mult = 10 ^ (numDecimalPlaces or 0)
|
||||||
return math.floor(num * mult + 0.5) / mult
|
return math.floor((num * mult) + 0.5 + 1e-10) / mult
|
||||||
end
|
end
|
||||||
|
|
||||||
function multi.AlignTable(tab)
|
function multi.AlignTable(tab)
|
||||||
@@ -2582,6 +2707,12 @@ end
|
|||||||
function multi:reallocate(processor, index)
|
function multi:reallocate(processor, index)
|
||||||
index=index or #processor.Mainloop+1
|
index=index or #processor.Mainloop+1
|
||||||
local int=self.Parent
|
local int=self.Parent
|
||||||
|
for i = #int.Mainloop, 1, -1 do
|
||||||
|
if int.Mainloop[i] == self then
|
||||||
|
table.remove(int.Mainloop,i)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
self.Parent=processor
|
self.Parent=processor
|
||||||
if index then
|
if index then
|
||||||
table.insert(processor.Mainloop, index, self)
|
table.insert(processor.Mainloop, index, self)
|
||||||
@@ -2679,11 +2810,8 @@ local function random_hex(len)
|
|||||||
end
|
end
|
||||||
return result
|
return result
|
||||||
end
|
end
|
||||||
|
math.randomseed(math.floor(os.time()))
|
||||||
multi.generate_uuid7 = function()
|
multi.generate_uuid7 = function()
|
||||||
-- Seed random number generator with current time
|
|
||||||
math.randomseed(os.time() * os.clock() * 1000000)
|
|
||||||
|
|
||||||
-- Get timestamp in milliseconds
|
-- Get timestamp in milliseconds
|
||||||
local timestamp_ms = get_timestamp_ms()
|
local timestamp_ms = get_timestamp_ms()
|
||||||
|
|
||||||
|
|||||||
@@ -58,16 +58,20 @@ function multi:newSystemThreadedQueue(name)
|
|||||||
GLOBAL[name] = c
|
GLOBAL[name] = c
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local peek = function()
|
||||||
|
return c:peek()
|
||||||
|
end
|
||||||
|
|
||||||
|
local pop = function()
|
||||||
|
return c:pop()
|
||||||
|
end
|
||||||
|
|
||||||
function c:Hold(opt)
|
function c:Hold(opt)
|
||||||
local multi, thread = require("multi"):init()
|
local multi, thread = require("multi"):init()
|
||||||
if opt.peek then
|
if opt.peek then
|
||||||
return thread.hold(function()
|
return thread.hold(peek)
|
||||||
return self:peek()
|
|
||||||
end)
|
|
||||||
else
|
else
|
||||||
return thread.hold(function()
|
return thread.hold(pop)
|
||||||
return self:pop()
|
|
||||||
end)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -23,9 +23,7 @@ SOFTWARE.
|
|||||||
]]
|
]]
|
||||||
package.path = "?/init.lua;?.lua;" .. package.path
|
package.path = "?/init.lua;?.lua;" .. package.path
|
||||||
local multi, thread = require("multi"):init()
|
local multi, thread = require("multi"):init()
|
||||||
|
|
||||||
local pseudoProcessor = multi:newProcessor()
|
local pseudoProcessor = multi:newProcessor()
|
||||||
|
|
||||||
if multi.integration then
|
if multi.integration then
|
||||||
return {
|
return {
|
||||||
init = function()
|
init = function()
|
||||||
|
|||||||
@@ -1,39 +0,0 @@
|
|||||||
function love.conf(t)
|
|
||||||
t.identity = nil -- The name of the save directory (string)
|
|
||||||
t.version = "12.0" -- The LOVE version this game was made for (string)
|
|
||||||
t.console = true -- Attach a console (boolean, Windows only)
|
|
||||||
|
|
||||||
t.window.title = "MultiThreadTest" -- The window title (string)
|
|
||||||
t.window.icon = nil -- Filepath to an image to use as the window's icon (string)
|
|
||||||
t.window.width = 1280 -- The window width (number)
|
|
||||||
t.window.height = 720 -- The window height (number)
|
|
||||||
|
|
||||||
t.window.borderless = false -- Remove all border visuals from the window (boolean)
|
|
||||||
t.window.resizable = true -- Let the window be user-resizable (boolean)
|
|
||||||
t.window.minwidth = 1 -- Minimum window width if the window is resizable (number)
|
|
||||||
t.window.minheight = 1 -- Minimum window height if the window is resizable (number)
|
|
||||||
t.window.fullscreen = false -- Enable fullscreen (boolean)
|
|
||||||
t.window.fullscreentype = "desktop" -- Standard fullscreen or desktop fullscreen mode (string)
|
|
||||||
t.window.vsync = false -- Enable vertical sync (boolean)
|
|
||||||
t.window.fsaa = 2 -- The number of samples to use with multi-sampled antialiasing (number)
|
|
||||||
t.window.display = 1 -- Index of the monitor to show the window in (number)
|
|
||||||
t.window.highdpi = false -- Enable high-dpi mode for the window on a Retina display (boolean)
|
|
||||||
t.window.srgb = false -- Enable sRGB gamma correction when drawing to the screen (boolean)
|
|
||||||
t.window.x = nil -- The x-coordinate of the window's position in the specified display (number)
|
|
||||||
t.window.y = nil -- The y-coordinate of the window's position in the specified display (number)
|
|
||||||
|
|
||||||
t.modules.audio = false -- Enable the audio module (boolean)
|
|
||||||
t.modules.event = false -- Enable the event module (boolean)
|
|
||||||
t.modules.graphics = false -- Enable the graphics module (boolean)
|
|
||||||
t.modules.image = false -- Enable the image module (boolean)
|
|
||||||
t.modules.joystick = false -- Enable the joystick module (boolean)
|
|
||||||
t.modules.keyboard = false -- Enable the keyboard module (boolean)
|
|
||||||
t.modules.math = false -- Enable the math module (boolean)
|
|
||||||
t.modules.mouse = false -- Enable the mouse module (boolean)
|
|
||||||
t.modules.physics = false -- Enable the physics module (boolean)
|
|
||||||
t.modules.sound = false -- Enable the sound module (boolean)
|
|
||||||
t.modules.system = false -- Enable the system module (boolean)
|
|
||||||
t.modules.timer = false -- Enable the timer module (boolean)
|
|
||||||
t.modules.window = false -- Enable the window module (boolean)
|
|
||||||
t.modules.thread = true -- Enable the thread module (boolean)
|
|
||||||
end
|
|
||||||
@@ -0,0 +1,244 @@
|
|||||||
|
--[[
|
||||||
|
Test suite for multi.lua
|
||||||
|
Run with: lua multi_test.lua
|
||||||
|
|
||||||
|
Requires multi.lua to be in the same directory or on the Lua path.
|
||||||
|
Compatible with Lua 5.1, 5.2, 5.3, 5.4, and LuaJIT.
|
||||||
|
]]
|
||||||
|
package.path = "../?/init.lua;../?.lua;../init.lua;../?.lua;" .. package.path
|
||||||
|
|
||||||
|
-- ─────────────────────────────────────────────
|
||||||
|
-- Minimal test runner
|
||||||
|
-- ─────────────────────────────────────────────
|
||||||
|
local passed, failed, skipped = 0, 0, 0
|
||||||
|
local failures = {}
|
||||||
|
|
||||||
|
local function test(name, fn)
|
||||||
|
local ok, err = pcall(fn)
|
||||||
|
if ok then
|
||||||
|
passed = passed + 1
|
||||||
|
io.write("\x1b[92m ✓\x1b[0m " .. name .. "\n")
|
||||||
|
else
|
||||||
|
failed = failed + 1
|
||||||
|
table.insert(failures, {name = name, err = tostring(err)})
|
||||||
|
io.write("\x1b[91m ✗\x1b[0m " .. name .. "\n")
|
||||||
|
io.write(" " .. tostring(err) .. "\n")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function skip(name, reason)
|
||||||
|
skipped = skipped + 1
|
||||||
|
io.write("\x1b[93m -\x1b[0m " .. name .. " [SKIPPED: " .. (reason or "") .. "]\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
local function section(name)
|
||||||
|
io.write("\n\x1b[97m── " .. name .. " ──\x1b[0m\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
local function assert_eq(a, b, msg)
|
||||||
|
if a ~= b then
|
||||||
|
error((msg or "assert_eq failed") .. ": expected " .. tostring(b) .. ", got " .. tostring(a), 2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function assert_truthy(v, msg)
|
||||||
|
if not v then
|
||||||
|
error((msg or "expected truthy value, got falsy") .. ": " .. tostring(v), 2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function assert_falsy(v, msg)
|
||||||
|
if v then
|
||||||
|
error((msg or "expected falsy value, got truthy") .. ": " .. tostring(v), 2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function assert_type(v, t, msg)
|
||||||
|
if type(v) ~= t then
|
||||||
|
error((msg or "type mismatch") .. ": expected " .. t .. ", got " .. type(v), 2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- ─────────────────────────────────────────────
|
||||||
|
-- Load the library
|
||||||
|
-- ─────────────────────────────────────────────
|
||||||
|
local multi, thread
|
||||||
|
local ok, err = pcall(function()
|
||||||
|
multi, thread = require("multi"):init()
|
||||||
|
end)
|
||||||
|
|
||||||
|
if not ok then
|
||||||
|
io.write("\x1b[91mFATAL: Could not load multi.lua: " .. tostring(err) .. "\x1b[0m\n")
|
||||||
|
io.write("Make sure multi.lua is in the same directory or on package.path.\n")
|
||||||
|
os.exit(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Helper: run the scheduler for up to `max_ticks` ticks or until `done()` returns true.
|
||||||
|
local function run_until(done, max_ticks)
|
||||||
|
max_ticks = max_ticks or 10000
|
||||||
|
for _ = 1, max_ticks do
|
||||||
|
multi:uManager()
|
||||||
|
if done and done() then return true end
|
||||||
|
end
|
||||||
|
return done == nil
|
||||||
|
end
|
||||||
|
|
||||||
|
section("Initialization")
|
||||||
|
|
||||||
|
test("lanesManager init returns GLOBAL and THREAD", function()
|
||||||
|
local GLOBAL, THREAD = require("multi.integration.lanesManager"):init()
|
||||||
|
assert_type(GLOBAL, "table")
|
||||||
|
assert_type(THREAD, "table")
|
||||||
|
end)
|
||||||
|
|
||||||
|
test("lanesManager sets integration table", function()
|
||||||
|
assert_type(multi.integration.GLOBAL, "table")
|
||||||
|
assert_type(multi.integration.THREAD, "table")
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- initialize once for rest of tests
|
||||||
|
local GLOBAL, THREAD = require("multi.integration.lanesManager"):init()
|
||||||
|
|
||||||
|
-- ─────────────────────────────────────────────
|
||||||
|
section("SystemThreadedQueue")
|
||||||
|
|
||||||
|
test("queue push/pop", function()
|
||||||
|
local q = multi:newSystemThreadedQueue("testQ1")
|
||||||
|
|
||||||
|
q:push(42)
|
||||||
|
local val = q:pop()
|
||||||
|
|
||||||
|
assert_eq(val, 42)
|
||||||
|
end)
|
||||||
|
|
||||||
|
test("queue peek does not remove", function()
|
||||||
|
local q = multi:newSystemThreadedQueue("testQ2")
|
||||||
|
|
||||||
|
q:push("hello")
|
||||||
|
|
||||||
|
assert_eq(q:peek(), "hello")
|
||||||
|
assert_eq(q:pop(), "hello")
|
||||||
|
end)
|
||||||
|
|
||||||
|
test("queue empty returns nil", function()
|
||||||
|
local q = multi:newSystemThreadedQueue("testQ3")
|
||||||
|
|
||||||
|
assert_eq(q:pop(), nil)
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- ─────────────────────────────────────────────
|
||||||
|
section("SystemThreadedTable")
|
||||||
|
|
||||||
|
test("table set/get", function()
|
||||||
|
local t = multi:newSystemThreadedTable("testT1")
|
||||||
|
|
||||||
|
t.foo = "bar"
|
||||||
|
assert_eq(t.foo, "bar")
|
||||||
|
end)
|
||||||
|
|
||||||
|
test("table overwrite", function()
|
||||||
|
local t = multi:newSystemThreadedTable("testT2")
|
||||||
|
|
||||||
|
t.x = 1
|
||||||
|
t.x = 2
|
||||||
|
|
||||||
|
assert_eq(t.x, 2)
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- ─────────────────────────────────────────────
|
||||||
|
section("THREAD API")
|
||||||
|
|
||||||
|
test("THREAD set/get", function()
|
||||||
|
THREAD.set("abc", 123)
|
||||||
|
assert_eq(THREAD.get("abc"), 123)
|
||||||
|
end)
|
||||||
|
|
||||||
|
test("THREAD getCores > 0", function()
|
||||||
|
assert_truthy(THREAD.getCores() > 0)
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- ─────────────────────────────────────────────
|
||||||
|
section("SystemThreadedConnection")
|
||||||
|
|
||||||
|
test("connection fires event", function()
|
||||||
|
local conn = multi:newSystemThreadedConnection("conn1"):init()
|
||||||
|
|
||||||
|
local received = nil
|
||||||
|
|
||||||
|
conn(function(v)
|
||||||
|
received = v
|
||||||
|
end)
|
||||||
|
|
||||||
|
conn:Fire("ping")
|
||||||
|
|
||||||
|
run_until(function()
|
||||||
|
return received ~= nil
|
||||||
|
end, 5000)
|
||||||
|
|
||||||
|
assert_eq(received, "ping")
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- ─────────────────────────────────────────────
|
||||||
|
section("SystemThreadedJobQueue")
|
||||||
|
|
||||||
|
test("job queue executes function", function()
|
||||||
|
local jq = multi:newSystemThreadedJobQueue(1)
|
||||||
|
|
||||||
|
jq:registerFunction("add", function(a, b)
|
||||||
|
return a + b
|
||||||
|
end)
|
||||||
|
|
||||||
|
local result = nil
|
||||||
|
|
||||||
|
jq.OnJobCompleted(function(_, val)
|
||||||
|
result = val
|
||||||
|
end)
|
||||||
|
|
||||||
|
jq:pushJob("add", 2, 3)
|
||||||
|
|
||||||
|
run_until(function()
|
||||||
|
return result ~= nil
|
||||||
|
end, 10000)
|
||||||
|
|
||||||
|
assert_eq(result, 5)
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- ─────────────────────────────────────────────
|
||||||
|
section("JobQueue newFunction")
|
||||||
|
|
||||||
|
test("newFunction returns correct result", function()
|
||||||
|
local jq = multi:newSystemThreadedJobQueue(1)
|
||||||
|
|
||||||
|
local fn = jq:newFunction(function(a, b)
|
||||||
|
return a * b
|
||||||
|
end,true)
|
||||||
|
|
||||||
|
local result = nil
|
||||||
|
|
||||||
|
result = fn(3, 4)
|
||||||
|
|
||||||
|
run_until(function()
|
||||||
|
return result ~= nil
|
||||||
|
end, 10000)
|
||||||
|
|
||||||
|
assert_eq(result, 12)
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- ─────────────────────────────────────────────
|
||||||
|
-- Summary
|
||||||
|
-- ─────────────────────────────────────────────
|
||||||
|
section("Results")
|
||||||
|
|
||||||
|
io.write("\n")
|
||||||
|
io.write("Passed: " .. passed .. "\n")
|
||||||
|
io.write("Failed: " .. failed .. "\n")
|
||||||
|
io.write("Skipped: " .. skipped .. "\n")
|
||||||
|
|
||||||
|
if failed > 0 then
|
||||||
|
io.write("\nFailures:\n")
|
||||||
|
for _, f in ipairs(failures) do
|
||||||
|
io.write(" - " .. f.name .. "\n")
|
||||||
|
io.write(" " .. f.err .. "\n")
|
||||||
|
end
|
||||||
|
os.exit(1)
|
||||||
|
end
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
package.path = "../?/init.lua;../?.lua;"..package.path
|
|
||||||
|
|
||||||
if os.getenv("LOCAL_LUA_DEBUGGER_VSCODE") == "1" then
|
|
||||||
require("lldebugger").start()
|
|
||||||
end
|
|
||||||
|
|
||||||
GLOBAL, THREAD = require("multi.integration.loveManager"):init()
|
|
||||||
|
|
||||||
require("runtests")
|
|
||||||
require("threadtests")
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,195 +0,0 @@
|
|||||||
package.path = "../?/init.lua;../?.lua;./init.lua;./?.lua;"..package.path
|
|
||||||
|
|
||||||
local multi, thread = require("multi"):init{print=true,warn=true,error=true}--{priority=true}
|
|
||||||
local good = false
|
|
||||||
local proc = multi:newProcessor("Test")
|
|
||||||
|
|
||||||
print("Version: "..multi.Version)
|
|
||||||
|
|
||||||
proc.Start()
|
|
||||||
|
|
||||||
proc:newAlarm(3):OnRing(function()
|
|
||||||
good = true
|
|
||||||
end)
|
|
||||||
|
|
||||||
runTest = thread:newFunction(function()
|
|
||||||
local alarms,tsteps,steps,loops,tloops,updaters,events=false,0,0,0,0,0,false
|
|
||||||
multi.print("Testing Basic Features. If this fails most other features will probably not work!")
|
|
||||||
proc:newAlarm(2):OnRing(function(a)
|
|
||||||
alarms = true
|
|
||||||
a:Destroy()
|
|
||||||
end)
|
|
||||||
proc:newTStep(1,10,1,.1):OnStep(function(t)
|
|
||||||
tsteps = tsteps + 1
|
|
||||||
end):OnEnd(function(step)
|
|
||||||
step:Destroy()
|
|
||||||
end)
|
|
||||||
proc:newStep(1,10):OnStep(function(s)
|
|
||||||
steps = steps + 1
|
|
||||||
end):OnEnd(function(step)
|
|
||||||
step:Destroy()
|
|
||||||
end)
|
|
||||||
local loop = proc:newLoop(function(l)
|
|
||||||
loops = loops + 1
|
|
||||||
end)
|
|
||||||
proc:newTLoop(function(t)
|
|
||||||
tloops = tloops + 1
|
|
||||||
end,.1)
|
|
||||||
local updater = proc:newUpdater(1):OnUpdate(function()
|
|
||||||
updaters = updaters + 1
|
|
||||||
end)
|
|
||||||
local event = proc:newEvent(function()
|
|
||||||
return alarms
|
|
||||||
end)
|
|
||||||
event.OnEvent(function(evnt)
|
|
||||||
evnt:Destroy()
|
|
||||||
events = true
|
|
||||||
multi.success("Alarms: Ok")
|
|
||||||
multi.success("Events: Ok")
|
|
||||||
if tsteps == 10 then multi.success("TSteps: Ok") else multi.error("TSteps: Bad!") end
|
|
||||||
if steps == 10 then multi.success("Steps: Ok") else multi.error("Steps: Bad!") end
|
|
||||||
if loops > 100 then multi.success("Loops: Ok") else multi.error("Loops: Bad!") end
|
|
||||||
if tloops > 10 then multi.success("TLoops: Ok") else multi.error("TLoops: Bad!") end
|
|
||||||
if updaters > 100 then multi.success("Updaters: Ok") else multi.error("Updaters: Bad!") end
|
|
||||||
end)
|
|
||||||
thread.hold(event.OnEvent)
|
|
||||||
multi.print("Starting Connection and Thread tests!")
|
|
||||||
func = thread:newFunction(function(count)
|
|
||||||
multi.print("Starting Status test: ",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", true, math.random(1,10000)
|
|
||||||
end)
|
|
||||||
local ret = func(10)
|
|
||||||
local ret2 = func(15)
|
|
||||||
local ret3 = func(20)
|
|
||||||
local s1,s2,s3 = 0,0,0
|
|
||||||
ret.OnError(function(...)
|
|
||||||
multi.error("Func 1:",...)
|
|
||||||
end)
|
|
||||||
ret2.OnError(function(...)
|
|
||||||
multi.error("Func 2:",...)
|
|
||||||
end)
|
|
||||||
ret3.OnError(function(...)
|
|
||||||
multi.error("Func 3:",...)
|
|
||||||
end)
|
|
||||||
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)
|
|
||||||
|
|
||||||
ret.OnReturn(function(...)
|
|
||||||
multi.success("Done 1",...)
|
|
||||||
end)
|
|
||||||
ret2.OnReturn(function(...)
|
|
||||||
multi.success("Done 2",...)
|
|
||||||
end)
|
|
||||||
ret3.OnReturn(function(...)
|
|
||||||
multi.success("Done 3",...)
|
|
||||||
end)
|
|
||||||
|
|
||||||
local err, timeout = thread.hold(ret.OnReturn * ret2.OnReturn * ret3.OnReturn)
|
|
||||||
|
|
||||||
if s1 == 100 and s2 == 100 and s3 == 100 then
|
|
||||||
multi.success("Threads: All tests Ok")
|
|
||||||
else
|
|
||||||
if s1>0 and s2>0 and s3 > 0 then
|
|
||||||
multi.success("Thread OnStatus: Ok")
|
|
||||||
else
|
|
||||||
multi.error("Threads OnStatus or thread.hold(conn) Error!")
|
|
||||||
end
|
|
||||||
if timeout then
|
|
||||||
multi.error("Connection Error!")
|
|
||||||
else
|
|
||||||
multi.success("Connection Test 1: Ok")
|
|
||||||
end
|
|
||||||
multi.error("Connection holding Error!")
|
|
||||||
end
|
|
||||||
|
|
||||||
conn1 = proc:newConnection()
|
|
||||||
conn2 = proc:newConnection()
|
|
||||||
conn3 = proc: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
|
|
||||||
multi.success("Connection Test 2: Ok")
|
|
||||||
else
|
|
||||||
multi.error("Connection Test 2: Error")
|
|
||||||
end
|
|
||||||
c3 = false
|
|
||||||
c4 = false
|
|
||||||
conn3:Unconnect(d)
|
|
||||||
conn3:Fire()
|
|
||||||
if c3 and not(c4) then
|
|
||||||
multi.success("Connection Test 3: Ok")
|
|
||||||
else
|
|
||||||
multi.error("Connection Test 3: Error removing connection")
|
|
||||||
end
|
|
||||||
if not love then
|
|
||||||
local ec = 0
|
|
||||||
multi.print("Testing pseudo threading")
|
|
||||||
capture = io.popen("lua tests/threadtests.lua p"):read("*a")
|
|
||||||
if capture:lower():match("error") then
|
|
||||||
ec = ec + 1
|
|
||||||
os.exit(1)
|
|
||||||
else
|
|
||||||
io.write(capture)
|
|
||||||
end
|
|
||||||
multi.print("Testing lanes threading")
|
|
||||||
capture = io.popen("lua tests/threadtests.lua l"):read("*a")
|
|
||||||
if capture:lower():match("error") then
|
|
||||||
ec = ec + 1
|
|
||||||
os.exit(1)
|
|
||||||
else
|
|
||||||
io.write(capture)
|
|
||||||
end
|
|
||||||
os.exit(0)
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
local handle = runTest()
|
|
||||||
|
|
||||||
handle.OnError(function(...)
|
|
||||||
multi.error("Something went wrong with the test!")
|
|
||||||
print(...)
|
|
||||||
end)
|
|
||||||
|
|
||||||
if not love then
|
|
||||||
multi:mainloop()
|
|
||||||
else
|
|
||||||
local hold = thread:newFunction(function()
|
|
||||||
thread.hold(handle.OnError + handle.OnReturn)
|
|
||||||
end, true)
|
|
||||||
hold()
|
|
||||||
multi.print("Starting Threading tests!")
|
|
||||||
end
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package.path = "D:/VSCWorkspace/?/init.lua;D:/VSCWorkspace/?.lua;"..package.path
|
package.path = "../?/init.lua;../?.lua;../init.lua;../?.lua;" .. package.path
|
||||||
package.cpath = "C:/luaInstalls/lua5.4/lib/lua/5.4/?/core.dll;" .. package.cpath
|
package.cpath = "C:/luaInstalls/lua5.4/lib/lua/5.4/?/core.dll;" .. package.cpath
|
||||||
multi, thread = require("multi"):init{error=true,warning=true,print=true, priority=true}
|
multi, thread = require("multi"):init{error=true,warning=true,print=true, priority=true}
|
||||||
proc = multi:newProcessor("Thread Test",true)
|
proc = multi:newProcessor("Thread Test",true)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user