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

add atomic operators for globals, memory, and setonce #52868

Merged
merged 2 commits into from
Feb 5, 2024

Conversation

vtjnash
Copy link
Sponsor Member

@vtjnash vtjnash commented Jan 12, 2024

This implements AtomicMemory, atomic operations for globals, and the class of atomic function for setting a field or global or memory exactly once (setting undef => value). It is quite similar to an @atomicreplace, but where there was not a previous value. This is not needed for pointers, since it is simply calling C_NULL => pointer in that case, since there is no "undef" value that throws after load.

plenty of future work still, for a later PR:

  • syntax lowering for @atomic global x = y and @atomic closedover = y
  • adding Core.AtomicBox for closure capture
  • generic functions for atomicsetindex & friends
  • macro for @atomic x = y and @atomic x[] = y, etc
  • design for @atomiconce f()

@vtjnash vtjnash added the domain:multithreading Base.Threads and related functionality label Jan 12, 2024
@vtjnash vtjnash requested a review from gbaraldi January 12, 2024 02:31
@vtjnash vtjnash force-pushed the jn/moreatomics branch 3 times, most recently from 4456be2 to cdd101e Compare January 27, 2024 00:34
@vtjnash vtjnash marked this pull request as ready for review January 27, 2024 00:34
@vtjnash
Copy link
Sponsor Member Author

vtjnash commented Jan 27, 2024

32-bit failing with

Error in testset atomics:
Test Failed at C:\buildkite-agent\builds\win2k22-amdci6-4\julialang\julia-master\julia-48bc10d274\share\julia\test\atomics.jl:76
  Expression: sizeof(mr) == length(mr) * sizeof(ar)
   Evaluated: 1600 == 1440

but everything else looks ready for review

@@ -145,10 +151,9 @@ end

## Conversions ##

convert(::Type{T}, a::AbstractArray) where {T<:GenericMemory} = a isa T ? a : T(a)::T
convert(::Type{T}, a::AbstractArray) where {T<:Memory} = a isa T ? a : T(a)::T
Copy link
Member

Choose a reason for hiding this comment

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

should the second argument here be AbstracVector?

Copy link
Sponsor Member Author

Choose a reason for hiding this comment

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

apparently not?

julia> @which convert(Vector{Int}, [1 2; 3 4])
convert(::Type{T}, a::AbstractArray) where T<:Array
     @ Base array.jl:607

julia> convert(Vector{Int}, [1 2; 3 4])
ERROR: MethodError: no method matching Vector{Int64}(::Matrix{Int64})

@vtjnash
Copy link
Sponsor Member Author

vtjnash commented Jan 31, 2024

I will merge tomorrow, and take any post-merge feedback instead then, if not gotten to before then.

@topolarity
Copy link
Member

Do you have a list of all the new and deleted intrinsics/builtins?

It's a bit hard to glean from the diff, since you also did some (appreciated) clean-up on things.

@atomiconce :sequentially_consistent :monotonic a.b.x = value

Perform the conditional assignment of value atomically if it was previously
unset, returning the value `success::Bool`. Where `success` indicates whether
Copy link
Member

Choose a reason for hiding this comment

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

So one thing is that unset isn't the nomenclature we seem to usually use, we mostly seem to use defined/undefined

Copy link
Sponsor Member Author

Choose a reason for hiding this comment

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

I guess that should say the field was not set or the field was undef?

Copy link
Member

Choose a reason for hiding this comment

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

I think that might be a bit more inline to what we call it in other places?

Copy link
Sponsor Member Author

@vtjnash vtjnash Feb 4, 2024

Choose a reason for hiding this comment

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

We use unset at lot for this also (e.g. unsetindex), since we use undefined to mean isbits types that are not initialized, while this is not undef->defined but rather unset->set

@vtjnash
Copy link
Sponsor Member Author

vtjnash commented Feb 1, 2024

Here's the list of new functions, from the docs (though your comment made me realize I had missed adding the rest of the memoryref builtins there):

Core.modifyglobal!
Core.swapglobal!
Core.replaceglobal!
Core.setglobalonce!

Core.memoryrefswap!
Core.memoryrefmodify!
Core.memoryrefreplace!
Core.memoryrefsetonce!

Core.setfieldonce!

@@ -2281,6 +2282,21 @@ instruction, otherwise it'll use a loop.
"""
replacefield!

"""
setfieldonce!(value, name::Union{Int,Symbol}, desired,
[success_order::Symbol, [fail_order::Symbol=success_order]) -> success::Bool
Copy link
Sponsor Member

@vchuravy vchuravy Feb 1, 2024

Choose a reason for hiding this comment

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

What is the default success_order? (Same for the other docstrings here)

Copy link
Sponsor Member Author

Choose a reason for hiding this comment

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

The default is not to have a success_order (in some places, equivalent to :not_atomic, but not identical)

setfield!(value, name, desired, success_order)
end
return ok
"""
Copy link
Sponsor Member

Choose a reason for hiding this comment

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

Probably should also get a compat note?

Copy link
Sponsor Member Author

Choose a reason for hiding this comment

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

Hopefully I got all those versions right

Adds an AtomicMemory{T} type (GenericMemory{:atomic,T,Core.CPU}) for
doing element-wise atomic operations on an array (with a lock
per-element if required).

Adds the full complement of atomic operations for global variables.

Also add a *setonce set of functions for atomically setting a value, but
only if it is unset. The complementary operation (Atomic `_unsetindex!`
for AtomicMemory) is not yet provided.
@vtjnash vtjnash added the status:merge me PR is reviewed. Merge when all tests are passing label Feb 4, 2024
@IanButterworth IanButterworth merged commit 8db1294 into master Feb 5, 2024
8 checks passed
@IanButterworth IanButterworth deleted the jn/moreatomics branch February 5, 2024 00:51
@IanButterworth IanButterworth removed the status:merge me PR is reviewed. Merge when all tests are passing label Feb 5, 2024
aviatesk added a commit that referenced this pull request Feb 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
domain:multithreading Base.Threads and related functionality
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants