Skip to content

Commit 3b6901b

Browse files
committed
Merge pull request #1790 from pguyot/w32/fix-oom-disterl
Fix leak with disterl monitor by name 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 630c11d + 066a9b1 commit 3b6901b

File tree

7 files changed

+68
-11
lines changed

7 files changed

+68
-11
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
5353
- Added `binary:replace/3`, `binary:replace/4`
5454
- Added `binary:match/2` and `binary:match/3`
5555
- Added `supervisor:which_children/1`
56+
- Added `monitored_by` in `process_info/2`
5657

5758
### Changed
5859

@@ -72,6 +73,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7273
- Support for zero count in `lists:duplicate/2`.
7374
- packbeam: fix memory leak preventing building with address sanitizer
7475
- Fixed a bug where empty atom could not be created on some platforms, thus breaking receiving a message for a registered process from an OTP node.
76+
- Fix a memory leak in distribution when a BEAM node would monitor a process by name.
7577

7678
## [0.6.7] - Unreleased
7779

libs/estdlib/src/erlang.erl

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,9 @@
178178
| port()
179179
| atom().
180180

181+
% Current type until we make these references
182+
-type resource() :: binary().
183+
181184
%%-----------------------------------------------------------------------------
182185
%% @param Time time in milliseconds after which to send the timeout message.
183186
%% @param Dest Pid or server name to which to send the timeout message.
@@ -255,6 +258,7 @@ send_after(Time, Dest, Msg) ->
255258
%% <li><b>message_queue_len</b> the number of messages enqueued for the process (integer)</li>
256259
%% <li><b>memory</b> the estimated total number of bytes in use by the process (integer)</li>
257260
%% <li><b>links</b> the list of linked processes</li>
261+
%% <li><b>monitored_by</b> the list of processes, NIF resources or ports that monitor the process</li>
258262
%% </ul>
259263
%% Specifying an unsupported term or atom raises a bad_arg error.
260264
%%
@@ -267,7 +271,8 @@ send_after(Time, Dest, Msg) ->
267271
(Pid :: pid(), stack_size) -> {stack_size, non_neg_integer()};
268272
(Pid :: pid(), message_queue_len) -> {message_queue_len, non_neg_integer()};
269273
(Pid :: pid(), memory) -> {memory, non_neg_integer()};
270-
(Pid :: pid(), links) -> {links, [pid()]}.
274+
(Pid :: pid(), links) -> {links, [pid()]};
275+
(Pid :: pid(), monitored_by) -> {monitored_by, [pid() | resource() | port()]}.
271276
process_info(_Pid, _Key) ->
272277
erlang:nif_error(undefined).
273278

