erlang:list_to_pid/1 with remote pid

Yao Bao by@REDACTED
Sun Jul 5 11:27:26 CEST 2020


Hello,

Thanks for the detailed explanation about it.

Based on the documentation you mentioned, I write a function to parse the PidBin, and here it is:

%% Begin

parse_bin_pid(BinPid) ->
    XLen = 1,
    FlagLen = 1,
    IDLen = 4,
    SerialLen = 4,
    CreationLen = 1,
    NodeLen = erlang:byte_size(BinPid) - (XLen + FlagLen + IDLen + SerialLen + CreationLen),
    <<
        X:XLen/binary, % What is this?
        Flag:FlagLen/binary,
        Node:NodeLen/binary,
        ID:IDLen/binary,
        Serial:SerialLen/binary,
        Creation:CreationLen/binary
    >> = BinPid,
    {X, Flag, Node, ID, Serial, Creation}.

test_parse_bin_pid() ->
    Pid = erlang:self(),
    Bin = erlang:term_to_binary(Pid),
    parse_bin_pid(Bin).

%% End

And, I test it with two local nodes to find the differences:

# 1
MacBookPro:code by$ erl -sname yao1
Erlang/OTP 22 [erts-10.5.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe] [dtrace]

Eshell V10.5.3  (abort with ^G)
(yao1@REDACTED)1> my_lib_misc:test_parse_bin_pid().
{<<131>>,
 <<"g">>,
 <<100,0,15,121,97,111,49,64,77,97,99,66,111,111,107,80,
   114,111>>,
 <<0,0,0,87>>,
 <<0,0,0,0>>,
 <<3>>}
(yao1@REDACTED)2> erlang:self().
<0.87.0>
(yao1@REDACTED)3> 

# 2
MacBookPro:code by$ erl -sname yao2
Erlang/OTP 22 [erts-10.5.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe] [dtrace]

Eshell V10.5.3  (abort with ^G)
(yao2@REDACTED)1> my_lib_misc:test_parse_bin_pid().
{<<131>>,
 <<"g">>,
 <<100,0,15,121,97,111,50,64,77,97,99,66,111,111,107,80,
   114,111>>,
 <<0,0,0,87>>,
 <<0,0,0,0>>,
 <<1>>}
(yao2@REDACTED)2> erlang:self().
<0.87.0>
(yao2@REDACTED)3> 

In my environment, PID_EXT is used, both Node and Creation are different in two local nodes.

Back to the module a_dist_demo:

Eshell V10.5.3  (abort with ^G)
(yao1@REDACTED)1> Pid = a_dist_demo:start('yao2@REDACTED').
<9222.131.0>
(yao1@REDACTED)2> Pid1 = erlang:list_to_pid("<9222.131.0>").
<9222.131.0>
(yao1@REDACTED)3> my_lib_misc:parse_bin_pid(erlang:term_to_binary(Pid)).      
{<<131>>,
 <<"g">>,
 <<100,0,21,121,97,111,50,64,77,97,99,66,111,111,107,80,
   114,111,46,108,111,99,97,108>>,
 <<0,0,0,131>>,
 <<0,0,0,0>>,
 <<1>>}
(yao1@REDACTED)4> my_lib_misc:parse_bin_pid(erlang:term_to_binary(Pid1)).
{<<131>>,
 <<"g">>,
 <<100,0,21,121,97,111,50,64,77,97,99,66,111,111,107,80,
   114,111,46,108,111,99,97,108>>,
 <<0,0,0,131>>,
 <<0,0,0,0>>,
 <<0>>}
(yao1@REDACTED)7> Bin = erlang:term_to_binary(Pid).                          
<<131,103,100,0,21,121,97,111,50,64,77,97,99,66,111,111,
  107,80,114,111,46,108,111,99,97,108,0,0,0,...>>
(yao1@REDACTED)8> Bin1 = erlang:term_to_binary(Pid1).
<<131,103,100,0,21,121,97,111,50,64,77,97,99,66,111,111,
  107,80,114,111,46,108,111,99,97,108,0,0,0,…>>
