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

Dependencies:   LinkedList

Dependents:   JobSchedulerDemo Borsch

Committer:
sgnezdov
Date:
Thu Aug 03 18:15:21 2017 +0000
Revision:
17:3b565ccd291b
Parent:
16:f61b62b119dd
changed JobList() to AppointmentList()

Who changed what in which revision?

UserRevisionLine numberNew contents of line
sgnezdov 0:806403f3d0d1 1 #pragma once
sgnezdov 0:806403f3d0d1 2
sgnezdov 0:806403f3d0d1 3 #include "mbed.h"
sgnezdov 0:806403f3d0d1 4 #include "LinkedList.h"
sgnezdov 0:806403f3d0d1 5 #include "jobService.h"
sgnezdov 0:806403f3d0d1 6
sgnezdov 0:806403f3d0d1 7 namespace JobScheduler {
sgnezdov 0:806403f3d0d1 8
sgnezdov 0:806403f3d0d1 9 typedef int JobID;
sgnezdov 1:ec6a1d054065 10 typedef int JobTypeID;
sgnezdov 2:9bf5366ad5a2 11
sgnezdov 0:806403f3d0d1 12 typedef int ActionType;
sgnezdov 0:806403f3d0d1 13
sgnezdov 0:806403f3d0d1 14 /**
sgnezdov 0:806403f3d0d1 15 Declares concept of the schedule.
sgnezdov 0:806403f3d0d1 16 For example, run once, run periodically, run at the top of the hour,
sgnezdov 0:806403f3d0d1 17 never run, run weekly, monthly, etc.
sgnezdov 0:806403f3d0d1 18 */
sgnezdov 0:806403f3d0d1 19 class ISchedule {
sgnezdov 0:806403f3d0d1 20 public:
sgnezdov 2:9bf5366ad5a2 21
sgnezdov 2:9bf5366ad5a2 22 virtual ~ISchedule() {};
sgnezdov 2:9bf5366ad5a2 23
sgnezdov 2:9bf5366ad5a2 24 /**
sgnezdov 2:9bf5366ad5a2 25 NextRunTime returns next run time or zero if never.
sgnezdov 2:9bf5366ad5a2 26
sgnezdov 2:9bf5366ad5a2 27 @param from reflects current time.
sgnezdov 2:9bf5366ad5a2 28 Test cases may manipulate the value of from to test algorithms.
sgnezdov 2:9bf5366ad5a2 29
sgnezdov 2:9bf5366ad5a2 30 If return time is less than from, then scheduler will run the job
sgnezdov 2:9bf5366ad5a2 31 ASAP.
sgnezdov 2:9bf5366ad5a2 32
sgnezdov 2:9bf5366ad5a2 33 If return time is more than from, then scheduler will run the job
sgnezdov 2:9bf5366ad5a2 34 in the future calculated as (return_value - from).
sgnezdov 2:9bf5366ad5a2 35 */
sgnezdov 2:9bf5366ad5a2 36 virtual time_t NextRunTime(time_t from) = 0;
sgnezdov 16:f61b62b119dd 37
sgnezdov 16:f61b62b119dd 38 /**
sgnezdov 16:f61b62b119dd 39 Returns unique number to identify each schedule type
sgnezdov 16:f61b62b119dd 40 without enabling C++ RTTI.
sgnezdov 16:f61b62b119dd 41 */
sgnezdov 16:f61b62b119dd 42 virtual int ScheduleType() = 0;
sgnezdov 2:9bf5366ad5a2 43 };
sgnezdov 2:9bf5366ad5a2 44
sgnezdov 2:9bf5366ad5a2 45 struct IJobData {
sgnezdov 2:9bf5366ad5a2 46 public:
sgnezdov 2:9bf5366ad5a2 47 virtual ~IJobData() = 0;
sgnezdov 0:806403f3d0d1 48 };
sgnezdov 0:806403f3d0d1 49
sgnezdov 1:ec6a1d054065 50 /**
sgnezdov 1:ec6a1d054065 51 ResBase provide common properties for Scheduler response queue.
sgnezdov 1:ec6a1d054065 52 */
sgnezdov 1:ec6a1d054065 53 struct ResBase {
sgnezdov 0:806403f3d0d1 54 Error error;
sgnezdov 1:ec6a1d054065 55 ResBase(Error err) : error(err) {}
sgnezdov 0:806403f3d0d1 56 };
sgnezdov 0:806403f3d0d1 57
sgnezdov 1:ec6a1d054065 58 template<typename T>
sgnezdov 1:ec6a1d054065 59 struct Response : ResBase {
sgnezdov 3:f08f55827736 60 T data;
sgnezdov 3:f08f55827736 61 Response(Error anError, T aData) : ResBase(anError), data(aData) {}
sgnezdov 1:ec6a1d054065 62 };
sgnezdov 1:ec6a1d054065 63
sgnezdov 0:806403f3d0d1 64 struct Action {
sgnezdov 0:806403f3d0d1 65 ActionType type;
sgnezdov 1:ec6a1d054065 66 Queue<ResBase, 1> resQueue;
sgnezdov 1:ec6a1d054065 67 Action(ActionType t): type(t) {}
sgnezdov 0:806403f3d0d1 68 };
sgnezdov 0:806403f3d0d1 69
sgnezdov 0:806403f3d0d1 70 /**
sgnezdov 2:9bf5366ad5a2 71 Job describes the job, its parameters and schedule.
sgnezdov 0:806403f3d0d1 72 */
sgnezdov 0:806403f3d0d1 73 class Job {
sgnezdov 0:806403f3d0d1 74 public:
sgnezdov 0:806403f3d0d1 75
sgnezdov 2:9bf5366ad5a2 76 Job(JobTypeID typeID, ISchedule *schedule, IJobData *data)
sgnezdov 3:f08f55827736 77 : _id(0), _typeID(typeID), _schedule(schedule), _data(data) {}
sgnezdov 0:806403f3d0d1 78
sgnezdov 0:806403f3d0d1 79 JobID GetID() const {
sgnezdov 0:806403f3d0d1 80 return _id;
sgnezdov 3:f08f55827736 81 }
sgnezdov 0:806403f3d0d1 82
sgnezdov 2:9bf5366ad5a2 83 void Init(JobID id) {
sgnezdov 2:9bf5366ad5a2 84 _id = id;
sgnezdov 2:9bf5366ad5a2 85 }
sgnezdov 2:9bf5366ad5a2 86
sgnezdov 1:ec6a1d054065 87 JobTypeID GetTypeID() const {
sgnezdov 0:806403f3d0d1 88 return _typeID;
sgnezdov 3:f08f55827736 89 }
sgnezdov 3:f08f55827736 90
sgnezdov 3:f08f55827736 91 ISchedule *GetSchedule() {
sgnezdov 3:f08f55827736 92 return _schedule;
sgnezdov 3:f08f55827736 93 }
sgnezdov 0:806403f3d0d1 94
sgnezdov 0:806403f3d0d1 95 private:
sgnezdov 0:806403f3d0d1 96 JobID _id;
sgnezdov 1:ec6a1d054065 97 JobTypeID _typeID;
sgnezdov 2:9bf5366ad5a2 98 ISchedule *_schedule;
sgnezdov 2:9bf5366ad5a2 99 IJobData *_data;
sgnezdov 0:806403f3d0d1 100 };
sgnezdov 0:806403f3d0d1 101
sgnezdov 2:9bf5366ad5a2 102 class Appointment {
sgnezdov 2:9bf5366ad5a2 103
sgnezdov 2:9bf5366ad5a2 104 public:
sgnezdov 2:9bf5366ad5a2 105
sgnezdov 2:9bf5366ad5a2 106 Appointment(JobTypeID typeID, ISchedule *schedule, IJobData *data, time_t time)
sgnezdov 2:9bf5366ad5a2 107 : _job(typeID, schedule, data), _time(time) { }
sgnezdov 2:9bf5366ad5a2 108
sgnezdov 2:9bf5366ad5a2 109 time_t GetTime() {
sgnezdov 2:9bf5366ad5a2 110 return _time;
sgnezdov 2:9bf5366ad5a2 111 }
sgnezdov 2:9bf5366ad5a2 112
sgnezdov 3:f08f55827736 113 void SetTime(time_t time) {
sgnezdov 3:f08f55827736 114 _time = time;
sgnezdov 3:f08f55827736 115 }
sgnezdov 3:f08f55827736 116
sgnezdov 2:9bf5366ad5a2 117 Job* GetJob() {
sgnezdov 2:9bf5366ad5a2 118 return &_job;
sgnezdov 2:9bf5366ad5a2 119 }
sgnezdov 2:9bf5366ad5a2 120
sgnezdov 2:9bf5366ad5a2 121 private:
sgnezdov 2:9bf5366ad5a2 122
sgnezdov 2:9bf5366ad5a2 123 Job _job;
sgnezdov 2:9bf5366ad5a2 124 time_t _time;
sgnezdov 2:9bf5366ad5a2 125 };
sgnezdov 2:9bf5366ad5a2 126
sgnezdov 0:806403f3d0d1 127 /**
sgnezdov 0:806403f3d0d1 128 Scheduler is responsible for maintaining job schedules and running jobs
sgnezdov 0:806403f3d0d1 129 in a serial manner. For example, next job appointments can be:
sgnezdov 0:806403f3d0d1 130 14:05, 14:05, 15:00, 16:00 and scheduler will run jobs even one after
sgnezdov 0:806403f3d0d1 131 another even if job run times collide.
sgnezdov 0:806403f3d0d1 132
sgnezdov 0:806403f3d0d1 133 The scheduler has no means of stopping running job.
sgnezdov 0:806403f3d0d1 134
sgnezdov 0:806403f3d0d1 135 The order of execution is preserved if job runs for a long time.
sgnezdov 0:806403f3d0d1 136
sgnezdov 0:806403f3d0d1 137 */
sgnezdov 0:806403f3d0d1 138 class Scheduler {
sgnezdov 0:806403f3d0d1 139 public:
sgnezdov 0:806403f3d0d1 140 Scheduler(JobService *_jobService);
sgnezdov 0:806403f3d0d1 141
sgnezdov 0:806403f3d0d1 142 void Start();
sgnezdov 0:806403f3d0d1 143 void Stop();
sgnezdov 0:806403f3d0d1 144 void WaitToStop();
sgnezdov 0:806403f3d0d1 145
sgnezdov 0:806403f3d0d1 146 /** JobAdd adds job of typeID and returns ID of added job. */
sgnezdov 2:9bf5366ad5a2 147 Response<JobID> JobAdd(JobTypeID typeID, ISchedule *schedule, IJobData *data);
sgnezdov 2:9bf5366ad5a2 148 void JobRemove(JobID jobID);
sgnezdov 17:3b565ccd291b 149 void AppointmentList(LinkedList<Appointment>& apts);
sgnezdov 0:806403f3d0d1 150 private:
sgnezdov 0:806403f3d0d1 151 static void updateAdapter(void *target);
sgnezdov 0:806403f3d0d1 152 void updateHandler();
sgnezdov 4:78bcd5a675e1 153
sgnezdov 4:78bcd5a675e1 154 static void runAdapter(void *target);
sgnezdov 4:78bcd5a675e1 155 void runHandler();
sgnezdov 1:ec6a1d054065 156
sgnezdov 5:d8f69ac330f2 157 Response<JobID> reschedule(Appointment *apt);
sgnezdov 5:d8f69ac330f2 158
sgnezdov 0:806403f3d0d1 159 void process(Action *action);
sgnezdov 3:f08f55827736 160 void onWakeOnce();
sgnezdov 0:806403f3d0d1 161 private:
sgnezdov 0:806403f3d0d1 162 Thread _updater;
sgnezdov 7:98c8b2eabea3 163 bool _quitUpdater;
sgnezdov 7:98c8b2eabea3 164 /** _updates contains incoming actions for _updater */
sgnezdov 7:98c8b2eabea3 165 Queue<Action, 5> _updates;
sgnezdov 7:98c8b2eabea3 166
sgnezdov 4:78bcd5a675e1 167 Thread _runner;
sgnezdov 7:98c8b2eabea3 168 bool _quitRunner;
sgnezdov 7:98c8b2eabea3 169 /** _runs contains Appointments for _runner to execute. */
sgnezdov 7:98c8b2eabea3 170 Queue<Appointment, 5> _runs;
sgnezdov 7:98c8b2eabea3 171
sgnezdov 0:806403f3d0d1 172 JobService *_jobService;
sgnezdov 0:806403f3d0d1 173 JobID _nextJobID;
sgnezdov 3:f08f55827736 174 LinkedList<Appointment> _timeline;
sgnezdov 0:806403f3d0d1 175 };
sgnezdov 0:806403f3d0d1 176 }