-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Fix data race between marking and sweeping #12934
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
62fd1af to
0ae2802
Compare
|
At the risk of sounding like a broken record :-), I would enjoy seeing more comments in the code to explain the subtle reasoning that is going on. Naive questions:
|
75ad442 to
af1519d
Compare
|
I added a justification comment and used the
No need, it already is: Lines 1038 to 1040 in a682d51
Plain reads from C without synchronization are a bug, this is one of them but there shouldn’t be many left. Header reads from OCaml are compiled to assembly in a way that should not cause problems. (They are intended to behave at the very least like relaxed loads, see #10995)
I changed to use I remark that our current mixed memory model guidelines are in fact not respected by bits of the runtime (e.g. GC marking) that predate it. Although it is probably a separate discussion, this makes me a bit unsatisfied about these guidelines, as:
For this reason I am tempted to defend that we should amend these guidelines and either: use |
|
I like when there is a way for the authors of the runtime to express their intent: "I know that all accessors of this location respect the C11 memory model" vs. "This is a mixed-model location where different reasoning applies". Currently we use volatile for compatibility reasons, and also to signal that we are in the second category. We could change to a different style, but I wish that it would still allow expressing this intent. Maybe we could have a macro or function for the second case that is defined in terms of relaxed (if we want)? But wouldn't using relaxed atomics there create incompatibility issues in practice when using the volatile macros? (Or maybe the second-case functions should take a volatile input and cast it into an atomic to perform a relaxed access? The worst of both worlds, happily.) |
gasche
left a comment
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.
I'm happy with the new change -- the code remains simple, and there is an explanatory comment about the subtle thing going on.
I approve to mark this, but of course I'm not competent to vet the memory model questions, so I think it would be helpful if for example @stedolan or @gadmm could say whether they agree that the code change goes in the right direction.
|
(If no one has time to comment then I'll just merge, because this is a not-incorrect change that silences an incorrect TSan alarm.) |
af1519d to
543b253
Compare
|
The advantage of expressing programmer intent is a good point. It looks to me like relaxed atomics present some tiny advantages (more guarantees to not break in a distant future on a new compiler that doesn’t behave like the existing ones wrt I have updated the changelog. |
543b253 to
60e1644
Compare
|
I included the changes from the very similar #12939 into this PR. |
I am not against asking for an expert opinion, of course, but I am curious: which part of the change are you did not convince you in terms of correctness? |
|
I am not worried about correctness, but rather about the fact that the code is or isn't "right": principled, justifiable, and thus easier to understand and evolve. @stedolan recommended relaxed atomics and we end up using volatile instead, my feeling is that this is "right" but I would prefer an approval from someone who actually understands the underlying questions. If no one is available, I'll fly blind and merge. |
|
I'm not nearly as kowledgeable as @stedolan on these matters, but the change to |
A sweeping thread is allowed to read a header while a marking concurrently writes to it: the marking thread can only make UNMARKED objects MARKED, both being treated identically by the sweeping code.
`verify_pool` is a function used to check the invariant that a major pool should contain no garbage after sweeping. It is obviously allowed to race with marking (which can only turn UNMARKED objects into MARKED or NOT_MARKABLE, but not into GARBAGE), we only need to mark the read as a relaxed atomic read.
The debug runtime should be exercised by the TSan CI as it can be more efficient at revealing some data races. Since the test `regression/pr9853/compaction_corner_case.ml` takes more than 30 minutes with the debug runtime, this commit also skips it when TSan is enabled.
60e1644 to
7bb5cae
Compare
|
I applied @damiendoligez's suggestion, and also took the occasion to fix the test |
|
The macOS job was cancelled without any error message. I don’t really know how to fix that 🤔 |
Fix data race between marking and sweeping (cherry picked from commit 33eae42)
|
@Octachron Should this be considered for cherry-picking into 5.2? |
|
I did, it's listed above ( 4b92d4a ), sorry for not being explicit about it. At this point in the freeze period I don't bother pinging @Octachron for every small bugfix. |
|
Oh, my bad, I missed the notification item. Thanks! |
|
I'm surprised that this change silences TSAN here. Surely what we actually want is a relaxed atomic read, and I don't think |
|
I understand your suprise, the subject relaxed atomic vs Line 129 in 22f3e56
Line 170 in 22f3e56
|
This fixes #12916. As reminded by @stedolan, a sweeping thread is allowed to read a header while a marking concurrently writes to it: the marking thread can only make UNMARKED objects MARKED, both being treated identically by the sweeping code. All it takes is therefore to mark the header read as a relaxed atomic load.