-
Notifications
You must be signed in to change notification settings - Fork 24
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
Race condition in waitForProcess
#38
Comments
I tried reproducing this problem with
|
This is pretty easy to turn into a failing test. I wouldn't mind making a PR for that if it would help! |
I'm not sure it's relevant to this test case failing, but the approach you're taking here is, generally, broken. You cannot write to Reproducing case would be appreciated. I'll see if something jumps out at me in the code. |
Also, it makes sense you can't reproduce with that |
Strangely enough, making this seemingly innocuous change seems to fix the problem on my system, can you confirm? @@ -768,6 +768,7 @@ startProcess pConfig'@ProcessConfig {..} = liftIO $ do
-- then call waitForProcess ourselves
Left _ -> do
eres <- try $ P.terminateProcess pHandle
+ P.getProcessExitCode pHandle
ec <-
case eres of
Left e My theory: there's a subtle race condition in |
The bug is definitely in Issue: we want In our case, the polling thread in typed-process is calling I'm open to suggestions on best behavior here, but this is probably just going to remain a bug in some case no matter what, with some potential workarounds in place for common situations. The right solution is for |
OH, good point! I hope this isn't an issue in this simple case. I just needed some example of interacting with an external process so I figured
Wait what? I just had another look at the source and
Yes that seems to match my intuition as well.
Ah shoot, that's what I was afraid of. To be quite honest, I'm not convinced that I fully grasp what's going on here, but I definitely expected my example to "just work" or at least not crash. (I'm using a fancy Whatever we do to solve this issue, could we please make sure to have a regression test for this behaviour if we decide that this (P.S. I still don't understand why my |
Side note: This
need not work. As far as I can tell, You need Also nice repro! |
I'm not sure I fully understand the problem, but would this idea work? When running a process, immediately do an internal |
See my comment above In our case, the polling thread in typed-process is calling waitForProcess and gets canceled. It has to be canceled to avoid a separate race condition: terminateProcess getting called on the wrong process! However, because waitForProcess isn't actually async-exception-safe, none of this works. |
This is the same as #69. What's happening here @NorfairKing with your original example is that:
Or in other words: The bug is not that you get an exception in the first place, the bug is that you get the wrong exception. A minimal reproducing example is at: #69 (comment) Exactly how we mess up in |
@snoyberg we essentially have the following code (ignoring the fallback code for the single-threaded runtime): ec <- unmask $ do
P.waitForProcess pHandle
-- Do we have any guarantee that we are not interrupted right here?
atomically $ putTMVar pExitCode ec Do we have anything that guarantees us that we are not interrupted right after |
Actually no, if So, as I understand it, we have two issues:
For (1) is there an important reason that we have to interrupt Otherwise, how about simply not to interrupt
For (2), we could change the type of
|
I'm not sure if this is supposed to go here or in
process
, but this code fails about 1 iteration in 200:I couldn't reproduce the failure without the interaction with the standard streams, so I may very well be doing something wrong, but every 200 iterations or so I see this:
The text was updated successfully, but these errors were encountered: