STM32L4xxx and RTOSv1/. Sending two signals from one ISR at the same time, to the same thread, results in abnormal behavior.

Using uVision v5.27.1.0 (RTOS 1) with STM32L4xxx. In an ISR two different signals are sent to the same thread like below:

.

.

osSignalSet(myTask, SIGNAL_1);

osSignalSet(myTask, SIGNAL_2);

.

 

In the waiting task myTask, the following code is executed:

for (;;) {

  osEvent evt = osSignalWait(0, osWaitForever);

  u32 signals = evt.value.signals;

.

.

The "signals " will NOT contain SIGNAL_2. Only SIGNAL_1. In other words, the waiting task will wake up on the first of the two signals, even though both of them were posted in the same ISR at the same time.

 I think it is a bug .

The work around would be, in general case, to add the following code to code above:

evt = osSignalWait(0, 0);

signals |= evt.value.signals;

 

Now both SIGNAL_1 and SIGNAL_2 are consumed, and are in the variable "signals " .

 

Cheers! 

Parents
  • Looking at the RTOS code the behavior you are describing does seem to be what will happen.

    The 1st signal gets processed in the PENDSV and it sees that the task is waiting on a signal.  The signal generated fully matches what is being waiting on (any signal) and it changes the task to READY instead of waiting on a signal AND sets the return value to the current signals set.

    On the 2nd signal, the PENDSV sees it and set the signal, but since the task is no longer "waiting" on a signal the return value is not updated.  The signal is not lost it is just not returned along with the first signal set.

    As a note, if you set 2 signals in a task in 2 separate set_signal calls you will also get the first signal returned from the 1st wait and the 2nd signal will come in a "future" wait.

    When first looking at your description it did seem like something might be missed, but it is not.  One of the reasons it was done the way it was done is so that no signal would ever be missed.

    All the os_wait() is waiting for is the criteria for what you are waiting on to be satisfied.  The signals returned will be the ones that contribute to that wait being satisfied at the point that it was satisfied.  This is why when you set the first signal, that is all you get in return from the wait.  The 2nd signal was not part of / contributing to the satisfying of the wait.

    IF you want make sure that you get both signals, you will need to make sure that they are both present when  you set the signal.  Do not make 2 separate calls to the Set.

    No indications that a signal has been set are lost in this implementation.   The behavior in the implementation is (very) appropriate and not a bug.

    The "work around" you have probably works fine, but the 1 thing that may not be obvious is that you don't actually know if both signals happened at the same time, all you know is that both have happen before your task has run again.  It could easily be that the IRQ was called and 1 of the signals was set and before your thread ran the next wait, the IRQ was called again setting the other signal. 

Reply
  • Looking at the RTOS code the behavior you are describing does seem to be what will happen.

    The 1st signal gets processed in the PENDSV and it sees that the task is waiting on a signal.  The signal generated fully matches what is being waiting on (any signal) and it changes the task to READY instead of waiting on a signal AND sets the return value to the current signals set.

    On the 2nd signal, the PENDSV sees it and set the signal, but since the task is no longer "waiting" on a signal the return value is not updated.  The signal is not lost it is just not returned along with the first signal set.

    As a note, if you set 2 signals in a task in 2 separate set_signal calls you will also get the first signal returned from the 1st wait and the 2nd signal will come in a "future" wait.

    When first looking at your description it did seem like something might be missed, but it is not.  One of the reasons it was done the way it was done is so that no signal would ever be missed.

    All the os_wait() is waiting for is the criteria for what you are waiting on to be satisfied.  The signals returned will be the ones that contribute to that wait being satisfied at the point that it was satisfied.  This is why when you set the first signal, that is all you get in return from the wait.  The 2nd signal was not part of / contributing to the satisfying of the wait.

    IF you want make sure that you get both signals, you will need to make sure that they are both present when  you set the signal.  Do not make 2 separate calls to the Set.

    No indications that a signal has been set are lost in this implementation.   The behavior in the implementation is (very) appropriate and not a bug.

    The "work around" you have probably works fine, but the 1 thing that may not be obvious is that you don't actually know if both signals happened at the same time, all you know is that both have happen before your task has run again.  It could easily be that the IRQ was called and 1 of the signals was set and before your thread ran the next wait, the IRQ was called again setting the other signal. 

Children
More questions in this forum