ARM-software / CMSIS_5

CMSIS Version 5 Development Repository
http://arm-software.github.io/CMSIS_5/index.html
Apache License 2.0
1.33k stars 1.08k forks source link

Message priority ignored if message queue is empty #645

Open AutoMatz opened 5 years ago

AutoMatz commented 5 years ago

Hi guys,

I using RTX5 with CMSIS RTOS2. For the following scenario I wondered about the following behavior:

A low prio thread is blocked on a osMessageQueueGet, because the queue is empty. The thread is "waiting for ever" until a message is availible.

  1. A high prio (timer) thread sends a LOW priority message (e.g. #msg 0) to the message queue.
  2. Wenn the high prio thread has finised, another mid prio thread starts running and sends a MID priotiry message (#msg 1) to the message queue.
  3. For test I let send this thread an follwing HIGH priority message (#msg 2) to the message queue.

After the mid prio thread has finished, the OS starts the low prio thread. This low prio thread now gets and processes the messages. The messages from the queue are gotten in the following order:

msg 0 (low prio message)! ????

msg 2 (high prio message)

msg 1 (mid prio message) - as expected AFTER msg 2

I expected that the highest prio message should have been gotten first. But it does not!

And all further tests shows that - if the queue is empty - always the first sent message will be gotten first, even though messages with higher priority had been sent to the queue bevor getting the first message.

In between I learned (thanks Andreas Barth) that this is the defined behaviour:

"the thing is, that the Put function already checks, if a thread is pending on the Queue. And if there is one, the message gets 'delivered' already and the thread is put in ready state. Next messages put in the queue find no thread waiting on the queue, and so the messages are sorted and pending in the queue."

I dont understand in which case this could be a meaningful definition. Do you have an example? In my opinion the highest prio message should have to be gotten first after the low prio receiver has started to run.

I'm looking forward to your responses.

JonatanAntoni commented 5 years ago

Hi @AutoMatz,

you gave the absolute correct answer already yourself, supported by Andreas. In this case its not purely a question of "meaningful" but of "performance".

In case the receiving thread is already waiting for a message, the message is directly copied to the receiver buffer. This way the message is effectively copied only once. The next two messages are copied into the message queue buffer by the sender. Later they are copied to the receivers buffer.

Actually, one could argue your situation is somehow a race which is not handled properly by our implementation. I am not sure if its possible to substitute the first message already in the receiver buffer with a higher priority one. And move the low prio message to the message queue buffer instead. I'll check with the dev team.

Cheers, Jonatan

JonatanAntoni commented 5 years ago

Hi @AutoMatz,

after initially discussing this issue with the dev team I need to revoke the "crazy" idea of "swapping already delivered messages".

Actually, the first message sent to a waiting thread is directly delivered to that thread, bypassing the message queue for performance reasons. The only solution would be removing this performance optimization and always push messages through the queue. This solution comes at cost of one additional copy for the (first) message.

Such a performance impact might be undesirable/unacceptable for existing user applications. Hence we need to further elaborate on a possible solution. Unfortunately we might not be able to solve this short term.

You could of course try to work around that issue by not letting the receiver thread block on the message queue. You could add a counting semaphore for thread synchronisation for instance, i.e. release a semaphore after putting a new message and use acquire to block the receiver thread.

I hope you can continue working with this intermediate solution.

Cheers, Jonatan

AutoMatz commented 5 years ago

Hi Jonatan.

First of all, thanks for your answer.

I had already worked out a very simple solution for my special case. It costs some perfomance, but this does not hurt me.

Because in my case the race condition only occures in a very special case, I was able to handle this special case. I did it like this: If a low prio message has to be posted, which might be passed by a higher prio message before the message-reveicer-thread is running, I first feet the message queue with a dummy message. After the receiving thread starts running, it first eats the dummy message and than processes the pending messages corresponding to their priority.

Yes, this cost some performace. But correct priority is more important for me in this case to handle the race condition properly.

I'm looking forward if and how you will revise this problem.

Best regards. Matthias.