Working on 16.0.0 #53

Merged
rayaman merged 120 commits from v16.0.0 into master 2024-02-25 00:00:51 -05:00
15 changed files with 242 additions and 25 deletions
Showing only changes of commit 614e032aa5 - Show all commits

42
.github/workflows/nix_ci.yml vendored Normal file
View File

@ -0,0 +1,42 @@
name: build & run tests (NIX)
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
strategy:
fail-fast: false
matrix:
build-type: [Release] # Debug
lua: ["lua 5.1", "lua 5.2", "lua 5.3", "luajit 2.1.0-beta3"]
os: ["macos-latest", "ubuntu-latest", "windows-2019"]
include:
- os: macos-latest
macos_build_target: 10.0
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
with:
submodules: recursive
- uses: actions/setup-python@v2
with:
python-version: '3.8'
- name: Setup env
env:
MACOSX_DEPLOYMENT_TARGET: ${{ matrix.macos_build_target }}
run: |
pip install hererocks
hererocks lua-pkg --${{ matrix.lua }} -rlatest
source ${{github.workspace}}/lua-pkg/bin/activate
- name: Install lanes
run: |
luarocks insatll lanes
- name: Run Tests
run: |
lua tests/runtests.lua

48
.github/workflows/win_ci.yml vendored Normal file
View File

@ -0,0 +1,48 @@
name: build & run tests (Win)
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
strategy:
fail-fast: false
matrix:
build-type: [Release] # Debug
lua: ["lua 5.1", "lua 5.2", "lua 5.3", "luajit 2.0"]
os: ["windows-2019"]
platform: [
{"forLua": "vs_32", "forCMake": "Win32"},
{"forLua": "vs_64", "forCMake": "x64"},
]
exclude:
- lua: "luajit 2.0"
platform: {"forLua": "vs_32", "forCMake": "Win32"}
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
with:
submodules: recursive
- uses: actions/setup-python@v2
with:
python-version: '3.8'
- name: Setup env
run: |
pip install hererocks
hererocks lua-pkg --${{ matrix.lua }} -rlatest --target ${{matrix.platform.forLua}}
cmd ${{github.workspace}}\lua-pkg\bin\activate
- name: Configure CMake & build
run: |
cmake -A ${{matrix.platform.forCMake}} -B ${{github.workspace}}\build -DLUA_INCLUDE_DIR="${{github.workspace}}/lua-pkg/include" -DLUA_LIBRARY="${{github.workspace}}/lua-pkg/lib/lua*.lib"
cmake --build ${{github.workspace}}/build --config ${{matrix.build-type}}
- name: Test
working-directory: ${{github.workspace}}/build
env:
STRESS: 1
run: |
${{github.workspace}}/lua-pkg/bin/lua ../tests/lua/run_tests

View File

