-
Notifications
You must be signed in to change notification settings - Fork 21
Add threadStatus
to IOSim and IOSimPOR
#19
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
Conversation
8a2ef39
to
e8b0ed3
Compare
@coot do you perhaps have time to review this? |
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.
@MaximilianAlgehed thanks that looks good. I see one problem with this implementation: it does not work well with our implementation of MVar
's which is based on TVar
's. When a thread is blocked on an MVar
we will thus report ThreadBlocked BlockedOnSTM
. But it shouldn't be difficult to distinguished MVar
s and TVar
s. We's need to add a boolean flag to TVar
: tvarIsMVar :: Bool
. The problem to solve is how to update it when we create an MVar
in newEmptyMVarDefault
. The simplest way would be to move that function to io-sim
, where we have access to TVar
internals.
@coot do you think we should try to address the |
|
Issue mentioning |
@coot I think this should be about ready now. |
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.
This looks ok to me.
I have to say I was not aware of the semantics of threadStatus
. It looks like you believe that the difference between status died and finished is receiving an async exception.
The library docs merely say
ThreadFinished | the thread has finished
ThreadDied | the thread received an uncaught exception
without saying anything about async vs sync exceptions.
My own experiment is even less helpful, it suggests that ThreadDied
isn't used at all!
import GHC.Conc
import Control.Exception
main = do
--setUncaughtExceptionHandler throwIO
tid <- forkIO $ do
print "foo"
threadDelay 10000000 --10sec
print "bar"
print =<< threadStatus tid
throwTo tid (ErrorCall "oh noes")
threadDelay 1000000
print =<< threadStatus tid
and
ghc-8.10.7 ThreadStatus.hs
[1 of 1] Compiling Main ( ThreadStatus.hs, ThreadStatus.o )
Linking ThreadStatus ...
[duncan@dunky io-sim]$ ./ThreadStatus
ThreadRunning
ThreadStatus: oh noes
ThreadFinished
I thought it might be related to the default top-level exception handler for forkIO threads, but apparently not. If one uncomments the line setUncaughtExceptionHandler throwIO
then the final result is instead
$ ./ThreadStatus
ThreadRunning
ThreadRunning
I cannot get ghc to ever report ThreadDied
.
If we don't need to track async vs sync exceptions for the cause here, then it'd simplify the patch quite a bit. If it were just threads terminating with an exception (any, sync or async) vs terminating via return
then we'd not have to track so much in this patch.
@dcoutts did you check the tests? On my machine the tests pass - indicating that our hypothesis about the difference between synch and asynch exceptions is true at least some of the time. See specifically the tests |
And to be clear, we were very surprised by the semantics we observed! |
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.
LGTM
I don't see how to make CI run, there's no box which github docs mentions 😞. |
@dcoutts could you perhaps push the right buttons on this so we can get it merged? |
I asked similar question today. Could you rebase the branch on top of |
@MaximilianAlgehed I pushed PR #27 with your changes (rebased), unfortunately two tests failed:
|
@coot that's a bit worrying - they pass locally. Are the tests run in parallel in CI? That might affect scheduling (these tests are understandably a bit sensitive to scheduling). |
d8732c5
to
cc73e31
Compare
The problem is only on Windows, where I can reproduce it locally too. |
Since |
@coot That's fine with me. I'll make an issue that mentions this so I have something to come back to after the next spate of deadlines. |
@coot I've made an issue here #28 and it's weirder than I thought! I finally got the time to look carefully at this and as I say in the issue the behaviour on Windows is probably just plain wrong! We don't do any operations that should put the thread that we ask |
Thanks, I disabled the tests in the other PR. Once CI will finish I'll merge it. |
Merged via #27. |
@MaximilianAlgehed I'm still going to claim that the So yes I did try running your two tests
we would expect that this should make no difference to the semantics right? Yet it does:
Now both examples return This can also be seen in an even simpler standalone test:
with the result
This example makes it somewhat clearer what is going on: ghc seems to behave differently when sending an async exception if the thread has never yet run, vs when it has already started running. The example above of running the same thing twice relies on the vagaries of scheduling, whereas inserting an explicit So overall, it's not clear that (at least when the victim thread is already running) that ghc makes any distinction between async and sync exceptions. It's just that the async case lets one distinguish between victim threads that have not yet started running, and those that are already running, which for some reason ghc seems to report differently. So I'd argue that we should back out the complexities of the tracking of sync vs async exceptions for the purpose of thread status reporting, and just do a simpler impl of |
@dcoutts I agree with your assessment. However, I don't know when I can get to this but I will try to make it my top priority to clean this patch up next week. Does that sound reasonable? |
I've filed a GHC issue: https://gitlab.haskell.org/ghc/ghc/-/issues/22279 |
@dcoutts I created an issue to track this, let's close this PR as it's already merged via #27. |
This PR introduces an implementation of
threadStatus
forIOSim
. It's currently a bit fast and loose on the "blocked reason" for threads (e.g. readingMVar
s etc.) but should implement the rest of the functionality faithfully.This fixes #12.