Skip to content

Commit

Permalink
Fix handling of dead processes in recon:info/2
Browse files Browse the repository at this point in the history
Closes #95
  • Loading branch information
ferd committed Oct 30, 2021
1 parent 59758c0 commit 5f29ba5
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 7 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ all stable changes of the first version of Recon.

*2.x*

- 2.5.3 (unpublished)
- [Handle dead processes in `recon:info/2` types and edge cases](https://github.com/ferd/recon/pull/97)
- 2.5.2
- [Increase Dialyzer strictness](https://github.com/ferd/recon/pull/88)
- [Accumulate all block entries in `format_blocks`](https://github.com/ferd/recon/pull/83)
Expand Down
2 changes: 1 addition & 1 deletion src/recon.app.src
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{application, recon,
[{description, "Diagnostic tools for production use"},
{vsn, "2.5.2"},
{vsn, "2.5.3"},
{modules, [recon, recon_alloc, recon_lib, recon_trace, recon_rec]},
{registered, []},
{applications, [kernel, stdlib]},
Expand Down
15 changes: 10 additions & 5 deletions src/recon.erl
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ info(A,B,C, Key) -> info(recon_lib:triple_to_pid(A,B,C), Key).
%% another registry supported in the `{via, Module, Name}' syntax (must have a
%% `Module:whereis_name/1' function). Pids can also be passed in as a string
%% (`"<0.39.0>"') or a triple (`{0,39,0}') and will be converted to be used.
%% Returns `undefined' as a value when a process died.
-spec info(pid_term()) -> [{info_type(), [{info_key(), Value}]},...] when
Value :: term().
info(PidTerm) ->
Expand All @@ -198,9 +199,9 @@ info(PidTerm) ->
%% A fake attribute `binary_memory' is also available to return the
%% amount of memory used by refc binaries for a process.
-dialyzer({no_contracts, info/2}). % ... Overloaded contract for recon:info/2 has overlapping domains
-spec info(pid_term(), info_type()) -> {info_type(), [{info_key(), term()}]}
; (pid_term(), [atom()]) -> [{atom(), term()}]
; (pid_term(), atom()) -> {atom(), term()}.
-spec info(pid_term(), info_type()) -> {info_type(), [{info_key(), term()}] | undefined}
; (pid_term(), [atom()]) -> [{atom(), term()}] | undefined
; (pid_term(), atom()) -> {atom(), term()} | undefined.
info(PidTerm, meta) ->
info_type(PidTerm, meta, [registered_name, dictionary, group_leader,
status]);
Expand All @@ -226,8 +227,12 @@ info_type(PidTerm, Type, Keys) ->
%% @private wrapper around `erlang:process_info/2' that allows special
%% attribute handling for items like `binary_memory'.
proc_info(Pid, binary_memory) ->
{binary, Bins} = erlang:process_info(Pid, binary),
{binary_memory, recon_lib:binary_memory(Bins)};
case erlang:process_info(Pid, binary) of
undefined ->
undefined;
{binary, Bins} ->
{binary_memory, recon_lib:binary_memory(Bins)}
end;
proc_info(Pid, Term) when is_atom(Term) ->
erlang:process_info(Pid, Term);
proc_info(Pid, List) when is_list(List) ->
Expand Down
27 changes: 26 additions & 1 deletion test/recon_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ all() -> [{group,info}, proc_count, proc_window, bin_leak,
node_stats_list, get_state, source, tcp, udp, files, port_types,
inet_count, inet_window, binary_memory, scheduler_usage].

groups() -> [{info, [], [info3, info4, info1, info2,
groups() -> [{info, [], [info3, info4, info1, info2, info_dead,
port_info1, port_info2]}].

init_per_group(info, Config) ->
Expand Down Expand Up @@ -144,6 +144,31 @@ info2(Config) ->
K1 == K2]),
unregister(info2).

info_dead(_Config) ->
Pid = spawn(fun() -> ok end),
timer:sleep(10),
Categories = [{meta, [registered_name, dictionary, group_leader, status]},
{signals, [links, monitors, monitored_by, trap_exit]},
{location, [initial_call, current_stacktrace]},
{memory_used, [memory, message_queue_len, heap_size,
total_heap_size, garbage_collection]},
{work, [reductions]}],
undefined = recon:info(Pid, registered_name),
Keys = lists:flatten([K || {_,L} <- Categories, K <- L]),
%% check that individual category calls return undefined values
[] = lists:flatten(
[GetCat || {Cat, _List} <- Categories,
{GetCat,Info} <- [recon:info(Pid, Cat)],
Cat =:= GetCat,
undefined =/= Info]
),
true = lists:all(fun(X) -> X == undefined end,
[recon:info(Pid, K) || K <- Keys]),
undefined = recon:info(Pid, Keys),
%% Special virtual record.
undefined = recon:info(Pid, binary_memory),
ok.

proc_count(_Config) ->
Res = recon:proc_count(memory, 10),
true = proc_attrs(Res),
Expand Down

0 comments on commit 5f29ba5

Please sign in to comment.