@ -67,6 +67,21 @@ multi, thread = require("multi"):init{print=true}
GLOBAL, THREAD = require("multi.integration.lanesManager"):init() GLOBAL, THREAD = require("multi.integration.lanesManager"):init()
``` ```
## Added New Integration: **effilManager**
Another option for multithreading support, works just like all the other threading integrations, but uses the internals of effil and it's unique features.
- Refer to this [doc](https://www.lua.org/wshop18/Kupriyanov.pdf) to read more about it.
- Project github [page](https://github.com/effil/effil/tree/master).
```lua
package.path = "?/init.lua;?.lua;"..package.path
local multi, thread = require("multi"):init({print=true, warn=true, error=true})
local THREAD, GLOBAL = require("multi.integration.effilManager"):init()
-- Code as you would
```
## Added New Integration: **priorityManager** ## Added New Integration: **priorityManager**
Allows the user to have multi auto set priorities (Requires chronos). 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 all other features will still work! Allows the user to have multi auto set priorities (Requires chronos). 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 all other features will still work!

View File

@ -60,6 +60,7 @@ function multi.setType(obj,t)
}) })
end end
end end
setmetatable(multi.DestroyedObj, { setmetatable(multi.DestroyedObj, {
__index = function(t,k) __index = function(t,k)
return setmetatable({},{__index = uni,__newindex = uni,__call = uni,__metatable = multi.DestroyedObj,__tostring = function() return "destroyed" end,__unm = uni,__add = uni,__sub = uni,__mul = uni,__div = uni,__mod = uni,__pow = uni,__concat = uni}) return setmetatable({},{__index = uni,__newindex = uni,__call = uni,__metatable = multi.DestroyedObj,__tostring = function() return "destroyed" end,__unm = uni,__add = uni,__sub = uni,__mul = uni,__div = uni,__mod = uni,__pow = uni,__concat = uni})
@ -68,7 +69,8 @@ setmetatable(multi.DestroyedObj, {
multi.DESTROYED = multi.DestroyedObj multi.DESTROYED = multi.DestroyedObj
multi.ROOTPROCESS = "rootprocess" multi.ROOTPROCESS = "rootprocess"
multi.CONNECTOR = "connector" multi.CONNECTOR = "connector" -- To be deprecated
multi.CONNECTION = "connector" -- To be changed to connection and replace connector (v17.x,x)
multi.TIMEMASTER = "timemaster" multi.TIMEMASTER = "timemaster"
multi.PROCESS = "process" multi.PROCESS = "process"
multi.TIMER = "timer" multi.TIMER = "timer"
@ -81,8 +83,18 @@ multi.STEP = "step"
multi.TSTEP = "tstep" multi.TSTEP = "tstep"
multi.THREAD = "thread" multi.THREAD = "thread"
multi.SERVICE = "service" multi.SERVICE = "service"
multi.THREADEDFUNCTION = "threaded_function" -- To be deprecated
multi.FUNCTION = "threaded_function" -- To be changed to connection and replace connector (v17.x,x)
-- Extensions
multi.PROXY = "proxy" multi.PROXY = "proxy"
multi.THREADEDFUNCTION = "threaded_function" multi.STHREAD = "s_thread"
multi.SQUEUE = "s_queue"
multi.STABLE = "s_table"
multi.SJOBQUEUE = "s_jobqueue"
multi.SCONNECTION = "s_connection"
multi.SPROCESS = "s_process"
multi.SFUNCTION = "s_function"
if not _G["$multi"] then if not _G["$multi"] then
_G["$multi"] = {multi = multi, thread = thread} _G["$multi"] = {multi = multi, thread = thread}
@ -305,7 +317,7 @@ function multi:newConnection(protect,func,kill)
return cn return cn
end}) end})
c.Type=multi.CONNECTOR c.Type=multi.CONNECTION
c.func={} c.func={}
c.ID=0 c.ID=0
local protect=protect or false local protect=protect or false
@ -1286,7 +1298,7 @@ function thread.hold(n, opt)
if type(n) == "number" then if type(n) == "number" then
thread.getRunningThread().lastSleep = clock() thread.getRunningThread().lastSleep = clock()
return yield(CMD, t_sleep, n or 0, nil, interval) return yield(CMD, t_sleep, n or 0, nil, interval)
elseif type(n) == "table" and n.Type == multi.CONNECTOR then elseif type(n) == "table" and n.Type == multi.CONNECTION then
return yield(CMD, t_hold, conn_test(n), nil, interval) return yield(CMD, t_hold, conn_test(n), nil, interval)
elseif type(n) == "table" and n.Hold ~= nil then elseif type(n) == "table" and n.Hold ~= nil then
return n:Hold(opt) return n:Hold(opt)
@ -1367,7 +1379,7 @@ function thread.pushStatus(...)
t.statusconnector:Fire(...) t.statusconnector:Fire(...)
end end
function thread:newFunctionBase(generator, holdme) function thread:newFunctionBase(generator, holdme, TYPE)
return function() return function()
local tfunc = {} local tfunc = {}
tfunc.Active = true tfunc.Active = true
@ -1449,7 +1461,7 @@ function thread:newFunctionBase(generator, holdme)
return temp return temp
end end
setmetatable(tfunc, tfunc) setmetatable(tfunc, tfunc)
tfunc.Type = multi.THREADEDFUNCTION tfunc.Type = TYPE or multi.FUNCTION
return tfunc return tfunc
end end
end end
@ -2043,7 +2055,7 @@ local function doOpt()
if type(n) == "number" then if type(n) == "number" then
thread.getRunningThread().lastSleep = clock() thread.getRunningThread().lastSleep = clock()
return yield(CMD, t_sleep, n or 0, nil, interval) return yield(CMD, t_sleep, n or 0, nil, interval)
elseif type(n) == "table" and n.Type == multi.CONNECTOR then elseif type(n) == "table" and n.Type == multi.CONNECTION then
local rdy = function() local rdy = function()
return false return false
end end

View File

View File

@ -0,0 +1,46 @@
local multi, thread = require("multi"):init{error=true}
multi.error("Currntly not supported!")
os.exit()
local effil = require("effil")
-- I like some of the things that this library offers.
-- Current limitations prevent me from being able to use effil,
-- but I might fork and work on it myself.
-- Configs
effil.allow_table_upvalues(false)
local GLOBAL,THREAD = require("multi.integration.effilManager.threads").init()
local count = 1
local started = false
local livingThreads = {}
function multi:newSystemThread(name, func, ...)
local name = name or multi.randomString(16)
local rand = math.random(1, 10000000)
c = {}
c.name = name
c.Name = name
c.Id = count
end
function THREAD:newFunction(func, holdme)
return thread:newFunctionBase(function(...)
return multi:newSystemThread("TempSystemThread",func,...)
end, holdme, multi.SFUNCTION)()
end
THREAD.newSystemThread = function(...)
multi:newSystemThread(...)
end
multi.print("Integrated Effil Threading!")
multi.integration = {} -- for module creators
multi.integration.GLOBAL = GLOBAL
multi.integration.THREAD = THREAD
require("multi.integration.effilManager.extensions")
return {
init = function()
return GLOBAL, THREAD
end
}

View File

View File

@ -34,6 +34,7 @@ function multi:newSystemThreadedQueue(name)
local c = {} local c = {}
c.Name = name c.Name = name
c.linda = lanes.linda() c.linda = lanes.linda()
c.Type = multi.SQUEUE
function c:push(v) function c:push(v)
self.linda:send("Q", v) self.linda:send("Q", v)
@ -57,6 +58,8 @@ function multi:newSystemThreadedQueue(name)
GLOBAL[name] = c GLOBAL[name] = c
end end
self:create(c)
return c return c
end end
@ -65,6 +68,7 @@ function multi:newSystemThreadedTable(name)
local c = {} local c = {}
c.link = lanes.linda() c.link = lanes.linda()
c.Name = name c.Name = name
c.Type = multi.STABLE
function c:init() function c:init()
return self return self
@ -85,12 +89,15 @@ function multi:newSystemThreadedTable(name)
GLOBAL[name] = c GLOBAL[name] = c
end end
self:create(c)
return c return c
end end
function multi:newSystemThreadedJobQueue(n) function multi:newSystemThreadedJobQueue(n)
local c = {} local c = {}
c.cores = n or THREAD.getCores()*2 c.cores = n or THREAD.getCores()*2
c.Type = multi.SJOBQUEUE
c.OnJobCompleted = multi:newConnection() c.OnJobCompleted = multi:newConnection()
local funcs = multi:newSystemThreadedTable():init() local funcs = multi:newSystemThreadedTable():init()
local queueJob = multi:newSystemThreadedQueue():init() local queueJob = multi:newSystemThreadedQueue():init()
@ -133,7 +140,6 @@ function multi:newSystemThreadedJobQueue(n)
link = c.OnJobCompleted(function(jid,...) link = c.OnJobCompleted(function(jid,...)
if id==jid then if id==jid then
rets = multi.pack(...) rets = multi.pack(...)
c.OnJobCompleted:Unconnect(link)
end end
end) end)
return thread.hold(function() return thread.hold(function()
@ -207,12 +213,16 @@ function multi:newSystemThreadedJobQueue(n)
multi:mainloop() multi:mainloop()
end,i).OnError(multi.error) end,i).OnError(multi.error)
end end
self:create(c)
return c return c
end end
function multi:newSystemThreadedConnection(name) function multi:newSystemThreadedConnection(name)
local name = name or multi.randomString(16) local name = name or multi.randomString(16)
local c = {} local c = {}
c.Type = multi.SCONNECTION
c.CONN = 0x00 c.CONN = 0x00
c.TRIG = 0x01 c.TRIG = 0x01
c.PING = 0x02 c.PING = 0x02
@ -348,6 +358,8 @@ function multi:newSystemThreadedConnection(name)
GLOBAL[name] = c GLOBAL[name] = c
end end
self:create(c)
return c return c
end end
require("multi.integration.sharedExtensions") require("multi.integration.sharedExtensions")

View File

@ -32,9 +32,7 @@ if multi.integration then -- This allows us to call the lanes manager from suppo
} }
end end
-- Step 1 get lanes -- Step 1 get lanes
lanes = require("lanes").configure{ lanes = require("lanes").configure()
nb_keepers = 4,
}
multi.SystemThreads = {} multi.SystemThreads = {}
multi.isMainThread = true multi.isMainThread = true
@ -63,7 +61,7 @@ local livingThreads = {}
function THREAD:newFunction(func, holdme) function THREAD:newFunction(func, holdme)
return thread:newFunctionBase(function(...) return thread:newFunctionBase(function(...)
return multi:newSystemThread("TempSystemThread",func,...) return multi:newSystemThread("TempSystemThread",func,...)
end, holdme)() end, holdme, multi.SFUNCTION)()
end end
function multi:newSystemThread(name, func, ...) function multi:newSystemThread(name, func, ...)
@ -143,7 +141,9 @@ function multi:newSystemThread(name, func, ...)
return c return c
end end
THREAD.newSystemThread = multi.newSystemThread THREAD.newSystemThread = function(...)
multi:newSystemThread(...)
end
function multi.InitSystemThreadErrorHandler() function multi.InitSystemThreadErrorHandler()
if started == true then if started == true then

