Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions erts/emulator/test/atomics_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,15 @@
-module(atomics_SUITE).
-export([suite/0, all/0,
signed/1, unsigned/1, bad/1, signed_limits/1, unsigned_limits/1,
error_info/1]).
error_info/1, doctests/1]).

-include_lib("common_test/include/ct.hrl").

suite() -> [{ct_hooks,[ts_install_cth]}].

all() ->
[signed, unsigned, bad, signed_limits, unsigned_limits,
error_info].
error_info, doctests].

signed(Config) when is_list(Config) ->
Size = 10,
Expand Down Expand Up @@ -157,6 +157,9 @@ max_atomic_sz() ->
end
end.

doctests(_Config) ->
ct_doctest:module(atomics).

error_info(_Config) ->
Atomics = atomics:new(10, []),
Huge = 1 bsl 64,
Expand Down
7 changes: 5 additions & 2 deletions erts/emulator/test/counters_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@

-export([suite/0, all/0]).
-export([basic/1, bad/1, limits/1, indep/1, write_concurrency/1,
error_info/1]).
error_info/1, doctests/1]).

suite() -> [{ct_hooks,[ts_install_cth]}].

all() ->
[basic, bad, limits, indep, write_concurrency, error_info].
[basic, bad, limits, indep, write_concurrency, error_info, doctests].

basic(Config) when is_list(Config) ->
Size = 10,
Expand Down Expand Up @@ -240,6 +240,9 @@ rand_log64() ->
2 -> Uint
end.

doctests(_Config) ->
ct_doctest:module(counters).

error_info(_Config) ->
Counters = counters:new(10, [write_concurrency]),
Huge = 1 bsl 64,
Expand Down
14 changes: 12 additions & 2 deletions erts/emulator/test/persistent_term_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@
shared_magic_ref/1,
non_message_signal/1,
get_put_colliding_bucket/1,
gc_binary_orig/1]).
gc_binary_orig/1,
doctests/1]).

%%
-export([test_init_restart_cmd/1]).
Expand All @@ -60,7 +61,8 @@ all() ->
shared_magic_ref,
non_message_signal,
get_put_colliding_bucket,
gc_binary_orig].
gc_binary_orig,
doctests].

init_per_suite(Config) ->
erts_debug:set_internal_state(available_internal_state, true),
Expand Down Expand Up @@ -1266,3 +1268,11 @@ gpcb_updater(CollidesWith) ->
persistent_term:erase(CollidesWith),
persistent_term:put(CollidesWith, unexpected),
gpcb_updater(CollidesWith).

doctests(_Config) ->
Keys = [scheduler_ets, my_key, foo, bar, {my_app, config}],
try
ct_doctest:module(persistent_term)
after
[persistent_term:erase(K) || K <- Keys]
end.
181 changes: 175 additions & 6 deletions erts/preloaded/src/atomics.erl
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,41 @@ access. The atomics are organized into arrays with the following semantics:
can read the new value of B and then read the old value of A.
- Indexes into atomic arrays are one-based. An atomic array of arity N contains
N atomics with index from 1 to N.

## Examples

```erlang
1> Ref = atomics:new(3, [{signed, true}]).
2> atomics:put(Ref, 1, 10).
ok
3> atomics:get(Ref, 1).
10
4> atomics:add(Ref, 1, 5).
ok
5> atomics:get(Ref, 1).
15
6> atomics:exchange(Ref, 1, 42).
15
7> atomics:compare_exchange(Ref, 1, 42, 100).
ok
8> atomics:get(Ref, 1).
100
9> atomics:info(Ref).
#{size => 3, max => ..., min => ..., memory => ...}
```

Atomics can be updated concurrently from multiple processes:

