%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%
%% %CopyrightEnd%
%%
-module(atomics_SUITE).
-include_lib("common_test/include/ct.hrl").
-compile(export_all).
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
[signed, unsigned, bad, signed_limits, unsigned_limits].
signed(Config) when is_list(Config) ->
Size = 10,
Ref = atomics:new(Size,[]),
#{size:=Size, memory:=Memory} = atomics:info(Ref),
{_,true} = {Memory, Memory > Size*8},
{_,true} = {Memory, Memory < Size*max_atomic_sz() + 100},
[signed_do(Ref, Ix) || Ix <- lists:seq(1, Size)],
ok.
signed_do(Ref, Ix) ->
0 = atomics:get(Ref, Ix),
ok = atomics:put(Ref, Ix, 3),
ok = atomics:add(Ref, Ix, 14),
17 = atomics:get(Ref, Ix),
20 = atomics:add_get(Ref, Ix, 3),
-3 = atomics:add_get(Ref, Ix, -23),
17 = atomics:add_get(Ref, Ix, 20),
ok = atomics:sub(Ref, Ix, 4),
13 = atomics:get(Ref, Ix),
-7 = atomics:sub_get(Ref, Ix, 20),
3 = atomics:sub_get(Ref, Ix, -10),
3 = atomics:exchange(Ref, Ix, 666),
ok = atomics:compare_exchange(Ref, Ix, 666, 777),
777 = atomics:compare_exchange(Ref, Ix, 666, -666),
ok.
unsigned(Config) when is_list(Config) ->
Size = 10,
Ref = atomics:new(Size,[{signed, false}]),
#{size:=Size, memory:=Memory} = atomics:info(Ref),
true = Memory > Size*8,
true = Memory < Size*max_atomic_sz() + 100,
[unsigned_do(Ref, Ix) || Ix <- lists:seq(1, Size)],
ok.
unsigned_do(Ref, Ix) ->
0 = atomics:get(Ref, Ix),
ok = atomics:put(Ref, Ix, 3),
ok = atomics:add(Ref, Ix, 14),
17 = atomics:get(Ref, Ix),
20 = atomics:add_get(Ref, Ix, 3),
ok = atomics:sub(Ref, Ix, 7),
13 = atomics:get(Ref, Ix),
3 = atomics:sub_get(Ref, Ix, 10),
3 = atomics:exchange(Ref, Ix, 666),
ok = atomics:compare_exchange(Ref, Ix, 666, 777),
777 = atomics:compare_exchange(Ref, Ix, 666, 888),
ok.
bad(Config) when is_list(Config) ->
{'EXIT',{badarg,_}} = (catch atomics:new(0,[])),
{'EXIT',{badarg,_}} = (catch atomics:new(10,[bad])),
{'EXIT',{badarg,_}} = (catch atomics:new(10,[{signed,bad}])),
{'EXIT',{badarg,_}} = (catch atomics:new(10,[{signed,true}, bad])),
{'EXIT',{badarg,_}} = (catch atomics:new(10,[{signed,false} | bad])),
Ref = atomics:new(10,[]),
{'EXIT',{badarg,_}} = (catch atomics:get(1742, 7)),
{'EXIT',{badarg,_}} = (catch atomics:get(make_ref(), 7)),
{'EXIT',{badarg,_}} = (catch atomics:get(Ref, -1)),
{'EXIT',{badarg,_}} = (catch atomics:get(Ref, 0)),
{'EXIT',{badarg,_}} = (catch atomics:get(Ref, 11)),
{'EXIT',{badarg,_}} = (catch atomics:get(Ref, 7.0)),
ok.
signed_limits(Config) when is_list(Config) ->
Bits = 64,
Max = (1 bsl (Bits-1)) - 1,
Min = -(1 bsl (Bits-1)),
Ref = atomics:new(1,[{signed, true}]),
#{max:=Max, min:=Min} = atomics:info(Ref),
0 = atomics:get(Ref, 1),
ok = atomics:add(Ref, 1, Max),
Min = atomics:add_get(Ref, 1, 1),
Max = atomics:sub_get(Ref, 1, 1),
IncrMax = (Max bsl 1) bor 1,
ok = atomics:put(Ref, 1, 0),
ok = atomics:add(Ref, 1, IncrMax),
-1 = atomics:get(Ref, 1),
{'EXIT',{badarg,_}} = (catch atomics:add(Ref, 1, IncrMax+1)),
{'EXIT',{badarg,_}} = (catch atomics:add(Ref, 1, Min-1)),
ok.
unsigned_limits(Config) when is_list(Config) ->
Bits = 64,
Max = (1 bsl Bits) - 1,
Min = 0,
Ref = atomics:new(1,[{signed,false}]),
#{max:=Max, min:=Min} = atomics:info(Ref),
0 = atomics:get(Ref, 1),
ok = atomics:add(Ref, 1, Max),
Min = atomics:add_get(Ref, 1, 1),
Max = atomics:sub_get(Ref, 1, 1),
atomics:put(Ref, 1, Max),
io:format("Max=~p~n", [atomics:get(Ref, 1)]),
{'EXIT',{badarg,_}} = (catch atomics:add(Ref, 1, Max+1)),
IncrMin = -(1 bsl (Bits-1)),
ok = atomics:put(Ref, 1, -IncrMin),
ok = atomics:add(Ref, 1, IncrMin),
0 = atomics:get(Ref, 1),
{'EXIT',{badarg,_}} = (catch atomics:add(Ref, 1, IncrMin-1)),
ok.
max_atomic_sz() ->
case erlang:system_info({wordsize, external}) of
4 -> 16;
8 ->
EI = erlang:system_info(ethread_info),
case lists:keyfind("64-bit native atomics", 1, EI) of
{_, "no", _} -> 16;
_ -> 8
end
end.