#== Atomics available on all backends ========================================== #-- fetching a value atomically proto sub atomic-fetch($, *%) {*} multi sub atomic-fetch($source is rw) { nqp::atomicload($source) } proto sub prefix:<⚛>($, *%) {*} multi sub prefix:<⚛>($source is rw) { nqp::atomicload($source) } #-- assigning a value atomically proto sub atomic-assign($, $, *%) {*} multi sub atomic-assign($target is rw, \value) { nqp::atomicstore($target, value) } #-- atomic compare and swap proto sub cas(Mu $, Mu $, Mu $?, *%) {*} multi sub cas(Mu $target is rw, Mu \expected, Mu \value) { nqp::cas($target, expected, value) } multi sub cas(Mu $target is rw, &code) { my $current := nqp::atomicload($target); nqp::until( nqp::stmts( (my $updated := code($current)), (my $seen := nqp::cas($target, $current, $updated)), nqp::eqaddr($seen, $current) ), $current := $seen ); $updated } #== Native integer atomics only available on MoarVM ============================ #?if !jvm my native atomicint is repr('P6int') is Int is ctype('atomic') { } #-- fetching a native integer value atomically multi sub atomic-fetch(atomicint $source is rw) { nqp::atomicload_i($source) } multi sub prefix:<⚛>(atomicint $source is rw) { nqp::atomicload_i($source) } #-- assigning a native integer value atomically multi sub atomic-assign(atomicint $target is rw, int $value) { nqp::atomicstore_i($target, $value) } multi sub atomic-assign(atomicint $target is rw, Int:D $value) { nqp::atomicstore_i($target, $value) } multi sub atomic-assign(atomicint $target is rw, $value) { nqp::atomicstore_i($target, $value.Int) } proto sub infix:<⚛=>($, $, *%) {*} multi sub infix:<⚛=>($target is rw, \value) { nqp::atomicstore($target, value) } multi sub infix:<⚛=>(atomicint $target is rw, int $value) { nqp::atomicstore_i($target, $value) } multi sub infix:<⚛=>(atomicint $target is rw, Int:D $value) { nqp::atomicstore_i($target, $value) } multi sub infix:<⚛=>(atomicint $target is rw, $value) { nqp::atomicstore_i($target, $value.Int) } #-- atomically fetch native integer value and increment it proto sub atomic-fetch-inc($, *%) {*} multi sub atomic-fetch-inc(atomicint $target is rw --> atomicint) { nqp::atomicinc_i($target) } proto sub postfix:<⚛++>($, *%) {*} multi sub postfix:<⚛++>(atomicint $target is rw --> atomicint) { nqp::atomicinc_i($target) } #-- atomically increment native integer value and fetch it proto sub atomic-inc-fetch($, *%) {*} multi sub atomic-inc-fetch(atomicint $target is rw --> atomicint) { my atomicint $ = nqp::atomicinc_i($target) + 1 } proto sub prefix:<++⚛>($, *%) {*} multi sub prefix:<++⚛>(atomicint $target is rw --> atomicint) { my atomicint $ = nqp::atomicinc_i($target) + 1 } #-- atomically fetch native integer value and decrement it proto sub atomic-fetch-dec($, *%) {*} multi sub atomic-fetch-dec(atomicint $target is rw --> atomicint) { nqp::atomicdec_i($target) } proto sub postfix:<⚛-->($, *%) {*} multi sub postfix:<⚛-->(atomicint $target is rw --> atomicint) { nqp::atomicdec_i($target) } #-- atomically decrement native integer value and fetch it proto sub atomic-dec-fetch($, *%) {*} multi sub atomic-dec-fetch(atomicint $target is rw --> atomicint) { my atomicint $ = nqp::atomicdec_i($target) - 1 } proto sub prefix:<--⚛>($, *%) {*} multi sub prefix:<--⚛>(atomicint $target is rw --> atomicint) { my atomicint $ = nqp::atomicdec_i($target) - 1 } #-- atomically fetch native integer value and then add given value to it proto sub atomic-fetch-add($, $, *%) {*} multi sub atomic-fetch-add(atomicint $target is rw, int $add --> atomicint) { nqp::atomicadd_i($target, $add) } multi sub atomic-fetch-add(atomicint $target is rw, Int:D $add --> atomicint) { nqp::atomicadd_i($target, $add) } multi sub atomic-fetch-add(atomicint $target is rw, $add --> atomicint) { nqp::atomicadd_i($target, $add.Int) } #-- atomically add given native integer value to value and return that proto sub atomic-add-fetch($, $, *%) {*} multi sub atomic-add-fetch(atomicint $target is rw, int $add --> atomicint) { my atomicint $ = nqp::atomicadd_i($target, $add) + $add } multi sub atomic-add-fetch(atomicint $target is rw, Int:D $add --> atomicint) { my atomicint $ = nqp::atomicadd_i($target, $add) + $add } multi sub atomic-add-fetch(atomicint $target is rw, $add --> atomicint) { my int $add-int = $add.Int; my atomicint $ = nqp::atomicadd_i($target, $add-int) + $add-int } proto sub infix:<⚛+=>($, $, *%) {*} multi sub infix:<⚛+=>(atomicint $target is rw, int $add --> atomicint) { my atomicint $ = nqp::atomicadd_i($target, $add) + $add } multi sub infix:<⚛+=>(atomicint $target is rw, Int:D $add --> atomicint) { my atomicint $ = nqp::atomicadd_i($target, $add) + $add } multi sub infix:<⚛+=>(atomicint $target is rw, $add --> atomicint) { my int $add-int = $add.Int; my atomicint $ = nqp::atomicadd_i($target, $add-int) + $add-int } #-- atomically fetch native integer value and then subtract given value from it proto sub atomic-fetch-sub($, $, *%) {*} multi sub atomic-fetch-sub(atomicint $target is rw, int $add --> atomicint) { nqp::atomicadd_i($target, nqp::neg_i($add)) } multi sub atomic-fetch-sub(atomicint $target is rw, Int:D $add --> atomicint) { nqp::atomicadd_i($target, nqp::neg_i($add)) } multi sub atomic-fetch-sub(atomicint $target is rw, $add --> atomicint) { nqp::atomicadd_i($target, nqp::neg_i($add.Int)) } #-- atomically subtract given native integer value from value and return that proto sub atomic-sub-fetch($, $, *%) {*} multi sub atomic-sub-fetch(atomicint $target is rw, int $add --> atomicint) { my atomicint $ = nqp::atomicadd_i($target, nqp::neg_i($add)) - $add } multi sub atomic-sub-fetch(atomicint $target is rw, Int:D $add --> atomicint) { my atomicint $ = nqp::atomicadd_i($target, nqp::neg_i($add)) - $add } multi sub atomic-sub-fetch(atomicint $target is rw, $add --> atomicint) { my int $add-int = nqp::neg_i($add.Int); my atomicint $ = nqp::atomicadd_i($target, $add-int) + $add-int } proto sub infix:<⚛-=>($, $, *%) {*} multi sub infix:<⚛-=>(atomicint $target is rw, int $add --> atomicint) { my atomicint $ = nqp::atomicadd_i($target, nqp::neg_i($add)) - $add } multi sub infix:<⚛-=>(atomicint $target is rw, Int:D $add --> atomicint) { my atomicint $ = nqp::atomicadd_i($target, nqp::neg_i($add)) - $add } multi sub infix:<⚛-=>(atomicint $target is rw, $add --> atomicint) { my int $add-int = nqp::neg_i($add.Int); my atomicint $ = nqp::atomicadd_i($target, $add-int) + $add-int } my constant &infix:<⚛−=> := &infix:<⚛-=>; #-- provide full barrier semantics proto sub full-barrier(*%) {*} multi sub full-barrier(--> Nil) { nqp::barrierfull() } #-- atomic compare and swap a native integer multi sub cas(atomicint $target is rw, int $expected, int $value) { nqp::cas_i($target, $expected, $value) } multi sub cas(atomicint $target is rw, Int:D $expected, Int:D $value) { nqp::cas_i($target, $expected, $value) } multi sub cas(atomicint $target is rw, $expected, $value) { nqp::cas_i($target, $expected.Int, $value.Int) } multi sub cas(atomicint $target is rw, &code) { my int $current = nqp::atomicload_i($target); loop { my int $updated = code($current); my int $seen = nqp::cas_i($target, $current, $updated); return $updated if $seen == $current; $current = $seen; } } #?endif # vim: expandtab shiftwidth=4