Thursday, January 13, 2011

Some Commentary on a Recent eetimes Article and a Referenced Paper

Some Commentary on a Recent eetimes Article and a Referenced Paper


An eetimes article in their online edition of a 1/10/2011, “Rapid development and reusable design for the connected car” by Kristopher Cieplak, was of interest to me.  See http://www.eetimes.com/design/embedded-internet-design/4212037/Rapid-development-and-reusable-design-for-the-connected-car?Ecosys.  The article refers to a framework that seemed to have similarities to that of my Exploratory Project.  Further, it referenced a paper by another QNX Software Systems author Ben VandenBelt, “Persistent Publish/Subscribe for Embedded Industrial Applications” that can be located at www.qnx.com.  This later paper is about the framework.

Some paragraphs of interest are as follows along with my interspersed comments concerning some of them.  In my comments I use application to refer to either a server or client.  An application can be a server to particular applications of the network and a client of others.  An application can refer to a partition or a separately loadable Windows process.  An application consists of numerous components that can also be a server to other components of the application and a client of others; that is, the component can be moved from one application to another without the need to modify the component.

The VandenBelt paper mentions “send/receive/reply (or synchronous) messaging” which is one of the options that can be selected for mC.  However, VandenBelt states that “Send/receive/reply messaging closely couples sender and receiver.  Every server communicates directly with its clients, and must know how to respond to all client messages.  With messaging thus closely coupled, a change to one software component may require changes to other software components, slowing or hindering system development and increasing system fragility.” 

That is not a problem with mC since the application that treats any particular message topic can be modified with the set of applications determining the application and software component that treats a message at power up via the subscription/registration messages and with the reply returned to whatever component sent the request. 

However, the point is made that “as a system increases in scale and as diverse components are added to it, that system rapidly grows in complexity and becomes increasingly brittle – difficult to upgrade and scale while ensuring performance and reliability.”  mC has never had to grow much so the subscription/registration messages might become a problem.  And, of course, as a one person experiment, there has never been anything done, as yet, concerning an application dropping offline, coming back online, etc. 

mC does use direct point-to-point connections – at least it doesn’t use a series of applications such that one (or more) application is merely passing the message along towards its eventual destination – if that’s what is meant by “direct”.  Of course it doesn’t do that for asynchronous messages either.  It requires that each application with its set of components can communicate directly with each of the other applications that are either its clients or its servers (or both).

The VandenBelt paper refers to an Embedded Design article “Making the case for commercial communication integration middleware” by Jerry Krasner.  It only seems to mean by “direct” that the applications are “socketed” together and that the old applications that now use the new application have to be reworked to take into account the protocol being used by the new application. 

The mC framework supports an integrated set of applications where each uses the same protocol.  However, non-compliant applications can be added to the network by adding a translation component to a compliant application.  For instance, a Display Application was added to the exploratory project to interface to Windows to display Windows forms and controls and transmit click, enter, etc events to compliant applications for treatment.

To avoid the need to modify existing components, except any that must treat the Windows event or produce a modification of a form or control, a translation component was added to each application that must directly interface with one of the Display Application “layers”.  These translation components are receive/transmit components that receive the non-standard message (non-standard in regard to the mC framework protocol) and convert it to contain the standard protocol header while retaining the data of the received message and then publishing it to be forwarded by the framework to the component (in whichever application it might reside in) that had subscribed for it.

The reply, if any, and other messages being sent to the non-standard application are first sent to the transmit sub-component of the translation component (which has previously subscribed for them) to be converted to the protocol of the non-standard application and then sent to it. 

In this way the non-standard application stays as is and the treating component stays as is except for the addition of the translation component to the application of the treating component.  If such a minimal change requires that all the unchanged components be retested, then, to avoid this problem, it should be possible to insert a new translation application (i.e., partition) that takes the place of the translation component.  Then the message would be routed from the non-standard application to the translation application and from it to the standard protocol application and vice versa.

