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