reworking jobs

This commit is contained in:
Ryan Ward 2020-02-20 12:05:07 -05:00
parent 3f147443bc
commit f737516009
5 changed files with 204 additions and 851 deletions

View File

@ -4,6 +4,26 @@ Table of contents
--- ---
[Update 14.1.0 - A whole new world of possibilities](#update-1410---a-whole-new-world-of-possibilities)</br>[Update 14.0.0 - Consistency, Additions and Stability](#update-1400-consistency-additions-and-stability)</br>[Update 13.1.0 - Bug fixes and features added](#update-1310-bug-fixes-and-features-added)</br>[Update 13.0.0 - Added some documentation, and some new features too check it out!](#update-1300-added-some-documentation-and-some-new-features-too-check-it-out)</br>[Update 12.2.2 - Time for some more bug fixes!](#update-1222-time-for-some-more-bug-fixes)</br>[Update 12.2.1 - Time for some bug fixes!](#update-1221-time-for-some-bug-fixes)</br>[Update 12.2.0 - The chains of binding](#update-1220---the-chains-of-binding)</br>[Update 12.1.0 - Threads just can't hold on anymore](#update-1210---threads-just-cant-hold-on-anymore)</br>[Update: 12.0.0 - Big update (Lots of additions some changes)](#update-1200-big-update-lots-of-additions-some-changes)</br>[Update: 1.11.1 - Small Clarification on Love](#update-1111---small-clarification-on-love)</br>[Update: 1.11.0](#update-1110)</br>[Update: 1.10.0](#update-1100)</br>[Update: 1.9.2](#update-192)</br>[Update: 1.9.1 - Threads can now argue](#update-191---threads-can-now-argue)</br>[Update: 1.9.0](#update-190)</br>[Update: 1.8.7](#update-187)</br>[Update: 1.8.6](#update-186)</br>[Update: 1.8.5](#update-185)</br>[Update: 1.8.4](#update-184)</br>[Update: 1.8.3 - Mainloop recieves some needed overhauling](#update-183---mainloop-recieves-some-needed-overhauling)</br>[Update: 1.8.2](#update-182)</br>[Update: 1.8.1](#update-181)</br>[Update: 1.7.6](#update-176)</br>[Update: 1.7.5](#update-175)</br>[Update: 1.7.4](#update-174)</br>[Update: 1.7.3](#update-173)</br>[Update: 1.7.2](#update-172)</br>[Update: 1.7.1 - Bug Fixes Only](#update-171---bug-fixes-only)</br>[Update: 1.7.0 - Threading the systems](#update-170---threading-the-systems)</br>[Update: 1.6.0](#update-160)</br>[Update: 1.5.0](#update-150)</br>[Update: 1.4.1 (4/10/2017) - First Public release of the library](#update-141-4102017---first-public-release-of-the-library)</br>[Update: 1.4.0 (3/20/2017)](#update-140-3202017)</br>[Update: 1.3.0 (1/29/2017)](#update-130-1292017)</br>[Update: 1.2.0 (12.31.2016)](#update-120-12312016)</br>[Update: 1.1.0](#update-110)</br>[Update: 1.0.0](#update-100)</br>[Update: 0.6.3](#update-063)</br>[Update: 0.6.2](#update-062)</br>[Update: 0.6.1-6](#update-061-6)</br>[Update: 0.5.1-6](#update-051-6)</br>[Update: 0.4.1](#update-041)</br>[Update: 0.3.0 - The update that started it all](#update-030---the-update-that-started-it-all)</br>[Update: EventManager 2.0.0](#update-eventmanager-200)</br>[Update: EventManager 1.2.0](#update-eventmanager-120)</br>[Update: EventManager 1.1.0](#update-eventmanager-110)</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) [Update 14.1.0 - A whole new world of possibilities](#update-1410---a-whole-new-world-of-possibilities)</br>[Update 14.0.0 - Consistency, Additions and Stability](#update-1400-consistency-additions-and-stability)</br>[Update 13.1.0 - Bug fixes and features added](#update-1310-bug-fixes-and-features-added)</br>[Update 13.0.0 - Added some documentation, and some new features too check it out!](#update-1300-added-some-documentation-and-some-new-features-too-check-it-out)</br>[Update 12.2.2 - Time for some more bug fixes!](#update-1222-time-for-some-more-bug-fixes)</br>[Update 12.2.1 - Time for some bug fixes!](#update-1221-time-for-some-bug-fixes)</br>[Update 12.2.0 - The chains of binding](#update-1220---the-chains-of-binding)</br>[Update 12.1.0 - Threads just can't hold on anymore](#update-1210---threads-just-cant-hold-on-anymore)</br>[Update: 12.0.0 - Big update (Lots of additions some changes)](#update-1200-big-update-lots-of-additions-some-changes)</br>[Update: 1.11.1 - Small Clarification on Love](#update-1111---small-clarification-on-love)</br>[Update: 1.11.0](#update-1110)</br>[Update: 1.10.0](#update-1100)</br>[Update: 1.9.2](#update-192)</br>[Update: 1.9.1 - Threads can now argue](#update-191---threads-can-now-argue)</br>[Update: 1.9.0](#update-190)</br>[Update: 1.8.7](#update-187)</br>[Update: 1.8.6](#update-186)</br>[Update: 1.8.5](#update-185)</br>[Update: 1.8.4](#update-184)</br>[Update: 1.8.3 - Mainloop recieves some needed overhauling](#update-183---mainloop-recieves-some-needed-overhauling)</br>[Update: 1.8.2](#update-182)</br>[Update: 1.8.1](#update-181)</br>[Update: 1.7.6](#update-176)</br>[Update: 1.7.5](#update-175)</br>[Update: 1.7.4](#update-174)</br>[Update: 1.7.3](#update-173)</br>[Update: 1.7.2](#update-172)</br>[Update: 1.7.1 - Bug Fixes Only](#update-171---bug-fixes-only)</br>[Update: 1.7.0 - Threading the systems](#update-170---threading-the-systems)</br>[Update: 1.6.0](#update-160)</br>[Update: 1.5.0](#update-150)</br>[Update: 1.4.1 (4/10/2017) - First Public release of the library](#update-141-4102017---first-public-release-of-the-library)</br>[Update: 1.4.0 (3/20/2017)](#update-140-3202017)</br>[Update: 1.3.0 (1/29/2017)](#update-130-1292017)</br>[Update: 1.2.0 (12.31.2016)](#update-120-12312016)</br>[Update: 1.1.0](#update-110)</br>[Update: 1.0.0](#update-100)</br>[Update: 0.6.3](#update-063)</br>[Update: 0.6.2](#update-062)</br>[Update: 0.6.1-6](#update-061-6)</br>[Update: 0.5.1-6](#update-051-6)</br>[Update: 0.4.1](#update-041)</br>[Update: 0.3.0 - The update that started it all](#update-030---the-update-that-started-it-all)</br>[Update: EventManager 2.0.0](#update-eventmanager-200)</br>[Update: EventManager 1.2.0](#update-eventmanager-120)</br>[Update: EventManager 1.1.0](#update-eventmanager-110)</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)
# Update 14.2.0 - State Saving reworked!
Full Update Showcase
---
```lua
package.path="?.lua;?/init.lua;?.lua;"..package.path
local multi, thread = require("multi"):init()
GLOBAL,THREAD = require("multi.integration.lanesManager"):init()
```
Going Forward:
---
-
Added:
---
-
Changed:
---
-
Removed:
---
- multi:newTrigger() — Connections do everything this thing could do and more. I plan on removing bloat features from the library anyway
# Update 14.1.0 - A whole new world of possibilities # Update 14.1.0 - A whole new world of possibilities
Full Update Showcase Full Update Showcase
--- ---

View File

@ -21,7 +21,6 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
]] ]]
local bin = pcall(require,"bin")
local multi = {} local multi = {}
local clock = os.clock local clock = os.clock
local thread = {} local thread = {}
@ -42,9 +41,7 @@ multi.fps = 60
multi.Type = "mainprocess" multi.Type = "mainprocess"
multi.Rest = 0 multi.Rest = 0
multi._type = type multi._type = type
multi.Jobs = {}
multi.queue = {} multi.queue = {}
multi.jobUS = 2
multi.clock = os.clock multi.clock = os.clock
multi.time = os.time multi.time = os.time
multi.LinkedPath = multi multi.LinkedPath = multi
@ -198,6 +195,8 @@ function multi:setPriority(s)
elseif type(s)=='string' then elseif type(s)=='string' then
if s:lower()=='core' or s:lower()=='c' then if s:lower()=='core' or s:lower()=='c' then
self.Priority=self.Priority_Core self.Priority=self.Priority_Core
elseif s:lower()=="very high" or s:lower()=="vh" then
self.Priority=self.Priority_Very_High
elseif s:lower()=='high' or s:lower()=='h' then elseif s:lower()=='high' or s:lower()=='h' then
self.Priority=self.Priority_High self.Priority=self.Priority_High
elseif s:lower()=='above' or s:lower()=='a' then elseif s:lower()=='above' or s:lower()=='a' then
@ -208,6 +207,8 @@ function multi:setPriority(s)
self.Priority=self.Priority_Below_Normal self.Priority=self.Priority_Below_Normal
elseif s:lower()=='low' or s:lower()=='l' then elseif s:lower()=='low' or s:lower()=='l' then
self.Priority=self.Priority_Low self.Priority=self.Priority_Low
elseif s:lower()=="very low" or s:lower()=="vl" then
self.Priority=self.Priority_Very_Low
elseif s:lower()=='idle' or s:lower()=='i' then elseif s:lower()=='idle' or s:lower()=='i' then
self.Priority=self.Priority_Idle self.Priority=self.Priority_Idle
end end
@ -458,26 +459,6 @@ function multi:reallocate(o,n)
self.Active=true self.Active=true
end end
multi.Reallocate=multi.Reallocate multi.Reallocate=multi.Reallocate
function multi:setJobSpeed(n)
self.jobUS=n
return self
end
function multi:hasJobs()
return #self.Jobs>0,#self.Jobs
end
function multi:getJobs()
return #self.Jobs
end
function multi:removeJob(name)
local count = 0
for i=#self.Jobs,1,-1 do
if self.Jobs[i][2]==name then
table.remove(self.Jobs,i)
count = count + 1
end
end
return count
end
function multi:FreeMainEvent() function multi:FreeMainEvent()
self.func={} self.func={}
end end
@ -656,116 +637,6 @@ function multi:newBase(ins)
_tid = _tid + 1 _tid = _tid + 1
return c return c
end end
function multi:newProcessor(file)
if not(self.Type=='mainprocess') then error('Can only create an interface on the multi obj') return false end
local c = {}
setmetatable(c, self)
c.Parent=self
c.Active=true
c.func={}
c.Type='process'
c.Mainloop={}
c.Garbage={}
c.Children={}
c.Active=false
c.Rest=0
c.Jobs={}
c.queue={}
c.jobUS=2
c.l=self:newLoop(function(self,dt)
if self.link.Active then
c:uManager()
end
end)
c.l.link = c
c.l.Type = "processor"
function c:getController()
return c.l
end
function c:Start()
self.Active = true
return self
end
function c:Resume()
self.Active = false
return self
end
function c:setName(name)
c.l.Name = name
return self
end
function c:Pause()
if self.l then
self.l:Pause()
end
return self
end
function c:Remove()
if self.Type == "process" then
self:__Destroy()
self.l:Destroy()
else
self:__Destroy()
end
end
function c:Destroy()
if self == c then
self.l:Destroy()
else
for i = #c.Mainloop,1,-1 do
if c.Mainloop[i] == self then
table.remove(c.Mainloop,i)
break
end
end
end
end
if file then
self.Cself=c
loadstring('local process=multi.Cself '..io.open(file,'rb'):read('*all'))()
end
self:create(c)
return c
end
function multi:newTimer()
local c={}
c.Type='timer'
local time=0
local count=0
local paused=false
function c:Start()
time=os.clock()
return self
end
function c:Get()
if self:isPaused() then return time end
return (clock()-time)+count
end
function c:isPaused()
return paused
end
c.Reset=c.Start
function c:Pause()
time=self:Get()
paused=true
return self
end
function c:Resume()
paused=false
time=os.clock()-time
return self
end
function c:tofile(path)
local m=bin.new()
count=count+self:Get()
m:addBlock(self.Type)
m:addBlock(count)
m:tofile(path)
return self
end
self:create(c)
return c
end
function multi:newConnector() function multi:newConnector()
local c = {Type = "connector"} local c = {Type = "connector"}
return c return c
@ -773,6 +644,7 @@ end
local CRef = { local CRef = {
Fire = function() end Fire = function() end
} }
local ignoreconn = true
function multi:newConnection(protect,func,kill) function multi:newConnection(protect,func,kill)
local c={} local c={}
c.callback = func c.callback = func
@ -939,39 +811,121 @@ function multi:newConnection(protect,func,kill)
m:tofile(path) m:tofile(path)
return self return self
end end
if not(ignoreconn) then
multi:create(c)
end
return c return c
end end
multi.OnObjectCreated=multi:newConnection() multi.OnObjectCreated=multi:newConnection()
multi.OnObjectDestroyed=multi:newConnection() multi.OnObjectDestroyed=multi:newConnection()
function multi:newJob(func,name) ignoreconn = false
if not(self.Type=='mainprocess' or self.Type=='process') then error('Can only create an object on multi or an interface obj') return false end function multi:newProcessor(file)
if not(self.Type=='mainprocess') then error('Can only create an interface on the multi obj') return false end
local c = {} local c = {}
if self.Type=='process' then
setmetatable(c, self.Parent)
else
setmetatable(c, self) setmetatable(c, self)
end c.Parent=self
c.Active=true c.Active=true
c.func={} c.func={}
c.Parent=self c.Type='process'
c.Type='job' c.Mainloop={}
c.trigfunc=func or function() end c.Garbage={}
function c:Act() c.Children={}
self:trigfunc(self) c.Active=false
c.Rest=0
c.queue={}
c.l=self:newLoop(function(self,dt)
if self.link.Active then
c:uManager()
end end
table.insert(self.Jobs,{c,name})
if self.JobRunner==nil then
self.JobRunner=self:newAlarm(self.jobUS):setName("multi.jobHandler")
self.JobRunner:OnRing(function(self)
if #self.Parent.Jobs>0 then
if self.Parent.Jobs[1] then
self.Parent.Jobs[1][1]:Act()
table.remove(self.Parent.Jobs,1)
end
end
self:Reset(self.Parent.jobUS)
end) end)
c.l.link = c
c.l.Type = "processor"
function c:getController()
return c.l
end end
function c:Start()
self.Active = true
return self
end
function c:Resume()
self.Active = false
return self
end
function c:setName(name)
c.l.Name = name
return self
end
function c:Pause()
if self.l then
self.l:Pause()
end
return self
end
function c:Remove()
if self.Type == "process" then
self:__Destroy()
self.l:Destroy()
else
self:__Destroy()
end
end
function c:Destroy()
if self == c then
self.l:Destroy()
else
for i = #c.Mainloop,1,-1 do
if c.Mainloop[i] == self then
table.remove(c.Mainloop,i)
break
end
end
end
end
if file then
self.Cself=c
loadstring('local process=multi.Cself '..io.open(file,'rb'):read('*all'))()
end
self:create(c)
return c
end
function multi:newTimer()
local c={}
c.Type='timer'
local time=0
local count=0
local paused=false
function c:Start()
time=os.clock()
return self
end
function c:Get()
if self:isPaused() then return time end
return (clock()-time)+count
end
function c:isPaused()
return paused
end
c.Reset=c.Start
function c:Pause()
time=self:Get()
paused=true
return self
end
function c:Resume()
paused=false
time=os.clock()-time
return self
end
function c:tofile(path)
local m=bin.new()
count=count+self:Get()
m:addBlock(self.Type)
m:addBlock(count)
m:tofile(path)
return self
end
self:create(c)
return c
end end
function multi.nextStep(func) function multi.nextStep(func)
ncount = ncount+1 ncount = ncount+1
@ -1093,6 +1047,7 @@ end
function multi:newFunction(func) function multi:newFunction(func)
local c={} local c={}
c.func=func c.func=func
c.Type = "mfunc"
mt={ mt={
__index=multi, __index=multi,
__call=function(self,...) __call=function(self,...)
@ -1225,17 +1180,6 @@ end
function multi:setTimeout(func,t) function multi:setTimeout(func,t)
multi:newThread(function() thread.sleep(t) func() end) multi:newThread(function() thread.sleep(t) func() end)
end end
function multi:newTrigger(func)
local c={}
c.Type='trigger'
c.trigfunc=func or function() end
function c:Fire(...)
self:trigfunc(...)
return self
end
self:create(c)
return c
end
function multi:newTStep(start,reset,count,set) function multi:newTStep(start,reset,count,set)
local c=self:newBase() local c=self:newBase()
think=1 think=1
@ -1643,6 +1587,7 @@ function multi:newThread(name,func,...)
end end
c.creationTime = os.clock() c.creationTime = os.clock()
threadid = threadid + 1 threadid = threadid + 1
multi.create(multi,c)
return c return c
end end
function multi.initThreads(justThreads) function multi.initThreads(justThreads)
@ -1819,7 +1764,7 @@ function multi:newService(func) -- Priority managed threads
local time local time
local p = multi.Priority_Normal local p = multi.Priority_Normal
local ap local ap
local task local task = thread.sleep
local scheme = 1 local scheme = 1
function c.Start() function c.Start()
time = multi:newTimer() time = multi:newTimer()
@ -1881,8 +1826,45 @@ function multi:newService(func) -- Priority managed threads
p = pri p = pri
c.SetScheme(scheme) c.SetScheme(scheme)
end end
multi.create(multi,c)
return c return c
end end
multi.Jobs = multi:newService(function(self,jobs)
local job = table.remove(jobs,1)
if job and job.removed==nil then
job.func()
end
end)
multi.Jobs.OnStarted(function(self,jobs)
function self:newJob(func,name)
table.insert(jobs,{
func = func,
name = name,
removeJob = function(self) self.removed = true end
})
end
function self:getJobs(name)
local tab = {}
if not name then return jobs end
for i=1,#jobs do
if name == jobs[i].name then
table.insert(tab,jobs[i])
end
end
return tab
end
function self:removeJobs(name)
for i=1,#jobs do
if name ~= nil and name == jobs[i].name then
jobs[i]:removeJob()
elseif name == nil then
jobs[i]:removeJob()
end
end
end
end)
multi.Jobs.SetPriority(multi.Priority_Normal)
multi.Jobs.Start()
function multi:newThreadedProcess(name) function multi:newThreadedProcess(name)
local c = {} local c = {}
local holding = false local holding = false
@ -1911,9 +1893,7 @@ function multi:newThreadedProcess(name)
c.Rest=0 c.Rest=0
c.updaterate=.01 c.updaterate=.01
c.restRate=.1 c.restRate=.1
c.Jobs={}
c.queue={} c.queue={}
c.jobUS=2
c.rest=false c.rest=false
function c:getController() function c:getController()
return nil return nil
@ -1962,6 +1942,7 @@ function multi:newThreadedProcess(name)
c:uManager() c:uManager()
end end
end) end)
multi:create(c)
return c return c
end end
function multi:newHyperThreadedProcess(name) function multi:newHyperThreadedProcess(name)
@ -2008,9 +1989,7 @@ function multi:newHyperThreadedProcess(name)
c.Rest=0 c.Rest=0
c.updaterate=.01 c.updaterate=.01
c.restRate=.1 c.restRate=.1
c.Jobs={}
c.queue={} c.queue={}
c.jobUS=2
c.rest=false c.rest=false
function c:getController() function c:getController()
return nil return nil
@ -2052,6 +2031,7 @@ function multi:newHyperThreadedProcess(name)
return self return self
end end
c.Hold=c.Sleep c.Hold=c.Sleep
multi:create(c)
return c return c
end end
-- Multi runners -- Multi runners

View File

@ -21,37 +21,45 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
]] ]]
local bin = pcall(require,"bin")
if not bin then return error("The bin library is required to use sterilization!") end
local multi,thread = require("multi"):init() local multi,thread = require("multi"):init()
local sterilizer = {}
--------------------- ---------------------
-- State Saving Stuff -- State Saving Stuff
--------------------- ---------------------
function multi:IngoreObject() multi.OnObjectCreated(function(obj)
print(obj.Type)
end)
function IngoreObject()
-- Tells system to not sterilize this object -- Tells system to not sterilize this object
end end
function multi:ToString() function sterilizer:ToString()
-- Turns the object into a string -- Turns the object into a string
end end
function multi:newFromString(str) function sterilizer:newFromString(str)
-- Creates an object from string -- Creates an object from string
end end
function multi:ToFile(path) function sterilizer:ToFile(path)
-- Turns multi object into a string -- Turns multi object into a string
end end
function multi:fromFile(path) function sterilizer:fromFile(path)
-- Loads multi object form file -- Loads multi object form file
end end
function multi:SetStateFlag(opt) function sterilizer:SetStateFlag(opt)
-- manage the states -- manage the states
end end
function multi:quickStateSave(b) function sterilizer:quickStateSave(b)
-- enables quick state saving -- enables quick state saving
end end
function multi:saveState(path,opt) function sterilizer:saveState(path,opt)
-- Saves entire state to file -- Saves entire state to file
end end
function multi:loadState(path) function sterilizer:loadState(path)
-- Loads entire state from file -- Loads entire state from file
end end
function multi:setDefualtStateFlag(opt) function sterilizer:setDefualtStateFlag(opt)
-- sets the default flags for managing states -- sets the default flags for managing states
end end
return sterilizer

