Skip to content
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

RFC: Add Atomic{Ptr} support and tests #33869

Closed
wants to merge 8 commits into from

Conversation

dillondaudert
Copy link

@dillondaudert dillondaudert commented Nov 16, 2019

This defines the following atomic operations on pointers via Atomic{Ptr}:

get_index(::Atomic{Ptr})
set_index!(::Atomic{Ptr}, ::Ptr)
atomic_cas!(::Atomic{Ptr}, ::Ptr, ::Ptr)
atomic_xchg!(::Atomic{Ptr}, ::Ptr)
atomic_max!(::Atomic{Ptr}, ::Ptr}
atomic_min!(::Atomic{Ptr}, ::Ptr}
atomic_add!(::Atomic{Ptr}, ::Integer)
atomic_sub!(::Atomic{Ptr}, ::Integer)

Fixes #29943, and possibly addresses #32455.

This still needs NEWS.

Copy link
Member

@NHDaly NHDaly left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is awesome. Thanks for doing this, Dillon! :) Looking forward to it!

This will probably also need NEWS as well, I would think, but you may want to wait for someone else to confirm that.

base/atomics.jl Outdated Show resolved Hide resolved
base/atomics.jl Outdated Show resolved Hide resolved
base/atomics.jl Show resolved Hide resolved
base/atomics.jl Show resolved Hide resolved
test/threads_exec.jl Show resolved Hide resolved
Copy link
Author

@dillondaudert dillondaudert left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I defined atomic_add!/sub!(::Atomic{Ptr}, ::Integer) separately since the signature is different enough (everything else follows the pattern (::Atomic{V}, V)).

@dillondaudert dillondaudert changed the title Add Atomic{Ptr} support and tests RFC: Add Atomic{Ptr} support and tests Nov 22, 2019
Copy link
Member

@NHDaly NHDaly left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:) Thanks for doing this Dillon, it looks good to me!
(Other than the annoying thing I just noticed about the "logical ops". i've left a comment.)

I think this would be ready for review from a maintainer.

base/atomics.jl Outdated Show resolved Hide resolved
base/atomics.jl Outdated Show resolved Hide resolved
base/atomics.jl Outdated Show resolved Hide resolved
@dillondaudert
Copy link
Author

I think this is ready for review. The build error looks unrelated.

@StefanKarpinski
Copy link
Member

@vtjnash, are you the right person to review this?

@dillondaudert
Copy link
Author

dillondaudert commented Dec 3, 2019

I can remove the logical ops defined on Atomic{Ptr}, per @NHDaly 's suggestion, if reviewers think that's appropriate.

@dillondaudert
Copy link
Author

I went ahead and excluded defining the logical operations on Atomic{Ptr}.

Copy link
Member

@NHDaly NHDaly left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, looks great!

@dillondaudert
Copy link
Author

Bump


# Note: atomic_cas! succeeded (i.e. it stored "new") if and only if the result is "cmp"
if typ <: Integer
@eval atomic_cas!(x::Atomic{$typ}, cmp::$typ, new::$typ) =
if typ <: Union{Integer, Ptr}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably be typ <: Integer || typ <: Ptr. Otherwise it includes the type Union{Integer, Ptr}.

@JeffBezanson
Copy link
Member

Welcome, @dillondaudert , and thanks for working on this. This looks basically correct, but I'm not sure what the use cases are. #29943 asks for it for implementing lock-free data structures, but I doubt it's actually useful for that since Ptrs are not tracked by the GC.

@dillondaudert
Copy link
Author

Could you elaborate your thoughts on why not being tracked by the GC makes atomic Ptr not useful for lock-free data structures? I admit I don't know all the subtleties and consequences around that.

I assumed since Ptr existed at all, it would be useful to have atomic operations for it. If that's not the case, should instead they be defined for Ref? I thought I read someone propose that in an issue at some point.

@ghost
Copy link

ghost commented Dec 18, 2019 via email

@oxinabox
Copy link
Contributor

But yeah, otherwise simple pointer assignment is of course already atomic.

No, it isn't.
I don't have a source handy but I found one for when @iamed2 made that claim. I can dig though LibPQ PRs and find it again tomorrow.
Pointer assignment is not atomic.
The CPU can act mid-word.


Yes, we likely also want this for Ref.
The TODO note in the source code only requested for Ptr.
Also seemed like that would be easier from working out what Todo with llvm.

@vtjnash
Copy link
Member

vtjnash commented Dec 19, 2019

But yeah, otherwise simple pointer assignment is of course already atomic.

It's unclear exactly what you intended to mean here. The simple assignment isn't "atomic" because that's not a property of the assignment but of the serializing side-effects that occur simultaneously (in the compiler and/or hardware). OTOH, it's pretty much unheard of for a processor do have a cache line smaller than a pointer word size, so the write of a pointer-sized word to an address with valid alignment is usually free of data races (torn writes). It's important to distinguish though that the Julia unsafe_load intrinsics though do not require alignment, and thus are NOT safe to use for threaded read/writes (the similar operation on a normal Julia object and array references should be fine).

I assumed since Ptr existed at all, it would be useful to have atomic operations for it

Yes, but maybe worth clarifying that's not what this PR does. It's been my goal for some time now to provide new Core.Intrinsics for doing atomic versions of each of the existing ops (e.g. fieldref, arrayref, pointerref, etc.) and then deprecate this file (it's inefficient and awkward). I'm happy to have others contribute towards the work to make it happen sooner, though I'd encourage anyone thinking of working in that direction to make a Julep first so we can review the design before they put a lot of effort into coding something.

@dillondaudert
Copy link
Author

I'd be happy to help get proper atomic (pointer) operations implemented in Julia. At this point, I don't believe I'm familiar enough with Core.Intrinsics (or the internals in general) well enough to make a design proposal. Since the changes in this PR aren't the right way to go about this, I'll close it.

@oxinabox
Copy link
Contributor

This remains an operation we should have though?

@NHDaly NHDaly self-assigned this Dec 20, 2021
@NHDaly NHDaly removed their assignment Dec 20, 2021
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.

Support Threads.Atomic{Ptr}
6 participants