From: Siraaj Khandkar <siraaj@khandkar.net>
Date: Tue, 22 Sep 2015 22:08:02 +0000 (-0400)
Subject: fix: handling 'undefined' from erlang:process_info/2
X-Git-Tag: 0.8.2^0
X-Git-Url: https://git.xandkar.net/?a=commitdiff_plain;h=2cd7cf62e9b1e456c0ccc963d92a9170c3af8251;p=beam_stats.git

fix: handling 'undefined' from erlang:process_info/2

Process could die between the time we get its PID from erlang:processes() and
when we start calling erlang:process_info/2 on it; or even somewhere between
the process_info calls.

The choice is between returning partial info (that we were able to collect
before process died) and just skipping the process. For now, I'm choosing to
skip the process (throwing away any partial info collected).
---

diff --git a/src/beam_stats.app.src b/src/beam_stats.app.src
index 1597668..2dbb0cf 100644
--- a/src/beam_stats.app.src
+++ b/src/beam_stats.app.src
@@ -1,7 +1,7 @@
 {application, beam_stats,
  [
   {description, "Periodic VM stats production and consumption."},
-  {vsn, "0.8.1"},
+  {vsn, "0.8.2"},
   {registered, []},
   {applications,
     [ kernel
diff --git a/src/beam_stats_process.erl b/src/beam_stats_process.erl
index e2751ea..b0b7da4 100644
--- a/src/beam_stats_process.erl
+++ b/src/beam_stats_process.erl
@@ -43,25 +43,33 @@
 %% ============================================================================
 
 -spec of_pid(pid()) ->
-    t().
+      none        % when process is dead
+    | {some, t()} % when process is alive
+    .
 of_pid(Pid) ->
-    Dict = pid_info_exn(Pid, dictionary),
-    Ancestry =
-        #beam_stats_process_ancestry
-        { raw_initial_call  = pid_info_exn(Pid, initial_call)
-        , otp_initial_call  = hope_kv_list:get(Dict, '$initial_call')
-        , otp_ancestors     = hope_kv_list:get(Dict, '$ancestors')
-        },
-    ?T
-    { pid               = Pid
-    , registered_name   = pid_info_opt(Pid, registered_name)
-    , ancestry          = Ancestry
-    , status            = pid_info_exn(Pid, status)
-    , memory            = pid_info_exn(Pid, memory)
-    , total_heap_size   = pid_info_exn(Pid, total_heap_size)
-    , stack_size        = pid_info_exn(Pid, stack_size)
-    , message_queue_len = pid_info_exn(Pid, message_queue_len)
-    }.
+    try
+        Dict = pid_info_exn(Pid, dictionary),
+        Ancestry =
+            #beam_stats_process_ancestry
+            { raw_initial_call  = pid_info_exn(Pid, initial_call)
+            , otp_initial_call  = hope_kv_list:get(Dict, '$initial_call')
+            , otp_ancestors     = hope_kv_list:get(Dict, '$ancestors')
+            },
+        T =
+            ?T
+            { pid               = Pid
+            , registered_name   = pid_info_opt(Pid, registered_name)
+            , ancestry          = Ancestry
+            , status            = pid_info_exn(Pid, status)
+            , memory            = pid_info_exn(Pid, memory)
+            , total_heap_size   = pid_info_exn(Pid, total_heap_size)
+            , stack_size        = pid_info_exn(Pid, stack_size)
+            , message_queue_len = pid_info_exn(Pid, message_queue_len)
+            },
+        {some, T}
+    catch throw:{process_dead, _} ->
+        none
+    end.
 
 -spec print(t()) ->
     ok.
@@ -122,6 +130,7 @@ pid_info_opt(Pid, Key) ->
     case {Key, beam_stats_source:erlang_process_info(Pid, Key)}
     of  {registered_name, []}           -> none
     ;   {_              , {Key, Value}} -> {some, Value}
+    ;   {_              , undefined}    -> throw({process_dead, Pid})
     end.
 
 %% ============================================================================
diff --git a/src/beam_stats_processes.erl b/src/beam_stats_processes.erl
index 90c3886..1b3fcb2 100644
--- a/src/beam_stats_processes.erl
+++ b/src/beam_stats_processes.erl
@@ -22,7 +22,8 @@
     t().
 collect() ->
     Pids = beam_stats_source:erlang_processes(),
-    Ps = [beam_stats_process:of_pid(P) || P <- Pids],
+    PsOpts = [beam_stats_process:of_pid(P) || P <- Pids],
+    Ps = [P || {some, P} <- PsOpts],
     ?T
     { individual_stats
         = Ps