Pumpkin, Inc.

Pumpkin User Forums

Possible problem when signaling MESSAGES in RAM

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

Possible problem when signaling MESSAGES in RAM

Postby luben » Tue May 08, 2001 8:06 am

Hello,

I have some problems with MESSAGEs. Messages are in fact pointers to some areas in the memory (ROM or RAM) where resides the real information (it’s possible to exchange directly non binary /non equal to zero/ data via messages, but it’s other case).

Today I saw that in the forum is explanation about how to check if mesages are free or not, so half of my questions are anwered already (thanks for the really excellent support in this forum on very high level - your answeres hit directly in the target). But maybe this should be written like a note in the manual, beacuse it's a potential problem for all users of messages if they don't care for the RAM.

After I successfully signal one message the pointer of the message points to the real data in the memory, correct? Until message is not free I can’t signal the message and can only wait with OS_Yield() or OS_Delay(). Here everything is clear and fine.

Now imagine that my data resides in RAM memory. And I already signaled the message successfully. The task can return the control to the RTOS kernel. The potential problem appears when I have to signal this message again and especially if I want to reuse the same RAM location.

If I try to signal the message again, before I run OSSignalXYZ() I have to put the new data into RAM location – and this is the critical moment. If the message is still filled and I do this, the old message’s information (that is not yet read) will be changed. So, the task that reads the messages will get not the old, but the new message. If the task already read the message – no problems will be seen. Note that this could be avoided with some changing of priorities and using OS_Yield() or other commands that return control to the RTOS. But you have to agree that not in all cases is suitable to change the priorities. The idea of the priority is to bring bigger attention to one task, then others. And not in all cases the task that receives message has higher priority then the task that signals it.

Because in SALVO 2.2 is simple way to check if MESSAGE is free or not, this problem is not so hard to solve with some additional operators. Before writing data to RAM cells could be made simple check if MESSAGE is free and only if it’s free the RAM could be written.

What are your suggestions for solving this problem in SALVO 2.1, I mean, how to ensure that before I store my data in the cell the message is already free. Or maybe there are some more elegant ways to solve this problem? Maybe could be made a new operator like OS_LOCK_RAM_LOCATION()/OS_UNLOCK_RAM_LOCATION() and supplementary OS_WRITE() and OS_READ(). Of course SALVO could read and write to any protected cells – these limitations are for the tasks. Think about this – Windows OS uses some protection of the memory too. Why not to add such feature in the SALVO?

Regards
Luben

luben
 
Posts: 324
Joined: Sun Nov 19, 2000 12:00 am
Location: Sofia, Bulgaria

Re: Possible problem when signaling MESSAGES in RAM

Postby Salvo Tech Support » Tue May 08, 2001 10:26 am

Hi Luben.

What you describe is not generally considered a problem -- it's how message passing is normally done. The problem you describe (wanting to reuse a RAM location for messages, but not knowing when it has been "received" by the waiting task) is usually solved with message queues and/or local copies of the message you want to send.

One option you can pursue: use constant messages instead of or in place of RAM messages. That way, the message pointer points to something that is invariant. Note that with OSBIG_MESSAGE_POINTERS you can pass both consts and RAM as messages.

Another option is to use local copies of the information you want to send in the message. But you really need a malloc for that ...

I think the solution to your problem is to re-consider what messages are for -- they are a "guaranteed" way to pass information from one process to the next. By guaranteed I mean that as long as you pass messages without modifying their contents after calling OSSignalXyz(), no matter what happens in the rest of the system, as soon as a task waits the message, it will get that particular message and no other one. In other words, the message "persists" until it is received at the other end.

In a system that has more memory than a PIC, one could imagine an RTOS that would make a copy of the message (not the pointer, but the actual message) and keep it until the message is received. But since a message can be anything (from a char to an int to a structure to a multi-dimensional array to a file, in increasing order of size), it's easy to see that one could actually run out of memory just trying to "preserve the message" between the time it's signaled and when it's successfully waited. Therefore this approach isn't taken at all, and instead pointers point to a single object that is expected to remain invariant.

Of course you could do interesting tricks if it were non-invariant, like if you passed a timer (e.g. TMR0) in a message -- then you might be able to deduce elapsed time between when it was signaled and when a task successfully waited it, since TMR0 might change during that time period.

In summary, memory protection is best left to hardware / MMUs and RTOSes designed for much bigger arhcitectures than the PIC et. al.

Also, I would advise you against altering task priorities in an effort to change event handling -- that's not what task priorities are for.

If you have a specific problem in mind, perhaps posting a code snippet might lead to some suggestions on how to implement the functionalty you seek in a different manner ...

Regards,

------------------
-----------------------
Salvo Technical Support
Please request all tech support through the Forums.

--------
Salvo Technical Support
Please request all tech support through the Forums.
Salvo Tech Support
 
Posts: 173
Joined: Sun Nov 19, 2000 12:00 am

Re: Possible problem when signaling MESSAGES in RAM

Postby luben » Wed May 09, 2001 8:06 am

