@@ -461,14 +461,8 @@ julia> mutable struct Atomic{T}; @atomic x::T; end
461461julia> a = Atomic(1)
462462Atomic{Int64}(1)
463463
464- julia> @atomic :sequentially_consistent a.x = 2 # set field x of a, with sequential consistency
465- 2
466-
467464julia> @atomic a.x # fetch field x of a, with sequential consistency
468- 2
469-
470- julia> @atomic a.x += 1 # increment field x of a, with sequential consistency
471- 3
465+ 1
472466```
473467"""
474468macro atomic (ex)
@@ -483,47 +477,33 @@ macro atomic(order, ex)
483477end
484478function make_atomic (order, ex)
485479 @nospecialize
486- if ex isa Expr
487- if ex. head === :.
488- l, r = esc (ex. args[1 ]), esc (ex. args[2 ])
489- return :(getproperty ($ l, $ r, $ order))
490- elseif ex. head === :(= )
491- l, r = ex. args[1 ], ex. args[2 ]
492- if is_expr (l, :., 2 )
493- ll, lr = esc (l. args[1 ]), esc (l. args[2 ])
494- return :(setproperty! ($ ll, $ lr, $ r, $ order))
495- end
496- end
497- if length (ex. args) == 2
498- if ex. head === :(+= )
499- op = :+
500- elseif ex. head === :(-= )
501- op = :-
502- elseif @isdefined string
503- shead = string (ex. head)
504- if endswith (shead, ' =' )
505- op = Symbol (shead[1 : prevind (shead, end )])
506- end
507- end
508- if @isdefined (op)
509- l, r = ex. args[1 ], esc (ex. args[2 ])
510- is_expr (l, :.) || error (" @atomic modify expression missing field access" )
511- ll, lr, op = esc (l. args[1 ]), esc (l. args[2 ]), esc (op)
512- return :(modifyproperty! ($ ll, $ lr, $ op, $ r, $ order)[2 ])
513- end
514- end
480+ if isexpr (ex, :., 2 )
481+ l, r = esc (ex. args[1 ]), esc (ex. args[2 ])
482+ return :(getproperty ($ l, $ r, $ order))
515483 end
516484 error (" could not parse @atomic expression $ex " )
517485end
518486
519487
520488"""
521- @atomic! a.b.x max new()
522- @atomic! a.b.x + new()
523- @atomic! max(a.b.x, new())
524- @atomic! :acquire_release max(a.b.x, new())
525- @atomic! :acquire_release a.b.x + new()
526- @atomic! :acquire_release a.b.x max new()
489+ @atomic! a.b.x = new
490+ @atomic! a.b.x += addend
491+ @atomic! :acquire_release a.b.x = new
492+ @atomic! :acquire_release a.b.x += addend
493+
494+ Perform the store operation expressed on the right atomically and return the
495+ new value.
496+
497+ With `=`, this operation translates to a `setproperty!(a.b, :x, new)` call.
498+ With any operator also, this operation translates to a `modifyproperty!(a.b,
499+ :x, +, addend)[2]` call.
500+
501+ @atomic! a.b.x max arg2
502+ @atomic! a.b.x + arg2
503+ @atomic! max(a.b.x, arg2)
504+ @atomic! :acquire_release max(a.b.x, arg2)
505+ @atomic! :acquire_release a.b.x + arg2
506+ @atomic! :acquire_release a.b.x max arg2
527507
528508Perform the binary operation expressed on the right atomically. Store the
529509result into the field in the first argument and return the values `(old, new)`.
@@ -538,14 +518,20 @@ julia> mutable struct Atomic{T}; @atomic x::T; end
538518julia> a = Atomic(1)
539519Atomic{Int64}(1)
540520
521+ julia> @atomic! :sequentially_consistent a.x = 2 # set field x of a, with sequential consistency
522+ 2
523+
524+ julia> @atomic! a.x += 1 # increment field x of a, with sequential consistency
525+ 3
526+
541527julia> @atomic! a.x + 1 # increment field x of a, with sequential consistency
542- (1, 2 )
528+ (3, 4 )
543529
544530julia> @atomic a.x # fetch field x of a, with sequential consistency
545- 2
531+ 4
546532
547533julia> @atomic! max(a.x, 10) # change field x of a to the max value, with sequential consistency
548- (2 , 10)
534+ (4 , 10)
549535
550536julia> @atomic! a.x max 5 # again change field x of a to the max value, with sequential consistency
551537(10, 10)
@@ -567,8 +553,36 @@ macro atomic!(ex)
567553end
568554function make_atomic! (order, ex)
569555 @nospecialize
570- isexpr (ex, :call , 3 ) || error (" could not parse @atomic! modify expression $ex " )
571- return make_atomic! (order, ex. args[2 ], ex. args[1 ], ex. args[3 ])
556+ if ex isa Expr
557+ if isexpr (ex, :call , 3 )
558+ return make_atomic! (order, ex. args[2 ], ex. args[1 ], ex. args[3 ])
559+ elseif ex. head === :(= )
560+ l, r = ex. args[1 ], ex. args[2 ]
561+ if is_expr (l, :., 2 )
562+ ll, lr = esc (l. args[1 ]), esc (l. args[2 ])
563+ return :(setproperty! ($ ll, $ lr, $ r, $ order))
564+ end
565+ end
566+ if length (ex. args) == 2
567+ if ex. head === :(+= )
568+ op = :+
569+ elseif ex. head === :(-= )
570+ op = :-
571+ elseif @isdefined string
572+ shead = string (ex. head)
573+ if endswith (shead, ' =' )
574+ op = Symbol (shead[1 : prevind (shead, end )])
575+ end
576+ end
577+ if @isdefined (op)
578+ l, r = ex. args[1 ], esc (ex. args[2 ])
579+ is_expr (l, :.) || error (" @atomic modify expression missing field access" )
580+ ll, lr, op = esc (l. args[1 ]), esc (l. args[2 ]), esc (op)
581+ return :(modifyproperty! ($ ll, $ lr, $ op, $ r, $ order)[2 ])
582+ end
583+ end
584+ end
585+ error (" could not parse @atomic! modify expression $ex " )
572586end
573587function make_atomic! (order, a1, op, a2)
574588 @nospecialize
@@ -674,6 +688,6 @@ function make_atomic_replace!(success_order, fail_order, ex, old_new)
674688 return :(replaceproperty! ($ ll, $ lr, $ exp, $ rep, $ success_order, $ fail_order))
675689 else
676690 old_new = esc (old_new)
677- return :(local old_new = $ old_new :: Pair ; replaceproperty! ($ ll, $ lr, old_new[ 1 ], old_new[ 2 ] , $ success_order, $ fail_order))
691+ return :(replaceproperty! ($ ll, $ lr, $ old_new:: Pair... , $ success_order, $ fail_order))
678692 end
679693end
0 commit comments