-
Notifications
You must be signed in to change notification settings - Fork 535
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
Refactor WorkerThread
runloop; avoid pathological starvation of pollers
#4247
base: series/3.6.x
Are you sure you want to change the base?
Conversation
def lookForWork(): Unit = { | ||
var state = 0 | ||
while (!done.get()) { | ||
(state: @switch) match { | ||
case 0 => | ||
// Check the external queue after a failed dequeue from the local | ||
// queue (due to the local queue being empty). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, we could lift case 0
out of the loop. It's always guaranteed to run exactly once, and never again. The loop just transitions between cases 1 and 2.
I think the failures are legit 😕 something must be broken. |
Aha, all the CI failures are on JDK 21, and this is the test it's hanging on. cats-effect/tests/jvm/src/test/scala/cats/effect/IOPlatformSpecification.scala Lines 615 to 630 in fc5818d
Edit: but ... we are getting this weirdness, on the new test I added in this PR.
|
try { | ||
latch.await() // wait until next task is in external queue | ||
} catch { | ||
case _: InterruptedException => // ignore, runtime is shutting down |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The stray InterruptedException
is apparently fatal and was nuking all the runtimes, causing remaining tests to hang. We only noticed this on JDK 21 CI runners because the last test in the suite happens to be JDK 21+ only.
Haven't reviewed the code yet, but I ran some benchmarks to sanity check. Looks like a very slight regression (note the Before
After
|
Fixes #4228.
At a high level, a
WorkerThread
is always in one of the following three states:Previously, (3) was a separate
parkLoop()
, but (1) and (2) were entangled in the top-level runloop. Now, (2) is refactored into a separatelookForWork()
loop. Thus, the top-level runloop is only responsible for tracking "ticks", such that polling runs every 64 ticks.