Other paragraphs of interest to me from the Ben VanderBelt paper are:
An Object-based System


Publishing is asynchronous, PPS objects are integrated into the PPS filesystem pathname space.  Publishers modify objects and their attributes, and write them to the filesystem.  When any publisher changes an object, the PPS service informs all clients subscribed to that object of the change.  PPS clients can subscribe to multiple objects, and PPS objects can have multiple publisher as well as multiple subscribers.  Thus, publishers with access to data that applies to different object attributes can use the same object to communicate their information to all subscribers to that object.

This seems directly similar to Upon Demand topics – objects as referred to in the VanderBelt paper – of the mC framework where the consumer component can subscribe to be notified when a new instance of the topic is published.

Push or Pull?

In its default implementation, the QNX PPS service acts as a push publishing systems; that is, publishers push data to objects, and subscribers read data upon notification or at their leisure.

However, some data, such as packet counts on an interface, changes fare too quickly to be efficiently published through PPS using its default push publishing.

QNX PPS therefore offers an option that allows a subscriber to change PPS into a pull publishing system.  When a subscriber that opened an object with this option issues a read() call, all publishers to that object receive a notification to write current data to the object.  The subscriber’s read blocks until the object’s data is updated, then returns with the new data.

With this pull mechanism, the PPS subscriber retrieves data from the publisher at whatever rate it requires – in effect, on-demand publishing.

Persistence

A Persistent Publish/Subscribe service maintains data across reboots. …

System Scalability

With PPS, publisher and subscriber do not know each other; …

The loosely-couple PPS messaging model also simplifies the integration of new software components.  Since publisher and subscriber do not have to know each other, developers adding components need only to determine what these new components should publish, and what data they need other PPS clients to publish.  No fine-tuning of APIs is required, and system complexity does not increase as components are added.


With PPS, components do not even need to be aware of each other’s existence on the system.

The pull publishing concept represented by
“QNX PPS therefore offers an option that allows a subscriber to change PPS into a pull publishing system.  When a subscriber that opened an object with this option issues a read() call, all publishers to that object receive a notification to write current data to the object.  The subscriber’s read blocks until the object’s data is updated, then returns with the new data.

With this pull mechanism, the PPS subscriber retrieves data from the publisher at whatever rate it requires – in effect, on-demand publishing.”
seems interesting.  mC has a concept that somewhat corresponds.  It uses Publish/Subscribe for the Topic Delivery Protocol (versus Point-to-Point) as well as Most Recently Published (MRP) for Topic Permanence.  (Note:  Permanence in mC is different than Persistence.)  For this combination, mC prepares a MRP instance of the published topic each time the publishing component executes and writes the topic.  However the subscribers are not notified.  Instead, each one gets the most recently published data when it reads.  Therefore, the subscriber retrieves the most current data at its own rate.  Since a low priority subscriber could still be reading a previously published instance, a non-used buffer is utilized to publish a new MRP message instance.

The following is extensive quoting the eetimes article in regards to features where the QMX framework seems similar to my exploratory project or could be applicable to it.

Persistent Publish/Subscribe

PPS is an object-based service with publishers and subscribers in a loosely-coupled messaging architecture.  Any PPS client to the service can be a publisher only, a subscriber only, or both a publisher and a subscriber, as required by the implementation.

Publishers and subscribers only need to be able to read and write objects and their attributes in the PPS file system pathname space. Subscribers must of course know what objects and attributes interest them, and publishers must know what objects and attributes may interest subscribers, but neither publisher nor subscriber needs to know anything more about other parts of the system. Objects are written to permanent storage, offering persistence across reboots.

We implemented PPS to handle messaging between Adobe Flash applications and all data source publisher components; that is, for Webkit (browser), Bluetooth, GPS, audio volume control, etc. Chief among the advantages offered by the PPS messaging model is that the API between the components is consistent and loosely coupled.

