RTOS broadcast messaging

Ralph Moore, Micro Digital, Inc.

January 18, 2015

Ralph Moore, Micro Digital, Inc.January 18, 2015

A customer recently asked for my advice on a messaging problem. The solution to this problem is a good exercise concerning how to use message broadcasting, different kinds of exchanges and semaphores, and helper tasks to solve difficult problems.

The customer had defined three tasks:

  • lcdt LCD task
  • mont monitoring task
  • newt networking task

newt sends notification messages to both of the other tasks as it receives network messages from the network. A logical structure would be to define an exchange for lcdt and another exchange for mont. Then newt could send a notification message to each whenever it received a network message. However, this solution is not acceptable because lcdt is not present in all systems and thus it is undesirable to hard-code sending messages to it in newt.

Broadcasting is a logical solution to this problem. For it, we create a broadcast exchange, bxchg:

     XCB_PTR bxchg;
     bxchg = smx_MsgXchgCreate(BCST, "bxchg");


Then newt sends a single message to bxchg, where both mont and lcdt (if it is present) wait. newt then waits at a threshold semaphore for lcdt and mont to finish:

     SCB_PTR tsem;
     tsem = smx_SemCreate(THRES, T, "tsem");


T is the threshold, which can be set to 2 if lcdt is present, or to 1 if it is not. (tsem is created by startup code, which knows if lcdt is present.) Note that newt does not need to know this. In fact, other receiving tasks could be added without changing newt's code. Another advantage of broadcasting is that it is not necessary to create duplicate messages -- one copy is sufficient.

So, newt_main() looks like this:

     void newt_main(void) {
        MCB_PTR nmsg;
        u8 *mp;

        nmsg = smx_MsgGet(msg_pool, &mp, 0);

        while (1) {

           // receive network message

           while (smx_SemTest(tsem, TMO)) {
              // fill notification message using mp
              smx_MsgSend(nmsg, bxchg);
              smx_SemSignal(gsem);
        }
     }


nmsg is obtained once from msg_pool; then it is used over and over. newt retains ownership of the nmsg, even after sending it to bxchg. Refilling nmsg and resending it to bxchg registers it as a new message. SemTest() passes the first time because lcdt and mont pre-signaled it.

gsem is a gate semaphore:

     SCB_PTR gsem;
     gsem = smx_SemCreate(GATE, 1, "gsem");

gsem serves to prevent the receiving tasks from receiving the same message twice. The receiving tasks have the following structure:

     void lcdt_main(void) {
        u8 *mp;

        smx_SemSignal(tsem); // pre-signal tsem

        while (smx_SemTest(gsem, INF)) {
           smx_MsgReceive(bxchg, &mp, TMO);
           // display notification message on LCD using mp
           smx_SemSignal(tsem);
        }
     }


The mont_main()code is similar. Since lcdt only reads nmsg, only mp is used; its handle, nmsg, is not needed.

The above code works reliably, but there is a problem because newt waits at tsem until both lcdt and mont are done with the message. Unfortunately, lcdt is a low-priority task, so this could take a long time. Hence, newt, which is a high-priority task, could miss an incoming message from the network. We have inadvertently created an unbounded priority inversion.

This problem can be solved by introducing a helper task, broadcast helper task bht. bht serves as a go-between, similar to the transmission in an automobile that allows the engine and the wheels to turn at different speeds. For bht, define and create a normal message exchange:

     XCB_PTR nxchg;
     nxchg = smx_MsgXchgCreate(NORM, "nxchg");

Now, newt_main() and bht_main() are as follows:

     void newt_main(void) {
        MCB_PTR nmsg;
        u8 *mp;
 
        while (1) {

           // receive network message

           nmsg = smx_MsgGet(msg_pool, &mp, 0);
           // fill notification message using mp
           smx_MsgSend(nmsg, nxchg);
        }
     }
     void bht_main(void) {
        MCB_PTR nmsg;

        while (smx_SemTest(tsem, TMO)) {
           nmsg = smx_MsgReceive(nxchg, NULL, INF);
           smx_MsgSend(nmsg, bxchg);
           smx_SemSignal(gsem);
        }
     }


Now, newt receives a message from the network, gets nmsg from msg_pool, fills it and sends it to nxchg without waiting on lcdt and mont. It then waits (not shown) for the next network message. Hence, it can keep up with the network, and notification messages will build up at nxchg, as necessary.

bht waits at tsem for lcdt and mont to finish. (tsem passes the first time due to pre-signals). It then waits at nxchg for a new message; this wait can be short or long, depending upon network activity. When a new message arrives, bht sends it to bxchg. A broadcast exchange can hold only one message at a time, so the previous message is automatically released to msg_pool for reuse. bht then goes back to waiting on tsem for lcdt and mont to finish with the latest notification message.

So we see that receiving network messages and processing resulting notification messages have been decoupled -- each proceeds at its own pace, within limits. This is a good way to design systems. Since bht does practically nothing, it needs only 120 bytes of stack plus 80 bytes for its TCB and timer. 200 bytes of RAM is not bad for a reliable and flexible solution to a relatively complex problem.

References:
SMX User’s Guide and Reference Manual

Ralph Moore, President of MicroDigital, graduated with a degree in physics from Caltech. He spent his early career in computer research. Then he moved into mainframe design in the 60's and became a consultant in the early 70's. He taught himself programming and became a microprocessor programmer. He founded Micro Digital in 1975, and many years of successful consulting led into architecting and developing the SMX kernel in 1987. For many years he managed the company’s business and sales, but in recent years he has been focused almost solely on v4 development of the SMX multitasking kernel.

Loading comments...

Parts Search Datasheets.com

Sponsored Blogs