Skip to content

Commit d583320

Browse files
committed
Made Process setters atomic
1 parent 2304ce8 commit d583320

4 files changed

Lines changed: 65 additions & 43 deletions

File tree

README.md

Lines changed: 41 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,62 @@
1-
# ArduinoServiceScheduler
2-
An Arduino Object Oriented Cooperative Service Scheduler to Replace Them All
1+
# ArduinoProcessScheduler
2+
An Arduino Object Oriented Cooperative Process Scheduler to Replace Them All
33

44
## Features
5-
- Fine Grained Control Over How Often a Service Runs (Periodically, Iterations, or as Often as Possible)
5+
- Fine Grained Control Over How Often a Process Runs (Periodically, Iterations, or as Often as Possible)
66
- Exception Handling (wait what?!)
77
- Atomicity Support
8-
- Dynamically Add/Remove and Enable/Disable Services
9-
- Automatic Service Monitoring Statsitics (Automatically calculates % CPU time for service)
10-
- Truly object orinted (a Service is no longer just a callback function like other libraries)
8+
- Dynamically Add/Remove and Enable/Disable Processes
9+
- Automatic Process Monitoring Statistics (Automatically calculates % CPU time for service)
10+
- Truly object oriented (a Process is no longer just a callback function like other libraries)
1111

1212
## Basic Usage
13-
There are two classes to worry about: `Scheduler` and `Service`.
13+
There are two classes to worry about: `Scheduler` and `Process`.
1414

1515
### Class `Scheduler`:
16-
A `Scheduler` oversees and maanges `Services`. There should only be one `Scheduler` in your project. Inside of `void loop()`, the scheduler's `run()` method should be repeatedly called.
16+
A `Scheduler` oversees and manages `Processes`. There should only be one `Scheduler` in your project. Inside of `void loop()`, the scheduler's `run()` method should be repeatedly called.
1717

18-
### Class `Service`:
19-
A service can be thought of as job or a task that needs to be run at certain times. Each Service had be scheduled to run Periodically
18+
### Class `Process`:
19+
A service can be thought of as job or a task that needs to be run at certain times. Each Process had be scheduled to run Periodically
2020
Constantly, or Periodically/Constantly with a set number of run iterations.
2121