View File

@ -35,6 +35,7 @@ function multi:newSystemThreadedQueue(name)
local name = name or multi.randomString(16) local name = name or multi.randomString(16)
local c = {} local c = {}
c.Name = name c.Name = name
c.Type = multi.SQUEUE
local fRef = {"func",nil} local fRef = {"func",nil}
function c:init() function c:init()
local q = {} local q = {}
@ -66,33 +67,49 @@ function multi:newSystemThreadedQueue(name)
end end
return q return q
end end
THREAD.package(name,c) THREAD.package(name,c)
self:create(c)
return c return c
end end
function multi:newSystemThreadedTable(name) function multi:newSystemThreadedTable(name)
local name = name or multi.randomString(16) local name = name or multi.randomString(16)
local c = {} local c = {}
c.Name = name c.Name = name
c.Type = multi.STABLE
function c:init() function c:init()
return THREAD.createTable(self.Name) return THREAD.createTable(self.Name)
end end
THREAD.package(name,c) THREAD.package(name,c)
self:create(c)
return c return c
end end
local jqc = 1 local jqc = 1
function multi:newSystemThreadedJobQueue(n) function multi:newSystemThreadedJobQueue(n)
local c = {} local c = {}
c.cores = n or THREAD.getCores() c.cores = n or THREAD.getCores()
c.registerQueue = {} c.registerQueue = {}
c.Type = multi.SJOBQUEUE
c.funcs = THREAD.createStaticTable("__JobQueue_"..jqc.."_table") c.funcs = THREAD.createStaticTable("__JobQueue_"..jqc.."_table")
c.queue = love.thread.getChannel("__JobQueue_"..jqc.."_queue") c.queue = love.thread.getChannel("__JobQueue_"..jqc.."_queue")
c.queueReturn = love.thread.getChannel("__JobQueue_"..jqc.."_queueReturn") c.queueReturn = love.thread.getChannel("__JobQueue_"..jqc.."_queueReturn")
c.queueAll = love.thread.getChannel("__JobQueue_"..jqc.."_queueAll") c.queueAll = love.thread.getChannel("__JobQueue_"..jqc.."_queueAll")
c.id = 0 c.id = 0
c.OnJobCompleted = multi:newConnection() c.OnJobCompleted = multi:newConnection()
local allfunc = 0 local allfunc = 0
function c:doToAll(func) function c:doToAll(func)
local f = THREAD.dump(func) local f = THREAD.dump(func)
for i = 1, self.cores do for i = 1, self.cores do
@ -211,13 +228,20 @@ function multi:newSystemThreadedJobQueue(n)
multi:mainloop() multi:mainloop()
end,jqc) end,jqc)
end end
jqc = jqc + 1 jqc = jqc + 1
self:create(c)
return c return c
end end
function multi:newSystemThreadedConnection(name) function multi:newSystemThreadedConnection(name)
local name = name or multi.randomString(16) local name = name or multi.randomString(16)
local c = {} local c = {}
c.Type = multi.SCONNECTION
c.CONN = 0x00 c.CONN = 0x00
c.TRIG = 0x01 c.TRIG = 0x01
c.PING = 0x02 c.PING = 0x02
@ -284,9 +308,11 @@ function multi:newSystemThreadedConnection(name)
end end
return r return r
end end
c.CID = THREAD_ID c.CID = THREAD_ID
c.Name = name c.Name = name
c.links = {} -- All triggers sent from main connection. When a connection is triggered on another thread, they speak to the main then send stuff out. c.links = {} -- All triggers sent from main connection. When a connection is triggered on another thread, they speak to the main then send stuff out.
-- Locals will only live in the thread that creates the original object -- Locals will only live in the thread that creates the original object
local ping local ping
local pong = function(link, links) local pong = function(link, links)
@ -317,7 +343,7 @@ function multi:newSystemThreadedConnection(name)
thread.sleep(3) thread.sleep(3)
ping:Resume() ping:Resume()
end,false) end, false)
local function fire(...) local function fire(...)
for _, link in pairs(c.links) do for _, link in pairs(c.links) do
@ -351,5 +377,7 @@ function multi:newSystemThreadedConnection(name)
THREAD.package(name,c) THREAD.package(name,c)
self:create(c)
return c return c
end end

