Mutex and thread priority

Hi, I have looked at mutex.c and thread.c and I've understood that a thread with higher priority (it has priority) will unlock the mutex even if thread with lower priority has not finished/unlock the mutex? Am I right? Now, in my case, I use UART with ethos (which use a mutex) and what happens on my case is: * I have thread A (high priority), thread B (low priority) * B starts to write on UART an long str * A wants to write on UART an lock the mutex (ethos) but because it has higher priority, it sends its message over UART until end of str * B can continue and finish to send its str

So I'm wondering why a thread with higher priority should be able to unlock a mutex locked by a thread with lower priorty?

Cheers

Hi Baptiste,

Hi, I have looked at mutex.c and thread.c and I've understood that a thread with higher priority (it has priority) will unlock the mutex even if thread with lower priority has not finished/unlock the mutex? Am I right?

You are referring to a situation in which a thread unlocks a mutex it did not lock before?

In that case the mutex is not behaving as such, but rather as a generic lock, and any thread can unlock it. See https://github.com/RIOT-OS/RIOT/issues/9594 .

If you want the mutex to actually behave as a mutex you should ensure you never have an unlock without a matching lock (i.e. that the only thread that can unlock a mutex is the one that locked it and thus own it). RIOT's mutexes do not enforce that, so you must resolve it by careful usage.

Now, in my case, I use UART with ethos (which use a mutex) and what happens on my case is: * I have thread A (high priority), thread B (low priority) * B starts to write on UART an long str * A wants to write on UART an lock the mutex (ethos) but because it has higher priority, it sends its message over UART until end of str * B can continue and finish to send its str

So you are saying that the lower priority "B" thread is being preempted and it's output interrupted by A's output?

I'm not familiar with ethos, but my intuition is that, while it may have a mutex, it may not be programmed in a way that the UART access is exclusive too. Exclusive access to UART would not be a good idea as in cases like yours it opens the door to priority inversions.

So I'm wondering why a thread with higher priority should be able to unlock a mutex locked by a thread with lower priorty?

Actually any thread can unlock a mutex locked by another thread. What can never happen is that a thread _locks_ a mutex locked by another thread. In your mind, replace the word "mutex" with "lock" and things may become clearer.

Regards,

Juan.

Thanks for your answer.

Hi Baptiste,

Hi, I have looked at mutex.c and thread.c and I’ve understood that a thread with higher priority (it has priority) will unlock the mutex even if thread with lower priority has not finished/unlock the mutex? Am I right?

You are referring to a situation in which a thread unlocks a mutex it did not lock before?

No. A thread A (high priority) locks a mutex which is locked by thread B (low priority) And it seems that scheduler stops thread B and make thread A run.

In that case the mutex is not behaving as such, but rather as a generic lock, and any thread can unlock it. See https://github.com/RIOT-OS/RIOT/issues/9594 .

If you want the mutex to actually behave as a mutex you should ensure you never have an unlock without a matching lock (i.e. that the only thread that can unlock a mutex is the one that locked it and thus own it). RIOT’s mutexes do not enforce that, so you must resolve it by careful usage.

Now, in my case, I use UART with ethos (which use a mutex) and what happens on my case is:

  • I have thread A (high priority), thread B (low priority)
  • B starts to write on UART an long str
  • A wants to write on UART an lock the mutex (ethos) but because it has higher priority, it sends its message over UART until end of str
  • B can continue and finish to send its str

So you are saying that the lower priority “B” thread is being preempted and it’s output interrupted by A’s output?

Yes exactly and this my problem. In my case, main thread with shell is being preempted by one of network stack threads

Let le explain again what I see: Context:

  • two threads: main thread (low prio) with shell and ipv6 thread (high prio) Sequence:
  1. Main thread starts to send a long str by UART via ethos (ethos_send_frame)
  2. Main thread locks ethos mutex in ethos_send_frame
  3. Ipv6 thread wants to send a str by UART, so ethos_send_frame is called and ipv6 thread tries to locks ethos mutex.

Result: What I see is that main thread str is cut by ipv6 thread. Str seen from UART reception: [START_STR_MAIN_THREAD][IPV6_THREAD_STR][END_STR_MAIN_THREAD]

  1. IMO, ipv6 thread preempts main thread and, I don’t really how, manages to access UART device and send its str before main thread can finish to send its str

Result is that main thread str is cut

Please have a look at ethos.c and especially ethos_send_frame() function to better understand what I say.

The behavior is only seen when ethos is used: Checkout my branch: https://github.com/biboc/RIOT/tree/uart_mutex_thread_pb And run example uart-thread-mutex_pb_BR on samr21-xpro (make flash BOARD=samr21-xpro)

See output: 2018-11-28 11:58:50.71 ~~33 `@0909]!UHCP@~~}!main(): This is RIOT! (Version: 2018.10-RC1-330-gd8cfe-uart_mutex_thread_pb) 2018-11-28 11:58:50.71 ~~}!RIOT border router example application 2018-11-28 11:58:50.72 ~~}!THREAD 2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+ 2018-11-28 11:58:50.74 ~~}!THREAD 2-|+2-|+2-|+2-|+THREAD 1_!*11_!*11_!*11_!*11_!*11_!*11_!*11_!*11_!*11_!*11_!*11_!*11_!*11_!*11_!*11_!*11_!*11_!*11_!*11_!*11_!*11_!*11_!*11_!*1 2018-11-28 11:58:50.75 ~~}!2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+ 2018-11-28 11:58:50.76 ~~}!THREAD 2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+2-|+

I’ve opened an Issue on github showing how to reproduce: https://github.com/RIOT-OS/RIOT/issues/10495