job scheduler works with run once and run periodic schedules. Stop logic is not fully thought through.
Dependents: JobSchedulerDemo Borsch
scheduler.h@4:78bcd5a675e1, 2017-07-11 (annotated)
- Committer:
- sgnezdov
- Date:
- Tue Jul 11 22:05:12 2017 +0000
- Revision:
- 4:78bcd5a675e1
- Parent:
- 3:f08f55827736
- Child:
- 5:d8f69ac330f2
added runner concept
Who changed what in which revision?
User | Revision | Line number | New 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 | 2:9bf5366ad5a2 | 37 | }; |
sgnezdov | 2:9bf5366ad5a2 | 38 | |
sgnezdov | 2:9bf5366ad5a2 | 39 | struct IJobData { |
sgnezdov | 2:9bf5366ad5a2 | 40 | public: |
sgnezdov | 2:9bf5366ad5a2 | 41 | virtual ~IJobData() = 0; |
sgnezdov | 0:806403f3d0d1 | 42 | }; |
sgnezdov | 0:806403f3d0d1 | 43 | |
sgnezdov | 1:ec6a1d054065 | 44 | /** |
sgnezdov | 1:ec6a1d054065 | 45 | ResBase provide common properties for Scheduler response queue. |
sgnezdov | 1:ec6a1d054065 | 46 | */ |
sgnezdov | 1:ec6a1d054065 | 47 | struct ResBase { |
sgnezdov | 0:806403f3d0d1 | 48 | Error error; |
sgnezdov | 1:ec6a1d054065 | 49 | ResBase(Error err) : error(err) {} |
sgnezdov | 0:806403f3d0d1 | 50 | }; |
sgnezdov | 0:806403f3d0d1 | 51 | |
sgnezdov | 1:ec6a1d054065 | 52 | template<typename T> |
sgnezdov | 1:ec6a1d054065 | 53 | struct Response : ResBase { |
sgnezdov | 3:f08f55827736 | 54 | T data; |
sgnezdov | 3:f08f55827736 | 55 | Response(Error anError, T aData) : ResBase(anError), data(aData) {} |
sgnezdov | 1:ec6a1d054065 | 56 | }; |
sgnezdov | 1:ec6a1d054065 | 57 | |
sgnezdov | 0:806403f3d0d1 | 58 | struct Action { |
sgnezdov | 0:806403f3d0d1 | 59 | ActionType type; |
sgnezdov | 1:ec6a1d054065 | 60 | Queue<ResBase, 1> resQueue; |
sgnezdov | 1:ec6a1d054065 | 61 | Action(ActionType t): type(t) {} |
sgnezdov | 0:806403f3d0d1 | 62 | }; |
sgnezdov | 0:806403f3d0d1 | 63 | |
sgnezdov | 0:806403f3d0d1 | 64 | /** |
sgnezdov | 2:9bf5366ad5a2 | 65 | Job describes the job, its parameters and schedule. |
sgnezdov | 0:806403f3d0d1 | 66 | */ |
sgnezdov | 0:806403f3d0d1 | 67 | class Job { |
sgnezdov | 0:806403f3d0d1 | 68 | public: |
sgnezdov | 0:806403f3d0d1 | 69 | |
sgnezdov | 2:9bf5366ad5a2 | 70 | Job(JobTypeID typeID, ISchedule *schedule, IJobData *data) |
sgnezdov | 3:f08f55827736 | 71 | : _id(0), _typeID(typeID), _schedule(schedule), _data(data) {} |
sgnezdov | 0:806403f3d0d1 | 72 | |
sgnezdov | 0:806403f3d0d1 | 73 | JobID GetID() const { |
sgnezdov | 0:806403f3d0d1 | 74 | return _id; |
sgnezdov | 3:f08f55827736 | 75 | } |
sgnezdov | 0:806403f3d0d1 | 76 | |
sgnezdov | 2:9bf5366ad5a2 | 77 | void Init(JobID id) { |
sgnezdov | 2:9bf5366ad5a2 | 78 | _id = id; |
sgnezdov | 2:9bf5366ad5a2 | 79 | } |
sgnezdov | 2:9bf5366ad5a2 | 80 | |
sgnezdov | 1:ec6a1d054065 | 81 | JobTypeID GetTypeID() const { |
sgnezdov | 0:806403f3d0d1 | 82 | return _typeID; |
sgnezdov | 3:f08f55827736 | 83 | } |
sgnezdov | 3:f08f55827736 | 84 | |
sgnezdov | 3:f08f55827736 | 85 | ISchedule *GetSchedule() { |
sgnezdov | 3:f08f55827736 | 86 | return _schedule; |
sgnezdov | 3:f08f55827736 | 87 | } |
sgnezdov | 0:806403f3d0d1 | 88 | |
sgnezdov | 0:806403f3d0d1 | 89 | private: |
sgnezdov | 0:806403f3d0d1 | 90 | JobID _id; |
sgnezdov | 1:ec6a1d054065 | 91 | JobTypeID _typeID; |
sgnezdov | 2:9bf5366ad5a2 | 92 | ISchedule *_schedule; |
sgnezdov | 2:9bf5366ad5a2 | 93 | IJobData *_data; |
sgnezdov | 0:806403f3d0d1 | 94 | }; |
sgnezdov | 0:806403f3d0d1 | 95 | |
sgnezdov | 2:9bf5366ad5a2 | 96 | class Appointment { |
sgnezdov | 2:9bf5366ad5a2 | 97 | |
sgnezdov | 2:9bf5366ad5a2 | 98 | public: |
sgnezdov | 2:9bf5366ad5a2 | 99 | |
sgnezdov | 2:9bf5366ad5a2 | 100 | Appointment(JobTypeID typeID, ISchedule *schedule, IJobData *data, time_t time) |
sgnezdov | 2:9bf5366ad5a2 | 101 | : _job(typeID, schedule, data), _time(time) { } |
sgnezdov | 2:9bf5366ad5a2 | 102 | |
sgnezdov | 2:9bf5366ad5a2 | 103 | time_t GetTime() { |
sgnezdov | 2:9bf5366ad5a2 | 104 | return _time; |
sgnezdov | 2:9bf5366ad5a2 | 105 | } |
sgnezdov | 2:9bf5366ad5a2 | 106 | |
sgnezdov | 3:f08f55827736 | 107 | void SetTime(time_t time) { |
sgnezdov | 3:f08f55827736 | 108 | _time = time; |
sgnezdov | 3:f08f55827736 | 109 | } |
sgnezdov | 3:f08f55827736 | 110 | |
sgnezdov | 2:9bf5366ad5a2 | 111 | Job* GetJob() { |
sgnezdov | 2:9bf5366ad5a2 | 112 | return &_job; |
sgnezdov | 2:9bf5366ad5a2 | 113 | } |
sgnezdov | 2:9bf5366ad5a2 | 114 | |
sgnezdov | 2:9bf5366ad5a2 | 115 | private: |
sgnezdov | 2:9bf5366ad5a2 | 116 | |
sgnezdov | 2:9bf5366ad5a2 | 117 | Job _job; |
sgnezdov | 2:9bf5366ad5a2 | 118 | time_t _time; |
sgnezdov | 2:9bf5366ad5a2 | 119 | }; |
sgnezdov | 2:9bf5366ad5a2 | 120 | |
sgnezdov | 0:806403f3d0d1 | 121 | /** |
sgnezdov | 0:806403f3d0d1 | 122 | Scheduler is responsible for maintaining job schedules and running jobs |
sgnezdov | 0:806403f3d0d1 | 123 | in a serial manner. For example, next job appointments can be: |
sgnezdov | 0:806403f3d0d1 | 124 | 14:05, 14:05, 15:00, 16:00 and scheduler will run jobs even one after |
sgnezdov | 0:806403f3d0d1 | 125 | another even if job run times collide. |
sgnezdov | 0:806403f3d0d1 | 126 | |
sgnezdov | 0:806403f3d0d1 | 127 | The scheduler has no means of stopping running job. |
sgnezdov | 0:806403f3d0d1 | 128 | |
sgnezdov | 0:806403f3d0d1 | 129 | The order of execution is preserved if job runs for a long time. |
sgnezdov | 0:806403f3d0d1 | 130 | |
sgnezdov | 0:806403f3d0d1 | 131 | */ |
sgnezdov | 0:806403f3d0d1 | 132 | class Scheduler { |
sgnezdov | 0:806403f3d0d1 | 133 | public: |
sgnezdov | 0:806403f3d0d1 | 134 | Scheduler(JobService *_jobService); |
sgnezdov | 0:806403f3d0d1 | 135 | |
sgnezdov | 0:806403f3d0d1 | 136 | void Start(); |
sgnezdov | 0:806403f3d0d1 | 137 | void Stop(); |
sgnezdov | 0:806403f3d0d1 | 138 | void WaitToStop(); |
sgnezdov | 0:806403f3d0d1 | 139 | |
sgnezdov | 0:806403f3d0d1 | 140 | /** JobAdd adds job of typeID and returns ID of added job. */ |
sgnezdov | 2:9bf5366ad5a2 | 141 | Response<JobID> JobAdd(JobTypeID typeID, ISchedule *schedule, IJobData *data); |
sgnezdov | 2:9bf5366ad5a2 | 142 | void JobRemove(JobID jobID); |
sgnezdov | 0:806403f3d0d1 | 143 | private: |
sgnezdov | 0:806403f3d0d1 | 144 | static void updateAdapter(void *target); |
sgnezdov | 0:806403f3d0d1 | 145 | void updateHandler(); |
sgnezdov | 4:78bcd5a675e1 | 146 | |
sgnezdov | 4:78bcd5a675e1 | 147 | static void runAdapter(void *target); |
sgnezdov | 4:78bcd5a675e1 | 148 | void runHandler(); |
sgnezdov | 1:ec6a1d054065 | 149 | |
sgnezdov | 0:806403f3d0d1 | 150 | void process(Action *action); |
sgnezdov | 3:f08f55827736 | 151 | void onWakeOnce(); |
sgnezdov | 0:806403f3d0d1 | 152 | private: |
sgnezdov | 0:806403f3d0d1 | 153 | Thread _updater; |
sgnezdov | 4:78bcd5a675e1 | 154 | Thread _runner; |
sgnezdov | 0:806403f3d0d1 | 155 | bool _quit; |
sgnezdov | 0:806403f3d0d1 | 156 | JobService *_jobService; |
sgnezdov | 0:806403f3d0d1 | 157 | JobID _nextJobID; |
sgnezdov | 4:78bcd5a675e1 | 158 | /** _updates contains incoming actions for _updater */ |
sgnezdov | 4:78bcd5a675e1 | 159 | Queue<Action, 5> _updates; |
sgnezdov | 4:78bcd5a675e1 | 160 | /** _runs contains Appointments for _runner to execute. */ |
sgnezdov | 4:78bcd5a675e1 | 161 | Queue<Appointment, 5> _runs; |
sgnezdov | 3:f08f55827736 | 162 | LinkedList<Appointment> _timeline; |
sgnezdov | 0:806403f3d0d1 | 163 | }; |
sgnezdov | 0:806403f3d0d1 | 164 | } |