PQRST
1.0
Priority Queue for Running Simple Tasks
|
A priority queue of Tasks. More...
#include <pqrst.h>
Public Member Functions | |
TaskQueue (void) | |
Creates a new TaskQueue. More... | |
bool | is_empty (void) const |
Return true if the task queue is empty. More... | |
unsigned int | size (bool inc_maintenance=false) const |
Return the number of user tasks currently in the queue. More... | |
void | traverse_queue (traverse_queue_cb_t, int max=-1) |
Traverse the queue. More... | |
void | dump_queue_contents (void) |
Dump the queue. More... | |
void | initialise (void) |
Initialise a TaskQueue. More... | |
bool | run_ready (ms_t) |
If the head task in the queue is ready at the given time (ie, its due time is at or before that time), then run it. More... | |
ms_t | next_due_after (void) const |
Return the interval between the queue reference time and the due-time of the task at the head of the queue. More... | |
void | remove (Task *) |
Remove from the queue an element which is == to the given Task. More... | |
void | remove_all_tasks (void) |
Discard all of the tasks from the queue, without running them. More... | |
void | signal (int, ms_t) |
Pass the given integer on to each task in the queue. More... | |
void | push_at (Task *, ms_t) |
Push the given task onto the queue, due at time t. More... | |
void | push_after (Task *, ms_t) |
Push the given task onto the queue, due some (positive) interval after the current reference time. More... | |
void | push_immediately (Task *) |
Push the given task on the queue, due immediately (in particular, at the current reference time). More... | |
int | lateness (ms_t) const |
Return the interval between the given time and the queue's ‘reference time’. More... | |
Friends | |
bool | Task::before (const Task *other) const |
A priority queue of Tasks.
The queue is maintained in time order; if PQRST_TASK_PRIORITIES
is defined as 1, it additionally takes account of a high/low priority task flag.
Tasks are added to the queue with a ‘ready time’ which is either absolute, or relative to the queue's current ‘reference time’. This reference time is notionally ‘now’, but it is set to be a task's ‘ready time’ when a task is run. It may therefore be slightly different from the ‘current time’ value passed to a Task::run method. This also means that two tasks which have the same ready time will have the same reference time when run. It is this reference time which is used when calculating offsets using TaskQueue::push_after and Task::run_after.
It may not need saying, but scheduling tasks within an interrupt handler is probably an extremely bad idea (at least in this version of the code).
Note: the reference time, as a reference for rescheduling, is reliable only within the Task::run method, and so the push_after and Task::run_after methods should only be called within an implementation of that method.
TaskQueue::TaskQueue | ( | void | ) |
Creates a new TaskQueue.
void TaskQueue::dump_queue_contents | ( | void | ) |
Dump the queue.
The output is a sequence of times and pointers to functions. For debugging only, since the printf
will do nothing useful otherwise. This method is therefore not available unless the variable PQRST_TEST_MODE
is set. The method traverse_queue is declared, though, so some debugging is possible in that case.
void TaskQueue::initialise | ( | void | ) |
Initialise a TaskQueue.
This will only be necessary if we want to start using a Queue again, after it has been cleared by remove_all_tasks.
bool TaskQueue::is_empty | ( | void | ) | const |
Return true if the task queue is empty.
int TaskQueue::lateness | ( | ms_t | t | ) | const |
Return the interval between the given time and the queue's ‘reference time’.
Note: the current implementation of this method assumes that t
is not earlier than the reference time, and it will not give particularly useful answers for times which are earlier. A future implementation of this method may change the semantics in this case.
t | the time of interest |
ms_t TaskQueue::next_due_after | ( | void | ) | const |
Return the interval between the queue reference time and the due-time of the task at the head of the queue.
If the head task is overdue, this returns zero, rather than a negative value. Returns 0xffffffff if the queue is empty.
Push the given task onto the queue, due some (positive) interval after the current reference time.
Note that the reference time is not millis()
, but instead the last time at which there was a non-null pop of the queue, or a signal sent to the queue. This is because we assume that the majority of the calls to this method are happening within a run()
method, in which case the relevant time is the time when the task was due, not the possibly slightly later actual time. If you need to push after the actual current time, or wish to push a task outside a run()
method, then use push_at(millis()+t)
.
Do not use this method outside a Task::run method.
T | the task to be queued |
interval | the time after the reference time, in non-negative ms, at which the task is to be queued |
Push the given task onto the queue, due at time t.
If the task is already present on the queue, then the earlier scheduling is cancelled. A task will only be scheduled on a queue once (it can, and often will, reschedule itself, but at any time it will be present on the queue only once).
If there is more than one queue in the code, a Task must not be scheduled in more than one of them.
Do not use push_at(Task*, 0)
as a way of scheduling a task for ‘immediately’. That is not guaranteed to work for all values of the reference time. If you wish this, instead use push_after with a zero offset, or push_immediately.
We can be deemed to take ownership of the new object.
It may not need saying, but scheduling tasks within an interrupt handler is probably an extremely bad idea.
T | the task to be queued, which must be non-null |
t | the due time |
void TaskQueue::push_immediately | ( | Task * | T | ) |
Push the given task on the queue, due immediately (in particular, at the current reference time).
This is broadly equivalent to push_after(Task*, ms_t), with an interval
argument of zero, except that the task is forced to the head of the queue, even if the current head task is overdue. Thus this task will be due to run the next time that run_ready is called; this is useful if some action is deemed particularly urgent.
If, as is more usually the case, you wish the task to run immediately without this preemption, then use push_after with a zero interval argument.
T | the task to be pushed |
void TaskQueue::remove | ( | Task * | T | ) |
Remove from the queue an element which is == to the given Task.
It is OK to 'remove' a task which is not in the queue: in this case, nothing happens.
T | the task to be removed |
void TaskQueue::remove_all_tasks | ( | void | ) |
Discard all of the tasks from the queue, without running them.
We don't do deallocation of any tasks, and we don't call Task::cancel on them. Any tasks that were on the queue may end up in an inconsistent internal state. Thus this method is really only useful for the case where we wish to break out of the main is_empty loop, such as in an error handler (using longjmp
, perhaps).
After this operation, is_empty returns true. If you wish to start using the queue again, then you must call initialise on the queue.
bool TaskQueue::run_ready | ( | ms_t | t | ) |
If the head task in the queue is ready at the given time (ie, its due time is at or before that time), then run it.
t | the current time |
void TaskQueue::signal | ( | int | signal, |
ms_t | t | ||
) |
Pass the given integer on to each task in the queue.
This calls Task::signal for each such task. There is no significance to the number, as far as this class is concerned. This updates the queue's ‘reference time’ to the time passed in the argument.
It is unspecified what order the tasks in the queue are signalled, but if the signalled tasks add tasks to the queue, those tasks will not receive the signal.
signal | the integer to be passed on. |
t | the current reference time |
unsigned int TaskQueue::size | ( | bool | inc_maintenance = false | ) | const |
void TaskQueue::traverse_queue | ( | traverse_queue_cb_t | callback, |
int | max = -1 |
||
) |
Traverse the queue.
Run through the queue, calling the provided function once for each entry. This is primarily for debugging; there is no way to change the queue during this traversal.
The callback prototype is either typedef void (*traverse_queue_cb_t)(ms_t, const char* ident, Task*)
or typedef void (*traverse_queue_cb_t)(ms_t, Task*)
depending on whether PQRST_TASK_IDENT
is defined (see the pqrst.h
code for further details).
callback | the callback function |
max | the maximum number of tasks to traverse (default: unlimited) |
|
friend |