src/libAtomVM/context.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,19 @@ bool context_get_process_info(Context *ctx, term *out, size_t *term_size, term a
492492
}
493493
break;
494494
}
495+
case MONITORED_BY_ATOM: {
496+
struct ListHead *item;
497+
ret_size = TUPLE_SIZE(2);
498+
LIST_FOR_EACH (item, &ctx->monitors_head) {
499+
struct Monitor *monitor = GET_LIST_ENTRY(item, struct Monitor, monitor_list_head);
500+
if (monitor->monitor_type == CONTEXT_MONITOR_MONITORED_LOCAL) {
501+
ret_size += CONS_SIZE;
502+
} else if (monitor->monitor_type == CONTEXT_MONITOR_RESOURCE) {
503+
ret_size += CONS_SIZE + TERM_BOXED_RESOURCE_SIZE;
504+
}
505+
}
506+
break;
507+
}
495508
default:
496509
if (out != NULL) {
497510
*out = BADARG_ATOM;
@@ -582,6 +595,24 @@ bool context_get_process_info(Context *ctx, term *out, size_t *term_size, term a
582595
term_put_tuple_element(ret, 1, list);
583596
break;
584597
}
598+
// pids of monitoring processes / resources
599+
case MONITORED_BY_ATOM: {
600+
term_put_tuple_element(ret, 0, MONITORED_BY_ATOM);
601+
term list = term_nil();
602+
struct ListHead *item;
603+
LIST_FOR_EACH (item, &ctx->monitors_head) {
604+
struct Monitor *monitor = GET_LIST_ENTRY(item, struct Monitor, monitor_list_head);
605+
if (monitor->monitor_type == CONTEXT_MONITOR_MONITORED_LOCAL) {
606+
struct MonitorLocalMonitor *monitored_monitor = CONTAINER_OF(monitor, struct MonitorLocalMonitor, monitor);
607+
list = term_list_prepend(monitored_monitor->monitor_obj, list, heap);
608+
} else if (monitor->monitor_type == CONTEXT_MONITOR_RESOURCE) {
609+
struct ResourceContextMonitor *resource_monitor = CONTAINER_OF(monitor, struct ResourceContextMonitor, monitor);
610+
list = term_list_prepend(term_from_resource(resource_monitor->resource_obj, heap), list, heap);
611+
}
612+
}
613+
term_put_tuple_element(ret, 1, list);
614+
break;
615+
}
585616

586617
default:
587618
UNREACHABLE();

src/libAtomVM/defaultatoms.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,3 +190,5 @@ X(SCOPE_ATOM, "\x5", "scope")
190190
X(NOMATCH_ATOM, "\x7", "nomatch")
191191

192192
X(INIT_ATOM, "\x4", "init")
193+
194+
X(MONITORED_BY_ATOM, "\xC", "monitored_by")

src/libAtomVM/dist_nifs.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -414,12 +414,13 @@ static term nif_erlang_dist_ctrl_get_data(Context *ctx, int argc, term argv[])
414414

415415
term dist_monitor(struct DistConnection *conn_obj, term from_pid, term target_proc, term monitor_ref, Context *ctx)
416416
{
417-
if (term_is_atom(target_proc)) {
418-
target_proc = globalcontext_get_registered_process(ctx->global, term_to_atom_index(target_proc));
419-
}
420417
int target_process_id = 0;
421-
if (term_is_local_pid(target_proc)) {
422-
target_process_id = term_to_local_process_id(target_proc);
418+
term target_process_pid = target_proc;
419+
if (term_is_atom(target_process_pid)) {
420+
target_process_pid = globalcontext_get_registered_process(ctx->global, term_to_atom_index(target_process_pid));
421+
}
422+
if (term_is_local_pid(target_process_pid)) {
423+
target_process_id = term_to_local_process_id(target_process_pid);
423424
} else {
424425
RAISE_ERROR(BADARG_ATOM);
425426
}

tests/erlang_tests/test_process_info.erl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ start() ->
4040
{links, [Self]} = process_info(Pid, links),
4141
unlink(Pid),
4242
{links, []} = process_info(Pid, links),
43+
Monitor = monitor(process, Pid),
44+
% Twice because of spawn_opt above
45+
{monitored_by, [Self, Self]} = process_info(Pid, monitored_by),
46+
demonitor(Monitor),
47+
{monitored_by, [Self]} = process_info(Pid, monitored_by),
4348
Pid ! {Self, stop},
4449
_Accum =
4550
receive

tests/libs/estdlib/test_net_kernel.erl

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -170,11 +170,14 @@ test_autoconnect_to_beam(Platform) ->
170170
"F = fun(G) ->"
171171
" receive"
172172
" {Caller, ping} -> Caller ! {self(), pong}, G(G);"
173-
" {Caller, quit} -> Caller ! {self(), quit}"
174-
" after 5000 -> exit(timeout)"
175-
" end "
176-
"end, "
177-
"F(F).\" -s init stop -noshell"
173+
" {Caller, net_adm_ping} -> Caller ! {self(), net_adm:ping('" ++
174+
atom_to_list(Node) ++
175+
"')}, G(G);"
176+
" {Caller, quit} -> Caller ! {self(), quit}"
177+
" after 5000 -> exit(timeout)"
178+
" end "
179+
"end, "
180+
"F(F).\" -s init stop -noshell"
178181
)
179182
end,
180183
[link, monitor]
@@ -202,6 +205,14 @@ test_autoconnect_to_beam(Platform) ->
202205
{OTPPid, pong} -> ok
203206
after 5000 -> timeout
204207
end,
208+
OTPPid ! {self(), net_adm_ping},
209+
ok =
210+
receive
211+
{OTPPid, pong} -> ok
212+
after 5000 -> timeout
213+
end,
214+
% Ensure there is no leak
215+
{monitored_by, []} = process_info(whereis(net_kernel), monitored_by),
205216
erlang:send(OTPPid, {self(), quit}),
206217
ok =
207218
receive

0 commit comments

Comments
 (0)