105
test.lua
View File

@ -1,100 +1,15 @@
package.path="?.lua;?/init.lua;?.lua;"..package.path package.path="?.lua;?/init.lua;?.lua;?/?/init.lua;"..package.path
local multi,thread = require("multi"):init() local multi,thread = require("multi"):init()
GLOBAL,THREAD = require("multi.integration.lanesManager"):init() --local sterilizer = require("multi.integration.sterilization")
serv = multi:newService(function(self,data) multi.Jobs:newJob(function()
print("Service Uptime: ",self:GetUpTime(),data.test) print("job called")
end) end)
serv.OnError(function(...) multi.Jobs:newJob(function()
print(...) print("job called2")
end) end)
serv.OnStarted(function(self,data) multi.Jobs:newJob(function()
print("Started!",self.Type,data) print("job called3")
data.test = "Testing..."
-- self as reference to the object and data is a reference to the datatable that the service has access to
end) end)
serv:Start() multi.Jobs.SetScheme(1)
serv:SetPriority(multi.Priority_Idle) multi.Jobs.SetPriority(multi.Priority_Core)
t = THREAD:newFunction(function(...)
print("This is a system threaded function!",...)
THREAD.sleep(1) -- This is handled within a system thread! Note: this creates a system thread that runs then ends.
return "We done!"
end)
print(t("hehe",1,2,3,true).connect(function(...)
print("connected:",...)
end)) -- The same features that work with thread:newFunction() are here as well
multi.OnLoad(function()
print("Code Loaded!") -- Connect to the load event
end)
t = os.clock()
co = 0
multi.OnExit(function(n)
print("Code Exited: ".. os.clock()-t .." Count: ".. co) -- Lets print when things have ended
end)
test = thread:newFunction(function()
thread.sleep(1) -- Internally this throws a yield call which sends to the scheduler to sleep 1 second for this thread!
return 1,math.random(2,100)
end)
multi:newThread(function()
while true do
thread.skip() -- Even though we have a few metamethods "yielding" I used this as an example of things still happening and counting. It connects to the Code Exited event later on.
co = co + 1
end
end)
-- We can get around the yielding across metamethods by using a threadedFunction
-- For Example
example = {}
setmetatable(example,{
__newindex = function(t,k,v) -- Using a threaded function inside of a normal function
print("Inside metamethod",t,k,v)
local a,b = test().wait() -- This function holds the code and "yields" see comment inside the test function!
-- we should see a 1 seconde delay since the function sleeps for a second than returns
print("We did it!",a,b)
rawset(t,k,v)
-- This means by using a threaded function we can get around the yielding across metamethods.
-- This is useful if you aren't using luajit, or if you using lua in an enviroment that is on version 5.1
-- There is a gotcha however, if using code that was meant to work with another coroutine based scheduler this may not work
end,
__index = thread:newFunction(function(t,k,v) -- Using a threaded function as the metamethod
-- This works by returning a table with a __call metamethod. Will this work? Will lua detect this as a function or a table?
thread.sleep(1)
return "You got a string"
end,true) -- Tell the code to force a wait. We need to do this for metamethods
})
example["test"] = "We set a variable!"
print(example["test"])
print(example.hi)
-- When not in a threaded enviroment at root level we need to tell the code that we are waiting! Alternitavely after the function argument we can pass true to force a wait
c,d = test().wait()
print(c,d)
a,b = 6,7
multi:newThread(function()
a,b = test().wait() -- Will modify Global
print("Waited:",a,b)
--This returns instantly even though the function isn't done!
print("called")
test().connect(function(a,b)
print("Connected:",a,b)
os.exit()
end)
print("Returned")
-- This waits for the returns since we are demanding them
end)
local test = multi:newSystemThreadedJobQueue(4) -- Load up a queue that has 4 running threads
func = test:newFunction("test",function(a) -- register a function on the queue that has an async function feature
test2() -- Call the other registered function on the queue
return a..a
end,true)
func2 = test:newFunction("test2",function(a)
print("ooo")
console = THREAD:getConsole()
console.print("Hello!",true)
end,true) -- When called internally on the job queue the function is a normal sync function and not an async function.
multi:scheduleJob({min = 15, hour = 14},function()
-- This function will be called once everyday at 2:15
-- Using a combination of the values above you are able to schedule a time
end)
print(func("1"))
print(func("Hello"))
print(func("sigh"))
multi:lightloop() multi:lightloop()