(yao1@REDACTED)9> {X, Y} = erlang:split_binary(Bin, erlang:byte_size(Bin)-1).
{<<131,103,100,0,21,121,97,111,50,64,77,97,99,66,111,111,
   107,80,114,111,46,108,111,99,97,108,0,0,...>>,
 <<1>>}
(yao1@REDACTED)12> Bin1 = <<X/binary, <<0>>/binary>>.
<<131,103,100,0,21,121,97,111,50,64,77,97,99,66,111,111,
  107,80,114,111,46,108,111,99,97,108,0,0,0,…>>

As you mentioned, the difference comes from the creation value, the erlang:list_to_pid/1 always set the creation value to 0, and this is why Pid =/= Pid1.

Cheers,
Yao

> 在 2020年6月21日,03:54,Dániel Szoboszlay <dszoboszlay@REDACTED> 写道:
> 
> Hi,
> 
> The first number in a pid identifies the node. The local node is always 0, remote nodes get some number assigned by the VM. This node number may differ across VM-s. So for example you can have 3 nodes in a cluster, a@REDACTED, b@REDACTED and c@REDACTED You spawn a process on a@REDACTED and get back pid <0.123.456>. If you send this pid value to processes on b@REDACTED and c@REDACTED and print it there, they may look different in the first number. You can get something like <987.123.456> and <654.123.456> or whatever. In this example b@REDACTED assigned the number 987 to a@REDACTED You can't tell just from looking at the pid <987.123.456> that 987 means a@REDACTED But you can be sure that all processes with the same first number come from the same node.
> 
> When you call binary_to_term/1 on a pid, Erlang encodes much more information in the result than what you see in the printed form of a pid: http://erlang.org/doc/apps/erts/erl_ext_dist.html#new_pid_ext <http://erlang.org/doc/apps/erts/erl_ext_dist.html#new_pid_ext> Notably it will include the full name of the node, not just this number we've seen so far. So if you send this binary to a different node it will be able to decode it properly.
> 
> I'm not 100% sure why Pid and Pid1 became different in your example. But I suspect because of the creation value. The creation value is also in the binary_to_term/1 output. It is meant to distinguish pids from different runs of the node with the same name. Local pids are generated somewhat deterministically, so for example the init process is always <0.1.0>, and processes spawned during the boot up also usually get the same pids - or at least identical looking pids in the shell. In fact, whenever the node boots up, it changes its creation value, so if a node crashes and gets restarted the new init process will have a different pid from the last one. Although both of them will look <0.1.0> for you in the shell. But this means list_to_pid/1 doesn't get the real creation value, it has to use some default instead. I guess that's why <9172.91.0> =/= <9172.91.0> for you.
> 
> Cheers,
> Daniel
> 
> On Sat, 20 Jun 2020 at 08:28, Yao Bao <by@REDACTED <mailto:by@REDACTED>> wrote:
> Hi,
> 
> By accident, I found erlang:list_to_pid/1 does not produce the same "thing" when putting remote pid string as the argument.
> 
> And, I found this mailing list post: http://erlang.org/pipermail/erlang-questions/2009-February/042100.html <http://erlang.org/pipermail/erlang-questions/2009-February/042100.html>
> 
> Quite interesting, but I still can't figure out why after reading the whole post.
> 
> I checked the source code, a function called list_to_pid_1() in erts/emulator/beam/bif.c handles this. Honestly speaking, I can't fully understand it. So I did some guess work.
> 
> I wrote a simple module:
> 
> %%
> %% A dist demo.
> %%
> -module(a_dist_demo).
> 
> -export([start/1, loop/0]).
> 
> start(Node) ->
>     spawn(Node, fun() -> loop() end).
> 
> loop() ->
>     receive
>     {From, {echo, Any}} ->
>         From ! Any,
>         loop()
>     end.
> 
> And two nodes get started:
> 
> MacBookPro:code by$ erl -name yao1
> Erlang/OTP 22 [erts-10.5.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe] [dtrace]
> Eshell V10.5.3  (abort with ^G)
> (yao1@REDACTED <mailto:yao1@REDACTED>)1> Pid = a_dist_demo:start('yao2@REDACTED <mailto:yao2@REDACTED>').
> <9172.91.0>
> (yao1@REDACTED <mailto:yao1@REDACTED>)2> Bin = erlang:term_to_binary(Pid).
> <<131,103,100,0,21,121,97,111,50,64,77,97,99,66,111,111,
>   107,80,114,111,46,108,111,99,97,108,0,0,0,...>>
> (yao1@REDACTED <mailto:yao1@REDACTED>)3> io:format("~p~n", [Bin]).
> <<131,103,100,0,21,121,97,111,50,64,77,97,99,66,111,111,107,80,114,111,46,108,
>   111,99,97,108,0,0,0,91,0,0,0,0,2>>
> ok
> (yao1@REDACTED <mailto:yao1@REDACTED>)4> Pid ! {self(), {echo, abcd}}.
> {<0.87.0>,{echo,abcd}}
> (yao1@REDACTED <mailto:yao1@REDACTED>)5> receive X -> X end.
> abcd
> (yao1@REDACTED <mailto:yao1@REDACTED>)6>
> (yao1@REDACTED <mailto:yao1@REDACTED>)8> Pid1 = erlang:list_to_pid("<9172.91.0>").
> <9172.91.0>
> (yao1@REDACTED <mailto:yao1@REDACTED>)9> Pid = Pid1.
> ** exception error: no match of right hand side value <9172.91.0>
> (yao1@REDACTED <mailto:yao1@REDACTED>)11> Bin1 = erlang:term_to_binary(Pid1).
> <<131,103,100,0,21,121,97,111,50,64,77,97,99,66,111,111,
>   107,80,114,111,46,108,111,99,97,108,0,0,0,…>>
> (yao1@REDACTED <mailto:yao1@REDACTED>)12> Bin = Bin1.
> ** exception error: no match of right hand side value 
>                     <<131,103,100,0,21,121,97,111,50,64,77,97,99,66,111,111,
>                       107,80,114,111,46,108,111,99,97,108,0,0,0,...>>
> (yao1@REDACTED <mailto:yao1@REDACTED>)13>
> 
> MacBookPro:code by$ erl -name yao2
> Erlang/OTP 22 [erts-10.5.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe] [dtrace]
> Eshell V10.5.3  (abort with ^G)
> (yao2@REDACTED <mailto:yao2@REDACTED>)1> Bin = <<131,103,100,0,21,121,97,111,50,64,77,97,99,66,111,111,107,80,114,111,46,108,111,99,97,108,0,0,0,91,0,0,0,0,2>>.
> <<131,103,100,0,21,121,97,111,50,64,77,97,99,66,111,111,
>   107,80,114,111,46,108,111,99,97,108,0,0,0,...>>
> (yao2@REDACTED <mailto:yao2@REDACTED>)2> Pid = erlang:binary_to_term(Bin).
> <0.91.0>
> (yao2@REDACTED <mailto:yao2@REDACTED>)3> Pid ! {self(), {echo, 1234}}.
> {<0.87.0>,{echo,1234}}
> (yao2@REDACTED <mailto:yao2@REDACTED>)4> receive X -> X end.
> 1234
> (yao2@REDACTED <mailto:yao2@REDACTED>)5>
> 
> The result is: the same binary produces two different shapes of pid ( <9172.91.0> and <0.91.0> ) in two nodes. Apparently, they refer to the same process.
> 
> I guess the remote pid need some unique information came from the remote node, and erlang:list_to_pid/1 just do not have those information.
> 
> I hope some internal thoughts can be revealed for this.
> 
> Cheers,
> Yao
> 

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20200705/befac4df/attachment.htm>


More information about the erlang-questions mailing list