Skip to content

Commit 9e1c16b

Browse files
committed
Merge pull request #2326 from bettio/updated-aliases
Add support for process aliases Implement process aliases, so a process can hand out a reference that works as a send target and deactivate it again once it is done with it. This is the OTP mechanism behind request/reply patterns that must not accept a late reply, and AtomVM had no equivalent. The series rebases the original implementation on `release-0.7` and lands the fixes found while reviewing it. Highlights: - `erlang:alias/0,1`, `erlang:unalias/1`, `erlang:monitor/3` with the `{alias, Mode}` option, and `spawn_opt` `{monitor, MonitorOpts}`. - Sending to an alias from `erlang:send/2`, the send opcode and the JIT send path, and from a remote node over distribution. - A new process reference term that carries the owner process id next to the ref ticks, with BEAM compliant ordering and `binary_to_term`/`term_to_binary` round tripping. - Alias sends are posted as a mailbox signal, so a sender never walks the owner's monitor list and send order is preserved. - Three pre-existing defects surfaced along the way are fixed in their own commits: a leaked process lock in `erlang:monitor/2,3`, a switch fall through in `context_demonitor`, and a dangling scheduler queue entry left behind by `context_destroy`. A send addressed to a remote alias is dropped instead of being routed over distribution, and the OTP `{tag, Term}` monitor option and the `alias/1` `priority` option raise `unsupported`. All three are documented. Supersedes #2027 Closes #2027 These changes are made under both the "Apache 2.0" and the "GNU Lesser General Public License 2.1 or later" license terms (dual license). SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
2 parents d189e7e + e11cc94 commit 9e1c16b

42 files changed

Lines changed: 1988 additions & 191 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2323
- Added `"USB_SERIAL_JTAG"` peripheral to the ESP32 `uart` module on chips with a built-in
2424
USB-Serial-JTAG controller (C3/C5/C6/C61/H2/H21/H4/P4/S3)
2525
- Added support for the `safe` option in `erlang:binary_to_term/2`
26+
- Added support for process aliases: `erlang:alias/0,1`, `erlang:unalias/1`,
27+
`erlang:monitor/3` with the `{alias, Mode}` option, `spawn_opt` `{monitor, MonitorOpts}` and
28+
sending to an alias reference
2629
- Added xtensa JIT backend for esp32 platform
2730
- Added support for configuring pins and width for sdmmc on ESP32
2831
- Added support for map comprehensions
@@ -49,6 +52,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
4952
for this limit
5053
- Replaced the `exavmlib` `Protocol` module with a small runtime shim (only `Protocol.__concat__/2`),
5154
saving ~31 KB of flash. ExAtomVM uses precompiled, unconsolidated protocols and continue to function normally at runtime.
55+
- Deprecated the C macro `REF_SIZE`: use `TERM_BOXED_REFERENCE_SHORT_SIZE` for references built
56+
from ref ticks, `TERM_BOXED_REFERENCE_PROCESS_SIZE` for process references (aliases), or
57+
`TERM_BOXED_REFERENCE_MAX_SIZE` to fit any reference. `REF_SIZE` still expands to the short
58+
reference size, but now emits a compiler warning
5259

5360
### Removed
5461
- Removed `ahttp_client` support for obsolete line folding (RFC 9112 §5.2); folded header and

doc/src/apidocs/libatomvm/functions.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ Functions
130130
.. doxygenfunction:: mailbox_next
131131
.. doxygenfunction:: mailbox_peek
132132
.. doxygenfunction:: mailbox_process_outer_list
133+
.. doxygenfunction:: mailbox_process_outer_list_native
133134
.. doxygenfunction:: mailbox_remove_message
134135
.. doxygenfunction:: mailbox_reset
135136
.. doxygenfunction:: mailbox_send

doc/src/distributed-erlang.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,4 +325,11 @@ RPC (remote procedure call) from Erlang/OTP to AtomVM is also supported.
325325