Just as PPS allows us to redesign our HMI without touching the underlying applications, it allows us to add new componentsvehicle telematics or ITS awareness, for instance — to our QNX CAR implementation without the time-consuming development usually required with other messaging paradigms. All that is needed is that all parties know what they need to publish, and what they need to read in from PPS. Further, this architecture ensures that other components do not require changes to accommodate new additions — changes which, as every software developer knows, at best require exhaustive testing, at worst introduce errors.

PPS thus provides us with a messaging model that allows us to add new components to our in-vehicle system with minimal effort beyond the HMI work required so that users can use the new capabities offered.

Resource separation

The technologies we chose for QNX CAR offer two techniques (beyond standard process and memory protection) for managing the impact of new applications on an in-vehicle system. First, the Adobe Flash-based HMI allows us to run a secondary Flash player whose virtual machine serves as a "sandbox" for running untrusted applications. Second, the QNX  Neutrino RTOS offers adaptive partitioning, a unique technology that dynamically offers unused CPU time to processes that need it, but guarantees resources to critical processes.

Secondary Flash player

To ensure that a newly introduced application does not introduce problems to our system, we chose to implement a secondary Adobe Flash player. The player is reserved for untrusted applications; that is, for applications that we have not confirmed will run cleanly without adverse effects on the reliability and performance of other applications, or of the system as whole.

Like all Flash players, this secondary player runs in its own virtual machine environment, and hence can be neatly separated from the rest of the system.  Applications in this secondary player’s virtual machine environment can not deprive applications in the primary player or other components in the system of the resources they require.

This simple approach allows us to try virtually any Flash application we choose, without worrying that it might bring down the system. In fact, any developer could write an application and run it on this secondary player without danger. He could use adaptive partitioning to ensure that the secondary Flash player did not interfere with applications in the primary Flash player, and that the applications this secondary player ran would not starve the system.

For a more detailed description of QNX PPS, see Ben VandenBelt, "Persistent Publish/Subscribe for Embedded Industrial Applications". QNX Software Systems, 2010. www.qnx.com.

Partitioning

Resource partitions are the traditional method implemented in OSs to protect different applications or groups of applications from each other. They are virtual walls that prevent one application from corrupting another application, or from starving it of  resources. The primary resource protected by partitions is CPU time, but partitioning can be used to protect other shared resources, such as memory or file space (disk or flash).

Fixed partitioning guarantees that processes will get the resources specified by the system designer, but lacks flexibility.

Rigid partitions

Traditional, rigid partitions are relatively easy to set, and they are effective; they guarantee that each application receives the resources specified by the system designer. They may not always be the best solution in embedded systems, such in-vehicle systems, however.

In-vehicle systems are embedded systems, which means that the boards they run on are usually constrained by power, heat and cost considerations. Power requirements are less stringent for in-vehicle systems than for consumer devices, such as smart phones. On the other hand, however, these systems are expected to run for the lifetimes of their vehicles, during which they can expect a steady increase in the load they are expected to handle, as more and more technologies, capabilities and applications become available.

In short, an in-vehicle system OS must not only be able to guarantee resources to critical processes, it must also not waste resources. When an application requires more resources than the original design foresaw, the OS must find a way to not provide them. It must not leave resources waiting unused because they are reserved for critical processes. It must offer them to whatever process needs them, but be able to get them back when they are need to ensure the system always meets designed reliability and performance requirements.

Adaptive partitioning

To meet these apparently conflicting requirements typical of embedded systems, the QNX  Neutrino Real Time OS (RTOS) implements adaptive partitioning. Adaptive partitioning is more flexible than traditional fixed partitioning models. It guarantees time to specified processes, just like traditional partitions. However, unlike traditional partitions, which are fixed, adaptive partitioning automatically adapts partitions to runtime conditions.

