This commit is contained in:
FlightControl 2016-12-14 06:58:24 +01:00
parent 02d4bbf3ff
commit 761053c95e
10 changed files with 137 additions and 103 deletions

View File

@ -132,7 +132,7 @@ function BASE:_SetDestructor()
-- TODO: Okay, this is really technical...
-- When you set a proxy to a table to catch __gc, weak tables don't behave like weak...
-- Therefore, I am parking this logic until I've properly discussed all this with the community.
--
--[[
local proxy = newproxy(true)
local proxyMeta = getmetatable(proxy)
@ -147,7 +147,7 @@ function BASE:_SetDestructor()
-- table is about to be garbage-collected - then the __gc hook
-- will be invoked and the destructor called
rawset( self, '__proxy', proxy )
--
--]]
end
--- This is the worker method to inherit from a parent class.

View File

@ -1,10 +1,29 @@
--- This module contains the TIMER class.
--- This module defines the SCHEDULEDISPATCHER class, which is used by a central object called _SCHEDULEDISPATCHER.
--
-- ===
--
-- Takes care of scheduled function dispatching for defined in MOOSE classes.
-- Takes care of the creation and dispatching of scheduled functions for SCHEDULER objects.
--
-- This function is complicated.
-- This class is tricky and needs some thorought explanation.
-- SCHEDULE classes are used to schedule functions for objects, or as persistent objects.
-- The SCHEDULEDISPATCHER class ensures that:
--
-- - Scheduled functions are planned according the SCHEDULER object parameters.
-- - Scheduled functions are repeated when requested, according the SCHEDULER object parameters.
-- - Scheduled functions are automatically removed when the schedule is finished, according the SCHEDULER object parameters.
--
-- The SCHEDULEDISPATCHER class will manage SCHEDULER object in memory during garbage collection:
-- - When a SCHEDULER object is not attached to another object (that is, it's first :Schedule() parameter is nil), then the SCHEDULER
-- object is _persistent_ within memory.
-- - When a SCHEDULER object *is* attached to another object, then the SCHEDULER object is _not persistent_ within memory after a garbage collection!
-- The none persistency of SCHEDULERS attached to objects is required to allow SCHEDULER objects to be garbage collectged, when the parent object is also desroyed or nillified and garbage collected.
-- Even when there are pending timer scheduled functions to be executed for the SCHEDULER object,
-- these will not be executed anymore when the SCHEDULER object has been destroyed.
--
-- The SCHEDULEDISPATCHER allows multiple scheduled functions to be planned and executed for one SCHEDULER object.
-- The SCHEDULER object therefore keeps a table of "CallID's", which are returned after each planning of a new scheduled function by the SCHEDULEDISPATCHER.
-- The SCHEDULER object plans new scheduled functions through the @{Core.Scheduler#SCHEDULER.Schedule}() method.
-- The Schedule() method returns the CallID that is the reference ID for each planned schedule.
--
-- ===
--
@ -13,16 +32,16 @@
-- ### Contributions: -
-- ### Authors: FlightControl : Design & Programming
--
-- @module Timer
-- @module ScheduleDispatcher
--- The TIMER structure
-- @type TIMER
TIMER = {
ClassName = "TIMER",
--- The SCHEDULEDISPATCHER structure
-- @type SCHEDULEDISPATCHER
SCHEDULEDISPATCHER = {
ClassName = "SCHEDULEDISPATCHER",
CallID = 0,
}
function TIMER:New()
function SCHEDULEDISPATCHER:New()
local self = BASE:Inherit( self, BASE:New() )
self:F3()
return self
@ -32,9 +51,9 @@ end
-- The development of this method was really tidy.
-- It is constructed as such that a garbage collection is executed on the weak tables, when the Scheduler is nillified.
-- Nothing of this code should be modified without testing it thoroughly.
-- @param #TIMER self
-- @param #SCHEDULEDISPATCHER self
-- @param Core.Scheduler#SCHEDULER Scheduler
function TIMER:AddSchedule( Scheduler, ScheduleFunction, ScheduleArguments, Start, Repeat, Randomize, Stop )
function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleArguments, Start, Repeat, Randomize, Stop )
self:F( { Scheduler, ScheduleFunction, ScheduleArguments, Start, Repeat, Randomize, Stop } )
self.CallID = self.CallID + 1
@ -128,15 +147,13 @@ function TIMER:AddSchedule( Scheduler, ScheduleFunction, ScheduleArguments, Star
( Randomize * Repeat / 2 )
) +
0.01
self:T3( { ScheduleArguments, "Repeat:", CurrentTime, ScheduleTime } )
self:T3( { Repeat = CallID, CurrentTime, ScheduleTime, ScheduleArguments } )
return ScheduleTime -- returns the next time the function needs to be called.
else
timer.removeFunction( ScheduleID )
ScheduleID = nil
self:Stop( Scheduler, CallID )
end
else
timer.removeFunction( ScheduleID )
ScheduleID = nil
self:Stop( Scheduler, CallID )
end
else
--self:E( "Scheduled obscolete call for CallID: " .. CallID )
@ -145,29 +162,49 @@ function TIMER:AddSchedule( Scheduler, ScheduleFunction, ScheduleArguments, Star
return nil
end
self.Schedule[Scheduler][self.CallID].ScheduleID = timer.scheduleFunction(
self.Schedule[Scheduler][self.CallID].CallHandler,
self.CallID,
timer.getTime() + self.Schedule[Scheduler][self.CallID].Start
)
self:Start( Scheduler, self.CallID )
return self.CallID
end
function TIMER:RemoveSchedule( CallID )
self:F( CallID )
function SCHEDULEDISPATCHER:RemoveSchedule( Scheduler, CallID )
self:F( { Remove = CallID, Scheduler = Scheduler } )
local Schedule = self.ObjectSchedulers[CallID]
if Schedule then
local ScheduleID = Schedule.ScheduleID
timer.removeFunction( ScheduleID )
ScheduleID = nil
Schedule = nil
if CallID then
self:Stop( Scheduler, CallID )
self.Schedule[Scheduler][CallID] = nil
end
end
function SCHEDULEDISPATCHER:Start( Scheduler, CallID )
self:F( { Start = CallID, Scheduler = Scheduler } )
if CallID then
local Schedule = self.Schedule[Scheduler]
Schedule[CallID].ScheduleID = timer.scheduleFunction(
Schedule[CallID].CallHandler,
CallID,
timer.getTime() + Schedule[CallID].Start
)
else
for CallID, Schedule in pairs( self.Schedule[Scheduler] ) do
self:Start( Scheduler, CallID ) -- Recursive
end
end
end
function SCHEDULEDISPATCHER:Stop( Scheduler, CallID )
self:F( { Stop = CallID, Scheduler = Scheduler } )
if CallID then
local Schedule = self.Schedule[Scheduler]
timer.removeFunction( Schedule[CallID].ScheduleID )
else
for CallID, Schedule in pairs( self.Schedule[Scheduler] ) do
self:Stop( Scheduler, CallID ) -- Recursive
end
end
end

View File

@ -1,36 +1,43 @@
--- This module contains the SCHEDULER class.
--
-- 1) @{Core.Scheduler#SCHEDULER} class, extends @{Core.Base#BASE}
-- =====================================================
-- The @{Core.Scheduler#SCHEDULER} class models time events calling given event handling functions.
-- # 1) @{Core.Scheduler#SCHEDULER} class, extends @{Core.Base#BASE}
--
-- The @{Core.Scheduler#SCHEDULER} class creates schedule.
--
-- 1.1) SCHEDULER constructor
-- --------------------------
-- The SCHEDULER class is quite easy to use:
-- ## 1.1) SCHEDULER constructor
--
-- The SCHEDULER class is quite easy to use, but note that the New constructor has variable parameters:
--
-- * @{Core.Scheduler#SCHEDULER.New}: Setup a new scheduler and start it with the specified parameters.
-- * @{Core.Scheduler#SCHEDULER.New}( nil ): Setup a new SCHEDULER object, which is persistently executed after garbage collection.
-- * @{Core.Scheduler#SCHEDULER.New}( Object ): Setup a new SCHEDULER object, which is linked to the Object. When the Object is nillified or destroyed, the SCHEDULER object will also be destroyed and stopped after garbage collection.
-- * @{Core.Scheduler#SCHEDULER.New}( nil, Function, FunctionArguments, Start, ... ): Setup a new persistent SCHEDULER object, and start a new schedule for the Function with the defined FunctionArguments according the Start and sequent parameters.
-- * @{Core.Scheduler#SCHEDULER.New}( Object, Function, FunctionArguments, Start, ... ): Setup a new SCHEDULER object, linked to Object, and start a new schedule for the Function with the defined FunctionArguments according the Start and sequent parameters.
--
-- ## 1.2) SCHEDULER timer stopping and (re-)starting.
--
-- 1.2) SCHEDULER timer stop and start
-- -----------------------------------
-- The SCHEDULER can be stopped and restarted with the following methods:
--
-- * @{Core.Scheduler#SCHEDULER.Start}: (Re-)Start the scheduler.
-- * @{Core.Scheduler#SCHEDULER.Stop}: Stop the scheduler.
-- * @{Core.Scheduler#SCHEDULER.Start}(): (Re-)Start the schedules within the SCHEDULER object. If a CallID is provided to :Start(), only the schedule referenced by CallID will be (re-)started.
-- * @{Core.Scheduler#SCHEDULER.Stop}(): Stop the schedules within the SCHEDULER object. If a CallID is provided to :Stop(), then only the schedule referenced by CallID will be stopped.
--
-- 1.3) Reschedule new time event
-- ------------------------------
-- With @{Core.Scheduler#SCHEDULER.Schedule} a new time event can be scheduled.
-- ## 1.3) Create a new schedule
--
-- With @{Core.Scheduler#SCHEDULER.Schedule}() a new time event can be scheduled. This function is used by the :New() constructor when a new schedule is planned.
--
-- ===
--
-- ### Contributions:
--
-- * Mechanist : Concept & Testing
-- * FlightControl : Concept & Testing
--
-- ### Authors:
--
-- * FlightControl : Design & Programming
--
-- ### Test Missions:
--
-- * SCH - Scheduler
--
-- ===
--
-- @module Scheduler
@ -55,19 +62,24 @@ SCHEDULER = {
-- @param #number RandomizationFactor Specifies a randomization factor between 0 and 1 to randomize the RepeatSecondsInterval.
-- @param #number StopSeconds Specifies the amount of seconds when the scheduler will be stopped.
-- @return #SCHEDULER self
-- @return #number The ScheduleID of the planned schedule.
function SCHEDULER:New( TimeEventObject, TimeEventFunction, TimeEventFunctionArguments, StartSeconds, RepeatSecondsInterval, RandomizationFactor, StopSeconds )
local self = BASE:Inherit( self, BASE:New() )
self:F2( { StartSeconds, RepeatSecondsInterval, RandomizationFactor, StopSeconds } )
self:Schedule( TimeEventObject, TimeEventFunction, TimeEventFunctionArguments, StartSeconds, RepeatSecondsInterval, RandomizationFactor, StopSeconds )
local ScheduleID = nil
if TimeEventFunction then
ScheduleID = self:Schedule( TimeEventObject, TimeEventFunction, TimeEventFunctionArguments, StartSeconds, RepeatSecondsInterval, RandomizationFactor, StopSeconds )
end
return self
return self, ScheduleID
end
--function SCHEDULER:_Destructor()
-- --self:E("_Destructor")
--
-- _TIMERDISPATCHER:RemoveSchedule( self.CallID )
-- _SCHEDULEDISPATCHER:RemoveSchedule( self.CallID )
--end
--- Schedule a new time event. Note that the schedule will only take place if the scheduler is *started*. Even for a single schedule event, the scheduler needs to be started also.
@ -79,7 +91,7 @@ end
-- @param #number RepeatSecondsInterval Specifies the interval in seconds when the scheduler will call the event function.
-- @param #number RandomizationFactor Specifies a randomization factor between 0 and 1 to randomize the RepeatSecondsInterval.
-- @param #number StopSeconds Specifies the amount of seconds when the scheduler will be stopped.
-- @return #SCHEDULER self
-- @return #number The ScheduleID of the planned schedule.
function SCHEDULER:Schedule( TimeEventObject, TimeEventFunction, TimeEventFunctionArguments, StartSeconds, RepeatSecondsInterval, RandomizationFactor, StopSeconds )
self:F2( { StartSeconds, RepeatSecondsInterval, RandomizationFactor, StopSeconds } )
self:T3( { TimeEventFunctionArguments } )
@ -87,7 +99,7 @@ function SCHEDULER:Schedule( TimeEventObject, TimeEventFunction, TimeEventFuncti
self.TimeEventObject = TimeEventObject
self.Schedules[#self.Schedules+1] = _TIMERDISPATCHER:AddSchedule(
local ScheduleID = _SCHEDULEDISPATCHER:AddSchedule(
self,
TimeEventFunction,
TimeEventFunctionArguments,
@ -96,51 +108,37 @@ function SCHEDULER:Schedule( TimeEventObject, TimeEventFunction, TimeEventFuncti
RandomizationFactor,
StopSeconds
)
return self
end
--- (Re-)Starts the scheduler.
-- @param #SCHEDULER self
-- @return #SCHEDULER self
function SCHEDULER:Start()
self:F2()
if self.RepeatSecondsInterval ~= 0 then
self.Repeat = true
end
if self.StartSeconds then
self:T( { self.StartSeconds } )
self.Schedules[#self.Schedules+1] = _TIMERDISPATCHER:AddSchedule(
self,
self.TimeEventObject,
self.TimeEventFunction,
self.TimeEventFunctionArguments,
self.StartSeconds,
self.RepeatSecondsInterval,
self.RandomizationFactor,
self.StopSeconds
)
end
return self
self.Schedules[#self.Schedules+1] = ScheduleID
return ScheduleID
end
--- Stops the scheduler.
--- (Re-)Starts the schedules or a specific schedule if a valid ScheduleID is provided.
-- @param #SCHEDULER self
-- @return #SCHEDULER self
function SCHEDULER:Stop()
self:F2( self.TimeEventObject )
-- @param #number ScheduleID (optional) The ScheduleID of the planned (repeating) schedule.
function SCHEDULER:Start( ScheduleID )
self:F3( { ScheduleID } )
self.Repeat = false
if self.ScheduleID then
self:E( "Stop Schedule" )
timer.removeFunction( self.ScheduleID )
end
self.ScheduleID = nil
_SCHEDULEDISPATCHER:Start( self, ScheduleID )
end
return self
--- Stops the schedules or a specific schedule if a valid ScheduleID is provided.
-- @param #SCHEDULER self
-- @param #number ScheduleID (optional) The ScheduleID of the planned (repeating) schedule.
function SCHEDULER:Stop( ScheduleID )
self:F3( { ScheduleID } )
_SCHEDULEDISPATCHER:Stop( self, ScheduleID )
end
--- Removes a specific schedule if a valid ScheduleID is provided.
-- @param #SCHEDULER self
-- @param #number ScheduleID (optional) The ScheduleID of the planned (repeating) schedule.
function SCHEDULER:Remove( ScheduleID )
self:F3( { ScheduleID } )
_SCHEDULEDISPATCHER:Remove( self, ScheduleID )
end

View File

@ -58,6 +58,8 @@ do -- FSM
self._EndStates = {}
self._Scores = {}
self.CallScheduler = SCHEDULER:New( self )
return self
end
@ -313,7 +315,8 @@ do -- FSM
self:E( { EventName = EventName } )
return function( self, DelaySeconds, ... )
self:T( "Delayed Event: " .. EventName )
SCHEDULER:New( self, self._handler, { EventName, ... }, DelaySeconds )
local CallID = self.CallScheduler:Schedule( self, self._handler, { EventName, ... }, DelaySeconds or 1 )
self:T( { CallID = CallID } )
end
end

View File

@ -7,7 +7,7 @@ Include.File( "Utilities/Utils" )
--- Core Classes
Include.File( "Core/Base" )
Include.File( "Core/Scheduler" )
Include.File( "Core/Timer")
Include.File( "Core/ScheduleDispatcher")
Include.File( "Core/Event" )
Include.File( "Core/Menu" )
Include.File( "Core/Zone" )
@ -64,8 +64,8 @@ Include.File( "Tasking/Task_A2G" )
--- Declare the event dispatcher based on the EVENT class
_EVENTDISPATCHER = EVENT:New() -- Core.Event#EVENT
--- Declare the timer dispatcher based on the TIMER class
_TIMERDISPATCHER = TIMER:New() -- Core.Timer#TIMER
--- Declare the timer dispatcher based on the SCHEDULEDISPATCHER class
_SCHEDULEDISPATCHER = SCHEDULEDISPATCHER:New() -- Core.Timer#SCHEDULEDISPATCHER
--- Declare the main database object, which is used internally by the MOOSE classes.
_DATABASE = DATABASE:New() -- Database#DATABASE

View File

@ -539,6 +539,7 @@ function TASK_BASE:RemoveStateMachine( TaskUnit )
self.Fsm[TaskUnit] = nil
collectgarbage()
self:T( "Garbage Collected, Processes should be finalized now ...")
end
--- Checks if there is a FiniteStateMachine assigned to Task@{Unit} for @{Task}

View File

@ -42,24 +42,19 @@ end
do
local Test1 = TEST_BASE:New( "Hello World Test 1" )
collectgarbage()
Test1 = nil
collectgarbage()
BASE:E( Test1 )
end
collectgarbage()
local Test2 = TEST_BASE:New( "Hello World Test 2" )
collectgarbage()
BASE:E( Test2 )
local Test3 = TEST_BASE:New( "Hello World Test 3" )
Test3 = nil
BASE:E( Test3 )
collectgarbage()
BASE:E( Test3 )
BASE:E( "Collect Garbage executed." )
BASE:E( "You should only see a Hello Worlld message for Test 2!" )
BASE:E( "Check if Test 1 and Test 3 are garbage collected!" )