Erlang: where does the unmatched message go? - erlang

When tried to send unmatched message to a spawned process in erlang shell, I was expecting the message should remain in the mailbox, but it seemed like the mailbox is empty, why?
Erlang R15B02 (erts-5.9.2) [smp:2:2] [async-threads:0]
Eshell V5.9.2 (abort with ^G)
1> Pid = spawn(fun()->receive stop->stop end end).
<0.33.0>
2> Pid ! msg.
msg
3> erlang:process_info(Pid, messages).
{messages,[]} %% where is the msg?

When the message can't be matched against a receive pattern it is moved from the mailbox to a save queue, see http://ndpar.blogspot.se/2010/11/erlang-explained-selective-receive.html for a detailed explanation of what happens.
The messages parameter to process_info/2 only shows the mailbox contents, AFAIK there is no way to inspect the contents of the save queue.

The message is of course there and it will be checked in subsequent receives. The fact that you can't see it with erlang:process_info(Pid, messages) is, in my opinion, weird.

(ppb2_bs6#esekilvxen245)1> self() ! a.
a
(ppb2_bs6#esekilvxen245)2> erlang:process_info(self(), messages).
{messages,[a]}

Related

Does Erlang's open_port call link to resulting process?

I've got some C code that I'm executing as an external process using Erlang's Port capability. I want the process that starts the C code, via open_port, to detect if the C code crashes. The documentation isn't completely clear to me, but as I understand it, a two-way link is established between the Erlang process and the external code. If one dies, the other is notified.
Here is a slightly modified version of the code in the "Erlang Interoperability Tutorial Guide" (http://www.erlang.org/doc/tutorial/c_port.html):
init(ExtPrg) ->
register(cport, self()),
process_flag(trap_exit, true),
Port = open_port({spawn, ExtPrg}, [{packet, 2}]),
PInfo = erlang:port_info(Port),
io:format("Port: ~p PInfo: ~p~n", [Port, PInfo]),
RVal = link(Port),
io:format("link? ~p~n", [RVal]),
loop(Port).
loop(Port) ->
receive
{call, Caller, Msg} ->
Port ! {self(), {command, encode(Msg)}},
receive
{Port, {data, Data}} ->
Caller ! {cport, decode(Data)}
end,
loop(Port);
stop ->
Port ! {self(), close},
receive
{Port, closed} ->
exit(normal)
end;
{'EXIT', Port, Reason} ->
exit(port_terminated)
end.
The init call correctly executes the C code, and as you can see sets trap_exit, but the EXTT message is not received when I kill the C code using kill -HUP from the Unix shell. I've tried with and without the link call (the Erlang documentation does not use it). The printing code I've added generates:
Eshell V5.9.1 (abort with ^G)
1> cport:start("./cport 22").
Port: #Port<0.630> PInfo: [{name,"./cport 22"},
{links,[<0.38.0>]},
{id,630},
{connected,<0.38.0>},
{input,0},
{output,0}]
<0.38.0>
link? true
It appears that a link is registered but I'm not catching the trap. What am I missing?
Try the extra option exit_status when calling open_port().
I did a similar Erlang program for supervising game servers.
When the external game server crashed I wanted to restart it from my central Erlang monitoring system.
This was the code that worked for me:
erlang:open_port({spawn_executable, "<Path to my game server start script>"},
[ exit_status ]),
When the external process is killed you will get a message of type
{Port,{exit_status,Status}}

How to manually send a message to a process which I just spawned?

How can I send a message to process with Erlang? I did start a process and the output shows me that the pid (process identifier) is <0.39.0>.
My question is how can I send a message to this process (<0.39.0>) manually.
While list_to_pid/1 can indeed be used to construct a PID and use it to send messages its usage is discouraged:
This BIF is intended for debugging and for use in the Erlang operating
system. It should not be used in application programs.
A better approach would be to save the PID when you start the process:
1> P = spawn(fun() -> receive _ -> ok end end).
<0.34.0>
2> P!hi.
hi
(emacs#yus-iMac.local)100> P = list_to_pid("<0.39.0>").
<0.39.0>
(emacs#yus-iMac.local)101> P!aaa.
aaa
Besides other solution,REGISTER func maybe helpful.
register(regpid,spawn(fun() -> receive _ ok end end).
regpid ! msg.
you can send msg to regpid everywhere.

Hot code replacement in erlang

I am working on my first real project in erlang, however, this code is simplified for brevity. I want to be able to load a newer version of a file into my project remotely while it's running. I've read about using a behavior like gen_server or gen_fsm which has this for free. While that might achieve the result, I want to use this to learn how to do it, not just get it done. I've read the docs about code replacement, and LYSE's bit about Hot Code Loving, among other things, but I haven't been able to find anything that works for what I'm doing, so here is the basic idea.
-module(reloading).
-export([loop/0]).
loop() ->
receive
upgrade ->
?MODULE:loop();
hello ->
io:format("This is a test~n"),
loop();
_ ->
loop()
end.
I am simply looping with the idea that I can send the message upgrade and it will load a newer version of the code.
$ erl
Erlang R15B01 (erts-5.9.1) [source] [64-bit] [async-threads:0] [hipe] [kernel-poll:false]
Eshell V5.9.1 (abort with ^G)
1> c(reloading).
{ok,reloading}
2> Loop = spawn(reloading, loop, []).
<0.39.0>
3> Loop ! hello.
This is a test
hello
At this point I change 10 line to io:format("I have changed this!~n"),
4> Loop ! upgrade.
upgrade
5> Loop ! hello.
This is a test
hello
I am expecting this hello call to print I have changed this! not This is a test. I know I can simply call c(reloading). and have this work the way expected, but I'm looking to send the actual project a message rather than manually updating the code. So where is my disconnect? What am I doing wrong, that I should be doing in order to hot load this code? As mentioned before, I am looking for a non-OTP solution for the sake of education.
For the sake of having an explicit answer, I am posting this.
Using #rvirding's suggestion of using the code module, I've modified it to look like this:
-module(reloading).
-export([loop/0]).
loop() ->
receive
upgrade ->
code:purge(?MODULE),
compile:file(?MODULE),
code:load_file(?MODULE),
?MODULE:loop();
hello ->
io:format("This is a test~n"),
loop();
_ ->
loop()
end.
First code:purge the old ?MODULE, then compile:file the new file, and finally, code:load_file the new ?MODULE.
This works as I originally intended.
$ erl
Erlang R15B01 (erts-5.9.1) [source] [64-bit] [async-threads:0] [hipe] [kernel-poll:false]
Eshell V5.9.1 (abort with ^G)
1> Loop = spawn(reloading, loop, []).
<0.34.0>
2> Loop ! hello.
This is a test
hello
Change line to io:format("I have changed this!~n"),
3> Loop ! upgrade.
upgrade
4> Loop ! hello.
I have changed this!
hello
While erlang can handle two versions of a module and calling a function with mod:func(...) will always call the latest version of a module (if the function is exported) you still have to load the new version of the module into Erlang system. You can't expect it automagically detect that you happen to have a new version of the module somewhere, find it, compile it and load it.
N.B. compiling and loading are two separate things. So c(mod). both compiles and loads the module, while l(mod). just loads the object code (.beam file) of the already compiled module. The Erlang compiler is called from the module compile and it just compiles and generates a .beam file while the code loading is handled by the module code.
In addition to the above I'd like to notice that some tools that reload code automatically for you exist.
You should have a look at sync or active projects.
Compile *.beam locally, then send it to your server and reload it as mentioned in man pages:
http://erlang.org/documentation/doc-1/reference_manual/code_loading.html#id86381
-module(m).
-export([loop/0]).
loop() ->
receive
code_switch ->
m:loop();
Msg ->
...
loop()
end.

Erlang: How to write my outputs in a text file?

I need to write my outputs from shell into a text file to keeping some required records. Can anyone please tell me how can I do this?
Thanks
If you have the data you wish to store as a single term you can read how here. In the simplest case you can just do file:write_file(Path, Data). If your data is more complex you may want to use io_lib:fwrite/2 to format it in a more readable way. For example:
Data = [1,2,3,{car, "honda"}],
file:write_file("/tmp/foo", io_lib:fwrite("~p.\n", [Data])).
tee command can capture shell output and save it to a file:
$ erl | tee output.txt
Eshell V5.8 (abort with ^G)
1> A = 5.
5
2> 5 + A.
10
3> ^Ca
$ cat output.txt
Eshell V5.8 (abort with ^G)
1> 5
2> 10
3>
There are many possibilities. Here's the first one which came to my mind.
In Erlang, every process is part of a group. For each group, a process - named group leader gets all the output from the group-mates. The shell process is part of the group init. So, what you could do is to change the group leader for the shell process by doing:
{ok, Log} = file:open("log", [write]),
erlang:group_leader(Log, self()).
You might want to create a dedicated process acting as group leader who manages the output in a more clever way. For example, it could wrap the file after a while or when the file reaches a certain size.
The problem with this approach is that you have to execute these lines any time you start your shell. Doing it by using the -s flag:
erl -s shell_log
where shell_log is:
-module(shell_log).
-export([start/0]).
start() ->
{ok, Log} = file:open("log", [write]),
erlang:group_leader(Log, self()).
won't work, because it's still too early (init is still in {starting, started}, as reported by init:get_status()).
In the same way, doing it by using the .erlang file in your HOME directory (whose lines are automatically executed every time you start a shell) will fail for a similar reason (init is still in the {starting, applications_loaded} state).
Not sure which is the best way to circumvent this problem. I'll think about it.
Finally, this question seems a duplicate of this thread.

Query an Erlang process for its state?

A common pattern in Erlang is the recursive loop that maintains state:
loop(State) ->
receive
Msg ->
NewState = whatever(Msg),
loop(NewState)
end.
Is there any way to query the state of a running process with a bif or tracing or something? Since crash messages say "...when state was..." and show the crashed process's state, I thought this would be easy, but I was disappointed that I haven't been able to find a bif to do this.
So, then, I figured using the dbg module's tracing would do it. Unfortunately, I believe because these loops are tail call optimized, dbg will only capture the first call to the function.
Any solution?
If your process is using OTP, it is enough to do sys:get_status(Pid).
The error message you mentions is displayed by SASL. SASL is an error reporting daemon in OTP.
The state you are referring in your example code is just an argument of tail recursive function. There is no way to extract it using anything except for tracing BIFs. I guess this would be not a proper solution in production code, since tracing is intended to be used only for debug purposes.
Proper, and industry tested, solution would be make extensive use of OTP in your project. Then you can take full advantage of SASL error reporting, rb module to collect these reports, sys - to inspect the state of the running OTP-compatible process, proc_lib - to make short-lived processes OTP-compliant, etc.
It turns out there's a better answer than all of these, if you're using OTP:
sys:get_state/1
Probably it didn't exist at the time.
It looks like you're making the problem out of nothing. erlang:process_info/1 gives enough information for debugging purposes. If your REALLY need loop function arguments, why don't you give it back to caller in response to one of the special messages that you define yourself?
UPDATE:
Just to clarify terminology. The closest thing to the 'state of the process' on the language level is process dictionary, usage of which is highly discouraged. It can be queried by erlang:process_info/1 or erlang:process/2.
What you actually need is to trace process's local functions calls along with their arguments:
-module(ping).
-export([start/0, send/1, loop/1]).
start() ->
spawn(?MODULE, loop, [0]).
send(Pid) ->
Pid ! {self(), ping},
receive
pong ->
pong
end.
loop(S) ->
receive
{Pid, ping} ->
Pid ! pong,
loop(S + 1)
end.
Console:
Erlang (BEAM) emulator version 5.6.5 [source] [smp:2] [async-threads:0] [kernel-poll:false]
Eshell V5.6.5 (abort with ^G)
1> l(ping).
{module,ping}
2> erlang:trace(all, true, [call]).
23
3> erlang:trace_pattern({ping, '_', '_'}, true, [local]).
5
4> Pid = ping:start().
<0.36.0>
5> ping:send(Pid).
pong
6> flush().
Shell got {trace,<0.36.0>,call,{ping,loop,[0]}}
Shell got {trace,<0.36.0>,call,{ping,loop,[1]}}
ok
7>
{status,Pid,_,[_,_,_,_,[_,_,{data,[{_,State}]}]]} = sys:get_status(Pid).
That's what I use to get the state of a gen_server. (Tried to add it as a comment to the reply above, but couldn't get formatting right.)
As far as I know you cant get the arguments passed to a locally called function. I would love for someone to prove me wrong.
-module(loop).
-export([start/0, loop/1]).
start() ->
spawn_link(fun () -> loop([]) end).
loop(State) ->
receive
Msg ->
loop([Msg|State])
end.
If we want to trace this module you do the following in the shell.
dbg:tracer().
dbg:p(new,[c]).
dbg:tpl(loop, []).
Using this tracing setting you get to see local calls (the 'l' in tpl means that local calls will be traced as well, not only global ones).
5> Pid = loop:start().
(<0.39.0>) call loop:'-start/0-fun-0-'/0
(<0.39.0>) call loop:loop/1
<0.39.0>
6> Pid ! foo.
(<0.39.0>) call loop:loop/1
foo
As you see, just the calls are included. No arguments in sight.
My recommendation is to base correctness in debugging and testing on the messages sent rather than state kept in processes. I.e. if you send the process a bunch of messages, assert that it does the right thing, not that it has a certain set of values.
But of course, you could also sprinkle some erlang:display(State) calls in your code temporarily. Poor man's debugging.
This is a "oneliner" That can be used in the shell.
sys:get_status(list_to_pid("<0.1012.0>")).
It helps you convert a pid string into a Pid.

Resources