This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

RTOS/AWR1642: Task and Mailbox

Part Number: AWR1642
Other Parts Discussed in Thread: SYSBIOS

Tool/software: TI-RTOS

hello,

The codes as follows:

#include <xdc/std.h>
#include <ti/sysbios/BIOS.h>
#include <xdc/runtime/Log.h>
#include <xdc/runtime/Error.h>
#include <ti/sysbios/knl/Mailbox.h>
#include <ti/sysbios/knl/Task.h>
#include <xdc/runtime/System.h>
#include <xdc/cfg/global.h>


#define NUMMSGS 3 /* number of messages */


#define TIMEOUT 10


typedef struct MsgObj {
Int id; /* writer task id */
Char val; /* message value */
} MsgObj, *Msg;


Void reader(Void);
Void writer(int id_arg);


Mailbox_Handle mbox;


/*
* ======== main ========
*/
Void main()
{
Task_Params taskParams;
Task_Handle myTsk0,myTski;
Mailbox_Params mboxParams;


UInt i;
Error_Block eb;


Error_init(&eb);


/*create 1 reader_task with priority 2*/
Task_Params_init(&taskParams);
// taskParams.stackSize = 4*1024;
taskParams.priority = 2;


myTsk0=Task_create((Task_FuncPtr)reader,&taskParams,&eb);
if(myTsk0==NULL)
System_abort("reader create failed");


Mailbox_Params_init(&mboxParams);
mbox = Mailbox_create(sizeof(MsgObj),2,&mboxParams,&eb);


if(mbox==NULL)
System_abort("Mailbox create failed");


/*Creat 3 tasks with priority 2*/
/*re-uses taskParams */
taskParams.priority=2;
for(i=0;i<3;i++)
{
taskParams.arg0=i;
myTski=Task_create((Task_FuncPtr)writer,&taskParams,&eb);
if(myTski==NULL)
System_abort("writer create failed");
}


/*Start SYS/BIOS*/
System_flush();
BIOS_start();


}


/*
* ======== reader ========
*/
Void reader(Void)
{
MsgObj msg;


while(1)
{
/* wait for mailbox to be posted by writer() */
if (Mailbox_pend(mbox,&msg, BIOS_WAIT_FOREVER) == 0) //BIOS_WAIT_FOREVER
{
System_printf("timeout expired for MBX_pend()\n");
System_flush();
break;
}


/* print value */
System_printf("read '%c' from (%d).\n", msg.val, msg.id);
System_flush();
}
System_printf("reader done.\n");
System_flush();
}


/*
* ======== writer ========
*/


Void writer(int id_arg)
{
MsgObj msg;
Int i;
Int id = id_arg;// 0;//ArgToInt (id_arg);


for (i=0; i < NUMMSGS; i++)
{
/* fill in value */
msg.id = id;
msg.val = i % NUMMSGS + (Int)('a');


/* enqueue message */
Mailbox_post(mbox,&msg, BIOS_WAIT_FOREVER);


System_printf("(%d) writing '%c' ...\n", id, (Int)msg.val);
System_flush();


}


System_printf("writer (%d) done.\n", id);
System_flush();
Task_yield();
}

The  debugging outcomes in the console as follows:

[C674X_0] (0) writing 'a' ...
(0) writing 'b' ...
read 'a' from (0).
read 'b' from (0).
(0) writing 'c' ...
writer (0) done.
(1) writing 'a' ...
read 'c' from (0).
read 'a' from (1).
(2) writing 'a' ...
(1) writing 'b' ...
read 'a' from (2).
read 'b' from (1).
(2) writing 'b' ...
(1) writing 'c' ...
writer (1) done.
read 'b' from (2).
read 'c' from (1).
(2) writing 'c' ...
writer (2) done.
read 'c' from (2).

But I think the outcomes should be as follows:

[C674X_0] (0) writing 'a' ...
(0) writing 'b' ...
read 'a' from (0).
read 'b' from (0).
(0) writing 'c' ...
writer (0) done.
(1) writing 'a' ...
read 'c' from (0).
read 'a' from (1).
(1) writing 'b' ...
(1) writing 'c' ...
writer (1) done.
read 'b' from (1).
read 'c' from (1).
(2) writing 'a' ...
(2) writing 'b' ...
read 'a' from (2).
read 'b' from (2).
(2) writing 'c' ...
writer (2) done.
read 'c' from (2).

