Skip to content

Commit 77acca1

Browse files
committed
Scheduler can now terminate long running processes
1 parent fff5b4d commit 77acca1

6 files changed

Lines changed: 80 additions & 20 deletions

File tree

src/ProcessScheduler/Config.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,21 @@
44
#include <Arduino.h>
55

66
/* Uncomment this to allow Exception Handling functionality */
7-
//#define _PROCESS_EXCEPTION_HANDLING
7+
#define _PROCESS_EXCEPTION_HANDLING
8+
9+
/* Uncomment this to allow the scheduler to interrupt long running processes */
10+
// This requires _PROCESS_EXCEPTION_HANDLING to also be enabled
11+
#define _PROCESS_TIMEOUT_INTERRUPTS
812

913
/* Uncomment this to allow Process timing statistics functionality */
1014
#define _PROCESS_STATISTICS
1115

1216
/* Uncomment this to use microseconds instead of milliseconds for timestamp unit (more precise) */
1317
//#define _MICROS_PRECISION
1418

19+
1520
/* The size of the scheduler job queue, */
1621
//increase if add(), destroy(), enable(), disable(), or updateStats() is returning false*/
17-
18-
//#define _PROCESS_REORDERING
19-
20-
#define _PROCESS_REORDERING_AGGRESSIVENESS 50000
21-
2222
#define SCHEDULER_JOB_QUEUE_SIZE 20
2323

2424
typedef enum ProcPriority

src/ProcessScheduler/Includes.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,19 @@
99
class Scheduler;
1010
class Process;
1111

12+
typedef enum ProcessWarning
13+
{
14+
WARNING_PROC_OVERSCHEDULED = 0,
15+
16+
#ifdef _PROCESS_TIMEOUT_INTERRUPTS
17+
WARNING_PROC_TIMED_OUT
18+
#endif
19+
} ProcessWarning;
20+
21+
// PICK INT VALUES PEOPLE UNLIKLEY TO USE
22+
#define LONGJMP_ISR_CODE -1000
23+
#define LONGJMP_YIELD_CODE -1001
24+
1225
#if defined(ARDUINO_ARCH_AVR)
1326
#include <setjmp.h>
1427
#include <util/atomic.h>
@@ -19,6 +32,13 @@ class Process;
1932
#define HALT_PROCESSOR() \
2033
do { noInterrupts(); sleep_enable(); sleep_cpu(); } while(0)
2134

35+
#define ENABLE_SCHEDULER_ISR() \
36+
do { OCR0A = 0xAA; TIMSK0 |= _BV(OCIE0A); } while(0)
37+
38+
39+
#define DISABLE_SCHEDULER_ISR() \
40+
do { TIMSK0 &= ~_BV(OCIE0A); } while(0)
41+
2242

2343
#elif defined(ARDUINO_ARCH_ESP8266)
2444
#ifndef __STRINGIFY
@@ -38,6 +58,11 @@ class Process;
3858

3959
#define HALT_PROCESSOR() \
4060
ESP.deepSleep(0)
61+
62+
// Not supported on ESP8266
63+
#define ENABLE_SCHEDULER_ISR()
64+
#define DISABLE_SCHEDULER_ISR()
65+
4166
#else
4267
#error “This library only supports AVR and ESP8266 Boards.”
4368
#endif

src/ProcessScheduler/Process.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,11 @@
6565
//called on enable/disable
6666
void Process::onEnable() { return; }
6767
void Process::onDisable() { return; }
68-
void Process::overScheduledHandler(uint32_t behind) { resetSchedulerWarning(); }
68+
void Process::handleWarning(ProcessWarning warning)
69+
{
70+
if (warning == WARNING_PROC_OVERSCHEDULED)
71+
resetOverSchedWarning();
72+
}
6973

7074
/*********** PRIVATE *************/
7175
bool Process::isPBehind(uint32_t curr)
@@ -92,9 +96,9 @@
9296
if (getOverSchedThresh() != OVERSCHEDULED_NO_WARNING && isPBehind(now)) {
9397
incrPBehind();
9498
if (getCurrPBehind() >= getOverSchedThresh())
95-
overScheduledHandler(now - getScheduledTS());
99+
handleWarning(WARNING_PROC_OVERSCHEDULED);
96100
} else {
97-
resetSchedulerWarning();
101+
resetOverSchedWarning();
98102
}
99103
}
100104

src/ProcessScheduler/Process.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,15 @@ class Process
4545

4646
inline void force() { _force = true; }
4747

48-
inline void resetSchedulerWarning() { _pBehind = 0; }
48+
inline void resetOverSchedWarning() { _pBehind = 0; }
4949
inline uint16_t getOverSchedThresh() { return _overSchedThresh; }
5050
inline uint16_t getCurrPBehind() { return _pBehind; }
5151

