Referred to Fig 2-2, the system components determine the performance of the system.
With the aid of RTAI APIs, the components can be realized easily.
3.2.1. Clock
The system clock is hidden in the system scheduler of RTAI, as mentioned in the last section. The function start_rt_timer () and stop_rt_timer ()can switch the system timer (clock)
time.
3.2.2. Short-term Memory
The short-term memory is a large piece of memory stores the recent variables, states of the agents, and can be accessed by every agent. Circular buffer is therefore a good data structure under this requirement. First, it can be allocated once and remain useful, which reduce the overhead of memory allocating time; Secondly, it allows the agents to read and write at the same time and therefore prevent the synchronization problem, as shown in Fig.
3-2.
In practice, the shared memory is allocated using the RTAI API rt_malloc (). Every chunk of circular buffer can be identified with an unsigned long integer, or a six characters name.
Data N Writing_lock
Current data
Data 3
3.2.3. Message Delivery and Router
The mailbox service is chosen in this system for message delivery. The mailbox service allows messages between processes to be automatically stored and retrieved as needed in a priority queue. In RTAI, mailbox service is very flexible.
z It can be explicitly setup to accept messages of customized sizes.
z Multiple receivers and senders can be connected to the same mailbox where the order in which messages are taken depends on the priorities of the receivers.
z When large messages need to be sent, the service provides functions to allow the process to send only the portion of the message that can be stored, returning the number of unsent bytes, or to continue to send the message until all of it has been accepted.
Mailboxes can be slightly less efficient than FIFO since it has twice more numbers of memcopy () operations. However, the advantage is relatively high that it is worth such a minor penalty. Furthermore, the effect is unlikely to be noticeable for relatively short messages.
The router is a real-time task with two mailboxes, one for registry, and the other for message dispatching. If an agent wants to join the system, it has to register its own mailboxes (which means that an agent can own more than one mailbox), and subscribes the desired mailboxes of the agents from the router. It can also assign target mailboxes initiatively. The
message to the router, and the router will look through the list and broadcast the message to every subscriber. This process produces some minor overhead, but introduces a dynamic linking between agents, instead of changing the code and recompiling it.
The connection list is maintained with a two-layered linking list, as shown in Fig 3-3, which takes advantages on adding and checking through mailboxes fast. However, removing a MBX from the list causes a chain effect: Every sub-list has to be checked and removed, which is O (N2). Therefore, the deletion of the MBX only removes it from the top level. When a sending task is processed, every MBX will be checked and the deleted one will be removed.
MBX1 MBX2 … MBX N
MBX5
MBX7
MBX1
MBX3
MBX6
MBX5
MBX7
3.2.4. Agent
The agent defined in our system can be just part of algorithm or functions. Since this is a multi-process/ multi-threaded system, it surfers from the synchronization and deadlock problems, etc, and have to be carefully handled. In this implementation, the messages and main tasks used by the agent are separated. This approach guarantees that the functions will never be blocked when waiting for messages. Fig. 3-4 shows how this approach works.
The message checker is a high priority task that listens to the mailbox and responses immediately on receiving messages. The message checker will interpret the message, modify the parameters or states of the agent, and keep them in the memory. The interpretation of the messages is left for the user in order to be compatible with their design. The agent task can be classified into two different types:
main function
z The event-driven (aperiodic) type is triggered right after the messages arrive.
Therefore, its execution rate is determined by its message source. Once it is started, the function will lock itself to prevent reentrant
z The periodic type is triggered periodically with different priorities and rates. The system can adjust its rate to achieve better performance.
In the case of sensor agent, it does the same trick. The only difference is that there is one more task, which listens to the data transferred from the sensor devices.
As mentioned before, the RTAI task can be executed in kernel space or user space.
Therefore, an agent may be implemented in two different forms. In the kernel space, the agent has to be written in the form of modules. The real-time tasks are initialed in init_module (), which is the starting point when a module is loaded. The code of the real-time task is implemented as function and then linked to the task when it is initialized using rt_task_init ().
In the user space, it takes more efforts to do the same job. First, the code of the real-time tasks is not linked to a function. The user has to use pthread to execute the functions
3.2.5. Decision Maker and Knowledge base
The decision maker works as a table look-up agent, which assigns different weight and execution rate under different circumstances reported by the agents.
3.2.6. Resource Manager
The resource manger works as a virtual sensor agent, gathering the CPU usage info and memory usage status, and reporting it to the decision maker. The system information can be gathered from the files under /proc directory.