when i read an artical from learnyousomeerlang.com,I got a question.
http://learnyousomeerlang.com/errors-and-processes
It says that:
Exception source: exit(self(), kill)
Untrapped Result: ** exception exit: killed
Trapped Result: ** exception exit: killed
Oops, look at that. It seems like this one is actually impossible to trap. Let's check something.
but it does not comply with what I test with the code blow:
-module(trapexit).
-compile(export_all).
self_kill_exit()->
process_flag(trap_exit,true),
Pid=spawn_link(fun()->timer:sleep(3000),exit(self(),kill) end),
receive
{_A,Pid,_B}->io:format("subinmain:~p output:~p~n",[Pid,{_A,Pid,_B}])
end.
oupput is:
**4> trapexit:self_kill_exit().
subinmain:<0.36.0> output:{'EXIT',<0.36.0>,killed}**
and does not comply with Trapped Result: ** exception exit: killed said before . which is right???
The call to self in the body of the function passed as an argument to spawn_link doesn't return the process calling spawn_link. It's being evaluated in the newly spawned process and as a result it will return its pid. Make a following change.
-module(trapexit).
-compile(export_all).
self_kill_exit()->
process_flag(trap_exit,true),
Self=self(),
Pid=spawn_link(fun()->timer:sleep(3000),exit(Self,kill) end),
receive
{_A,Pid,_B}->io:format("subinmain:~p output:~p~n",[Pid,{_A,Pid,_B}])
end.
Now it should work as expected.
10> c(trapexit).
{ok,trapexit}
11> trapexit:self_kill_exit().
** exception exit: killed
The book is right. Trapping exit(self(), kill) is not possible.
Related
I having crypto_server problems:
=CRASH REPORT==== 23-Jul-2019::10:20:17 ===
crasher:
pid: <0.49.0>
registered_name: crypto_server
exception exit: {einval,
[{erlang,open_port,
[{spawn,
"crypto_drv elibcrypto
c:/myapp/lib/crypto-1.5.3/priv/lib/win32/elibcrypto"},
[]]},
{crypto_server,open_ports,2},
{gen_server,init_it,6},
{proc_lib,init_p_do_apply,3}]}
in function gen_server:init_it/6
initial call: crypto_server:init/1
ancestors: [crypto_sup,<0.47.0>]
messages: []
links: [<0.48.0>]
dictionary: []
trap_exit: true
status: running
heap_size: 610
stack_size: 23
reductions: 425
neighbours:
and the application doesn't start:
Kernel pid terminated (application_controller)
({application_start_failure,crypto,{shutdown,{crypto_app,start,[normal,[]]}}})
einval is a is a linux error that means invalid argument. Erlang returns quite a few of those types of errors back to the user. If you need a handy lookup table, you check look here.
I'm guessing the version of OpenSSL you have installed is incompatible with the old version of erlang. You could always start a trace on the init and see what's happening in during all of the message passing. You'll have to add the trace to your start up code before starting up the crypto lib. Here's a basic primer on tracing.
You must start the tracer program:
dbg:tracer().
Then you need to identify which process(es) you'd like to trace. The simple version is to watch all processes. (c is short for [call], which means trace all function calls.)
dbg:p(all, c).
Finally, say what function calls you're interested in tracing by Module; Module and Function; or Module, Function, and Arity. You can use '_' in place of any of them.
dbg:tpl(Module, cx).
dbg:tpl(Module, Function, cx).
dbg:tpl(Module, Function, Arity, cx).
You can turn tracing off with a similar function that disables tracing for all functions; by Module; by Module and Function; or by Module, Function, and Arity. Again, you can use '_' in place of any of them.
dbg:ctpl().
dbg:ctpl(Module).
dbg:ctpl(Module, Function).
dbg:ctpl(Module, Function, Arity).
A simple, working example that you can copy/paste into a fresh repl:
dbg:tracer().
dbg:p(all, c).
dbg:tpl(file, open, cx).
file:open("idontexist", []).
dbg:ctpl(file).
file:open("idontexist", []).
That should produce something like:
1> dbg:tracer().
{ok,<0.299.0>}
2> dbg:p(all, c).
{ok,[{matched,engine#ryan,215}]}
3> dbg:tpl(file, open, cx).
{ok,[{matched,node#sam,1},{saved,cx}]}
4> file:open("idontexist", []).
(<0.50.0>) call file:open("idontexist",[]) ({erl_eval,do_apply,6})
(<0.50.0>) returned from file:open/2 -> {error,enoent}
{error,enoent}
5> dbg:ctpl(file).
{ok,[{matched,node#sam,95}]}
6> file:open("idontexist", []).
{error,enoent}
7>
when using lager's 'trace' as follows:
lager:trace_file("/var/log/peter/lager_test_a_debug.log",[{module,lager_test_a}],debug),
lager:trace_file("/var/log/peter/lager_test_http_server_debug.log",[{module,lager_test_http_server}],debug),
'lager_test_a' is gen_server module, and it is terminated, the reason is as follows:
terminate(Reason, _State) ->
io:format("_123:~n\t~p",[Reason]),
ok.
{badarg,[{ets,update_counter,[40984,input,{2,1}],[]},
{lager_default_tracer,handle,1,[]},
{lager_util,check_trace,2,
[{file,"src/lager_util.erl"},{line,445}]},
{lager_util,check_traces,4,
[{file,"src/lager_util.erl"},{line,438}]},
{lager,do_log,9,[{file,"src/lager.erl"},{line,103}]},
{lager_test_a,handle_info,2,
[{file,"src/lager_test_a.erl"},{line,104}]},
{gen_server,try_dispatch,4,
[{file,"gen_server.erl"},{line,593}]},
{gen_server,handle_msg,5,
[{file,"gen_server.erl"},{line,659}]}]}
But I can't find lager_default_tracer.beam and source file.
I think that it may be ets's 'table 40984' doesn't exist, and the error happens.
But how to solve the problem?
Here is my function :
mydemonitor(Pid) ->
io:format("Demonitor : ~w ~n", [Pid]), %%For debugging and trying to see what's wrong
erlang:demonitor(Pid, [flush]).
And here is what I get :
Demonitor : <0.41.0>
=ERROR REPORT==== 15-Oct-2014::15:32:19 ===
Error in process <0.47.0> with exit value: {badarg,[{erlang,demonitor,[<0.41.0>,[flush]],[]},{node3,mydemonitor,1,[{file,"node3.erl"},{line,213}]},{node3,stabilize,4,[{file,"node3.erl"},{line,147}]},{node3,node,5,[{file,"node3.erl"},{line,46}]}]}
I looked at the man of erlang:demonitor/2 and erlang:demonitor/1, it seems that I use the right syntax. I tried to use demonitor/1 (so without the flush option) without success.
I really don't see what is wrong, any idea would be greatly appreciated :D
The argument to demonitor/1 and demonitor/2 is not the PID of the process being monitored, but the reference returned by monitor/2.
consider the code below:
-module(except).
-compile(export_all).
divone(X)-> erlang:error({badnews,erlang:get_stacktrace()}),1/X-1.
tryreturn(X)->
try divone(X) of
Val->{result,2/Val}
catch
exit:Reason->{exit,Reason};
throw:Throw->{throw,Throw};
error:Error->{error,Error}
end.
test the code in shell:
Eshell V5.9.1 (abort with ^G)
1> c(except).
{ok,except}
2> except:tryreturn(10). **%why cant't get stack trace info here?**
{error,{badnews,[]}}
3> except:tryreturn(10). **%why can get here?**
{error,{badnews,[{except,divone,1,
[{file,"except.erl"},{line,4}]},
{except,tryreturn,1,[{file,"except.erl"},{line,7}]},
{erl_eval,do_apply,6,[{file,"erl_eval.erl"},{line,576}]},
{shell,exprs,7,[{file,"shell.erl"},{line,668}]},
{shell,eval_exprs,7,[{file,"shell.erl"},{line,623}]},
{shell,eval_loop,3,[{file,"shell.erl"},{line,608}]}]}}
If there hasn't been any exceptions, the stacktrace returned by erlang:backtrace() is empty.
Something more helpful than erlang:backtrace() for you would be something that includes the instruction pointer and the process's callstack, irrespective of if you've caught an exception.
This should be the ticket:
io:format("~s~n", [element(2, process_info(self(), backtrace))]).
(Naturally, self can be freely exchanged with another Pid)
According to documentation:
Gets the call stack back-trace (stacktrace) of the last exception in the calling process as a list of {Module,Function,Arity,Location} tuples. Field Arity in the first tuple can be the argument list of that function call instead of an arity integer, depending on the exception.
Note the last exception in above text. During your first call, there was not any exception yet, so there is not any stacktrace to return. Then you make error class[1] exception using erlang:error/1 so next call returns stacktrace of the previous call!
There is idiom how to get stacktrace of the current code:
try throw(foo) catch foo -> erlang:get_stacktrace() end.
or using older (obsolete) way:
catch throw(foo), erlang:get_stacktrace().
[1]: There are three classes of exception: throw, error, exit.
I'm working on an erlang program and getting a strange runtime error. Any idea why? Thanks!
The errors are (after compiling the program successfully):
8> PID = spawn(planner,start,[]).
** exception error: no match of right hand side value <0.65.0>
9>
This is the program:
-module(planner).
-export([start/0]).
start() ->
loop([],[]).
loop(ContactsList,EventsList) ->
receive
{contact, Last, First, Number} ->
loop([{Last,First,Number}|ContactsList],EventsList);
{event, Date, Time, What} ->
loop([{Date,Time,What}|ContactsList],EventsList);
print_contacts ->
NewList=lists:sort(ContactsList),
lists:foreach(fun(Elem)->io:format("~p~n", [Elem]) end, NewList),
loop(ContactsList,EventsList);
print_events ->
NewList=lists:sort(EventsList),
lists:foreach(fun(Elem)->io:format("~p~n", [Elem]) end, NewList),
loop(ContactsList,EventsList);
exit ->
io:format("Exiting.~n");
_ ->
io:format("Dude, I don't even know what you're talking about.~n"),
loop(ContactsList,EventsList)
end.
The variable PID is probably set to something else but <0.65.0> from an earlier line you entered in the shell:
5> PID = spawn(...).
<0.42.0>
8> PID = spawn(...).
** exception error: no match of right hand side value <0.65.0>
This effectively makes the line which generates the error something like
8> <0.42.0> = <0.65.0>.
which will result in a "no match" error.
More obvious illustration of the issue:
1> X = 1.
1
2> X = 2.
** exception error: no match of right hand side value 2
As to solving your issue: You probably want to run f(PID) to have the shell forget just the PID variable, or even f() to have the shell forget ALL variables.