5252
inline ProcPriority getPriority() { return _pLevel; }
5353

54+
// Timeout
55+
virtual uint32_t getTimeout() { return 0; };
56+
5457
protected:
5558
inline uint32_t getStartDelay() { return _actualTS - _scheduledTS; }
5659
// Fired on creation/destroy
@@ -62,7 +65,7 @@ class Process
6265
// Process routine
6366
virtual void service() = 0;
6467
// Overscheduled warning
65-
virtual void overScheduledHandler(uint32_t behind);
68+
virtual void handleWarning(ProcessWarning warning);
6669

6770
private:
6871
enum ProcessFlags
@@ -107,6 +110,10 @@ class Process
107110
const ProcPriority _pLevel;
108111

109112

113+
#ifdef _PROCESS_TIMEOUT_INTERRUPTS
114+
115+
116+
#endif
110117

111118
#ifdef _PROCESS_STATISTICS
112119
public:

src/ProcessScheduler/Scheduler.cpp

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,18 @@
11
#include "Scheduler.h"
22
#include "Process.h"
33

4+
Process *Scheduler::_active = NULL;
5+
jmp_buf Scheduler::_env = {};
6+
7+
ISR(TIMER0_COMPA_vect)
8+
{
9+
if (Scheduler::getActive()) { // routine is running
10+
uint32_t timeout = Scheduler::getActive()->getTimeout();
11+
if (timeout && Scheduler::getCurrTS() - Scheduler::getActive()->getActualRunTS() >= timeout)
12+
longjmp(Scheduler::_env, LONGJMP_ISR_CODE);
13+
}
14+
}
15+
416

517
Scheduler::Scheduler()
618
: _pLevels{}
@@ -21,7 +33,7 @@ uint32_t Scheduler::getCurrTS()
2133
return TIMESTAMP();
2234
}
2335

24-
Process *Scheduler::getCurrProcess()
36+
Process *Scheduler::getActive()
2537
{
2638
return _active;
2739
}
@@ -134,15 +146,22 @@ int Scheduler::run()
134146

135147
#ifdef _PROCESS_EXCEPTION_HANDLING
136148
int ret = setjmp(_env);
149+
150+
#ifdef _PROCESS_TIMEOUT_INTERRUPTS
151+
ENABLE_SCHEDULER_ISR();
152+
#endif
137153
if (!ret) {
138154
_active->service();
139155
} else {
140-
eDispatcher(ret);
156+
jmpHandler(ret);
141157
}
142158
#else
143159
_active->service();
144160
#endif
145161

162+
#ifdef _PROCESS_TIMEOUT_INTERRUPTS
163+
DISABLE_SCHEDULER_ISR();
164+
#endif
146165

147166
#ifdef _PROCESS_STATISTICS
148167
uint32_t runTime = getCurrTS() - start;
@@ -383,12 +402,15 @@ void Scheduler::handleHistOverFlow(uint8_t div)
383402
}
384403

385404

386-
bool Scheduler::eDispatcher(int e)
405+
bool Scheduler::jmpHandler(int e)
387406
{
388407
if (e != 0 && _active)
389408
{
390-
if (!_active->handleException(e))
409+
if (e == LONGJMP_ISR_CODE)
410+
_active->handleWarning(WARNING_PROC_TIMED_OUT);
411+
else if (!_active->handleException(e))
391412
handleException(*_active, e);
413+
392414
return true;
393415
}
394416
return false;

src/ProcessScheduler/Scheduler.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ typedef struct RingBuf RingBuf;
1313

1414
class Process;
1515

16+
17+
1618
class Scheduler
1719
{
1820

@@ -30,10 +32,10 @@ class Scheduler
3032
bool isNotDestroyed(Process &process);
3133
bool isEnabled(Process &process);
3234

33-
Process *getCurrProcess();
35+
static Process *getActive();
3436
Process *findProcById(uint8_t id);
3537
uint8_t countProcesses(int priority = ALL_PRIORITY_LEVELS, bool enabledOnly = true);
36-
uint32_t getCurrTS();
38+
static uint32_t getCurrTS();
3739

3840
int run();
3941
protected:
@@ -83,7 +85,7 @@ class Scheduler
8385
Process *findPrevNode(Process &node);
8486

8587

86-
Process *_active;
88+
static Process *_active;
8789
uint8_t _lastID;
8890
RingBuf *_queue;
8991

@@ -115,9 +117,9 @@ class Scheduler
115117
public:
116118
void raiseException(int e);
117119
virtual void handleException(Process &process, int e) { };
120+
static jmp_buf _env; // have to do this to access it from ISR
118121
protected:
119-
bool eDispatcher(int e);
120-
jmp_buf _env;
122+
bool jmpHandler(int e);
121123
#endif
122124

123125
};

0 commit comments

Comments
 (0)