Home > Multitasking, Projects, RTOS, SKC++ > SKC++: Event Handling

SKC++: Event Handling

Wednesday, October 14, 2009 Leave a comment Go to comments

Systems running a pre-emptive kernel are essentially event-driven.

Primary events are things which happen outside the software system, in the real world. These are usually communicated to the software via Interrupt Service Routines (ISRs) which are pre-emptively “called” by the hardware interrupt mechanism of the processor. Our kernel becomes aware of the event if and only if the ISR signals its occurrence, in some way, to a task. It is quite possible for an ISR to handle a primary event completely, without involving a task, but in this case the kernel never knows about it and it is outside the scope of this post. ISRs themselves will be discussed here later on.

Secondary events occur within the software system: tasks post events to other tasks. I call these events secondary because each one is always caused, directly or indirectly, by some prior primary event – which includes, for the purposes of this assertion, system startup. This is a feature of pre-emptive multitasking systems which is often forgotten. Whenever such a system has nothing to do, it is running its built-in idle task (i.e. doing nothing) and it needs a primary event to wake it up. A burst of secondary events may then be generated but the cause of each one of them can be traced back to the initial primary event.

Event Flag Groups: the Good, the Bad and the Ugly

Many older (C-based) kernels feature Event Flag Groups (EFGs from now on, to save me some typing). The flags in each group are implemented as individual bits in a word of some length – say an unsigned int or an unsigned long. From the efficiency point of view (both time and memory usage) this is quite a good way of doing things but other things about EFGs are historically bad, in my opinion.

I first had to deal with EFGs was when replacing VRTX with SKED (my previous kernel) for a client. I fought hard, though unsuccessfully, against implementing EFGs the VRTX way. The following set of features, taken together, more or less guaranteed problems:

  • An EFG was a stand-alone object at which any number of tasks could wait for events to happen.
  • Each task could wait for any (OR) or all (AND) of a specified subset of events.
  • Because VRTX allowed any number of tasks to wait, it could not itself reset flags on their first service by a task (other tasks might still be expecting them) so it left this management matter to the application designer.

Some kernels solve the management problem by binding each EFG to a single task which is the only one able to wait there. A pSOS task, for example, normally resets all serviced bits atomically within its ev_receive function. However, a task is still allowed to wait for different combinations (OR/AND) of flags each time round its loop and, given the unpredictable timing of events, use of this feature requires some very careful design if timing problems and race conditions are to be avoided. It also forces the task’s code to deal with all of the received events in each loop iteration; doing one thing each time round would be simpler and less error-prone.

Of course, people are not forced to use dodgy features just because they are there but their very presence tends to suggest they might not be dodgy. A core principle of SKC++ is that it should be difficult to misuse, so here is the way it deals with events…

The SKC++ Way

TaskEvents

When thinking about events, I could have followed the path of true OO and immediately made an event an object, described by a class Event. However, it is obvious from the diagram that Event is not a class but an enumeration. It is also pretty obvious that each individual event, like its ancestral event flag, is bit-mapped, effectively into an unsigned short. This is mainly for speedy performance. In SKC++, events are designed to give the fastest possible interaction between tasks and between ISRs and tasks, so OO principles are sacrificed to this end.

As in pSOS (for example), SKC++ events are bit-mapped and an event “group” is bound to a single task. But SKC++ also removes the logical OR/AND features of previous designs, leaving any such logic to application code where, I believe, it belongs. Accordingly:

  • only one event can be posted at a time.
  • each event has a built-in priority, with EVENT_0 having highest priority and EVENT_15 having lowest.
  • although several events may be pending when the task waits, only the pending event of highest priority is passed to the task (and cleared); the rest remain pending.

This one-thing-at-a-time approach is simpler and is adequate, I believe, within the realm of a single task. If we want more concurrency, we should have more tasks!

The diagram shows three more functions in Task: a post function and two overloaded wait functions. In ExampleTask, we can see activity running in a loop and collecting a single event each time round, using the simpler form of wait. The other form of wait allows a task’s activity function to filter the events waited for on any particular iteration by passing wait an argument something like EVENT_8 + EVENT_9 or EVENT_ALL – EVENT_0. So, yes, I have left in just a little bit of logic which might be useful!

FAQ (a Few Anticipated Questions)

I can see why wait is protected (only activity uses it) but why isn’t post public?

The idea is to enforce encapsulation of low-level posting, along with waiting, into the appropriate task. It is not very obvious, at the moment, why this is important; it will make more sense when message-passing is covered in a later article. In the meantime, let’s just observe that it is an internal task matter how events (and messages) are used in detail – see ExampleTask::someUserFunction. Another task wishing to use the services of an ExampleTask object should do so by calling its public methods, not by calling Task‘s kernel-related functions directly.

It would be easy and equally efficient to allow me to post more than one event at the same time. Why can’t I do this?

It could be done by changing post‘s parameter type from Event to unsigned short. However, reducing type safety in this way makes the operation more error-prone. A user might, for example, pass in the value 3 instead of EVENT_3. It is seldom useful to post multiple events simultaneously so in this case greater type-safety took precedence. In the case of wait and its eventFilter, the opposite view prevailed because it can be very useful for an activity to be able to ignore some events sometimes; it’s also much more efficient and less problematic than catching unwanted ones and having to re-post them.

If I can post or retrieve only one event at a time, why (with the exception of eventFilter) aren’t simple numbers used to describe events instead of enumerated constants?

Type safety (range limitation), performance (bit-maps in; bit-maps out) and consistency (with eventFilter).

Why 16 events, exactly?

8, 16 and 32 were candidates for the group of bits representing events. 8 was deemed too few and 32 too many. 16 was deemed “just right”, given that events are per-task. The underlying data type might nevertheless become unsigned int, one day, if justified during performance tweaks.

Finally, a question for my loyal reader(s)

What is the major shortcoming of encapsulating activity and the task’s public methods in the same class?

Clues:

  • The problem concerns something which could be present in ExampleTask, but is not.
  • Unless someone comes up with the answer before me, you won’t hear about this again until I deal with mutual exclusion.
Advertisements
Categories: Multitasking, Projects, RTOS, SKC++ Tags:
  1. Peter Bushell
    Wednesday, October 14, 2009 at 16:09

    I’ve just realised that, contrary to what I said in the “FAQ”, it is possible to post more than one event – indeed all of them – by specifying EVENT_ALL. I should take that value out of the enumeration!

  2. Peter Bushell
    Wednesday, November 4, 2009 at 17:10

    Timeout on the open question.

    The answer is embodied in my more recent article “SKC++: Pause for Thought”.

    (No, I still haven’t dealt with mutual exclusion but it was at least mentioned in that article.)

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: