8000 virtual_alarm: add unit test for quick alarm case and fix by jettr · Pull Request #3277 · tock/tock · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

virtual_alarm: add unit test for quick alarm case and fix #3277

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

Merged
merged 1 commit into from
Oct 18, 2022

Conversation

jettr
Copy link
Contributor
@jettr jettr commented Oct 7, 2022

Pull Request Overview

Ensure we test the case when there are multiple alarms that do not get fired on the first pass of checking, but they would have fired by the time we do the calculation to set the next arm time. In that scenario the next arm time is way in the future (rollover) and the alarms do not get called when they are supposed to.

@phil-levis provided final fix for issue.

Formatting

  • Ran make prepush.

@jettr
Copy link
Contributor Author
jettr commented Oct 11, 2022

FYI I updated the unit test to better reflect the scenario.

We need another alarm in the future to make the test more accurate since that it way really triggers/exposes the issue.

@phil-levis
Copy link
Contributor
phil-levis commented Oct 14, 2022

Can you explain the exact issue? The way that the virtualizer is currently implemented, this case should be handled by setting a low-level alarm in the very near future. I.e., suppose I have these three Alarms:

A: reference: 100, dt: 50
B: reference: 100, dt: 54
C: reference: 100, dt: 500

At time 150, the low-level alarm should fire. This should trigger alarm A. Suppose that, when the loop across the alarms examines B, the current time t=153, so B does not fire. However, by the time the loop completes it is now t=155. This means that B should have fired but didn't.

My understanding is that the statement starting here

let next = self
should handle this. After firing the alarms, the virtualizer scans across the alarms and finds the earliest one. It should find that B is the earliest and set an alarm for (100, 54). The underlying Alarm implementation should know that 100 is in the past, so 154 is in the past, so this means fire as soon as possible, e.g.:

fn set_alarm(&self, reference: Self::Ticks, dt: Self::Ticks) {

pub fn set_alarm(&self, reference: Ticks64, dt: Ticks64) {

But it sounds like this is not happening?

I see this approach (delays sometimes in alarms that are very close) as preferable to the potential of introducing an infinite loop. Delaying the alarms (to a subsequent interrupt) doesn't break concurrency in the system: the kernel will continue to handle interrupts, etc. In contrast, with this approach, if I repeatedly set an alarm with a tiny duration, I might enter an infinite loop.

But you're seeing this problem happen in practice, so I must be missing something? Perhaps that line of code at the end lf the alarm handler isn't quite right?

@phil-levis
Copy link
Contributor

But you're seeing this problem happen in practice, so I must be missing something? Perhaps that line of code at the end lf the alarm handler isn't quite right?

I think this is the problem.

        let next = self
            .virtual_alarms
            .iter()
            .filter(|cur| cur.armed.get())
            .min_by_key(|cur| cur.dt_reference.get().reference_plus_dt().wrapping_sub(now));

is incorrect. It should not be a simple wrapping_sub, as this fails in the above case. Instead, this needs to properly consider an expired alarm as earlier than any unexpired alarm.

phil-levis added a commit that referenced this pull request Oct 14, 2022
happens if a virtual alarm expires *after* the virtualizer
loops over it but *before* the virtualizer calculates the next alarm.
It is possible that there is an alarm that has not fired but is in the
past. The bug is that when calculating the next alarm, the virtualizer
performs a simple `wrapping_sub` of reference+dt to compare it with `now`.
This calculation will make alarm in the past appear to be in the far future.

Therefore, when calculating what the "next" alarm is, the code needs to
consider if an alarm is in the past (but has not fired). Such an alarm
should be one of the "newest" alarms, and so cause the virtualizer to
schedule a near-immediate alarm to fire and trigger it.

This PR also fixes a syntax error in the macro for a multi-alarm test.
@phil-levis
Copy link
Contributor
phil-levis commented Oct 14, 2022

@jettr Can you check whether this fixes the problem?

master...jettr_alarm_fix

Fix issue that occurs if a virtual alarm expires *after* the virtualizer
loops over it but *before* the virtualizer calculates the next alarm.
It is possible that there is an alarm that has not fired but is in the
past. The bug is that when calculating the next alarm, the virtualizer
performs a simple `wrapping_sub` of reference+dt to compare it with
`now`. This calculation will make alarm in the past appear to be in the
far future.

Therefore, when calculating what the "next" alarm is, the code needs to
consider if an alarm is in the past (but has not fired). Such an alarm
should be one of the "newest" alarms, and so cause the virtualizer to
schedule a near-immediate alarm to fire and trigger it.

Also add unit test for verify this is fixed and prevent future
regressions.

Change-Id: Ib9e95e0c2d8791b0eb544881b604ede79b6fdb51
@jettr
Copy link
Contributor Author
jettr commented Oct 17, 2022

Yes, the code above does fix the issue and pass the unit test. I forced pushed this PR with your fix and the unit test (which I also updated to be a little more clear).

@phil-levis-google
Copy link
Contributor

bors r+

@bors
Copy link
Contributor
bors bot commented Oct 18, 2022

🔒 Permission denied

Existing reviewers: click here to make phil-levis-google a reviewer

@phil-levis
< AE0F path d="M8 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3ZM1.5 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Zm13 0a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"> Copy link
Contributor

bors r+

@bors
Copy link
Contributor
bors bot commented Oct 18, 2022

@bors bors bot merged commit 4106219 into tock:master Oct 18, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants
0