Pumpkin, Inc.

Pumpkin User Forums

OS_WaitMsgQ Problem or Question

If you can't make Salvo do what you want it to do, post it here.

OS_WaitMsgQ Problem or Question

Postby samuel » Thu Oct 26, 2006 10:16 am

I'm having a hard time understand the flow of control when using OS_WaitMsgQ. For example take a look at this pseudocode:

code:
task1 {
print("before signal");
OSSignalMsgQ();
OS_Yield();
print("after signal");
}

task2 {
OS_WaitMsgQ();
print("gotq");
}


Assuming task1 starts first you would expect:
"before signal"
"gotq"
"after signal"

I don't get this. I get:
"before signal"
"after signal"
"before signal"
"gotq"

I've tried many more test cases. OS_WaitQ context switches everytime (unless it is called multiple times when there is no other context switch between calls) regardless of the state of the Q. An unusual workaround I found is to call OS_Yield() twice back to back. This results in the correct output. Please help.

sam

[This message has been edited by aek (edited October 27, 2006).]

[This message has been edited by aek (edited October 27, 2006).]

samuel
 
Posts: 22
Joined: Sun Oct 08, 2006 11:00 pm

Re: OS_WaitMsgQ Problem or Question

Postby samuel » Fri Oct 27, 2006 12:17 am

I searched through all the source files and could not find a macro definition fo OS_WaitXyz... I followed the source code from OS_WaitMsgQ to OSWaitEvent but had trouble understanding why this happens and is permissible.
samuel
 
Posts: 22
Joined: Sun Oct 08, 2006 11:00 pm

Re: OS_WaitMsgQ Problem or Question

Postby aek » Fri Oct 27, 2006 12:40 am

grep the header files (salvo.h, etc.) and you'll find it.

But here's the skinny.

1) Salvo's scheduler follows a simple rule -- always run the highest priority eligible task.

2) There's a not-so-obvious corrollary to this rule (I searched the Salvo User Manual but can't find this explicitly stated -- I'll look into adding it): Namely, that every context switch is unconditional. With OS_Yield() it's obvious. But with OS_WaitXyz() it's not so obvious. Every call to OS_WaitXyz() includes an unconditional context switch whether or not the event is available. I won't go into how this works , but the reason why you want this is to preserve responsiveness in the system. So in your example, it looks like this:

