Ensure atomicity in the Atomic module is respected by flambda#10035
Ensure atomicity in the Atomic module is respected by flambda#10035xavierleroy merged 2 commits intoocaml:trunkfrom
Conversation
|
The key point in your example is the claim that Flambda may optimize let new_val = x :: old_val in
if r.contents == old_val
then (r.contents <- new_val; true)
else falseinto if r.contents == old_val
then
(let new_val = x :: old_val in
r.contents <- new_val; true)
else falseThis is counter-intuitive, as in my intuition they are not equivalent (the allocation may result in OCaml callbacks running that can change the result of the Here again (as in #9998) the proposed solution is the use of
|
|
Yes, this is my understanding.
The problem is more general, see for instance https://github.com/search?p=1&q=org%3Ajanestreet+%28%2A+BEGIN+ATOMIC+%2A%29&type=Code or b84f7ee#diff-3281003824dbd4299b844117c245dab1aff4aa02452d0c534fd096d388105ad8R53-R66
I do not think we need to ask as much, which sounds like would invalidate many transformations (most of the times code will be atomic only accidentally).
As a heavy user of reasoning on polling locations (re. prototypes of safe resource management), this is something I am looking forward to. Discussing the details of such an annotation would heavily depend on details of the work on adding new polling locations for multicore, which is why I tried to make it out of scope of the current PR. But you are right that this PR is a very good example of why such an annotation is desired, for the reasons you give. |
3b77b20 to
d3cd9cc
Compare
gasche
left a comment
There was a problem hiding this comment.
This seems okay to me, even though I would prefer a more robust way to control program reasoning. Could you fill the Changes entry?
You placed this in the 4.12 section of the Changes. Merging this in the 4.12 release branch indeed sounds reasonable, as it fixes a potential issue (not observed yet) and is extremely safe. (It may hurt performance, but this is better than endangering correctness.)
Prevent inlining of some of the functions, otherwise Flambda can move unrelated allocations inside the critical sections, making them non-atomic. (cherry picked from commit 2109946)
|
Merged in trunk and in 4.12 (955a4b4). |
|
Thanks! |
This PR ensures that the Atomic module is really atomic when taking flambda into account. It might be considered as a bugfix for 4.12.
I explain in terms of
refbut it goes the same forAtomic.t. The code below is a stack thread-safe for systhread:But flambda considers that it can move allocations around, and that it is equivalent to:
This is no longer thread-safe because there can be a context-switch between the equality test and the assignation.
Code of this form is used in the standard library with the Atomic module.
Atomic.compare_and_setis defined as follows:However, flambda considers that it can inline this function and subsequently move surrounding code between the test and the assignation.
There is no testcase in this PR, because I did not manage to trigger the issue in actual code. But it was confirmed to me that this is something flambda is allowed to do.
A short-term solution is to forbid inlining atomic functions from the Atomic module, which is the strategy taken in this PR. In the longer term it would be nice to have a way to force flambda to respect the semantics of polling locations inside specific pieces of code with an annotation (this is beyond the scope of this PR, there will be opportunities to discuss it elsewhere).
(Thank you to @lthls for his explanations, who I ping again in case he is interested in reviewing this PR.)