One of the main responsibilities of the QP Framework is to efficiently and safely deliver events from various producers to Active Objects. Any part of the system can produce events, not necessarily only the Active Objects. For example, ISRs, device drivers, or legacy code running outside the framework can produce events. On the other hand, only Active Objects can consume events, because only Active Objects have event queues.
The simplest mechanism lets producers post events directly to the event queue of the recipient Active Object. Figure 220 illustrates this form of communication as thick, solid arrows connecting event producers and the consumer Active Objects.
Direct event posting is a “push-style” communication mechanism, in which recipients receive unsolicited events whether they want them or not. Direct event posting is ideal in situations where a group of Active Objects, or an Active Object and an ISR, form a subsystem delivering a particular service, such as a communication stack, GPS capability, digital camera subsystem in a mobile phone, or the like. This style of event passing requires that the event producers “knows” the recipients and their interests in various events. The “knowledge” that a sender needs is, at a minimum, the handle (e.g., a pointer) to the recipient Active Object.
The publish–subscribe model is a popular way of decoupling the event producers from the event consumers. Publish-subscribe is a “pull-style” communication mechanism in which recipients receive only solicited events. The properties of the publish-subscribe model are:
The publish-subscribe event delivery is shown in Figure 220 as a “software bus” into which Active Objects “plug in” through the specified interface. Active Objects interested in certain events subscribe to one or more srs_evt_sig "Event Signals" by the QP framework.
Event producers make event publication requests to the framework. Such requests can originate asynchronously from many sources, not necessarily just from Active Objects. For example, events can be published from interrupts or device drivers. The QP framework manages all these interactions by supplying the following services:
One obvious implication of publish-subscribe is that the framework must store the subscriber information, whereas it must allow associating more than one subscriber Active Object with an srs_evt_sig "Event Signals". The framework must also allow modifying the subscriber information at runtime (dynamic subscribe and unsubscribe).
In any event-driven system, events are frequently produced and consumed, so by nature they are highly dynamic. One of the most critical aspects of every real-time framework is managing the memory used by events, because obviously this memory must be frequently reused as new events are constantly produced. The main challenge for the framework is to guarantee that the event memory is not reused until all Active Objects have finished their RTC processing of the event. In fact, as described in Section Run-to-Completion Processing, corrupting the current event while it is still in use constitutes a violation of the RTC semantics and is one of the hardest bugs to resolve.
Not all event instances in the system have parameters or changing parameters. Some event instances, for example, can be constant with the permanently assigned signal and unchanging parameter(s). Such immutable event objects can be shared safely among any number of concurrent threads and interrupts, and can be allocated statically once, rather than being created and recycled every time. The QP Framework should support immutable events as an optimization and simplification of the event memory management.
Many event instances, especially events with parameters cannot be easily made immutable. For example, event with just one 16-bit parameter can potentially have 64K values, and it is rather impractical to create that many immutable events (in an array, perhaps). For such cases, the QP framework needs to support mutable events.
The brute-force approach of copying entire events into message queues is the best a traditional RTOS can do, because an RTOS does not control the events after they leave the queue. A real-time framework, on the other hand, can be far more efficient because, due to inversion of control, the framework actually manages the whole life cycle of an event. As shown in Figures 6.5(B), 6.8, and 6.9(A) earlier in this chapter, a real-time framework is in charge of extracting an event from the active object’s event queue and then dispatching the event for RTC processing. After the RTC step completes, the framework regains control of the event. At this point, the framework “knows” that the event has been processed and so the framework can automatically recycle the event. Figure 6.12 shows the garbage collection step (event recycling) added to the active object life cycle.
A real-time framework can also easily control the allocation of events. The framework can simply provide an API function that application code must call to allocate new events. The QF framework, for example, provides the macro Q_NEW() for this purpose. With the addition of the event creation and automatic garbage collection steps, the framework controls the life cycle of an event from cradle to grave. This in turn permits the framework to implement controlled, thread-safe sharing of event memory, which from the application standpoint is indistinguishable from true event copying. Such memory management is called zero-copy event delivery.
QP Framework shall...