Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: JobSchedulerDemo Borsch
scheduler.cpp@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 | #include "scheduler.h" |
| sgnezdov | 0:806403f3d0d1 | 2 | |
| sgnezdov | 3:f08f55827736 | 3 | Timeout WakeOnce; |
| sgnezdov | 3:f08f55827736 | 4 | |
| sgnezdov | 0:806403f3d0d1 | 5 | void update(void *target) { |
| sgnezdov | 0:806403f3d0d1 | 6 | }; |
| sgnezdov | 0:806403f3d0d1 | 7 | |
| sgnezdov | 0:806403f3d0d1 | 8 | namespace JobScheduler { |
| sgnezdov | 1:ec6a1d054065 | 9 | |
| sgnezdov | 3:f08f55827736 | 10 | const ActionType JobAddAT(1); |
| sgnezdov | 3:f08f55827736 | 11 | const ActionType JobRunAT(3); |
| sgnezdov | 3:f08f55827736 | 12 | |
| sgnezdov | 2:9bf5366ad5a2 | 13 | bool descendingTimeline(Appointment *a1, Appointment *a2) |
| sgnezdov | 2:9bf5366ad5a2 | 14 | { |
| sgnezdov | 2:9bf5366ad5a2 | 15 | bool rv = a1->GetTime() <= a2->GetTime(); |
| sgnezdov | 2:9bf5366ad5a2 | 16 | //printf("(%d %d:%d)", *d1, *d2, rv); |
| sgnezdov | 2:9bf5366ad5a2 | 17 | return rv; |
| sgnezdov | 2:9bf5366ad5a2 | 18 | }; |
| sgnezdov | 3:f08f55827736 | 19 | |
| sgnezdov | 2:9bf5366ad5a2 | 20 | /** |
| sgnezdov | 2:9bf5366ad5a2 | 21 | JobAddReq adds new job to the scheduler. |
| sgnezdov | 2:9bf5366ad5a2 | 22 | */ |
| sgnezdov | 1:ec6a1d054065 | 23 | struct JobAddReq: Action { |
| sgnezdov | 2:9bf5366ad5a2 | 24 | Appointment *apt; |
| sgnezdov | 1:ec6a1d054065 | 25 | Response<JobID> response; |
| sgnezdov | 2:9bf5366ad5a2 | 26 | JobAddReq(Appointment *a) : Action(JobAddAT), apt(a), response(NoError, 0) {} |
| sgnezdov | 1:ec6a1d054065 | 27 | }; |
| sgnezdov | 0:806403f3d0d1 | 28 | |
| sgnezdov | 3:f08f55827736 | 29 | struct JobRunReq: Action { |
| sgnezdov | 3:f08f55827736 | 30 | JobRunReq() : Action(JobRunAT) {} |
| sgnezdov | 3:f08f55827736 | 31 | }; |
| sgnezdov | 3:f08f55827736 | 32 | |
| sgnezdov | 0:806403f3d0d1 | 33 | Scheduler::Scheduler(JobService *jobService) |
| sgnezdov | 2:9bf5366ad5a2 | 34 | : _jobService(jobService), _nextJobID(1) { } |
| sgnezdov | 0:806403f3d0d1 | 35 | |
| sgnezdov | 0:806403f3d0d1 | 36 | void Scheduler::updateAdapter(void *thisPointer) { |
| sgnezdov | 0:806403f3d0d1 | 37 | Scheduler *self = static_cast<Scheduler*>(thisPointer); |
| sgnezdov | 0:806403f3d0d1 | 38 | self->updateHandler(); |
| sgnezdov | 0:806403f3d0d1 | 39 | } |
| sgnezdov | 4:78bcd5a675e1 | 40 | |
| sgnezdov | 4:78bcd5a675e1 | 41 | void Scheduler::runAdapter(void *thisPointer) { |
| sgnezdov | 4:78bcd5a675e1 | 42 | Scheduler *self = static_cast<Scheduler*>(thisPointer); |
| sgnezdov | 4:78bcd5a675e1 | 43 | self->runHandler(); |
| sgnezdov | 4:78bcd5a675e1 | 44 | } |
| sgnezdov | 0:806403f3d0d1 | 45 | |
| sgnezdov | 0:806403f3d0d1 | 46 | void Scheduler::Start() { |
| sgnezdov | 0:806403f3d0d1 | 47 | _updater.start(callback(Scheduler::updateAdapter, this)); |
| sgnezdov | 4:78bcd5a675e1 | 48 | _runner.start(callback(Scheduler::runAdapter, this)); |
| sgnezdov | 0:806403f3d0d1 | 49 | } |
| sgnezdov | 0:806403f3d0d1 | 50 | |
| sgnezdov | 0:806403f3d0d1 | 51 | void Scheduler::Stop() { |
| sgnezdov | 0:806403f3d0d1 | 52 | // it is not thread-safe, but impact is non-existent. |
| sgnezdov | 0:806403f3d0d1 | 53 | _quit = true; |
| sgnezdov | 0:806403f3d0d1 | 54 | } |
| sgnezdov | 0:806403f3d0d1 | 55 | |
| sgnezdov | 0:806403f3d0d1 | 56 | void Scheduler::WaitToStop() { |
| sgnezdov | 0:806403f3d0d1 | 57 | _updater.join(); |
| sgnezdov | 4:78bcd5a675e1 | 58 | _runner.join(); |
| sgnezdov | 0:806403f3d0d1 | 59 | } |
| sgnezdov | 0:806403f3d0d1 | 60 | |
| sgnezdov | 2:9bf5366ad5a2 | 61 | Response<JobID> Scheduler::JobAdd(JobTypeID jobTID, ISchedule *schedule, IJobData *data) { |
| sgnezdov | 2:9bf5366ad5a2 | 62 | Appointment *apt = new Appointment(jobTID, schedule, data, time_t(0)); |
| sgnezdov | 2:9bf5366ad5a2 | 63 | if (NULL == apt) { |
| sgnezdov | 2:9bf5366ad5a2 | 64 | printf("[Scheduler::JobAdd] failed to allocate appointment\n"); |
| sgnezdov | 2:9bf5366ad5a2 | 65 | return Response<JobID>(1, 0); |
| sgnezdov | 2:9bf5366ad5a2 | 66 | } |
| sgnezdov | 2:9bf5366ad5a2 | 67 | JobAddReq req(apt); |
| sgnezdov | 4:78bcd5a675e1 | 68 | _updates.put(&req); |
| sgnezdov | 0:806403f3d0d1 | 69 | // default is wait forever |
| sgnezdov | 1:ec6a1d054065 | 70 | osEvent evt = req.resQueue.get(); |
| sgnezdov | 0:806403f3d0d1 | 71 | if (evt.status == osEventMessage) { |
| sgnezdov | 2:9bf5366ad5a2 | 72 | if (evt.value.p != NULL) { |
| sgnezdov | 2:9bf5366ad5a2 | 73 | printf("[Scheduler::JobAdd] completed ok\n"); |
| sgnezdov | 2:9bf5366ad5a2 | 74 | } else { |
| sgnezdov | 2:9bf5366ad5a2 | 75 | printf("[Scheduler::JobAdd] NOT added (C1)\n"); |
| sgnezdov | 2:9bf5366ad5a2 | 76 | } |
| sgnezdov | 2:9bf5366ad5a2 | 77 | } else { |
| sgnezdov | 2:9bf5366ad5a2 | 78 | // not sure what condition is |
| sgnezdov | 2:9bf5366ad5a2 | 79 | printf("[Scheduler::JobAdd] NOT added (C2)\n"); |
| sgnezdov | 2:9bf5366ad5a2 | 80 | delete apt; |
| sgnezdov | 2:9bf5366ad5a2 | 81 | apt = NULL; |
| sgnezdov | 0:806403f3d0d1 | 82 | } |
| sgnezdov | 2:9bf5366ad5a2 | 83 | // yes, return a copy of the structure |
| sgnezdov | 1:ec6a1d054065 | 84 | return req.response; |
| sgnezdov | 0:806403f3d0d1 | 85 | } |
| sgnezdov | 0:806403f3d0d1 | 86 | |
| sgnezdov | 2:9bf5366ad5a2 | 87 | void Scheduler::JobRemove(JobID jobID) { |
| sgnezdov | 0:806403f3d0d1 | 88 | } |
| sgnezdov | 3:f08f55827736 | 89 | |
| sgnezdov | 3:f08f55827736 | 90 | static JobRunReq jobRunReq; |
| sgnezdov | 3:f08f55827736 | 91 | void Scheduler::onWakeOnce() |
| sgnezdov | 3:f08f55827736 | 92 | { |
| sgnezdov | 4:78bcd5a675e1 | 93 | _updates.put(&jobRunReq); |
| sgnezdov | 3:f08f55827736 | 94 | } |
| sgnezdov | 0:806403f3d0d1 | 95 | |
| sgnezdov | 0:806403f3d0d1 | 96 | void Scheduler::updateHandler() { |
| sgnezdov | 0:806403f3d0d1 | 97 | while (!_quit) { |
| sgnezdov | 0:806403f3d0d1 | 98 | printf("[Scheduler::updateHandler] waiting for action\n"); |
| sgnezdov | 0:806403f3d0d1 | 99 | // wait forever ... |
| sgnezdov | 4:78bcd5a675e1 | 100 | osEvent evt = _updates.get(); |
| sgnezdov | 0:806403f3d0d1 | 101 | if (evt.status == osEventMessage) { |
| sgnezdov | 0:806403f3d0d1 | 102 | printf("[Scheduler::updateHandler] process action\n"); |
| sgnezdov | 0:806403f3d0d1 | 103 | this->process((Action*)evt.value.p); |
| sgnezdov | 0:806403f3d0d1 | 104 | } else { |
| sgnezdov | 0:806403f3d0d1 | 105 | printf("[Scheduler::updateHandler] NOT osEventMessage\n"); |
| sgnezdov | 0:806403f3d0d1 | 106 | } |
| sgnezdov | 0:806403f3d0d1 | 107 | wait(2); |
| sgnezdov | 0:806403f3d0d1 | 108 | } |
| sgnezdov | 0:806403f3d0d1 | 109 | } |
| sgnezdov | 3:f08f55827736 | 110 | |
| sgnezdov | 0:806403f3d0d1 | 111 | void Scheduler::process(Action *action) |
| sgnezdov | 0:806403f3d0d1 | 112 | { |
| sgnezdov | 3:f08f55827736 | 113 | time_t now = time(NULL); // now in seconds |
| sgnezdov | 1:ec6a1d054065 | 114 | switch(action->type) { |
| sgnezdov | 1:ec6a1d054065 | 115 | case JobAddAT: { |
| sgnezdov | 1:ec6a1d054065 | 116 | JobAddReq *req = static_cast<JobAddReq*>(action); |
| sgnezdov | 2:9bf5366ad5a2 | 117 | Job *job = req->apt->GetJob(); |
| sgnezdov | 2:9bf5366ad5a2 | 118 | if (job->GetID() == 0) { |
| sgnezdov | 2:9bf5366ad5a2 | 119 | // assign job its ID |
| sgnezdov | 2:9bf5366ad5a2 | 120 | job->Init(_nextJobID++); |
| sgnezdov | 2:9bf5366ad5a2 | 121 | } |
| sgnezdov | 3:f08f55827736 | 122 | // set next appointment time |
| sgnezdov | 3:f08f55827736 | 123 | req->apt->SetTime(job->GetSchedule()->NextRunTime(now)); |
| sgnezdov | 2:9bf5366ad5a2 | 124 | node<Appointment> *tmp = _timeline.insertOrdered(req->apt, descendingTimeline); |
| sgnezdov | 2:9bf5366ad5a2 | 125 | if (NULL == tmp) { |
| sgnezdov | 2:9bf5366ad5a2 | 126 | printf("[Scheduler::process] timeline insert failed\n"); |
| sgnezdov | 2:9bf5366ad5a2 | 127 | action->resQueue.put(NULL); |
| sgnezdov | 3:f08f55827736 | 128 | // internal state has not changed |
| sgnezdov | 2:9bf5366ad5a2 | 129 | return; |
| sgnezdov | 2:9bf5366ad5a2 | 130 | } |
| sgnezdov | 3:f08f55827736 | 131 | req->response.data = job->GetID(); |
| sgnezdov | 2:9bf5366ad5a2 | 132 | //printf("[Scheduler::process] simulate error\n"); |
| sgnezdov | 2:9bf5366ad5a2 | 133 | //action->resQueue.put(NULL); |
| sgnezdov | 1:ec6a1d054065 | 134 | action->resQueue.put(&req->response); |
| sgnezdov | 1:ec6a1d054065 | 135 | break; |
| sgnezdov | 1:ec6a1d054065 | 136 | } |
| sgnezdov | 3:f08f55827736 | 137 | case JobRunAT: { |
| sgnezdov | 3:f08f55827736 | 138 | // execute job run logic after switch |
| sgnezdov | 3:f08f55827736 | 139 | break; |
| sgnezdov | 3:f08f55827736 | 140 | } |
| sgnezdov | 1:ec6a1d054065 | 141 | default: |
| sgnezdov | 1:ec6a1d054065 | 142 | printf("[Scheduler::process] unknown action type\n"); |
| sgnezdov | 1:ec6a1d054065 | 143 | action->resQueue.put(NULL); |
| sgnezdov | 1:ec6a1d054065 | 144 | } |
| sgnezdov | 3:f08f55827736 | 145 | node<Appointment> *wakeNode = _timeline.pop(1); |
| sgnezdov | 3:f08f55827736 | 146 | Appointment *wakeApt = wakeNode->data; |
| sgnezdov | 3:f08f55827736 | 147 | Job* wakeJob = wakeApt->GetJob(); |
| sgnezdov | 3:f08f55827736 | 148 | time_t sleepTime = wakeApt->GetTime() - now; |
| sgnezdov | 3:f08f55827736 | 149 | if (sleepTime > 0) { |
| sgnezdov | 3:f08f55827736 | 150 | // request wake up |
| sgnezdov | 3:f08f55827736 | 151 | printf("[Scheduler::process] job %d wake up in %d seconds\n", wakeJob->GetID(), sleepTime); |
| sgnezdov | 3:f08f55827736 | 152 | WakeOnce.attach(callback(this, &Scheduler::onWakeOnce), sleepTime); |
| sgnezdov | 3:f08f55827736 | 153 | } else { |
| sgnezdov | 3:f08f55827736 | 154 | // process job |
| sgnezdov | 3:f08f55827736 | 155 | printf("[Scheduler::process] running job ID %d\n", wakeJob->GetID()); |
| sgnezdov | 3:f08f55827736 | 156 | _timeline.remove(1); |
| sgnezdov | 4:78bcd5a675e1 | 157 | _runs.put(wakeApt); |
| sgnezdov | 3:f08f55827736 | 158 | } |
| sgnezdov | 4:78bcd5a675e1 | 159 | } |
| sgnezdov | 4:78bcd5a675e1 | 160 | |
| sgnezdov | 4:78bcd5a675e1 | 161 | void Scheduler::runHandler() { |
| sgnezdov | 4:78bcd5a675e1 | 162 | while (!_quit) { |
| sgnezdov | 4:78bcd5a675e1 | 163 | printf("[Scheduler::runHandler] waiting for action\n"); |
| sgnezdov | 4:78bcd5a675e1 | 164 | // wait forever ... |
| sgnezdov | 4:78bcd5a675e1 | 165 | osEvent evt = _runs.get(); |
| sgnezdov | 4:78bcd5a675e1 | 166 | if (evt.status == osEventMessage) { |
| sgnezdov | 4:78bcd5a675e1 | 167 | printf("[Scheduler::runHandler] run action\n"); |
| sgnezdov | 4:78bcd5a675e1 | 168 | Appointment *apt = (Appointment*)evt.value.p; |
| sgnezdov | 4:78bcd5a675e1 | 169 | printf("[Scheduler::runHandler] TBD: RUN, RESCHEDULE\n"); |
| sgnezdov | 4:78bcd5a675e1 | 170 | } else { |
| sgnezdov | 4:78bcd5a675e1 | 171 | printf("[Scheduler::runHandler] NOT osEventMessage\n"); |
| sgnezdov | 4:78bcd5a675e1 | 172 | } |
| sgnezdov | 4:78bcd5a675e1 | 173 | } |
| sgnezdov | 4:78bcd5a675e1 | 174 | } |
| sgnezdov | 3:f08f55827736 | 175 | |
| sgnezdov | 0:806403f3d0d1 | 176 | |
| sgnezdov | 0:806403f3d0d1 | 177 | } |