2010-11-09 34 views

Répondre

12

Les données sont cachées dans le dictionnaire de processus (de tout processus a donné naissance à proc_lib) sous l'entrée '$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,[]}] 

Voici la ligne qui nous intéresse est {dictionary,[{'$ancestors',[<0.31.0>]},. Notez que c'est le genre de choses que vous devriez rarement avoir aucune raison de vous utiliser. Pour autant que je sache, il est principalement utilisé pour gérer la terminaison propre dans les arbres de supervision plutôt que l'introspection pour le code que vous avez. Manipuler avec soin.

Une manière plus simple de faire les choses sans se soucier des entrailles sensibles d'OTP serait de que le superviseur passe son propre pid comme argument au processus lors du démarrage. Cela devrait être beaucoup moins déroutant pour les personnes qui liront votre code.

+0

Oui, cela semble être une bonne idée. –

+3

J'irais aussi avec la passe du superviseur pid. C'est plus simple à mettre en œuvre et à maintenir. –

1

Si vous voulez le faire du mal, voici notre 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).