[erlang-questions] [erlang-bugs] Strange behaviour of exit(kill)

Fred Hebert <>
Fri Oct 9 03:41:39 CEST 2015

On 10/09, Roland Karlsson wrote:
>So Robert, tell me who missed it.
>What is the difference in behaviour when using exit/1 or exit/2?
>And is the difference still there if the process kills itself with exit/2?

exit/1 raises a 'kill' exception (you can do it with erlang:raise(exit, 
kill, Stacktrace)) that will unwind the stack and can be caught by try 
... catch. In the case where the exception is not caught, the process is 
terminated and the reason of its death forwarded as a signal.

exit/2 sends an exit signal asynchronously.

The confusing aspect is that a 'kill' signal sent by exit/2 is 
untrappable, but a 'kill' signal that comes from a process terminating 
after an exception doesn't.

This means the underlying secret is you have 2 levels of signals (at 

- termination signals (uncaught exception create one of these, dying 
  from any other signal does the same)
- kill signals (untrappable)

The interesting bit then is why is there a need to translate 'kill' into 
'killed'? From what I can tell, it's just so you can know the process 
was brutally killed -- if you only had 'kill' then you know it came from 
an exception. Buuuut here's the kicker:

1> spawn_link(fun() -> exit(kill) end), flush().
Shell got {'EXIT',<0.87.0>,kill}
2> spawn_link(fun() -> spawn_link(fun() -> exit(kill) end), 
timer:sleep(infinity) end), flush().
Shell got {'EXIT',<0.89.0>,killed}
3> spawn_link(fun() -> process_flag(trap_exit, true), spawn_link(fun() 
-> exit(kill) end), timer:sleep(infinity) end), flush().

woops. There's no real consistency there. In the end:

- a special 'kill' signal that cannot be trapped will unconditionally 
  kill a process and produce a signal 'killed' for peer processes
- an exception 'kill' bubbling up is reported as a trappable exit signal 
  with the reason 'kill'
- that 'kill' exit signal is converted to 'killed' for other processes, 
  regardless of the source, as long as it's not from a local stack.

This just sounds like a leaky abstraction where the conversion of kill 
-> killed only takes place on incoming signals being converted, 
unconditionally. Still, you have two types of signals: untrappable 
(exit(Pid, kill)), and trappable (anything else, even with a reason 
kill, if produced from a stacktrace).

It's confusing and always has been so.

More information about the erlang-questions mailing list