Hi guys,
Just a quick one, can anyone confirm the behaviour of os_evt_get?
I'm wishing to share a buffer between two threads of different priority. When the thread of higher priority wishes to use the buffer, it sends a cease and desist event signal to the other thread.
I'm using Mutex locks but am concerned about the remote possibility of the cease and desist signal arriving in-between the lower priority thread waking up and locking the Mutex.
My thoughts were to lock the Mutex then re-check the event signaling, however the manual states:
"You can use the os_evt_get function to identify the event that caused the os_evt_wait_or function to complete."
Can I be sure that this function will always return the latest set of events, even if they've not yet been used to wake a thread?
Many thanks
I have no answer I'm afraid, but I am quite curious about the outcome because I'm also looking at the best ways of using the RTX management functions to protect access to buffers.
I think this may be one to contact Keil support about.
As you quoted, the description says "You can use the os_evt_get function to identify the event that caused the os_evt_wait_or function to complete." If that is to be taken literally, then that says to me that any bit that was set following an exit from os_evt_wait_or / os_evt_wait_and will not be included in the result of os_evt_get(). I would also assume that any pending flags, i.e. flags that become set while the task is running and not waiting, would cause an immediate return from the next os_evt_wait_or() / os_evt_wait_and(). But I don't know, so I'd be interested in confirmation. I'm assuming therefore that os_evt_get() provides you with a masked copy of the flags that was made immediately prior to return from os_evt_wait_xxx.
I think these functions are really specifically intended for the purpose of waking a task when another task decides it should do some work. For example, to implement a periodic wake-up. I'm not so sure if this mechanism is best used as a signal to guard access to a resource, because there is no function to poll the current states of the event flags; you only get to know which woke the thread from sleep. I don't know how your tasks are designed, but I'm assuming it's possible for your lower-priority task to execute occasionally to do work even at times when it shouldn't access the buffer. Therefore it would be possible for the higher priority task to have sent an event flag to say 'stop accessing the buffer' and the lower priority task presumably won't see this event again until it goes into wait state.
Could it be better to consider a combination of only mutex and semaphore? In fact, guarded with a mutex, could you use a simple 'shared' boolean?
The event function decides what flags that is waking up the thread at the moment it wakes up the thread - it doesn't care about other events that may happen.
But ignore the event. Just lock the mutex, do something, release. Then lock again, do something and relesae.
If the high-prio thread tries to get the mutex, it will have to wait until the low-prio thread releases the mutex. If it catches the mutex, then you can ignore the low-prio thread until the high-prio thread releases the mutex again.
So please explain again - why do you see a need to mix event and mutex to synchronizing the same thing?
A couple of observations here:
"I'm wishing to share a buffer between two threads of different priority. When the thread of higher priority wishes to use the buffer, it sends a cease and desist event signal to the other thread."
First, when the higher priority thread needs to run, the RTOS will switch it in (it is the HIGHER priority than the other task, therefore preemption will occur). So, by definition, the lower task will not be running (ie: in pending state) nor actively accessing the buffer in question when the higher task is running (it could be 'in process' of using it when it was preempted though).
"I'm using Mutex locks but am concerned about the remote possibility of the cease and desist signal arriving in-between the lower priority thread waking up and locking the Mutex."
Second, in this case a Mutex does more harm than good for the reasons you mentioned (ie: locking out higher priority task from accessing the buffer).
If these two tasks are sharing the buffer for read/write purposes (ie: one tasks reads while the other writes to the buffer) you could use a circular buffer with read(tail) and write(head)pointers. If both tasks have visibility to the pointers, then when they are equal there is no more data to read. If they are both reading/writing to the same buffer (ie common data as in a database type use) then tasks of equal priority might be the best route to go here. Since I don't know your actual design thats as far as I can go here.
If they are both reading/writing to the same [circular] buffer then tasks of equal priority might be the best route to go here. I think that "tasks of equal priority" will only very rarely be needed, especially if the low prt is fill and the high prt is drain.
Thanks for the response guys.
To clarify, I have a Send thread, Receive thread, a command decode thread and one (eventually more) low priority task thread.
The device itself communicates over multi-drop half-duplex EIA485 with a single master issuing commands. As many devices may need to be accessed at the same time, I took an approach that allowed some level of multiplexing, eliminating any form of unpredictable response delay.
Master issues short commands (segmenting them if necessary), whilst the slave must provide an immediate acknowledgement so that the master can move on to communicating with other slaves, however I'm also RAM limited.
So I have two small buffers, one for comms and one for the running task to prepare its response.
What takes place is once a new complete command is received, the buffer is swapped, exposing the new command to the task (and for the task to prepare its response in), meanwhile an ack response is prepared in parallel in the other buffer.
The concern was that I could have triggered a send response, whilst a higher priority receive came in before send had locked the buffers. Receive then fills the buffer with a few bytes, only for send to go ahead and swap them whilst the receive fifo was busy filling up again. Simple solution was to check that receive hadn't changed its mind since locking the buffers, hense the os_evt_get query. Certainly another approach would have been to use a mutex protected boolean between the two threads but I thought it would be nice to signal as the system was already in place.
Ultimately I moved the swapping of my buffers to a different thread that had higher priority than receive, eliminating the issue, but I could just as easily have not been in a position to do this and there are certainly other times I've thought that the ability to check event signals mid-flight would be handy.
So as Trevor says, it would certainly be nice to know and maybe have it clarified in the manual.
I don't see what information you want clarified.
The manual does say about os_evt_get() that:
You can use the os_evt_get function to identify the event that caused the os_evt_wait_or function to complete.
So the answer to your question
is no. The function will not return the latest set of events. It will return the event that woke up the thread. Any more events happening will (and must) be held back until next time you wait. Because you want to make sure that you don't accidentally lose events.
os_evt_wait_or() should be seen as an "dequeue" function, that "checks out" pending events.
The documentation for os_evt_wait_or() does say:
The event flag or flags that caused the os_evt_wait_or function to complete are cleared before the function returns. You can identify those event flags with os_evt_get function later.
If os_evt_get() could pick up extra flags, then they would not pass that "clear" stage. While os_evt_get() must return old events that has already been cleared by os_evt_wait_or().
So the way to poll for current event state is to call os_evt_wait_or() with zero timeout and see if you got a timeout or not.
Makes sense, hadn't occurred to me os_evt_wait_or() could be used with zero timeout.
FYI: Remember also that only 1 wait/delay RTOS routine can be used per task:
You cannot mix the wait method os_itv_wait and os_dly_wait (or any other delay wait method) in the same task."
http://www.keil.com/support/man/docs/rlarm/rlarm_os_dly_wait.htm
Although this statement does not specifically state os_evt_wait_or() it does have a generic disclaimer within the parenthesis (and os_evt_wait_or() DOES require some type of RTOS timer).
reading through this stuff I come to think of one REAL concern re comms: "You can NOT pause reading" In most cases you can pause sending. I have seen schemes that were guaranteed to allowpausing reading and all have failed
Erik
Thanks for the concern, but no problem, there's a hardware fifo of 16 bytes and receive has priority over send, the only task that's of a higher priority is triggered only when the fifo is empty and sleeps within O(1) time, which is considerably less than the time it takes to fill the FIFO.
Originally I was using DMA, which was so much simpler, however I had a need to detect parity bits and so had to avoid this ultimately :S
You can have multiple wait/delay routines in the task.
But os_itv_wait() consumes the only timing resource for the thread, disallowing any other delay methods for the task. But a task that doesn't use os_itv_set()/os_itv_wait() and have multiple os_dly_wait(), os_evt_wait_or(), ... without a problem. This is because os_dly_wait(), os_evt_wait_or(), ... only needs a timing resource during that specific function call. After call ends, the task-specific variables are available for reuse.
os_itv_set()/os_itv_wait() on the other hand makes permanent use of the task-specific delay variables, to make sure that the thread gets a wake up call again and again and again like a metronome. So when os_itv_wait() returns, the task variables are still used to keep track of when the task should wake up next time.