Skip to content

Conversation

@fjarri
Copy link

@fjarri fjarri commented Dec 9, 2025

Fixes #3369 by exposing autojump and autojump_threshold as methods of abc.Clock. runner.clock_autojump_threshold is removed, and the runner now gets it from clock.

TODO: adjust documentation (autoump_threshold description can be moved from MockClock to abc.Clock)

Note that MockClock still has some internal trickery related to guest mode, but it is only necessary if you want to modify autojump_threshold while the loop is running. I am not sure how to resolve that at the moment, but I'll think about it.

@codecov
Copy link

codecov bot commented Dec 9, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.99484%. Comparing base (c0fa9bc) to head (76524e5).
⚠️ Report is 1 commits behind head on main.

❌ Your project check has failed because the head coverage (99.99484%) is below the target coverage (100.00000%). You can increase the head coverage or adjust the target coverage.

Additional details and impacted files
@@                 Coverage Diff                  @@
##                 main       #3371         +/-   ##
====================================================
- Coverage   100.00000%   99.99484%   -0.00517%     
====================================================
  Files             128         128                 
  Lines           19407       19398          -9     
  Branches         1318        1316          -2     
====================================================
- Hits            19407       19397         -10     
- Partials            0           1          +1     
Files with missing lines Coverage Δ
src/trio/_abc.py 100.00000% <100.00000%> (ø)
src/trio/_core/_mock_clock.py 100.00000% <100.00000%> (ø)
src/trio/_core/_run.py 99.90494% <100.00000%> (-0.09507%) ⬇️
src/trio/_core/_tests/test_mock_clock.py 100.00000% <100.00000%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@fjarri fjarri force-pushed the abc-clock branch 2 times, most recently from a666494 to 25289f1 Compare December 10, 2025 20:59
@fjarri
Copy link
Author

fjarri commented Dec 10, 2025

Following some discussion in #3369, the first commit now represents the minimum change - the new methods in the ABC have default implementations, so the PR is not breaking.

But the whole handling of the clock in the event loops feels a little weird to me. So I tried to re-imagine the logic in the second commit.

The idea is, we have real time (system time), and virtual time (clock time). These should not be mixed. The runner's statistics work with virtual times. In unrolled_run(), the return time of runner.deadlines.next_deadline(), or the timeouts in runner.waiting_for_idle are all virtual times. But when we call events = yield timeout, this is real time - we will actually sleep for the requested time.

Thus the responsibility of the clock is to keep virtual time, and to convert it to real time when necessary. When we yield, some real time may pass (possibly less than requested), so we need to tell the clock that. Obviously, SystemClock will already know it via the side effect, so it can just ignore it, but MockClock needs to know. The abstract API of a clock is then:

  • current_time() (naturally)
  • deadline_to_sleep_time(timeout: float) -> float (probably to be renamed) - given the virtual timeout, returns the real time to sleep
  • propagate(real_time_passed: float, virtual_timeout: float) - a new method, telling the clock that we slept for some real time derived from virtual_timeout, and the clock needs to be updated accordingly.

The second argument in propagate is really only needed to handle MockClock with rate = 0, whose logic I still don't completely understand. The docs say that "the clock only advances through manual calls to jump", and it's true technically, but an important detail is that the runner makes these calls too. The question is, if the autojump threshold is 2 seconds, and we sleep for 1 second, should the clock advance? With the original logic it doesn't, but I think it should.

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.

sleep() hangs indefinitely when using a custom clock

1 participant