```erlang
1> Ref = atomics:new(1, []).
2> Self = self().
3> N = 1000.
1000
4> Pids = [spawn(fun() -> atomics:add(Ref, 1, 1), Self ! self() end) || _ <- lists:seq(1, N)].
5> [receive Pid -> ok end || Pid <- Pids].
6> atomics:get(Ref, 1).
1000
```
""".
-moduledoc(#{since => "OTP 21.2"}).

Expand Down Expand Up @@ -77,6 +112,14 @@ Argument `Opts` is a list of the following possible options:

Atomics are not tied to the current process and are automatically garbage
collected when they are no longer referenced.

## Examples

```erlang
1> atomics:new(5, []).
2> atomics:new(5, [{signed, false}]).
3> atomics:new(5, [{signed, true}]).
```
""".
-doc(#{since => <<"OTP 21.2">>}).
-spec new(Arity, Opts) -> atomics_ref() when
Expand Down Expand Up @@ -105,7 +148,23 @@ encode_opts([], Acc) ->
encode_opts(_, _) ->
throw(badopt).

-doc "Set atomic to `Value`.".
-doc """
Set atomic to `Value`.

## Examples

```erlang
1> Ref = atomics:new(1, []).
2> atomics:put(Ref, 1, 42).
ok
3> atomics:get(Ref, 1).
42
4> atomics:put(Ref, 1, -10).
ok
5> atomics:get(Ref, 1).
-10
```
""".
-doc(#{since => <<"OTP 21.2">>}).
-spec put(Ref, Ix, Value) -> ok when
Ref :: atomics_ref(),
Expand All @@ -114,15 +173,47 @@ encode_opts(_, _) ->
put(_Ref, _Ix, _Value) ->
erlang:nif_error(undef).

-doc "Read atomic value.".
-doc """
Read atomic value.

## Examples

```erlang
1> Ref = atomics:new(2, []).
2> atomics:get(Ref, 1).
0
3> atomics:put(Ref, 1, 100).
ok
4> atomics:get(Ref, 1).
100
```
""".
-doc(#{since => <<"OTP 21.2">>}).
-spec get(Ref, Ix) -> integer() when
Ref :: atomics_ref(),
Ix :: pos_integer().
get(_Ref, _Ix) ->
erlang:nif_error(undef).

-doc "Add `Incr` to atomic.".
-doc """
Add `Incr` to atomic.

## Examples

```erlang
1> Ref = atomics:new(1, []).
2> atomics:add(Ref, 1, 5).
ok
3> atomics:add(Ref, 1, 3).
ok
4> atomics:get(Ref, 1).
8
5> atomics:add(Ref, 1, -2).
ok
6> atomics:get(Ref, 1).
6
```
""".
-doc(#{since => <<"OTP 21.2">>}).
-spec add(Ref, Ix, Incr) -> ok when
Ref :: atomics_ref(),
Expand All @@ -131,7 +222,21 @@ get(_Ref, _Ix) ->
add(_Ref, _Ix, _Incr) ->
erlang:nif_error(undef).

-doc "Atomically add `Incr` to atomic and return the result.".
-doc """
Atomically add `Incr` to atomic and return the result.

## Examples

```erlang
1> Ref = atomics:new(1, []).
2> atomics:add_get(Ref, 1, 5).
5
3> atomics:add_get(Ref, 1, 10).
15
4> atomics:add_get(Ref, 1, -3).
12
```
""".
-doc(#{since => <<"OTP 21.2">>}).
-spec add_get(Ref, Ix, Incr) -> integer() when
Ref :: atomics_ref(),
Expand All @@ -140,7 +245,21 @@ add(_Ref, _Ix, _Incr) ->
add_get(_Ref, _Ix, _Incr) ->
erlang:nif_error(undef).

-doc "Subtract `Decr` from atomic.".
-doc """
Subtract `Decr` from atomic.

## Examples

```erlang
1> Ref = atomics:new(1, []).
2> atomics:put(Ref, 1, 10).
ok
3> atomics:sub(Ref, 1, 3).
ok
4> atomics:get(Ref, 1).
7
```
""".
-doc(#{since => <<"OTP 21.2">>}).
-spec sub(Ref, Ix, Decr) -> ok when
Ref :: atomics_ref(),
Expand All @@ -154,7 +273,21 @@ sub(Ref, Ix, Decr) ->
error_with_info(Error, [Ref, Ix, Decr])
end.

-doc "Atomically subtract `Decr` from atomic and return the result.".
-doc """
Atomically subtract `Decr` from atomic and return the result.

## Examples

```erlang
1> Ref = atomics:new(1, []).
2> atomics:put(Ref, 1, 20).
ok
3> atomics:sub_get(Ref, 1, 5).
15
4> atomics:sub_get(Ref, 1, 10).
5
```
""".
-doc(#{since => <<"OTP 21.2">>}).
-spec sub_get(Ref, Ix, Decr) -> integer() when
Ref :: atomics_ref(),
Expand All @@ -170,6 +303,18 @@ sub_get(Ref, Ix, Decr) ->

-doc """
Atomically replace the value of the atomic with `Desired` and return the previous value.

## Examples

```erlang
1> Ref = atomics:new(1, []).
2> atomics:put(Ref, 1, 42).
ok
3> atomics:exchange(Ref, 1, 100).
42
4> atomics:get(Ref, 1).
100
```
""".
-doc(#{since => <<"OTP 21.2">>}).
-spec exchange(Ref, Ix, Desired) -> integer() when
Expand All @@ -185,6 +330,22 @@ atomic to `Desired`.

Return `ok` if `Desired` was written. Return the actual atomic value if
not equal to `Expected`.

## Examples

```erlang
1> Ref = atomics:new(1, []).
2> atomics:put(Ref, 1, 42).
ok
3> atomics:compare_exchange(Ref, 1, 42, 100).
ok
4> atomics:get(Ref, 1).
100
5> atomics:compare_exchange(Ref, 1, 42, 200).
100
6> atomics:get(Ref, 1).
100
```
""".
-doc(#{since => <<"OTP 21.2">>}).
-spec compare_exchange(Ref, Ix, Expected, Desired) -> ok | integer() when
Expand All @@ -204,6 +365,14 @@ The map has the following keys:
- **`max`** - The highest possible value an atomic in this array can hold.
- **`min`** - The lowest possible value an atomic in this array can hold.
- **`memory`** - Approximate memory consumption for the array in bytes.

## Examples

```erlang
1> Ref = atomics:new(10, []).
2> atomics:info(Ref).
#{size => 10, max => ..., min => ..., memory => ...}
```
""".
-doc(#{since => <<"OTP 21.2">>}).
-spec info(Ref) -> Info when
Expand Down
Loading
Loading