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

fix: Deadlocks in singlethreaded execution context #3860

Merged
merged 3 commits into from Apr 3, 2024

Conversation

WojciechMazur
Copy link
Contributor

@WojciechMazur WojciechMazur commented Apr 2, 2024

Fixes #3859
Based on work in #3853, kept as draft until deciding the new API for Native ExecutionContext

The only changes related to this fix are in the commit 516444b

@WojciechMazur WojciechMazur marked this pull request as ready for review April 3, 2024 12:08
@catap
Copy link
Contributor

catap commented Apr 3, 2024

So, no need for user to make their own interface after all :)


import scala.scalanative.annotation.alwaysinline
import scala.concurrent.duration.FiniteDuration

object Proxy {
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't this also be private[scala.scalanative]?
At least based on the description from #3863, I thought each project that wanted to use this would have to define their own Proxy

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Right, this one should be fixed, but I'll do it in follow up PR. It's actually more dangerous since it's defined in javalib which does not emit Bytecode

Comment on lines 575 to 576
val deadline = now + timeout.toNanos
Proxy.stealWork(timeout)
Copy link
Contributor

Choose a reason for hiding this comment

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

This probably won't really matter (it's not like the toNanos conversion will take 1ms, and that doSleep is not exactly precise...), but just in case, it might be worth to run the stealWork ASAP.

Suggested change
val deadline = now + timeout.toNanos
Proxy.stealWork(timeout)
Proxy.stealWork(timeout)
val deadline = now + timeout.toNanos


@alwaysinline
final def parkNanos(nanos: Long): Unit = if (nanos > 0) {
park(nanos, isAbsolute = false)
if (isMultithreadingEnabled) park(nanos, isAbsolute = false)
else NativeExecutionContext.queueInternal.stealWork(nanos.nanos)
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not sure if this works as expected, as stealWork(FiniteDuration) rounds down to the millisecond, so in a lot of situations this won't yield.

I guess this matches what's said on the javadoc, but I also see that the WindowsThread uses millis.max(1).toUInt... I don't know, maybe this is OK. 🤷

Copy link
Contributor

Choose a reason for hiding this comment

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

If we use JDK as reference implementation I’d like to point that small delay is a kind of edge case.

see: https://kirill.korins.ky/articles/sleeping-at-jvm-thread-for-a-very-short-period/ where I kept notes on that investigation

@catap
Copy link
Contributor

catap commented Apr 3, 2024

@WojciechMazur I have one bad news. This PR doesn't fix #3848

@WojciechMazur WojciechMazur merged commit 01d9752 into scala-native:main Apr 3, 2024
61 checks passed
@WojciechMazur WojciechMazur deleted the fix/3859 branch April 3, 2024 19:57
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.

Deadlock in future without multithreading
3 participants