job scheduler works with run once and run periodic schedules. Stop logic is not fully thought through.

Dependencies:   LinkedList

Dependents:   JobSchedulerDemo Borsch

scheduler.h

Committer:
sgnezdov
Date:
2017-08-02
Revision:
13:6be67ee77861
Parent:
7:98c8b2eabea3
Child:
14:a30cc783ae89

File content as of revision 13:6be67ee77861:

#pragma once

#include "mbed.h"
#include "LinkedList.h"
#include "jobService.h"

namespace JobScheduler {
    
    typedef int JobID;
    typedef int JobTypeID;
    
    typedef int ActionType;
    
    /**
    Declares concept of the schedule.
    For example, run once, run periodically, run at the top of the hour,
    never run, run weekly, monthly, etc.
    */
    class ISchedule {
        public:
           
            virtual ~ISchedule() {};
            
            /**
            NextRunTime returns next run time or zero if never.
            
            @param from reflects current time.
            Test cases may manipulate the value of from to test algorithms.
            
            If return time is less than from, then scheduler will run the job
            ASAP.
            
            If return time is more than from, then scheduler will run the job
            in the future calculated as (return_value - from).
            */
            virtual time_t NextRunTime(time_t from) = 0;
    };
    
    struct IJobData {
        public:
            virtual ~IJobData() = 0;
    };
    
    /** 
    ResBase provide common properties for Scheduler response queue.
    */
    struct ResBase {
        Error error;
        ResBase(Error err) : error(err) {}
    };
    
    template<typename T>
    struct Response : ResBase {
       T data;
       Response(Error anError, T aData) : ResBase(anError), data(aData) {}
    };
       
    struct Action {
        ActionType type;
        Queue<ResBase, 1> resQueue;
        Action(ActionType t): type(t) {}
    };
       
    /**
    Job describes the job, its parameters and schedule.
    */
    class Job {
        public:
        
        Job(JobTypeID typeID, ISchedule *schedule, IJobData *data)
        : _id(0), _typeID(typeID), _schedule(schedule), _data(data) {}

        JobID GetID() const {
            return _id;
        }
        
        void Init(JobID id) {
            _id = id;
        }
        
        JobTypeID GetTypeID() const {
            return _typeID;
        }
        
        ISchedule *GetSchedule() {
            return _schedule;
        }
        
        private:
            JobID _id;
            JobTypeID _typeID;
            ISchedule *_schedule;
            IJobData *_data;
    };
    
    class Appointment {
        
        public:
        
        Appointment(JobTypeID typeID, ISchedule *schedule, IJobData *data, time_t time)
        : _job(typeID, schedule, data), _time(time) { }
        
        time_t GetTime() {
            return _time;
        }
        
        void SetTime(time_t time) {
            _time = time;
        }
        
        Job* GetJob() {
            return &_job;
        }
        
        private:
        
        Job _job;
        time_t _time;
    };
       
    /**
    Scheduler is responsible for maintaining job schedules and running jobs
    in a serial manner.  For example, next job appointments can be:
    14:05, 14:05, 15:00, 16:00 and scheduler will run jobs even one after
    another even if job run times collide.  
    
    The scheduler has no means of stopping running job.
    
    The order of execution is preserved if job runs for a long time.

    */
    class Scheduler {
        public:
            Scheduler(JobService *_jobService);
            
            void Start();
            void Stop();
            void WaitToStop();
            
            /** JobAdd adds job of typeID and returns ID of added job. */
            Response<JobID> JobAdd(JobTypeID typeID, ISchedule *schedule, IJobData *data);
            void JobRemove(JobID jobID);
            LinkedList<Job> JobList();
        private:
            static void updateAdapter(void *target);
            void updateHandler();

            static void runAdapter(void *target);
            void runHandler();
            
            Response<JobID> reschedule(Appointment *apt);
            
            void process(Action *action);
            void onWakeOnce();
        private:
            Thread _updater;
            bool _quitUpdater;
            /** _updates contains incoming actions for _updater */
            Queue<Action, 5> _updates;
            
            Thread _runner;
            bool _quitRunner;
            /** _runs contains Appointments for _runner to execute. */
            Queue<Appointment, 5> _runs;
            
            JobService *_jobService;
            JobID _nextJobID;
            LinkedList<Appointment> _timeline;           
    };  
}