How to find the supervisor of an OTP process?
Asked Answered
V

2

8

Are there functions which would allow an OTP process to find the pid of its supervisor?

Vanzandt answered 9/11, 2010 at 9:49 Comment(1)
No idea, but afaik you can get the linked processes and the supervisor is one of them.Lighter
S
14

The data is hidden in the process dictionary (of any process spawned with proc_lib) under the entry '$ancestors':

1> proc_lib:spawn(fun() -> timer:sleep(infinity) end).
<0.33.0>
2> i(0,33,0).
[{current_function,{timer,sleep,1}},
 {initial_call,{proc_lib,init_p,3}},
 {status,waiting},
 {message_queue_len,0},
 {messages,[]},
 {links,[]},
 {dictionary,[{'$ancestors',[<0.31.0>]},
              {'$initial_call',{erl_eval,'-expr/5-fun-1-',0}}]},
 {trap_exit,false},
 {error_handler,error_handler},
 {priority,normal},
 {group_leader,<0.24.0>},
 {total_heap_size,233},
 {heap_size,233},
 {stack_size,6},
 {reductions,62},
 {garbage_collection,[{min_bin_vheap_size,46368},
                      {min_heap_size,233},
                      {fullsweep_after,65535},
                      {minor_gcs,0}]},
 {suspending,[]}]

Here the line that interests us is {dictionary,[{'$ancestors',[<0.31.0>]},.

Note that this is the kind of stuff you should rarely have any reason to use yourself. As far as I know, it's mostly used to handle clean termination in supervision trees rather than introspection for whatever code you have. Handle with care.

A cleaner way to do things without messing with OTP's sensible innards would be to have the supervisor pass its own pid as an argument to the process when starting it. This should be far less confusing for the people who'll read your code.

Schoolmaster answered 9/11, 2010 at 11:39 Comment(1)
I'd go with the pass of the supervisor pid as well. It is simpler to implement and maintain.Choreographer
B
1

If you want to do it wrong, here's our solution:

%% @spec get_ancestors(proc()) -> [proc()]
%% @doc Find the supervisor for a process by introspection of proc_lib
%% $ancestors (WARNING: relies on an implementation detail of OTP).
get_ancestors(Pid) when is_pid(Pid) ->
    case erlang:process_info(Pid, dictionary) of
        {dictionary, D} ->
            ancestors_from_dict(D);
        _ ->
            []
    end;
get_ancestors(undefined) ->
    [];
get_ancestors(Name) when is_atom(Name) ->
    get_ancestors(whereis(Name)).

ancestors_from_dict([]) ->
    [];
ancestors_from_dict([{'$ancestors', Ancestors} | _Rest]) ->
    Ancestors;
ancestors_from_dict([_Head | Rest]) ->
    ancestors_from_dict(Rest).
Bryonbryony answered 10/11, 2010 at 14:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.