An adaptive partition is a set of threads that work on a common or related goal or activity. Like a static partition, an adaptive partition has a budget allocated to it that guarantees its minimum share of the CPU's resources, but it responds to dynamically changing runtime loads in order to always make full use of all available CPU cycles.

Adaptive partitioning is more flexible than rigid partitions. It is a set of rules that protect specified threads and groups of threads, and is an excellent solution for dynamic embedded systems.

First, unlike a static partition, an adaptive partition is not locked to a fixed set of code in a static partition; developers can dynamically add and configure adaptive partitions, as required.

Second, an adaptive partition behaves as a global hard realtime thread scheduler under normal load, but can still provide minimal interrupt latencies even under overload conditions. Third, with adaptive partitioning, the thread scheduler distributes a partition's unused budget among partitions that require extra resources when the system isn't loaded.

Adaptive partitioning is thus ideal for dynamic systemssystems that must perform consistently despite rapidly changing demands made on them.

Conclusion

The advent of the connected car brings in-vehicle systems into the rapid delivery cycle of consumer device technologies. Automobile manufacturers and tier one suppliers can design their in-vehicle systems both to mitigate the challenges of reconciling the development cycles of software and steel, and to open the door to new opportunities.

Our experience with QNX CAR suggests that a system with an Adobe Flash Lite user interface communicating with underlying components through PPS messaging is the most effective solution. It facilitates user interface branding, localization and customization without impact on underlying components, and it simplifies the addition (both during development and in the future) of new applications and components.

Running a secondary Flash player allows untrusted applications to be downloaded and used while protecting other applications and the system.

The QNX Neutrino RTOSs adaptive partitioning technology is also available to make maximum use of available computing power; more flexible than rigid partitions, adaptive partitioning offers available CPU cycles to processes that can use them, while guaranteeing resources to critical processes and applications.

So much of the QNX CAR system is the RTOS that is not applicable to the Exploratory Project since it is Windows based.  Just the portions about easily adding or moving applications seems directly applicable and similar.  So it is an example of the usefulness of this ability.  While, the adaptive partitioning might be something that could be added to an aircraft system is it could only be used for Level C or D applications.  I would suppose that it could never be used for more critical applications so such an operating system would need to limit adaptive scheduling to particular applications.


Monday, December 13, 2010

Software Tracing

Software Tracing


In the December 2010 Embedded Systems Design “parity bit” column, Mira Samek of  state-machine.com writes “Instead of re-inventing all this for every project at hand, you can combine them into a generic, reusable state machine *framework*. A framework like this allows you to take software tracing to the entirely new level, because a framework funnels all important interactions within the system. … This sort of software tracing is not just a theoretical possibility.  For example, the open source QP state machine frameworks that I’ve described in my book Practical UML Statecharts in C/C++, 2nd Ed contain software tracing instrumentation called Q-SPY.”  [Where UML stands for Unified Modeling Language.]

So the QP state machine framework is another framework that treats all the events that cause particular routines to execute.

I expect that the code for the state machine states of the open source QP state machine frameworks must be one routine for each state in order that the framework can execute the correct state for a given event – just as in the Exploratory Project Message Controller (mC) framework.  That is, that the state machine selection mechanism can’t be promoted to the framework without making the code for each state into a separately callable method.

As Mira Samek points out, having the selection done within the framework allows instrumentation for software tracing to take place automatically in the framework without the need to add it to the code for the various states.  Therefore, I propose to add such tracing via logging to a disk file to the Exploratory Project mC.  Since various applications of the interconnected network can reside on separate computers, a disk file will be necessary for each application.  Or, perhaps, a logging application can be implemented to receive and store the trace output of each of the networked applications.  This would depend upon the sequencing of the communication mechanism to indicate the relative occurrences of the events in the various applications.

Dynamic Display Update

Dynamic Display Update


To illustrate the ability to dynamically update of the display by a user application of the Exploratory Project I added a text box to the second display layer via the display definition file (DF) and a periodic timer component to user application App2. 

