Skip to content

Commit 0c8bbd3

Browse files
committed
#41 Ensure events set the running state properly, ensure all possible interrupt points use ISR_ATTR
1 parent fcfd358 commit 0c8bbd3

3 files changed

Lines changed: 35 additions & 13 deletions

File tree

src/TaskManagerIO.cpp

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,21 @@ void TaskManager::yieldForMicros(uint32_t microsToWait) {
186186
tm_internal::atomicWritePtr(&runningTask, prevTask);
187187
}
188188

189+
class TaskExecutionRecorder {
190+
private:
191+
TimerTask* prevTask;
192+
TaskManager* taskMgr;
193+
public:
194+
TaskExecutionRecorder(TaskManager* tm, TimerTask* task) : taskMgr(tm) {
195+
prevTask = tm->getRunningTask();
196+
tm_internal::atomicWritePtr(&tm->runningTask, task);
197+
}
198+
199+
~TaskExecutionRecorder() {
200+
tm_internal::atomicWritePtr(&taskMgr->runningTask, prevTask);
201+
}
202+
};
203+
189204
void TaskManager::dealWithInterrupt() {
190205
interrupted = false;
191206
if(interruptCallback != nullptr) interruptCallback(lastInterruptTrigger);
@@ -194,16 +209,20 @@ void TaskManager::dealWithInterrupt() {
194209
for(taskid_t i=0; i<lastSlot; i++) {
195210
auto* task = getTask(i);
196211
if(task->isInUse() && task->isEvent()) {
197-
tm_internal::atomicWritePtr(&runningTask, task);
198-
task->processEvent();
199-
tm_internal::atomicWritePtr(&runningTask, nullptr);
200-
removeFromQueue(task);
201-
if(task->isRepeating()) {
202-
putItemIntoQueue(task);
212+
if (!task->isRunning()) {
213+
TaskExecutionRecorder taskExecutionRecorder(this, task);
214+
task->processEvent();
215+
removeFromQueue(task);
216+
if (task->isRepeating()) {
217+
putItemIntoQueue(task);
218+
}
219+
else {
220+
task->clear();
221+
tm_internal::tmNotification(tm_internal::TM_INFO_TASK_FREE, TASKMGR_INVALIDID);
222+
}
203223
}
204224
else {
205-
task->clear();
206-
tm_internal::tmNotification(tm_internal::TM_INFO_TASK_FREE, TASKMGR_INVALIDID);
225+
interrupted = true; // we have to assume we still need to process this event next time around.
207226
}
208227
}
209228
}
@@ -223,9 +242,8 @@ void TaskManager::runLoop() {
223242
// by here we know that the task is in use. If it's in use nothing will touch it until it's marked as
224243
// available. We can do this part without a lock, knowing that we are the only thing that will touch
225244
// the task. We further know that all non-immutable fields on TimerTask are volatile.
226-
tm_internal::atomicWritePtr(&runningTask, tm);
245+
TaskExecutionRecorder executionRecorder(this, tm);
227246
tm->execute();
228-
tm_internal::atomicWritePtr(&runningTask, nullptr);
229247
removeFromQueue(tm);
230248
if (tm->isRepeating()) {
231249
putItemIntoQueue(tm);

src/TaskManagerIO.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ class InterruptAbstraction {
7171
virtual void attachInterrupt(pintype_t pin, RawIntHandler fn, uint8_t mode) = 0;
7272
};
7373

74+
class TaskExecutionRecorder;
75+
7476
/**
7577
* TaskManager is a lightweight cooperative co-routine implementation for Arduino, it works by scheduling tasks to be
7678
* done either immediately, or at a future point in time. It is quite efficient at scheduling tasks as internally tasks
@@ -187,7 +189,7 @@ class TaskManager {
187189
* Generally used by the BaseEvent class in the markTriggeredAndNotify to indicate that at least
188190
* one event has now triggered and needs to be evaluated.
189191
*/
190-
void triggerEvents() {
192+
ISR_ATTR void triggerEvents() {
191193
lastInterruptTrigger = 0xff; // 0xff is the shorthand for event trigger basically.
192194
interrupted = true;
193195
}
@@ -299,6 +301,7 @@ class TaskManager {
299301
*/
300302
TimerTask* getRunningTask() { return runningTask; }
301303

304+
friend class TaskExecutionRecorder;
302305
private:
303306
/**
304307
* Finds and allocates the next free task, once this returns a task will either have been allocated, making task

src/TaskTypes.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ void TimerTask::clear() {
127127
}
128128

129129
void TimerTask::processEvent() {
130+
RunningState runningState(this);
130131
myTimingSchedule = eventRef->timeOfNextCheck();
131132
if(eventRef->isTriggered()) {
132133
eventRef->setTriggered(false);
@@ -147,7 +148,7 @@ bool TimerTask::isRepeating() const {
147148
}
148149
}
149150

150-
void BaseEvent::markTriggeredAndNotify() {
151-
setTriggered(true);
151+
ISR_ATTR void BaseEvent::markTriggeredAndNotify() {
152+
triggered = true;
152153
taskMgrAssociation->triggerEvents();
153154
}

0 commit comments

Comments
 (0)