Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add multithreading to FiOne #1545

Merged
merged 17 commits into from
Nov 12, 2024
6 changes: 6 additions & 0 deletions MainModule/Server/Shared/FiOne/LocalRunner.meta.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"properties": {
"RunContext": "Client",
"Disabled": true
}
}
21 changes: 21 additions & 0 deletions MainModule/Server/Shared/FiOne/LocalRunner.server.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
--!native
--!optimize 2
--[[
Description: Wrapper for FiOne multithread closures
Author: github@ccuser44
Date: 2024
License: CC0
]]

local fiOne = require(script.FiOne)
local actor = script.Parent
local event = script.ReturnPass
local callback = function(...) return ... end

actor:BindToMessage("wrap_state", function(proto, env, upval)
callback = fiOne.wrap_state(proto, env, upval)
end)

actor:BindToMessageParallel("run_callback", function(tag, ...)
event:Fire(tag, pcall(callback, ...))
end)
5 changes: 5 additions & 0 deletions MainModule/Server/Shared/FiOne/Runner.meta.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"properties": {
"Disabled": true
}
}
21 changes: 21 additions & 0 deletions MainModule/Server/Shared/FiOne/Runner.server.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
--!native
--!optimize 2
--[[
Description: Wrapper for FiOne multithread closures
Author: github@ccuser44
Date: 2024
License: CC0
]]

local fiOne = require(script.FiOne)
local actor = script.Parent
local event = script.ReturnPass
local callback = function(...) return ... end

actor:BindToMessage("wrap_state", function(proto, env, upval)
callback = fiOne.wrap_state(proto, env, upval)
end)

actor:BindToMessageParallel("run_callback", function(tag, ...)
event:Fire(tag, pcall(callback, ...))
end)
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
--!native
--!nolint TableOperations
--# selene: allow(divide_by_zero, multiple_statements, mixed_table)
--[[
FiOne
Expand Down Expand Up @@ -460,6 +461,59 @@ local function on_lua_error(failed, err)
error(string.format("%s:%i: %s", src, line, err), 0)
end

-- ccuser44 added multithreading support
-- TODO: Create multiple threads for closure and use a module and/or round robin load balancer to distribute usage
local isClient, actorContainer
local function new_threaded_closure(proto, env, upval)
isClient = isClient or game:GetService("RunService"):IsClient()
actorContainer = actorContainer or script
local actor = Instance.new("Actor")
local clone = script:Clone()
local runner = script[isClient and "LocalRunner" or "Runner"]:Clone()
local event = Instance.new("BindableEvent")
local tag = 0

for _, v in clone:GetChildren() do
if v:IsA("Actor") then
v:Destroy()
end
end

event.Name = "ReturnPass"
event.Parent = runner
clone.Parent = runner
runner.Disabled = false
runner.Parent = actor
actor.Name = "MultithreadRunner_"..tostring(math.random())
actor.Parent = actorContainer

task.defer(actor.SendMessage, actor, "wrap_state", proto, env, upval)

task.wait()

return function(...)
tag = tag + 1
local currentTag = tag
local routine = coroutine.running()
local connection = event.Event:Connect(function(eventTag, ...)
if eventTag == currentTag then
coroutine.resume(routine, ...)
end
end)

task.defer(actor.SendMessage, actor, "run_callback", currentTag, ...)

local args = table.pack(coroutine.yield())
connection:Disconnect()

if not args[1] then
error(args[2], 2)
end

return table.unpack(args, 2)
end
end

local function run_lua_func(state, env, upvals)
local code = state.code
local subs = state.subs
Expand Down Expand Up @@ -854,7 +908,7 @@ local function run_lua_func(state, env, upvals)
pc = pc + nups
end

memory[inst.A] = lua_wrap_state(sub, env, uvlist)
memory[inst.A] = (sub.source and string.sub(sub.source, 1, 39) == "SUPER_SECRET_ADONIS_MULTITHREAD_PREFIX_") and new_threaded_closure(sub, env, uvlist) or lua_wrap_state(sub, env, uvlist)
else
--[[TESTSET]]
local A = inst.A
Expand Down
Loading