The specification of the text box with its widget identifier was all that was necessary to have the Display Application display the text box and then display the date and time in the box each time commands are received to clear the text box and write new text to it.

The addition of a timer component to user App2 that sends commands to display layer 2 of the Display Application was all that was necessary to periodically output the commands for the particular widget identifier.

Upon install, at initialization time, this periodic timer component was registered to be run every 5 seconds.  This component was implemented to read both the system date and time (that is, GMT) and the local date and upon each execution.  Using the system and local times provided by Windows, it then creates a display command topic for layer 2 for the widget and publishes it for the Display Response subcomponent of App2.  Without needing any modification, every time the Display Response subcomponent of the Display component receives the topic it, in turn, automatically transmits it to the Display App.

Whenever the Display App receives the command for the layer it causes the thread that outputs to the particular Windows form for the layer to run.  The command is then decoded and output to the Windows text box control is performed to cause the new values for the date and time to be displayed.  Since the correct user thread is running, Windows problems due to cross-threading of controls is avoided.

Upon running the three applications (Display and the two user applications) the new text box of layer 2 is periodically updated with the date and the two times.  All that was required was the addition of a minor component to the one user application and without any need to modify the Display Application.

Friday, November 19, 2010

Peer-to-Peer

Peer-to-Peer


In the October 2010 Communications of the ACM is an article “Peer-to-Peer Systems” by Rodrigo Rodrigues and Peter Druschel small parts thereof I have quoted below.

“The term P2P has been defined in different ways, so we should clarify what exactly we mean by a P2P system.  For the purposes of this article, a P2P system is a distributed system with the following properties:

     High degree of decentralization.  The peers implement both client and server functionality and most of the system’s state and tasks are dynamically allocated among the peers.  There are few if any dedicated nodes with centralized state.  As a result, the bulk of the computation, bandwidth, and storage needed to operate the system are contributed by participating nodes.
     Self-organization.  Once a node is introduced into the system (typically by providing it with the IP address of a participating node and any necessary key material), little or no manual configuration is needed to maintain the system.
     Multiple administrative domains.  The participating nodes are not owned and controlled by a single organization.  In general, each node is owned and operated by an independent individual who voluntarily joins the system.


In some decentralized P2P systems, nodes with plenty of resources, high availability and a publicly routable IP address act as supernodes.  These supernodes have additional responsibilities, such as acting as a rendezvous point for nodes behind firewalls, storing state or keeping an index of available content.  Supernodes can increase the efficiency of a P2P system, but may also increase its vulnerability to node failure.


     Overlay maintenance.  P2P systems maintain an overlay network, which can be thought of as a directed graph G = (N,E), where N is the set of participating computers and E is a set of overlay links.  A pair of nodes connected by a link in E is aware of each other’s IP address and communicates directly via the Internet.”

The Exploratory Project to a large degree seems to fit the definition of the Peer-to-Peer Systems article.  That is, each distributed application (except for the display application) is both a server and a client in that particular components of the application can provide a service while others can be a client of a service or be both a provider / producer of a topic(s) and a client / consumer of other topics.  There is a configuration file that specifies the communication protocol supported by each application of the distributed system and, in the case of sockets, the IP address.  The various applications automatically connect with each other as they come online and determine which applications can provide their unmet services (that is, topics) and make known what services that they can provide to other applications of the system. 

At the time I read the article, only one node of the distributed system communicated with the display application while other nodes were all clients that received particular display events from the display server node and published display commands to the server node to be forwarded to the display application rather than the display application being a peer in the network.  Hence, in that version of the Exploratory Project, the node that interacts with the display application represents a supernode.

However, the ARINC-661 protocol for communications between user applications and a display application specifies that multiple user applications can communicate with the display application with any particular user application associated with its own display “layer”. 

