Files
coa-tsm/TradeSkillMaster/Core/Threading.lua
T
Andrew6810 f3e579cb57 init
2022-11-05 21:19:42 -07:00

113 lines
3.4 KiB
Lua

-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster --
-- http://www.curse.com/addons/wow/tradeskill-master --
-- --
-- A TradeSkillMaster Addon (http://tradeskillmaster.com) --
-- All Rights Reserved* - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
-- This file contains code for running stuff in a pseudo-thread
local TSM = select(2, ...)
local private = {frames={}, threads={}}
TSMAPI:RegisterForTracing(private, "TradeSkillMaster.Threading_private")
TSMAPI.Threading = {}
local STATUS_YIELD = {}
local STATUS_DEAD = {}
local MAX_QUANTUM = 50
local ThreadPrototype = {
Resume = function(self, runTime)
self._endTime = debugprofilestop() + runTime
local noErr, status = coroutine.resume(self._co, self, self._param)
if noErr then
return status
else
-- throw error in delay so we don't kill this execution path
TSMAPI:CreateTimeDelay(0, function() error(status) end)
return STATUS_DEAD
end
end,
Yield = function(self, force)
local currentTime = debugprofilestop()
if force or currentTime > self._endTime then
coroutine.yield(STATUS_YIELD)
end
end,
Sleep = function(self, seconds)
self._sleeping = seconds
coroutine.yield(STATUS_YIELD)
end,
}
local quantums = {}
function private.RunScheduler(_, elapsed)
-- deal with sleeping threads and try and assign requested quantums
local totalTime = min(elapsed * 1000, MAX_QUANTUM)
local usedTime = 0
for i, thread in ipairs(private.threads) do
if thread._sleeping then
thread._sleeping = thread._sleeping - elapsed
if thread._sleeping <= 0 then
thread._sleeping = nil
end
end
quantums[i] = thread._sleeping and 0 or (thread._percent * totalTime)
usedTime = usedTime + quantums[i]
end
-- scale everything down if the total is > the total time
if usedTime > totalTime then
for i=1, #quantums do
quantums[i] = quantums[i] * (totalTime / usedTime)
end
end
-- run the threads that aren't sleeping
for i, thread in ipairs(private.threads) do
if quantums[i] > 0 then
-- resume running for a quantum based on its percent
local status = thread:Resume(quantums[i])
if status ~= STATUS_YIELD then
tremove(private.threads, i)
if thread._callback and status ~= STATUS_DEAD then thread._callback() end
end
end
end
end
function TSMAPI.Threading:Start(func, percent, callback, param)
local thread = CopyTable(ThreadPrototype)
thread._co = coroutine.create(func)
thread._percent = percent
thread._callback = callback
thread._param = param
thread._sleeping = nil
tinsert(private.threads, thread)
end
do
local frame = CreateFrame("Frame")
frame:SetScript("OnUpdate", private.RunScheduler)
end
-- -- EXAMPLE USAGE:
-- local function TestFunc(self, letter)
-- for i = 1, 10 do
-- self:Sleep(1)
-- print(letter, i)
-- if letter == "B" and i == 10 then print(_G[i].nonExistant) end
-- end
-- end
-- function TSMTest()
-- local start = GetTime()
-- TSMAPI.Threading:Start(TestFunc, 1, function() print("DONE", GetTime()-start) end, "A")
-- TSMAPI.Threading:Start(TestFunc, 1, function() print("DONE", GetTime()-start) end, "B")
-- end