Skip to content
Merged
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
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added USB CDC port drivers for ESP32, RP2, and STM32 platforms
- Added a Linux `gpio` driver for the generic_unix port (in `avm_unix`) using sysfs
- Added `console:print_err/1` to write to standard error
- Added support for `process_info/1` and `process_info/2` with list argument
- Added `erlang:term_to_binary/2`, `erlang:is_builtin/3` and `erlang:bitstring_to_list/1`
- Added `lists:mapfoldr/3`

### Changed
- `erlang:process_info/2` now accepts only pids of local processes, as Erlang/OTP does:
calling it with a port now raises `badarg` (previous versions accepted any id-carrying
term, so it could be used to read port information; there is no `erlang:port_info/2`
in AtomVM yet to migrate such code to)
- Updated network type db() to dbm() to reflect the actual representation of the type
- Use ES6 modules for emscripten port, using .mjs suffix
- `ahttp_client` now returns `{error, {parser, incomplete_response}}` when a socket closes mid-response
Expand Down Expand Up @@ -77,6 +82,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fixed `ahttp_client` crash on headers with empty or all-whitespace values
- Fixed a bug in `supervisor` handling of failing child
- Fixed two bugs related to closing fds in `atomvm:subprocess/4`
- Fixed `message_queue_len` (as reported by `erlang:process_info/2`): unprocessed signals,
such as monitor or unlink requests, were counted as queued messages
- Fixed a process hanging forever after catching an exception raised asynchronously by a
trapping BIF: the trap flag was left set, so the process parked at the next scheduling
point and never ran again
- Fixed `erlang:localtime/1` memory leak, use-after-free, and TZ restore bugs on newlib/picolibc
- Fixed ESP32 I2C driver resource leaks, half-closed state, and close-during-transmission errors
- Fixed several underallocation issues that could trigger data corruption on `binary:replace`, `zlib:compress` and bsd socket recv code.
Expand Down
4 changes: 4 additions & 0 deletions UPDATING.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ bitshifts: e.g. `(16#FFFF band 0xF) bsl 252`.
- `binary_to_integer` and `list_to_integer` do not raise `overflow` error anymore, they instead
raise `badarg` when trying to parse an integer that exceeds 256 bits. Update any relevant error
handling code.
- `erlang:process_info/2` now accepts only pids of local processes, as Erlang/OTP does: calling
it with a port raises `badarg`. Previous versions accepted any id-carrying term, so it could be
used to read port information; there is no `erlang:port_info/2` in AtomVM yet, so such calls
must be removed or guarded when updating.
- ESP32 builds with Elixir support may be configured without making changes to git-tracked files
using `idf.py -DATOMVM_ELIXIR_SUPPORT=on set-target ${CHIP}` instead of copying
partitions-elixir.csv to partitions.csv. This configures the build to use partitions-elixir.csv for
Expand Down
10 changes: 4 additions & 6 deletions doc/src/apidocs/libatomvm/data_structures.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,12 @@ Data Structures
:maxdepth: 4
:caption: Structs

