**4.4 Basic RELTEQ primitives**

Three operations can be performed on an event queue: a new event can be inserted, the head event can be popped, and an arbitrary event in the queue can be deleted.


*PopEvent(qi)* When an event is popped from a queue it is simply removed from the head of the queue *qi*. It is not handled at this point.

*DeleteEvent(qi, ej)* Since all events in a queue are stored relative to each other, the time *ej*.*time* of any event *ej* ∈ *qi* is critical for the integrity of the events later in the queue. Therefore, before an event *ej* is removed from *qi*, its event time *ej*.*time* is added to the following event in *qi*.

Note that the addition could overflow. In such case, instead of adding *ej*.*time* to the following event in *qi*, the kind of *ej* is set to a dummy event and the event is not removed. If *ej* is the last event in *qi* then it is simply removed, together with any dummy events preceding it.

### **4.5 Event queue implementation**

10 Will-be-set-by-IN-TECH

While RELTEQ is not restricted to any specific hardware timer, in this chapter we assume a

The tick handler is responsible for managing the *system queue*, which is a RELTEQ queue keeping track of all the timed events in the system. At every tick of the periodic timer the time of the head event in the queue is decremented. When the time of the head event is 0, then the

The scheduler is called at the end of the tick handler, but only in case an event was handled.

How an event is handled by *HandleEvent()* depends on its kind. E.g. a *delay event* will resume the delayed task. In general, the event handler will often use the basic RELTEQ primitives, as

Note that the tick granularity dictates the granularity of any timed events driven by the tick handler: e.g. a server's budget can be depleted only upon a tick. High resolution one-shot timers (e.g. High Precision Event Timer) provide a fine grained alternative to periodic ticks. In case these are present, RELTEQ can easily take advantage of the fine time granularity by setting the timer to the expiration of the earliest event among the active queues. The tick based approach was chosen due to lack of hardware support for high resolution one-shot timers on our example platform. In case such a one-shot timer is available, our RELTEQ based approach

Three operations can be performed on an event queue: a new event can be inserted, the head

*NewEvent(k, t, p)* Creates and returns a new event *ei* with *ei*.*kind* = *k*, *ei*.*time* = *t*, and

*InsertEvent(qi, ej)* When a new event *ej* with absolute time *tj* is inserted into the event queue *qi*, the queue is traversed accumulating the relative times of the events until a later event *ek* is found, with absolute time *tk* ≥ *tj*. When such an event is found, then (i) *ej* is inserted before *ek*, (ii) its time *ej*.*time* is set relative to the previous event, and (iii) the arrival time of *ek* is set relative to *ej* (i.e. *tk* − *tj*). If no later event was found, then *ej* is appended at the

event can be popped, and an arbitrary event in the queue can be deleted.

end of the queue, and its time is set relative to the previous event.

periodic timer which invokes the *tick handler*, outlined in Figure 4.

events with time equal to 0 are popped from the queue and handled.

The behavior of a RELTEQ tick handler is summarized in Figure 4.

*Head(system).time* := *Head(system).time* - 1;

Fig. 4. Pseudocode for the RELTEQ tick handler.

can be easily modified to take advantage of it.

**if** *Head*(*system*).*time* = 0 **then while** *Head*(*system*).*time* = 0 **do** *HandleEvent*(*Head*(*system*));

*PopEvent*(*system*);

described in the following sections.

**4.4 Basic RELTEQ primitives**

*ei*.*data* = *p*.

**end while** *Schedule*();

**end if**

If no event was handled the currently running task is resumed straightway.

**4.3 RELTEQ tick handler**

The most straightforward queue implementation is probably a doubly linked list. The time complexity of the *InsertEvent()* operation is then linear in the number of events in the queue, while the complexity of the *DeleteEvent()* and *PopEvent()* operations is constant.

The linear time complexity of the insert operation may be inconvenient for large event queues. An alternative implementation based on a heap or a balanced binary tree may seem more appropriate, as it promises logarithmic time operations. However, as the following theorem states, the relative time representation coupled with the requirement for long event interarrival times (compared to the time representation) make such an implementation impossible.

**Theorem 4.1.** *Assume that the maximum value we can represent in the time representation is d and also assume that we store times in a tree using relative values no greater than d. Finally, assume that any two events in the tree are at most kd apart in real time, for some parameter k. Then a logarithmic time retrieval of an event from a tree is not possible.*