Hello,

I agree with you that messages and message queues are used for sending fixed messages between tasks. And when sending data directly trough the queue (when signaling the event, pointer directly holds the value, but not the address of the data) is possible to exchange even binary values between tasks.

But there is one example that this is hard to do, or it will consume a lot of memory – when you try to exchange both fixed strings and variable strings between tasks. Imagine that you have RS232 task that outputs data. One solution is to pass to this task via message queue directly the data – no problems. But if I want to use both fixed messages in the ROM like “OK” or “ERROR” and in the same time want to echo the coming characters from the port – then the things become more complicated.

The fixed messages have this advantage that they are very compact and very easy to exchange between tasks – you just point the address of the beginning of the message and then the task that receives the message reads the whole string from the ROM, until meets 0x00 code for end of the string. In this case the “receive” task just takes the address of one string in ROM or RAM and alone picks character by character the whole message. Advantages – the communication between tasks is minimal, that means – less resources of SALVO will be used and for less time. The result is higher performance of such system, compared with system, where every character is sent in message queue like binary data.

In my example with sending both fixed messages (from ROM) and the echo of the coming data (that should be kept in the RAM), there is a need to point RAM messages too. And immediately the problem of protecting them from reuse appears. One solution is to use message queue and 2 or more buffers in RAM and to put my strings there. But even in this case there is potential problem to change the RAM contents before it’s used – imagine that the queue is filled and I try to put new data. First I write data in the buffer, then I try to signal the message queue with loading the address of the data in the pointer. If the queue is filled I can wait, until it becomes free, but in all cases the data is already corrupted – because first I write the data and then I signal it.

There are two ways to solve this problem.

1. In the manual you wrote that the pointer in message and message queue points to data , array or some structure. That means, [italic]before signaling the message or the message queue you assume that the data is already at this place[/italic]. From other side OSSignalXYZ() doesn’t return the control to the SALVO kernel, [bold]so the first way to prevent the corrupting the data is first to signal the message or message queue and only if this is made successfully – to put the real data in the RAM cells.[/bold] It’s a little different from the basic idea, described in the manual – where you assume that data already is in the RAM, in the place. Because you don’t bring the control to any other task that could receive the event – there is no matter when you put the data – before or after signaling the message. So, my recommendation is to add somewhere in the manual that message and message queues point to some data in the memory and it’s up to you when you will make it actual – in all cases it should be made before you return the control to the kernel with OS_Yield(), OS_Delay(), OS_Stop() or OS_WaitXYZ().
So, the first method uses just simple exchange of the time when you put the actual data – you should write it only after you signaled the message successfully. Using this way of signaling messages you can send both ROM fixed strings and RAM reside strings with simple message or message queue. And you have not to worry about any reuse of the RAM cells.

2. Second method is fully compatible with everything described in the manual – you first check if the message is free or if the queue is not filled (unfortunately in SALVO2.1 manual is no description about how to check if message queue is filled or message empty “on fly” – it’s described in the forum). Then you put actual data and signal it without problems.


In both cases you should take care of the ISR if you signal events from ISR and from base level. And if the message is not free you should return the control to the kernel, so other tasks could finish some job too.

I think that messages and message queues in SALVO are one excellent structure. Maybe this topic explains how you can send with simple messages both ROM resident and RAM resident strings, avoiding problem of corrupting data when message is filled and you try to signal it again.

Regards
Luben

luben
 
Posts: 324
Joined: Sun Nov 19, 2000 12:00 am
Location: Sofia, Bulgaria

Re: Possible problem when signaling MESSAGES in RAM

Postby aek » Thu May 10, 2001 4:46 am

Here's how I would look at your problem:

1) Since there's no way to know how long it will take for the receiving ("waiting") task to get the message, assume that it could be a very, very long time. You must write your code to handle this situation.

This leads to ... 2) Some means of handshaking between the sending ("signaling") entity (task, ISR or mainline code) and the receiving task is required.

Assuming you've dedicated some RAM for a message that will be passed exclusively to the receiving task, what you want (if I understand you correctly) is to be able to be sure that a particular message that you signal successfully will indeed reach the intended recipient, AND you'll have some means of preventing the sending task from overwriting the message before the receiving task gets it.

Well, one solution would be to use a form of inter-task communication to control access to a shared resource, i.e. the RAM where you put the messages.

For example, you could set a flag to 1 initially, indicating that the RAM is available. Your code would then look like this:

Sending task:

code:
if ( flag ) {
flag = 0;
OSSignalMsg();
}
else
/* unable to signal new message because */
/* old message not yet been received. */
}

Receiving task:

code:
...
OSWaitMsg();
flag = 1;
...

You can see that this can be extended to handle the messages in ROM (don't care what the flag status is). The above example uses the flag as a semaphore -- you could actually use OSWaitBinSem() and OSWaitBinSem() if you wanted, though that presupposes that messages are sent from a task.

This scheme can be extended quite easily ...

[This message has been edited by aek (edited May 10, 2001).]

-------
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 1 guest

cron