View File

@ -1,570 +0,0 @@
--------------------------------------------------------------------------------
-- A library for the manipulation of dates and periods according to the
-- Gregorian calendar.
--
-- Credit: the Gregorian calendar routines contained in this library are
-- ported from Claus Tøndering calendar algorithms:
-- http://www.tondering.dk/main/index.php/calendar-information .
--
-- Copyright (C) 2011-2016 Stefano Peluchetti. All rights reserved.
--------------------------------------------------------------------------------
local ffi = require "ffi"
local C = ffi.C
local format = string.format
local floor, min = math.floor, math.min
local type, new, istype, tonumber = type, ffi.new, ffi.istype, tonumber
local int64_ct = ffi.typeof("int64_t")
local function T_int(x)
if not (type(x) == "number" and x == floor(x)) then
error("integer number expected")
end
end
local function T_same(x, y)
if not istype(x, y) then
error("same type expected")
end
end
-- Period ----------------------------------------------------------------------
-- Return string representation for a positive period.
local function posptostr(h, m, s, ms)
return format("%02i:%02i:%02i.%06i", h, m, s, ms)
end
local p_ct
local function T_period(x)
if not istype(p_ct, x) then
error("period expected")
end
end
local function p_64(ticks)
return new(p_ct, ticks)
end
local function pfirst(x, y)
if istype(p_ct, y) then
return y, x
else
return x, y
end
end
local p_mt = {
__new = function(ct, h, m, s, ms)
h = h or 0; m = m or 0; s = s or 0; ms = ms or 0;
T_int(h); T_int(m); T_int(s); T_int(ms);
return new(ct, h*(1e6*60*60LL)+m*(1e6*60LL)+s*(1e6*1LL)+ms)
end,
copy = function(self)
return new(p_ct, self)
end,
__eq = function(self, rhs) T_same(self, rhs)
return self._ticks == rhs._ticks
end,
__lt = function(self, rhs) T_same(self, rhs)
return self._ticks < rhs._ticks
end,
__le = function(self, rhs) T_same(self, rhs)
return self._ticks <= rhs._ticks
end,
__add = function(self, rhs) T_same(self, rhs) -- Commutative.
return p_64(self._ticks + rhs._ticks)
end,
__sub = function(self, rhs) T_same(self, rhs)
return p_64(self._ticks - rhs._ticks)
end,
__unm = function(self)
return p_64(-self._ticks)
end,
__mul = function(self, rhs) -- Commutative.
local p, n = pfirst(self, rhs)
T_int(n)
return p_64(p._ticks*n)
end,
-- Approximate ratio, non-reversible in both cases.
__div = function(self, rhs)
T_period(self) -- Disallow (not-a-period)/period.
if type(rhs) == "number" then
return p_64(self._ticks/rhs)
elseif istype(p_ct, rhs) then
return tonumber(self._ticks)/tonumber(rhs._ticks)
else
error("unexpected type")
end
end,
__tostring = function(self)
local h, m, s, ms = self:parts()
if self._ticks >= 0 then
return posptostr(h, m, s, ms)
else
return "-"..posptostr(-h, -m, -s, -ms)
end
end,
ticks = function(self) -- Expose int64_t.
return self._ticks
end,
microseconds = function(self)
return tonumber(self._ticks%1e6)
end,
seconds = function(self)
return tonumber((self._ticks/1e6)%60)
end,
minutes = function(self)
return tonumber((self._ticks/(1e6*60))%60)
end,
hours = function(self)
return tonumber(self._ticks/(1e6*60*60))
end,
parts = function(self)
return self:hours(), self:minutes(), self:seconds(), self:microseconds()
end,
tomicroseconds = function(self)
return tonumber(self._ticks)
end,
tomilliseconds = function(self)
return tonumber(self._ticks)/1e3
end,
toseconds = function(self)
return tonumber(self._ticks)/1e6
end,
tominutes = function(self)
return tonumber(self._ticks)/(1e6*60)
end,
tohours = function(self)
return tonumber(self._ticks)/(1e6*60*60)
end,
}
p_mt.__index = p_mt
p_ct = ffi.metatype("struct { int64_t _ticks; }", p_mt)
local function weeks(x) T_int(x) return p_64(x*(1e6*60*60*24*7LL)) end
local function days(x) T_int(x) return p_64(x*(1e6*60*60*24LL)) end
local function hours(x) T_int(x) return p_64(x*(1e6*60*60LL)) end
local function minutes(x) T_int(x) return p_64(x*(1e6*60LL)) end
local function seconds(x) T_int(x) return p_64(x*(1e6*1LL)) end
local function milliseconds(x) T_int(x) return p_64(x*(1e3*1LL)) end
local function microseconds(x) T_int(x) return p_64(x*1LL) end
local function toperiod(x)
if type(x) == "string" then
local f1, l1, h, m, s, ms = x:find("(%d+):(%d+):(%d+).(%d+)")
if h == nil or ms == nil or l1 ~= #x then
error("'"..x.."' is not a string representation of a period")
end
local ton = tonumber
return p_ct(ton(h), ton(m), ton(s), ton(ms))
elseif istype(int64_ct, x) then
return p_64(x)
else
error("unexpected type")
end
end
-- Months ----------------------------------------------------------------------
local months_mt = {
__new = function(ct, x) T_int(x)
return new(ct, x)
end,
}
local months_ct = ffi.metatype("struct { int32_t _m; }", months_mt)
-- Years -----------------------------------------------------------------------
local years_mt = {
__new = function(ct, x) T_int(x)
return new(ct, x)
end,
}
local years_ct = ffi.metatype("struct { int32_t _y; }", years_mt)
-- Date ------------------------------------------------------------------------
-- It's date(1582, 1, 1):
local d_ticks_min = 198622713600000000LL
-- It's date(9999,12,31) + period(23, 59, 59, 999999):
local d_ticks_max = 464269103999999999LL
local d_ct
local function T_date(x)
if not istype(d_ct, x) then
error("date expected")
end
end
local function T_date_range(ticks)
if not (d_ticks_min <= ticks and ticks <= d_ticks_max) then
error("resulting date is outside the allowed range")
end
end
local function d_64(ticks) T_date_range(ticks)
return new(d_ct, ticks)
end
local function dfirst(x, y)
if istype(d_ct, y) then
return y, x
else
return x, y
end
end
-- 1582 adoption, 9999 to keep 4 chars for years part:
local function T_year(year) T_int(year)
if not (1582 <= year and year <= 9999) then
error("year "..year.." outside the allowed range [1582, 9999]")
end
end
local function T_month(month) T_int(month)
if not (1 <= month and month <= 12) then
error("month "..month.." outside the allowed range [1, 12]")
end
end
local function isleapyear(year) T_year(year)
return year%4 == 0 and (year%100 ~= 0 or year%400 == 0)
end
local eom = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
local function endofmonth(year, month) T_year(year) T_month(month)
return (month == 2 and isleapyear(year)) and 29 or eom[month]
end
local function T_day(year, month, day)
if not (1 <= day and day <= endofmonth(year, month)) then
error(year.."-"..month.."-"..day.." is not a valid date")
end
end
local function weekday(year, month, day) T_year(year) T_month(month)
T_day(year, month, day)
local a = floor((14 - month)/12)
local y = year - a
local m = month + 12*a - 2
local d = (day + y + floor(y/4) - floor(y/100) + floor(y/400) +
floor((31*m)/12)) % 7
return d == 0 and 7 or d -- Days of week from 1 = Monday to 7 = Sunday.
end
local function shift_months(y, m, deltam)
local newm = (m - 1 + deltam) % 12 + 1
local newy = y + floor((m - 1 + deltam)/12)
T_year(newy)
T_month(newm)
return newy, newm
end
local function ymd_to_julian(year, month, day)
-- Range of numbers suffices for this:
local a = floor((14 - month)/12)
local y = year + 4800 - a
local m = month + 12*a - 3
return day + floor((153*m + 2)/5) + 365*y + floor(y/4) - floor(y/100) +
floor(y/400) - 32045
end
local function julian_to_ymd(julian)
-- Range of numbers suffices for this:
local a = julian + 32044
local b = floor((4*a + 3)/146097)
local c = a - floor((146097*b)/4)
local d = floor((4*c + 3)/1461)
local e = c - floor((1461*d)/4)
local m = floor((5*e + 2)/153)
local day = e - floor((153*m + 2)/5) + 1
local month = m + 3 - 12*floor(m/10)
local year = 100*b + d - 4800 + floor(m/10)
return year, month, day
end
-- Assumes only violation of valid date may be in day outside of end of month
-- due to months and years shifts. Cap the day and returns a valid date.
local function valid_date_cap_day(year, month, day)
day = min(day, endofmonth(year, month))
return d_ct(year, month, day)
end
local d_mt = {
__new = function(ct, year, month, day) T_year(year) T_month(month)
T_day(year, month, day)
return new(ct, ymd_to_julian(year, month, day)*(86400LL*1e6))
end,
copy = function(self)
return new(d_ct, self)
end,
__eq = p_mt.__eq,
__lt = p_mt.__lt,
__le = p_mt.__le,
__add = function(self, rhs) -- Commutative.
local d, s = dfirst(self, rhs)
if istype(p_ct, s) then
return d_64(d._ticks + s._ticks)
elseif istype(months_ct, s) then
local year, month, day = d:ymd()
year, month = shift_months(year, month, s._m)
return valid_date_cap_day(year, month, day) + d:period()
elseif istype(years_ct, s) then
local year, month, day = d:ymd()
year = year + s._y
return valid_date_cap_day(year, month, day) + d:period()
else
error("unexpected type")
end
end,
__sub = function(self, rhs)
T_date(self) -- Disallow (not-a-date)-date.
if istype(p_ct, rhs) then
return d_64(self._ticks - rhs._ticks)
elseif istype(months_ct, rhs) then
local year, month, day = self:ymd()
year, month = shift_months(year, month, -rhs._m)
return valid_date_cap_day(year, month, day) + self:period()
elseif istype(years_ct, rhs) then
local year, month, day = self:ymd()
year = year - rhs._y
return valid_date_cap_day(year, month, day) + self:period()
elseif istype(d_ct, rhs) then
return p_64(self._ticks - rhs._ticks)
else
error("unexpected type")
end
end,
__tostring = function(self)
local year, month, day = self:ymd()
local h, m, s, ms = self:period():parts()
return format("%i-%02i-%02iT", year, month, day)..posptostr(h, m, s, ms)
end,
ticks = p_mt.ticks,
ymd = function(self)
local julian = tonumber(self._ticks/(86400LL*1e6))
return julian_to_ymd(julian)
end,
year = function(self) local y, m, d = self:ymd() return y end,
month = function(self) local y, m, d = self:ymd() return m end,
day = function(self) local y, m, d = self:ymd() return d end,
period = function(self)
return p_64(self._ticks%(86400LL*1e6))
end,
isleapyear = function(self)
local y = self:ymd()
return isleapyear(y)
end,
endofmonth = function(self)
local y, m = self:ymd()
return endofmonth(y, m)
end,
weekday = function(self)
local y, m, d = self:ymd()
return weekday(y, m, d)
end,
}
d_mt.__index = d_mt
d_ct = ffi.metatype("struct { int64_t _ticks; }", d_mt)
local function todate(x)
if type(x) == "string" then
local f1, l1, year, month, day, h, m, s, ms =
x:find("(%d+)-(%d+)-(%d+)T(%d+):(%d+):(%d+).(%d+)")
if year == nil or ms == nil or l1 ~= #x then
error("'"..x.."' is not a string representation of a date")
end
local ton = tonumber
return d_ct(ton(year), ton(month), ton(day)) +
p_ct(ton(h), ton(m), ton(s), ton(ms))
elseif istype(int64_ct, x) then
return d_64(x)
else
error("unexpected type")
end
end
-- System-dependent functions --------------------------------------------------
local nowlocal, nowutc, sleep
if jit.os == "Windows" then -- On Windows sizeof(long) == 4 on both x86 and x64.
ffi.cdef[[
typedef unsigned long DWORD;
typedef unsigned short WORD;
typedef unsigned __int64 ULONGLONG;
typedef struct _SYSTEMTIME {
WORD wYear;
WORD wMonth;
WORD wDayOfWeek;
WORD wDay;
WORD wHour;
WORD wMinute;
WORD wSecond;
WORD wMilliseconds;
} SYSTEMTIME, *PSYSTEMTIME;
typedef union _ULARGE_INTEGER {
struct {
DWORD LowPart;
DWORD HighPart;
};
struct {
DWORD LowPart;
DWORD HighPart;
} u;
ULONGLONG QuadPart;
} ULARGE_INTEGER, *PULARGE_INTEGER;
typedef struct _FILETIME {
DWORD dwLowDateTime;
DWORD dwHighDateTime;
} FILETIME, *PFILETIME;
void GetLocalTime(
PSYSTEMTIME lpSystemTime
);
//void GetSystemTime(
// PSYSTEMTIME lpSystemTime
//);
void GetSystemTimeAsFileTime(
PFILETIME lpSystemTimeAsFileTime
);
void GetSystemTimeAsPreciseFileTime(
PFILETIME lpSystemTimeAsFileTime
);
void Sleep(
DWORD dwMilliseconds
);
]]
local st = ffi.new("SYSTEMTIME")
local ft = ffi.new("FILETIME")
local ul = ffi.new("ULARGE_INTEGER")
nowlocal = function()
C.GetLocalTime(st)
return d_ct(st.wYear, st.wMonth, st.wDay) + p_ct(st.wHour, st.wMinute,
st.wSecond, st.wMilliseconds*1000)
end
local epoch_offset = d_ct(1601, 1, 1):ticks()
local function if_available(lib, fname)
local ok, f = pcall(function() return lib[fname] end)
return ok and f
end
local get_system_time = if_available(C, 'GetSystemTimeAsPreciseFileTime')
or C.GetSystemTimeAsFileTime
nowutc = function()
-- Resolution: 1 microsecond.
-- Accuracy : 1 millisecond up to Windows 7, higher otherwise.
get_system_time(ft)
ul.LowPart = ft.dwLowDateTime
ul.HighPart = ft.dwHighDateTime
return new(d_ct, epoch_offset + ul.QuadPart/10)
end
sleep = function(p)
if p < p_ct() then
error("cannot sleep a negative amount of time")
end
C.Sleep(p:ticks()/1000)
end
else -- Linux and OSX.
ffi.cdef[[
typedef long time_t;
typedef int useconds_t;
typedef struct timeval {
long tv_sec;
int tv_usec;
} timeval;
typedef struct tm {
int tm_sec;
int tm_min;
int tm_hour;
int tm_mday;
int tm_mon;
int tm_year;
int tm_wday;
int tm_yday;
int tm_isdst;
long tm_gmtoff;
char *tm_zone;
} tm;
int gettimeofday(
struct timeval * restrict,
void * restrict
);
struct tm *localtime(
const time_t *
);
int usleep(
useconds_t useconds
);
]]
-- C.host_get_clock_service it's slower and we don't need higher resolution.
-- C.mach_absolute_time does not report real clock.
local epoch_offset = d_ct(1970, 1, 1):ticks()
local tv = ffi.new("timeval[1]")
local tt = ffi.new("time_t[1]")
nowlocal = function()
C.gettimeofday(tv, nil)
tt[0] = tv[0].tv_sec
local tm = C.localtime(tt)
return d_ct(1900 + tm.tm_year, 1 + tm.tm_mon, tm.tm_mday) +
p_ct(tm.tm_hour, tm.tm_min, tm.tm_sec, tv[0].tv_usec)
end
nowutc = function()
-- Resolution: 1 microsecond.
-- Accuracy : 1 microsecond.
C.gettimeofday(tv, nil)
return new(d_ct, epoch_offset + tv[0].tv_sec*1000000LL + tv[0].tv_usec)
end
sleep = function(p)
if p < p_ct() then
error("cannot sleep a negative amount of time")
end
C.usleep(p:ticks())
end
end
return {
period = p_ct,
toperiod = toperiod,
weeks = weeks,
days = days,
hours = hours,
minutes = minutes,
seconds = seconds,
milliseconds = milliseconds,
microseconds = microseconds,
date = d_ct,
todate = todate,
isleapyear = isleapyear,
endofmonth = endofmonth,
weekday = weekday,
months = months_ct,
years = years_ct,
sleep = sleep,
nowlocal = nowlocal,
nowutc = nowutc,
}