View File

@ -116,10 +116,12 @@ end
function THREAD:newFunction(func, holdme) function THREAD:newFunction(func, holdme)
return thread:newFunctionBase(function(...) return thread:newFunctionBase(function(...)
return multi:newSystemThread("SystemThreaded Function Handler", func, ...) return multi:newSystemThread("SystemThreaded Function Handler", func, ...)
end, holdme)() end, holdme, multi.SFUNCTION)()
end end
THREAD.newSystemThread = multi.newSystemThread THREAD.newSystemThread = function(...)
multi:newSystemThread(...)
end
function love.threaderror(thread, errorstr) function love.threaderror(thread, errorstr)
multi.print("Thread error!\n" .. errorstr) multi.print("Thread error!\n" .. errorstr)

View File

@ -213,6 +213,7 @@ function multi:newSystemThreadedProcessor(cores)
setmetatable(c,{__index = multi}) setmetatable(c,{__index = multi})
c.Type = multi.SPROCESS
c.threads = {} c.threads = {}
c.cores = cores or 8 c.cores = cores or 8
c.Name = name c.Name = name

1
tests/multi Symbolic link
View File

@ -0,0 +1 @@
D:/VSCWorkspace/discord-lua/multi

View File

@ -182,11 +182,19 @@ runTest = thread:newFunction(function()
end end
end) end)
runTest().OnError(function(...) local handle = runTest()
handle.OnError(function(...)
multi.error("Something went wrong with the test!") multi.error("Something went wrong with the test!")
print(...) print(...)
end) end)
if not love then if not love then
multi:mainloop() multi:mainloop()
else
local hold = thread:newFunction(function()
thread.hold(handle.OnError + handle.OnReturn)
end, true)
hold()
multi.print("Starting Threading tests!")
end end