22-
Each project will have multiple services, here are some examples of `Services`:
23-
- A Service to handle user input
24-
- A Service to run a basic webserver
25-
- A Service to update a display
26-
27-
`Service` is a base class that should be extended to handle your particular Service (such as the examples mentioned above). The scheduler's will call the following virtual function as an entry point when it is time for you service to run:
22+
Each project will have multiple services, here are some examples of `Processes`:
23+
- A Process to handle user input
24+
- A Process to run a basic webserver
25+
- A Process to update a display
26+
27+
`Process` is a base class that should be extended to handle your particular Process (such as the examples mentioned above). The scheduler's will call the following virtual function as an entry point when it is time for you service to run:
2828
```
2929
virtual void service();
3030
```
31-
From here your `service()` routine is expected to be non-blocking, and return from `service()` as soon as possible (that means no long `delay()`'s). Fortunately, since your service routine is a method inside a class, you can store the state of your service in custom class attributes before returning, so you know where you left off when the scheduler calls your Service again. As soon you return from `service()`, control is transferred back to the Scheduler (it will also be transferred back if you raise an Exception--advanced).
31+
From here your `service()` routine is expected to be non-blocking, and return from `service()` as soon as possible (that means no long `delay()`'s). Fortunately, since your service routine is a method inside a class, you can store the state of your service in custom class attributes before returning, so you know where you left off when the scheduler calls your Process again. As soon you return from `service()`, control is transferred back to the Scheduler (it will also be transferred back if you raise an Exception--advanced).
3232

33-
Additionally, each Service inherits the following virtual functions which are called by the `Scheduler` at the appropriate times. Note you are guaranteed that only one of these methods will exist in the call stack at once, even if an interrupt fires trying to modify this Service at the same time (such as with `add()`, `destroy()`, `enable()`, or `disable()`). This also includes the `service()` method mentioned above. You do not have to worry about concurrency!
33+
Additionally, each Process inherits the following virtual functions which are called by the `Scheduler` at the appropriate times. Note you are guaranteed that only one of these methods will exist in the call stack at once, even if an interrupt fires trying to modify this Process at the same time (such as with `add()`, `destroy()`, `enable()`, or `disable()`). This also includes the `service()` method mentioned above. You do not have to worry about concurrency!
3434

35-
**Thanks to the magic of virtual functions, you don't have to impliment any of these unless your particular Service needs them:**
35+
**Thanks to the magic of virtual functions, you don't have to impliment any of these unless your particular Process needs them:**
3636
```
3737
virtual void setup()
3838
virtual void cleanup()
39-
39+
4040
virtual void onEnable()
4141
virtual void onDisable()
42-
42+
4343
virtual void overScheduledHandler(uint32_t behind)
4444
```
4545

4646
#### `setup()`
47-
This method is called by the scheduler when the Service is being added to the scheduling chain with `add()`, it is guaranteed to only be called once when a Service not part of the scheduling chain is being added (`add()`). Keep in mind it will still be called if the Service is removed from the scheduling chain with `destroy()`, then added again with `add()`.
47+
This method is called by the scheduler when the Process is being added to the scheduling chain with `add()`, it is guaranteed to only be called once when a Process not part of the scheduling chain is being added (`add()`). Keep in mind it will still be called if the Process is removed from the scheduling chain with `destroy()`, then added again with `add()`.
4848

4949
#### `cleanup()`
50-
This is only called once when a `Service` part of the scheduling chain is being removed from the scheduling chain with `destroy()`. This method should undo whatever was done in `setup()`. You are guaranteed it will not be called unless `setup()` was called previously.
50+
This is only called once when a `Process` part of the scheduling chain is being removed from the scheduling chain with `destroy()`. This method should undo whatever was done in `setup()`. You are guaranteed it will not be called unless `setup()` was called previously.
5151

5252
#### `onEnable()`
53-
This method is called only once when a disabled task is being enabled with `enable()`.
53+
This method is called only once when a disabled task is being enabled with `enable()`.
5454

5555
#### `onDisable()`
5656
This method is called only once when a enabled task is being disabled with `disable()`. You are guaranteed it will not be called unless `onEnable()` was called previously. It should undo whatever `onEnable()` did.
5757

5858
#### `overScheduledHandler(uint32_t behind)`
59-
This method is called if the scheduler can not meet the current set period for the Service and is falling behind. The scheduler will pass in variable `behind` containing how many milliseconds (or microseconds) behind the scheduler is with this task. Inside this method might be a good time increase the period between when this task is run, then call `resetSchedulerWarning()` to clear the warning.
59+
This method is called if the scheduler can not meet the current set period for the Process and is falling behind. The scheduler will pass in variable `behind` containing how many milliseconds (or microseconds) behind the scheduler is with this task. Inside this method might be a good time increase the period between when this task is run, then call `resetSchedulerWarning()` to clear the warning.
6060

6161

6262
## API
@@ -85,45 +85,45 @@ ___
8585

8686
#### getID()
8787
```
88-
getID(Service &service)
88+
getID(Process &service)
8989
```
9090
Get the unique id for the service. Same as `service.getID()`.
9191

9292
**Returns:** `uint8_t`
9393
___
9494

95-
#### isRunningService()
95+
#### isRunningProcess()
9696
```
97-
isRunningService(Service &service)
97+
isRunningProcess(Process &service)
9898
```
99-
Determine if the scheduler is in the middle of running this service. Same as calling `service.isRunningService()`
99+
Determine if the scheduler is in the middle of running this service. Same as calling `service.isRunningProcess()`
100100

101101
**Returns:** `bool`
102102
___
103103

104104
#### isEnabled()
105105
```
106-
isEnabled(Service &service)
106+
isEnabled(Process &service)
107107
```
108108
Determines if this service is enabled. Same as calling `service.isEnabled()`
109109

110110
**Returns:** `bool`
111111
___
112112

113-
#### getCurrService()
113+
#### getCurrProcess()
114114
```
115-
getCurrService()
115+
getCurrProcess()
116116
```
117117
Get pointer to the current service being run by the scheduler. Return NULL if no service being currently run.
118118

119-
**Returns:** `Service*`
119+
**Returns:** `Process*`
120120
___
121121

122-
#### countServices()
122+
#### countProcesses()
123123
```
124-
countServices(bool enabledOnly = true)
124+
countProcesses(bool enabledOnly = true)
125125
```
126-
Get number of servies in the scheduler's chain. If enabledOnly is true, only the enabled Services will be counted.
126+
Get number of servies in the scheduler's chain. If enabledOnly is true, only the enabled Processes will be counted.
127127

128128
**Returns:** `uint8_t`
129129
___
@@ -140,7 +140,7 @@ ___
140140

141141
#### add()
142142
```
143-
add (Service &service))
143+
add (Process &service))
144144
```
145145
Add the service to the scheduler, same as calling `service.add()`. Note, this will trigger the service's `setup()` method to fire. This method can only fail inside an interrupt routine, particularly when an interrupt interrupts any call to either `add()` or `remove()`. It will also fail if the service is already added.
146146

@@ -149,16 +149,16 @@ ___
149149

150150
#### destroy()
151151
```
152-
destroy (Service &service))
152+
destroy (Process &service))
153153
```
154-
Remove the service from the scheduler. Same as calling `service.destroy()`. Note, this will trigger the service's `cleanup()` method to fire. If the service is not disabled, it will first call `disable()`. This method can only fail inside an interrupt routine, particularly when an interrupt interrupts any call to either `add()` or `remove()`. It will first try and QUEUE the request for later, before failing. It will also fail if the service is already destroyed.
154+
Remove the service from the scheduler. Same as calling `service.destroy()`. Note, this will trigger the service's `cleanup()` method to fire. If the service is not disabled, it will first call `disable()`. This method can only fail inside an interrupt routine, particularly when an interrupt interrupts any call to either `add()` or `remove()`. It will first try and QUEUE the request for later, before failing. It will also fail if the service is already destroyed.
155155

156156
**Returns:** type `SchedulerAction`, `ACTION_NONE` on failure, `ACTION_QUEUED` on Queuing it, `ACTION_SUCCESS` on success.
157157
___
158158

159159
#### enable()
160160
```
161-
enable (Service &service))
161+
enable (Process &service))
162162
```
163163
Enable a service, same as calling `service.enable()`. Note, this will trigger the service's `onEnable()` method to fire. This method call will always succeed if it was not called on itself from a method inside of this service. If it was, the scheduler will queue the request. Also, the request will fail if the service is already enabled or is destroyed.
164164

@@ -167,7 +167,7 @@ ___
167167

168168
#### disable()
169169
```
170-
disable (Service &service))
170+
disable (Process &service))
171171
```
172172
Disable a service, same as calling `service.disable()`. Note, this will trigger the service's `onDisable()` method to fire. This method call will always succeed if it was not called on itself from a method inside of this service. If it was, the scheduler will queue the request. Also, the request will fail if the service is already enabled or is destroyed.
173173

src/ProcessScheduler/Process.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,25 @@
5151
(getIterations() == RUNTIME_FOREVER || getIterations() > 0))));
5252
}
5353

