Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@adamgfraser
Copy link
Contributor

Resolves #4457.

I think the issue in #4457 can be traced to a race condition in effectAsyncInterrupt, which is used in the implementation of Promise. Specifically, if effectAsyncInterrupt is interrupted before the asynchronous effect starts executing then no canceler will be run, but the state is not updated to ensure that the register function is not invoked. With this change the original test that joiners are properly removed passes.

Copying @jsfwa and @narma.

@adamgfraser adamgfraser requested review from iravid and jdegoes December 7, 2020 18:53
@jdegoes
Copy link
Member

jdegoes commented Dec 7, 2020

@adamgfraser I think one could argue this is ultimately a problem in the implementation of EffectAsync, such that the race is even possible. Essentially the logic we do "after" calling register must be carefully inspected because it cannot change any fiber state detail, or else if the callback is called concurrently, then we could have 2 running evaluateNow.

@adamgfraser
Copy link
Contributor Author

@jdegoes I'm not sure we have enough information in FiberContext to handle this particular issue. My understanding is that this issue happens in the following situation:

  1. On the main fiber we are interpreting EffectAsync and check for interruption in enterAsync. At that point we have not been interrupted so we continue and call register.
  2. Then another fiber interrupts the main fiber and the logic in onInterrupt in effectAsyncInterrupt begins executing. It checks the status of started and finds that started is still false so it doesn't execute any cancellation logic.
  3. Then within register we set started to true and do whatever logic is in the register, such as adding a joiner. At this point we have a leak because cancellation logic will no longer be run (since it already was run in (2) above).

It seems like we are already checking for interruption immediately before invoking register and we need interruption to proceed concurrently with the evaluation of register because we potentially need the cancelation logic to prevent register from continuing to do something. So I don't see this as an issue where we have multiple evaluations of evaluateNow causing inconsistent state but where we have already implemented our own interruption logic in effectAsyncInterrupt through the use of the AtomicBoolean and onInterrupt and have just done it in a faulty way.

@jsfwa
Copy link

jsfwa commented Dec 8, 2020

Do we really have guarantees that other instructions wont be affected by such race?
The first thing that comes to my mind is Fail of uninterruptible effect right after interruption, something like this:
image

  1. We have effect with mix of flatMap/uninterruptible/foldCause
  2. Main evaluationNow executes ZIO.Tags.InterruptStatus this line
    2.1 We call interrupt and before (2) set uninterruptible we change state and executes evaluateLater in kill0 this line
  3. (2) set uninterruptible and throws exeception
  4. (2) & (3) executes foldCause twice this line

Its sort of conspiracy theory and looks very flaky, but I dont see any barriers, that will protect us from described or similar situations

@narma
Copy link
Contributor

narma commented Dec 10, 2020

I'd like merge this PR and address further investigation to new issue, shall we?

@jdegoes jdegoes merged commit 2e2635b into zio:master Dec 14, 2020
@jdegoes
Copy link
Member

jdegoes commented Dec 14, 2020

We do have a guarantee that at most one thread will be inside evaluateNow, with one small exception: the async effect can invoke a callback before the last evaluteNow finishes. That logic needs to be inspected to ensure it does not alter any state (it was inspected at one point, of course).

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.

Promise.await not always interrupting properly

4 participants