View File

@ -109,12 +109,10 @@ multi:newThread("Scheduler Thread",function()
local ready = false local ready = false
jq = multi:newSystemThreadedJobQueue(5) -- Job queue with 4 worker threads jq = multi:newSystemThreadedJobQueue(5) -- Job queue with 4 worker threads
func = jq:newFunction("test-thread",function(a,b) func = jq:newFunction("test-thread",function(a,b)
THREAD.sleep(.2) THREAD.sleep(.2)
return a+b return a+b
end) end)
local count = 0 local count = 0
for i = 1,10 do for i = 1,10 do
func(i, i*3).OnReturn(function(data) func(i, i*3).OnReturn(function(data)
@ -134,6 +132,7 @@ multi:newThread("Scheduler Thread",function()
multi.success("SystemThreadedJobQueues: Ok") multi.success("SystemThreadedJobQueues: Ok")
queue2 = multi:newSystemThreadedQueue("Test_Queue2"):init() queue2 = multi:newSystemThreadedQueue("Test_Queue2"):init()
print(1)
multi:newSystemThread("Test_Thread_2",function() multi:newSystemThread("Test_Thread_2",function()
queue2 = THREAD.waitFor("Test_Queue2"):init() queue2 = THREAD.waitFor("Test_Queue2"):init()
connOut = THREAD.waitFor("ConnectionNAMEHERE"):init() connOut = THREAD.waitFor("ConnectionNAMEHERE"):init()
@ -142,7 +141,7 @@ multi:newThread("Scheduler Thread",function()
end) end)
multi:mainloop() multi:mainloop()
end).OnError(multi.error) end).OnError(multi.error)
print(2)
multi:newSystemThread("Test_Thread_3",function() multi:newSystemThread("Test_Thread_3",function()
queue2 = THREAD.waitFor("Test_Queue2"):init() queue2 = THREAD.waitFor("Test_Queue2"):init()
connOut = THREAD.waitFor("ConnectionNAMEHERE"):init() connOut = THREAD.waitFor("ConnectionNAMEHERE"):init()
@ -151,32 +150,35 @@ multi:newThread("Scheduler Thread",function()
end) end)
multi:mainloop() multi:mainloop()
end).OnError(multi.error) end).OnError(multi.error)
print(3)
connOut = multi:newSystemThreadedConnection("ConnectionNAMEHERE"):init() connOut = multi:newSystemThreadedConnection("ConnectionNAMEHERE"):init()
a=0 a=0
connOut(function(arg) connOut(function(arg)
queue2:push("Main") queue2:push("Main")
end) end)
print(4)
for i=1,3 do for i=1,3 do
thread.sleep(.1) thread.sleep(.1)
connOut:Fire("Test From Main Thread: "..i.."\n") connOut:Fire("Test From Main Thread: "..i.."\n")
end end
print(5)
thread.sleep(2) thread.sleep(2)
local count = 0 local count = 0
multi:newThread(function() multi:newThread(function()
while count < 9 do while count < 9 do
if queue2:pop() then if queue2:pop() then
count = count + 1 count = count + 1
print("Popped", count)
end end
end end
end).OnError(multi.error) end).OnError(multi.error)
print(6)
_, err = thread.hold(function() return count == 9 end,{sleep=.3}) _, err = thread.hold(function() return count == 9 end,{sleep=.3})
print(7)
if err == multi.TIMEOUT then if err == multi.TIMEOUT then
multi.error("SystemThreadedConnections: Failed") multi.error("SystemThreadedConnections: Failed")
end end
print(8)
multi.success("SystemThreadedConnections: Ok") multi.success("SystemThreadedConnections: Ok")
we_good = true we_good = true