54+
void Process::setIterations(int iterations)
55+
{
56+
ATOMIC_START
57+
{
58+
_iterations = iterations;
59+
}
60+
ATOMIC_END
61+
}
62+
63+
64+
void Process::setPeriod(uint32_t period)
65+
{
66+
ATOMIC_START
67+
{
68+
_period = period;
69+
}
70+
ATOMIC_END
71+
}
72+
5473

5574

5675
/*********** PROTECTED *************/

src/ProcessScheduler/Process.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ class Process
4141
inline uint16_t getCurrPBehind() { return _pBehind; }
4242

4343
///////////////////// SETTERS /////////////////////////
44-
inline void setIterations(int iterations) { _iterations = iterations; }
45-
inline void setPeriod(uint32_t period) { _period = period; }
44+
void setIterations(int iterations);
45+
void setPeriod(uint32_t period);
4646
inline void force() { _force = true; }
4747

4848
inline void resetOverSchedWarning() { _pBehind = 0; }

src/ProcessScheduler/Scheduler.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,7 @@ void Scheduler::procAdd(Process &process)
256256

257257
void Scheduler::procHalt()
258258
{
259+
259260
for (uint8_t i = 0; i < NUM_PRIORITY_LEVELS; i++)
260261
{
261262
for (Process *curr = _pLevels[i].head; curr != NULL; curr = curr->getNext())
@@ -264,6 +265,8 @@ void Scheduler::procHalt()
264265
}
265266
}
266267

268+
delay(100);
269+
267270
HALT_PROCESSOR();
268271
}
269272

0 commit comments

Comments
 (0)