Task1() runs 1st, up to its OS_Yield().
Task2() runs 2nd, and context switches (remember, all OS_'s are unconditional context switches).
Task1() runs 3rd, since Tasks Rask1() and Task2() run at the same priority.
Task2() runs 4th since it has completed its unconditional context switch, this time it waits the event successfully, and goes on its merry way to ultimately wait the event again.

The behavior is a bit simpler if the event is not available -- in that case, it's obvious that a context switch is required.

Why do things this way? Well, consider a case where you are "bombarding" a sem from an ISR via OSSignalSem(). If you wrote OS_WaitXyz() code that only yielded to the scheduler if the event was not available, then in this case you'd be stuck in said event until the sem dropped down to 0 via successful waits. Well, what happens if another, higher-priority task is made eligible during this time? Nada -- the scheduler can't dispatch it because the waiting task never yields. And you blow your whole application. Therefore, in a cooperative scheduling scheme like Salvo's, unconditional context switches are required for proper operation (and they make for excellent responsiveness, too).

Note that in your example, what you are essentially trying to do is handshake between two tasks, yet your signaling is strictly unidirectional (from Task1() to Task2()). In a loosely coupled system, that sort of thinking leads to some assumptions that are (as demonstrated in your initial puzzlement) incorrect. If, instead, you signaled a binSem from Task2() to Task1() and waited it in Task1() until you knew that Task2() had processed the message, then you'd have had exactly the behavior you expected.

The Salvo code handles all of this behavior based on the basic rule of the scheduler. I recommend not thinking about "linear sequencing" when you're considering (interacting) tasks, but rather, think along the lines of "when will this task actually run based on the scheduler's rule?" And the answer for Task2() in your example is "As soon as it's the highest-priority eligible task."

FYI, tasks at the same priority round-robin. So Task1() ran before Task2() only because it was created first.

------------------

-------
aek
aek
 
Posts: 1888
Joined: Sat Aug 26, 2000 11:00 pm

Re: OS_WaitMsgQ Problem or Question

Postby samuel » Fri Oct 27, 2006 1:47 am

I understand. On p. 66 of the manual it is stated that every OS_ may or may not result in a context switch. The previous message states that every OS_ is an unconditional context switch. Is there a mistake in the manual?
samuel
 
Posts: 22
Joined: Sun Oct 08, 2006 11:00 pm

Re: OS_WaitMsgQ Problem or Question

Postby aek » Fri Oct 27, 2006 2:31 am

Yes, the manual is out of date.

I'll fix that -- thanks.

------------------

-------
aek
aek
 
Posts: 1888
Joined: Sat Aug 26, 2000 11:00 pm

Re: OS_WaitMsgQ Problem or Question

Postby samuel » Fri Oct 27, 2006 9:32 am

main.c
code:

----------------------------------------
#include <__cross_studio_io.h>
#include <salvo.h>
#include <MSP430.h>

#define TASK1_TCBP OSTCBP(1)
#define TASK2_TCBP OSTCBP(2)

#define MSGQ_ECBP OSECBP(1)
#define MSGQ_SIZE 4
#define MSGQ_QCBP OSMQCBP(1)

void Task1( void );
void Task2( void );

OSgltypeMsgQP MsgQ[MSGQ_SIZE];

void main(void)
{
OSInit();

OSCreateTask(Task1, TASK1_TCBP, 10);
OSCreateTask(Task2, TASK2_TCBP, 10);

OSCreateMsgQ(MSGQ_ECBP, MSGQ_QCBP, MsgQ, MSGQ_SIZE);

while(1) {
OSSched();
}
}

void Task1( void )
{
static OStypeMsgP qMsgP1;

while(1) {
debug_printf("
Before Q Signal");
OSSignalMsgQ( MSGQ_ECBP, (OSgltypeMsgQP)&qMsgP1 );
OS_Yield();
debug_printf("
After Q Signal");
}
}


void Task2( void )
{
static OStypeMsgP qMsgP2;

while(1) {
OS_WaitMsgQ( MSGQ_ECBP, &qMsgP2, OSNO_TIMEOUT );
debug_printf("
Received Q Signal");
}
}


salvocfg.h

code:

----------------------------------------
#define OSUSE_LIBRARY FALSE

#define OSTASKS 2

#define OSEVENTS 1

#define OSEVENT_FLAGS 0

#define OSENABLE_MESSAGE_QUEUES TRUE
#define OSMESSAGE_QUEUES 1

#define OSENABLE_EVENT_READING FALSE
#define OSENABLE_EVENT_TRYING FALSE

#define OSENABLE_BINARY_SEMAPHORES FALSE



Debug Output
code:

----------------------------------------
Before Q Signal
After Q Signal
Before Q Signal
Received Q Signal
After Q Signal
Before Q Signal
Received Q Signal

[This message has been edited by aek (edited October 27, 2006).]

samuel
 
Posts: 22
Joined: Sun Oct 08, 2006 11:00 pm

Re: OS_WaitMsgQ Problem or Question

Postby aek » Fri Oct 27, 2006 10:03 am

OK, it took me a while to figure out why the behavior as shown is correct (but not intuitive).

If you change the priority of Task1() to be _lower_ than that of Task2() (e.g. to 12) then you will get the behavior that you expected.

Shall I explain why, or do you want to give it a shot first? It's quite instructive. Hint: look at the macro definition for OS_WaitXyz() and note that there are conditionals inside it. Or, step through the source code and note the comments.

------------------

[This message has been edited by aek (edited October 27, 2006).]

-------
aek
aek
 
Posts: 1888
Joined: Sat Aug 26, 2000 11:00 pm

Re: OS_WaitMsgQ Problem or Question

Postby aek » Fri Oct 27, 2006 11:27 am

Let's see the entire application, with the salvocfg.h used ...

------------------

-------
aek
aek
 
Posts: 1888
Joined: Sat Aug 26, 2000 11:00 pm


Return to Coding

Who is online

Users browsing this forum: No registered users and 2 guests

cron