.. doxygenstruct:: AtomsHashTable
:allow-dot-graphs:
.. doxygenstruct:: AtomStringIntPair
:allow-dot-graphs:
.. doxygenstruct:: AtomTable
:allow-dot-graphs:
.. doxygenstruct:: AVMPackData
:allow-dot-graphs:
.. doxygenstruct:: BuiltInAtomRequestSignal
:allow-dot-graphs:
.. doxygenstruct:: BuiltInAtomSignal
:allow-dot-graphs:
.. doxygenstruct:: CharDataToBytesAcc
:allow-dot-graphs:
.. doxygenstruct:: CharDataToBytesSizeAcc
Expand Down Expand Up @@ -68,6 +62,8 @@ Data Structures
:allow-dot-graphs:
.. doxygenstruct:: IFFRecord
:allow-dot-graphs:
.. doxygenstruct:: ImmediateSignal
:allow-dot-graphs:
.. doxygenstruct:: InMemoryAVMPack
:allow-dot-graphs:
.. defined in excluded opcodesswitch.h
Expand Down Expand Up @@ -116,6 +112,8 @@ Data Structures
.. doxygenstruct:: Nif
:allow-dot-graphs:
.. doxygenstruct:: PrinterFun
.. doxygenstruct:: ProcessInfoRequestSignal
:allow-dot-graphs:
.. doxygenstruct:: RefcBinary
:allow-dot-graphs:
.. doxygenstruct:: RefcBinaryAVMPack
Expand Down
9 changes: 7 additions & 2 deletions doc/src/programmers-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -576,22 +576,27 @@ You can obtain a list of all processes in the system via [`erlang:processes/0`](
Pids = erlang:processes().
```

And for each process, you can get detailed process information via the [`erlang:process_info/2`](./apidocs/erlang/estdlib/erlang.md#process_info2) function:
And for each process, you can get detailed process information via the [`erlang:process_info/1`](./apidocs/erlang/estdlib/erlang.md#process_info1) and [`erlang:process_info/2`](./apidocs/erlang/estdlib/erlang.md#process_info2) functions:

```erlang
io:format("Heap size for Pid ~p: ~p~n", [Pid, erlang:process_info(Pid, heap_size)]).
```

The return value is a tuple containing the key passed into the `erlang:process_info/2` function and its associated value.
The return value is a tuple containing the key passed into the `erlang:process_info/2` function and its associated value, e.g. `{heap_size, 170}`. A list of keys may be passed instead of a single key, in which case the result is a list with one `{Key, Value}` tuple per requested key, in request order. `erlang:process_info/1` returns the default key set in one call. As in Erlang/OTP, these functions return `undefined` if the process is not alive, and querying the single key `registered_name` on a process without a registered name returns `[]`.

The currently supported keys are enumerated in the following table:

| Key | Value Type | Description |
|-----|------------|-------------|
| `heap_size` | `non_neg_integer()` | Number of terms (in machine words) used in the process heap |
| `total_heap_size` | `non_neg_integer()` | Number of terms (in machine words) used in the process heap, including heap fragments |
| `stack_size` | `non_neg_integer()` | Number of terms (in machine words) used in the process stack |
| `message_queue_len` | `non_neg_integer()` | Number of unprocessed messages in the process mailbox |
| `memory` | `non_neg_integer()` | Total number of bytes used by the process (estimate) |
| `registered_name` | `atom()` | The registered name of the process |
| `links` | `[pid()]` | The processes and ports the process is linked to |
| `monitored_by` | `[pid() \| port() \| resource()]` | The processes, ports and NIF resources monitoring the process |
| `trap_exit` | `boolean()` | Whether the process is trapping exits |

See the `word_size` key in the [System APIs](#system-apis) section for information about how to find the number of bytes used in a machine word on the current platform.

Expand Down
58 changes: 49 additions & 9 deletions libs/estdlib/src/erlang.erl
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
start_timer/3, start_timer/4,
cancel_timer/1,
send_after/3,
process_info/1,
process_info/2,
system_info/1,
system_flag/2,
Expand Down Expand Up @@ -319,6 +320,39 @@ cancel_timer(TimerRef) ->
send_after(Time, Dest, Msg) ->
timer_manager:send_after(Time, Dest, Msg).

%%-----------------------------------------------------------------------------
%% @param Pid the process pid.
%% @returns a list of `{Key, Value}' tuples, or `undefined' if the process
%% is not alive.
%% @doc Return information about the specified process.
%%
%% As in Erlang/OTP, the result covers a default set of keys; AtomVM returns
%% the supported subset of OTP's default set, in the same relative order:
%% `registered_name' (omitted when the process is not registered, first
%% otherwise), `message_queue_len', `links', `trap_exit', `total_heap_size',
%% `heap_size' and `stack_size'.
%% @end
%%-----------------------------------------------------------------------------
-spec process_info(Pid :: pid()) -> [{atom(), term()}] | undefined.
process_info(Pid) when erlang:is_pid(Pid) ->
case
erlang:process_info(Pid, [
registered_name,
message_queue_len,
links,
trap_exit,
total_heap_size,
heap_size,
stack_size
])
of
undefined -> undefined;
[{registered_name, []} | Info] -> Info;
Info -> Info
end;
process_info(Pid) ->
erlang:error(badarg, [Pid]).

%%-----------------------------------------------------------------------------
%% @param Pid the process pid.
%% @param Key key used to find process information.
Expand All @@ -338,20 +372,26 @@ send_after(Time, Dest, Msg) ->
%% <li><b>memory</b> the estimated total number of bytes in use by the process (integer)</li>
%% <li><b>links</b> the list of linked processes</li>
%% <li><b>monitored_by</b> the list of processes, NIF resources or ports that monitor the process</li>
%% <li><b>trap_exit</b> whether the process is trapping exits (boolean)</li>
%% </ul>
%% Specifying an unsupported term or atom raises a bad_arg error.
%% A list of keys may also be specified, in which case the result is a list
%% with one `{Key, Value}' tuple per requested key, in the same order and
%% with duplicates preserved, or `undefined' if the process is not alive.
%% Specifying an unsupported term or atom raises a badarg error.
%%
%% @end
%%-----------------------------------------------------------------------------
-spec process_info
(Pid :: pid(), heap_size) -> {heap_size, non_neg_integer()};
(Pid :: pid(), total_heap_size) -> {total_heap_size, non_neg_integer()};
(Pid :: pid(), registered_name) -> {registered_name, term()} | [];
(Pid :: pid(), stack_size) -> {stack_size, non_neg_integer()};
(Pid :: pid(), message_queue_len) -> {message_queue_len, non_neg_integer()};
(Pid :: pid(), memory) -> {memory, non_neg_integer()};
(Pid :: pid(), links) -> {links, [pid()]};
(Pid :: pid(), monitored_by) -> {monitored_by, [pid() | resource() | port()]}.
(Pid :: pid(), heap_size) -> {heap_size, non_neg_integer()} | undefined;
(Pid :: pid(), total_heap_size) -> {total_heap_size, non_neg_integer()} | undefined;
(Pid :: pid(), registered_name) -> {registered_name, term()} | [] | undefined;
(Pid :: pid(), stack_size) -> {stack_size, non_neg_integer()} | undefined;
(Pid :: pid(), message_queue_len) -> {message_queue_len, non_neg_integer()} | undefined;
(Pid :: pid(), memory) -> {memory, non_neg_integer()} | undefined;
(Pid :: pid(), links) -> {links, [pid()]} | undefined;
(Pid :: pid(), monitored_by) -> {monitored_by, [pid() | resource() | port()]} | undefined;
(Pid :: pid(), trap_exit) -> {trap_exit, boolean()} | undefined;
(Pid :: pid(), [atom()]) -> [{atom(), term()}] | undefined.
process_info(_Pid, _Key) ->
erlang:nif_error(undefined).

Expand Down
Loading
Loading