On race conditions when using k_thread_suspend and k_thread_resume


Erling Rennemo Jellum <erling.r.jellum@...>
 

Hi fellow Zephyr users.


I am trying to have a thread go to sleep until either:
A) A Counter alarm fires
B) Another ISR wants to asynchronously wake it up.

This could be implemented something like this:
```
static bool alarm_fired=false;
static bool other_irq=false;
// Alarm callback. Resume thread
static void alarm_callback(…) {
    alarm_fired=true;

    k_thread_resume(&my_thread);
}

// Another ISR callback. Resume thread
static void other_irq_callback(…) {

    other_irq=true;

    k_thread_resume(&my_thread);
}

// Go to sleep.
// This is called while interrupts are disabled
void thread_sleep() {
  // Set up alarm for wakeup
   counter_set_channel_alarm(…)

   // Enable interrupts
  irq_unlock();

  // Suspend until alarm or an interrupt
  k_thread_suspend(&my_thread);

  // Wakeup
}
```

The problem is this: If there is a pending interrupt when we execute the `thread_sleep` function. The moment I call `irq_unlock()` there will be a context-switch and the ISR will be executed.

This means that `k_thread_resume` will be called by the ISR and then `k_thread_suspend` will be called. Thus putting the thread to sleep and not dealing with the interrupt.

Any ideas for how to solve this problem with other Zephyr primitives?

Thanks,
Erling


Moń, Tomasz
 

On Mon, 2022-11-07 at 01:29 +0000, Erling Rennemo Jellum via
lists.zephyrproject.org wrote:
I am trying to have a thread go to sleep until either:
A) A Counter alarm fires
B) Another ISR wants to asynchronously wake it up.
Probably the easiest solution is to use semaphore with K_FOREVER take
timeout.

The problem is this: If there is a pending interrupt when we execute
the `thread_sleep` function. The moment I call `irq_unlock()` there
will be a context-switch and the ISR will be executed.
This means that `k_thread_resume` will be called by the ISR and then
`k_thread_suspend` will be called. Thus putting the thread to sleep
and not dealing with the interrupt.

Any ideas for how to solve this problem with other Zephyr primitives?
Declare a semaphore, e.g.
K_SEM_DEFINE(my_sem, 0, 1);

then instead of suspending the thread take it, i.e.
k_sem_take(&my_sem, K_FOREVER);

and instead of resuming thread, simply give the semaphore, i.e.
k_sem_give(&my_sem);


Note that for the above to work, the k_sem_take() must be called from
thread that is supposed to be suspended.


Best Regards,
Tomasz Moń | Senior Firmware Engineer
P +48 882 826 111 | Wrocław, Poland
nordicsemi.com | devzone.nordicsemi.com


Mitsis, Peter
 

Zephyr kernel events might be helpful in this case. A thread can wait on one or more events and reset/clear specific ones as well.

 

See the following link for more details.

 

  https://docs.zephyrproject.org/latest/kernel/services/synchronization/events.html

 

Peter Mitsis

 

From: users@... <users@...> On Behalf Of Erling Rennemo Jellum
Sent: Sunday, November 6, 2022 8:30 PM
To: users@...
Subject: [Zephyr-users] On race conditions when using k_thread_suspend and k_thread_resume

 

Hi fellow Zephyr users.


I am trying to have a thread go to sleep until either:
A) A Counter alarm fires
B) Another ISR wants to asynchronously wake it up.

This could be implemented something like this:
```
static bool alarm_fired=false;
static bool other_irq=false;
// Alarm callback. Resume thread
static void alarm_callback(…) {
    alarm_fired=true;

    k_thread_resume(&my_thread);
}

// Another ISR callback. Resume thread
static void other_irq_callback(…) {

    other_irq=true;

    k_thread_resume(&my_thread);
}

// Go to sleep.
// This is called while interrupts are disabled
void thread_sleep() {
  // Set up alarm for wakeup
   counter_set_channel_alarm(…)

   // Enable interrupts
  irq_unlock();

  // Suspend until alarm or an interrupt
  k_thread_suspend(&my_thread);

  // Wakeup
}
```

The problem is this: If there is a pending interrupt when we execute the `thread_sleep` function. The moment I call `irq_unlock()` there will be a context-switch and the ISR will be executed.

This means that `k_thread_resume` will be called by the ISR and then `k_thread_suspend` will be called. Thus putting the thread to sleep and not dealing with the interrupt.

Any ideas for how to solve this problem with other Zephyr primitives?

Thanks,
Erling