Therefore, I extended the Exploratory Project such that multiple P2P applications can interface directly to the display application with each such application having its own display layer.  Since any particular component of an application can register to treat a particular display event, multiple components can be responsible for what is displayed on a display layer just as currently implemented for a single display layer.  And, since the component that registers to treat the display event can be allocated to any peer-to-peer application, such an application can communicate with the display in two different ways; one, via the application that has been allocated to treat the display layer and, two by being the application that has been allocated to treat the events of a different display layer.

For instance, the new version of the Exploratory Project is such that two layers can be described in the Definition File (DF) file and treated by the C# Display Application.  This, of course, can be extended by increasing the array sizes that retain data for the various layers. 

As in the previous version, the App1 P2P node connects to the Display Application for the forms and controls specified in the DF for layer 1.  Three forms are specified for the layer with three components of the P2P system each registering to treat the widget events of one of the forms with two of these components allocated to App2.

For the new version, App2 was extended to also interface to the Display Application via a separate communication channel by cloning the code of App1 and the Display Application was modified to select the communication channel to be used based on the layer of the form containing the widget / Windows control.

Due to the capabilities of the Exploratory Project, events of one display layer can modify another display layer controlled by another application.  That is, a layer 1 event transmitted to App1 can cause a change in layer 2 controlled by App2.  To illustrate this I changed the component that treats the text box of the third form of layer 1 to examine the text to check for “SHOW” or “HIDE” without regard to upper or lower case.  This control was already treated by a component of App2 to which the event had been forwarded by the project framework and then the response returned to App1 to forward to the Display App. 

If either Show or Hide were entered the normal response was changed to only clear the text box (rather than also adding the text to a list box of the first form of the layer) and to create a second response to display (show) the layer 2 form or hide it with the second response using the cloned version of the topic that is delivered to the layer 2 interface component of App2.  Therefore, the first response to clear the text box is sent to App1 for it to forward to the Display App using the layer 1 connection and the second is sent to the Display App via the layer 2 connection of App2.


Problems encountered in extending the Display Application

One modification to the C# Display Application necessary to add multiple layers was to add the use of worker threads to the application so that waits to receive commands from the P2P applications could occur on the connection for each layer at the same time.  This was something that was desirable prior to treating multiple layers, but not yet implemented, so that commands could be received asynchronously to events being transmitted to the responding application.  That is, to remove the need for command-response operation.

It was also necessary to have a pair of MS Pipes for each layer so that a wait for receive could occur on one pipe of the pair while an event could be transmitted using the other pipe of the pair.  Therefore, the MS Pipes between the Display Application server and each P2P application client node became similar to the pair of pipes between P2P nodes (except in the later case one pipe of the pair for any node was for the node acting as the server and the other for the node acting as a client of the other node).

The use of worker threads for the receives caused another problem.  That is, the interface to Windows requires that the access to the form controls always be from the same thread.  At first I thought that I could send an event to the main thread that was used to display the default form of the layer and have it then update the form responding to the received command.  However, the event handler ran in the same thread as had sent the event so that didn’t help.