326326
Shell requires several OTP standard library modules. See [the example project](https://github.com/pguyot/atomvm_shell).
327327

328+
## Known Issues & Limitations
329+
330+
- Sending to a remote process alias is not supported: a message sent from AtomVM to an alias
331+
(a reference) of another node is silently dropped instead of being routed over distribution.
332+
The other direction works: a message sent from a remote BEAM node to an alias of an AtomVM
333+
process is delivered.
334+
328335
Please do not hesitate to file issues or pull requests for additional features.

libs/estdlib/src/erlang.erl

Lines changed: 86 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@
104104
make_ref/0,
105105
send/2,
106106
monitor/2,
107+
monitor/3,
107108
demonitor/1,
108109
demonitor/2,
109110
exit/1,
@@ -174,7 +175,10 @@
174175
tl/1,
175176
trunc/1,
176177
tuple_size/1,
177-
tuple_to_list/1
178+
tuple_to_list/1,
179+
alias/0,
180+
alias/1,
181+
unalias/1
178182
]).
179183

180184
-export_type([
@@ -212,12 +216,14 @@
212216
| {max_heap_size, pos_integer()}
213217
| {atomvm_heap_growth, atomvm_heap_growth_strategy()}
214218
| link
215-
| monitor.
219+
| monitor
220+
| {monitor, [monitor_option()]}.
216221

217222
-type send_destination() ::
218223
pid()
219224
| port()
220-
| atom().
225+
| atom()
226+
| reference().
221227

222228
% Current type until we make these references
223229
-type resource() :: binary().
@@ -238,6 +244,8 @@
238244
-type raise_stacktrace() ::
239245
[{module(), atom(), arity() | [term()]} | {function(), arity() | [term()]}] | stacktrace().
240246

247+
-type monitor_option() :: {alias, explicit_unalias | demonitor | reply_demonitor}.
248+
241249
%%-----------------------------------------------------------------------------
242250
%% @param Time time in milliseconds after which to send the timeout message.
243251
%% @param Dest Pid or server name to which to send the timeout message.
@@ -1222,8 +1230,10 @@ spawn_monitor(Module, Function, Args) ->
12221230

12231231
%%-----------------------------------------------------------------------------
12241232
%% @param Function function to create a process from
1225-
%% @param Options additional options.
1226-
%% @returns pid of the new process
1233+
%% @param Options additional options, see `spawn_option()'. With `monitor'
1234+
%% or `{monitor, MonitorOpts}' the new process is also monitored, see
1235+
%% `monitor/3' for the monitor options.
1236+
%% @returns pid of the new process, or `{Pid, MonitorRef}' when monitoring
12271237
%% @doc Create a new process.
12281238
%% @end
12291239
%%-----------------------------------------------------------------------------
@@ -1236,8 +1246,10 @@ spawn_opt(_Name, _Options) ->
12361246
%% @param Module module of the function to create a process from
12371247
%% @param Function name of the function to create a process from
12381248
%% @param Args arguments to pass to the function to create a process from
1239-
%% @param Options additional options.
1240-
%% @returns pid of the new process
1249+
%% @param Options additional options, see `spawn_option()'. With `monitor'
1250+
%% or `{monitor, MonitorOpts}' the new process is also monitored, see
1251+
%% `monitor/3' for the monitor options.
1252+
%% @returns pid of the new process, or `{Pid, MonitorRef}' when monitoring
12411253
%% @doc Create a new process by calling exported Function from Module with Args.
12421254
%% @end
12431255
%%-----------------------------------------------------------------------------
@@ -1277,10 +1289,11 @@ make_ref() ->
12771289
erlang:nif_error(undefined).
12781290

12791291
%%-----------------------------------------------------------------------------
1280-
%% @param Pid process to send the message to
1292+
%% @param Target process, registered name or alias to send the message to
12811293
%% @param Message message to send
12821294
%% @returns the sent message
1283-
%% @doc Send a message to a given process
1295+
%% @doc Send a message to a given process. A message sent to a reference
1296+
%% that is not an active alias is silently dropped.
12841297
%% @end
12851298
%%-----------------------------------------------------------------------------
12861299
-spec send(Target :: send_destination(), Message :: Message) -> Message.
@@ -1306,6 +1319,32 @@ send(_Target, _Message) ->
13061319
monitor(_Type, _PidOrPort) ->
13071320
erlang:nif_error(undefined).
13081321

1322+
%%-----------------------------------------------------------------------------
1323+
%% @param Type type of monitor to create
1324+
%% @param PidOrPort pid or port of the object to monitor
1325+
%% @param Options monitor options
1326+
%% @returns a monitor reference
1327+
%% @doc Creates a monitor and allows passing additional options.
1328+
%% Currently, only the `{alias, AliasMode}' option is supported. Passing it
1329+
%% makes the monitor also an alias on the calling process (see `alias/0').
1330+
%% `AliasMode' defines the behaviour of the alias:
1331+
%% - explicit_unalias - the alias can be only removed with `unalias/1',
1332+
%% - demonitor - the alias is also removed when the monitor is removed,
1333+
%% by `demonitor/1' or by the delivery of a `DOWN' message,
1334+
%% - reply_demonitor - additionally, the alias is deactivated and the
1335+
%% monitor removed (as by `demonitor/1') when the
1336+
%% first message sent via the alias is delivered.
1337+
%%
1338+
%% <b>Note:</b> Unlike Erlang/OTP, the `{tag, Term}' option is not
1339+
%% supported and raises `unsupported'.
1340+
%% @end
1341+
%%-----------------------------------------------------------------------------
1342+
-spec monitor
1343+
(Type :: process, Pid :: pid() | atom(), [monitor_option()]) -> reference();
1344+
(Type :: port, Port :: port() | atom(), [monitor_option()]) -> reference().
1345+
monitor(_Type, _PidOrPort, _Options) ->
1346+
erlang:nif_error(undefined).
1347+
13091348
%%-----------------------------------------------------------------------------
13101349
%% @param Monitor reference of monitor to remove
13111350
%% @returns `true'
@@ -2147,3 +2186,41 @@ tuple_size(_Tuple) ->
21472186
-spec tuple_to_list(Tuple :: tuple()) -> [term()].
21482187
tuple_to_list(_Tuple) ->
21492188
erlang:nif_error(undefined).
2189+
2190+
%%-----------------------------------------------------------------------------
2191+
%% @returns A reference aliasing the calling process.
2192+
%% @doc Creates an alias for the calling process. The alias can be used
2193+
%% to send messages to the process like the PID. The alias can also be
2194+
%% created along with a monitor - see `monitor/3'. The alias can be
2195+
%% removed by calling `unalias/1'.
2196+
%% @end
2197+
%%-----------------------------------------------------------------------------
2198+
-spec alias() -> Alias when Alias :: reference().
2199+
alias() ->
2200+
erlang:nif_error(undefined).
2201+
2202+
%%-----------------------------------------------------------------------------
2203+
%% @param Options alias options
2204+
%% @returns A reference aliasing the calling process.
2205+
%% @doc Creates an alias for the calling process, like `alias/0'.
2206+
%% With `explicit_unalias' (the default, so `alias([])' is `alias/0')
2207+
%% the alias stays active until `unalias/1'; with `reply' it is
2208+
%% deactivated when the first message sent via the alias is delivered.
2209+
%%
2210+
%% <b>Note:</b> Unlike Erlang/OTP, the `priority' option (OTP 28) is
2211+
%% not supported and raises `unsupported'.
2212+
%% @end
2213+
%%-----------------------------------------------------------------------------
2214+
-spec alias(Options) -> Alias when Options :: [explicit_unalias | reply], Alias :: reference().
2215+
alias(_Options) ->
2216+
erlang:nif_error(undefined).
2217+
2218+
%%-----------------------------------------------------------------------------
2219+
%% @param Alias the alias to be removed.
2220+
%% @returns `true' if alias was removed, `false' if it was not found
2221+
%% @doc Removes process alias. See `alias/0' for more information.
2222+
%% @end
2223+
%%-----------------------------------------------------------------------------
2224+
-spec unalias(Alias) -> boolean() when Alias :: reference().
2225+
unalias(_Alias) ->
2226+
erlang:nif_error(undefined).

0 commit comments

Comments
 (0)