Starting on my first RTOS project and can't quite see the logic to the interprocess communications. The Zilog RTOS offers message queues, but if the queue is empty the reading process is suspended until something shows up in the queue. Well sorry, that isn't good because my process has multiple things it needs to monitor periodically. It can't get hung on just one message queue. I thought a message queue would work or have an option to work like a ring buffer but that does not seem to be the case. My concept is to have this process check several "queues" and then suspend for a safe amount of time before looping back to check them again. Any sage advice appreciated. Thanks.
I'd think there'd be a way to sleep on lots of queues at once, or use interrupts. This is very common stuff. In unix world there is select() and poll(). Keep studying the manual for the OS, it's got to have this stuff.
David Ashley http://www.xdr.com/dash
Embedded linux, device drivers, system architecture
Queues are there for processes that only have reason to run if there's something in the queue to be processed.
If you just want a FIFO but have no plans to block on it then don't use the OS queue -- the OS queue adds significant overhead for just the behavior that you're decrying.
I would use the word "monitoring" if I'm only interested in the current value of something -- if this is the case then don't use a queue at all
-- just stuff your values (atomically, please) into registers, wake up periodically, and read them.
On the other hand, if you have one RTOS task that's performing multiple 'real' tasks -- break it up, and do it now!
One of the biggest software disasters I ever had the misfortune to work on featured a task that controlled two motors, with a single queue that sent messages about target positions. The task wouldn't service the queue until both motors were still, so you could pump messages in way faster than the task would take them off. A user could sit down in front of the system and flip a switch for a while until the queue overflowed. Once that happened the whole messaging system for the entire application got bent*, about half of the processes went into snits and stopped talking, and the thing would limp along until someone took pity on it and cycled power.
Had the task just woken up periodically and monitored target values for the motors (or -- gasp -- had there been _two tasks_) none of that would have happened.
The function RZKReceiveFromQueue() includes a wait time parameter.
Also, from the ZiLOG Real-Time Kernel v2.0.0 Reference Manual, page 15:
"You can choose not to block on message queues to receive or send message queue messages. When this option is chosen, a TIMEOUT error occurs if the message queue is empty while receiving, or full while sending messages."
And there is also the RZKPeekMessageQueue() function which might do for you.
If you were to block on each queue for one tick, wouldn't that be safe since you say "suspend for a safe amount of time before looping back to check them again"?
That is true. You have a good point. If I want to suspend for a period of time then I ought to be able to use the timeout on each queue set to half of that period. I just have not figured out this kooky RTOS stuff. The peek command copies the entire message out of the queue, which seems rather pointless. I just can't see the logic of not providing a non-blocking way to determine if there are one or more messages in the queue. I mean what is the point of that? Ring buffers worked fine for talking to ISR's. Why aren't they good enough for an RTOS?
Unless you're using a processor with a memory management unit they can't stop you from looking anywhere you want. If you build the application and link it as one, then you have global access to anything you make global (I'm assuming you're programming in C or assembly here).
Some RTOS manuals will write about interprocess communication as if it must always be synchronous, but this is not necessarily so.
Having said that, I should mention that if you _do_ choose to communicate via register, you should assume that it will change at any time, and adjust your expectations accordingly.
I'm looking at this thread, and I'm thinking that you need to go digging for a basic tutorial on using an RTOS. They're very handy things, but it sounds like you're misusing the features.
Here's my quick, dirty, and probably wrong summation:
Never write a task loop inside a task. Use one RTOS task per 'real' task.
Think about how things need to be synchronized, and why. 2a. A message handler should be event-driven, because there's nothing to do between messages. 2b. If an out-of-date message is useless, don't bother using a queue -- just write to a spot in memory ('register') and set a semaphore. 2c. Some things are inherently periodic, like motion control loops or video interrupt handlers. There's no point in using a queue here -- just set a semaphore from your timer interrupt (or use a periodic semaphore if your OS provides it).
Don't synchronize things that don't need to be. If your task polls X, and your task is guaranteed to repeat fast enough to catch X in the act of doing anything interesting, just read X inside your task and be happy.
Think about OS resources. OS messages queues can be very expensive in terms of processor time and memory, so if you know you're going to get a ton of messages each time your task has a chance to run don't use a message queue.
An example of this is serial handling -- for handling serial messages I'll have the ISR dump stuff into a ring buffer and set a semaphore. The (possibly low priority) task that services the ring buffer my not come on until there's 50 characters in the buffer, and it'll chew through all of them before going back to sleep.
Better yet, if I can the ISR will dump stuff into a ring buffer and only set a semaphore on a delimiter (end-of-packet, or carriage return if it's ASCII). This _really_ trims down the clock cycles.
And don't forget that the 'RT' in RTOS means "real time" -- make sure you make your deadlines!
I should mention that after my experience with the Worst Software Ever that I detailed in my other post I keep a string of garlic and a crucifix handy, and I wave them around whenever anyone mentions queues for anything other than strict message handling. So you can take my input as slightly biased...
When working with blocking queues, you should only have one receive queue for a single process.
Either split your process functionality into several processes, so that each process receives messages only from its single private queue.
Alternatively, keep all the functionality in the same process, but include a message-ID in each message sent to a single message queue, thus any message sent to this queue will activate the process and you can select the functionality according to the message-ID.
If the process also needs periodic wakeups, just send Clock-Tick messages from the interrupt service routine to the queues of each process needing scheduled wakeups.
I would question, in this case, if you weren't trying to do two things in one task, and therefore shouldn't split it up -- that doesn't mean you aren't doing the right thing, but it would seem that if it can't be handled properly with timeouts then you're really doing two independent things that should be split into two independent tasks.
On Fri, 25 Aug 2006 00:02:36 -0700, Tim Wescott wrote in comp.arch.embedded:
I don't actually think that's always called for here. Sometimes you need messages from multiple sources to accomplish one logical task.
I'm think of a manual motion task I wrote for a system.
It receives messages from a low level i/o task of user button presses and releases. When it decides to start a motion, it fires off a message to the motion control chain of tasks.
It eventually receives a message back from the motion control/validation chain indicating whether the motion was actually started or if not, what constraint kept it from starting.
If a manual motion starts, it eventually receives a motion complete notification message from the motion chain indicating the reason why the motion stopped, which could be end of travel reached, emergency stop button pressed, or a host of other issues.
This task also sets one-shot timers and so receives timer messages, because under some circumstances it starts a motion at a slow speed and then increases to a higher speed after several seconds if the button is still held.
And it receives commands that come through a communications interface from a higher level computer, to enable and disable certain user control buttons during certain system operations.
Given that RTOS tasks, message queues, and mutexes are all expensive, and given that all of these operations are related to the high level task of recognizing user button inputs and initiating manual motions, I don't see any way to do this more economically by splitting this task up. If it were split up, there would need to be a large amount of information shared between these tasks.
While many systems would work very nicely during normal operation without message queue timeouts or tick messages from the timer interrupt, you quite often have to detect missing messages or missing interrupt e.g. due to disconnected external cables etc. in order to activate some alarm output or switch to a redundant system etc.
Getting two clock tick messages (say once a second) from the message queue without getting even a single data message would be a clear indication that something is wrong.
The purpose of an RTOS is to guarantee that something can be handled on time. This means you have to be able to characterize the various tasks to ensure any postponement is not excessive. This allows you to handle the sort of thing where a signal means an incipient explosion, unless something is readjusted in time.
For many purposes an RTOS is not the appropriate solution, and you will often be better off with a normal system that simply provides time sharing, possibly with assigned priorities.
Some informative links:
And the typical answer to this problem is that the multiple sources put the messages onto a single queue. So the task in question doesn't have to monitor more than one queue, problem solved.
If the message sources can't use messages, then some other communication method has to be used. Semaphores, etc. A message on a queue doesn't have to contain any data; it can be enough just to wake up the task so that it looks at the places where there might be waiting data. But for efficiency, the task should always be sleeping when there isn't any work; even if it's polling it should sleep instead of busy waiting.
The purpose of an RTOS is to make things simpler, not harder. But the job of converting an existing "big loop" application into an OS based app can be frustrating, because they can involve two completely different ways of thinking about the problem.
Messages queues can be very efficient. I'm surprised some think they're not. They're no worse than a semaphore wrapped around a normal queue. Of course, I'm coming from a large system perspective, where context switching time is larger than queue manipulation time.
Yes, I think I need to reconsider my situation. I was brought in to help on a project where the wonderful RTOS was supposed to make everything easy. I don't know a thing about RTOS's and can't really tell if anyone else does. I'm supposed to do the menu and the other guys are doing the low level stuff, so the menu will be monitoring various events and reacting to them.