Therefore, I also created a display thread for each layer that was created when the pipe pair for the layer connected with its P2P application.  The open of the display thread opens and displays the default form of the layer.  But it also starts a Windows timer prior to opening the default form so that the timer runs in the same thread.  (The other types of C# timers run in the main thread rather than the thread in which they are created.)  Then, each time the timer event handler runs, it checks if there is a received command for the layer and, if so, uses it to update the form associated with the layer.  In this way the use of the Windows controls for a layer is always from the same worker thread.

To determine the layer of a thread, the worker threads are named when they are created and the name of the executing thread is compared with these possible names to determine which thread is running.

Churn due to applications connecting, disconnecting, reconnecting, etc has yet to be addressed.

Friday, October 1, 2010

Service-Oriented Architecture Attributes Progress Report 2

Service-Oriented Architecture Attributes Progress Report 2


The use of the Queued attribute has been extended in the Exploratory Project framework to be more general along with implementing the Queue Size attribute.

Since the Queue Size attribute is a Subscription Attribute, it is used by a particular consumer subscribing to a topic.  Therefore, the queue of published topic instances yet to be read by a consumer component is not just one queue for a component but a set of queues, one for each queued topic subscribed to be read by the component. 

Therefore, a change was made so that each such consumer of the topic was provided with a queue of the requested size and the single queue for a consumer was removed.  Presumably a consumer that is to be run at a slower rate will request a longer queue to avoid losing instances of a queued topic.

Note:  Topics that are published very frequently where only the latest instance is needed by a component will continue to use a Most Recently Published topic rather than a queued one to avoid the processor cycles necessary to make extra copies.  One analysis of a Flight Management System found that such copies are a significant source of CPU loading. 

Also note that the lack of extra copies only applies to components within the same application.  Two extra copies will be necessary for each remote application that needs to receive the Most Recently Published instance of the topic but not extra copies for multiple components within the remote application.  This could be avoided if a common memory could be used by the applications so that the producer could write to it and the various consumers could read the MRP instance via the pointer to its buffer in the common memory.

Although I have retained the Pseudo Periodic component Activation attribute, since it was previously implemented, it can’t have the framework release any final buffer instance.   That is, the previously read buffer is released when the component does a new read.  But when the component doesn’t drain the queue by reading until there are no more entries to be read, the last entry read won’t be released until the component continues after the delay.  This is because a Pseudo Periodic does its own delay and doesn’t return to framework after it is first started.  Thus the framework cannot release the last entry that was read as it can when an Upon Demand, Periodic, or Aperiodic component finishes running and returns to the framework to await the next time it is invoked.

Getting the new queued topics changes debugged took longer than I had thought it would.  This was because I used two chains of linked elements to keep track of the consumers with queued topics and the particular topics with read queues for a consumer.  This resulted in a structure illustrated as follows.


 Consumer Queue Anchor
    |
    |  Consumer Q Chain     Consumer Queue        Read Q Chain
    |     +------+          +-----------+          +------+
    +---->| Item |--------->| Read Q Ptr|--------->| Item |---> Read
          |------|      /   |-----------+          |------|     Queue C
       +--| Next |     /    |   Key 2   |       +--| Next |
       |  +------+    /     +-----------+       |  +------+
       |             /                          |
       |            /                           |  +------+
       |      Consumer Queue                    +->| Item |---> Read
       |         Addr/Ptr                          |------|     Queue B
       |            \                              |   0  | <-- end of
       |             \                             +------+     chain
       |              \
       |  +------+     \    +-----------+          +------+
       +->| Item |--------->| Read Q Ptr|--------->| Item |---> Read
          |------|          |-----------+          |------|     Queue A
          |   0  |          |   Key 1   |          |   0  |
          +------+          +-----------+          +------+

The Consumer Queue Anchor points to the beginning of the Consumer Queue Chain.  Each link of the Consumer Queue Chain has an Item that points to the data of the link and a Next pointer to the next link of the chain.

Each entry in the Consumer Queue is pointed to by an Item of the Consumer Queue Chain.  This set of data records each has the key of a particular consumer for which topic instances are queued and an anchor address/pointer providing the location of the Read Queue Chain of the consumer.

Each link of the Read Queue Chain has an Item that points to the Read Queue for a particular topic that has its published instances queued for the consumer and a Next pointer to the next link of the chain.

For each of the two types of chains, a null (0) Next pointer indicates the end of the chain.

Also, note that the links are added such that the chains will be read in LIFO order.

For some reason, although I had numerous examples of the code required to add links to a chain I had difficulty following my examples.  A sign of getting old?  Hope it was just temporary. 

Next will be to create more example components with various methods of activation and more example topics with various methods of message exchange and use them to subscribe to various combinations of most recently published and queued topics to more completely debug the modifications of the SOA attributes.