Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

detachInterrupt() from within ISR (freeRTOS) runs into Mutex #1441

Closed
caveman99 opened this issue May 12, 2023 · 10 comments · Fixed by #1442
Closed

detachInterrupt() from within ISR (freeRTOS) runs into Mutex #1441

caveman99 opened this issue May 12, 2023 · 10 comments · Fixed by #1442
Labels
freertos FreeRTOS support waiting for feedback Requires response from original poster

Comments

@caveman99
Copy link

We are using Radiolib in Meshtastic. While porting the existing code (that runs fine on ESP32* an nRF52) to RP2040 we're running into a mutex deadlock when calling detachInterrupt through the Radiolib clearDio1Action() from a running ISR. This seems to be a similar issue as #878

There is more comments and a debug trace in meshtastic/firmware#2299

The calling code is as simple as

void INTERRUPT_ATTR RadioLibInterface::isrLevel0Common(PendingISR cause)
{
    instance->disableInterrupt(); // this calls lora.clearDio1Action()

    BaseType_t xHigherPriorityTaskWoken;
    instance->notifyFromISR(&xHigherPriorityTaskWoken, cause, true);

    /* Force a context switch if xHigherPriorityTaskWoken is now set to pdTRUE.
    The macro used to do this is dependent on the port and may be called
    portEND_SWITCHING_ISR. */
    YIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
@maxgerhardt
Copy link
Contributor

Hmm

extern "C" void detachInterrupt(pin_size_t pin) {
CoreMutex m(&_irqMutex);
if (!m) {
return;
}
noInterrupts();
_detachInterruptInternal(pin);
interrupts();
}

You think the right path here would to check if we're inside an interrupt when detachInterrupt() is called and then not take the mutex?

@caveman99
Copy link
Author

a speculative fix i came up with was adding portCHECK_IF_IN_ISR() to the CoreMutex.cpp so it would call __freertos_mutex_take_from_isr(m); instead of the vanilla version. I am not sure just skipping the mutex at all is safe.

Problem with that approach is, i don't know how the include system in the framework is supposed to work, so i shoehorned relative path includes to FreeRTOSConfig.h and portmacro.h to the CoreMutex.cpp file, and i am positive that's not how it's supposed to work :-)

@earlephilhower earlephilhower added the freertos FreeRTOS support label May 12, 2023
@earlephilhower
Copy link
Owner

@caveman99 your suggestion sounds good. Do you have a PR you'd like to throw out there?

The mutex can't be skipped because the underlying call uses a 32b bitmask which is a 3-cycle read/modify/write operation. So you can't safely clear or set a bit w/o it. Removing the mutex would require turning the 4-byte value into an array of 32 ints taking 128 bytes.

@earlephilhower earlephilhower added the waiting for feedback Requires response from original poster label May 12, 2023
earlephilhower added a commit that referenced this issue May 12, 2023
Automatically check, when in FreeRTOS, if we're in an ISR and
if so call the correct mutex grab.

Thanks to @caveman99 for finding and proposing a solution!

Fixes #1441
earlephilhower added a commit that referenced this issue May 12, 2023
Automatically check, when in FreeRTOS, if we're in an ISR and
if so call the correct mutex grab.

Thanks to @caveman99 for finding and proposing a solution!

Fixes #1441
@earlephilhower
Copy link
Owner

So I just read the 2nd part of your comment, @caveman99 . The FreeRTOS includes in the core are kind of obtuse since we don't use FreeRTOS and its in a library.

I've done a proposed change implementing what you said. Could you give #1442 a try and report back, or offer suggestions if it's not what you had done?

@caveman99
Copy link
Author

caveman99 commented May 13, 2023

Thanks, that was exactly what i had in mind. I will test asap, was tied up today...

@earlephilhower
Copy link
Owner

If you pulled #1442 earlier, please re-pull the PR and try again. I forgot to handle the mutex_give_from_isr() portion in the destructor. That's been cleaned up, along with the manual special case I did for GPIO IRQ handling (taken care of by the real API am-i-in-isr call).

earlephilhower added a commit that referenced this issue May 15, 2023
Tested using Multicode-FreeRTOS, #1402 and #1441

The USB FIFO interrupts were still being serviced even when the core was
frozen, leading to crashes.  Explicitly shut off IRQs on both the victim
and the initiator core when freezing.

Removed the need for hack __holdUpPendSV flag
earlephilhower added a commit that referenced this issue May 16, 2023
Fixes #1439

Use a real FreeRTOS task, at the highest priority, to idle the other core
while doing flash accesses.

The USB stack seems to have some timing dependent bits which get broken
if FreeRTOS switches out the current task when it's running.  Avoid any
issue by disabling preemption on the core for all tud_task calls.

The PendSV handler disable flag can live completely inside the FreeRTOS
variant port, so remove any reference to it in the main core.

Tested using Multicode-FreeRTOS, #1402 and #1441

The USB FIFO interrupts were still being serviced even when the core was
frozen, leading to crashes.  Explicitly shut off IRQs on both the victim
and the initiator core when freezing.

Removed the need for hack __holdUpPendSV flag
@earlephilhower
Copy link
Owner

Ping @caveman99 . Any update?

@caveman99
Copy link
Author

i'm sorry, i have a surprise workload this week. will get to this asap monday or tuesday.

earlephilhower added a commit that referenced this issue May 23, 2023
* Fix FreeRTOS CoreMutex shim to handle ISRs

Automatically check, when in FreeRTOS, if we're in an ISR and
if so call the correct mutex grab.

Thanks to @caveman99 for finding and proposing a solution!

Fixes #1441

* Fix the CoreMutex destructor, too
@GUVWAF
Copy link
Contributor

GUVWAF commented May 23, 2023

I see that you merged the PR already, but I wanted to let you know that I just tested the Meshtastic firmware with this and it doesn't run into a deadlock upon receiving anymore. Thank you very much for the quick implementation! Looks like Meshtastic has another supported board :)

@earlephilhower
Copy link
Owner

Awesome, thanks for the feedback! Normally I'd wait for feedback, but the problem and solution were pretty obvious here so I' figured I'd take a shot to get out a new release this week.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
freertos FreeRTOS support waiting for feedback Requires response from original poster
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants