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

GPIO: prevent woken task interrupting GPIO handler #2838

Merged
merged 2 commits into from
Dec 19, 2024
Merged

Conversation

bugadani
Copy link
Contributor

@bugadani bugadani commented Dec 18, 2024

This PR fixes an issue when InterruptExecutor uses async GPIO operations, but the GPIO handler runs on a lower priority. The issue caused the interrupt executor to enter an infinite loop.

@bugadani bugadani added the skip-changelog No changelog modification needed label Dec 18, 2024
@bugadani bugadani marked this pull request as draft December 18, 2024 18:12
@bugadani bugadani marked this pull request as ready for review December 18, 2024 18:21
Comment on lines +933 to +937

crate::interrupt::free(|| {
asynch::PIN_WAKERS[pin_nr as usize].wake();
set_int_enable(pin_nr, Some(0), 0, false);
});
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you change your mind? This doesn't match the PR title.
I was expecting you to swap the order of waking and interrupt clearing.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, it depends how you look at it, the task is waken immediately, or effectively at the end of the interrupt-free section. I'm not sure that swapping the order would be correct.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The infinite loop is caused because the waker is woken before the interrupts are cleared right? Swapping the order seems correct to me in that case. "Don't wake up the task until the pin's interrupt has been completely serviced"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it might be safe enough, but I'm not confident enough.

@bugadani bugadani changed the title GPIO: Clear interrupt bit before allowing waker to wake a task GPIO: fix woken task interrupting GPIO handler Dec 18, 2024
@bugadani bugadani changed the title GPIO: fix woken task interrupting GPIO handler GPIO: prevent woken task interrupting GPIO handler Dec 18, 2024
set_int_enable(pin_nr, Some(0), 0, false);

crate::interrupt::free(|| {
asynch::PIN_WAKERS[pin_nr as usize].wake();
Copy link
Collaborator

@Dominaezzz Dominaezzz Dec 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's an interesting problem here. Suppose you have two higher priority tasks.

  • GPIO interrupt priority is lowest.
  • Task A priority is higher.
  • Task B priority is highest.

Task A & B are waiting for gpio events on separate pins. Say task A is waiting for GPIO2 and task B is waiting for GPIO3.

If both GPIO pin events trigger at the same time, task A is woken up first because it's listening to a low number GPIO pin, even though it has a lower priority than task B. Ideally task B should've been woken up first.

I suppose you can call this WAD but it's a bit strange.
Ideally all the wakers should be woken up before any task can resume but that might be asking too much.

EDIT: This problem existed before this PR of course, just thought I'd mention it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough, I guess. We can extend the interrupt-free context to improve this. But we can't solve it fully when the GPIO handler has a low priority: GPIO3 can be toggled at any time, even immediately after we have read the pin states, and then the same situation ends up happening.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The whole situation where the handler is below the executors is weird enough, and workaroundable enough for me to think it's not worth spending much time on.

Copy link
Collaborator

@Dominaezzz Dominaezzz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. This solves the immediate problem

Copy link
Contributor

@bjoernQ bjoernQ left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@bjoernQ bjoernQ added this pull request to the merge queue Dec 19, 2024
Merged via the queue into esp-rs:main with commit 9759896 Dec 19, 2024
28 checks passed
@bugadani bugadani deleted the gpio branch December 19, 2024 08:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
skip-changelog No changelog modification needed
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants