Are there functions which would allow an OTP process to find the pid of its supervisor?
可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
回答1:
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.
回答2:
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).