Can you explain why? Thanks very much!

  • Hi,

    The actual output is correct (and expected), but it's rather tricky since all the tasks are the same priority. Note: a Mailbox instance has a Data and Free Queue. The free queue is populated with the # of msgs specified in the create. The queues are protected by Data and Free semaphores.

    Before BIOS_start here are the tasks in the ready queue for priority 2 (looking in ROV->Task->ReadyQ is very helpful!)

    readyQ: R, W0, W1, W2 Blocked: none
    Num Msgs in Mailbox: 0
    Action: BIOS_start is called, so R runs first and then immediately blocks since the Mailbox is empty.

    readyQ: W0, W1, W2 Blocked: R
    Num Msgs in Mailbox: 0
    Action: W0 runs and posts the first message. This makes R ready to run and then is 1 message in the Mailbox
    Output: (0) writing 'a' ...

    readyQ: W0, W1, W2, R (where W0 is running) Blocked: none
    Num Msgs in Mailbox: 1
    Action: W0 continues to run and posts the second message. Now there are 2 message in the Mailbox.
    Output: (0) writing 'b' ...

    readyQ: W0, W1, W2, R (where W0 is running) Blocked: none
    Num Msgs in Mailbox: 2
    Action: W0 continues to run and tries to post 3rd message, but mailbox is full, so it blocks.

    readyQ: W1, W2, R Blocked: W0
    Num Msgs in Mailbox: 2
    Action: W1 runs, but is blocked on Mailbox_post since the mailbox is full

    readyQ: W2, R Blocked: W0, W1
    Num Msgs in Mailbox: 2
    Action: W2 runs, but is blocked on Mailbox_post since the mailbox is full

    readyQ: R Blocked: W0, W1, W2
    Num Msgs in Mailbox: 2
    Action: Reader runs and gets one message. This makes W0 ready.
    read 'a' from (0).

    readyQ: R, W0 Blocked: W1, W2
    Num Msgs in Mailbox: 1
    Action: Reader continues to run and gets second message. This makes W1 ready.
    Output: read 'b' from (0).

    readyQ: R, W0 , W1 Blocked: W2
    Num Msgs in Mailbox: 0
    Action: Reader blocks on Mailbox_pend since it is empty.

    readyQ: W0 , W1 Blocked: W2, R
    Num Msgs in Mailbox: 0
    Action: W0 runs and places third message on the mailbox and ends. This makes R ready. 1 msg in mailbox.
    Output:(0) writing 'c' ...
    writer (0) done.

    readyQ: W1, R Blocked: W2
    Num Msgs in Mailbox: 1
    Action: W1 runs and places first message in the Mailbox. 2 msgs in mailbox now
    Output: (1) writing 'a' ...

    readyQ: W1, R Blocked: W2
    Num Msgs in Mailbox: 2
    Action: W1 continue to run but is blocked when trying to place its second message since mailbox is full.

    readyQ: R Blocked: W2, W1
    Num Msgs in Mailbox: 2
    Action: Reader runs and gets message (last from W0). This makes W2 ready (so it will take the first free msg in the mailbox)
    Output: read 'c' from (0).

    readyQ: R, W2 Blocked: W1
    Num Msgs in Mailbox: 1
    Action: Reader runs and gets message (first from from W1). This makes W1 ready. This is subtle…it also basically gives W1 the second free msg in the mailbox.
    Output: read 'a' from (1).

    readyQ: R, W2, W1 Blocked:
    Num Msgs in Mailbox: 0
    Action: Reader runs and is blocked since mailbox is empty

    readyQ: W2, W1 Blocked: R
    Num Msgs in Mailbox: 1
    Action: W2 runs and places its first message. This R ready.
    Output: (2) writing 'a' ...

    readyQ: W2, W1, R Blocked:
    Num Msgs in Mailbox: 1
    Action: W2 runs and but cannot obtain a free msg (owned by W1 from a few lines ago)…so it blocks

    readyQ: W1, R Blocked: W2
    Num Msgs in Mailbox: 1
    Action: W1 runs and places its second message.
    Output: (1) writing 'b' ...

    readyQ: W1, R Blocked: W2
    Num Msgs in Mailbox: 2
    Action: W1 runs and blocks since there are no free msgs

    readyQ: R Blocked: W2, W1
    Num Msgs in Mailbox: 2
    Action: R gets a message and this makes W2 ready
    Output: read 'a' from (2).

    readyQ: R, W2 Blocked: W1
    Num Msgs in Mailbox: 1
    Action: R gets a message and this makes W1 ready (and basically gives it the second free msg in the mailbox)
    Output: read 'b' from (1)

    readyQ: R, W2, W1 Blocked:
    Num Msgs in Mailbox: 0
    Action: R blocks since there are no msgs

    readyQ: W2, W1 Blocked: R
    Num Msgs in Mailbox: 0
    Action: W2 runs … left to the reader to complete…

    Does this make sense?
  • Sorry,I don't understand the underline place in the following picture,why?I think W2 runs and it doesn't block. Thanks very much!

  • Since the mailbox was created with 2 msgs, when it is empty, the 2 msgs are on the free queue. The semaphore (call it free-semaphore) used to manage the free queue has a count of 2 (zero denotes not available). Here are the two critical steps from above (I wished I had numbered them!). I've added some more description

    readyQ: R Blocked: W2, W1
    Num Msgs in Mailbox: 2
    Free -semaphore count: 0
    Action: Reader runs and gets message (last from W0). This makes W2 ready (so it will take the first free msg in the mailbox).
    More detail: When the reader gets the msg via Mailbox_pend, it places the msg back on the free queue. It also sees that W2 is pending on the free semaphore. So it makes W2 ready and does not increment the free-semaphore count. Remember that W1 is on the free-semaphore pending queue also. Since W2 was made ready, W1 is now at the front on the free-semaphore pending queue.
    Output: read 'c' from (0).

    readyQ: R, W2 Blocked: W1
    Num Msgs in Mailbox: 1
    Free-semaphore count: 0
    Action: Reader runs and gets message (first from from W1). This makes W1 ready. This is subtle…it also basically gives W1 the second free msg in the mailbox.
    More detail: Again, when R gets the msg, the internal msg that had the data is now put on the free queue. Since there is a task (W1) on the free-semaphore pending queue, it is made ready. The free-semaphore count is still zero (since both W2 and W1 obtained it and there are no more free msgs).
    Output: read 'a' from (1).

    Later when W2 tries to get another msgs, it blocks since there are no more free message (one is on the data queue and the other is owned by W1).

    Todd
  • Thanks very much!