@@ -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+
189204void 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);
0 commit comments