*Proof.* If there are *k* events, the largest time span these *k* events can represent is *kd* time units, i.e., the time difference between the first and last event can be at most *kd* units. If we are to obtain this value by summing over a path this path has to be of length *k* which leads to a linear representation. This argument pertains to any representation that sums contributions over a path.

We can illustrate Theorem 4.1 using dummy events: assuming that we start at time 0, the real time of a newly inserted event is at most *kd*. We would need to insert dummy events until a root path can contain this value. This means we would need to add dummy events until there is a root path of length *k*.

Conversely, if we assume a tree representation, then we would like to obtain *kd* as a sum of log(*k*) events. If we assume an even distribution over all events, which is the best case with respect to the number of bits required for the time representation, then each event time will be equal to *<sup>k</sup>* log(*k*) *<sup>d</sup>*. This means that log *<sup>k</sup>* log(*k*) extra bits are needed. Therefore, in a tree implementation one cannot limit the time representation to a given fixed value, independent of *kd* (i.e. the tree span).

a periodic task *τ<sup>i</sup>* upon which (i) the event time of the *ei* is set to *Ti* and reinserted into the

An Efficient Hierarchical Scheduling Framework for the Automotive Domain 79

To support periodic tasks we have equipped each task with three additional variables: *TaskPeriod*, expressed in the number of ticks, *TaskPeriodSemaphore*, pointing to the semaphore guarding the release of the task, and *TaskPeriodEvent*, pointing to a RELTEQ period event. For efficiency reasons we have added these directly to the Task Control Block (TCB), which is the *μ*C/OS-II structure storing the state information about a task. Our extensions could, however,

2. removes the *TaskPeriodEvent* from the system queue using *DeleteEvent()*, in case it was already inserted by a previous call to *TaskMakePeriodic()*, otherwise creates a new period

3. sets the event time of the *TaskPeriodEvent* to *φ<sup>i</sup>* if *φ<sup>i</sup>* > 0 or *Ti* if *φ<sup>i</sup>* = 0, and inserts it into

A server *σ<sup>i</sup>* is created using *ServerCreate*(Π*i*, Θ*i*, *kind*), where *kind* specifies whether the server is *idling periodic* or *deferrable*. A task *τ<sup>i</sup>* is mapped to server *σ<sup>i</sup>* using *ServerAddTask(σi, τi)*.

In Section 4.3 we have introduced a system queue, which keeps track of pending timed events. For handling periodic tasks assigned to servers we could reuse the system queue. However, this would mean that the tick handler would process the expiration of events local to inactive

In order to limit the interference from inactive servers we would like to separate the events belonging to different servers. For this purpose we introduce additional RELTEQ queues for each server. We start this section by introducing additional primitives for manipulating queues, followed by describing how to use these in order to implement fixed-priority servers.

We introduce the notion of a pool of queues, and define two pools: *active queues* and *inactive queues*. They are implemented as lists of RELTEQ queues. Conceptually, at every tick of the periodic timer the heads of all active queues are decremented. The inactive queues are left

*IncrementQueue(qi)* Increments the head event in queue *qi* by 1. Time overflows are handled by setting the overflowing event to 2*<sup>n</sup>* <sup>−</sup> 1 and inserting a new dummy event at the head

*SyncQueueUntilEvent(qi, qj, ek)* Synchronizes queue *qi* with queue *qj* until event *ek* ∈ *qj*, by conceptually computing the absolute time of *ek*, and then popping and handling all the

To support servers we extend RELTEQ with the following methods:

of the queue with time equal to the overflow (i.e. 1).

events in *qi* which have occurred during that time interval.

*ActivateQueue(qi)* Moves queue *qi* from the inactive pool to the active pool. *DeactivateQueue(qi)* Moves queue *qi* from the active pool to the inactive pool.

system queue using *InsertEvent()*, and (ii) the semaphore blocking *τ<sup>i</sup>* is raised.

reside in a separate structure pointing back to the original TCB.

1. sets the *TaskPeriod* to *Ti*,

the system queue.

servers within the budget of the running server.

**6.1 RELTEQ primitives for servers**

**6. Servers**

untouched.

A task *τ<sup>i</sup>* is made periodic by calling *TaskMakePeriodic(τi, φi, Ti)*, which

event using *NewEvent(period, Ti, τi)* and assigns it to *TaskPeriodEvent*.

In order to satisfy our initial requirement for long event interarrival time, we chose for a linked-list implementation of RELTEQ queues. In future work we look into relaxing this requirement.
