Added better priority management
This commit is contained in:
parent
21aed09d6d
commit
8db42e19f9
24
PManager.txt
24
PManager.txt
@ -1,10 +1,10 @@
|
|||||||
C: 2731526 ~I*7
|
C: 3322269 ~I*7
|
||||||
H: 2341308 ~I*6
|
H: 2847660 ~I*6
|
||||||
A: 1951090 ~I*5
|
A: 2373050 ~I*5
|
||||||
N: 1560872 ~I*4
|
N: 1898440 ~I*4
|
||||||
B: 1170655 ~I*3
|
B: 1423830 ~I*3
|
||||||
L: 780438 ~I*2
|
L: 949220 ~I*2
|
||||||
I: 390219 ~I
|
I: 474610 ~I
|
||||||
~n=I*PRank
|
~n=I*PRank
|
||||||
|
|
||||||
P2
|
P2
|
||||||
@ -17,3 +17,13 @@ B: 26175
|
|||||||
L: 6543
|
L: 6543
|
||||||
I: 1635
|
I: 1635
|
||||||
~n=n*4
|
~n=n*4
|
||||||
|
|
||||||
|
P3
|
||||||
|
----------------
|
||||||
|
C: 2120906
|
||||||
|
H: 2120906
|
||||||
|
A: 2120906
|
||||||
|
N: 2120906
|
||||||
|
B: 2120906
|
||||||
|
L: 2120906
|
||||||
|
I: 2120506
|
||||||
74
changes.md
74
changes.md
@ -1,5 +1,76 @@
|
|||||||
#Changes
|
#Changes
|
||||||
[TOC]
|
[TOC]
|
||||||
|
Update 12.2.0
|
||||||
|
-------------
|
||||||
|
**Added:**
|
||||||
|
- multi.nextStep(func)
|
||||||
|
- Method chaining
|
||||||
|
- Priority 3 has been added!
|
||||||
|
- ResetPriority() -- This will set a flag for a process to be re evaluated for how much of an impact it is having on the performance of the system.
|
||||||
|
- setting: auto_priority added! -- If only lua os.clock was more fine tuned... milliseconds are not enough for this to work
|
||||||
|
- setting: auto_lowerbound added! -- when using auto_priority this will allow you to set the lowbound for pirority. The defualt is a hyrid value that was calculated to reach the max potential with a delay of .001, but can be changed to whatever. Remember this is set to processes that preform really badly! If lua could handle more detail in regards to os.clock() then i would set the value a bit lower like .0005 or something like that
|
||||||
|
- setting: auto_stretch added! -- This is another way to modify the extent of the lowest setting. This reduces the impact that a low preforming process has! Setting this higher reduces the number of times that a process is called. Only in effect when using auto_priotity
|
||||||
|
- setting: auto_delay added! -- sets the time in seconds that the system will recheck for low performing processes and manage them. Will also upgrade a process if it starts to run better.
|
||||||
|
```lua
|
||||||
|
-- All methods that did not return before now return a copy of itself. Thus allowing chaining. Most if not all mutators returned nil, so chaining can now be done. I will eventually write up a full documentation of everything which will show this.
|
||||||
|
multi = require("multi")
|
||||||
|
multi:newStep(1,100):OnStep(function(self,i)
|
||||||
|
print("Index: "..i)
|
||||||
|
end):OnEnd(function(self)
|
||||||
|
print("Step is done!")
|
||||||
|
end)
|
||||||
|
multi:mainloop{
|
||||||
|
priority = 3
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Priority 3 works a bit differently than the other 2.
|
||||||
|
|
||||||
|
P1 follows a forumla that resembles this: ~n=I*PRank where n is the amount of steps given to an object with PRank and where I is the idle time see chart below. The aim of this priority scheme was to make core objects run fastest while letting idle processes get decent time as well.
|
||||||
|
```
|
||||||
|
C: 3322269 ~I*7
|
||||||
|
H: 2847660 ~I*6
|
||||||
|
A: 2373050 ~I*5
|
||||||
|
N: 1898440 ~I*4
|
||||||
|
B: 1423830 ~I*3
|
||||||
|
L: 949220 ~I*2
|
||||||
|
I: 474610 ~I
|
||||||
|
~n=I*PRank
|
||||||
|
```
|
||||||
|
P2 follows a formula that resembles this: ~n=n*4 where n is the idle time, see chart below. The goal of this one was to make core process' higher while keeping idle process' low.
|
||||||
|
```
|
||||||
|
C: 6700821
|
||||||
|
H: 1675205
|
||||||
|
A: 418801
|
||||||
|
N: 104700
|
||||||
|
B: 26175
|
||||||
|
L: 6543
|
||||||
|
I: 1635
|
||||||
|
~n=n*4
|
||||||
|
```
|
||||||
|
P3 Ignores using a basic funceion and instead bases its processing time on the amount of cpu time is there. If cpu-time is low and a process is set at a lower priority it will get its time reduced. There is no formula, at idle almost all process work at the same speed!
|
||||||
|
```
|
||||||
|
C: 2120906
|
||||||
|
H: 2120906
|
||||||
|
A: 2120906
|
||||||
|
N: 2120906
|
||||||
|
B: 2120906
|
||||||
|
L: 2120906
|
||||||
|
I: 2120506
|
||||||
|
```
|
||||||
|
|
||||||
|
Auto Priority works by seeing what should be set high or low. Due to lua not having more persicion than milliseconds, I was unable to have a detailed manager that can set things to high, above normal, normal, ect. This has either high or low. If a process takes longer than .001 millisecond it will be set to low priority. You can change this by using the setting auto_lowest = multi.Priority_[PLevel] the defualt is low, not idle, since idle tends to get about 1 process each second though you can change it to idle using that setting.
|
||||||
|
|
||||||
|
**Improved:**
|
||||||
|
- Performance at the base level has been doubled! On my machine benchmark went from ~9mil to ~20 mil steps/s.
|
||||||
|
Note: If you write slow code this library's improbements wont make much of a difference.
|
||||||
|
- Loops have been optimised as well! Being the most used objects I felt they needed to be made as fast as possible
|
||||||
|
|
||||||
|
I usually give an example of the changes made, but this time I have an explantion for multi.nextStep(). It's not an entirely new feature since multi:newJob() does something like this, but is completely different. nextStep addes a function that is executed first on the next step. If multiple things are added to next step, then they will be executed in the order that they were added.
|
||||||
|
|
||||||
|
Note:
|
||||||
|
The upper limit of this libraries performance on my machine is ~39mil. This is simply a while loop counting up from 0 and stops after 1 second. The 20mil that I am currently getting is probably as fast as it can get since its half of the max performance possible, and each layer I have noticed that it doubles complexity. Throughout the years with this library I have seen massive improvements in speed. In the beginning we had only ~2000 steps per second. Fast right? then after some tweaks we went to about 300000 steps per second, then 600000. Some more tweaks brought me to ~1mil steps per second, then to ~4 mil then ~9 mil and now finally ~20 mil... the doubling effect that i have now been seeing means that odds are I have reach the limit. I will aim to add more features and optimize individule objects. If its possible to make the library even faster then I will go for it.
|
||||||
|
|
||||||
|
|
||||||
Update 12.1.0
|
Update 12.1.0
|
||||||
-------------
|
-------------
|
||||||
Fixed:
|
Fixed:
|
||||||
@ -35,7 +106,8 @@ Contunue to make small changes as I come about them. This change was inspired wh
|
|||||||
|
|
||||||
Update: 12.0.0 Big update (Lots of additions some changes)
|
Update: 12.0.0 Big update (Lots of additions some changes)
|
||||||
------------------------
|
------------------------
|
||||||
**Note:** ~~After doing some testing, I have noticed that using multi-objects are slightly, quite a bit, faster than using (coroutines)multi:newthread(). Only create a thread if there is no other possibility! System threads are different and will improve performance if you know what you are doing. Using a (coroutine)thread as a loop with a timer is slower than using a TLoop! If you do not need the holding features I strongly recommend that you use the multi-objects. This could be due to the scheduler that I am using, and I am looking into improving the performance of the scheduler for (coroutine)threads. This is still a work in progress so expect things to only get better as time passes!~~ This was the reason threadloop was added. It binds the thread scheduler into the mainloop allowing threads to run much faster than before. Also the use of locals is now possible since I am not dealing with seperate objects. And finally, reduced function overhead help keeps the threads running better.
|
**Note:** ~~After doing some testing, I have noticed that using multi-objects are slightly, quite a bit, faster than using (coroutines)multi:newthread(). Only create a thread if there is no other possibility! System threads are different and will improve performance if you know what you are doing. Using a (coroutine)thread as a loop with a
|
||||||
|
is slower than using a TLoop! If you do not need the holding features I strongly recommend that you use the multi-objects. This could be due to the scheduler that I am using, and I am looking into improving the performance of the scheduler for (coroutine)threads. This is still a work in progress so expect things to only get better as time passes!~~ This was the reason threadloop was added. It binds the thread scheduler into the mainloop allowing threads to run much faster than before. Also the use of locals is now possible since I am not dealing with seperate objects. And finally, reduced function overhead help keeps the threads running better.
|
||||||
|
|
||||||
#Added:
|
#Added:
|
||||||
- `nGLOBAL = require("multi.integration.networkManager").init()`
|
- `nGLOBAL = require("multi.integration.networkManager").init()`
|
||||||
|
|||||||
423
multi/init.lua
423
multi/init.lua
@ -23,8 +23,9 @@ SOFTWARE.
|
|||||||
]]
|
]]
|
||||||
local bin = pcall(require,"bin")
|
local bin = pcall(require,"bin")
|
||||||
local multi = {}
|
local multi = {}
|
||||||
multi.Version = "12.0.0"
|
local clock = os.clock
|
||||||
multi._VERSION = "12.0.0"
|
multi.Version = "12.2.0"
|
||||||
|
multi._VERSION = "12.2.0"
|
||||||
multi.stage = "stable"
|
multi.stage = "stable"
|
||||||
multi.__index = multi
|
multi.__index = multi
|
||||||
multi.Mainloop = {}
|
multi.Mainloop = {}
|
||||||
@ -43,7 +44,11 @@ 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
|
||||||
multi.isRunning = false
|
multi.lastTime = clock()
|
||||||
|
local mainloopActive = false
|
||||||
|
local isRunning = false
|
||||||
|
local next
|
||||||
|
local ncount = 0
|
||||||
multi.defaultSettings = {
|
multi.defaultSettings = {
|
||||||
priority = 0,
|
priority = 0,
|
||||||
protect = false,
|
protect = false,
|
||||||
@ -144,6 +149,7 @@ function multi:setPriority(s)
|
|||||||
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
|
||||||
|
self.solid = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
-- System
|
-- System
|
||||||
@ -230,25 +236,23 @@ function multi:getError()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
function multi:benchMark(sec,p,pt)
|
function multi:benchMark(sec,p,pt)
|
||||||
|
local c = 0
|
||||||
local temp=self:newLoop(function(self,t)
|
local temp=self:newLoop(function(self,t)
|
||||||
if self.clock()-self.init>self.sec then
|
if t>sec then
|
||||||
if pt then
|
if pt then
|
||||||
print(pt.." "..self.c.." Steps in "..sec.." second(s)!")
|
print(pt.." "..c.." Steps in "..sec.." second(s)!")
|
||||||
end
|
end
|
||||||
self.tt(self.sec,self.c)
|
self.tt(sec,c)
|
||||||
self:Destroy()
|
self:Destroy()
|
||||||
else
|
else
|
||||||
self.c=self.c+1
|
c=c+1
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
temp.Priority=p or 1
|
temp:setPriority(p or 1)
|
||||||
function temp:OnBench(func)
|
function temp:OnBench(func)
|
||||||
self.tt=func
|
self.tt=func
|
||||||
end
|
end
|
||||||
self.tt=function() end
|
self.tt=function() end
|
||||||
temp.sec=sec
|
|
||||||
temp.init=self.clock()
|
|
||||||
temp.c=0
|
|
||||||
return temp
|
return temp
|
||||||
end
|
end
|
||||||
function multi.startFPSMonitior()
|
function multi.startFPSMonitior()
|
||||||
@ -268,7 +272,9 @@ function multi.timer(func,...)
|
|||||||
local timer=multi:newTimer()
|
local timer=multi:newTimer()
|
||||||
timer:Start()
|
timer:Start()
|
||||||
args={func(...)}
|
args={func(...)}
|
||||||
return timer:Get(),unpack(args)
|
local t = timer:Get()
|
||||||
|
timer = nil
|
||||||
|
return t,unpack(args)
|
||||||
end
|
end
|
||||||
function multi:IsAnActor()
|
function multi:IsAnActor()
|
||||||
return ({watcher=true,tstep=true,step=true,updater=true,loop=true,alarm=true,event=true})[self.Type]
|
return ({watcher=true,tstep=true,step=true,updater=true,loop=true,alarm=true,event=true})[self.Type]
|
||||||
@ -369,12 +375,15 @@ function multi:ResolveTimer(...)
|
|||||||
self.funcTMR[i](self,...)
|
self.funcTMR[i](self,...)
|
||||||
end
|
end
|
||||||
self:Pause()
|
self:Pause()
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function multi:OnTimedOut(func)
|
function multi:OnTimedOut(func)
|
||||||
self.funcTM[#self.funcTM+1]=func
|
self.funcTM[#self.funcTM+1]=func
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function multi:OnTimerResolved(func)
|
function multi:OnTimerResolved(func)
|
||||||
self.funcTMR[#self.funcTMR+1]=func
|
self.funcTMR[#self.funcTMR+1]=func
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
-- Timer stuff done
|
-- Timer stuff done
|
||||||
function multi:Pause()
|
function multi:Pause()
|
||||||
@ -386,6 +395,7 @@ function multi:Pause()
|
|||||||
table.remove(self.Parent.Mainloop,self.Id)
|
table.remove(self.Parent.Mainloop,self.Id)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function multi:Resume()
|
function multi:Resume()
|
||||||
if self.Type=='process' or self.Type=='mainprocess' then
|
if self.Type=='process' or self.Type=='mainprocess' then
|
||||||
@ -401,6 +411,7 @@ function multi:Resume()
|
|||||||
self.Active=true
|
self.Active=true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function multi:Destroy()
|
function multi:Destroy()
|
||||||
if self.Type=='process' or self.Type=='mainprocess' then
|
if self.Type=='process' or self.Type=='mainprocess' then
|
||||||
@ -419,9 +430,11 @@ function multi:Destroy()
|
|||||||
end
|
end
|
||||||
self.Active=false
|
self.Active=false
|
||||||
end
|
end
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function multi:Reset(n)
|
function multi:Reset(n)
|
||||||
self:Resume()
|
self:Resume()
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function multi:isDone()
|
function multi:isDone()
|
||||||
return self.Active~=true
|
return self.Active~=true
|
||||||
@ -482,20 +495,24 @@ function multi:newProcess(file)
|
|||||||
if self.l then
|
if self.l then
|
||||||
self.l:Resume()
|
self.l:Resume()
|
||||||
end
|
end
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:Resume()
|
function c:Resume()
|
||||||
if self.l then
|
if self.l then
|
||||||
self.l:Resume()
|
self.l:Resume()
|
||||||
end
|
end
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:Pause()
|
function c:Pause()
|
||||||
if self.l then
|
if self.l then
|
||||||
self.l:Pause()
|
self.l:Pause()
|
||||||
end
|
end
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:Remove()
|
function c:Remove()
|
||||||
self:Destroy()
|
self:Destroy()
|
||||||
self.l:Destroy()
|
self.l:Destroy()
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
if file then
|
if file then
|
||||||
self.Cself=c
|
self.Cself=c
|
||||||
@ -512,6 +529,7 @@ function multi:newQueuer(file)
|
|||||||
c.funcE={}
|
c.funcE={}
|
||||||
function c:OnQueueCompleted(func)
|
function c:OnQueueCompleted(func)
|
||||||
table.insert(self.funcE,func)
|
table.insert(self.funcE,func)
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
if file then
|
if file then
|
||||||
self.Cself=c
|
self.Cself=c
|
||||||
@ -534,40 +552,45 @@ function multi:newQueuer(file)
|
|||||||
function c:Start()
|
function c:Start()
|
||||||
self.Mainloop[#self.Mainloop]:Resume()
|
self.Mainloop[#self.Mainloop]:Resume()
|
||||||
self.l:Resume()
|
self.l:Resume()
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
return c
|
return c
|
||||||
end
|
end
|
||||||
function multi:newTimer()
|
function multi:newTimer()
|
||||||
local c={}
|
local c={}
|
||||||
c.Type='timer'
|
c.Type='timer'
|
||||||
c.time=0
|
local time=0
|
||||||
c.count=0
|
local count=0
|
||||||
c.paused=false
|
local paused=false
|
||||||
function c:Start()
|
function c:Start()
|
||||||
self.time=os.clock()
|
time=os.clock()
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:Get()
|
function c:Get()
|
||||||
if self:isPaused() then return self.time end
|
if self:isPaused() then return time end
|
||||||
return (os.clock()-self.time)+self.count
|
return (clock()-time)+count
|
||||||
end
|
end
|
||||||
function c:isPaused()
|
function c:isPaused()
|
||||||
return self.paused
|
return paused
|
||||||
end
|
end
|
||||||
c.Reset=c.Start
|
c.Reset=c.Start
|
||||||
function c:Pause()
|
function c:Pause()
|
||||||
self.time=self:Get()
|
time=self:Get()
|
||||||
self.paused=true
|
paused=true
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:Resume()
|
function c:Resume()
|
||||||
self.paused=false
|
paused=false
|
||||||
self.time=os.clock()-self.time
|
time=os.clock()-time
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:tofile(path)
|
function c:tofile(path)
|
||||||
local m=bin.new()
|
local m=bin.new()
|
||||||
self.count=self.count+self:Get()
|
count=count+self:Get()
|
||||||
m:addBlock(self.Type)
|
m:addBlock(self.Type)
|
||||||
m:addBlock(self.count)
|
m:addBlock(count)
|
||||||
m:tofile(path)
|
m:tofile(path)
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
self:create(c)
|
self:create(c)
|
||||||
return c
|
return c
|
||||||
@ -597,12 +620,14 @@ function multi:newConnection(protect)
|
|||||||
self.Parent:uManager(multi.defaultSettings)
|
self.Parent:uManager(multi.defaultSettings)
|
||||||
until self.waiting==false
|
until self.waiting==false
|
||||||
id:Destroy()
|
id:Destroy()
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
c.HoldUT=c.holdUT
|
c.HoldUT=c.holdUT
|
||||||
function c:fConnect(func)
|
function c:fConnect(func)
|
||||||
local temp=self:connect(func)
|
local temp=self:connect(func)
|
||||||
table.insert(self.fconnections,temp)
|
table.insert(self.fconnections,temp)
|
||||||
self.FC=self.FC+1
|
self.FC=self.FC+1
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
c.FConnect=c.fConnect
|
c.FConnect=c.fConnect
|
||||||
function c:getConnection(name,ingore)
|
function c:getConnection(name,ingore)
|
||||||
@ -633,9 +658,11 @@ function multi:newConnection(protect)
|
|||||||
end
|
end
|
||||||
function c:Bind(t)
|
function c:Bind(t)
|
||||||
self.func=t
|
self.func=t
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:Remove()
|
function c:Remove()
|
||||||
self.func={}
|
self.func={}
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:connect(func,name,num)
|
function c:connect(func,name,num)
|
||||||
self.ID=self.ID+1
|
self.ID=self.ID+1
|
||||||
@ -687,6 +714,7 @@ function multi:newConnection(protect)
|
|||||||
m:addBlock(self.Type)
|
m:addBlock(self.Type)
|
||||||
m:addBlock(self.func)
|
m:addBlock(self.func)
|
||||||
m:tofile(path)
|
m:tofile(path)
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
return c
|
return c
|
||||||
end
|
end
|
||||||
@ -723,6 +751,14 @@ function multi:newJob(func,name)
|
|||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
function multi.nextStep(func)
|
||||||
|
ncount = ncount+1
|
||||||
|
if not next then
|
||||||
|
next = {func}
|
||||||
|
else
|
||||||
|
next[#self.next+1] = func
|
||||||
|
end
|
||||||
|
end
|
||||||
function multi:newRange()
|
function multi:newRange()
|
||||||
local selflink=self
|
local selflink=self
|
||||||
local temp={
|
local temp={
|
||||||
@ -819,26 +855,54 @@ function multi:mainloop(settings)
|
|||||||
multi.defaultSettings = settings or multi.defaultSettings
|
multi.defaultSettings = settings or multi.defaultSettings
|
||||||
self.uManager=self.uManagerRef
|
self.uManager=self.uManagerRef
|
||||||
multi.OnPreLoad:Fire()
|
multi.OnPreLoad:Fire()
|
||||||
if not multi.isRunning then
|
local p_c,p_h,p_an,p_n,p_bn,p_l,p_i = self.Priority_Core,self.Priority_High,self.Priority_Above_Normal,self.Priority_Normal,self.Priority_Below_Normal,self.Priority_Low,self.Priority_Idle
|
||||||
|
local P_LB = p_i
|
||||||
|
if not isRunning then
|
||||||
local protect = false
|
local protect = false
|
||||||
local priority = false
|
local priority = false
|
||||||
local stopOnError = true
|
local stopOnError = true
|
||||||
|
local delay = 3
|
||||||
if settings then
|
if settings then
|
||||||
|
priority = settings.priority
|
||||||
|
if settings.auto_priority then
|
||||||
|
priority = -1
|
||||||
|
end
|
||||||
if settings.preLoop then
|
if settings.preLoop then
|
||||||
settings.preLoop(self)
|
settings.preLoop(self)
|
||||||
end
|
end
|
||||||
if settings.stopOnError then
|
if settings.stopOnError then
|
||||||
stopOnError = settings.stopOnError
|
stopOnError = settings.stopOnError
|
||||||
end
|
end
|
||||||
protect = settings.protect
|
if settings.auto_stretch then
|
||||||
priority = settings.priority
|
p_i = p_i * settings.auto_stretch
|
||||||
end
|
end
|
||||||
multi.isRunning=true
|
if settings.auto_delay then
|
||||||
rawset(self,'Start',self.clock())
|
delay = settings.auto_delay
|
||||||
while self.Active do
|
end
|
||||||
if priority==1 then
|
if settings.auto_lowerbound then
|
||||||
|
P_LB = settings.auto_lowerbound
|
||||||
|
end
|
||||||
|
protect = settings.protect
|
||||||
|
end
|
||||||
|
local t,tt = clock(),0
|
||||||
|
isRunning=true
|
||||||
|
local lastTime = clock()
|
||||||
|
rawset(self,'Start',clock())
|
||||||
|
mainloopActive = true
|
||||||
local Loop=self.Mainloop
|
local Loop=self.Mainloop
|
||||||
local PS=self
|
local PS=self
|
||||||
|
local PStep = 1
|
||||||
|
local autoP = 0
|
||||||
|
local solid
|
||||||
|
local sRef
|
||||||
|
while mainloopActive do
|
||||||
|
if ncount ~= 0 then
|
||||||
|
for i = 1, ncount do
|
||||||
|
next[i]()
|
||||||
|
end
|
||||||
|
ncount = 0
|
||||||
|
end
|
||||||
|
if priority == 1 then
|
||||||
for _D=#Loop,1,-1 do
|
for _D=#Loop,1,-1 do
|
||||||
for P=1,7 do
|
for P=1,7 do
|
||||||
if Loop[_D] then
|
if Loop[_D] then
|
||||||
@ -863,11 +927,9 @@ function multi:mainloop(settings)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
elseif priority == 2 then
|
elseif priority == 2 then
|
||||||
local Loop=self.Mainloop
|
|
||||||
local PS=self
|
|
||||||
for _D=#Loop,1,-1 do
|
for _D=#Loop,1,-1 do
|
||||||
if Loop[_D] then
|
if Loop[_D] then
|
||||||
if (PS.PStep)%Loop[_D].Priority==0 then
|
if (PStep)%Loop[_D].Priority==0 then
|
||||||
if Loop[_D].Active then
|
if Loop[_D].Active then
|
||||||
self.CID=_D
|
self.CID=_D
|
||||||
if not protect then
|
if not protect then
|
||||||
@ -886,12 +948,96 @@ function multi:mainloop(settings)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
PS.PStep=PS.PStep+1
|
PStep=PStep+1
|
||||||
if PS.PStep>self.Priority_Idle then
|
if PStep==p_i then
|
||||||
PS.PStep=1
|
PStep=0
|
||||||
|
end
|
||||||
|
elseif priority == 3 then
|
||||||
|
tt = clock()-t
|
||||||
|
t = clock()
|
||||||
|
for _D=#Loop,1,-1 do
|
||||||
|
if Loop[_D] then
|
||||||
|
if Loop[_D].Priority == p_c or (Loop[_D].Priority == p_h and tt<.5) or (Loop[_D].Priority == p_an and tt<.125) or (Loop[_D].Priority == p_n and tt<.063) or (Loop[_D].Priority == p_bn and tt<.016) or (Loop[_D].Priority == p_l and tt<.003) or (Loop[_D].Priority == p_i and tt<.001) then
|
||||||
|
if Loop[_D].Active then
|
||||||
|
self.CID=_D
|
||||||
|
if not protect then
|
||||||
|
Loop[_D]:Act()
|
||||||
|
else
|
||||||
|
local status, err=pcall(Loop[_D].Act,Loop[_D])
|
||||||
|
if err then
|
||||||
|
Loop[_D].error=err
|
||||||
|
self.OnError:Fire(Loop[_D],err)
|
||||||
|
if stopOnError then
|
||||||
|
Loop[_D]:Destroy()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif priority == -1 then
|
||||||
|
for _D=#Loop,1,-1 do
|
||||||
|
sRef = Loop[_D]
|
||||||
|
if Loop[_D] then
|
||||||
|
if (sRef.Priority == p_c) or PStep==0 then
|
||||||
|
if sRef.Active then
|
||||||
|
self.CID=_D
|
||||||
|
if not protect then
|
||||||
|
if sRef.solid then
|
||||||
|
sRef:Act()
|
||||||
|
solid = true
|
||||||
|
else
|
||||||
|
time = multi.timer(sRef.Act,sRef)
|
||||||
|
sRef.solid = true
|
||||||
|
solid = false
|
||||||
|
end
|
||||||
|
if Loop[_D] and not solid then
|
||||||
|
if time == 0 then
|
||||||
|
Loop[_D].Priority = p_c
|
||||||
|
else
|
||||||
|
Loop[_D].Priority = P_LB
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if Loop[_D].solid then
|
||||||
|
Loop[_D]:Act()
|
||||||
|
solid = true
|
||||||
|
else
|
||||||
|
time, status, err=multi.timer(pcall,Loop[_D].Act,Loop[_D])
|
||||||
|
Loop[_D].solid = true
|
||||||
|
solid = false
|
||||||
|
end
|
||||||
|
if Loop[_D] and not solid then
|
||||||
|
if time == 0 then
|
||||||
|
Loop[_D].Priority = p_c
|
||||||
|
else
|
||||||
|
Loop[_D].Priority = P_LB
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if err then
|
||||||
|
Loop[_D].error=err
|
||||||
|
self.OnError:Fire(Loop[_D],err)
|
||||||
|
if stopOnError then
|
||||||
|
Loop[_D]:Destroy()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
PStep=PStep+1
|
||||||
|
if PStep>p_i then
|
||||||
|
PStep=0
|
||||||
|
if clock()-lastTime>delay then
|
||||||
|
lastTime = clock()
|
||||||
|
for i = 1,#Loop do
|
||||||
|
Loop[i]:ResetPriority()
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
local Loop=self.Mainloop
|
|
||||||
for _D=#Loop,1,-1 do
|
for _D=#Loop,1,-1 do
|
||||||
if Loop[_D] then
|
if Loop[_D] then
|
||||||
if Loop[_D].Active then
|
if Loop[_D].Active then
|
||||||
@ -919,19 +1065,37 @@ function multi:mainloop(settings)
|
|||||||
end
|
end
|
||||||
function multi:uManager(settings)
|
function multi:uManager(settings)
|
||||||
multi.OnPreLoad:Fire()
|
multi.OnPreLoad:Fire()
|
||||||
|
multi.defaultSettings = settings or multi.defaultSettings
|
||||||
|
self.t,self.tt = clock(),0
|
||||||
if settings then
|
if settings then
|
||||||
|
priority = settings.priority
|
||||||
|
if settings.auto_priority then
|
||||||
|
priority = -1
|
||||||
|
end
|
||||||
if settings.preLoop then
|
if settings.preLoop then
|
||||||
settings.preLoop(self)
|
settings.preLoop(self)
|
||||||
end
|
end
|
||||||
|
if settings.stopOnError then
|
||||||
|
stopOnError = settings.stopOnError
|
||||||
|
end
|
||||||
|
multi.defaultSettings.p_i = settings.auto_stretch*self.Priority_Idle or self.Priority_Idle
|
||||||
|
multi.defaultSettings.delay = settings.auto_delay or 3
|
||||||
|
multi.defaultSettings.auto_lowerbound = settings.auto_lowerbound or self.Priority_Idle
|
||||||
|
protect = settings.protect
|
||||||
end
|
end
|
||||||
multi.defaultSettings = settings or multi.defaultSettings
|
|
||||||
self.uManager=self.uManagerRef
|
self.uManager=self.uManagerRef
|
||||||
end
|
end
|
||||||
function multi:uManagerRef(settings)
|
function multi:uManagerRef(settings)
|
||||||
if self.Active then
|
if self.Active then
|
||||||
if multi.defaultSettings.priority==1 then
|
if ncount ~= 0 then
|
||||||
|
for i = 1, ncount do
|
||||||
|
next[i]()
|
||||||
|
end
|
||||||
|
ncount = 0
|
||||||
|
end
|
||||||
local Loop=self.Mainloop
|
local Loop=self.Mainloop
|
||||||
local PS=self
|
local PS=self
|
||||||
|
if multi.defaultSettings.priority==1 then
|
||||||
for _D=#Loop,1,-1 do
|
for _D=#Loop,1,-1 do
|
||||||
for P=1,7 do
|
for P=1,7 do
|
||||||
if Loop[_D] then
|
if Loop[_D] then
|
||||||
@ -945,6 +1109,9 @@ function multi:uManagerRef(settings)
|
|||||||
if err then
|
if err then
|
||||||
Loop[_D].error=err
|
Loop[_D].error=err
|
||||||
self.OnError:Fire(Loop[_D],err)
|
self.OnError:Fire(Loop[_D],err)
|
||||||
|
if multi.defaultSettings.stopOnError then
|
||||||
|
Loop[_D]:Destroy()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -953,8 +1120,6 @@ function multi:uManagerRef(settings)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
elseif multi.defaultSettings.priority==2 then
|
elseif multi.defaultSettings.priority==2 then
|
||||||
local Loop=self.Mainloop
|
|
||||||
local PS=self
|
|
||||||
for _D=#Loop,1,-1 do
|
for _D=#Loop,1,-1 do
|
||||||
if Loop[_D] then
|
if Loop[_D] then
|
||||||
if (PS.PStep)%Loop[_D].Priority==0 then
|
if (PS.PStep)%Loop[_D].Priority==0 then
|
||||||
@ -967,6 +1132,9 @@ function multi:uManagerRef(settings)
|
|||||||
if err then
|
if err then
|
||||||
Loop[_D].error=err
|
Loop[_D].error=err
|
||||||
self.OnError:Fire(Loop[_D],err)
|
self.OnError:Fire(Loop[_D],err)
|
||||||
|
if multi.defaultSettings.stopOnError then
|
||||||
|
Loop[_D]:Destroy()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -975,10 +1143,94 @@ function multi:uManagerRef(settings)
|
|||||||
end
|
end
|
||||||
PS.PStep=PS.PStep+1
|
PS.PStep=PS.PStep+1
|
||||||
if PS.PStep>self.Priority_Idle then
|
if PS.PStep>self.Priority_Idle then
|
||||||
PS.PStep=1
|
PS.PStep=0
|
||||||
|
end
|
||||||
|
elseif priority == 3 then
|
||||||
|
self.tt = clock()-self.t
|
||||||
|
self.t = clock()
|
||||||
|
for _D=#Loop,1,-1 do
|
||||||
|
if Loop[_D] then
|
||||||
|
if Loop[_D].Priority == self.Priority_Core or (Loop[_D].Priority == self.Priority_High and tt<.5) or (Loop[_D].Priority == self.Priority_Above_Normal and tt<.125) or (Loop[_D].Priority == self.Priority_Normal and tt<.063) or (Loop[_D].Priority == self.Priority_Below_Normal and tt<.016) or (Loop[_D].Priority == self.Priority_Low and tt<.003) or (Loop[_D].Priority == self.Priority_Idle and tt<.001) then
|
||||||
|
if Loop[_D].Active then
|
||||||
|
self.CID=_D
|
||||||
|
if not protect then
|
||||||
|
Loop[_D]:Act()
|
||||||
|
else
|
||||||
|
local status, err=pcall(Loop[_D].Act,Loop[_D])
|
||||||
|
if err then
|
||||||
|
Loop[_D].error=err
|
||||||
|
self.OnError:Fire(Loop[_D],err)
|
||||||
|
if multi.defaultSettings.stopOnError then
|
||||||
|
Loop[_D]:Destroy()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif priority == -1 then
|
||||||
|
for _D=#Loop,1,-1 do
|
||||||
|
local sRef = Loop[_D]
|
||||||
|
if Loop[_D] then
|
||||||
|
if (sRef.Priority == self.Priority_Core) or PStep==0 then
|
||||||
|
if sRef.Active then
|
||||||
|
self.CID=_D
|
||||||
|
if not protect then
|
||||||
|
if sRef.solid then
|
||||||
|
sRef:Act()
|
||||||
|
solid = true
|
||||||
|
else
|
||||||
|
time = multi.timer(sRef.Act,sRef)
|
||||||
|
sRef.solid = true
|
||||||
|
solid = false
|
||||||
|
end
|
||||||
|
if Loop[_D] and not solid then
|
||||||
|
if time == 0 then
|
||||||
|
Loop[_D].Priority = self.Priority_Core
|
||||||
|
else
|
||||||
|
Loop[_D].Priority = multi.defaultSettings.auto_lowerbound
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if Loop[_D].solid then
|
||||||
|
Loop[_D]:Act()
|
||||||
|
solid = true
|
||||||
|
else
|
||||||
|
time, status, err=multi.timer(pcall,Loop[_D].Act,Loop[_D])
|
||||||
|
Loop[_D].solid = true
|
||||||
|
solid = false
|
||||||
|
end
|
||||||
|
if Loop[_D] and not solid then
|
||||||
|
if time == 0 then
|
||||||
|
Loop[_D].Priority = self.Priority_Core
|
||||||
|
else
|
||||||
|
Loop[_D].Priority = multi.defaultSettings.auto_lowerbound
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if err then
|
||||||
|
Loop[_D].error=err
|
||||||
|
self.OnError:Fire(Loop[_D],err)
|
||||||
|
if multi.defaultSettings.stopOnError then
|
||||||
|
Loop[_D]:Destroy()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self.PStep=self.PStep+1
|
||||||
|
if self.PStep>multi.defaultSettings.p_i then
|
||||||
|
self.PStep=0
|
||||||
|
if clock()-self.lastTime>multi.defaultSettings.delay then
|
||||||
|
self.lastTime = clock()
|
||||||
|
for i = 1,#Loop do
|
||||||
|
Loop[i]:ResetPriority()
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
local Loop=self.Mainloop
|
|
||||||
for _D=#Loop,1,-1 do
|
for _D=#Loop,1,-1 do
|
||||||
if Loop[_D] then
|
if Loop[_D] then
|
||||||
if Loop[_D].Active then
|
if Loop[_D].Active then
|
||||||
@ -1036,9 +1288,11 @@ function multi:newEvent(task)
|
|||||||
end
|
end
|
||||||
function c:SetTask(func)
|
function c:SetTask(func)
|
||||||
self.Task=func
|
self.Task=func
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:OnEvent(func)
|
function c:OnEvent(func)
|
||||||
table.insert(self.func,func)
|
table.insert(self.func,func)
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
self:create(c)
|
self:create(c)
|
||||||
return c
|
return c
|
||||||
@ -1059,6 +1313,7 @@ function multi:newUpdater(skip)
|
|||||||
end
|
end
|
||||||
function c:SetSkip(n)
|
function c:SetSkip(n)
|
||||||
self.skip=n
|
self.skip=n
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
c.OnUpdate=self.OnMainConnect
|
c.OnUpdate=self.OnMainConnect
|
||||||
self:create(c)
|
self:create(c)
|
||||||
@ -1082,18 +1337,22 @@ function multi:newAlarm(set)
|
|||||||
function c:Resume()
|
function c:Resume()
|
||||||
self.Parent.Resume(self)
|
self.Parent.Resume(self)
|
||||||
self.timer:Resume()
|
self.timer:Resume()
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:Reset(n)
|
function c:Reset(n)
|
||||||
if n then self.set=n end
|
if n then self.set=n end
|
||||||
self:Resume()
|
self:Resume()
|
||||||
self.timer:Reset()
|
self.timer:Reset()
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:OnRing(func)
|
function c:OnRing(func)
|
||||||
table.insert(self.func,func)
|
table.insert(self.func,func)
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:Pause()
|
function c:Pause()
|
||||||
self.timer:Pause()
|
self.timer:Pause()
|
||||||
self.Parent.Pause(self)
|
self.Parent.Pause(self)
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
self:create(c)
|
self:create(c)
|
||||||
return c
|
return c
|
||||||
@ -1101,17 +1360,19 @@ end
|
|||||||
function multi:newLoop(func)
|
function multi:newLoop(func)
|
||||||
local c=self:newBase()
|
local c=self:newBase()
|
||||||
c.Type='loop'
|
c.Type='loop'
|
||||||
c.Start=self.clock()
|
local start=self.clock()
|
||||||
|
local funcs = {}
|
||||||
if func then
|
if func then
|
||||||
c.func={func}
|
funcs={func}
|
||||||
end
|
end
|
||||||
function c:Act()
|
function c:Act()
|
||||||
for i=1,#self.func do
|
for i=1,#funcs do
|
||||||
self.func[i](self,self.Parent.clock()-self.Start)
|
funcs[i](self,clock()-start)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
function c:OnLoop(func)
|
function c:OnLoop(func)
|
||||||
table.insert(self.func,func)
|
table.insert(funcs,func)
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
self:create(c)
|
self:create(c)
|
||||||
return c
|
return c
|
||||||
@ -1126,9 +1387,11 @@ function multi:newFunction(func)
|
|||||||
c.Parent=self
|
c.Parent=self
|
||||||
function c:Pause()
|
function c:Pause()
|
||||||
self.Active=false
|
self.Active=false
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:Resume()
|
function c:Resume()
|
||||||
self.Active=true
|
self.Active=true
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
setmetatable(c,mt)
|
setmetatable(c,mt)
|
||||||
self:create(c)
|
self:create(c)
|
||||||
@ -1180,15 +1443,19 @@ function multi:newStep(start,reset,count,skip)
|
|||||||
c.Reset=c.Resume
|
c.Reset=c.Resume
|
||||||
function c:OnStart(func)
|
function c:OnStart(func)
|
||||||
table.insert(self.funcS,func)
|
table.insert(self.funcS,func)
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:OnStep(func)
|
function c:OnStep(func)
|
||||||
table.insert(self.func,1,func)
|
table.insert(self.func,1,func)
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:OnEnd(func)
|
function c:OnEnd(func)
|
||||||
table.insert(self.funcE,func)
|
table.insert(self.funcE,func)
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:Break()
|
function c:Break()
|
||||||
self.Active=nil
|
self.Active=nil
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:Update(start,reset,count,skip)
|
function c:Update(start,reset,count,skip)
|
||||||
self.start=start or self.start
|
self.start=start or self.start
|
||||||
@ -1196,6 +1463,7 @@ function multi:newStep(start,reset,count,skip)
|
|||||||
self.skip=skip or self.skip
|
self.skip=skip or self.skip
|
||||||
self.count=count or self.count
|
self.count=count or self.count
|
||||||
self:Resume()
|
self:Resume()
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
self:create(c)
|
self:create(c)
|
||||||
return c
|
return c
|
||||||
@ -1221,13 +1489,16 @@ function multi:newTLoop(func,set)
|
|||||||
function c:Resume()
|
function c:Resume()
|
||||||
self.Parent.Resume(self)
|
self.Parent.Resume(self)
|
||||||
self.timer:Resume()
|
self.timer:Resume()
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:Pause()
|
function c:Pause()
|
||||||
self.timer:Pause()
|
self.timer:Pause()
|
||||||
self.Parent.Pause(self)
|
self.Parent.Pause(self)
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:OnLoop(func)
|
function c:OnLoop(func)
|
||||||
table.insert(self.func,func)
|
table.insert(self.func,func)
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
self:create(c)
|
self:create(c)
|
||||||
return c
|
return c
|
||||||
@ -1238,6 +1509,7 @@ function multi:newTrigger(func)
|
|||||||
c.trigfunc=func or function() end
|
c.trigfunc=func or function() end
|
||||||
function c:Fire(...)
|
function c:Fire(...)
|
||||||
self:trigfunc(...)
|
self:trigfunc(...)
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
self:create(c)
|
self:create(c)
|
||||||
return c
|
return c
|
||||||
@ -1265,6 +1537,7 @@ function multi:newTStep(start,reset,count,set)
|
|||||||
self.count=count or self.count or 1
|
self.count=count or self.count or 1
|
||||||
self.timer=self.clock()
|
self.timer=self.clock()
|
||||||
self:Resume()
|
self:Resume()
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:Act()
|
function c:Act()
|
||||||
if self.clock()-self.timer>=self.set then
|
if self.clock()-self.timer>=self.set then
|
||||||
@ -1289,20 +1562,25 @@ function multi:newTStep(start,reset,count,set)
|
|||||||
end
|
end
|
||||||
function c:OnStart(func)
|
function c:OnStart(func)
|
||||||
table.insert(self.funcS,func)
|
table.insert(self.funcS,func)
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:OnStep(func)
|
function c:OnStep(func)
|
||||||
table.insert(self.func,func)
|
table.insert(self.func,func)
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:OnEnd(func)
|
function c:OnEnd(func)
|
||||||
table.insert(self.funcE,func)
|
table.insert(self.funcE,func)
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:Break()
|
function c:Break()
|
||||||
self.Active=nil
|
self.Active=nil
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:Reset(n)
|
function c:Reset(n)
|
||||||
if n then self.set=n end
|
if n then self.set=n end
|
||||||
self.timer=self.clock()
|
self.timer=self.clock()
|
||||||
self:Resume()
|
self:Resume()
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
self:create(c)
|
self:create(c)
|
||||||
return c
|
return c
|
||||||
@ -1391,24 +1669,31 @@ function multi:newTimeStamper()
|
|||||||
else
|
else
|
||||||
self.time[#self.time+1]={hour,minute,true}
|
self.time[#self.time+1]={hour,minute,true}
|
||||||
end
|
end
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:OnHour(hour,func)
|
function c:OnHour(hour,func)
|
||||||
self.hour[#self.hour+1]={string.format("%02d",hour),func,true}
|
self.hour[#self.hour+1]={string.format("%02d",hour),func,true}
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:OnMinute(minute,func)
|
function c:OnMinute(minute,func)
|
||||||
self.minute[#self.minute+1]={string.format("%02d",minute),func,true}
|
self.minute[#self.minute+1]={string.format("%02d",minute),func,true}
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:OnSecond(second,func)
|
function c:OnSecond(second,func)
|
||||||
self.second[#self.second+1]={string.format("%02d",second),func,true}
|
self.second[#self.second+1]={string.format("%02d",second),func,true}
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:OnDay(day,func)
|
function c:OnDay(day,func)
|
||||||
self.day[#self.day+1]={day,func,true}
|
self.day[#self.day+1]={day,func,true}
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:OnMonth(month,func)
|
function c:OnMonth(month,func)
|
||||||
self.month[#self.month+1]={string.format("%02d",month),func,true}
|
self.month[#self.month+1]={string.format("%02d",month),func,true}
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:OnYear(year,func)
|
function c:OnYear(year,func)
|
||||||
self.year[#self.year+1]={string.format("%02d",year),func,true}
|
self.year[#self.year+1]={string.format("%02d",year),func,true}
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
self:create(c)
|
self:create(c)
|
||||||
return c
|
return c
|
||||||
@ -1426,6 +1711,7 @@ function multi:newWatcher(namespace,name)
|
|||||||
c.cv=ns[n]
|
c.cv=ns[n]
|
||||||
function c:OnValueChanged(func)
|
function c:OnValueChanged(func)
|
||||||
table.insert(self.func,func)
|
table.insert(self.func,func)
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:Act()
|
function c:Act()
|
||||||
if self.cv~=self.ns[self.n] then
|
if self.cv~=self.ns[self.n] then
|
||||||
@ -1631,18 +1917,22 @@ function multi:newThreadedAlarm(name,set)
|
|||||||
function c:Resume()
|
function c:Resume()
|
||||||
self.rest=false
|
self.rest=false
|
||||||
self.timer:Resume()
|
self.timer:Resume()
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:Reset(n)
|
function c:Reset(n)
|
||||||
if n then self.set=n end
|
if n then self.set=n end
|
||||||
self.rest=false
|
self.rest=false
|
||||||
self.timer:Reset(n)
|
self.timer:Reset(n)
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:OnRing(func)
|
function c:OnRing(func)
|
||||||
table.insert(self.func,func)
|
table.insert(self.func,func)
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:Pause()
|
function c:Pause()
|
||||||
self.timer:Pause()
|
self.timer:Pause()
|
||||||
self.rest=true
|
self.rest=true
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
c.rest=false
|
c.rest=false
|
||||||
c.updaterate=multi.Priority_Low -- skips
|
c.updaterate=multi.Priority_Low -- skips
|
||||||
@ -1672,9 +1962,11 @@ function multi:newThreadedUpdater(name,skip)
|
|||||||
c.skip=skip or 1
|
c.skip=skip or 1
|
||||||
function c:Resume()
|
function c:Resume()
|
||||||
self.rest=false
|
self.rest=false
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:Pause()
|
function c:Pause()
|
||||||
self.rest=true
|
self.rest=true
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
c.OnUpdate=self.OnMainConnect
|
c.OnUpdate=self.OnMainConnect
|
||||||
c.rest=false
|
c.rest=false
|
||||||
@ -1718,29 +2010,37 @@ function multi:newThreadedTStep(name,start,reset,count,set)
|
|||||||
self.count=count or self.count or 1
|
self.count=count or self.count or 1
|
||||||
self.timer=os.clock()
|
self.timer=os.clock()
|
||||||
self:Resume()
|
self:Resume()
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:Resume()
|
function c:Resume()
|
||||||
self.rest=false
|
self.rest=false
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:Pause()
|
function c:Pause()
|
||||||
self.rest=true
|
self.rest=true
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:OnStart(func)
|
function c:OnStart(func)
|
||||||
table.insert(self.funcS,func)
|
table.insert(self.funcS,func)
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:OnStep(func)
|
function c:OnStep(func)
|
||||||
table.insert(self.func,func)
|
table.insert(self.func,func)
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:OnEnd(func)
|
function c:OnEnd(func)
|
||||||
table.insert(self.funcE,func)
|
table.insert(self.funcE,func)
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:Break()
|
function c:Break()
|
||||||
self.Active=nil
|
self.Active=nil
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:Reset(n)
|
function c:Reset(n)
|
||||||
if n then self.set=n end
|
if n then self.set=n end
|
||||||
self.timer=os.clock()
|
self.timer=os.clock()
|
||||||
self:Resume()
|
self:Resume()
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
c.updaterate=0--multi.Priority_Low -- skips
|
c.updaterate=0--multi.Priority_Low -- skips
|
||||||
c.restRate=0
|
c.restRate=0
|
||||||
@ -1784,12 +2084,15 @@ function multi:newThreadedTLoop(name,func,n)
|
|||||||
end
|
end
|
||||||
function c:Resume()
|
function c:Resume()
|
||||||
self.rest=false
|
self.rest=false
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:Pause()
|
function c:Pause()
|
||||||
self.rest=true
|
self.rest=true
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:OnLoop(func)
|
function c:OnLoop(func)
|
||||||
table.insert(self.func,func)
|
table.insert(self.func,func)
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
c.rest=false
|
c.rest=false
|
||||||
c.updaterate=0
|
c.updaterate=0
|
||||||
@ -1828,22 +2131,28 @@ function multi:newThreadedStep(name,start,reset,count,skip)
|
|||||||
end
|
end
|
||||||
function c:Resume()
|
function c:Resume()
|
||||||
self.rest=false
|
self.rest=false
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:Pause()
|
function c:Pause()
|
||||||
self.rest=true
|
self.rest=true
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
c.Reset=c.Resume
|
c.Reset=c.Resume
|
||||||
function c:OnStart(func)
|
function c:OnStart(func)
|
||||||
table.insert(self.funcS,func)
|
table.insert(self.funcS,func)
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:OnStep(func)
|
function c:OnStep(func)
|
||||||
table.insert(self.func,1,func)
|
table.insert(self.func,1,func)
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:OnEnd(func)
|
function c:OnEnd(func)
|
||||||
table.insert(self.funcE,func)
|
table.insert(self.funcE,func)
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:Break()
|
function c:Break()
|
||||||
self.rest=true
|
self.rest=true
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:Update(start,reset,count,skip)
|
function c:Update(start,reset,count,skip)
|
||||||
self.start=start or self.start
|
self.start=start or self.start
|
||||||
@ -1851,6 +2160,7 @@ function multi:newThreadedStep(name,start,reset,count,skip)
|
|||||||
self.skip=skip or self.skip
|
self.skip=skip or self.skip
|
||||||
self.count=count or self.count
|
self.count=count or self.count
|
||||||
self:Resume()
|
self:Resume()
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
c.updaterate=0
|
c.updaterate=0
|
||||||
c.restRate=.1
|
c.restRate=.1
|
||||||
@ -1929,21 +2239,26 @@ function multi:newThreadedProcess(name)
|
|||||||
end
|
end
|
||||||
function c:Start()
|
function c:Start()
|
||||||
self.rest=false
|
self.rest=false
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:Resume()
|
function c:Resume()
|
||||||
self.rest=false
|
self.rest=false
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:Pause()
|
function c:Pause()
|
||||||
self.rest=true
|
self.rest=true
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:Remove()
|
function c:Remove()
|
||||||
self.ref:kill()
|
self.ref:kill()
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:kill()
|
function c:kill()
|
||||||
err=coroutine.yield({"_kill_"})
|
err=coroutine.yield({"_kill_"})
|
||||||
if err then
|
if err then
|
||||||
error("Failed to kill a thread! Exiting...")
|
error("Failed to kill a thread! Exiting...")
|
||||||
end
|
end
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:sleep(n)
|
function c:sleep(n)
|
||||||
if type(n)=="function" then
|
if type(n)=="function" then
|
||||||
@ -1954,6 +2269,7 @@ function multi:newThreadedProcess(name)
|
|||||||
else
|
else
|
||||||
error("Invalid Type for sleep!")
|
error("Invalid Type for sleep!")
|
||||||
end
|
end
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
c.hold=c.sleep
|
c.hold=c.sleep
|
||||||
multi:newThread(name,function(ref)
|
multi:newThread(name,function(ref)
|
||||||
@ -1977,12 +2293,15 @@ function multi:newThreadedLoop(name,func)
|
|||||||
end
|
end
|
||||||
function c:Resume()
|
function c:Resume()
|
||||||
self.rest=false
|
self.rest=false
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:Pause()
|
function c:Pause()
|
||||||
self.rest=true
|
self.rest=true
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:OnLoop(func)
|
function c:OnLoop(func)
|
||||||
table.insert(self.func,func)
|
table.insert(self.func,func)
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
c.rest=false
|
c.rest=false
|
||||||
c.updaterate=0
|
c.updaterate=0
|
||||||
@ -2008,12 +2327,15 @@ function multi:newThreadedEvent(name,task)
|
|||||||
c.Task=task or function() end
|
c.Task=task or function() end
|
||||||
function c:OnEvent(func)
|
function c:OnEvent(func)
|
||||||
table.insert(self.func,func)
|
table.insert(self.func,func)
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:Resume()
|
function c:Resume()
|
||||||
self.rest=false
|
self.rest=false
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
function c:Pause()
|
function c:Pause()
|
||||||
self.rest=true
|
self.rest=true
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
c.rest=false
|
c.rest=false
|
||||||
c.updaterate=0
|
c.updaterate=0
|
||||||
@ -2039,6 +2361,7 @@ end
|
|||||||
-- State Saving Stuff
|
-- State Saving Stuff
|
||||||
function multi:IngoreObject()
|
function multi:IngoreObject()
|
||||||
self.Ingore=true
|
self.Ingore=true
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
multi.scheduler:IngoreObject()
|
multi.scheduler:IngoreObject()
|
||||||
function multi:ToString()
|
function multi:ToString()
|
||||||
|
|||||||
15
multitut.lua
Normal file
15
multitut.lua
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package.path="?/init.lua;?.lua;"..package.path
|
||||||
|
local multi = require("multi")
|
||||||
|
--~ local GLOBAL, THREAD = require("multi.integration.lanesManager").init()
|
||||||
|
--~ nGLOBAL = require("multi.integration.networkManager").init()
|
||||||
|
|
||||||
|
|
||||||
|
local a = 0
|
||||||
|
local clock = os.clock
|
||||||
|
b = clock()
|
||||||
|
while clock()-b <1 do
|
||||||
|
a = a +1
|
||||||
|
end
|
||||||
|
print("a: "..a)
|
||||||
|
--~ multi:benchMark(1,nil,"Bench:")
|
||||||
|
--~ multi:mainloop()
|
||||||
32
rockspecs/multi-12.2-0.rockspec
Normal file
32
rockspecs/multi-12.2-0.rockspec
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package = "multi"
|
||||||
|
version = "12.2-0"
|
||||||
|
source = {
|
||||||
|
url = "git://github.com/rayaman/multi.git",
|
||||||
|
tag = "v12.2.0",
|
||||||
|
}
|
||||||
|
description = {
|
||||||
|
summary = "Lua Multi tasking library",
|
||||||
|
detailed = [[
|
||||||
|
This library contains many methods for multi tasking. From simple side by side code using multi-objs, to using coroutine based Threads and System threads(When you have lua lanes installed or are using love2d)
|
||||||
|
]],
|
||||||
|
homepage = "https://github.com/rayaman/multi",
|
||||||
|
license = "MIT"
|
||||||
|
}
|
||||||
|
dependencies = {
|
||||||
|
"lua >= 5.1",
|
||||||
|
"bin",
|
||||||
|
"lanes",
|
||||||
|
"lua-net"
|
||||||
|
}
|
||||||
|
build = {
|
||||||
|
type = "builtin",
|
||||||
|
modules = {
|
||||||
|
["multi.init"] = "multi/init.lua",
|
||||||
|
["multi.compat.love2d"] = "multi/compat/love2d.lua",
|
||||||
|
["multi.integration.lanesManager"] = "multi/integration/lanesManager.lua",
|
||||||
|
["multi.integration.loveManager"] = "multi/integration/loveManager.lua",
|
||||||
|
["multi.integration.luvitManager"] = "multi/integration/luvitManager.lua",
|
||||||
|
["multi.integration.networkManager"] = "multi/integration/networkManager.lua",
|
||||||
|
["multi.integration.shared"] = "multi/integration/shared.lua"
|
||||||
|
}
|
||||||
|
}
|
||||||
65
test.lua
65
test.lua
@ -1,17 +1,54 @@
|
|||||||
package.path="?/init.lua;?.lua;"..package.path
|
package.path="?/init.lua;?.lua;"..package.path
|
||||||
|
--~ package.cpath="./?.dll;"..package.cpath
|
||||||
|
--~ time = require("time")
|
||||||
|
--~ local d1 = time.date(2012, 4, 30)
|
||||||
|
--~ a=time.nowlocal()
|
||||||
|
--~ while true do
|
||||||
|
--~ print(time.nowlocal():ticks())
|
||||||
|
--~ end
|
||||||
multi = require("multi")
|
multi = require("multi")
|
||||||
local a = 0
|
--~ multi:newTLoop(function(self)
|
||||||
multi:newThread("test",function()
|
--~ a = 0
|
||||||
print("lets go")
|
--~ end,.001)
|
||||||
b,c = thread.hold(function()
|
--~ multi:benchMark(1,nil,"Steps/s:"):OnBench(function()
|
||||||
return b,"We did it!"
|
--~ os.exit()
|
||||||
end)
|
--~ end)
|
||||||
print(b,c)
|
function multi:ResetPriority()
|
||||||
end)
|
self.solid = false
|
||||||
multi:newTLoop(function()
|
end
|
||||||
a=a+1
|
local clock = os.clock
|
||||||
if a == 5 then
|
function sleep(n) -- seconds
|
||||||
b = "Hello"
|
local t0 = clock()
|
||||||
|
while clock() - t0 <= n do end
|
||||||
|
end
|
||||||
|
local a=0
|
||||||
|
local b=0
|
||||||
|
local c=0
|
||||||
|
multi:benchMark(1,multi.Priority_Core,"Regular Bench:"):OnBench(function() -- the onbench() allows us to do each bench after each other!
|
||||||
|
print("AutoP\n---------------")
|
||||||
|
multi:newLoop(function()
|
||||||
|
a=a+1
|
||||||
|
end)
|
||||||
|
t=multi:newLoop(function()
|
||||||
|
c=c+1
|
||||||
|
sleep(.001)
|
||||||
|
end)
|
||||||
|
multi:newLoop(function()
|
||||||
|
b=b+1
|
||||||
|
end)
|
||||||
|
multi:benchMark(1,multi.Priority_Core,"Hmm:"):OnBench(function()
|
||||||
|
multi.nextStep(function()
|
||||||
|
print(a,b,c)
|
||||||
|
--~ os.exit()
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
settings = {
|
||||||
|
--~ priority = 3, -- this is overwritten while auto_priority is being used! You can also use -1 for this setting as well
|
||||||
|
auto_priority = true,
|
||||||
|
auto_stretch = 1000,
|
||||||
|
auto_lowerbound = multi.Priority_Idle
|
||||||
|
}
|
||||||
|
while true do
|
||||||
|
multi:uManager(settings)
|
||||||
end
|
end
|
||||||
end,1)
|
|
||||||
multi:mainloop()
|
|
||||||
|
|||||||
570
time/init.lua
Normal file
570
time/init.lua
Normal file
@ -0,0 +1,570 @@
|
|||||||
|
--------------------------------------------------------------------------------
|
||||||
|
-- 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,
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user